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