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