コード例 #1
0
ファイル: smb_kshare.c プロジェクト: mikess/illumos-gate
/*
 * This function is invoked when a share is disabled to disconnect trees
 * and close files.  Cleaning up may involve VOP and/or VFS calls, which
 * may conflict/deadlock with stuck threads if something is amiss with the
 * file system.  Queueing the request for asynchronous processing allows the
 * call to return immediately so that, if the unshare is being done in the
 * context of a forced unmount, the forced unmount will always be able to
 * proceed (unblocking stuck I/O and eventually allowing all blocked unshare
 * processes to complete).
 *
 * The path lookup to find the root vnode of the VFS in question and the
 * release of this vnode are done synchronously prior to any associated
 * unmount.  Doing these asynchronous to an associated unmount could run
 * the risk of a spurious EBUSY for a standard unmount or an EIO during
 * the path lookup due to a forced unmount finishing first.
 */
int
smb_kshare_unexport_list(smb_ioc_share_t *ioc)
{
	smb_server_t	*sv = NULL;
	smb_unshare_t	*ux;
	nvlist_t	*shrlist = NULL;
	nvpair_t	*nvp;
	boolean_t	unexport = B_FALSE;
	char		*shrname;
	int		rc;

	if ((rc = smb_server_lookup(&sv)) != 0)
		return (rc);

	if ((rc = nvlist_unpack(ioc->shr, ioc->shrlen, &shrlist, 0)) != 0)
		goto out;

	for (nvp = nvlist_next_nvpair(shrlist, NULL); nvp != NULL;
	    nvp = nvlist_next_nvpair(shrlist, nvp)) {
		if (nvpair_type(nvp) != DATA_TYPE_NVLIST)
			continue;

		shrname = nvpair_name(nvp);
		ASSERT(shrname);

		if ((rc = smb_kshare_unexport(sv, shrname)) != 0)
			continue;

		ux = kmem_cache_alloc(smb_kshare_cache_unexport, KM_SLEEP);
		(void) strlcpy(ux->us_sharename, shrname, MAXNAMELEN);

		smb_slist_insert_tail(&sv->sv_export.e_unexport_list, ux);
		unexport = B_TRUE;
	}

	if (unexport)
		smb_thread_signal(&sv->sv_export.e_unexport_thread);
	rc = 0;

out:
	if (shrlist != NULL)
		nvlist_free(shrlist);
	smb_server_release(sv);
	return (rc);
}
コード例 #2
0
/*
 * smb_nt_transact_notify_change
 *
 * This function is responsible for processing NOTIFY CHANGE requests.
 * Requests are stored in a global queue. This queue is processed when
 * a monitored directory is changed or client cancels one of its already
 * sent requests.
 */
smb_sdrc_t
smb_nt_transact_notify_change(struct smb_request *sr, struct smb_xa *xa)
{
	uint32_t		CompletionFilter;
	unsigned char		WatchTree;
	smb_node_t		*node;

	if (smb_mbc_decodef(&xa->req_setup_mb, "lwb",
	    &CompletionFilter, &sr->smb_fid, &WatchTree) != 0)
		return (SDRC_NOT_IMPLEMENTED);

	smbsr_lookup_file(sr);
	if (sr->fid_ofile == NULL) {
		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
		return (SDRC_ERROR);
	}

	node = sr->fid_ofile->f_node;

	if (!smb_node_is_dir(node)) {
		/*
		 * Notify change requests are only valid on directories.
		 */
		smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY, 0, 0);
		return (SDRC_ERROR);
	}

	mutex_enter(&sr->sr_mutex);
	switch (sr->sr_state) {
	case SMB_REQ_STATE_ACTIVE:
		node->waiting_event++;
		node->flags |= NODE_FLAGS_NOTIFY_CHANGE;
		if ((node->flags & NODE_FLAGS_CHANGED) == 0) {
			sr->sr_ncr.nc_node = node;
			sr->sr_ncr.nc_flags = CompletionFilter;
			if (WatchTree)
				sr->sr_ncr.nc_flags |= NODE_FLAGS_WATCH_TREE;

			sr->sr_keep = B_TRUE;
			sr->sr_state = SMB_REQ_STATE_WAITING_EVENT;

			smb_slist_insert_tail(&smb_ncr_list, sr);

			/*
			 * Monitor events system-wide.
			 *
			 * XXX: smb_node_ref() and smb_node_release()
			 * take &node->n_lock.  May need alternate forms
			 * of these routines if node->n_lock is taken
			 * around calls to smb_fem_fcn_install() and
			 * smb_fem_fcn_uninstall().
			 */

			smb_fem_fcn_install(node);

			mutex_exit(&sr->sr_mutex);
			return (SDRC_SR_KEPT);
		} else {
			/* node already changed, reply immediately */
			if (--node->waiting_event == 0)
				node->flags &=
				    ~(NODE_FLAGS_NOTIFY_CHANGE |
				    NODE_FLAGS_CHANGED);
			mutex_exit(&sr->sr_mutex);
			return (SDRC_SUCCESS);
		}

	case SMB_REQ_STATE_CANCELED:
		mutex_exit(&sr->sr_mutex);
		smbsr_error(sr, NT_STATUS_CANCELLED, 0, 0);
		return (SDRC_ERROR);

	default:
		ASSERT(0);
		mutex_exit(&sr->sr_mutex);
		return (SDRC_SUCCESS);
	}
}