Print this page
NEX-13644 File access audit logging
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-17779 Creating named streams on existing files is not quite right
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-2807 Restoring previous versions from snapshots doesn't work with nested folders.
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15931 Panic removing files in SMB3 CA share
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Include in backports of:
NEX-9808 SMB3 persistent handles
NEX-15931 Panic removing files in SMB3 CA share
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Include in backports of:
NEX-9808 SMB3 persistent handles
NEX-9808 SMB3 persistent handles
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15578 SMB2 durable handle redesign
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-5665 SMB2 oplock leases
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-15069 smtorture smb2.create.blob is failed
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-9808 SMB3 persistent handles
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15578 SMB2 durable handle redesign
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-5665 SMB2 oplock leases
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-15069 smtorture smb2.create.blob is failed
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-13653 Obsolete SMB server work-around for ZFS read-only
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-9604 SMB: smb2 does not delete a read-only file, where smb1 does
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-6041 Should pass the smbtorture lock tests
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
NEX-5312 delete_on_close should be acted on earlier
Reviewed by: Gordon Ross <gwr@nexenta.com>
NEX-3906 Prefer that SMB change notify not tie up a worker thread
NEX-5278 SMB notify should buffer per file handle
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
NEX-4083 Upstream changes from illumos 5917 and 5995
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-3620 need upstream cleanups for smbsrv
Reviewed by: Hans Rosenfeld <hans.rosenfeld@nexenta.com>
SMB-142 Deadlock in SMB2
SMB-131 Don't allow setting delete-on-close on non empty dirs
SMB-11 SMB2 message parse & dispatch
SMB-12 SMB2 Negotiate Protocol
SMB-13 SMB2 Session Setup
SMB-14 SMB2 Logoff
SMB-15 SMB2 Tree Connect
SMB-16 SMB2 Tree Disconnect
SMB-17 SMB2 Create
SMB-18 SMB2 Close
SMB-19 SMB2 Flush
SMB-20 SMB2 Read
SMB-21 SMB2 Write
SMB-22 SMB2 Lock/Unlock
SMB-23 SMB2 Ioctl
SMB-24 SMB2 Cancel
SMB-25 SMB2 Echo
SMB-26 SMB2 Query Dir
SMB-27 SMB2 Change Notify
SMB-28 SMB2 Query Info
SMB-29 SMB2 Set Info
SMB-30 SMB2 Oplocks
SMB-53 SMB2 Create Context options
(SMB2 code review cleanup 1, 2, 3)
SMB-50 User-mode SMB server
Includes work by these authors:
Thomas Keiser <thomas.keiser@nexenta.com>
Albert Lee <trisk@nexenta.com>
SMB-65 SMB server in non-global zones (use zone_kcred())
SMB-65 SMB server in non-global zones (kmem_caches)
common kmem_cache instances across zones
separate GZ-only init from NGZ init
SUP-599 smb_oplock_acquire thread deadlock
re #7815 SMB server delivers old modification time... (fix allocsz)
re #13470 rb4432 Sync some SMB differences from illumos
re #7815 SMB server delivers old modification time...
re #11215 rb3676 sesctl to SGI JBOD hangs in biowait() with a command stuck in mptsas driver
re #10734 NT Trans. Notify returning too quickly
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/fs/smbsrv/smb_node.c
+++ new/usr/src/uts/common/fs/smbsrv/smb_node.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
|
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 - * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
23 + * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
24 24 */
25 25 /*
26 26 * SMB Node State Machine
27 27 * ----------------------
28 28 *
29 29 *
30 30 * +----------- Creation/Allocation
31 31 * |
32 32 * | T0
33 33 * |
34 34 * v
35 35 * +----------------------------+
36 36 * | SMB_NODE_STATE_AVAILABLE |
37 37 * +----------------------------+
38 38 * |
39 39 * | T1
40 40 * |
41 41 * v
42 42 * +-----------------------------+
43 43 * | SMB_NODE_STATE_DESTROYING |
44 44 * +-----------------------------+
45 45 * |
46 46 * |
47 47 * | T2
48 48 * |
49 49 * +----------> Deletion/Free
50 50 *
51 51 * Transition T0
52 52 *
53 53 * This transition occurs in smb_node_lookup(). If the node looked for is
54 54 * not found in the has table a new node is created. The reference count is
55 55 * initialized to 1 and the state initialized to SMB_NODE_STATE_AVAILABLE.
56 56 *
57 57 * Transition T1
58 58 *
59 59 * This transition occurs in smb_node_release(). If the reference count
60 60 * drops to zero the state is moved to SMB_NODE_STATE_DESTROYING and no more
61 61 * reference count will be given out for that node.
62 62 *
63 63 * Transition T2
64 64 *
65 65 * This transition occurs in smb_node_release(). The structure is deleted.
66 66 *
67 67 * Comments
68 68 * --------
69 69 *
70 70 * The reason the smb node has 2 states is the following synchronization
71 71 * rule:
72 72 *
73 73 * There's a mutex embedded in the node used to protect its fields and
74 74 * there's a lock embedded in the bucket of the hash table the node belongs
75 75 * to. To increment or to decrement the reference count the mutex must be
76 76 * entered. To insert the node into the bucket and to remove it from the
77 77 * bucket the lock must be entered in RW_WRITER mode. When both (mutex and
78 78 * lock) have to be entered, the lock has always to be entered first then
79 79 * the mutex. This prevents a deadlock between smb_node_lookup() and
80 80 * smb_node_release() from occurring. However, in smb_node_release() when the
|
↓ open down ↓ |
47 lines elided |
↑ open up ↑ |
81 81 * reference count drops to zero and triggers the deletion of the node, the
82 82 * mutex has to be released before entering the lock of the bucket (to
83 83 * remove the node). This creates a window during which the node that is
84 84 * about to be freed could be given out by smb_node_lookup(). To close that
85 85 * window the node is moved to the state SMB_NODE_STATE_DESTROYING before
86 86 * releasing the mutex. That way, even if smb_node_lookup() finds it, the
87 87 * state will indicate that the node should be treated as non existent (of
88 88 * course the state of the node should be tested/updated under the
89 89 * protection of the mutex).
90 90 */
91 -#include <smbsrv/smb_kproto.h>
91 +#include <smbsrv/smb2_kproto.h>
92 92 #include <smbsrv/smb_fsops.h>
93 93 #include <smbsrv/smb_kstat.h>
94 94 #include <sys/ddi.h>
95 95 #include <sys/extdirent.h>
96 96 #include <sys/pathname.h>
97 97 #include <sys/sdt.h>
98 98 #include <sys/nbmlock.h>
99 99 #include <fs/fs_reparse.h>
100 100
101 101 uint32_t smb_is_executable(char *);
102 -static void smb_node_delete_on_close(smb_node_t *);
103 102 static void smb_node_create_audit_buf(smb_node_t *, int);
104 103 static void smb_node_destroy_audit_buf(smb_node_t *);
105 104 static void smb_node_audit(smb_node_t *);
106 105 static smb_node_t *smb_node_alloc(char *, vnode_t *, smb_llist_t *, uint32_t);
107 106 static void smb_node_free(smb_node_t *);
108 107 static int smb_node_constructor(void *, void *, int);
109 108 static void smb_node_destructor(void *, void *);
110 109 static smb_llist_t *smb_node_get_hash(fsid_t *, smb_attr_t *, uint32_t *);
111 110
112 111 static void smb_node_init_reparse(smb_node_t *, smb_attr_t *);
113 112 static void smb_node_init_system(smb_node_t *);
114 113
115 114 #define VALIDATE_DIR_NODE(_dir_, _node_) \
116 115 ASSERT((_dir_)->n_magic == SMB_NODE_MAGIC); \
117 116 ASSERT(((_dir_)->vp->v_xattrdir) || ((_dir_)->vp->v_type == VDIR)); \
118 117 ASSERT((_dir_)->n_dnode != (_node_));
119 118
120 119 /* round sz to DEV_BSIZE block */
121 120 #define SMB_ALLOCSZ(sz) (((sz) + DEV_BSIZE-1) & ~(DEV_BSIZE-1))
122 121
123 122 static kmem_cache_t *smb_node_cache = NULL;
124 123 static smb_llist_t smb_node_hash_table[SMBND_HASH_MASK+1];
125 124 static smb_node_t *smb_root_node;
126 125
127 126 /*
128 127 * smb_node_init
129 128 *
130 129 * Initialization of the SMB node layer.
131 130 *
132 131 * This function is not multi-thread safe. The caller must make sure only one
133 132 * thread makes the call.
134 133 */
135 134 void
136 135 smb_node_init(void)
137 136 {
138 137 smb_attr_t attr;
139 138 smb_llist_t *node_hdr;
140 139 smb_node_t *node;
141 140 uint32_t hashkey;
142 141 int i;
143 142
144 143 if (smb_node_cache != NULL)
145 144 return;
146 145
147 146 smb_node_cache = kmem_cache_create(SMBSRV_KSTAT_NODE_CACHE,
148 147 sizeof (smb_node_t), 8, smb_node_constructor, smb_node_destructor,
149 148 NULL, NULL, NULL, 0);
150 149
151 150 for (i = 0; i <= SMBND_HASH_MASK; i++) {
152 151 smb_llist_constructor(&smb_node_hash_table[i],
153 152 sizeof (smb_node_t), offsetof(smb_node_t, n_lnd));
154 153 }
155 154
156 155 /*
157 156 * The node cache is shared by all zones, so the smb_root_node
158 157 * must represent the real (global zone) rootdir.
159 158 * Note intentional use of kcred here.
160 159 */
161 160 attr.sa_mask = SMB_AT_ALL;
162 161 VERIFY0(smb_vop_getattr(rootdir, NULL, &attr, 0, kcred));
163 162 node_hdr = smb_node_get_hash(&rootdir->v_vfsp->vfs_fsid, &attr,
164 163 &hashkey);
165 164 node = smb_node_alloc("/", rootdir, node_hdr, hashkey);
166 165 smb_llist_enter(node_hdr, RW_WRITER);
167 166 smb_llist_insert_head(node_hdr, node);
168 167 smb_llist_exit(node_hdr);
169 168 smb_root_node = node; /* smb_node_release in smb_node_fini */
170 169 }
171 170
172 171 /*
173 172 * smb_node_fini
174 173 *
175 174 * This function is not multi-thread safe. The caller must make sure only one
176 175 * thread makes the call.
177 176 */
178 177 void
179 178 smb_node_fini(void)
180 179 {
181 180 int i;
182 181
|
↓ open down ↓ |
70 lines elided |
↑ open up ↑ |
183 182 if (smb_root_node != NULL) {
184 183 smb_node_release(smb_root_node);
185 184 smb_root_node = NULL;
186 185 }
187 186
188 187 if (smb_node_cache == NULL)
189 188 return;
190 189
191 190 #ifdef DEBUG
192 191 for (i = 0; i <= SMBND_HASH_MASK; i++) {
192 + smb_llist_t *bucket;
193 193 smb_node_t *node;
194 194
195 195 /*
196 196 * The following sequence is just intended for sanity check.
197 197 * This will have to be modified when the code goes into
198 198 * production.
199 199 *
200 200 * The SMB node hash table should be emtpy at this point. If the
201 201 * hash table is not empty a panic will be triggered.
202 202 *
203 203 * The reason why SMB nodes are still remaining in the hash
204 204 * table is problably due to a mismatch between calls to
205 205 * smb_node_lookup() and smb_node_release(). You must track that
206 206 * down.
207 207 */
208 - node = smb_llist_head(&smb_node_hash_table[i]);
209 - ASSERT(node == NULL);
208 + bucket = &smb_node_hash_table[i];
209 + node = smb_llist_head(bucket);
210 + while (node != NULL) {
211 + cmn_err(CE_NOTE, "leaked node: 0x%p %s",
212 + (void *)node, node->od_name);
213 + node = smb_llist_next(bucket, node);
214 + }
210 215 }
211 216 #endif
212 217
213 218 for (i = 0; i <= SMBND_HASH_MASK; i++) {
214 219 smb_llist_destructor(&smb_node_hash_table[i]);
215 220 }
216 221 kmem_cache_destroy(smb_node_cache);
217 222 smb_node_cache = NULL;
218 223 }
219 224
220 225 /*
221 226 * smb_node_lookup()
222 227 *
223 228 * NOTE: This routine should only be called by the file system interface layer,
224 229 * and not by SMB.
225 230 *
226 231 * smb_node_lookup() is called upon successful lookup, mkdir, and create
227 232 * (for both non-streams and streams). In each of these cases, a held vnode is
228 233 * passed into this routine. If a new smb_node is created it will take its
229 234 * own hold on the vnode. The caller's hold therefore still belongs to, and
230 235 * should be released by, the caller.
231 236 *
232 237 * A reference is taken on the smb_node whether found in the hash table
233 238 * or newly created.
234 239 *
235 240 * If an smb_node needs to be created, a reference is also taken on the
236 241 * dnode (if passed in).
237 242 *
238 243 * See smb_node_release() for details on the release of these references.
239 244 */
240 245
241 246 /*ARGSUSED*/
242 247 smb_node_t *
243 248 smb_node_lookup(
244 249 struct smb_request *sr,
245 250 struct open_param *op,
246 251 cred_t *cred,
247 252 vnode_t *vp,
248 253 char *od_name,
249 254 smb_node_t *dnode,
250 255 smb_node_t *unode)
251 256 {
252 257 smb_llist_t *node_hdr;
253 258 smb_node_t *node;
254 259 smb_attr_t attr;
255 260 uint32_t hashkey = 0;
256 261 fsid_t fsid;
257 262 int error;
258 263 krw_t lock_mode;
259 264 vnode_t *unnamed_vp = NULL;
260 265
261 266 /*
262 267 * smb_vop_getattr() is called here instead of smb_fsop_getattr(),
263 268 * because the node may not yet exist. We also do not want to call
264 269 * it with the list lock held.
265 270 */
266 271
267 272 if (unode)
268 273 unnamed_vp = unode->vp;
269 274
270 275 /*
271 276 * This getattr is performed on behalf of the server
272 277 * that's why kcred is used not the user's cred
273 278 */
274 279 attr.sa_mask = SMB_AT_ALL;
275 280 error = smb_vop_getattr(vp, unnamed_vp, &attr, 0, zone_kcred());
276 281 if (error)
277 282 return (NULL);
278 283
279 284 if (sr && sr->tid_tree) {
280 285 /*
281 286 * The fsid for a file is that of the tree, even
282 287 * if the file resides in a different mountpoint
283 288 * under the share.
284 289 */
285 290 fsid = SMB_TREE_FSID(sr->tid_tree);
286 291 } else {
287 292 /*
288 293 * This should be getting executed only for the
289 294 * tree root smb_node.
290 295 */
291 296 fsid = vp->v_vfsp->vfs_fsid;
292 297 }
293 298
294 299 node_hdr = smb_node_get_hash(&fsid, &attr, &hashkey);
295 300 lock_mode = RW_READER;
296 301
297 302 smb_llist_enter(node_hdr, lock_mode);
298 303 for (;;) {
299 304 node = list_head(&node_hdr->ll_list);
300 305 while (node) {
301 306 ASSERT(node->n_magic == SMB_NODE_MAGIC);
302 307 ASSERT(node->n_hash_bucket == node_hdr);
303 308 if ((node->n_hashkey == hashkey) && (node->vp == vp)) {
304 309 mutex_enter(&node->n_mutex);
305 310 DTRACE_PROBE1(smb_node_lookup_hit,
306 311 smb_node_t *, node);
307 312 switch (node->n_state) {
308 313 case SMB_NODE_STATE_AVAILABLE:
309 314 /* The node was found. */
310 315 node->n_refcnt++;
311 316 if ((node->n_dnode == NULL) &&
312 317 (dnode != NULL) &&
313 318 (node != dnode) &&
314 319 (strcmp(od_name, "..") != 0) &&
315 320 (strcmp(od_name, ".") != 0)) {
316 321 VALIDATE_DIR_NODE(dnode, node);
317 322 node->n_dnode = dnode;
318 323 smb_node_ref(dnode);
319 324 }
320 325
321 326 smb_node_audit(node);
322 327 mutex_exit(&node->n_mutex);
323 328 smb_llist_exit(node_hdr);
324 329 return (node);
325 330
326 331 case SMB_NODE_STATE_DESTROYING:
327 332 /*
328 333 * Although the node exists it is about
329 334 * to be destroyed. We act as it hasn't
330 335 * been found.
331 336 */
332 337 mutex_exit(&node->n_mutex);
333 338 break;
334 339 default:
335 340 /*
336 341 * Although the node exists it is in an
337 342 * unknown state. We act as it hasn't
338 343 * been found.
339 344 */
340 345 ASSERT(0);
341 346 mutex_exit(&node->n_mutex);
342 347 break;
343 348 }
344 349 }
345 350 node = smb_llist_next(node_hdr, node);
346 351 }
347 352 if ((lock_mode == RW_READER) && smb_llist_upgrade(node_hdr)) {
348 353 lock_mode = RW_WRITER;
349 354 continue;
350 355 }
351 356 break;
352 357 }
353 358 node = smb_node_alloc(od_name, vp, node_hdr, hashkey);
354 359 smb_node_init_reparse(node, &attr);
355 360
356 361 if (op)
357 362 node->flags |= smb_is_executable(op->fqi.fq_last_comp);
358 363
359 364 if (dnode) {
360 365 smb_node_ref(dnode);
361 366 node->n_dnode = dnode;
362 367 ASSERT(dnode->n_dnode != node);
363 368 ASSERT((dnode->vp->v_xattrdir) ||
364 369 (dnode->vp->v_type == VDIR));
365 370 }
366 371
367 372 if (unode) {
368 373 smb_node_ref(unode);
369 374 node->n_unode = unode;
370 375 }
371 376
372 377 smb_node_init_system(node);
373 378
374 379 DTRACE_PROBE1(smb_node_lookup_miss, smb_node_t *, node);
375 380 smb_node_audit(node);
376 381 smb_llist_insert_head(node_hdr, node);
377 382 smb_llist_exit(node_hdr);
378 383 return (node);
379 384 }
380 385
381 386 /*
382 387 * smb_stream_node_lookup()
383 388 *
384 389 * Note: stream_name (the name that will be stored in the "od_name" field
385 390 * of a stream's smb_node) is the same as the on-disk name for the stream
386 391 * except that it does not have SMB_STREAM_PREFIX prepended.
387 392 */
388 393
389 394 smb_node_t *
390 395 smb_stream_node_lookup(smb_request_t *sr, cred_t *cr, smb_node_t *fnode,
391 396 vnode_t *xattrdirvp, vnode_t *vp, char *stream_name)
392 397 {
393 398 smb_node_t *xattrdir_node;
394 399 smb_node_t *snode;
395 400
396 401 xattrdir_node = smb_node_lookup(sr, NULL, cr, xattrdirvp, XATTR_DIR,
397 402 fnode, NULL);
398 403
399 404 if (xattrdir_node == NULL)
400 405 return (NULL);
401 406
402 407 snode = smb_node_lookup(sr, NULL, cr, vp, stream_name, xattrdir_node,
403 408 fnode);
404 409
405 410 (void) smb_node_release(xattrdir_node);
406 411 return (snode);
407 412 }
408 413
409 414
410 415 /*
411 416 * This function should be called whenever a reference is needed on an
412 417 * smb_node pointer. The copy of an smb_node pointer from one non-local
413 418 * data structure to another requires a reference to be taken on the smb_node
414 419 * (unless the usage is localized). Each data structure deallocation routine
415 420 * will call smb_node_release() on its smb_node pointers.
416 421 *
417 422 * In general, an smb_node pointer residing in a structure should never be
418 423 * stale. A node pointer may be NULL, however, and care should be taken
419 424 * prior to calling smb_node_ref(), which ASSERTs that the pointer is valid.
420 425 * Care also needs to be taken with respect to racing deallocations of a
421 426 * structure.
422 427 */
423 428 void
424 429 smb_node_ref(smb_node_t *node)
425 430 {
426 431 SMB_NODE_VALID(node);
427 432
428 433 mutex_enter(&node->n_mutex);
429 434 switch (node->n_state) {
430 435 case SMB_NODE_STATE_AVAILABLE:
431 436 node->n_refcnt++;
432 437 ASSERT(node->n_refcnt);
433 438 DTRACE_PROBE1(smb_node_ref_exit, smb_node_t *, node);
434 439 smb_node_audit(node);
435 440 break;
436 441 default:
437 442 SMB_PANIC();
438 443 }
439 444 mutex_exit(&node->n_mutex);
440 445 }
441 446
442 447 /*
443 448 * smb_node_lookup() takes a hold on an smb_node, whether found in the
444 449 * hash table or newly created. This hold is expected to be released
445 450 * in the following manner.
446 451 *
447 452 * smb_node_lookup() takes an address of an smb_node pointer. This should
448 453 * be getting passed down via a lookup (whether path name or component), mkdir,
449 454 * create. If the original smb_node pointer resides in a data structure, then
450 455 * the deallocation routine for the data structure is responsible for calling
451 456 * smb_node_release() on the smb_node pointer. Alternatively,
452 457 * smb_node_release() can be called as soon as the smb_node pointer is no longer
453 458 * needed. In this case, callers are responsible for setting an embedded
454 459 * pointer to NULL if it is known that the last reference is being released.
455 460 *
456 461 * If the passed-in address of the smb_node pointer belongs to a local variable,
457 462 * then the caller with the local variable should call smb_node_release()
458 463 * directly.
459 464 *
460 465 * smb_node_release() itself will call smb_node_release() on a node's n_dnode,
461 466 * as smb_node_lookup() takes a hold on dnode.
462 467 */
463 468 void
464 469 smb_node_release(smb_node_t *node)
465 470 {
466 471 SMB_NODE_VALID(node);
467 472
468 473 mutex_enter(&node->n_mutex);
469 474 ASSERT(node->n_refcnt);
470 475 DTRACE_PROBE1(smb_node_release, smb_node_t *, node);
471 476 if (--node->n_refcnt == 0) {
472 477 switch (node->n_state) {
473 478
474 479 case SMB_NODE_STATE_AVAILABLE:
|
↓ open down ↓ |
255 lines elided |
↑ open up ↑ |
475 480 node->n_state = SMB_NODE_STATE_DESTROYING;
476 481 mutex_exit(&node->n_mutex);
477 482
478 483 smb_llist_enter(node->n_hash_bucket, RW_WRITER);
479 484 smb_llist_remove(node->n_hash_bucket, node);
480 485 smb_llist_exit(node->n_hash_bucket);
481 486
482 487 /*
483 488 * Check if the file was deleted
484 489 */
485 - smb_node_delete_on_close(node);
490 + if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
491 + smb_node_delete_on_close(node);
492 + }
486 493
487 494 if (node->n_dnode) {
488 495 ASSERT(node->n_dnode->n_magic ==
489 496 SMB_NODE_MAGIC);
490 497 smb_node_release(node->n_dnode);
491 498 }
492 499
493 500 if (node->n_unode) {
494 501 ASSERT(node->n_unode->n_magic ==
495 502 SMB_NODE_MAGIC);
496 503 smb_node_release(node->n_unode);
497 504 }
498 505
499 506 smb_node_free(node);
|
↓ open down ↓ |
4 lines elided |
↑ open up ↑ |
500 507 return;
501 508
502 509 default:
503 510 SMB_PANIC();
504 511 }
505 512 }
506 513 smb_node_audit(node);
507 514 mutex_exit(&node->n_mutex);
508 515 }
509 516
510 -static void
517 +void
511 518 smb_node_delete_on_close(smb_node_t *node)
512 519 {
513 520 smb_node_t *d_snode;
514 521 int rc = 0;
515 522 uint32_t flags = 0;
516 523
517 524 d_snode = node->n_dnode;
518 - if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
519 - node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
520 - flags = node->n_delete_on_close_flags;
521 - ASSERT(node->od_name != NULL);
522 525
523 - if (smb_node_is_dir(node))
524 - rc = smb_fsop_rmdir(0, node->delete_on_close_cred,
525 - d_snode, node->od_name, flags);
526 - else
527 - rc = smb_fsop_remove(0, node->delete_on_close_cred,
528 - d_snode, node->od_name, flags);
529 - crfree(node->delete_on_close_cred);
530 - }
526 + ASSERT((node->flags & NODE_FLAGS_DELETE_ON_CLOSE) != 0);
527 +
528 + node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
529 + node->flags |= NODE_FLAGS_DELETE_COMMITTED;
530 + flags = node->n_delete_on_close_flags;
531 + ASSERT(node->od_name != NULL);
532 +
533 + if (smb_node_is_dir(node))
534 + rc = smb_fsop_rmdir(0, node->delete_on_close_cred,
535 + d_snode, node->od_name, flags);
536 + else
537 + rc = smb_fsop_remove(0, node->delete_on_close_cred,
538 + d_snode, node->od_name, flags);
539 + crfree(node->delete_on_close_cred);
540 + node->delete_on_close_cred = NULL;
541 +
531 542 if (rc != 0)
532 543 cmn_err(CE_WARN, "File %s could not be removed, rc=%d\n",
533 544 node->od_name, rc);
534 545 DTRACE_PROBE2(smb_node_delete_on_close, int, rc, smb_node_t *, node);
535 546 }
536 547
537 548 /*
538 549 * smb_node_rename()
539 550 *
540 551 */
541 552 void
542 553 smb_node_rename(
543 554 smb_node_t *from_dnode,
544 555 smb_node_t *ret_node,
545 556 smb_node_t *to_dnode,
546 557 char *to_name)
547 558 {
548 559 SMB_NODE_VALID(from_dnode);
549 560 SMB_NODE_VALID(to_dnode);
550 561 SMB_NODE_VALID(ret_node);
551 562
552 563 smb_node_ref(to_dnode);
553 564 mutex_enter(&ret_node->n_mutex);
554 565 switch (ret_node->n_state) {
555 566 case SMB_NODE_STATE_AVAILABLE:
556 567 ret_node->n_dnode = to_dnode;
557 568 mutex_exit(&ret_node->n_mutex);
558 569 ASSERT(to_dnode->n_dnode != ret_node);
559 570 ASSERT((to_dnode->vp->v_xattrdir) ||
560 571 (to_dnode->vp->v_type == VDIR));
561 572 smb_node_release(from_dnode);
562 573 (void) strcpy(ret_node->od_name, to_name);
563 574 /*
564 575 * XXX Need to update attributes?
565 576 */
566 577 break;
567 578 default:
568 579 SMB_PANIC();
569 580 }
570 581 }
571 582
572 583 /*
573 584 * Find/create an SMB node for the root of this zone and store it
574 585 * in *svrootp. Also create nodes leading to this directory.
575 586 */
576 587 int
577 588 smb_node_root_init(smb_server_t *sv, smb_node_t **svrootp)
578 589 {
579 590 zone_t *zone = curzone;
580 591 int error;
|
↓ open down ↓ |
40 lines elided |
↑ open up ↑ |
581 592
582 593 ASSERT(zone->zone_id == sv->sv_zid);
583 594 if (smb_root_node == NULL)
584 595 return (ENOENT);
585 596
586 597 /*
587 598 * We're getting smb nodes below the zone root here,
588 599 * so need to use kcred, not zone_kcred().
589 600 */
590 601 error = smb_pathname(NULL, zone->zone_rootpath, 0,
591 - smb_root_node, smb_root_node, NULL, svrootp, kcred);
602 + smb_root_node, smb_root_node, NULL, svrootp, kcred, NULL);
592 603
593 604 return (error);
594 605 }
595 606
596 607 /*
597 608 * Helper function for smb_node_set_delete_on_close(). Assumes node is a dir.
598 609 * Return 0 if this is an empty dir. Otherwise return a NT_STATUS code.
599 - * We distinguish between readdir failure and non-empty dir by returning
600 - * different values.
610 + * Unfortunately, to find out if a directory is empty, we have to read it
611 + * and check for anything other than "." or ".." in the readdir buf.
601 612 */
602 613 static uint32_t
603 -smb_rmdir_possible(smb_node_t *n, uint32_t flags)
614 +smb_rmdir_possible(smb_node_t *n)
604 615 {
605 616 ASSERT(n->vp->v_type == VDIR);
606 - char buf[512]; /* Only large enough to see if the dir is empty. */
607 - int eof, bsize = sizeof (buf), reclen = 0;
608 - char *name;
609 - boolean_t edp = vfs_has_feature(n->vp->v_vfsp, VFSFT_DIRENTFLAGS);
617 + char *buf;
618 + char *bufptr;
619 + struct dirent64 *dp;
620 + uint32_t status = NT_STATUS_SUCCESS;
621 + int bsize = SMB_ODIR_BUFSIZE;
622 + int eof = 0;
610 623
611 - union {
612 - char *u_bufptr;
613 - struct edirent *u_edp;
614 - struct dirent64 *u_dp;
615 - } u;
616 -#define bufptr u.u_bufptr
617 -#define extdp u.u_edp
618 -#define dp u.u_dp
624 + buf = kmem_alloc(SMB_ODIR_BUFSIZE, KM_SLEEP);
619 625
620 - if (smb_vop_readdir(n->vp, 0, buf, &bsize, &eof, flags, zone_kcred()))
621 - return (NT_STATUS_CANNOT_DELETE);
622 - if (bsize == 0)
623 - return (NT_STATUS_CANNOT_DELETE);
626 + /* Flags zero: no edirent, no ABE wanted here */
627 + if (smb_vop_readdir(n->vp, 0, buf, &bsize, &eof, 0, zone_kcred())) {
628 + status = NT_STATUS_INTERNAL_ERROR;
629 + goto out;
630 + }
631 +
624 632 bufptr = buf;
625 - while ((bufptr += reclen) < buf + bsize) {
626 - if (edp) {
627 - reclen = extdp->ed_reclen;
628 - name = extdp->ed_name;
629 - } else {
630 - reclen = dp->d_reclen;
631 - name = dp->d_name;
633 + while (bsize > 0) {
634 + /* LINTED pointer alignment */
635 + dp = (struct dirent64 *)bufptr;
636 +
637 + bufptr += dp->d_reclen;
638 + bsize -= dp->d_reclen;
639 + if (bsize < 0) {
640 + /* partial record */
641 + status = NT_STATUS_DIRECTORY_NOT_EMPTY;
642 + break;
632 643 }
633 - if (strcmp(name, ".") != 0 && strcmp(name, "..") != 0)
634 - return (NT_STATUS_DIRECTORY_NOT_EMPTY);
644 +
645 + if (strcmp(dp->d_name, ".") != 0 &&
646 + strcmp(dp->d_name, "..") != 0) {
647 + status = NT_STATUS_DIRECTORY_NOT_EMPTY;
648 + break;
649 + }
635 650 }
636 - return (0);
651 +
652 +out:
653 + kmem_free(buf, SMB_ODIR_BUFSIZE);
654 + return (status);
637 655 }
638 656
639 657 /*
640 658 * When DeleteOnClose is set on an smb_node, the common open code will
641 659 * reject subsequent open requests for the file. Observation of Windows
642 660 * 2000 indicates that subsequent opens should be allowed (assuming
643 661 * there would be no sharing violation) until the file is closed using
644 662 * the fid on which the DeleteOnClose was requested.
645 663 *
646 664 * If there are multiple opens with delete-on-close create options,
647 665 * whichever the first file handle is closed will trigger the node to be
648 666 * marked as delete-on-close. The credentials of that ofile will be used
649 667 * as the delete-on-close credentials of the node.
668 + *
669 + * Note that "read-only" tests have already happened before this call.
650 670 */
651 671 uint32_t
652 672 smb_node_set_delete_on_close(smb_node_t *node, cred_t *cr, uint32_t flags)
653 673 {
654 - int rc = 0;
655 674 uint32_t status;
656 - smb_attr_t attr;
657 675
658 - if (node->n_pending_dosattr & FILE_ATTRIBUTE_READONLY)
659 - return (NT_STATUS_CANNOT_DELETE);
660 -
661 - bzero(&attr, sizeof (smb_attr_t));
662 - attr.sa_mask = SMB_AT_DOSATTR;
663 - rc = smb_fsop_getattr(NULL, zone_kcred(), node, &attr);
664 - if ((rc != 0) || (attr.sa_dosattr & FILE_ATTRIBUTE_READONLY)) {
665 - return (NT_STATUS_CANNOT_DELETE);
666 - }
667 -
668 676 /*
669 677 * If the directory is not empty we should fail setting del-on-close
670 678 * with STATUS_DIRECTORY_NOT_EMPTY. see MS's
671 679 * "File System Behavior Overview" doc section 4.3.2
672 680 */
673 681 if (smb_node_is_dir(node)) {
674 - status = smb_rmdir_possible(node, flags);
682 + status = smb_rmdir_possible(node);
675 683 if (status != 0) {
676 684 return (status);
677 685 }
678 686 }
679 687
680 688 mutex_enter(&node->n_mutex);
681 689 if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
690 + /* It was already marked. We're done. */
682 691 mutex_exit(&node->n_mutex);
683 - return (NT_STATUS_CANNOT_DELETE);
692 + return (NT_STATUS_SUCCESS);
684 693 }
685 694
686 695 crhold(cr);
687 696 node->delete_on_close_cred = cr;
688 697 node->n_delete_on_close_flags = flags;
689 698 node->flags |= NODE_FLAGS_DELETE_ON_CLOSE;
690 699 mutex_exit(&node->n_mutex);
691 700
692 701 /*
693 702 * Tell any change notify calls to close their handles
694 703 * and get out of the way. FILE_ACTION_DELETE_PENDING
695 704 * is a special, internal-only action for this purpose.
696 705 */
697 - smb_notify_event(node, FILE_ACTION_DELETE_PENDING, NULL);
706 + smb_node_notify_change(node, FILE_ACTION_DELETE_PENDING, NULL);
698 707
699 708 return (NT_STATUS_SUCCESS);
700 709 }
701 710
702 711 void
703 712 smb_node_reset_delete_on_close(smb_node_t *node)
704 713 {
705 714 mutex_enter(&node->n_mutex);
706 715 if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
707 716 node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
708 717 crfree(node->delete_on_close_cred);
709 718 node->delete_on_close_cred = NULL;
710 719 node->n_delete_on_close_flags = 0;
711 720 }
712 721 mutex_exit(&node->n_mutex);
713 722 }
714 723
715 724 /*
716 725 * smb_node_open_check
717 726 *
718 727 * check file sharing rules for current open request
719 728 * against all existing opens for a file.
720 729 *
721 730 * Returns NT_STATUS_SHARING_VIOLATION if there is any
722 731 * sharing conflict, otherwise returns NT_STATUS_SUCCESS.
723 732 */
724 733 uint32_t
725 734 smb_node_open_check(smb_node_t *node, uint32_t desired_access,
726 735 uint32_t share_access)
727 736 {
728 737 smb_ofile_t *of;
729 738 uint32_t status;
730 739
731 740 SMB_NODE_VALID(node);
732 741
733 742 smb_llist_enter(&node->n_ofile_list, RW_READER);
734 743 of = smb_llist_head(&node->n_ofile_list);
|
↓ open down ↓ |
27 lines elided |
↑ open up ↑ |
735 744 while (of) {
736 745 status = smb_ofile_open_check(of, desired_access, share_access);
737 746
738 747 switch (status) {
739 748 case NT_STATUS_INVALID_HANDLE:
740 749 case NT_STATUS_SUCCESS:
741 750 of = smb_llist_next(&node->n_ofile_list, of);
742 751 break;
743 752 default:
744 753 ASSERT(status == NT_STATUS_SHARING_VIOLATION);
754 + DTRACE_PROBE3(conflict3,
755 + smb_ofile_t, of,
756 + uint32_t, desired_access,
757 + uint32_t, share_access);
745 758 smb_llist_exit(&node->n_ofile_list);
746 759 return (status);
747 760 }
748 761 }
749 762
750 763 smb_llist_exit(&node->n_ofile_list);
751 764 return (NT_STATUS_SUCCESS);
752 765 }
753 766
754 767 uint32_t
755 768 smb_node_rename_check(smb_node_t *node)
756 769 {
757 770 smb_ofile_t *of;
758 771 uint32_t status;
759 772
760 773 SMB_NODE_VALID(node);
761 774
762 775 /*
763 776 * Intra-CIFS check
764 777 */
765 778 smb_llist_enter(&node->n_ofile_list, RW_READER);
766 779 of = smb_llist_head(&node->n_ofile_list);
|
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
767 780 while (of) {
768 781 status = smb_ofile_rename_check(of);
769 782
770 783 switch (status) {
771 784 case NT_STATUS_INVALID_HANDLE:
772 785 case NT_STATUS_SUCCESS:
773 786 of = smb_llist_next(&node->n_ofile_list, of);
774 787 break;
775 788 default:
776 789 ASSERT(status == NT_STATUS_SHARING_VIOLATION);
790 + DTRACE_PROBE1(conflict1, smb_ofile_t, of);
777 791 smb_llist_exit(&node->n_ofile_list);
778 792 return (status);
779 793 }
780 794 }
781 795 smb_llist_exit(&node->n_ofile_list);
782 796 return (NT_STATUS_SUCCESS);
783 797 }
784 798
785 799 uint32_t
786 800 smb_node_delete_check(smb_node_t *node)
787 801 {
788 802 smb_ofile_t *of;
789 803 uint32_t status;
790 804
791 805 SMB_NODE_VALID(node);
792 806
793 807 if (smb_node_is_dir(node))
794 808 return (NT_STATUS_SUCCESS);
795 809
796 810 if (smb_node_is_reparse(node))
797 811 return (NT_STATUS_ACCESS_DENIED);
798 812
799 813 /*
800 814 * intra-CIFS check
801 815 */
802 816 smb_llist_enter(&node->n_ofile_list, RW_READER);
803 817 of = smb_llist_head(&node->n_ofile_list);
|
↓ open down ↓ |
17 lines elided |
↑ open up ↑ |
804 818 while (of) {
805 819 status = smb_ofile_delete_check(of);
806 820
807 821 switch (status) {
808 822 case NT_STATUS_INVALID_HANDLE:
809 823 case NT_STATUS_SUCCESS:
810 824 of = smb_llist_next(&node->n_ofile_list, of);
811 825 break;
812 826 default:
813 827 ASSERT(status == NT_STATUS_SHARING_VIOLATION);
828 + DTRACE_PROBE1(conflict1, smb_ofile_t, of);
814 829 smb_llist_exit(&node->n_ofile_list);
815 830 return (status);
816 831 }
817 832 }
818 833 smb_llist_exit(&node->n_ofile_list);
819 834 return (NT_STATUS_SUCCESS);
820 835 }
821 836
822 837 /*
823 838 * smb_node_share_check
824 839 *
825 840 * Returns: TRUE - ofiles have non-zero share access
826 841 * B_FALSE - ofile with share access NONE.
827 842 */
828 843 boolean_t
829 844 smb_node_share_check(smb_node_t *node)
830 845 {
831 846 smb_ofile_t *of;
832 847 boolean_t status = B_TRUE;
833 848
834 849 SMB_NODE_VALID(node);
835 850
836 851 smb_llist_enter(&node->n_ofile_list, RW_READER);
837 852 of = smb_llist_head(&node->n_ofile_list);
838 853 if (of)
839 854 status = smb_ofile_share_check(of);
|
↓ open down ↓ |
16 lines elided |
↑ open up ↑ |
840 855 smb_llist_exit(&node->n_ofile_list);
841 856
842 857 return (status);
843 858 }
844 859
845 860 /*
846 861 * SMB Change Notification
847 862 */
848 863
849 864 void
850 -smb_node_fcn_subscribe(smb_node_t *node, smb_request_t *sr)
865 +smb_node_fcn_subscribe(smb_node_t *node)
851 866 {
852 - smb_node_fcn_t *fcn = &node->n_fcn;
853 867
854 - mutex_enter(&fcn->fcn_mutex);
855 - if (fcn->fcn_count == 0)
868 + mutex_enter(&node->n_mutex);
869 + if (node->n_fcn_count == 0)
856 870 (void) smb_fem_fcn_install(node);
857 - fcn->fcn_count++;
858 - list_insert_tail(&fcn->fcn_watchers, sr);
859 - mutex_exit(&fcn->fcn_mutex);
871 + node->n_fcn_count++;
872 + mutex_exit(&node->n_mutex);
860 873 }
861 874
862 875 void
863 -smb_node_fcn_unsubscribe(smb_node_t *node, smb_request_t *sr)
876 +smb_node_fcn_unsubscribe(smb_node_t *node)
864 877 {
865 - smb_node_fcn_t *fcn = &node->n_fcn;
866 878
867 - mutex_enter(&fcn->fcn_mutex);
868 - list_remove(&fcn->fcn_watchers, sr);
869 - fcn->fcn_count--;
870 - if (fcn->fcn_count == 0)
879 + mutex_enter(&node->n_mutex);
880 + node->n_fcn_count--;
881 + if (node->n_fcn_count == 0)
871 882 smb_fem_fcn_uninstall(node);
872 - mutex_exit(&fcn->fcn_mutex);
883 + mutex_exit(&node->n_mutex);
873 884 }
874 885
875 886 void
876 887 smb_node_notify_change(smb_node_t *node, uint_t action, const char *name)
877 888 {
889 + smb_ofile_t *of;
890 +
878 891 SMB_NODE_VALID(node);
879 892
880 - smb_notify_event(node, action, name);
893 + smb_llist_enter(&node->n_ofile_list, RW_READER);
894 + of = smb_llist_head(&node->n_ofile_list);
895 + while (of) {
896 + /*
897 + * We'd rather deliver events only to ofiles that have
898 + * subscribed. There's no explicit synchronization with
899 + * where this flag is set, but other actions cause this
900 + * value to reach visibility soon enough for events to
901 + * start arriving by the time we need them to start.
902 + * Once nc_subscribed is set, it stays set for the
903 + * life of the ofile.
904 + */
905 + if (of->f_notify.nc_subscribed)
906 + smb_notify_ofile(of, action, name);
907 + of = smb_llist_next(&node->n_ofile_list, of);
908 + }
909 + smb_llist_exit(&node->n_ofile_list);
881 910
882 911 /*
883 - * These two events come as a pair:
884 - * FILE_ACTION_RENAMED_OLD_NAME
885 - * FILE_ACTION_RENAMED_NEW_NAME
886 - * Only do the parent notify for "new".
912 + * After changes that add or remove a name,
913 + * we know the directory attributes changed,
914 + * and we can tell the immediate parent.
887 915 */
888 - if (action == FILE_ACTION_RENAMED_OLD_NAME)
889 - return;
916 + switch (action) {
917 + case FILE_ACTION_ADDED:
918 + case FILE_ACTION_REMOVED:
919 + case FILE_ACTION_RENAMED_NEW_NAME:
920 + /*
921 + * Note: FILE_ACTION_RENAMED_OLD_NAME is intentionally
922 + * omitted, because it's always followed by another
923 + * event with FILE_ACTION_RENAMED_NEW_NAME posted to
924 + * the same directory, and we only need/want one.
925 + */
926 + if (node->n_dnode != NULL) {
927 + smb_node_notify_change(node->n_dnode,
928 + FILE_ACTION_MODIFIED, node->od_name);
929 + }
930 + break;
931 + }
890 932
891 - smb_node_notify_parents(node);
933 + /*
934 + * If we wanted to support recursive notify events
935 + * (where a notify call on some directory receives
936 + * events from all objects below that directory),
937 + * we might deliver _SUBDIR_CHANGED to all our
938 + * parents, grandparents etc, here. However, we
939 + * don't currently subscribe to changes on all the
940 + * child (and grandchild) objects that would be
941 + * needed to make that work. It's prohibitively
942 + * expensive to do that, and support for recursive
943 + * notify is optional anyway, so don't bother.
944 + */
892 945 }
893 946
894 947 /*
895 - * smb_node_notify_parents
896 - *
897 - * Iterate up the directory tree notifying any parent
898 - * directories that are being watched for changes in
899 - * their sub directories.
900 - * Stop at the root node, which has a NULL parent node.
901 - */
902 -void
903 -smb_node_notify_parents(smb_node_t *dnode)
904 -{
905 - smb_node_t *pnode; /* parent */
906 -
907 - SMB_NODE_VALID(dnode);
908 - pnode = dnode->n_dnode;
909 -
910 - while (pnode != NULL) {
911 - SMB_NODE_VALID(pnode);
912 - smb_notify_event(pnode, FILE_ACTION_SUBDIR_CHANGED, NULL);
913 - /* cd .. */
914 - dnode = pnode;
915 - pnode = dnode->n_dnode;
916 - }
917 -}
918 -
919 -/*
920 948 * smb_node_start_crit()
921 949 *
922 950 * Enter critical region for share reservations.
923 951 * See comments above smb_fsop_shrlock().
924 952 */
925 953 void
926 954 smb_node_start_crit(smb_node_t *node, krw_t mode)
927 955 {
928 956 rw_enter(&node->n_lock, mode);
929 957 nbl_start_crit(node->vp, mode);
930 958 }
931 959
932 960 /*
933 961 * smb_node_end_crit()
934 962 *
935 963 * Exit critical region for share reservations.
936 964 */
937 965 void
938 966 smb_node_end_crit(smb_node_t *node)
939 967 {
940 968 nbl_end_crit(node->vp);
941 969 rw_exit(&node->n_lock);
942 970 }
943 971
944 972 int
945 973 smb_node_in_crit(smb_node_t *node)
946 974 {
947 975 return (nbl_in_crit(node->vp) && RW_LOCK_HELD(&node->n_lock));
948 976 }
949 977
950 978 void
951 979 smb_node_rdlock(smb_node_t *node)
952 980 {
953 981 rw_enter(&node->n_lock, RW_READER);
954 982 }
955 983
956 984 void
957 985 smb_node_wrlock(smb_node_t *node)
958 986 {
959 987 rw_enter(&node->n_lock, RW_WRITER);
960 988 }
961 989
962 990 void
963 991 smb_node_unlock(smb_node_t *node)
964 992 {
965 993 rw_exit(&node->n_lock);
966 994 }
967 995
968 996 void
969 997 smb_node_add_ofile(smb_node_t *node, smb_ofile_t *of)
970 998 {
971 999 SMB_NODE_VALID(node);
972 1000
973 1001 smb_llist_enter(&node->n_ofile_list, RW_WRITER);
974 1002 smb_llist_insert_tail(&node->n_ofile_list, of);
975 1003 smb_llist_exit(&node->n_ofile_list);
976 1004 }
977 1005
978 1006 void
979 1007 smb_node_rem_ofile(smb_node_t *node, smb_ofile_t *of)
980 1008 {
981 1009 SMB_NODE_VALID(node);
982 1010
983 1011 smb_llist_enter(&node->n_ofile_list, RW_WRITER);
984 1012 smb_llist_remove(&node->n_ofile_list, of);
985 1013 smb_llist_exit(&node->n_ofile_list);
986 1014 }
987 1015
988 1016 /*
989 1017 * smb_node_inc_open_ofiles
990 1018 */
991 1019 void
992 1020 smb_node_inc_open_ofiles(smb_node_t *node)
993 1021 {
994 1022 SMB_NODE_VALID(node);
995 1023 atomic_inc_32(&node->n_open_count);
996 1024 }
997 1025
998 1026 /*
999 1027 * smb_node_dec_open_ofiles
1000 1028 * returns new value
1001 1029 */
1002 1030 uint32_t
1003 1031 smb_node_dec_open_ofiles(smb_node_t *node)
1004 1032 {
1005 1033 SMB_NODE_VALID(node);
1006 1034 return (atomic_dec_32_nv(&node->n_open_count));
1007 1035 }
1008 1036
1009 1037 /*
1010 1038 * smb_node_inc_opening_count
1011 1039 */
1012 1040 void
1013 1041 smb_node_inc_opening_count(smb_node_t *node)
1014 1042 {
1015 1043 SMB_NODE_VALID(node);
1016 1044 atomic_inc_32(&node->n_opening_count);
1017 1045 }
1018 1046
1019 1047 /*
1020 1048 * smb_node_dec_opening_count
1021 1049 */
1022 1050 void
1023 1051 smb_node_dec_opening_count(smb_node_t *node)
1024 1052 {
1025 1053 SMB_NODE_VALID(node);
1026 1054 atomic_dec_32(&node->n_opening_count);
1027 1055 }
1028 1056
1029 1057 /*
1030 1058 * smb_node_getmntpath
1031 1059 */
1032 1060 int
1033 1061 smb_node_getmntpath(smb_node_t *node, char *buf, uint32_t buflen)
1034 1062 {
1035 1063 vnode_t *vp, *root_vp;
1036 1064 vfs_t *vfsp;
1037 1065 int err;
1038 1066
1039 1067 ASSERT(node);
1040 1068 ASSERT(node->vp);
1041 1069 ASSERT(node->vp->v_vfsp);
1042 1070
1043 1071 vp = node->vp;
1044 1072 vfsp = vp->v_vfsp;
1045 1073
1046 1074 if (VFS_ROOT(vfsp, &root_vp))
1047 1075 return (ENOENT);
1048 1076
1049 1077 VN_HOLD(vp);
1050 1078
1051 1079 /* NULL is passed in as we want to start at "/" */
1052 1080 err = vnodetopath(NULL, root_vp, buf, buflen, zone_kcred());
1053 1081
1054 1082 VN_RELE(vp);
1055 1083 VN_RELE(root_vp);
1056 1084 return (err);
1057 1085 }
1058 1086
1059 1087 /*
1060 1088 * smb_node_getshrpath
1061 1089 *
1062 1090 * Determine the absolute pathname of 'node' within the share (tree).
1063 1091 * For example if the node represents file "test1.txt" in directory
1064 1092 * "dir1" the pathname would be: \dir1\test1.txt
1065 1093 */
1066 1094 int
1067 1095 smb_node_getshrpath(smb_node_t *node, smb_tree_t *tree,
1068 1096 char *buf, uint32_t buflen)
1069 1097 {
1070 1098 int rc;
1071 1099
1072 1100 ASSERT(node);
1073 1101 ASSERT(tree);
1074 1102 ASSERT(tree->t_snode);
1075 1103
1076 1104 rc = smb_node_getpath(node, tree->t_snode->vp, buf, buflen);
1077 1105 (void) strsubst(buf, '/', '\\');
1078 1106 return (rc);
1079 1107 }
1080 1108
1081 1109 /*
1082 1110 * smb_node_getpath
1083 1111 *
1084 1112 * Determine the absolute pathname of 'node' from 'rootvp'.
1085 1113 *
1086 1114 * Using vnodetopath is only reliable for directory nodes (due to
1087 1115 * its reliance on the DNLC for non-directory nodes). Thus, if node
1088 1116 * represents a file, construct the pathname for the parent dnode
1089 1117 * and append filename.
1090 1118 * If node represents a named stream, construct the pathname for the
1091 1119 * associated unnamed stream and append the stream name.
1092 1120 *
1093 1121 * The pathname returned in buf will be '/' separated.
1094 1122 */
1095 1123 int
1096 1124 smb_node_getpath(smb_node_t *node, vnode_t *rootvp, char *buf, uint32_t buflen)
1097 1125 {
1098 1126 int rc;
1099 1127 vnode_t *vp;
1100 1128 smb_node_t *unode, *dnode;
1101 1129 cred_t *kcr = zone_kcred();
1102 1130
1103 1131 unode = (SMB_IS_STREAM(node)) ? node->n_unode : node;
1104 1132 dnode = (smb_node_is_dir(unode)) ? unode : unode->n_dnode;
1105 1133
1106 1134 /* find path to directory node */
1107 1135 vp = dnode->vp;
1108 1136 VN_HOLD(vp);
1109 1137 if (rootvp) {
1110 1138 VN_HOLD(rootvp);
1111 1139 rc = vnodetopath(rootvp, vp, buf, buflen, kcr);
1112 1140 VN_RELE(rootvp);
1113 1141 } else {
1114 1142 rc = vnodetopath(NULL, vp, buf, buflen, kcr);
1115 1143 }
1116 1144 VN_RELE(vp);
1117 1145
1118 1146 if (rc != 0)
1119 1147 return (rc);
1120 1148
1121 1149 /* append filename if necessary */
1122 1150 if (!smb_node_is_dir(unode)) {
1123 1151 if (buf[strlen(buf) - 1] != '/')
1124 1152 (void) strlcat(buf, "/", buflen);
1125 1153 (void) strlcat(buf, unode->od_name, buflen);
|
↓ open down ↓ |
196 lines elided |
↑ open up ↑ |
1126 1154 }
1127 1155
1128 1156 /* append named stream name if necessary */
1129 1157 if (SMB_IS_STREAM(node))
1130 1158 (void) strlcat(buf, node->od_name, buflen);
1131 1159
1132 1160 return (rc);
1133 1161 }
1134 1162
1135 1163 /*
1164 + * smb_node_getpath_nofail
1165 + *
1166 + * Same as smb_node_getpath, but try to reconstruct on failure,
1167 + * and truncate from the beginning if we can't.
1168 + */
1169 +void
1170 +smb_node_getpath_nofail(smb_node_t *node, vnode_t *rootvp, char *buf,
1171 + uint32_t buflen)
1172 +{
1173 + int rc, len, addlen;
1174 + vnode_t *vp;
1175 + smb_node_t *unode, *dnode;
1176 + cred_t *kcr = zone_kcred();
1177 + boolean_t is_dir, is_stream;
1178 +
1179 + is_stream = (SMB_IS_STREAM(node) != NULL);
1180 + unode = (is_stream) ? node->n_unode : node;
1181 + is_dir = smb_node_is_dir(unode);
1182 + dnode = (is_dir) ? unode : unode->n_dnode;
1183 +
1184 + /* find path to directory node */
1185 + vp = dnode->vp;
1186 + VN_HOLD(vp);
1187 + if (rootvp) {
1188 + VN_HOLD(rootvp);
1189 + rc = vnodetopath(rootvp, vp, buf, buflen, kcr);
1190 + VN_RELE(rootvp);
1191 + } else {
1192 + rc = vnodetopath(NULL, vp, buf, buflen, kcr);
1193 + }
1194 + VN_RELE(vp);
1195 +
1196 + /* On failure, reconstruct the path from the node_t's */
1197 + if (rc != 0) {
1198 + smb_node_t *nodep = unode;
1199 + char *p = buf + buflen;
1200 +
1201 + /* append named stream name if necessary */
1202 + if (is_stream) {
1203 + len = strlen(node->od_name) + 1;
1204 + ASSERT3U(buflen, >=, len);
1205 + p -= len;
1206 + (void) strcpy(p, node->od_name);
1207 + }
1208 +
1209 + len = strlen(nodep->od_name) + 1;
1210 + p -= len;
1211 + while (nodep->n_dnode != NULL && nodep->vp != rootvp &&
1212 + p >= buf) {
1213 + (void) strcpy(p, nodep->od_name);
1214 + p[len - 1] = '/';
1215 + nodep = nodep->n_dnode;
1216 + len = strlen(nodep->od_name) + 1;
1217 + p -= len;
1218 + }
1219 + if (nodep->n_dnode != NULL && nodep->vp != rootvp) {
1220 + /* something went horribly wrong... */
1221 +#ifdef DEBUG
1222 + cmn_err(CE_WARN,
1223 + "smb_node_getpath_nofail: buffer too small: "
1224 + "size %d", buflen);
1225 +#else
1226 + cmn_err(CE_WARN,
1227 + "smb_node_getpath_nofail: couldn't get full path");
1228 +#endif
1229 + p = buf;
1230 + *p = '*';
1231 + } else {
1232 + p += len - 1;
1233 + if (p >= buf)
1234 + *p = '/';
1235 + }
1236 +
1237 + buf[buflen - 1] = '\0';
1238 + (void) memmove(buf, p, strlen(p) + 1);
1239 + cmn_err(CE_NOTE,
1240 + "smb_node_getpath_nofail: vnodetopath failed, rc=%d", rc);
1241 + return;
1242 + }
1243 +
1244 + len = strlen(buf) + 1;
1245 +
1246 + /* append filename if necessary */
1247 + if (!is_dir) {
1248 + if (buf[len - 2] != '/' && strlcat(buf, "/", buflen) >= buflen)
1249 + goto trunc;
1250 + if (strlcat(buf, unode->od_name, buflen) >= buflen)
1251 + goto trunc;
1252 + }
1253 +
1254 + /* append named stream name if necessary */
1255 + if (!is_stream || strlcat(buf, node->od_name, buflen) < buflen)
1256 + return;
1257 +
1258 +trunc:
1259 + buf[len - 1] = '\0';
1260 + addlen = 0;
1261 + /* append filename if necessary */
1262 + if (!is_dir) {
1263 + if (buf[len - 2] != '/')
1264 + addlen++;
1265 + addlen += strlen(unode->od_name);
1266 + }
1267 +
1268 + /* append named stream name if necessary */
1269 + if (is_stream)
1270 + addlen += strlen(node->od_name);
1271 +
1272 + if ((buflen - len) < addlen) {
1273 +#ifdef DEBUG
1274 + cmn_err(CE_WARN,
1275 + "smb_node_getpath_nofail: vnodetopath succeeded, "
1276 + "but buffer too small for filename");
1277 +#else
1278 + cmn_err(CE_WARN,
1279 + "smb_node_getpath_nofail: couldn't get full path");
1280 +#endif
1281 + addlen = addlen - (buflen - len);
1282 + (void) memmove(buf, buf + addlen, len - addlen);
1283 + buf[0] = '*';
1284 + }
1285 +
1286 + /* append filename if necessary */
1287 + if (!is_dir) {
1288 + if (buf[len - 2] != '/')
1289 + (void) strlcat(buf, "/", buflen);
1290 + (void) strlcat(buf, unode->od_name, buflen);
1291 + }
1292 +
1293 + /* append named stream name if necessary */
1294 + if (is_stream)
1295 + (void) strlcat(buf, node->od_name, buflen);
1296 +}
1297 +
1298 +/*
1136 1299 * smb_node_alloc
1137 1300 */
1138 1301 static smb_node_t *
1139 1302 smb_node_alloc(
1140 1303 char *od_name,
1141 1304 vnode_t *vp,
1142 1305 smb_llist_t *bucket,
1143 1306 uint32_t hashkey)
1144 1307 {
1145 1308 smb_node_t *node;
1146 1309 vnode_t *root_vp;
1147 1310
1148 1311 node = kmem_cache_alloc(smb_node_cache, KM_SLEEP);
|
↓ open down ↓ |
3 lines elided |
↑ open up ↑ |
1149 1312
1150 1313 if (node->n_audit_buf != NULL)
1151 1314 node->n_audit_buf->anb_index = 0;
1152 1315
1153 1316 node->flags = 0;
1154 1317 VN_HOLD(vp);
1155 1318 node->vp = vp;
1156 1319 node->n_refcnt = 1;
1157 1320 node->n_hash_bucket = bucket;
1158 1321 node->n_hashkey = hashkey;
1159 - node->n_pending_dosattr = 0;
1160 1322 node->n_open_count = 0;
1161 1323 node->n_allocsz = 0;
1162 1324 node->n_dnode = NULL;
1163 1325 node->n_unode = NULL;
1164 1326 node->delete_on_close_cred = NULL;
1165 1327 node->n_delete_on_close_flags = 0;
1166 1328 node->n_oplock.ol_fem = B_FALSE;
1167 - node->n_oplock.ol_xthread = NULL;
1168 - node->n_oplock.ol_count = 0;
1169 - node->n_oplock.ol_break = SMB_OPLOCK_NO_BREAK;
1170 1329
1171 1330 (void) strlcpy(node->od_name, od_name, sizeof (node->od_name));
1172 1331 if (strcmp(od_name, XATTR_DIR) == 0)
1173 1332 node->flags |= NODE_XATTR_DIR;
1174 1333
1175 1334 if (VFS_ROOT(vp->v_vfsp, &root_vp) == 0) {
1176 1335 if (vp == root_vp)
1177 1336 node->flags |= NODE_FLAGS_VFSROOT;
1178 1337 VN_RELE(root_vp);
1179 1338 }
1180 1339
1181 1340 node->n_state = SMB_NODE_STATE_AVAILABLE;
1182 1341 node->n_magic = SMB_NODE_MAGIC;
1183 1342
1184 1343 return (node);
1185 1344 }
1186 1345
1187 1346 /*
|
↓ open down ↓ |
8 lines elided |
↑ open up ↑ |
1188 1347 * smb_node_free
1189 1348 */
1190 1349 static void
1191 1350 smb_node_free(smb_node_t *node)
1192 1351 {
1193 1352 SMB_NODE_VALID(node);
1194 1353
1195 1354 node->n_magic = 0;
1196 1355 VERIFY(!list_link_active(&node->n_lnd));
1197 1356 VERIFY(node->n_lock_list.ll_count == 0);
1357 + VERIFY(node->n_wlock_list.ll_count == 0);
1198 1358 VERIFY(node->n_ofile_list.ll_count == 0);
1199 - VERIFY(node->n_oplock.ol_count == 0);
1200 - VERIFY(node->n_oplock.ol_xthread == NULL);
1201 1359 VERIFY(node->n_oplock.ol_fem == B_FALSE);
1202 1360 VERIFY(MUTEX_NOT_HELD(&node->n_mutex));
1203 1361 VERIFY(!RW_LOCK_HELD(&node->n_lock));
1204 1362 VN_RELE(node->vp);
1205 1363 kmem_cache_free(smb_node_cache, node);
1206 1364 }
1207 1365
1208 1366 /*
1209 1367 * smb_node_constructor
1210 1368 */
1211 1369 static int
1212 1370 smb_node_constructor(void *buf, void *un, int kmflags)
1213 1371 {
1214 1372 _NOTE(ARGUNUSED(kmflags, un))
1215 1373
1216 1374 smb_node_t *node = (smb_node_t *)buf;
1217 1375
1218 1376 bzero(node, sizeof (smb_node_t));
1219 1377
1220 1378 smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t),
1221 - offsetof(smb_ofile_t, f_nnd));
1379 + offsetof(smb_ofile_t, f_node_lnd));
1222 1380 smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t),
1223 1381 offsetof(smb_lock_t, l_lnd));
1224 - mutex_init(&node->n_fcn.fcn_mutex, NULL, MUTEX_DEFAULT, NULL);
1225 - list_create(&node->n_fcn.fcn_watchers, sizeof (smb_request_t),
1226 - offsetof(smb_request_t, sr_ncr.nc_lnd));
1227 - cv_init(&node->n_oplock.ol_cv, NULL, CV_DEFAULT, NULL);
1382 + smb_llist_constructor(&node->n_wlock_list, sizeof (smb_lock_t),
1383 + offsetof(smb_lock_t, l_lnd));
1228 1384 mutex_init(&node->n_oplock.ol_mutex, NULL, MUTEX_DEFAULT, NULL);
1229 - list_create(&node->n_oplock.ol_grants, sizeof (smb_oplock_grant_t),
1230 - offsetof(smb_oplock_grant_t, og_lnd));
1385 + cv_init(&node->n_oplock.WaitingOpenCV, NULL, CV_DEFAULT, NULL);
1231 1386 rw_init(&node->n_lock, NULL, RW_DEFAULT, NULL);
1232 1387 mutex_init(&node->n_mutex, NULL, MUTEX_DEFAULT, NULL);
1233 1388 smb_node_create_audit_buf(node, kmflags);
1234 1389 return (0);
1235 1390 }
1236 1391
1237 1392 /*
1238 1393 * smb_node_destructor
1239 1394 */
1240 1395 static void
1241 1396 smb_node_destructor(void *buf, void *un)
1242 1397 {
1243 1398 _NOTE(ARGUNUSED(un))
1244 1399
1245 1400 smb_node_t *node = (smb_node_t *)buf;
1246 1401
1247 1402 smb_node_destroy_audit_buf(node);
1248 1403 mutex_destroy(&node->n_mutex);
1249 1404 rw_destroy(&node->n_lock);
1250 - cv_destroy(&node->n_oplock.ol_cv);
1405 + cv_destroy(&node->n_oplock.WaitingOpenCV);
1251 1406 mutex_destroy(&node->n_oplock.ol_mutex);
1252 - list_destroy(&node->n_fcn.fcn_watchers);
1253 - mutex_destroy(&node->n_fcn.fcn_mutex);
1254 1407 smb_llist_destructor(&node->n_lock_list);
1408 + smb_llist_destructor(&node->n_wlock_list);
1255 1409 smb_llist_destructor(&node->n_ofile_list);
1256 - list_destroy(&node->n_oplock.ol_grants);
1257 1410 }
1258 1411
1259 1412 /*
1260 1413 * smb_node_create_audit_buf
1261 1414 */
1262 1415 static void
1263 1416 smb_node_create_audit_buf(smb_node_t *node, int kmflags)
1264 1417 {
1265 1418 smb_audit_buf_node_t *abn;
1266 1419
1267 1420 if (smb_audit_flags & SMB_AUDIT_NODE) {
1268 1421 abn = kmem_zalloc(sizeof (smb_audit_buf_node_t), kmflags);
1269 1422 abn->anb_max_index = SMB_AUDIT_BUF_MAX_REC - 1;
1270 1423 node->n_audit_buf = abn;
1271 1424 }
1272 1425 }
1273 1426
1274 1427 /*
1275 1428 * smb_node_destroy_audit_buf
1276 1429 */
1277 1430 static void
1278 1431 smb_node_destroy_audit_buf(smb_node_t *node)
1279 1432 {
1280 1433 if (node->n_audit_buf != NULL) {
1281 1434 kmem_free(node->n_audit_buf, sizeof (smb_audit_buf_node_t));
1282 1435 node->n_audit_buf = NULL;
1283 1436 }
1284 1437 }
1285 1438
1286 1439 /*
1287 1440 * smb_node_audit
1288 1441 *
1289 1442 * This function saves the calling stack in the audit buffer of the node passed
1290 1443 * in.
1291 1444 */
1292 1445 static void
1293 1446 smb_node_audit(smb_node_t *node)
1294 1447 {
1295 1448 #ifdef _KERNEL
1296 1449 smb_audit_buf_node_t *abn;
1297 1450 smb_audit_record_node_t *anr;
1298 1451
1299 1452 if (node->n_audit_buf) {
1300 1453 abn = node->n_audit_buf;
1301 1454 anr = abn->anb_records;
1302 1455 anr += abn->anb_index;
1303 1456 abn->anb_index++;
1304 1457 abn->anb_index &= abn->anb_max_index;
1305 1458 anr->anr_refcnt = node->n_refcnt;
1306 1459 anr->anr_depth = getpcstack(anr->anr_stack,
1307 1460 SMB_AUDIT_STACK_DEPTH);
1308 1461 }
1309 1462 #else /* _KERNEL */
1310 1463 _NOTE(ARGUNUSED(node))
1311 1464 #endif /* _KERNEL */
1312 1465 }
1313 1466
1314 1467 static smb_llist_t *
1315 1468 smb_node_get_hash(fsid_t *fsid, smb_attr_t *attr, uint32_t *phashkey)
1316 1469 {
1317 1470 uint32_t hashkey;
1318 1471
1319 1472 hashkey = fsid->val[0] + attr->sa_vattr.va_nodeid;
1320 1473 hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8);
1321 1474 *phashkey = hashkey;
1322 1475 return (&smb_node_hash_table[(hashkey & SMBND_HASH_MASK)]);
1323 1476 }
1324 1477
1325 1478 boolean_t
1326 1479 smb_node_is_file(smb_node_t *node)
1327 1480 {
1328 1481 SMB_NODE_VALID(node);
1329 1482 return (node->vp->v_type == VREG);
1330 1483 }
1331 1484
1332 1485 boolean_t
1333 1486 smb_node_is_dir(smb_node_t *node)
1334 1487 {
1335 1488 SMB_NODE_VALID(node);
1336 1489 return ((node->vp->v_type == VDIR) ||
1337 1490 (node->flags & NODE_FLAGS_DFSLINK));
1338 1491 }
1339 1492
1340 1493 boolean_t
1341 1494 smb_node_is_symlink(smb_node_t *node)
1342 1495 {
1343 1496 SMB_NODE_VALID(node);
1344 1497 return ((node->vp->v_type == VLNK) &&
1345 1498 ((node->flags & NODE_FLAGS_REPARSE) == 0));
1346 1499 }
1347 1500
1348 1501 boolean_t
1349 1502 smb_node_is_dfslink(smb_node_t *node)
1350 1503 {
1351 1504 SMB_NODE_VALID(node);
1352 1505 return ((node->vp->v_type == VLNK) &&
1353 1506 (node->flags & NODE_FLAGS_DFSLINK));
1354 1507 }
1355 1508
1356 1509 boolean_t
1357 1510 smb_node_is_reparse(smb_node_t *node)
1358 1511 {
1359 1512 SMB_NODE_VALID(node);
1360 1513 return ((node->vp->v_type == VLNK) &&
1361 1514 (node->flags & NODE_FLAGS_REPARSE));
1362 1515 }
1363 1516
1364 1517 boolean_t
1365 1518 smb_node_is_vfsroot(smb_node_t *node)
1366 1519 {
1367 1520 SMB_NODE_VALID(node);
1368 1521 return ((node->flags & NODE_FLAGS_VFSROOT) == NODE_FLAGS_VFSROOT);
1369 1522 }
1370 1523
1371 1524 boolean_t
|
↓ open down ↓ |
105 lines elided |
↑ open up ↑ |
1372 1525 smb_node_is_system(smb_node_t *node)
1373 1526 {
1374 1527 SMB_NODE_VALID(node);
1375 1528 return ((node->flags & NODE_FLAGS_SYSTEM) == NODE_FLAGS_SYSTEM);
1376 1529 }
1377 1530
1378 1531 /*
1379 1532 * smb_node_file_is_readonly
1380 1533 *
1381 1534 * Checks if the file (which node represents) is marked readonly
1382 - * in the filesystem. No account is taken of any pending readonly
1383 - * in the node, which must be handled by the callers.
1384 - * (See SMB_OFILE_IS_READONLY and SMB_PATHFILE_IS_READONLY)
1535 + * in the filesystem. Note that there may be handles open with
1536 + * modify rights, and those continue to allow access even after
1537 + * the DOS read-only flag has been set in the file system.
1385 1538 */
1386 1539 boolean_t
1387 1540 smb_node_file_is_readonly(smb_node_t *node)
1388 1541 {
1389 1542 smb_attr_t attr;
1390 1543
1391 1544 if (node == NULL)
1392 1545 return (B_FALSE); /* pipes */
1393 1546
1394 - if (node->n_pending_dosattr & FILE_ATTRIBUTE_READONLY)
1395 - return (B_TRUE);
1396 -
1397 1547 bzero(&attr, sizeof (smb_attr_t));
1398 1548 attr.sa_mask = SMB_AT_DOSATTR;
1399 1549 (void) smb_fsop_getattr(NULL, zone_kcred(), node, &attr);
1400 1550 return ((attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) != 0);
1401 1551 }
1402 1552
1403 1553 /*
1404 1554 * smb_node_setattr
1405 1555 *
1406 1556 * The sr may be NULL, for example when closing an ofile.
1407 1557 * The ofile may be NULL, for example when a client request
1408 1558 * specifies the file by pathname.
1409 1559 *
1410 1560 * Returns: errno
1411 1561 *
1412 1562 * Timestamps
1413 1563 *
1414 1564 * Windows and Unix have different models for timestamp updates.
1415 1565 * [MS-FSA 2.1.5.14 Server Requests Setting of File Information]
1416 1566 *
1417 1567 * An open "handle" in Windows can control whether and when
1418 1568 * any timestamp updates happen for that handle. For example,
1419 1569 * timestamps set via some handle are no longer updated by I/O
1420 1570 * operations on that handle. In Unix we don't really have any
1421 1571 * way to avoid the timestamp updates that the file system does.
1422 1572 * Therefore, we need to make some compromises, and simulate the
1423 1573 * more important parts of the Windows file system semantics.
1424 1574 *
1425 1575 * For example, when an SMB client sets file times, set those
1426 1576 * times in the file system (so the change will be visible to
1427 1577 * other clients, at least until they change again) but we also
1428 1578 * make those times "sticky" in our open handle, and reapply
1429 1579 * those times when the handle is closed. That reapply on close
1430 1580 * simulates the Windows behavior where the timestamp updates
1431 1581 * would be discontinued after they were set. These "sticky"
1432 1582 * attributes are returned in any query on the handle where
1433 1583 * they are stored.
1434 1584 *
1435 1585 * Other than the above, the file system layer takes care of the
1436 1586 * normal time stamp updates, such as updating the mtime after a
1437 1587 * write, and ctime after an attribute change.
1438 1588 *
1439 1589 * Dos Attributes are stored persistently, but with a twist:
1440 1590 * In Windows, when you set the "read-only" bit on some file,
1441 1591 * existing writable handles to that file continue to have
1442 1592 * write access. (because access check happens at open)
1443 1593 * If we were to set the read-only bit directly, we would
1444 1594 * cause errors in subsequent writes on any of our open
1445 1595 * (and writable) file handles. So here too, we have to
1446 1596 * simulate the Windows behavior. We keep the read-only
1447 1597 * bit "pending" in the smb_node (so it will be visible in
1448 1598 * any new opens of the file) and apply it on close.
1449 1599 *
1450 1600 * File allocation size is also simulated, and not persistent.
1451 1601 * When the file allocation size is set it is first rounded up
|
↓ open down ↓ |
45 lines elided |
↑ open up ↑ |
1452 1602 * to block size. If the file size is smaller than the allocation
1453 1603 * size the file is truncated by setting the filesize to allocsz.
1454 1604 */
1455 1605 int
1456 1606 smb_node_setattr(smb_request_t *sr, smb_node_t *node,
1457 1607 cred_t *cr, smb_ofile_t *of, smb_attr_t *attr)
1458 1608 {
1459 1609 int rc;
1460 1610 uint_t times_mask;
1461 1611 smb_attr_t tmp_attr;
1612 + smb_node_t *unnamed_node;
1462 1613
1463 1614 SMB_NODE_VALID(node);
1464 1615
1465 1616 /* set attributes specified in attr */
1466 1617 if (attr->sa_mask == 0)
1467 1618 return (0); /* nothing to do (caller bug?) */
1468 1619
1469 1620 /*
1470 1621 * Allocation size and EOF position interact.
1471 1622 * We don't persistently store the allocation size
1472 1623 * but make it look like we do while there are opens.
1473 1624 * Note: We update the caller's attr in the cases
1474 1625 * where they're setting only one of allocsz|size.
1475 1626 */
1476 1627 switch (attr->sa_mask & (SMB_AT_ALLOCSZ | SMB_AT_SIZE)) {
1477 1628
1478 1629 case SMB_AT_ALLOCSZ:
1479 1630 /*
1480 1631 * Setting the allocation size but not EOF position.
1481 1632 * Get the current EOF in tmp_attr and (if necessary)
1482 1633 * truncate to the (rounded up) allocation size.
1483 1634 * Using kcred here because if we don't have access,
1484 1635 * we want to fail at setattr below and not here.
1485 1636 */
1486 1637 bzero(&tmp_attr, sizeof (smb_attr_t));
1487 1638 tmp_attr.sa_mask = SMB_AT_SIZE;
1488 1639 rc = smb_fsop_getattr(NULL, zone_kcred(), node, &tmp_attr);
1489 1640 if (rc != 0)
1490 1641 return (rc);
1491 1642 attr->sa_allocsz = SMB_ALLOCSZ(attr->sa_allocsz);
1492 1643 if (tmp_attr.sa_vattr.va_size > attr->sa_allocsz) {
1493 1644 /* truncate the file to allocsz */
1494 1645 attr->sa_vattr.va_size = attr->sa_allocsz;
1495 1646 attr->sa_mask |= SMB_AT_SIZE;
1496 1647 }
1497 1648 break;
1498 1649
1499 1650 case SMB_AT_SIZE:
1500 1651 /*
1501 1652 * Setting the EOF position but not allocation size.
1502 1653 * If the new EOF position would be greater than
1503 1654 * the allocation size, increase the latter.
1504 1655 */
1505 1656 if (node->n_allocsz < attr->sa_vattr.va_size) {
1506 1657 attr->sa_mask |= SMB_AT_ALLOCSZ;
1507 1658 attr->sa_allocsz =
1508 1659 SMB_ALLOCSZ(attr->sa_vattr.va_size);
1509 1660 }
1510 1661 break;
1511 1662
1512 1663 case SMB_AT_ALLOCSZ | SMB_AT_SIZE:
1513 1664 /*
1514 1665 * Setting both. Increase alloc size if needed.
1515 1666 */
1516 1667 if (attr->sa_allocsz < attr->sa_vattr.va_size)
1517 1668 attr->sa_allocsz =
1518 1669 SMB_ALLOCSZ(attr->sa_vattr.va_size);
1519 1670 break;
1520 1671
1521 1672 default:
1522 1673 break;
1523 1674 }
1524 1675
1525 1676 /*
1526 1677 * If we have an open file, and we set the size,
1527 1678 * then set the "written" flag so that at close,
1528 1679 * we can force an mtime update.
1529 1680 */
1530 1681 if (of != NULL && (attr->sa_mask & SMB_AT_SIZE) != 0)
1531 1682 of->f_written = B_TRUE;
1532 1683
1533 1684 /*
1534 1685 * When operating on an open file, some settable attributes
1535 1686 * become "sticky" in the open file object until close.
1536 1687 * (see above re. timestamps)
1537 1688 */
1538 1689 times_mask = attr->sa_mask & SMB_AT_TIMES;
1539 1690 if (of != NULL && times_mask != 0) {
1540 1691 smb_attr_t *pa;
1541 1692
1542 1693 SMB_OFILE_VALID(of);
1543 1694 mutex_enter(&of->f_mutex);
1544 1695 pa = &of->f_pending_attr;
1545 1696
1546 1697 pa->sa_mask |= times_mask;
1547 1698
1548 1699 if (times_mask & SMB_AT_ATIME)
1549 1700 pa->sa_vattr.va_atime =
1550 1701 attr->sa_vattr.va_atime;
1551 1702 if (times_mask & SMB_AT_MTIME)
|
↓ open down ↓ |
80 lines elided |
↑ open up ↑ |
1552 1703 pa->sa_vattr.va_mtime =
1553 1704 attr->sa_vattr.va_mtime;
1554 1705 if (times_mask & SMB_AT_CTIME)
1555 1706 pa->sa_vattr.va_ctime =
1556 1707 attr->sa_vattr.va_ctime;
1557 1708 if (times_mask & SMB_AT_CRTIME)
1558 1709 pa->sa_crtime =
1559 1710 attr->sa_crtime;
1560 1711
1561 1712 mutex_exit(&of->f_mutex);
1713 +
1562 1714 /*
1563 1715 * The f_pending_attr times are reapplied in
1564 1716 * smb_ofile_close().
1565 1717 */
1718 +
1719 + /*
1720 + * If this change is comming directly from a client
1721 + * (sr != NULL) and it's a persistent handle, save
1722 + * the "sticky times" in the handle.
1723 + */
1724 + if (sr != NULL && of->dh_persist) {
1725 + smb2_dh_update_times(sr, of, attr);
1726 + }
1566 1727 }
1567 1728
1568 - /*
1569 - * After this point, tmp_attr is what we will actually
1570 - * store in the file system _now_, which may differ
1571 - * from the callers attr and f_pending_attr w.r.t.
1572 - * the DOS readonly flag etc.
1573 - */
1574 - bcopy(attr, &tmp_attr, sizeof (tmp_attr));
1575 - if (attr->sa_mask & (SMB_AT_DOSATTR | SMB_AT_ALLOCSZ)) {
1729 + if ((attr->sa_mask & SMB_AT_ALLOCSZ) != 0) {
1576 1730 mutex_enter(&node->n_mutex);
1577 - if ((attr->sa_mask & SMB_AT_DOSATTR) != 0) {
1578 - tmp_attr.sa_dosattr &= smb_vop_dosattr_settable;
1579 - if (((tmp_attr.sa_dosattr &
1580 - FILE_ATTRIBUTE_READONLY) != 0) &&
1581 - (node->n_open_count != 0)) {
1582 - /* Delay setting readonly */
1583 - node->n_pending_dosattr =
1584 - tmp_attr.sa_dosattr;
1585 - tmp_attr.sa_dosattr &=
1586 - ~FILE_ATTRIBUTE_READONLY;
1587 - } else {
1588 - node->n_pending_dosattr = 0;
1589 - }
1590 - }
1591 1731 /*
1592 1732 * Simulate n_allocsz persistence only while
1593 1733 * there are opens. See smb_node_getattr
1594 1734 */
1595 - if ((attr->sa_mask & SMB_AT_ALLOCSZ) != 0 &&
1596 - node->n_open_count != 0)
1735 + if (node->n_open_count != 0)
1597 1736 node->n_allocsz = attr->sa_allocsz;
1598 1737 mutex_exit(&node->n_mutex);
1599 1738 }
1600 1739
1601 - rc = smb_fsop_setattr(sr, cr, node, &tmp_attr);
1740 + rc = smb_fsop_setattr(sr, cr, node, attr);
1602 1741 if (rc != 0)
1603 1742 return (rc);
1604 1743
1605 1744 if (node->n_dnode != NULL) {
1606 1745 smb_node_notify_change(node->n_dnode,
1607 1746 FILE_ACTION_MODIFIED, node->od_name);
1608 1747 }
1609 1748
1749 + if ((unnamed_node = SMB_IS_STREAM(node)) != NULL) {
1750 + ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
1751 + ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
1752 + smb_node_notify_change(node->n_dnode,
1753 + FILE_ACTION_MODIFIED_STREAM, node->od_name);
1754 + }
1755 +
1610 1756 return (0);
1611 1757 }
1612 1758
1613 1759 /*
1614 1760 * smb_node_getattr
1615 1761 *
1616 1762 * Get attributes from the file system and apply any smb-specific
1617 1763 * overrides for size, dos attributes and timestamps
1618 1764 *
1619 1765 * When node->n_pending_readonly is set on a node, pretend that
1620 1766 * we've already set this node readonly at the filesystem level.
1621 1767 * We can't actually do that until all writable handles are closed
1622 1768 * or those writable handles would suddenly loose their access.
1623 1769 *
1624 1770 * Returns: errno
1625 1771 */
1626 1772 int
1627 1773 smb_node_getattr(smb_request_t *sr, smb_node_t *node, cred_t *cr,
1628 1774 smb_ofile_t *of, smb_attr_t *attr)
1629 1775 {
1630 1776 int rc;
1631 1777 uint_t want_mask, pend_mask;
1632 1778 boolean_t isdir;
1633 1779
1634 1780 SMB_NODE_VALID(node);
1635 1781
1636 1782 /* Deal with some interdependencies */
1637 1783 if (attr->sa_mask & SMB_AT_ALLOCSZ)
1638 1784 attr->sa_mask |= SMB_AT_SIZE;
1639 1785 if (attr->sa_mask & SMB_AT_DOSATTR)
|
↓ open down ↓ |
20 lines elided |
↑ open up ↑ |
1640 1786 attr->sa_mask |= SMB_AT_TYPE;
1641 1787
1642 1788 rc = smb_fsop_getattr(sr, cr, node, attr);
1643 1789 if (rc != 0)
1644 1790 return (rc);
1645 1791
1646 1792 isdir = smb_node_is_dir(node);
1647 1793
1648 1794 mutex_enter(&node->n_mutex);
1649 1795
1650 - /*
1651 - * When there are open handles, and one of them has
1652 - * set the DOS readonly flag (in n_pending_dosattr),
1653 - * it will not have been stored in the file system.
1654 - * In this case use n_pending_dosattr. Note that
1655 - * n_pending_dosattr has only the settable bits,
1656 - * (setattr masks it with smb_vop_dosattr_settable)
1657 - * so we need to keep any non-settable bits we got
1658 - * from the file-system above.
1659 - */
1660 1796 if (attr->sa_mask & SMB_AT_DOSATTR) {
1661 - if (node->n_pending_dosattr) {
1662 - attr->sa_dosattr &= ~smb_vop_dosattr_settable;
1663 - attr->sa_dosattr |= node->n_pending_dosattr;
1664 - }
1665 1797 if (attr->sa_dosattr == 0) {
1666 1798 attr->sa_dosattr = (isdir) ?
1667 1799 FILE_ATTRIBUTE_DIRECTORY:
1668 1800 FILE_ATTRIBUTE_NORMAL;
1669 1801 }
1670 1802 }
1671 1803
1672 1804 /*
1673 1805 * Also fix-up sa_allocsz, which is not persistent.
1674 1806 * When there are no open files, allocsz is faked.
1675 1807 * While there are open files, we pretend we have a
1676 1808 * persistent allocation size in n_allocsz, and
1677 1809 * keep that up-to-date here, increasing it when
1678 1810 * we see the file size grow past it.
1679 1811 */
1680 1812 if (attr->sa_mask & SMB_AT_ALLOCSZ) {
1681 1813 if (isdir) {
1682 1814 attr->sa_allocsz = 0;
1683 1815 } else if (node->n_open_count == 0) {
1684 1816 attr->sa_allocsz =
1685 1817 SMB_ALLOCSZ(attr->sa_vattr.va_size);
1686 1818 } else {
1687 1819 if (node->n_allocsz < attr->sa_vattr.va_size)
1688 1820 node->n_allocsz =
1689 1821 SMB_ALLOCSZ(attr->sa_vattr.va_size);
1690 1822 attr->sa_allocsz = node->n_allocsz;
1691 1823 }
1692 1824 }
1693 1825
1694 1826 mutex_exit(&node->n_mutex);
1695 1827
1696 1828 if (isdir) {
1697 1829 attr->sa_vattr.va_size = 0;
1698 1830 attr->sa_vattr.va_nlink = 1;
1699 1831 }
1700 1832
1701 1833 /*
1702 1834 * getattr with an ofile gets any "pending" times that
1703 1835 * might have been previously set via this ofile.
1704 1836 * This is what makes these times "sticky".
1705 1837 */
1706 1838 want_mask = attr->sa_mask & SMB_AT_TIMES;
1707 1839 if (of != NULL && want_mask != 0) {
1708 1840 smb_attr_t *pa;
1709 1841
1710 1842 SMB_OFILE_VALID(of);
1711 1843 mutex_enter(&of->f_mutex);
1712 1844 pa = &of->f_pending_attr;
1713 1845
1714 1846 pend_mask = pa->sa_mask;
1715 1847
1716 1848 if (want_mask & pend_mask & SMB_AT_ATIME)
1717 1849 attr->sa_vattr.va_atime =
1718 1850 pa->sa_vattr.va_atime;
1719 1851 if (want_mask & pend_mask & SMB_AT_MTIME)
1720 1852 attr->sa_vattr.va_mtime =
1721 1853 pa->sa_vattr.va_mtime;
1722 1854 if (want_mask & pend_mask & SMB_AT_CTIME)
1723 1855 attr->sa_vattr.va_ctime =
1724 1856 pa->sa_vattr.va_ctime;
1725 1857 if (want_mask & pend_mask & SMB_AT_CRTIME)
1726 1858 attr->sa_crtime =
1727 1859 pa->sa_crtime;
1728 1860
1729 1861 mutex_exit(&of->f_mutex);
1730 1862 }
1731 1863
1732 1864
1733 1865 return (0);
1734 1866 }
1735 1867
1736 1868
1737 1869 #ifndef _KERNEL
1738 1870 extern int reparse_vnode_parse(vnode_t *vp, nvlist_t *nvl);
1739 1871 #endif /* _KERNEL */
1740 1872
1741 1873 /*
1742 1874 * Check to see if the node represents a reparse point.
1743 1875 * If yes, whether the reparse point contains a DFS link.
1744 1876 */
1745 1877 static void
1746 1878 smb_node_init_reparse(smb_node_t *node, smb_attr_t *attr)
1747 1879 {
1748 1880 nvlist_t *nvl;
1749 1881 nvpair_t *rec;
1750 1882 char *rec_type;
1751 1883
1752 1884 if ((attr->sa_dosattr & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
1753 1885 return;
1754 1886
1755 1887 if ((nvl = reparse_init()) == NULL)
1756 1888 return;
1757 1889
1758 1890 if (reparse_vnode_parse(node->vp, nvl) != 0) {
1759 1891 reparse_free(nvl);
1760 1892 return;
1761 1893 }
1762 1894
1763 1895 node->flags |= NODE_FLAGS_REPARSE;
1764 1896
1765 1897 rec = nvlist_next_nvpair(nvl, NULL);
1766 1898 while (rec != NULL) {
1767 1899 rec_type = nvpair_name(rec);
1768 1900 if ((rec_type != NULL) &&
1769 1901 (strcasecmp(rec_type, DFS_REPARSE_SVCTYPE) == 0)) {
1770 1902 node->flags |= NODE_FLAGS_DFSLINK;
1771 1903 break;
1772 1904 }
1773 1905 rec = nvlist_next_nvpair(nvl, rec);
1774 1906 }
1775 1907
1776 1908 reparse_free(nvl);
1777 1909 }
1778 1910
1779 1911 /*
1780 1912 * smb_node_init_system
1781 1913 *
1782 1914 * If the node represents a special system file set NODE_FLAG_SYSTEM.
1783 1915 * System files:
1784 1916 * - any node whose parent dnode has NODE_FLAG_SYSTEM set
1785 1917 * - any node whose associated unnamed stream node (unode) has
1786 1918 * NODE_FLAG_SYSTEM set
1787 1919 * - .$EXTEND at root of share (quota management)
1788 1920 */
1789 1921 static void
1790 1922 smb_node_init_system(smb_node_t *node)
1791 1923 {
1792 1924 smb_node_t *dnode = node->n_dnode;
1793 1925 smb_node_t *unode = node->n_unode;
1794 1926
1795 1927 if ((dnode) && (dnode->flags & NODE_FLAGS_SYSTEM)) {
1796 1928 node->flags |= NODE_FLAGS_SYSTEM;
1797 1929 return;
1798 1930 }
1799 1931
1800 1932 if ((unode) && (unode->flags & NODE_FLAGS_SYSTEM)) {
1801 1933 node->flags |= NODE_FLAGS_SYSTEM;
1802 1934 return;
1803 1935 }
1804 1936
1805 1937 if ((dnode) && (smb_node_is_vfsroot(node->n_dnode) &&
1806 1938 (strcasecmp(node->od_name, ".$EXTEND") == 0))) {
1807 1939 node->flags |= NODE_FLAGS_SYSTEM;
1808 1940 }
1809 1941 }
|
↓ open down ↓ |
135 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX