xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_notify.c (revision 5677e04907859594bfe1a95ba3bfdb1629b89dac)
1a90cf9f2SGordon Ross /*
2a90cf9f2SGordon Ross  * CDDL HEADER START
3a90cf9f2SGordon Ross  *
4a90cf9f2SGordon Ross  * The contents of this file are subject to the terms of the
5a90cf9f2SGordon Ross  * Common Development and Distribution License (the "License").
6a90cf9f2SGordon Ross  * You may not use this file except in compliance with the License.
7a90cf9f2SGordon Ross  *
8a90cf9f2SGordon Ross  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9a90cf9f2SGordon Ross  * or http://www.opensolaris.org/os/licensing.
10a90cf9f2SGordon Ross  * See the License for the specific language governing permissions
11a90cf9f2SGordon Ross  * and limitations under the License.
12a90cf9f2SGordon Ross  *
13a90cf9f2SGordon Ross  * When distributing Covered Code, include this CDDL HEADER in each
14a90cf9f2SGordon Ross  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15a90cf9f2SGordon Ross  * If applicable, add the following below this CDDL HEADER, with the
16a90cf9f2SGordon Ross  * fields enclosed by brackets "[]" replaced with your own identifying
17a90cf9f2SGordon Ross  * information: Portions Copyright [yyyy] [name of copyright owner]
18a90cf9f2SGordon Ross  *
19a90cf9f2SGordon Ross  * CDDL HEADER END
20a90cf9f2SGordon Ross  */
21a90cf9f2SGordon Ross 
22a90cf9f2SGordon Ross /*
23a90cf9f2SGordon Ross  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24*5677e049SGordon Ross  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
25a90cf9f2SGordon Ross  */
26a90cf9f2SGordon Ross 
27a90cf9f2SGordon Ross /*
28a90cf9f2SGordon Ross  * File Change Notification (FCN)
29a90cf9f2SGordon Ross  * Common parts shared by SMB1 & SMB2
30a90cf9f2SGordon Ross  */
31a90cf9f2SGordon Ross 
32a90cf9f2SGordon Ross /*
33a90cf9f2SGordon Ross  * This command notifies the client when the specified directory
34a90cf9f2SGordon Ross  * has changed, and optionally returns the names of files and
35a90cf9f2SGordon Ross  * directories that changed, and how they changed.  The caller
36a90cf9f2SGordon Ross  * specifies a "Completion Filter" to select which kinds of
37a90cf9f2SGordon Ross  * changes they want to know about.
38a90cf9f2SGordon Ross  *
39a90cf9f2SGordon Ross  * When a change that's in the CompletionFilter is made to the directory,
40a90cf9f2SGordon Ross  * the command completes.  The names of the files that have changed since
41a90cf9f2SGordon Ross  * the last time the command was issued are returned to the client.
42a90cf9f2SGordon Ross  * If too many files have changed since the last time the command was
43a90cf9f2SGordon Ross  * issued, then zero bytes are returned and an alternate status code
44a90cf9f2SGordon Ross  * is returned in the Status field of the response.
45a90cf9f2SGordon Ross  *
46a90cf9f2SGordon Ross  * The CompletionFilter is a mask created as the sum of any of the
47a90cf9f2SGordon Ross  * following flags:
48a90cf9f2SGordon Ross  *
49a90cf9f2SGordon Ross  * FILE_NOTIFY_CHANGE_FILE_NAME        0x00000001
50a90cf9f2SGordon Ross  * FILE_NOTIFY_CHANGE_DIR_NAME         0x00000002
51a90cf9f2SGordon Ross  * FILE_NOTIFY_CHANGE_NAME             0x00000003
52a90cf9f2SGordon Ross  * FILE_NOTIFY_CHANGE_ATTRIBUTES       0x00000004
53a90cf9f2SGordon Ross  * FILE_NOTIFY_CHANGE_SIZE             0x00000008
54a90cf9f2SGordon Ross  * FILE_NOTIFY_CHANGE_LAST_WRITE       0x00000010
55a90cf9f2SGordon Ross  * FILE_NOTIFY_CHANGE_LAST_ACCESS      0x00000020
56a90cf9f2SGordon Ross  * FILE_NOTIFY_CHANGE_CREATION         0x00000040
57a90cf9f2SGordon Ross  * FILE_NOTIFY_CHANGE_EA               0x00000080
58a90cf9f2SGordon Ross  * FILE_NOTIFY_CHANGE_SECURITY         0x00000100
59a90cf9f2SGordon Ross  * FILE_NOTIFY_CHANGE_STREAM_NAME      0x00000200
60a90cf9f2SGordon Ross  * FILE_NOTIFY_CHANGE_STREAM_SIZE      0x00000400
61a90cf9f2SGordon Ross  * FILE_NOTIFY_CHANGE_STREAM_WRITE     0x00000800
62a90cf9f2SGordon Ross  *
63a90cf9f2SGordon Ross  *
64a90cf9f2SGordon Ross  * The response contains FILE_NOTIFY_INFORMATION structures, as defined
65a90cf9f2SGordon Ross  * below.  The NextEntryOffset field of the structure specifies the offset,
66a90cf9f2SGordon Ross  * in bytes, from the start of the current entry to the next entry in the
67a90cf9f2SGordon Ross  * list.  If this is the last entry in the list, this field is zero.  Each
68a90cf9f2SGordon Ross  * entry in the list must be longword aligned, so NextEntryOffset must be a
69a90cf9f2SGordon Ross  * multiple of four.
70a90cf9f2SGordon Ross  *
71a90cf9f2SGordon Ross  * typedef struct {
72a90cf9f2SGordon Ross  *     ULONG NextEntryOffset;
73a90cf9f2SGordon Ross  *     ULONG Action;
74a90cf9f2SGordon Ross  *     ULONG FileNameLength;
75a90cf9f2SGordon Ross  *     WCHAR FileName[1];
76a90cf9f2SGordon Ross  * } FILE_NOTIFY_INFORMATION;
77a90cf9f2SGordon Ross  *
78a90cf9f2SGordon Ross  * Where Action describes what happened to the file named FileName:
79a90cf9f2SGordon Ross  *
80a90cf9f2SGordon Ross  * FILE_ACTION_ADDED            0x00000001
81a90cf9f2SGordon Ross  * FILE_ACTION_REMOVED          0x00000002
82a90cf9f2SGordon Ross  * FILE_ACTION_MODIFIED         0x00000003
83a90cf9f2SGordon Ross  * FILE_ACTION_RENAMED_OLD_NAME 0x00000004
84a90cf9f2SGordon Ross  * FILE_ACTION_RENAMED_NEW_NAME 0x00000005
85a90cf9f2SGordon Ross  * FILE_ACTION_ADDED_STREAM     0x00000006
86a90cf9f2SGordon Ross  * FILE_ACTION_REMOVED_STREAM   0x00000007
87a90cf9f2SGordon Ross  * FILE_ACTION_MODIFIED_STREAM  0x00000008
88a90cf9f2SGordon Ross  */
89a90cf9f2SGordon Ross 
90a90cf9f2SGordon Ross #include <smbsrv/smb_kproto.h>
91a90cf9f2SGordon Ross #include <sys/sdt.h>
92a90cf9f2SGordon Ross 
93a90cf9f2SGordon Ross static void smb_notify_sr(smb_request_t *, uint_t, const char *);
94a90cf9f2SGordon Ross static uint32_t smb_notify_encode_action(struct smb_request *,
95a90cf9f2SGordon Ross 	mbuf_chain_t *, uint32_t, char *);
96a90cf9f2SGordon Ross 
97*5677e049SGordon Ross /*
98*5677e049SGordon Ross  * Cancel method for smb_notify_common()
99*5677e049SGordon Ross  *
100*5677e049SGordon Ross  * This request is waiting in change notify.
101*5677e049SGordon Ross  */
102*5677e049SGordon Ross static void
103*5677e049SGordon Ross smb_notify_cancel(smb_request_t *sr)
104*5677e049SGordon Ross {
105*5677e049SGordon Ross 	cv_signal(&sr->sr_ncr.nc_cv);
106*5677e049SGordon Ross }
107*5677e049SGordon Ross 
108a90cf9f2SGordon Ross uint32_t
109a90cf9f2SGordon Ross smb_notify_common(smb_request_t *sr, mbuf_chain_t *mbc,
110a90cf9f2SGordon Ross 	uint32_t CompletionFilter)
111a90cf9f2SGordon Ross {
112a90cf9f2SGordon Ross 	smb_notify_change_req_t *nc;
113a90cf9f2SGordon Ross 	smb_node_t	*node;
114a90cf9f2SGordon Ross 	uint32_t	status;
115a90cf9f2SGordon Ross 
116a90cf9f2SGordon Ross 	if (sr->fid_ofile == NULL)
117a90cf9f2SGordon Ross 		return (NT_STATUS_INVALID_HANDLE);
118a90cf9f2SGordon Ross 
119a90cf9f2SGordon Ross 	node = sr->fid_ofile->f_node;
120a90cf9f2SGordon Ross 	if (node == NULL || !smb_node_is_dir(node)) {
121a90cf9f2SGordon Ross 		/*
122a90cf9f2SGordon Ross 		 * Notify change is only valid on directories.
123a90cf9f2SGordon Ross 		 */
124a90cf9f2SGordon Ross 		return (NT_STATUS_INVALID_PARAMETER);
125a90cf9f2SGordon Ross 	}
126a90cf9f2SGordon Ross 
127a90cf9f2SGordon Ross 	/*
128a90cf9f2SGordon Ross 	 * Prepare to receive event data.
129a90cf9f2SGordon Ross 	 */
130a90cf9f2SGordon Ross 	nc = &sr->sr_ncr;
131a90cf9f2SGordon Ross 	nc->nc_flags = CompletionFilter;
132a90cf9f2SGordon Ross 	ASSERT(nc->nc_action == 0);
133a90cf9f2SGordon Ross 	ASSERT(nc->nc_fname == NULL);
134a90cf9f2SGordon Ross 	nc->nc_fname = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
135a90cf9f2SGordon Ross 
136a90cf9f2SGordon Ross 	/*
137a90cf9f2SGordon Ross 	 * Subscribe to events on this node.
138a90cf9f2SGordon Ross 	 */
139a90cf9f2SGordon Ross 	smb_node_fcn_subscribe(node, sr);
140a90cf9f2SGordon Ross 
141a90cf9f2SGordon Ross 	/*
142a90cf9f2SGordon Ross 	 * Wait for subscribed events to arrive.
143a90cf9f2SGordon Ross 	 * Expect SMB_REQ_STATE_EVENT_OCCURRED
144*5677e049SGordon Ross 	 * or SMB_REQ_STATE_CANCELLED when signaled.
145a90cf9f2SGordon Ross 	 * Note it's possible (though rare) to already
146*5677e049SGordon Ross 	 * have SMB_REQ_STATE_CANCELLED here.
147a90cf9f2SGordon Ross 	 */
148a90cf9f2SGordon Ross 	mutex_enter(&sr->sr_mutex);
149*5677e049SGordon Ross 	if (sr->sr_state == SMB_REQ_STATE_ACTIVE) {
150a90cf9f2SGordon Ross 		sr->sr_state = SMB_REQ_STATE_WAITING_EVENT;
151*5677e049SGordon Ross 		sr->cancel_method = smb_notify_cancel;
152*5677e049SGordon Ross 	}
153a90cf9f2SGordon Ross 	while (sr->sr_state == SMB_REQ_STATE_WAITING_EVENT) {
154a90cf9f2SGordon Ross 		cv_wait(&nc->nc_cv, &sr->sr_mutex);
155a90cf9f2SGordon Ross 	}
156*5677e049SGordon Ross 	sr->cancel_method = NULL;
157*5677e049SGordon Ross 
158*5677e049SGordon Ross 	switch (sr->sr_state) {
159*5677e049SGordon Ross 	case SMB_REQ_STATE_WAITING_EVENT:
160*5677e049SGordon Ross 	case SMB_REQ_STATE_EVENT_OCCURRED:
161*5677e049SGordon Ross 		/* normal wakeup */
162a90cf9f2SGordon Ross 		sr->sr_state = SMB_REQ_STATE_ACTIVE;
163*5677e049SGordon Ross 		status = 0;
164*5677e049SGordon Ross 		break;
165*5677e049SGordon Ross 
166*5677e049SGordon Ross 	case SMB_REQ_STATE_CANCEL_PENDING:
167*5677e049SGordon Ross 		/* cancelled via smb_notify_cancel */
168*5677e049SGordon Ross 		sr->sr_state = SMB_REQ_STATE_CANCELLED;
169*5677e049SGordon Ross 		status = NT_STATUS_CANCELLED;
170*5677e049SGordon Ross 		break;
171*5677e049SGordon Ross 
172*5677e049SGordon Ross 	case SMB_REQ_STATE_CANCELLED:
173*5677e049SGordon Ross 		/* cancelled before this function ran */
174*5677e049SGordon Ross 		status = NT_STATUS_CANCELLED;
175*5677e049SGordon Ross 		break;
176*5677e049SGordon Ross 
177*5677e049SGordon Ross 	default:
178*5677e049SGordon Ross 		status = NT_STATUS_INTERNAL_ERROR;
179*5677e049SGordon Ross 		break;
180*5677e049SGordon Ross 	}
181*5677e049SGordon Ross 
182a90cf9f2SGordon Ross 	mutex_exit(&sr->sr_mutex);
183a90cf9f2SGordon Ross 
184a90cf9f2SGordon Ross 	/*
185a90cf9f2SGordon Ross 	 * Unsubscribe from events on this node.
186a90cf9f2SGordon Ross 	 */
187a90cf9f2SGordon Ross 	smb_node_fcn_unsubscribe(node, sr);
188a90cf9f2SGordon Ross 
189a90cf9f2SGordon Ross 	/*
190a90cf9f2SGordon Ross 	 * Why did we wake up?
191a90cf9f2SGordon Ross 	 */
192*5677e049SGordon Ross 	if (status != 0)
193a90cf9f2SGordon Ross 		goto out;
194a90cf9f2SGordon Ross 
195a90cf9f2SGordon Ross 	/*
196a90cf9f2SGordon Ross 	 * We have SMB_REQ_STATE_ACTIVE.
197a90cf9f2SGordon Ross 	 *
198a90cf9f2SGordon Ross 	 * If we have event data, marshall it now, else just
199a90cf9f2SGordon Ross 	 * say "many things changed". Note that when we get
200a90cf9f2SGordon Ross 	 * action FILE_ACTION_SUBDIR_CHANGED, we don't have
201a90cf9f2SGordon Ross 	 * any event details and only know that some subdir
202a90cf9f2SGordon Ross 	 * changed, so just report "many things changed".
203a90cf9f2SGordon Ross 	 */
204a90cf9f2SGordon Ross 	switch (nc->nc_action) {
205a90cf9f2SGordon Ross 
206a90cf9f2SGordon Ross 	case FILE_ACTION_ADDED:
207a90cf9f2SGordon Ross 	case FILE_ACTION_REMOVED:
208a90cf9f2SGordon Ross 	case FILE_ACTION_MODIFIED:
209a90cf9f2SGordon Ross 	case FILE_ACTION_RENAMED_OLD_NAME:
210a90cf9f2SGordon Ross 	case FILE_ACTION_RENAMED_NEW_NAME:
211a90cf9f2SGordon Ross 	case FILE_ACTION_ADDED_STREAM:
212a90cf9f2SGordon Ross 	case FILE_ACTION_REMOVED_STREAM:
213a90cf9f2SGordon Ross 	case FILE_ACTION_MODIFIED_STREAM:
214a90cf9f2SGordon Ross 		/*
215a90cf9f2SGordon Ross 		 * Build the reply
216a90cf9f2SGordon Ross 		 */
217a90cf9f2SGordon Ross 		status = smb_notify_encode_action(sr, mbc,
218a90cf9f2SGordon Ross 		    nc->nc_action, nc->nc_fname);
219a90cf9f2SGordon Ross 		break;
220a90cf9f2SGordon Ross 
221a90cf9f2SGordon Ross 	case FILE_ACTION_SUBDIR_CHANGED:
222a90cf9f2SGordon Ross 		status = NT_STATUS_NOTIFY_ENUM_DIR;
223a90cf9f2SGordon Ross 		break;
224a90cf9f2SGordon Ross 
225a90cf9f2SGordon Ross 	case FILE_ACTION_DELETE_PENDING:
226a90cf9f2SGordon Ross 		status = NT_STATUS_DELETE_PENDING;
227a90cf9f2SGordon Ross 		break;
228a90cf9f2SGordon Ross 
229a90cf9f2SGordon Ross 	default:
230a90cf9f2SGordon Ross 		ASSERT(0);
231a90cf9f2SGordon Ross 		status = NT_STATUS_INTERNAL_ERROR;
232a90cf9f2SGordon Ross 		break;
233a90cf9f2SGordon Ross 	}
234a90cf9f2SGordon Ross 
235a90cf9f2SGordon Ross out:
236a90cf9f2SGordon Ross 	kmem_free(nc->nc_fname, MAXNAMELEN);
237a90cf9f2SGordon Ross 	nc->nc_fname = NULL;
238a90cf9f2SGordon Ross 	return (status);
239a90cf9f2SGordon Ross }
240a90cf9f2SGordon Ross 
241a90cf9f2SGordon Ross /*
242a90cf9f2SGordon Ross  * Encode a FILE_NOTIFY_INFORMATION struct.
243a90cf9f2SGordon Ross  *
244a90cf9f2SGordon Ross  * We only ever put one of these in a response, so this
245a90cf9f2SGordon Ross  * does not bother handling appending additional ones.
246a90cf9f2SGordon Ross  */
247a90cf9f2SGordon Ross static uint32_t
248a90cf9f2SGordon Ross smb_notify_encode_action(struct smb_request *sr, mbuf_chain_t *mbc,
249a90cf9f2SGordon Ross 	uint32_t action, char *fname)
250a90cf9f2SGordon Ross {
251a90cf9f2SGordon Ross 	uint32_t namelen;
252a90cf9f2SGordon Ross 
253a90cf9f2SGordon Ross 	ASSERT(FILE_ACTION_ADDED <= action &&
254a90cf9f2SGordon Ross 	    action <= FILE_ACTION_MODIFIED_STREAM);
255a90cf9f2SGordon Ross 
256a90cf9f2SGordon Ross 	if (fname == NULL)
257a90cf9f2SGordon Ross 		return (NT_STATUS_INTERNAL_ERROR);
258a90cf9f2SGordon Ross 	namelen = smb_wcequiv_strlen(fname);
259a90cf9f2SGordon Ross 	if (namelen == 0)
260a90cf9f2SGordon Ross 		return (NT_STATUS_INTERNAL_ERROR);
261a90cf9f2SGordon Ross 
262a90cf9f2SGordon Ross 	if (smb_mbc_encodef(mbc, "%lllU", sr,
263a90cf9f2SGordon Ross 	    0, /* NextEntryOffset */
264a90cf9f2SGordon Ross 	    action, namelen, fname))
265a90cf9f2SGordon Ross 		return (NT_STATUS_NOTIFY_ENUM_DIR);
266a90cf9f2SGordon Ross 
267a90cf9f2SGordon Ross 	return (0);
268a90cf9f2SGordon Ross }
269a90cf9f2SGordon Ross 
270a90cf9f2SGordon Ross /*
271a90cf9f2SGordon Ross  * smb_notify_file_closed
272a90cf9f2SGordon Ross  *
273a90cf9f2SGordon Ross  * Cancel any change-notify calls on this open file.
274a90cf9f2SGordon Ross  */
275a90cf9f2SGordon Ross void
276a90cf9f2SGordon Ross smb_notify_file_closed(struct smb_ofile *of)
277a90cf9f2SGordon Ross {
278a90cf9f2SGordon Ross 	smb_session_t	*ses;
279a90cf9f2SGordon Ross 	smb_request_t	*sr;
280a90cf9f2SGordon Ross 	smb_slist_t	*list;
281a90cf9f2SGordon Ross 
282a90cf9f2SGordon Ross 	SMB_OFILE_VALID(of);
283a90cf9f2SGordon Ross 	ses = of->f_session;
284a90cf9f2SGordon Ross 	SMB_SESSION_VALID(ses);
285a90cf9f2SGordon Ross 	list = &ses->s_req_list;
286a90cf9f2SGordon Ross 
287a90cf9f2SGordon Ross 	smb_slist_enter(list);
288a90cf9f2SGordon Ross 
289a90cf9f2SGordon Ross 	sr = smb_slist_head(list);
290a90cf9f2SGordon Ross 	while (sr) {
291a90cf9f2SGordon Ross 		SMB_REQ_VALID(sr);
292a90cf9f2SGordon Ross 		if (sr->sr_state == SMB_REQ_STATE_WAITING_EVENT &&
293a90cf9f2SGordon Ross 		    sr->fid_ofile == of) {
294a90cf9f2SGordon Ross 			smb_request_cancel(sr);
295a90cf9f2SGordon Ross 		}
296a90cf9f2SGordon Ross 		sr = smb_slist_next(list, sr);
297a90cf9f2SGordon Ross 	}
298a90cf9f2SGordon Ross 
299a90cf9f2SGordon Ross 	smb_slist_exit(list);
300a90cf9f2SGordon Ross }
301a90cf9f2SGordon Ross 
302a90cf9f2SGordon Ross 
303a90cf9f2SGordon Ross /*
304a90cf9f2SGordon Ross  * smb_notify_event
305a90cf9f2SGordon Ross  *
306a90cf9f2SGordon Ross  * Post an event to the watchers on a given node.
307a90cf9f2SGordon Ross  *
308a90cf9f2SGordon Ross  * This makes one exception for RENAME, where we expect a
309a90cf9f2SGordon Ross  * pair of events for the {old,new} directory element names.
310a90cf9f2SGordon Ross  * This only delivers an event for the "new" name.
311a90cf9f2SGordon Ross  *
312a90cf9f2SGordon Ross  * The event delivery mechanism does not implement delivery of
313a90cf9f2SGordon Ross  * multiple events for one "NT Notify" call.  One could do that,
314a90cf9f2SGordon Ross  * but modern clients don't actually use the event data.  They
315a90cf9f2SGordon Ross  * set a max. received data size of zero, which means we discard
316a90cf9f2SGordon Ross  * the data and send the special "lots changed" error instead.
317a90cf9f2SGordon Ross  * Given that, there's not really any point in implementing the
318a90cf9f2SGordon Ross  * delivery of multiple events.  In fact, we don't even need to
319a90cf9f2SGordon Ross  * implement single event delivery, but do so for completeness,
320a90cf9f2SGordon Ross  * for debug convenience, and to be nice to older clients that
321a90cf9f2SGordon Ross  * may actually want some event data instead of the error.
322a90cf9f2SGordon Ross  *
323a90cf9f2SGordon Ross  * Given that we only deliver a single event for an "NT Notify"
324a90cf9f2SGordon Ross  * caller, we want to deliver the "new" name event.  (The "old"
325a90cf9f2SGordon Ross  * name event is less important, even ignored by some clients.)
326a90cf9f2SGordon Ross  * Since we know these are delivered in pairs, we can simply
327a90cf9f2SGordon Ross  * discard the "old" name event, knowing that the "new" name
328a90cf9f2SGordon Ross  * event will be delivered immediately afterwards.
329a90cf9f2SGordon Ross  *
330a90cf9f2SGordon Ross  * So, why do event sources post the "old name" event at all?
331a90cf9f2SGordon Ross  * (1) For debugging, so we see both {old,new} names here.
332a90cf9f2SGordon Ross  * (2) If in the future someone decides to implement the
333a90cf9f2SGordon Ross  * delivery of both {old,new} events, the changes can be
334a90cf9f2SGordon Ross  * mostly isolated to this file.
335a90cf9f2SGordon Ross  */
336a90cf9f2SGordon Ross void
337a90cf9f2SGordon Ross smb_notify_event(smb_node_t *node, uint_t action, const char *name)
338a90cf9f2SGordon Ross {
339a90cf9f2SGordon Ross 	smb_request_t	*sr;
340a90cf9f2SGordon Ross 	smb_node_fcn_t	*fcn;
341a90cf9f2SGordon Ross 
342a90cf9f2SGordon Ross 	SMB_NODE_VALID(node);
343a90cf9f2SGordon Ross 	fcn = &node->n_fcn;
344a90cf9f2SGordon Ross 
345a90cf9f2SGordon Ross 	if (action == FILE_ACTION_RENAMED_OLD_NAME)
346a90cf9f2SGordon Ross 		return; /* see above */
347a90cf9f2SGordon Ross 
348a90cf9f2SGordon Ross 	mutex_enter(&fcn->fcn_mutex);
349a90cf9f2SGordon Ross 
350a90cf9f2SGordon Ross 	sr = list_head(&fcn->fcn_watchers);
351a90cf9f2SGordon Ross 	while (sr) {
352a90cf9f2SGordon Ross 		smb_notify_sr(sr, action, name);
353a90cf9f2SGordon Ross 		sr = list_next(&fcn->fcn_watchers, sr);
354a90cf9f2SGordon Ross 	}
355a90cf9f2SGordon Ross 
356a90cf9f2SGordon Ross 	mutex_exit(&fcn->fcn_mutex);
357a90cf9f2SGordon Ross }
358a90cf9f2SGordon Ross 
359a90cf9f2SGordon Ross /*
360a90cf9f2SGordon Ross  * What completion filter (masks) apply to each of the
361a90cf9f2SGordon Ross  * FILE_ACTION_... events.
362a90cf9f2SGordon Ross  */
363a90cf9f2SGordon Ross static const uint32_t
364a90cf9f2SGordon Ross smb_notify_action_mask[] = {
365a90cf9f2SGordon Ross 	0,  /* not used */
366a90cf9f2SGordon Ross 
367a90cf9f2SGordon Ross 	/* FILE_ACTION_ADDED	 */
368a90cf9f2SGordon Ross 	FILE_NOTIFY_CHANGE_NAME |
369a90cf9f2SGordon Ross 	FILE_NOTIFY_CHANGE_LAST_WRITE,
370a90cf9f2SGordon Ross 
371a90cf9f2SGordon Ross 	/* FILE_ACTION_REMOVED	 */
372a90cf9f2SGordon Ross 	FILE_NOTIFY_CHANGE_NAME |
373a90cf9f2SGordon Ross 	FILE_NOTIFY_CHANGE_LAST_WRITE,
374a90cf9f2SGordon Ross 
375a90cf9f2SGordon Ross 	/* FILE_ACTION_MODIFIED	 */
376a90cf9f2SGordon Ross 	FILE_NOTIFY_CHANGE_ATTRIBUTES |
377a90cf9f2SGordon Ross 	FILE_NOTIFY_CHANGE_SIZE |
378a90cf9f2SGordon Ross 	FILE_NOTIFY_CHANGE_LAST_WRITE |
379a90cf9f2SGordon Ross 	FILE_NOTIFY_CHANGE_LAST_ACCESS |
380a90cf9f2SGordon Ross 	FILE_NOTIFY_CHANGE_CREATION |
381a90cf9f2SGordon Ross 	FILE_NOTIFY_CHANGE_EA |
382a90cf9f2SGordon Ross 	FILE_NOTIFY_CHANGE_SECURITY,
383a90cf9f2SGordon Ross 
384a90cf9f2SGordon Ross 	/* FILE_ACTION_RENAMED_OLD_NAME */
385a90cf9f2SGordon Ross 	FILE_NOTIFY_CHANGE_NAME |
386a90cf9f2SGordon Ross 	FILE_NOTIFY_CHANGE_LAST_WRITE,
387a90cf9f2SGordon Ross 
388a90cf9f2SGordon Ross 	/* FILE_ACTION_RENAMED_NEW_NAME */
389a90cf9f2SGordon Ross 	FILE_NOTIFY_CHANGE_NAME |
390a90cf9f2SGordon Ross 	FILE_NOTIFY_CHANGE_LAST_WRITE,
391a90cf9f2SGordon Ross 
392a90cf9f2SGordon Ross 	/* FILE_ACTION_ADDED_STREAM */
393a90cf9f2SGordon Ross 	FILE_NOTIFY_CHANGE_STREAM_NAME,
394a90cf9f2SGordon Ross 
395a90cf9f2SGordon Ross 	/* FILE_ACTION_REMOVED_STREAM */
396a90cf9f2SGordon Ross 	FILE_NOTIFY_CHANGE_STREAM_NAME,
397a90cf9f2SGordon Ross 
398a90cf9f2SGordon Ross 	/* FILE_ACTION_MODIFIED_STREAM */
399a90cf9f2SGordon Ross 	FILE_NOTIFY_CHANGE_STREAM_SIZE |
400a90cf9f2SGordon Ross 	FILE_NOTIFY_CHANGE_STREAM_WRITE,
401a90cf9f2SGordon Ross 
402a90cf9f2SGordon Ross 	/* FILE_ACTION_SUBDIR_CHANGED */
403a90cf9f2SGordon Ross 	NODE_FLAGS_WATCH_TREE,
404a90cf9f2SGordon Ross 
405a90cf9f2SGordon Ross 	/* FILE_ACTION_DELETE_PENDING */
406a90cf9f2SGordon Ross 	NODE_FLAGS_WATCH_TREE |
407a90cf9f2SGordon Ross 	FILE_NOTIFY_VALID_MASK,
408a90cf9f2SGordon Ross };
409a90cf9f2SGordon Ross static const int smb_notify_action_nelm =
410a90cf9f2SGordon Ross 	sizeof (smb_notify_action_mask) /
411a90cf9f2SGordon Ross 	sizeof (smb_notify_action_mask[0]);
412a90cf9f2SGordon Ross 
413a90cf9f2SGordon Ross /*
414a90cf9f2SGordon Ross  * smb_notify_sr
415a90cf9f2SGordon Ross  *
416a90cf9f2SGordon Ross  * Post an event to an smb request waiting on some node.
417a90cf9f2SGordon Ross  *
418a90cf9f2SGordon Ross  * Note that node->fcn.mutex is held.  This implies a
419a90cf9f2SGordon Ross  * lock order: node->fcn.mutex, then sr_mutex
420a90cf9f2SGordon Ross  */
421a90cf9f2SGordon Ross static void
422a90cf9f2SGordon Ross smb_notify_sr(smb_request_t *sr, uint_t action, const char *name)
423a90cf9f2SGordon Ross {
424a90cf9f2SGordon Ross 	smb_notify_change_req_t	*ncr;
425a90cf9f2SGordon Ross 	uint32_t	mask;
426a90cf9f2SGordon Ross 
427a90cf9f2SGordon Ross 	SMB_REQ_VALID(sr);
428a90cf9f2SGordon Ross 	ncr = &sr->sr_ncr;
429a90cf9f2SGordon Ross 
430a90cf9f2SGordon Ross 	/*
431a90cf9f2SGordon Ross 	 * Compute the completion filter mask bits for which
432a90cf9f2SGordon Ross 	 * we will signal waiting notify requests.
433a90cf9f2SGordon Ross 	 */
434a90cf9f2SGordon Ross 	VERIFY(action < smb_notify_action_nelm);
435a90cf9f2SGordon Ross 	mask = smb_notify_action_mask[action];
436a90cf9f2SGordon Ross 
437a90cf9f2SGordon Ross 	mutex_enter(&sr->sr_mutex);
438a90cf9f2SGordon Ross 	if (sr->sr_state == SMB_REQ_STATE_WAITING_EVENT &&
439a90cf9f2SGordon Ross 	    (ncr->nc_flags & mask) != 0) {
440a90cf9f2SGordon Ross 		sr->sr_state = SMB_REQ_STATE_EVENT_OCCURRED;
441a90cf9f2SGordon Ross 		/*
442a90cf9f2SGordon Ross 		 * Save event data in the sr_ncr field so the
443a90cf9f2SGordon Ross 		 * reply handler can return it.
444a90cf9f2SGordon Ross 		 */
445a90cf9f2SGordon Ross 		ncr->nc_action = action;
446a90cf9f2SGordon Ross 		if (name != NULL)
447a90cf9f2SGordon Ross 			(void) strlcpy(ncr->nc_fname, name, MAXNAMELEN);
448a90cf9f2SGordon Ross 		cv_signal(&ncr->nc_cv);
449a90cf9f2SGordon Ross 	}
450a90cf9f2SGordon Ross 	mutex_exit(&sr->sr_mutex);
451a90cf9f2SGordon Ross }
452