From ccc71be50bb49efb4e31004c77fb3e065e9c0596 Mon Sep 17 00:00:00 2001 From: Gordon Ross Date: Wed, 10 Oct 2012 20:07:26 -0400 Subject: [PATCH] 3523 SMB NT Notify returning too soon Reviewed by: Albert Lee Reviewed by: Dan McDonald Reviewed by: Yakov Zaytsev Approved by: Richard Lowe --- .../common/fs/smbsrv/smb_common_transact.c | 7 +- usr/src/uts/common/fs/smbsrv/smb_fem.c | 27 +- usr/src/uts/common/fs/smbsrv/smb_fsops.c | 17 +- usr/src/uts/common/fs/smbsrv/smb_node.c | 75 +- usr/src/uts/common/fs/smbsrv/smb_nt_cancel.c | 5 +- .../fs/smbsrv/smb_nt_transact_notify_change.c | 674 +++++++----------- usr/src/uts/common/fs/smbsrv/smb_ofile.c | 9 +- usr/src/uts/common/fs/smbsrv/smb_rename.c | 29 +- usr/src/uts/common/fs/smbsrv/smb_server.c | 4 - usr/src/uts/common/fs/smbsrv/smb_session.c | 14 +- usr/src/uts/common/smbsrv/smb_kproto.h | 16 +- usr/src/uts/common/smbsrv/smb_ktypes.h | 18 +- 12 files changed, 406 insertions(+), 489 deletions(-) diff --git a/usr/src/uts/common/fs/smbsrv/smb_common_transact.c b/usr/src/uts/common/fs/smbsrv/smb_common_transact.c index 21dff73b3cba..7d534665fdfe 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_common_transact.c +++ b/usr/src/uts/common/fs/smbsrv/smb_common_transact.c @@ -21,6 +21,7 @@ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012 Nexenta Systems, Inc. All rights reserved. */ #include @@ -127,7 +128,7 @@ smb_com_transaction(smb_request_t *sr) if (smb_xa_open(xa)) { smb_xa_rele(sr->session, xa); - smbsr_error(sr, 0, ERRDOS, ERRsrverror); + smbsr_error(sr, 0, ERRSRV, ERRsrverror); return (SDRC_ERROR); } sr->r_xa = xa; @@ -314,7 +315,7 @@ smb_com_transaction2(struct smb_request *sr) if (smb_xa_open(xa)) { smb_xa_rele(sr->session, xa); - smbsr_error(sr, 0, ERRDOS, ERRsrverror); + smbsr_error(sr, 0, ERRSRV, ERRsrverror); return (SDRC_ERROR); } sr->r_xa = xa; @@ -586,7 +587,7 @@ smb_com_nt_transact(struct smb_request *sr) if (smb_xa_open(xa)) { smb_xa_rele(sr->session, xa); - smbsr_error(sr, 0, ERRDOS, ERRsrverror); + smbsr_error(sr, 0, ERRSRV, ERRsrverror); return (SDRC_ERROR); } sr->r_xa = xa; diff --git a/usr/src/uts/common/fs/smbsrv/smb_fem.c b/usr/src/uts/common/fs/smbsrv/smb_fem.c index e32b5fc92595..38cfab1f5c7b 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_fem.c +++ b/usr/src/uts/common/fs/smbsrv/smb_fem.c @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012 Nexenta Systems, Inc. All rights reserved. */ #include @@ -223,7 +224,7 @@ smb_fem_fcn_create( ct, vsecp); if (error == 0) - smb_node_notify_change(dnode); + smb_node_notify_change(dnode, FILE_ACTION_ADDED, name); return (error); } @@ -257,7 +258,7 @@ smb_fem_fcn_remove( error = vnext_remove(arg, name, cr, ct, flags); if (error == 0) - smb_node_notify_change(dnode); + smb_node_notify_change(dnode, FILE_ACTION_REMOVED, name); return (error); } @@ -281,10 +282,18 @@ smb_fem_fcn_rename( error = vnext_rename(arg, snm, tdvp, tnm, cr, ct, flags); - if (error == 0) - smb_node_notify_change(dnode); + if (error != 0) + return (error); - return (error); + /* + * Note that renames in the same directory are normally + * delivered in {old,new} pairs, and clients expect them + * in that order, if both events are delivered. + */ + smb_node_notify_change(dnode, FILE_ACTION_RENAMED_OLD_NAME, snm); + smb_node_notify_change(dnode, FILE_ACTION_RENAMED_NEW_NAME, tnm); + + return (0); } static int @@ -308,7 +317,7 @@ smb_fem_fcn_mkdir( error = vnext_mkdir(arg, name, vap, vpp, cr, ct, flags, vsecp); if (error == 0) - smb_node_notify_change(dnode); + smb_node_notify_change(dnode, FILE_ACTION_ADDED, name); return (error); } @@ -332,7 +341,7 @@ smb_fem_fcn_rmdir( error = vnext_rmdir(arg, name, cdir, cr, ct, flags); if (error == 0) - smb_node_notify_change(dnode); + smb_node_notify_change(dnode, FILE_ACTION_REMOVED, name); return (error); } @@ -356,7 +365,7 @@ smb_fem_fcn_link( error = vnext_link(arg, svp, tnm, cr, ct, flags); if (error == 0) - smb_node_notify_change(dnode); + smb_node_notify_change(dnode, FILE_ACTION_ADDED, tnm); return (error); } @@ -381,7 +390,7 @@ smb_fem_fcn_symlink( error = vnext_symlink(arg, linkname, vap, target, cr, ct, flags); if (error == 0) - smb_node_notify_change(dnode); + smb_node_notify_change(dnode, FILE_ACTION_ADDED, linkname); return (error); } diff --git a/usr/src/uts/common/fs/smbsrv/smb_fsops.c b/usr/src/uts/common/fs/smbsrv/smb_fsops.c index 68e32246cd83..f9ec3fa67461 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_fsops.c +++ b/usr/src/uts/common/fs/smbsrv/smb_fsops.c @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012 Nexenta Systems, Inc. All rights reserved. */ #include @@ -423,7 +424,8 @@ smb_fsop_create_stream(smb_request_t *sr, cred_t *cr, /* notify change to the unnamed stream */ if (rc == 0) - smb_node_notify_change(dnode); + smb_node_notify_change(dnode, + FILE_ACTION_ADDED_STREAM, fname); return (rc); } @@ -679,9 +681,10 @@ smb_fsop_remove( rc = smb_vop_stream_remove(fnode->vp, name, flags, cr); /* notify change to the unnamed stream */ - if ((rc == 0) && fnode->n_dnode) - smb_node_notify_change(fnode->n_dnode); - + if ((rc == 0) && fnode->n_dnode) { + smb_node_notify_change(fnode->n_dnode, + FILE_ACTION_REMOVED_STREAM, fnode->od_name); + } } else if (smb_is_stream_name(name)) { smb_stream_parse_name(name, fname, sname); @@ -710,8 +713,10 @@ smb_fsop_remove( smb_node_release(fnode); /* notify change to the unnamed stream */ - if (rc == 0) - smb_node_notify_change(dnode); + if (rc == 0) { + smb_node_notify_change(dnode, + FILE_ACTION_REMOVED_STREAM, fname); + } } else { rc = smb_vop_remove(dnode->vp, name, flags, cr); diff --git a/usr/src/uts/common/fs/smbsrv/smb_node.c b/usr/src/uts/common/fs/smbsrv/smb_node.c index bd69147095f5..bfb08c2d1581 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_node.c +++ b/usr/src/uts/common/fs/smbsrv/smb_node.c @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012 Nexenta Systems, Inc. All rights reserved. */ /* * SMB Node State Machine @@ -784,15 +785,51 @@ smb_node_share_check(smb_node_t *node) return (status); } +/* + * SMB Change Notification + */ + +void +smb_node_fcn_subscribe(smb_node_t *node, smb_request_t *sr) +{ + smb_node_fcn_t *fcn = &node->n_fcn; + + mutex_enter(&fcn->fcn_mutex); + if (fcn->fcn_count == 0) + smb_fem_fcn_install(node); + fcn->fcn_count++; + list_insert_tail(&fcn->fcn_watchers, sr); + mutex_exit(&fcn->fcn_mutex); +} + +void +smb_node_fcn_unsubscribe(smb_node_t *node, smb_request_t *sr) +{ + smb_node_fcn_t *fcn = &node->n_fcn; + + mutex_enter(&fcn->fcn_mutex); + list_remove(&fcn->fcn_watchers, sr); + fcn->fcn_count--; + if (fcn->fcn_count == 0) + smb_fem_fcn_uninstall(node); + mutex_exit(&fcn->fcn_mutex); +} + void -smb_node_notify_change(smb_node_t *node) +smb_node_notify_change(smb_node_t *node, uint_t action, const char *name) { SMB_NODE_VALID(node); - if (node->flags & NODE_FLAGS_NOTIFY_CHANGE) { - node->flags |= NODE_FLAGS_CHANGED; - smb_process_node_notify_change_queue(node); - } + smb_notify_event(node, action, name); + + /* + * These two events come as a pair: + * FILE_ACTION_RENAMED_OLD_NAME + * FILE_ACTION_RENAMED_NEW_NAME + * Only do the parent notify for "new". + */ + if (action == FILE_ACTION_RENAMED_OLD_NAME) + return; smb_node_notify_parents(node); } @@ -808,17 +845,17 @@ smb_node_notify_change(smb_node_t *node) void smb_node_notify_parents(smb_node_t *dnode) { - smb_node_t *pnode = dnode; + smb_node_t *pnode; /* parent */ SMB_NODE_VALID(dnode); + pnode = dnode->n_dnode; - while ((pnode = pnode->n_dnode) != NULL) { + while (pnode != NULL) { SMB_NODE_VALID(pnode); - if ((pnode->flags & NODE_FLAGS_NOTIFY_CHANGE) && - (pnode->flags & NODE_FLAGS_WATCH_TREE)) { - pnode->flags |= NODE_FLAGS_CHANGED; - smb_process_node_notify_change_queue(pnode); - } + smb_notify_event(pnode, 0, dnode->od_name); + /* cd .. */ + dnode = pnode; + pnode = dnode->n_dnode; } } @@ -1140,6 +1177,9 @@ smb_node_constructor(void *buf, void *un, int kmflags) offsetof(smb_ofile_t, f_nnd)); smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t), offsetof(smb_lock_t, l_lnd)); + mutex_init(&node->n_fcn.fcn_mutex, NULL, MUTEX_DEFAULT, NULL); + list_create(&node->n_fcn.fcn_watchers, sizeof (smb_request_t), + offsetof(smb_request_t, sr_ncr.nc_lnd)); cv_init(&node->n_oplock.ol_cv, NULL, CV_DEFAULT, NULL); mutex_init(&node->n_oplock.ol_mutex, NULL, MUTEX_DEFAULT, NULL); list_create(&node->n_oplock.ol_grants, sizeof (smb_oplock_grant_t), @@ -1165,6 +1205,8 @@ smb_node_destructor(void *buf, void *un) rw_destroy(&node->n_lock); cv_destroy(&node->n_oplock.ol_cv); mutex_destroy(&node->n_oplock.ol_mutex); + list_destroy(&node->n_fcn.fcn_watchers); + mutex_destroy(&node->n_fcn.fcn_mutex); smb_llist_destructor(&node->n_lock_list); smb_llist_destructor(&node->n_ofile_list); list_destroy(&node->n_oplock.ol_grants); @@ -1416,9 +1458,12 @@ smb_node_setattr(smb_request_t *sr, smb_node_t *node, if (tmp_attr.sa_mask) smb_node_set_cached_timestamps(node, &tmp_attr); - if (tmp_attr.sa_mask & SMB_AT_MTIME || explicit_times & SMB_AT_MTIME) { - if (node->n_dnode != NULL) - smb_node_notify_change(node->n_dnode); + if ((tmp_attr.sa_mask & SMB_AT_MTIME) || + (explicit_times & SMB_AT_MTIME)) { + if (node->n_dnode != NULL) { + smb_node_notify_change(node->n_dnode, + FILE_ACTION_MODIFIED, node->od_name); + } } return (0); diff --git a/usr/src/uts/common/fs/smbsrv/smb_nt_cancel.c b/usr/src/uts/common/fs/smbsrv/smb_nt_cancel.c index 1e4d9df89285..35bdf74b0d93 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_nt_cancel.c +++ b/usr/src/uts/common/fs/smbsrv/smb_nt_cancel.c @@ -21,6 +21,7 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * Copyright 2012 Nexenta Systems, Inc. All rights reserved. */ /* @@ -79,9 +80,5 @@ smb_com_nt_cancel(smb_request_t *sr) } smb_slist_exit(&session->s_req_list); - /* Now, search the notify change queue to find the request */ - - smb_reply_specific_cancel_request(sr); - return (SDRC_NO_REPLY); } diff --git a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c index 2efd4cba5aa1..4b6befa344d6 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c +++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c @@ -20,8 +20,8 @@ */ /* - * Copyright 2011 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012 Nexenta Systems, Inc. All rights reserved. */ /* @@ -113,86 +113,50 @@ #include #include -static void smb_notify_change_daemon(smb_thread_t *, void *); - -static boolean_t smb_notify_initialized = B_FALSE; -static smb_slist_t smb_ncr_list; -static smb_slist_t smb_nce_list; -static smb_thread_t smb_thread_notify_daemon; - /* - * smb_notify_init - * - * This function is not multi-thread safe. The caller must make sure only one - * thread makes the call. + * We add this flag to the CompletionFilter (see above) when the + * client sets WatchTree. Must not overlap FILE_NOTIFY_VALID_MASK. */ -int -smb_notify_init(void) -{ - int rc; - - if (smb_notify_initialized) - return (0); - - smb_slist_constructor(&smb_ncr_list, sizeof (smb_request_t), - offsetof(smb_request_t, sr_ncr.nc_lnd)); - - smb_slist_constructor(&smb_nce_list, sizeof (smb_request_t), - offsetof(smb_request_t, sr_ncr.nc_lnd)); +#define NODE_FLAGS_WATCH_TREE 0x10000000 +#if (NODE_FLAGS_WATCH_TREE & FILE_NOTIFY_VALID_MASK) +#error "NODE_FLAGS_WATCH_TREE" +#endif - smb_thread_init(&smb_thread_notify_daemon, - "smb_notify_change_daemon", smb_notify_change_daemon, NULL); - - rc = smb_thread_start(&smb_thread_notify_daemon); - if (rc) { - smb_thread_destroy(&smb_thread_notify_daemon); - smb_slist_destructor(&smb_ncr_list); - smb_slist_destructor(&smb_nce_list); - return (rc); - } - - smb_notify_initialized = B_TRUE; - - return (0); -} - -/* - * smb_notify_fini - * - * This function is not multi-thread safe. The caller must make sure only one - * thread makes the call. - */ -void -smb_notify_fini(void) -{ - if (!smb_notify_initialized) - return; +static void smb_notify_sr(smb_request_t *, uint_t, const char *); - smb_thread_stop(&smb_thread_notify_daemon); - smb_thread_destroy(&smb_thread_notify_daemon); - smb_slist_destructor(&smb_ncr_list); - smb_slist_destructor(&smb_nce_list); - smb_notify_initialized = B_FALSE; -} +static int smb_notify_encode_action(struct smb_request *, struct smb_xa *, + uint32_t, char *); /* * 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. + * Handle and SMB NT transact NOTIFY CHANGE request. + * Basically, wait until "something has changed", and either + * return information about what changed, or return a special + * error telling the client "many things changed". + * + * The implementation uses a per-node list of waiting notify + * requests like this one, each with a blocked worker thead. + * Later, FEM and/or smbsrv events wake these threads, which + * then send the reply to the client. */ smb_sdrc_t -smb_nt_transact_notify_change(struct smb_request *sr, struct smb_xa *xa) +smb_nt_transact_notify_change(smb_request_t *sr, struct smb_xa *xa) { uint32_t CompletionFilter; unsigned char WatchTree; + smb_error_t err; + int rc; smb_node_t *node; if (smb_mbc_decodef(&xa->req_setup_mb, "lwb", - &CompletionFilter, &sr->smb_fid, &WatchTree) != 0) - return (SDRC_NOT_IMPLEMENTED); + &CompletionFilter, &sr->smb_fid, &WatchTree) != 0) { + smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0); + return (SDRC_ERROR); + } + CompletionFilter &= FILE_NOTIFY_VALID_MASK; + if (WatchTree) + CompletionFilter |= NODE_FLAGS_WATCH_TREE; smbsr_lookup_file(sr); if (sr->fid_ofile == NULL) { @@ -201,7 +165,6 @@ smb_nt_transact_notify_change(struct smb_request *sr, struct smb_xa *xa) } node = sr->fid_ofile->f_node; - if (node == NULL || !smb_node_is_dir(node)) { /* * Notify change requests are only valid on directories. @@ -210,133 +173,70 @@ smb_nt_transact_notify_change(struct smb_request *sr, struct smb_xa *xa) return (SDRC_ERROR); } + /* + * Prepare to receive event data. + */ + sr->sr_ncr.nc_flags = CompletionFilter; + ASSERT(sr->sr_ncr.nc_action == 0); + ASSERT(sr->sr_ncr.nc_fname == NULL); + sr->sr_ncr.nc_fname = kmem_zalloc(MAXNAMELEN, KM_SLEEP); + + /* + * Subscribe to events on this node. + */ + smb_node_fcn_subscribe(node, sr); + + /* + * Wait for subscribed events to arrive. + * Expect SMB_REQ_STATE_EVENT_OCCURRED + * or SMB_REQ_STATE_CANCELED when signaled. + * Note it's possible (though rare) to already + * have SMB_REQ_STATE_CANCELED here. + */ 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); + if (sr->sr_state == SMB_REQ_STATE_ACTIVE) + sr->sr_state = SMB_REQ_STATE_WAITING_EVENT; + while (sr->sr_state == SMB_REQ_STATE_WAITING_EVENT) { + cv_wait(&sr->sr_ncr.nc_cv, &sr->sr_mutex); } -} - -/* - * smb_reply_notify_change_request - * - * This function sends appropriate response to an already queued NOTIFY CHANGE - * request. If node is changed (reply == NODE_FLAGS_CHANGED), a normal reply is - * sent. - * If client cancels the request or session dropped, an NT_STATUS_CANCELED - * is sent in reply. - */ - -void -smb_reply_notify_change_request(smb_request_t *sr) -{ - smb_node_t *node; - smb_srqueue_t *srq; - int total_bytes, n_setup, n_param, n_data; - int param_off, param_pad, data_off, data_pad; - struct smb_xa *xa; - smb_error_t err; - - SMB_REQ_VALID(sr); - srq = sr->session->s_srqueue; - smb_srqueue_waitq_to_runq(srq); + if (sr->sr_state == SMB_REQ_STATE_EVENT_OCCURRED) + sr->sr_state = SMB_REQ_STATE_ACTIVE; + mutex_exit(&sr->sr_mutex); - xa = sr->r_xa; - node = sr->sr_ncr.nc_node; + /* + * Unsubscribe from events on this node. + */ + smb_node_fcn_unsubscribe(node, sr); - if (--node->waiting_event == 0) { - node->flags &= ~(NODE_FLAGS_NOTIFY_CHANGE | NODE_FLAGS_CHANGED); - smb_fem_fcn_uninstall(node); - } + /* + * Build the reply + */ - mutex_enter(&sr->sr_mutex); switch (sr->sr_state) { - case SMB_REQ_STATE_EVENT_OCCURRED: - sr->sr_state = SMB_REQ_STATE_ACTIVE; - - /* many things changed */ - - (void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0L); - - /* setup the NT transact reply */ - - n_setup = MBC_LENGTH(&xa->rep_setup_mb); - n_param = MBC_LENGTH(&xa->rep_param_mb); - n_data = MBC_LENGTH(&xa->rep_data_mb); - - n_setup = (n_setup + 1) / 2; /* Convert to setup words */ - param_pad = 1; /* must be one */ - param_off = param_pad + 32 + 37 + (n_setup << 1) + 2; - /* Pad to 4 bytes */ - data_pad = (4 - ((param_off + n_param) & 3)) % 4; - /* Param off from hdr */ - data_off = param_off + n_param + data_pad; - total_bytes = param_pad + n_param + data_pad + n_data; - - (void) smbsr_encode_result(sr, 18+n_setup, total_bytes, - "b3.llllllllbCw#.C#.C", - 18 + n_setup, /* wct */ - n_param, /* Total Parameter Bytes */ - n_data, /* Total Data Bytes */ - n_param, /* Total Parameter Bytes this buffer */ - param_off, /* Param offset from header start */ - 0, /* Param displacement */ - n_data, /* Total Data Bytes this buffer */ - data_off, /* Data offset from header start */ - 0, /* Data displacement */ - n_setup, /* suwcnt */ - &xa->rep_setup_mb, /* setup[] */ - total_bytes, /* Total data bytes */ - param_pad, - &xa->rep_param_mb, - data_pad, - &xa->rep_data_mb); + case SMB_REQ_STATE_ACTIVE: + /* + * If we have event data, marshall it now, else just + * say "many things changed". Note that when we are + * woken by a WatchTree event (action == 0) then we + * don't have true event details, and only know the + * directory under which something changed. In that + * case we just say "many things changed". + */ + if (sr->sr_ncr.nc_action != 0 && 0 == + smb_notify_encode_action(sr, xa, + sr->sr_ncr.nc_action, sr->sr_ncr.nc_fname)) { + rc = SDRC_SUCCESS; + break; + } + /* + * This error says "many things changed". + */ + err.status = NT_STATUS_NOTIFY_ENUM_DIR; + err.errcls = ERRDOS; + err.errcode = ERROR_NOTIFY_ENUM_DIR; + smbsr_set_error(sr, &err); + rc = SDRC_ERROR; break; case SMB_REQ_STATE_CANCELED: @@ -344,284 +244,226 @@ smb_reply_notify_change_request(smb_request_t *sr) err.errcls = ERRDOS; err.errcode = ERROR_OPERATION_ABORTED; smbsr_set_error(sr, &err); - - (void) smb_mbc_encodef(&sr->reply, "bwbw", - (short)0, 0L, (short)0, 0L); - sr->smb_wct = 0; - sr->smb_bcc = 0; + rc = SDRC_ERROR; break; + default: ASSERT(0); + err.status = NT_STATUS_INTERNAL_ERROR; + err.errcls = ERRDOS; + err.errcode = ERROR_INTERNAL_ERROR; + smbsr_set_error(sr, &err); + rc = SDRC_ERROR; + break; } - mutex_exit(&sr->sr_mutex); - /* Setup the header */ - (void) smb_mbc_poke(&sr->reply, 0, SMB_HEADER_ED_FMT, - sr->first_smb_com, - sr->smb_rcls, - sr->smb_reh, - sr->smb_err, - sr->smb_flg | SMB_FLAGS_REPLY, - sr->smb_flg2, - sr->smb_pid_high, - sr->smb_sig, - sr->smb_tid, - sr->smb_pid, - sr->smb_uid, - sr->smb_mid); - - if (sr->session->signing.flags & SMB_SIGNING_ENABLED) - smb_sign_reply(sr, NULL); - - /* send the reply */ - DTRACE_PROBE1(ncr__reply, struct smb_request *, sr) - (void) smb_session_send(sr->session, 0, &sr->reply); - smbsr_cleanup(sr); + if (sr->sr_ncr.nc_fname != NULL) { + kmem_free(sr->sr_ncr.nc_fname, MAXNAMELEN); + sr->sr_ncr.nc_fname = NULL; + } - mutex_enter(&sr->sr_mutex); - sr->sr_state = SMB_REQ_STATE_COMPLETED; - mutex_exit(&sr->sr_mutex); - smb_srqueue_runq_exit(srq); - smb_request_free(sr); + return (rc); } /* - * smb_process_session_notify_change_queue + * Encode a FILE_NOTIFY_INFORMATION struct. * - * This function traverses notify change request queue and sends - * cancel replies to all of requests that are related to a specific - * session. + * We only ever put one of these in a response, so this + * does not bother handling appending additional ones. */ -void -smb_process_session_notify_change_queue( - smb_session_t *session, - smb_tree_t *tree) +static int +smb_notify_encode_action(struct smb_request *sr, struct smb_xa *xa, + uint32_t action, char *fname) { - smb_request_t *sr; - smb_request_t *tmp; - boolean_t sig = B_FALSE; + uint32_t namelen; + int rc; - smb_slist_enter(&smb_ncr_list); - smb_slist_enter(&smb_nce_list); - sr = smb_slist_head(&smb_ncr_list); - while (sr) { - ASSERT(sr->sr_magic == SMB_REQ_MAGIC); - tmp = smb_slist_next(&smb_ncr_list, sr); - if ((sr->session == session) && - (tree == NULL || sr->tid_tree == tree)) { - mutex_enter(&sr->sr_mutex); - switch (sr->sr_state) { - case SMB_REQ_STATE_WAITING_EVENT: - smb_slist_obj_move( - &smb_nce_list, - &smb_ncr_list, - sr); - smb_srqueue_waitq_enter( - sr->session->s_srqueue); - sr->sr_state = SMB_REQ_STATE_CANCELED; - sig = B_TRUE; - break; - default: - ASSERT(0); - break; - } - mutex_exit(&sr->sr_mutex); - } - sr = tmp; - } - smb_slist_exit(&smb_nce_list); - smb_slist_exit(&smb_ncr_list); - if (sig) - smb_thread_signal(&smb_thread_notify_daemon); -} + if (action < FILE_ACTION_ADDED || + action > FILE_ACTION_MODIFIED_STREAM) + return (-1); -/* - * smb_process_file_notify_change_queue - * - * This function traverses notify change request queue and sends - * cancel replies to all of requests that are related to the - * specified file. - */ -void -smb_process_file_notify_change_queue(struct smb_ofile *of) -{ - smb_request_t *sr; - smb_request_t *tmp; - boolean_t sig = B_FALSE; + namelen = smb_ascii_or_unicode_strlen(sr, fname); + if (namelen == 0) + return (-1); - smb_slist_enter(&smb_ncr_list); - smb_slist_enter(&smb_nce_list); - sr = smb_slist_head(&smb_ncr_list); - while (sr) { - ASSERT(sr->sr_magic == SMB_REQ_MAGIC); - tmp = smb_slist_next(&smb_ncr_list, sr); - if (sr->fid_ofile == of) { - mutex_enter(&sr->sr_mutex); - switch (sr->sr_state) { - case SMB_REQ_STATE_WAITING_EVENT: - smb_slist_obj_move(&smb_nce_list, - &smb_ncr_list, sr); - smb_srqueue_waitq_enter( - sr->session->s_srqueue); - sr->sr_state = SMB_REQ_STATE_CANCELED; - sig = B_TRUE; - break; - default: - ASSERT(0); - break; - } - mutex_exit(&sr->sr_mutex); - } - sr = tmp; - } - smb_slist_exit(&smb_nce_list); - smb_slist_exit(&smb_ncr_list); - if (sig) - smb_thread_signal(&smb_thread_notify_daemon); + rc = smb_mbc_encodef(&xa->rep_data_mb, "%lllu", sr, + 0, /* NextEntryOffset */ + action, namelen, fname); + return (rc); } /* - * smb_reply_specific_cancel_request + * smb_notify_file_closed * - * This function searches global request list for a specific request. If found, - * moves the request to event queue and kicks the notify change daemon. + * Cancel any change-notify calls on this open file. */ - void -smb_reply_specific_cancel_request(struct smb_request *zsr) +smb_notify_file_closed(struct smb_ofile *of) { + smb_session_t *ses; smb_request_t *sr; - smb_request_t *tmp; - boolean_t sig = B_FALSE; + smb_slist_t *list; - smb_slist_enter(&smb_ncr_list); - smb_slist_enter(&smb_nce_list); - sr = smb_slist_head(&smb_ncr_list); + SMB_OFILE_VALID(of); + ses = of->f_session; + SMB_SESSION_VALID(ses); + list = &ses->s_req_list; + + smb_slist_enter(list); + + sr = smb_slist_head(list); while (sr) { - ASSERT(sr->sr_magic == SMB_REQ_MAGIC); - tmp = smb_slist_next(&smb_ncr_list, sr); - if ((sr->session == zsr->session) && - (sr->smb_uid == zsr->smb_uid) && - (sr->smb_pid == zsr->smb_pid) && - (sr->smb_tid == zsr->smb_tid) && - (sr->smb_mid == zsr->smb_mid)) { - mutex_enter(&sr->sr_mutex); - switch (sr->sr_state) { - case SMB_REQ_STATE_WAITING_EVENT: - smb_slist_obj_move(&smb_nce_list, - &smb_ncr_list, sr); - smb_srqueue_waitq_enter( - sr->session->s_srqueue); - sr->sr_state = SMB_REQ_STATE_CANCELED; - sig = B_TRUE; - break; - default: - ASSERT(0); - break; - } - mutex_exit(&sr->sr_mutex); + SMB_REQ_VALID(sr); + if (sr->sr_state == SMB_REQ_STATE_WAITING_EVENT && + sr->fid_ofile == of) { + smb_request_cancel(sr); } - sr = tmp; + sr = smb_slist_next(list, sr); } - smb_slist_exit(&smb_nce_list); - smb_slist_exit(&smb_ncr_list); - if (sig) - smb_thread_signal(&smb_thread_notify_daemon); + + smb_slist_exit(list); } + /* - * smb_process_node_notify_change_queue + * smb_notify_event + * + * Post an event to the watchers on a given node. + * + * This makes one exception for RENAME, where we expect a + * pair of events for the {old,new} directory element names. + * This only delivers an event for the "new" name. + * + * The event delivery mechanism does not implement delivery of + * multiple events for one "NT Notify" call. One could do that, + * but modern clients don't actually use the event data. They + * set a max. received data size of zero, which means we discard + * the data and send the special "lots changed" error instead. + * Given that, there's not really any point in implementing the + * delivery of multiple events. In fact, we don't even need to + * implement single event delivery, but do so for completeness, + * for debug convenience, and to be nice to older clients that + * may actually want some event data instead of the error. * - * This function searches notify change request queue and sends - * 'NODE MODIFIED' reply to all requests which are related to a - * specific node. - * WatchTree flag: We handle this flag in a special manner just - * for DAVE clients. When something is changed, we notify all - * requests which came from DAVE clients on the same volume which - * has been modified. We don't care about the tree that they wanted - * us to monitor. any change in any part of the volume will lead - * to notifying all notify change requests from DAVE clients on the - * different parts of the volume hierarchy. + * Given that we only deliver a single event for an "NT Notify" + * caller, we want to deliver the "new" name event. (The "old" + * name event is less important, even ignored by some clients.) + * Since we know these are delivered in pairs, we can simply + * discard the "old" name event, knowing that the "new" name + * event will be delivered immediately afterwards. + * + * So, why do event sources post the "old name" event at all? + * (1) For debugging, so we see both {old,new} names here. + * (2) If in the future someone decides to implement the + * delivery of both {old,new} events, the changes can be + * mostly isolated to this file. */ void -smb_process_node_notify_change_queue(smb_node_t *node) +smb_notify_event(smb_node_t *node, uint_t action, const char *name) { smb_request_t *sr; - smb_request_t *tmp; - smb_node_t *nc_node; - boolean_t sig = B_FALSE; + smb_node_fcn_t *fcn; - ASSERT(node->n_magic == SMB_NODE_MAGIC); + SMB_NODE_VALID(node); + fcn = &node->n_fcn; - if (!(node->flags & NODE_FLAGS_NOTIFY_CHANGE)) - return; + if (action == FILE_ACTION_RENAMED_OLD_NAME) + return; /* see above */ - node->flags |= NODE_FLAGS_CHANGED; + mutex_enter(&fcn->fcn_mutex); - smb_slist_enter(&smb_ncr_list); - smb_slist_enter(&smb_nce_list); - sr = smb_slist_head(&smb_ncr_list); + sr = list_head(&fcn->fcn_watchers); while (sr) { - ASSERT(sr->sr_magic == SMB_REQ_MAGIC); - tmp = smb_slist_next(&smb_ncr_list, sr); - - nc_node = sr->sr_ncr.nc_node; - if (nc_node == node) { - mutex_enter(&sr->sr_mutex); - switch (sr->sr_state) { - case SMB_REQ_STATE_WAITING_EVENT: - smb_slist_obj_move(&smb_nce_list, - &smb_ncr_list, sr); - smb_srqueue_waitq_enter( - sr->session->s_srqueue); - sr->sr_state = SMB_REQ_STATE_EVENT_OCCURRED; - sig = B_TRUE; - break; - default: - ASSERT(0); - break; - } - mutex_exit(&sr->sr_mutex); - } - sr = tmp; + smb_notify_sr(sr, action, name); + sr = list_next(&fcn->fcn_watchers, sr); } - smb_slist_exit(&smb_nce_list); - smb_slist_exit(&smb_ncr_list); - if (sig) - smb_thread_signal(&smb_thread_notify_daemon); + + mutex_exit(&fcn->fcn_mutex); } /* - * smb_notify_change_daemon + * What completion filter (masks) apply to each of the + * FILE_ACTION_... events. + */ +static const uint32_t +smb_notify_action_mask[] = { + /* 0: Special, used by smb_node_notify_parents() */ + NODE_FLAGS_WATCH_TREE, + + /* FILE_ACTION_ADDED */ + FILE_NOTIFY_CHANGE_NAME, + + /* FILE_ACTION_REMOVED */ + FILE_NOTIFY_CHANGE_NAME, + + /* FILE_ACTION_MODIFIED */ + FILE_NOTIFY_CHANGE_ATTRIBUTES | + FILE_NOTIFY_CHANGE_SIZE | + FILE_NOTIFY_CHANGE_LAST_WRITE | + FILE_NOTIFY_CHANGE_LAST_ACCESS | + FILE_NOTIFY_CHANGE_CREATION | + FILE_NOTIFY_CHANGE_EA | + FILE_NOTIFY_CHANGE_SECURITY, + + /* FILE_ACTION_RENAMED_OLD_NAME */ + FILE_NOTIFY_CHANGE_NAME, + + /* FILE_ACTION_RENAMED_NEW_NAME */ + FILE_NOTIFY_CHANGE_NAME, + + /* FILE_ACTION_ADDED_STREAM */ + FILE_NOTIFY_CHANGE_STREAM_NAME, + + /* FILE_ACTION_REMOVED_STREAM */ + FILE_NOTIFY_CHANGE_STREAM_NAME, + + /* FILE_ACTION_MODIFIED_STREAM */ + FILE_NOTIFY_CHANGE_STREAM_SIZE | + FILE_NOTIFY_CHANGE_STREAM_WRITE, +}; +static const int smb_notify_action_nelm = + sizeof (smb_notify_action_mask) / + sizeof (smb_notify_action_mask[0]); + +/* + * smb_notify_sr * - * This function processes notify change event list and send appropriate - * responses to the requests. This function executes in the system as an - * indivdual thread. + * Post an event to an smb request waiting on some node. + * + * Note that node->fcn.mutex is held. This implies a + * lock order: node->fcn.mutex, then sr_mutex */ static void -smb_notify_change_daemon(smb_thread_t *thread, void *arg) +smb_notify_sr(smb_request_t *sr, uint_t action, const char *name) { - _NOTE(ARGUNUSED(arg)) + smb_notify_change_req_t *ncr; + uint32_t mask; - smb_request_t *sr; - smb_request_t *tmp; - list_t sr_list; - - list_create(&sr_list, sizeof (smb_request_t), - offsetof(smb_request_t, sr_ncr.nc_lnd)); - - while (smb_thread_continue(thread)) { - - while (smb_slist_move_tail(&sr_list, &smb_nce_list)) { - sr = list_head(&sr_list); - while (sr) { - ASSERT(sr->sr_magic == SMB_REQ_MAGIC); - tmp = list_next(&sr_list, sr); - list_remove(&sr_list, sr); - smb_reply_notify_change_request(sr); - sr = tmp; - } - } + SMB_REQ_VALID(sr); + ncr = &sr->sr_ncr; + + /* + * Compute the completion filter mask bits for which + * we will signal waiting notify requests. + */ + if (action >= smb_notify_action_nelm) { + ASSERT(0); + return; } - list_destroy(&sr_list); + mask = smb_notify_action_mask[action]; + + mutex_enter(&sr->sr_mutex); + if (sr->sr_state == SMB_REQ_STATE_WAITING_EVENT && + (ncr->nc_flags & mask) != 0) { + sr->sr_state = SMB_REQ_STATE_EVENT_OCCURRED; + /* + * Save event data in the sr_ncr field so the + * reply handler can return it. + */ + ncr->nc_action = action; + if (name != NULL) + (void) strlcpy(ncr->nc_fname, name, MAXNAMELEN); + cv_signal(&ncr->nc_cv); + } + mutex_exit(&sr->sr_mutex); } diff --git a/usr/src/uts/common/fs/smbsrv/smb_ofile.c b/usr/src/uts/common/fs/smbsrv/smb_ofile.c index 6855a795bded..39635170e93f 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_ofile.c +++ b/usr/src/uts/common/fs/smbsrv/smb_ofile.c @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012 Nexenta Systems, Inc. All rights reserved. */ /* @@ -324,11 +325,11 @@ smb_ofile_close(smb_ofile_t *of, uint32_t last_wtime) of->f_cr); /* - * Cancel any notify change requests related - * to this open instance. + * Cancel any notify change requests that + * may be using this open instance. */ - if (of->f_node->flags & NODE_FLAGS_NOTIFY_CHANGE) - smb_process_file_notify_change_queue(of); + if (of->f_node->n_fcn.fcn_count) + smb_notify_file_closed(of); smb_server_dec_files(of->f_server); } atomic_dec_32(&of->f_tree->t_open_files); diff --git a/usr/src/uts/common/fs/smbsrv/smb_rename.c b/usr/src/uts/common/fs/smbsrv/smb_rename.c index ca09cf493557..8541fdc847e2 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_rename.c +++ b/usr/src/uts/common/fs/smbsrv/smb_rename.c @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012 Nexenta Systems, Inc. All rights reserved. */ #include @@ -480,10 +481,25 @@ smb_common_rename(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi) src_dnode, src_fnode->od_name, dst_dnode, new_name); - smb_rename_release_src(sr); + if (rc == 0) { + /* + * Note that renames in the same directory are normally + * delivered in {old,new} pairs, and clients expect them + * in that order, if both events are delivered. + */ + int a_src, a_dst; /* action codes */ + if (src_dnode == dst_dnode) { + a_src = FILE_ACTION_RENAMED_OLD_NAME; + a_dst = FILE_ACTION_RENAMED_NEW_NAME; + } else { + a_src = FILE_ACTION_REMOVED; + a_dst = FILE_ACTION_ADDED; + } + smb_node_notify_change(src_dnode, a_src, src_fnode->od_name); + smb_node_notify_change(dst_dnode, a_dst, new_name); + } - if (rc == 0) - smb_node_notify_change(dst_dnode); + smb_rename_release_src(sr); if (dst_fqi->fq_fnode) { smb_node_end_crit(dst_fnode); @@ -617,9 +633,12 @@ smb_make_link(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi) rc = smb_fsop_link(sr, sr->user_cr, src_fqi->fq_fnode, dst_fqi->fq_dnode, dst_fqi->fq_last_comp); + if (rc == 0) { + smb_node_notify_change(dst_fqi->fq_dnode, + FILE_ACTION_ADDED, dst_fqi->fq_last_comp); + } + smb_rename_release_src(sr); - if (rc == 0) - smb_node_notify_change(dst_fqi->fq_dnode); smb_node_release(dst_fqi->fq_dnode); return (rc); } diff --git a/usr/src/uts/common/fs/smbsrv/smb_server.c b/usr/src/uts/common/fs/smbsrv/smb_server.c index 9eeb7d8d50d1..3654744569c4 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_server.c +++ b/usr/src/uts/common/fs/smbsrv/smb_server.c @@ -294,8 +294,6 @@ smb_server_svc_init(void) continue; if (rc = smb_fem_init()) continue; - if (rc = smb_notify_init()) - continue; if (rc = smb_net_init()) continue; smb_llist_init(); @@ -306,7 +304,6 @@ smb_server_svc_init(void) smb_llist_fini(); smb_net_fini(); - smb_notify_fini(); smb_fem_fini(); smb_node_fini(); smb_vop_fini(); @@ -328,7 +325,6 @@ smb_server_svc_fini(void) if (smb_llist_get_count(&smb_servers) == 0) { smb_llist_fini(); smb_net_fini(); - smb_notify_fini(); smb_fem_fini(); smb_node_fini(); smb_oplock_fini(); diff --git a/usr/src/uts/common/fs/smbsrv/smb_session.c b/usr/src/uts/common/fs/smbsrv/smb_session.c index 6e1bd6d69a4e..f2a337158f26 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_session.c +++ b/usr/src/uts/common/fs/smbsrv/smb_session.c @@ -19,8 +19,8 @@ * CDDL HEADER END */ /* - * Copyright 2011 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012 Nexenta Systems, Inc. All rights reserved. */ #include #include @@ -392,13 +392,14 @@ smb_request_cancel(smb_request_t *sr) break; case SMB_REQ_STATE_WAITING_EVENT: - case SMB_REQ_STATE_EVENT_OCCURRED: /* - * Cancellations for these states are handled by the - * notify-change code + * This request is waiting in change notify. */ + sr->sr_state = SMB_REQ_STATE_CANCELED; + cv_signal(&sr->sr_ncr.nc_cv); break; + case SMB_REQ_STATE_EVENT_OCCURRED: case SMB_REQ_STATE_COMPLETED: case SMB_REQ_STATE_CANCELED: /* @@ -785,8 +786,6 @@ smb_session_cancel_requests( { smb_request_t *sr; - smb_process_session_notify_change_queue(session, tree); - smb_slist_enter(&session->s_req_list); sr = smb_slist_head(&session->s_req_list); @@ -1076,6 +1075,7 @@ smb_request_alloc(smb_session_t *session, int req_length) bzero(sr, sizeof (smb_request_t)); mutex_init(&sr->sr_mutex, NULL, MUTEX_DEFAULT, NULL); + cv_init(&sr->sr_ncr.nc_cv, NULL, CV_DEFAULT, NULL); smb_srm_init(sr); sr->session = session; sr->sr_server = session->s_server; @@ -1104,6 +1104,7 @@ smb_request_free(smb_request_t *sr) ASSERT(sr->sr_magic == SMB_REQ_MAGIC); ASSERT(sr->session); ASSERT(sr->r_xa == NULL); + ASSERT(sr->sr_ncr.nc_fname == NULL); if (sr->fid_ofile != NULL) { smb_ofile_request_complete(sr->fid_ofile); @@ -1132,6 +1133,7 @@ smb_request_free(smb_request_t *sr) m_freem(sr->raw_data.chain); sr->sr_magic = 0; + cv_destroy(&sr->sr_ncr.nc_cv); mutex_destroy(&sr->sr_mutex); kmem_cache_free(sr->sr_cache, sr); } diff --git a/usr/src/uts/common/smbsrv/smb_kproto.h b/usr/src/uts/common/smbsrv/smb_kproto.h index 7c5c9f3b3084..3006153d0824 100644 --- a/usr/src/uts/common/smbsrv/smb_kproto.h +++ b/usr/src/uts/common/smbsrv/smb_kproto.h @@ -173,9 +173,6 @@ SMB_COM_DECL(write_raw); SMB_NT_TRANSACT_DECL(nt_transact_create); -int smb_notify_init(void); -void smb_notify_fini(void); - smb_sdrc_t smb_nt_transact_notify_change(smb_request_t *, smb_xa_t *); smb_sdrc_t smb_nt_transact_query_security_info(smb_request_t *, smb_xa_t *); smb_sdrc_t smb_nt_transact_set_security_info(smb_request_t *, smb_xa_t *); @@ -208,8 +205,6 @@ void smb_close_all_connections(void); int smb_net_id(uint32_t); -void smb_process_file_notify_change_queue(smb_ofile_t *of); - /* * oplock functions - node operations */ @@ -446,7 +441,10 @@ uint32_t smb_node_open_check(smb_node_t *, uint32_t, uint32_t); DWORD smb_node_rename_check(smb_node_t *); DWORD smb_node_delete_check(smb_node_t *); boolean_t smb_node_share_check(smb_node_t *); -void smb_node_notify_change(smb_node_t *); + +void smb_node_fcn_subscribe(smb_node_t *, smb_request_t *); +void smb_node_fcn_unsubscribe(smb_node_t *, smb_request_t *); +void smb_node_notify_change(smb_node_t *, uint_t, const char *); void smb_node_notify_parents(smb_node_t *); int smb_node_getattr(smb_request_t *, smb_node_t *, smb_attr_t *); int smb_node_setattr(smb_request_t *, smb_node_t *, cred_t *, @@ -477,9 +475,9 @@ void smb_vfs_rele(smb_export_t *, vfs_t *); void smb_vfs_rele_all(smb_export_t *); /* NOTIFY CHANGE */ -void smb_process_session_notify_change_queue(smb_session_t *, smb_tree_t *); -void smb_process_node_notify_change_queue(smb_node_t *); -void smb_reply_specific_cancel_request(smb_request_t *); + +void smb_notify_event(smb_node_t *, uint_t, const char *); +void smb_notify_file_closed(smb_ofile_t *of); void smb_fem_fcn_install(smb_node_t *); void smb_fem_fcn_uninstall(smb_node_t *); diff --git a/usr/src/uts/common/smbsrv/smb_ktypes.h b/usr/src/uts/common/smbsrv/smb_ktypes.h index 4ce19673dee0..53bceab332dc 100644 --- a/usr/src/uts/common/smbsrv/smb_ktypes.h +++ b/usr/src/uts/common/smbsrv/smb_ktypes.h @@ -452,12 +452,18 @@ typedef struct { } smb_rwx_t; /* NOTIFY CHANGE */ +typedef struct smb_node_fcn { + kmutex_t fcn_mutex; + uint32_t fcn_count; + list_t fcn_watchers; /* smb_request_t, sr_ncr.nc_lnd */ +} smb_node_fcn_t; typedef struct smb_notify_change_req { - list_node_t nc_lnd; - struct smb_node *nc_node; - uint32_t nc_reply_type; + list_node_t nc_lnd; /* n_fcn.fcn_watchers */ + kcondvar_t nc_cv; /* prot: sr_mutex */ uint32_t nc_flags; + uint32_t nc_action; + char *nc_fname; } smb_notify_change_req_t; /* @@ -638,6 +644,7 @@ typedef struct smb_node { volatile int waiting_event; smb_times_t n_timestamps; u_offset_t n_allocsz; + smb_node_fcn_t n_fcn; smb_oplock_t n_oplock; struct smb_node *n_dnode; struct smb_node *n_unode; @@ -652,10 +659,6 @@ typedef struct smb_node { #define NODE_FLAGS_DFSLINK 0x00002000 #define NODE_FLAGS_VFSROOT 0x00004000 #define NODE_FLAGS_SYSTEM 0x00008000 -#define NODE_FLAGS_WATCH_TREE 0x10000000 -#define NODE_FLAGS_NOTIFY_CHANGE \ - (NODE_FLAGS_WATCH_TREE | FILE_NOTIFY_VALID_MASK) -#define NODE_FLAGS_CHANGED 0x08000000 #define NODE_FLAGS_WRITE_THROUGH 0x00100000 #define NODE_XATTR_DIR 0x01000000 #define NODE_FLAGS_DELETE_ON_CLOSE 0x40000000 @@ -1602,7 +1605,6 @@ typedef struct smb_request { kmutex_t sr_mutex; list_node_t sr_session_lnd; smb_req_state_t sr_state; - boolean_t sr_keep; kmem_cache_t *sr_cache; struct smb_server *sr_server; pid_t *sr_pid;