xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c (revision a90cf9f29973990687fa61de9f1f6ea22e924e40)
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 2015 Nexenta Systems, Inc.  All rights reserved.
25  */
26 
27 /*
28  * File Change Notification (FCN)
29  * SMB1 specific part.
30  */
31 
32 /*
33  * SMB: nt_transact_notify_change
34  *
35  *  Client Setup Words                 Description
36  *  ================================== =================================
37  *
38  *  ULONG CompletionFilter;            Specifies operation to monitor
39  *  USHORT Fid;                        Fid of directory to monitor
40  *  BOOLEAN WatchTree;                 TRUE = watch all subdirectories too
41  *  UCHAR Reserved;                    MBZ
42  *
43  * This command notifies the client when the directory specified by Fid is
44  * modified.  See smb_notify.c for details.
45  *
46  * The MaxParameterCount field in the NT transact header determines
47  * the size of the buffer used to return change information:
48  *
49  *  Server Response                    Description
50  *  ================================== ================================
51  *  ParameterCount                     # of bytes of change data
52  *  Parameters[ ParameterCount ]       FILE_NOTIFY_INFORMATION
53  *                                      structures
54  *
55  * See smb_notify.c for details of FILE_NOTIFY_INFORMATION
56  */
57 
58 #include <smbsrv/smb_kproto.h>
59 
60 /*
61  * We add this flag to the CompletionFilter (see above) when the
62  * client sets WatchTree.  Must not overlap FILE_NOTIFY_VALID_MASK.
63  */
64 #define	NODE_FLAGS_WATCH_TREE		0x10000000
65 #if (NODE_FLAGS_WATCH_TREE & FILE_NOTIFY_VALID_MASK)
66 #error "NODE_FLAGS_WATCH_TREE"
67 #endif
68 
69 /*
70  * smb_nt_transact_notify_change
71  *
72  * Handle and SMB NT transact NOTIFY CHANGE request.
73  * Basically, wait until "something has changed", and either
74  * return information about what changed, or return a special
75  * error telling the client "many things changed".
76  *
77  * The implementation uses a per-node list of waiting notify
78  * requests like this one, each with a blocked worker thead.
79  * Later, FEM and/or smbsrv events wake these threads, which
80  * then send the reply to the client.
81  */
82 smb_sdrc_t
83 smb_nt_transact_notify_change(smb_request_t *sr, struct smb_xa *xa)
84 {
85 	uint32_t		CompletionFilter;
86 	unsigned char		WatchTree;
87 	uint32_t		status;
88 	hrtime_t		t1, t2;
89 
90 	if (smb_mbc_decodef(&xa->req_setup_mb, "lwb",
91 	    &CompletionFilter, &sr->smb_fid, &WatchTree) != 0) {
92 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0);
93 		return (SDRC_ERROR);
94 	}
95 	CompletionFilter &= FILE_NOTIFY_VALID_MASK;
96 	if (WatchTree)
97 		CompletionFilter |= NODE_FLAGS_WATCH_TREE;
98 
99 	smbsr_lookup_file(sr);
100 
101 	t1 = gethrtime();
102 	status = smb_notify_common(sr, &xa->rep_data_mb, CompletionFilter);
103 	t2 = gethrtime();
104 
105 	/*
106 	 * We don't want to include the (indefinite) wait time of the
107 	 * smb_notify_common() call in the SMB1 transact latency.
108 	 * The easiest way to do that, without adding special case
109 	 * logic to the common SMB1 dispatch handler is to adjust the
110 	 * start time of this request to effectively subtract out the
111 	 * time we were blocked in smb_notify_common().
112 	 */
113 	sr->sr_time_start += (t2 - t1);
114 
115 	if (status != 0)
116 		smbsr_error(sr, status, 0, 0);
117 
118 	return (SDRC_SUCCESS);
119 }
120