1a90cf9fGordon Ross/*
2a90cf9fGordon Ross * CDDL HEADER START
3a90cf9fGordon Ross *
4a90cf9fGordon Ross * The contents of this file are subject to the terms of the
5a90cf9fGordon Ross * Common Development and Distribution License (the "License").
6a90cf9fGordon Ross * You may not use this file except in compliance with the License.
7a90cf9fGordon Ross *
8a90cf9fGordon Ross * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9a90cf9fGordon Ross * or http://www.opensolaris.org/os/licensing.
10a90cf9fGordon Ross * See the License for the specific language governing permissions
11a90cf9fGordon Ross * and limitations under the License.
12a90cf9fGordon Ross *
13a90cf9fGordon Ross * When distributing Covered Code, include this CDDL HEADER in each
14a90cf9fGordon Ross * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15a90cf9fGordon Ross * If applicable, add the following below this CDDL HEADER, with the
16a90cf9fGordon Ross * fields enclosed by brackets "[]" replaced with your own identifying
17a90cf9fGordon Ross * information: Portions Copyright [yyyy] [name of copyright owner]
18a90cf9fGordon Ross *
19a90cf9fGordon Ross * CDDL HEADER END
20a90cf9fGordon Ross */
21a90cf9fGordon Ross
22a90cf9fGordon Ross/*
23a90cf9fGordon Ross * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24bfe5e73Gordon Ross * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
25a90cf9fGordon Ross */
26a90cf9fGordon Ross
27a90cf9fGordon Ross/*
28a90cf9fGordon Ross * File Change Notification (FCN)
29a90cf9fGordon Ross * Common parts shared by SMB1 & SMB2
30a90cf9fGordon Ross */
31a90cf9fGordon Ross
32a90cf9fGordon Ross/*
33a90cf9fGordon Ross * This command notifies the client when the specified directory
34a90cf9fGordon Ross * has changed, and optionally returns the names of files and
35a90cf9fGordon Ross * directories that changed, and how they changed.  The caller
36a90cf9fGordon Ross * specifies a "Completion Filter" to select which kinds of
37a90cf9fGordon Ross * changes they want to know about.
38a90cf9fGordon Ross *
39a90cf9fGordon Ross * When a change that's in the CompletionFilter is made to the directory,
40a90cf9fGordon Ross * the command completes.  The names of the files that have changed since
41a90cf9fGordon Ross * the last time the command was issued are returned to the client.
42a90cf9fGordon Ross * If too many files have changed since the last time the command was
43a90cf9fGordon Ross * issued, then zero bytes are returned and an alternate status code
44a90cf9fGordon Ross * is returned in the Status field of the response.
45a90cf9fGordon Ross *
46a90cf9fGordon Ross * The CompletionFilter is a mask created as the sum of any of the
47a90cf9fGordon Ross * following flags:
48a90cf9fGordon Ross *
49a90cf9fGordon Ross * FILE_NOTIFY_CHANGE_FILE_NAME        0x00000001
50a90cf9fGordon Ross * FILE_NOTIFY_CHANGE_DIR_NAME         0x00000002
51a90cf9fGordon Ross * FILE_NOTIFY_CHANGE_NAME             0x00000003
52a90cf9fGordon Ross * FILE_NOTIFY_CHANGE_ATTRIBUTES       0x00000004
53a90cf9fGordon Ross * FILE_NOTIFY_CHANGE_SIZE             0x00000008
54a90cf9fGordon Ross * FILE_NOTIFY_CHANGE_LAST_WRITE       0x00000010
55a90cf9fGordon Ross * FILE_NOTIFY_CHANGE_LAST_ACCESS      0x00000020
56a90cf9fGordon Ross * FILE_NOTIFY_CHANGE_CREATION         0x00000040
57a90cf9fGordon Ross * FILE_NOTIFY_CHANGE_EA               0x00000080
58a90cf9fGordon Ross * FILE_NOTIFY_CHANGE_SECURITY         0x00000100
59a90cf9fGordon Ross * FILE_NOTIFY_CHANGE_STREAM_NAME      0x00000200
60a90cf9fGordon Ross * FILE_NOTIFY_CHANGE_STREAM_SIZE      0x00000400
61a90cf9fGordon Ross * FILE_NOTIFY_CHANGE_STREAM_WRITE     0x00000800
62a90cf9fGordon Ross *
63a90cf9fGordon Ross *
64a90cf9fGordon Ross * The response contains FILE_NOTIFY_INFORMATION structures, as defined
65a90cf9fGordon Ross * below.  The NextEntryOffset field of the structure specifies the offset,
66a90cf9fGordon Ross * in bytes, from the start of the current entry to the next entry in the
67a90cf9fGordon Ross * list.  If this is the last entry in the list, this field is zero.  Each
68a90cf9fGordon Ross * entry in the list must be longword aligned, so NextEntryOffset must be a
69a90cf9fGordon Ross * multiple of four.
70a90cf9fGordon Ross *
71a90cf9fGordon Ross * typedef struct {
72a90cf9fGordon Ross *     ULONG NextEntryOffset;
73a90cf9fGordon Ross *     ULONG Action;
74a90cf9fGordon Ross *     ULONG FileNameLength;
75a90cf9fGordon Ross *     WCHAR FileName[1];
76a90cf9fGordon Ross * } FILE_NOTIFY_INFORMATION;
77a90cf9fGordon Ross *
78a90cf9fGordon Ross * Where Action describes what happened to the file named FileName:
79a90cf9fGordon Ross *
80a90cf9fGordon Ross * FILE_ACTION_ADDED            0x00000001
81a90cf9fGordon Ross * FILE_ACTION_REMOVED          0x00000002
82a90cf9fGordon Ross * FILE_ACTION_MODIFIED         0x00000003
83a90cf9fGordon Ross * FILE_ACTION_RENAMED_OLD_NAME 0x00000004
84a90cf9fGordon Ross * FILE_ACTION_RENAMED_NEW_NAME 0x00000005
85a90cf9fGordon Ross * FILE_ACTION_ADDED_STREAM     0x00000006
86a90cf9fGordon Ross * FILE_ACTION_REMOVED_STREAM   0x00000007
87a90cf9fGordon Ross * FILE_ACTION_MODIFIED_STREAM  0x00000008
88bfe5e73Gordon Ross *
89bfe5e73Gordon Ross * The internal interface between SMB1 and/or SMB2 protocol handlers
90bfe5e73Gordon Ross * and this module has some sophistication to allow for:
91bfe5e73Gordon Ross * (1) code sharing between SMB1 and SMB2(+)
92bfe5e73Gordon Ross * (2) efficient handling of non-blocking scenarios
93bfe5e73Gordon Ross * (3) long blocking calls without tying up a thread
94bfe5e73Gordon Ross *
95bfe5e73Gordon Ross * The interface has three calls (like a three act play)
96bfe5e73Gordon Ross *
97bfe5e73Gordon Ross * smb_notify_act1:
98bfe5e73Gordon Ross *	Validate parameters, setup ofile buffer.
99bfe5e73Gordon Ross *	If data already available, return it, all done.
100bfe5e73Gordon Ross * 	(In the "all done" case, skip act2 & act3.)
101bfe5e73Gordon Ross * 	If no data available, return a special error
102bfe5e73Gordon Ross *	("STATUS_PENDING") to tell the caller they must
103bfe5e73Gordon Ross *	proceed with calls to act2 & act3.
104bfe5e73Gordon Ross *
105bfe5e73Gordon Ross * smb_notify_act2:
106bfe5e73Gordon Ross *	Arrange wakeup after event delivery or cancellation.
107bfe5e73Gordon Ross *	Return leaving the SR with no worker thread.
108bfe5e73Gordon Ross *
109bfe5e73Gordon Ross * smb_notify_act3:
110bfe5e73Gordon Ross *	New taskq work thread runs this after the wakeup
111bfe5e73Gordon Ross *	or cancellation arranged in act2 happens.  This
112bfe5e73Gordon Ross *	returns the notification data and retires the SR.
113bfe5e73Gordon Ross *
114bfe5e73Gordon Ross * In the SMB2 notify handler, we call act1 during the initial
115bfe5e73Gordon Ross * synchronous handling of the request.  If that returns anything
116bfe5e73Gordon Ross * other than STATUS_PENDING, that request is fully complete.
117bfe5e73Gordon Ross * If act1 returns STATUS_PENDING, SMB2 calls act2 as it's
118bfe5e73Gordon Ross * "go async" handler, which arranges to call act3 later.
119bfe5e73Gordon Ross *
120bfe5e73Gordon Ross * In the SMB1 notify handler there is not separate sync. & async
121bfe5e73Gordon Ross * handler so act1 and (if necessary) act2 are both called during
122bfe5e73Gordon Ross * the initial handling of the request.
123bfe5e73Gordon Ross *
124bfe5e73Gordon Ross * About notify event buffering:
125bfe5e73Gordon Ross *
126bfe5e73Gordon Ross * An important (and poorly documented) feature of SMB notify is
127bfe5e73Gordon Ross * that once a notify call has happened on a given directory handle,
128bfe5e73Gordon Ross * the system CONTINUES to post events to the notify event buffer
129bfe5e73Gordon Ross * for the handle, even when SMB notify calls are NOT running.
130bfe5e73Gordon Ross * When the client next comes back with a notify call, we return
131bfe5e73Gordon Ross * any events that were posted while they were "away".  This is
132bfe5e73Gordon Ross * how clients track directory changes without missing events.
133bfe5e73Gordon Ross *
134bfe5e73Gordon Ross * About simultaneous notify calls:
135bfe5e73Gordon Ross *
136bfe5e73Gordon Ross * Note that SMB "notify" calls are destructive to events, much like
137bfe5e73Gordon Ross * reading data from a pipe.  It therefore makes little sense to
138bfe5e73Gordon Ross * allow multiple simultaneous callers.  However, we permit it
139bfe5e73Gordon Ross * (like Windows does) as follows:  When multiple notify calls
140bfe5e73Gordon Ross * are waiting for events, the next event wakes them all, and
141bfe5e73Gordon Ross * only the last one out clears the event buffer.  They all get
142bfe5e73Gordon Ross * whatever events are pending at the time they woke up.
143bfe5e73Gordon Ross *
144bfe5e73Gordon Ross * About NT_STATUS_NOTIFY_ENUM_DIR
145bfe5e73Gordon Ross *
146bfe5e73Gordon Ross * One more caution about NT_STATUS_NOTIFY_ENUM_DIR:  Some clients
147bfe5e73Gordon Ross * are stupid about re-reading the directory almost continuously when
148bfe5e73Gordon Ross * there are changes happening in the directory.  We want to bound
149bfe5e73Gordon Ross * the rate of such directory re-reading, so before returning an
150bfe5e73Gordon Ross * NT_STATUS_NOTIFY_ENUM_DIR, we delay just a little.  The length
151bfe5e73Gordon Ross * of the delay can be adjusted via smb_notify_enum_dir_delay,
152bfe5e73Gordon Ross * though it's not expected that should need to be changed.
153a90cf9fGordon Ross */
154a90cf9fGordon Ross
155a90cf9fGordon Ross#include <smbsrv/smb_kproto.h>
156a90cf9fGordon Ross#include <sys/sdt.h>
157a90cf9fGordon Ross
158bfe5e73Gordon Ross/*
159bfe5e73Gordon Ross * Length of the short delay we impose before returning
160bfe5e73Gordon Ross * NT_STATUS_NOTIFY_ENUM_DIR (See above)
161bfe5e73Gordon Ross */
162bfe5e73Gordon Rossint smb_notify_enum_dir_delay = 100; /* mSec. */
163bfe5e73Gordon Ross
164bfe5e73Gordon Rossstatic uint32_t smb_notify_get_events(smb_request_t *);
165bfe5e73Gordon Rossstatic void smb_notify_cancel(smb_request_t *);
166bfe5e73Gordon Rossstatic void smb_notify_wakeup(smb_request_t *);
167bfe5e73Gordon Rossstatic void smb_notify_dispatch2(smb_request_t *);
168bfe5e73Gordon Rossstatic void smb_notify_encode_action(smb_ofile_t *,
169bfe5e73Gordon Ross	uint32_t, const char *);
170bfe5e73Gordon Ross
171a90cf9fGordon Ross
1725677e04Gordon Ross/*
173bfe5e73Gordon Ross * smb_notify_act1()
174bfe5e73Gordon Ross *
175bfe5e73Gordon Ross * Check for events and consume, non-blocking.
176bfe5e73Gordon Ross * Special return STATUS_PENDING means:
177bfe5e73Gordon Ross * No events; caller must call "act2" next.
1785677e04Gordon Ross *
179bfe5e73Gordon Ross * See overall design notes, top of file.
1805677e04Gordon Ross */
181a90cf9fGordon Rossuint32_t
182bfe5e73Gordon Rosssmb_notify_act1(smb_request_t *sr, uint32_t buflen, uint32_t filter)
183a90cf9fGordon Ross{
184bfe5e73Gordon Ross	smb_ofile_t	*of;
185a90cf9fGordon Ross	smb_node_t	*node;
186bfe5e73Gordon Ross	smb_notify_t	*nc;
187a90cf9fGordon Ross	uint32_t	status;
188a90cf9fGordon Ross
189bfe5e73Gordon Ross	/*
190bfe5e73Gordon Ross	 * Validate parameters
191bfe5e73Gordon Ross	 */
192bfe5e73Gordon Ross	if ((of = sr->fid_ofile) == NULL)
193a90cf9fGordon Ross		return (NT_STATUS_INVALID_HANDLE);
194bfe5e73Gordon Ross	nc = &of->f_notify;
195bfe5e73Gordon Ross	node = of->f_node;
196a90cf9fGordon Ross	if (node == NULL || !smb_node_is_dir(node)) {
197bfe5e73Gordon Ross		/* Notify change is only valid on directories. */
198bfe5e73Gordon Ross		return (NT_STATUS_INVALID_PARAMETER);
199bfe5e73Gordon Ross	}
200bfe5e73Gordon Ross
201bfe5e73Gordon Ross	mutex_enter(&of->f_mutex);
202bfe5e73Gordon Ross
203bfe5e73Gordon Ross	/*
204bfe5e73Gordon Ross	 * On the first FCN call with this ofile, subscribe to
205bfe5e73Gordon Ross	 * events on the node.  The corresponding unsubscribe
206bfe5e73Gordon Ross	 * happens in smb_ofile_delete().
207bfe5e73Gordon Ross	 */
208bfe5e73Gordon Ross	if (nc->nc_subscribed == B_FALSE) {
209bfe5e73Gordon Ross		nc->nc_subscribed = B_TRUE;
210bfe5e73Gordon Ross		smb_node_fcn_subscribe(node);
211bfe5e73Gordon Ross		/* In case this happened before we subscribed. */
212bfe5e73Gordon Ross		if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
213bfe5e73Gordon Ross			nc->nc_events |= FILE_NOTIFY_CHANGE_EV_DELETE;
214bfe5e73Gordon Ross		}
215a90cf9fGordon Ross		/*
216bfe5e73Gordon Ross		 * Windows only lets you set these on the first call,
217bfe5e73Gordon Ross		 * so we may as well do the same.
218a90cf9fGordon Ross		 */
219bfe5e73Gordon Ross		nc->nc_buffer.max_bytes = buflen;
220bfe5e73Gordon Ross		nc->nc_filter = filter;
221bfe5e73Gordon Ross	}
222bfe5e73Gordon Ross	/*
223bfe5e73Gordon Ross	 * If we already have events, consume them.
224bfe5e73Gordon Ross	 */
225bfe5e73Gordon Ross	sr->raw_data.max_bytes = buflen;
226bfe5e73Gordon Ross	if (nc->nc_events != 0) {
227bfe5e73Gordon Ross		status = smb_notify_get_events(sr);
228bfe5e73Gordon Ross	} else {
229bfe5e73Gordon Ross		/* Caller will come back for act2 */
230bfe5e73Gordon Ross		status = NT_STATUS_PENDING;
231a90cf9fGordon Ross	}
232a90cf9fGordon Ross
233bfe5e73Gordon Ross	mutex_exit(&of->f_mutex);
234bfe5e73Gordon Ross
235a90cf9fGordon Ross	/*
236bfe5e73Gordon Ross	 * See: About NT_STATUS_NOTIFY_ENUM_DIR (above)
237a90cf9fGordon Ross	 */
238bfe5e73Gordon Ross	if (status == NT_STATUS_NOTIFY_ENUM_DIR &&
239bfe5e73Gordon Ross	    smb_notify_enum_dir_delay > 0)
240bfe5e73Gordon Ross		delay(MSEC_TO_TICK(smb_notify_enum_dir_delay));
241bfe5e73Gordon Ross
242bfe5e73Gordon Ross	return (status);
243bfe5e73Gordon Ross}
244bfe5e73Gordon Ross
245bfe5e73Gordon Ross/*
246bfe5e73Gordon Ross * smb_notify_act2()
247bfe5e73Gordon Ross *
248bfe5e73Gordon Ross * Prepare to wait for events after act1 found that none were pending.
249bfe5e73Gordon Ross * Assume the wait may be for a very long time.  (hours, days...)
250bfe5e73Gordon Ross * Special return STATUS_PENDING means the SR will later be
251bfe5e73Gordon Ross * scheduled again on a new worker thread, and this thread
252bfe5e73Gordon Ross * MUST NOT touch it any longer (return SDRC_SR_KEPT).
253bfe5e73Gordon Ross *
254bfe5e73Gordon Ross * See overall design notes, top of file.
255bfe5e73Gordon Ross */
256bfe5e73Gordon Rossuint32_t
257bfe5e73Gordon Rosssmb_notify_act2(smb_request_t *sr)
258bfe5e73Gordon Ross{
259bfe5e73Gordon Ross	smb_ofile_t	*of;
260bfe5e73Gordon Ross	smb_notify_t	*nc;
261bfe5e73Gordon Ross	uint32_t	status;
262a90cf9fGordon Ross
263a90cf9fGordon Ross	/*
264bfe5e73Gordon Ross	 * Sanity checks.
265a90cf9fGordon Ross	 */
266bfe5e73Gordon Ross	if ((of = sr->fid_ofile) == NULL)
267bfe5e73Gordon Ross		return (NT_STATUS_INVALID_HANDLE);
268bfe5e73Gordon Ross	nc = &of->f_notify;
269bfe5e73Gordon Ross
270bfe5e73Gordon Ross	mutex_enter(&of->f_mutex);
271a90cf9fGordon Ross
272a90cf9fGordon Ross	/*
273bfe5e73Gordon Ross	 * Prepare for a potentially long wait for events.
274bfe5e73Gordon Ross	 * Normally transition from ACTIVE to WAITING_FCN1.
275bfe5e73Gordon Ross	 *
276bfe5e73Gordon Ross	 * Note we hold both of->f_mutex, sr->sr_mutex here,
277bfe5e73Gordon Ross	 * taken in that order.
278a90cf9fGordon Ross	 */
279a90cf9fGordon Ross	mutex_enter(&sr->sr_mutex);
280bfe5e73Gordon Ross	switch (sr->sr_state) {
281bfe5e73Gordon Ross	case SMB_REQ_STATE_ACTIVE:
282bfe5e73Gordon Ross		/*
283bfe5e73Gordon Ross		 * This sr has no worker thread until smb_notify_act3
284bfe5e73Gordon Ross		 * or smb_notify_cancel (later, via taskq_dispatch).
285bfe5e73Gordon Ross		 */
286bfe5e73Gordon Ross		sr->sr_state = SMB_REQ_STATE_WAITING_FCN1;
2875677e04Gordon Ross		sr->cancel_method = smb_notify_cancel;
288bfe5e73Gordon Ross		sr->sr_worker = NULL;
289bfe5e73Gordon Ross		list_insert_tail(&nc->nc_waiters, sr);
290bfe5e73Gordon Ross		status = NT_STATUS_PENDING;
291bfe5e73Gordon Ross		break;
292bfe5e73Gordon Ross
293bfe5e73Gordon Ross	case SMB_REQ_STATE_CANCELLED:
294bfe5e73Gordon Ross		status = NT_STATUS_CANCELLED;
295bfe5e73Gordon Ross		break;
296bfe5e73Gordon Ross	default:
297bfe5e73Gordon Ross		status = NT_STATUS_INTERNAL_ERROR;
298bfe5e73Gordon Ross		break;
2995677e04Gordon Ross	}
300bfe5e73Gordon Ross	mutex_exit(&sr->sr_mutex);
301bfe5e73Gordon Ross
302bfe5e73Gordon Ross	/*
303bfe5e73Gordon Ross	 * In case we missed any events before setting
304bfe5e73Gordon Ross	 * state FCN1, schedule our own wakeup.
305bfe5e73Gordon Ross	 */
306bfe5e73Gordon Ross	if (status == NT_STATUS_PENDING && nc->nc_events != 0) {
307bfe5e73Gordon Ross		smb_notify_wakeup(sr);
308a90cf9fGordon Ross	}
309bfe5e73Gordon Ross
310bfe5e73Gordon Ross	mutex_exit(&of->f_mutex);
311bfe5e73Gordon Ross
312bfe5e73Gordon Ross	/* Note: Never NT_STATUS_NOTIFY_ENUM_DIR here. */
313bfe5e73Gordon Ross	ASSERT(status != NT_STATUS_NOTIFY_ENUM_DIR);
314bfe5e73Gordon Ross
315bfe5e73Gordon Ross	return (status);
316bfe5e73Gordon Ross}
317bfe5e73Gordon Ross
318bfe5e73Gordon Ross/*
319bfe5e73Gordon Ross * smb_notify_act3()
320bfe5e73Gordon Ross *
321bfe5e73Gordon Ross * This runs via the 2nd taskq_dispatch call, after we've either
322bfe5e73Gordon Ross * seen a change notify event, or the request has been cancelled.
323bfe5e73Gordon Ross * Complete it here.  This returns to SMB1 or SMB2 code to send
324bfe5e73Gordon Ross * the response and free the request.
325bfe5e73Gordon Ross *
326bfe5e73Gordon Ross * See overall design notes, top of file.
327bfe5e73Gordon Ross */
328bfe5e73Gordon Rossuint32_t
329bfe5e73Gordon Rosssmb_notify_act3(smb_request_t *sr)
330bfe5e73Gordon Ross{
331bfe5e73Gordon Ross	smb_ofile_t	*of;
332bfe5e73Gordon Ross	smb_notify_t	*nc;
333bfe5e73Gordon Ross	uint32_t	status;
334bfe5e73Gordon Ross
335bfe5e73Gordon Ross	of = sr->fid_ofile;
336bfe5e73Gordon Ross	ASSERT(of != NULL);
337bfe5e73Gordon Ross	nc = &of->f_notify;
338bfe5e73Gordon Ross
339bfe5e73Gordon Ross	mutex_enter(&of->f_mutex);
340bfe5e73Gordon Ross
341bfe5e73Gordon Ross	mutex_enter(&sr->sr_mutex);
342bfe5e73Gordon Ross	ASSERT3P(sr->sr_worker, ==, NULL);
343bfe5e73Gordon Ross	sr->sr_worker = curthread;
3445677e04Gordon Ross	sr->cancel_method = NULL;
3455677e04Gordon Ross
346bfe5e73Gordon Ross	list_remove(&nc->nc_waiters, sr);
347bfe5e73Gordon Ross
3485677e04Gordon Ross	switch (sr->sr_state) {
349bfe5e73Gordon Ross	case SMB_REQ_STATE_WAITING_FCN2:
350bfe5e73Gordon Ross		/*
351bfe5e73Gordon Ross		 * Got smb_notify_wakeup.
352bfe5e73Gordon Ross		 */
353a90cf9fGordon Ross		sr->sr_state = SMB_REQ_STATE_ACTIVE;
3545677e04Gordon Ross		status = 0;
3555677e04Gordon Ross		break;
3565677e04Gordon Ross
3575677e04Gordon Ross	case SMB_REQ_STATE_CANCEL_PENDING:
358bfe5e73Gordon Ross		/*
359bfe5e73Gordon Ross		 * Got smb_notify_cancel
360bfe5e73Gordon Ross		 */
3615677e04Gordon Ross		sr->sr_state = SMB_REQ_STATE_CANCELLED;
3625677e04Gordon Ross		status = NT_STATUS_CANCELLED;
3635677e04Gordon Ross		break;
3645677e04Gordon Ross	default:
3655677e04Gordon Ross		status = NT_STATUS_INTERNAL_ERROR;
3665677e04Gordon Ross		break;
3675677e04Gordon Ross	}
368a90cf9fGordon Ross	mutex_exit(&sr->sr_mutex);
369a90cf9fGordon Ross
370bfe5e73Gordon Ross	if (status == 0)
371bfe5e73Gordon Ross		status = smb_notify_get_events(sr);
372bfe5e73Gordon Ross
373bfe5e73Gordon Ross	mutex_exit(&of->f_mutex);
374bfe5e73Gordon Ross
375a90cf9fGordon Ross	/*
376bfe5e73Gordon Ross	 * See: About NT_STATUS_NOTIFY_ENUM_DIR (above)
377a90cf9fGordon Ross	 */
378bfe5e73Gordon Ross	if (status == NT_STATUS_NOTIFY_ENUM_DIR &&
379bfe5e73Gordon Ross	    smb_notify_enum_dir_delay > 0)
380bfe5e73Gordon Ross		delay(MSEC_TO_TICK(smb_notify_enum_dir_delay));
381bfe5e73Gordon Ross
382bfe5e73Gordon Ross	return (status);
383bfe5e73Gordon Ross}
384bfe5e73Gordon Ross
385bfe5e73Gordon Rossstatic uint32_t
386bfe5e73Gordon Rosssmb_notify_get_events(smb_request_t *sr)
387bfe5e73Gordon Ross{
388bfe5e73Gordon Ross	smb_ofile_t	*of;
389bfe5e73Gordon Ross	smb_notify_t	*nc;
390bfe5e73Gordon Ross	uint32_t	status;
391bfe5e73Gordon Ross	int		len;
392bfe5e73Gordon Ross
393bfe5e73Gordon Ross	of = sr->fid_ofile;
394bfe5e73Gordon Ross	ASSERT(of != NULL);
395bfe5e73Gordon Ross	ASSERT(MUTEX_HELD(&of->f_mutex));
396bfe5e73Gordon Ross	nc = &of->f_notify;
397bfe5e73Gordon Ross
398bfe5e73Gordon Ross	DTRACE_PROBE2(notify__get__events,
399bfe5e73Gordon Ross	    smb_request_t, sr,
400bfe5e73Gordon Ross	    uint32_t, nc->nc_events);
401a90cf9fGordon Ross
402a90cf9fGordon Ross	/*
403bfe5e73Gordon Ross	 * Special events which override other events
404a90cf9fGordon Ross	 */
405bfe5e73Gordon Ross	if (nc->nc_events & FILE_NOTIFY_CHANGE_EV_CLOSED) {
406bfe5e73Gordon Ross		status = NT_STATUS_NOTIFY_CLEANUP;
407bfe5e73Gordon Ross		goto out;
408bfe5e73Gordon Ross	}
409bfe5e73Gordon Ross	if (nc->nc_events & FILE_NOTIFY_CHANGE_EV_DELETE) {
410bfe5e73Gordon Ross		status = NT_STATUS_DELETE_PENDING;
411bfe5e73Gordon Ross		goto out;
412bfe5e73Gordon Ross	}
413bfe5e73Gordon Ross	if (nc->nc_events & FILE_NOTIFY_CHANGE_EV_SUBDIR) {
414bfe5e73Gordon Ross		status = NT_STATUS_NOTIFY_ENUM_DIR;
415a90cf9fGordon Ross		goto out;
416bfe5e73Gordon Ross	}
417bfe5e73Gordon Ross	if (nc->nc_events & FILE_NOTIFY_CHANGE_EV_OVERFLOW) {
418bfe5e73Gordon Ross		status = NT_STATUS_NOTIFY_ENUM_DIR;
419bfe5e73Gordon Ross		goto out;
420bfe5e73Gordon Ross	}
421a90cf9fGordon Ross
422a90cf9fGordon Ross	/*
423bfe5e73Gordon Ross	 * Normal events (FILE_NOTIFY_VALID_MASK)
424a90cf9fGordon Ross	 *
425bfe5e73Gordon Ross	 * At this point there should be some, or else
426bfe5e73Gordon Ross	 * some sort of bug woke us up for nothing.
427a90cf9fGordon Ross	 */
428bfe5e73Gordon Ross	if ((nc->nc_events & FILE_NOTIFY_VALID_MASK) == 0) {
429bfe5e73Gordon Ross		status = NT_STATUS_INTERNAL_ERROR;
430bfe5e73Gordon Ross		goto out;
431bfe5e73Gordon Ross	}
432a90cf9fGordon Ross
433bfe5e73Gordon Ross	/*
434bfe5e73Gordon Ross	 * Many Windows clients call change notify with a
435bfe5e73Gordon Ross	 * zero-length buffer, expecting all events to be
436bfe5e73Gordon Ross	 * reported as _ENUM_DIR.  Testing max_bytes here
437bfe5e73Gordon Ross	 * because ROOM_FOR check below says "yes" if both
438bfe5e73Gordon Ross	 * max_bytes and the amount we ask for are zero.
439bfe5e73Gordon Ross	 */
440bfe5e73Gordon Ross	if (nc->nc_buffer.max_bytes <= 0) {
441a90cf9fGordon Ross		status = NT_STATUS_NOTIFY_ENUM_DIR;
442bfe5e73Gordon Ross		goto out;
443bfe5e73Gordon Ross	}
444a90cf9fGordon Ross
445bfe5e73Gordon Ross	/*
446bfe5e73Gordon Ross	 * Client gave us a non-zero output buffer, and
447bfe5e73Gordon Ross	 * there was no overflow event (checked above)
448bfe5e73Gordon Ross	 * so there should be some event data.
449bfe5e73Gordon Ross	 */
450bfe5e73Gordon Ross	if ((len = nc->nc_buffer.chain_offset) <= 0) {
451a90cf9fGordon Ross		status = NT_STATUS_INTERNAL_ERROR;
452bfe5e73Gordon Ross		goto out;
453bfe5e73Gordon Ross	}
454bfe5e73Gordon Ross
455bfe5e73Gordon Ross	/*
456bfe5e73Gordon Ross	 * If the current SR has a smaller output buffer
457bfe5e73Gordon Ross	 * then what was setup by some previous notify,
458bfe5e73Gordon Ross	 * we could have more data than will fit.
459bfe5e73Gordon Ross	 */
460bfe5e73Gordon Ross	if (!MBC_ROOM_FOR(&sr->raw_data, len)) {
461bfe5e73Gordon Ross		/* Would overflow caller's buffer. */
462bfe5e73Gordon Ross		status = NT_STATUS_NOTIFY_ENUM_DIR;
463bfe5e73Gordon Ross		goto out;
464a90cf9fGordon Ross	}
465a90cf9fGordon Ross
466bfe5e73Gordon Ross	/*
467bfe5e73Gordon Ross	 * Copy the event data to sr->raw_data.  In the copy,
468bfe5e73Gordon Ross	 * zap the NextEntryOffset in the last entry, and
469bfe5e73Gordon Ross	 * trim any extra bytes at the tail.
470bfe5e73Gordon Ross	 */
471bfe5e73Gordon Ross	(void) smb_mbc_copy(&sr->raw_data, &nc->nc_buffer, 0, len);
472bfe5e73Gordon Ross	(void) smb_mbc_poke(&sr->raw_data, nc->nc_last_off, "l", 0);
473bfe5e73Gordon Ross	smb_mbuf_trim(sr->raw_data.chain, len);
474bfe5e73Gordon Ross	status = 0;
475bfe5e73Gordon Ross
476a90cf9fGordon Rossout:
477bfe5e73Gordon Ross	/*
478bfe5e73Gordon Ross	 * If there are no other SRs waiting on this ofile,
479bfe5e73Gordon Ross	 * mark all events consumed, except for those that
480bfe5e73Gordon Ross	 * remain until the ofile is closed.  That means
481bfe5e73Gordon Ross	 * clear all bits EXCEPT: _EV_CLOSED, _EV_DELETE
482bfe5e73Gordon Ross	 *
483bfe5e73Gordon Ross	 * If there are other waiters (rare) all will get
484bfe5e73Gordon Ross	 * the currently pending events, and then the
485bfe5e73Gordon Ross	 * the last one out will clear the events.
486bfe5e73Gordon Ross	 */
487bfe5e73Gordon Ross	if (list_is_empty(&nc->nc_waiters)) {
488bfe5e73Gordon Ross		nc->nc_buffer.chain_offset = 0;
489bfe5e73Gordon Ross		nc->nc_events &= (FILE_NOTIFY_CHANGE_EV_CLOSED |
490bfe5e73Gordon Ross		    FILE_NOTIFY_CHANGE_EV_DELETE);
491bfe5e73Gordon Ross	}
492bfe5e73Gordon Ross
493a90cf9fGordon Ross	return (status);
494a90cf9fGordon Ross}
495a90cf9fGordon Ross
496a90cf9fGordon Ross/*
497bfe5e73Gordon Ross * Called by common code after a transition from
498bfe5e73Gordon Ross * state WAITING_FCN1 to state CANCEL_PENDING.
499a90cf9fGordon Ross */
500bfe5e73Gordon Rossstatic void
501bfe5e73Gordon Rosssmb_notify_cancel(smb_request_t *sr)
502a90cf9fGordon Ross{
503bfe5e73Gordon Ross	ASSERT3U(sr->sr_state, ==, SMB_REQ_STATE_CANCEL_PENDING);
504bfe5e73Gordon Ross	smb_notify_dispatch2(sr);
505a90cf9fGordon Ross}
506a90cf9fGordon Ross
507a90cf9fGordon Ross/*
508bfe5e73Gordon Ross * Called after ofile event delivery to take a waiting smb request
509bfe5e73Gordon Ross * from state FCN1 to state FCN2.  This may be called many times
510bfe5e73Gordon Ross * (as events are delivered) but it must (exactly once) schedule
511bfe5e73Gordon Ross * the taskq job to run smb_notify_act3().  Only the event that
512bfe5e73Gordon Ross * takes us from state FCN1 to FCN2 schedules the taskq job.
513a90cf9fGordon Ross */
514bfe5e73Gordon Rossstatic void
515bfe5e73Gordon Rosssmb_notify_wakeup(smb_request_t *sr)
516a90cf9fGordon Ross{
517bfe5e73Gordon Ross	boolean_t do_disp = B_FALSE;
518a90cf9fGordon Ross
519bfe5e73Gordon Ross	SMB_REQ_VALID(sr);
520bfe5e73Gordon Ross
521bfe5e73Gordon Ross	mutex_enter(&sr->sr_mutex);
522bfe5e73Gordon Ross	if (sr->sr_state == SMB_REQ_STATE_WAITING_FCN1) {
523bfe5e73Gordon Ross		sr->sr_state = SMB_REQ_STATE_WAITING_FCN2;
524bfe5e73Gordon Ross		do_disp = B_TRUE;
525a90cf9fGordon Ross	}
526bfe5e73Gordon Ross	mutex_exit(&sr->sr_mutex);
527a90cf9fGordon Ross
528bfe5e73Gordon Ross	if (do_disp) {
529bfe5e73Gordon Ross		smb_notify_dispatch2(sr);
530bfe5e73Gordon Ross	}
531a90cf9fGordon Ross}
532a90cf9fGordon Ross
533a90cf9fGordon Ross/*
534bfe5e73Gordon Ross * smb_notify_dispatch2()
535bfe5e73Gordon Ross * Schedule a 2nd taskq call to finish up a change notify request;
536bfe5e73Gordon Ross * (smb_notify_act3) either completing it or cancelling it.
537a90cf9fGordon Ross */
538bfe5e73Gordon Rossstatic void
539bfe5e73Gordon Rosssmb_notify_dispatch2(smb_request_t *sr)
540a90cf9fGordon Ross{
541bfe5e73Gordon Ross	void (*tq_func)(void *);
542a90cf9fGordon Ross
543bfe5e73Gordon Ross	/*
544bfe5e73Gordon Ross	 * Both of these call smb_notify_act3(), returning
545bfe5e73Gordon Ross	 * to version-specific code to send the response.
546bfe5e73Gordon Ross	 */
547bfe5e73Gordon Ross	if (sr->session->dialect >= SMB_VERS_2_BASE)
548bfe5e73Gordon Ross		tq_func = smb2_change_notify_finish;
549bfe5e73Gordon Ross	else
550bfe5e73Gordon Ross		tq_func = smb_nt_transact_notify_finish;
551a90cf9fGordon Ross
552bfe5e73Gordon Ross	(void) taskq_dispatch(sr->sr_server->sv_worker_pool,
553bfe5e73Gordon Ross	    tq_func, sr, TQ_SLEEP);
554a90cf9fGordon Ross}
555a90cf9fGordon Ross
556bfe5e73Gordon Ross
557a90cf9fGordon Ross/*
558a90cf9fGordon Ross * What completion filter (masks) apply to each of the
559a90cf9fGordon Ross * FILE_ACTION_... events.
560a90cf9fGordon Ross */
561a90cf9fGordon Rossstatic const uint32_t
562a90cf9fGordon Rosssmb_notify_action_mask[] = {
563a90cf9fGordon Ross	0,  /* not used */
564a90cf9fGordon Ross
565a90cf9fGordon Ross	/* FILE_ACTION_ADDED	 */
566a90cf9fGordon Ross	FILE_NOTIFY_CHANGE_NAME |
567a90cf9fGordon Ross	FILE_NOTIFY_CHANGE_LAST_WRITE,
568a90cf9fGordon Ross
569a90cf9fGordon Ross	/* FILE_ACTION_REMOVED	 */
570a90cf9fGordon Ross	FILE_NOTIFY_CHANGE_NAME |
571a90cf9fGordon Ross	FILE_NOTIFY_CHANGE_LAST_WRITE,
572a90cf9fGordon Ross
573a90cf9fGordon Ross	/* FILE_ACTION_MODIFIED	 */
574a90cf9fGordon Ross	FILE_NOTIFY_CHANGE_ATTRIBUTES |
575a90cf9fGordon Ross	FILE_NOTIFY_CHANGE_SIZE |
576a90cf9fGordon Ross	FILE_NOTIFY_CHANGE_LAST_WRITE |
577a90cf9fGordon Ross	FILE_NOTIFY_CHANGE_LAST_ACCESS |
578a90cf9fGordon Ross	FILE_NOTIFY_CHANGE_CREATION |
579a90cf9fGordon Ross	FILE_NOTIFY_CHANGE_EA |
580a90cf9fGordon Ross	FILE_NOTIFY_CHANGE_SECURITY,
581a90cf9fGordon Ross
582a90cf9fGordon Ross	/* FILE_ACTION_RENAMED_OLD_NAME */
583a90cf9fGordon Ross	FILE_NOTIFY_CHANGE_NAME |
584a90cf9fGordon Ross	FILE_NOTIFY_CHANGE_LAST_WRITE,
585a90cf9fGordon Ross
586a90cf9fGordon Ross	/* FILE_ACTION_RENAMED_NEW_NAME */
587a90cf9fGordon Ross	FILE_NOTIFY_CHANGE_NAME |
588a90cf9fGordon Ross	FILE_NOTIFY_CHANGE_LAST_WRITE,
589a90cf9fGordon Ross
590a90cf9fGordon Ross	/* FILE_ACTION_ADDED_STREAM */
591a90cf9fGordon Ross	FILE_NOTIFY_CHANGE_STREAM_NAME,
592a90cf9fGordon Ross
593a90cf9fGordon Ross	/* FILE_ACTION_REMOVED_STREAM */
594a90cf9fGordon Ross	FILE_NOTIFY_CHANGE_STREAM_NAME,
595a90cf9fGordon Ross
596a90cf9fGordon Ross	/* FILE_ACTION_MODIFIED_STREAM */
597a90cf9fGordon Ross	FILE_NOTIFY_CHANGE_STREAM_SIZE |
598a90cf9fGordon Ross	FILE_NOTIFY_CHANGE_STREAM_WRITE,
599a90cf9fGordon Ross
600a90cf9fGordon Ross	/* FILE_ACTION_SUBDIR_CHANGED */
601bfe5e73Gordon Ross	FILE_NOTIFY_CHANGE_EV_SUBDIR,
602a90cf9fGordon Ross
603a90cf9fGordon Ross	/* FILE_ACTION_DELETE_PENDING */
604bfe5e73Gordon Ross	FILE_NOTIFY_CHANGE_EV_DELETE,
605bfe5e73Gordon Ross
606bfe5e73Gordon Ross	/* FILE_ACTION_HANDLE_CLOSED */
607bfe5e73Gordon Ross	FILE_NOTIFY_CHANGE_EV_CLOSED,
608a90cf9fGordon Ross};
609a90cf9fGordon Rossstatic const int smb_notify_action_nelm =
610a90cf9fGordon Ross	sizeof (smb_notify_action_mask) /
611a90cf9fGordon Ross	sizeof (smb_notify_action_mask[0]);
612a90cf9fGordon Ross
613a90cf9fGordon Ross/*
614bfe5e73Gordon Ross * smb_notify_ofile
615a90cf9fGordon Ross *
616bfe5e73Gordon Ross * Post an event to the change notify buffer for this ofile,
617bfe5e73Gordon Ross * subject to the mask that selects subscribed event types.
618bfe5e73Gordon Ross * If an SR is waiting for events and we've delivered some,
619bfe5e73Gordon Ross * wake the SR.
620a90cf9fGordon Ross */
621bfe5e73Gordon Rossvoid
622bfe5e73Gordon Rosssmb_notify_ofile(smb_ofile_t *of, uint_t action, const char *name)
623a90cf9fGordon Ross{
624bfe5e73Gordon Ross	smb_notify_t	*nc;
625bfe5e73Gordon Ross	smb_request_t	*sr;
626bfe5e73Gordon Ross	uint32_t	filter, events;
627a90cf9fGordon Ross
628bfe5e73Gordon Ross	SMB_OFILE_VALID(of);
629bfe5e73Gordon Ross
630bfe5e73Gordon Ross	mutex_enter(&of->f_mutex);
631bfe5e73Gordon Ross	nc = &of->f_notify;
632a90cf9fGordon Ross
633a90cf9fGordon Ross	/*
634bfe5e73Gordon Ross	 * Compute the filter & event bits for this action,
635bfe5e73Gordon Ross	 * which determine whether we'll post the event.
636bfe5e73Gordon Ross	 * Note: always sensitive to: delete, closed.
637a90cf9fGordon Ross	 */
638bfe5e73Gordon Ross	filter = nc->nc_filter |
639bfe5e73Gordon Ross	    FILE_NOTIFY_CHANGE_EV_DELETE |
640bfe5e73Gordon Ross	    FILE_NOTIFY_CHANGE_EV_CLOSED;
641a90cf9fGordon Ross	VERIFY(action < smb_notify_action_nelm);
642bfe5e73Gordon Ross	events = smb_notify_action_mask[action];
643bfe5e73Gordon Ross	if ((filter & events) == 0)
644bfe5e73Gordon Ross		goto unlock_out;
645a90cf9fGordon Ross
646bfe5e73Gordon Ross	/*
647bfe5e73Gordon Ross	 * OK, we're going to post this event.
648bfe5e73Gordon Ross	 */
649bfe5e73Gordon Ross	switch (action) {
650bfe5e73Gordon Ross	case FILE_ACTION_ADDED:
651bfe5e73Gordon Ross	case FILE_ACTION_REMOVED:
652bfe5e73Gordon Ross	case FILE_ACTION_MODIFIED:
653bfe5e73Gordon Ross	case FILE_ACTION_RENAMED_OLD_NAME:
654bfe5e73Gordon Ross	case FILE_ACTION_RENAMED_NEW_NAME:
655bfe5e73Gordon Ross	case FILE_ACTION_ADDED_STREAM:
656bfe5e73Gordon Ross	case FILE_ACTION_REMOVED_STREAM:
657bfe5e73Gordon Ross	case FILE_ACTION_MODIFIED_STREAM:
658bfe5e73Gordon Ross		/*
659bfe5e73Gordon Ross		 * Append this event to the buffer.
660bfe5e73Gordon Ross		 * Also keep track of events seen.
661bfe5e73Gordon Ross		 */
662bfe5e73Gordon Ross		smb_notify_encode_action(of, action, name);
663bfe5e73Gordon Ross		nc->nc_events |= events;
664bfe5e73Gordon Ross		break;
665bfe5e73Gordon Ross
666bfe5e73Gordon Ross	case FILE_ACTION_SUBDIR_CHANGED:
667bfe5e73Gordon Ross	case FILE_ACTION_DELETE_PENDING:
668bfe5e73Gordon Ross	case FILE_ACTION_HANDLE_CLOSED:
669a90cf9fGordon Ross		/*
670bfe5e73Gordon Ross		 * These are "internal" events, and therefore
671bfe5e73Gordon Ross		 * are not appended to the response buffer.
672bfe5e73Gordon Ross		 * Just record the event flags and wakeup.
673a90cf9fGordon Ross		 */
674bfe5e73Gordon Ross		nc->nc_events |= events;
675bfe5e73Gordon Ross		break;
676bfe5e73Gordon Ross
677bfe5e73Gordon Ross	default:
678bfe5e73Gordon Ross		ASSERT(0);	/* bogus action */
679bfe5e73Gordon Ross		break;
680a90cf9fGordon Ross	}
681bfe5e73Gordon Ross
682bfe5e73Gordon Ross	sr = list_head(&nc->nc_waiters);
683bfe5e73Gordon Ross	while (sr != NULL) {
684bfe5e73Gordon Ross		smb_notify_wakeup(sr);
685bfe5e73Gordon Ross		sr = list_next(&nc->nc_waiters, sr);
686bfe5e73Gordon Ross	}
687bfe5e73Gordon Ross
688bfe5e73Gordon Rossunlock_out:
689bfe5e73Gordon Ross	mutex_exit(&of->f_mutex);
690bfe5e73Gordon Ross}
691bfe5e73Gordon Ross
692bfe5e73Gordon Ross/*
693bfe5e73Gordon Ross * Encode a FILE_NOTIFY_INFORMATION struct.
694bfe5e73Gordon Ross */
695bfe5e73Gordon Rossstatic void
696bfe5e73Gordon Rosssmb_notify_encode_action(smb_ofile_t *of,
697bfe5e73Gordon Ross    uint32_t action, const char *fname)
698bfe5e73Gordon Ross{
699bfe5e73Gordon Ross	smb_notify_t *nc = &of->f_notify;
700bfe5e73Gordon Ross	mbuf_chain_t *mbc;
701bfe5e73Gordon Ross	uint32_t namelen, totlen;
702bfe5e73Gordon Ross
703bfe5e73Gordon Ross	ASSERT(nc != NULL);
704bfe5e73Gordon Ross	ASSERT(FILE_ACTION_ADDED <= action &&
705bfe5e73Gordon Ross	    action <= FILE_ACTION_MODIFIED_STREAM);
706bfe5e73Gordon Ross	ASSERT(fname != NULL);
707bfe5e73Gordon Ross	ASSERT(MUTEX_HELD(&of-&g