/* * 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); }
/* * 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); } }