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 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
24 * Copyright 2015 Joyent, Inc.
25 */
26
27 #include <smbsrv/smb_kproto.h>
28 #include <smbsrv/smb_fsops.h>
29 #include <sys/sdt.h>
30 #include <sys/fcntl.h>
31 #include <sys/vfs.h>
32 #include <sys/vfs_opreg.h>
33 #include <sys/vnode.h>
34 #include <sys/fem.h>
35
36 extern caller_context_t smb_ct;
37
38 static boolean_t smb_fem_initialized = B_FALSE;
39 static fem_t *smb_fcn_ops = NULL;
40 static fem_t *smb_oplock_ops = NULL;
41
42 /*
43 * Declarations for FCN (file change notification) FEM monitors
64 VOPNAME_RENAME, {.femop_rename = smb_fem_fcn_rename},
65 VOPNAME_MKDIR, {.femop_mkdir = smb_fem_fcn_mkdir},
66 VOPNAME_RMDIR, {.femop_rmdir = smb_fem_fcn_rmdir},
67 VOPNAME_LINK, {.femop_link = smb_fem_fcn_link},
68 VOPNAME_SYMLINK, {.femop_symlink = smb_fem_fcn_symlink},
69 NULL, NULL
70 };
71
72 /*
73 * Declarations for oplock FEM monitors
74 */
75
76 static int smb_fem_oplock_open(femarg_t *, int, cred_t *,
77 struct caller_context *);
78 static int smb_fem_oplock_read(femarg_t *, uio_t *, int, cred_t *,
79 struct caller_context *);
80 static int smb_fem_oplock_write(femarg_t *, uio_t *, int, cred_t *,
81 struct caller_context *);
82 static int smb_fem_oplock_setattr(femarg_t *, vattr_t *, int, cred_t *,
83 caller_context_t *);
84 static int smb_fem_oplock_rwlock(femarg_t *, int, caller_context_t *);
85 static int smb_fem_oplock_space(femarg_t *, int, flock64_t *, int,
86 offset_t, cred_t *, caller_context_t *);
87 static int smb_fem_oplock_vnevent(femarg_t *, vnevent_t, vnode_t *, char *,
88 caller_context_t *);
89
90 static const fs_operation_def_t smb_oplock_tmpl[] = {
91 VOPNAME_OPEN, { .femop_open = smb_fem_oplock_open },
92 VOPNAME_READ, { .femop_read = smb_fem_oplock_read },
93 VOPNAME_WRITE, { .femop_write = smb_fem_oplock_write },
94 VOPNAME_SETATTR, { .femop_setattr = smb_fem_oplock_setattr },
95 VOPNAME_RWLOCK, { .femop_rwlock = smb_fem_oplock_rwlock },
96 VOPNAME_SPACE, { .femop_space = smb_fem_oplock_space },
97 VOPNAME_VNEVENT, { .femop_vnevent = smb_fem_oplock_vnevent },
98 NULL, NULL
99 };
100
101 static int smb_fem_oplock_break(femarg_t *, caller_context_t *, uint32_t);
102
103 /*
104 * smb_fem_init
105 *
106 * This function is not multi-thread safe. The caller must make sure only one
107 * thread makes the call.
108 */
109 int
110 smb_fem_init(void)
111 {
112 int rc = 0;
113
114 if (smb_fem_initialized)
115 return (0);
116
117 rc = fem_create("smb_fcn_ops", smb_fcn_tmpl, &smb_fcn_ops);
118 if (rc)
119 return (rc);
120
121 rc = fem_create("smb_oplock_ops", smb_oplock_tmpl,
138 * This function is not multi-thread safe. The caller must make sure only one
139 * thread makes the call.
140 */
141 void
142 smb_fem_fini(void)
143 {
144 if (!smb_fem_initialized)
145 return;
146
147 if (smb_fcn_ops != NULL) {
148 fem_free(smb_fcn_ops);
149 smb_fcn_ops = NULL;
150 }
151 if (smb_oplock_ops != NULL) {
152 fem_free(smb_oplock_ops);
153 smb_oplock_ops = NULL;
154 }
155 smb_fem_initialized = B_FALSE;
156 }
157
158 int
159 smb_fem_fcn_install(smb_node_t *node)
160 {
161 int rc;
162
163 if (smb_fcn_ops == NULL)
164 return (ENOSYS);
165 rc = fem_install(node->vp, smb_fcn_ops, (void *)node, OPARGUNIQ,
166 (fem_func_t)smb_node_ref, (fem_func_t)smb_node_release);
167 return (rc);
168 }
169
170 void
171 smb_fem_fcn_uninstall(smb_node_t *node)
172 {
173 if (smb_fcn_ops == NULL)
174 return;
175 VERIFY0(fem_uninstall(node->vp, smb_fcn_ops, (void *)node));
176 }
177
178 int
179 smb_fem_oplock_install(smb_node_t *node)
180 {
181 int rc;
182
183 if (smb_oplock_ops == NULL)
184 return (ENOSYS);
185 rc = fem_install(node->vp, smb_oplock_ops, (void *)node, OPARGUNIQ,
186 (fem_func_t)smb_node_ref, (fem_func_t)smb_node_release);
406 if (error == 0 && ct != &smb_ct)
407 smb_node_notify_change(dnode, FILE_ACTION_ADDED, linkname);
408
409 return (error);
410 }
411
412 /*
413 * FEM oplock monitors
414 *
415 * The monitors below are not intended to intercept CIFS calls.
416 * CIFS higher-level routines will break oplocks as needed prior
417 * to getting to the VFS layer.
418 */
419 static int
420 smb_fem_oplock_open(
421 femarg_t *arg,
422 int mode,
423 cred_t *cr,
424 caller_context_t *ct)
425 {
426 uint32_t flags;
427 int rc = 0;
428
429 if (ct != &smb_ct) {
430 if (mode & (FWRITE|FTRUNC))
431 flags = SMB_OPLOCK_BREAK_TO_NONE;
432 else
433 flags = SMB_OPLOCK_BREAK_TO_LEVEL_II;
434 rc = smb_fem_oplock_break(arg, ct, flags);
435 }
436 if (rc == 0)
437 rc = vnext_open(arg, mode, cr, ct);
438
439 return (rc);
440 }
441
442 /*
443 * Should normally be hit only via NFSv2/v3. All other accesses
444 * (CIFS/NFS/local) should call VOP_OPEN first.
445 */
446
447 static int
448 smb_fem_oplock_read(
449 femarg_t *arg,
450 uio_t *uiop,
451 int ioflag,
452 cred_t *cr,
453 caller_context_t *ct)
454 {
455 int rc = 0;
456
457 if (ct != &smb_ct) {
458 rc = smb_fem_oplock_break(arg, ct,
459 SMB_OPLOCK_BREAK_TO_LEVEL_II);
460 }
461 if (rc == 0)
462 rc = vnext_read(arg, uiop, ioflag, cr, ct);
463
464 return (rc);
465 }
466
467 /*
468 * Should normally be hit only via NFSv2/v3. All other accesses
469 * (CIFS/NFS/local) should call VOP_OPEN first.
470 */
471
472 static int
473 smb_fem_oplock_write(
474 femarg_t *arg,
475 uio_t *uiop,
476 int ioflag,
477 cred_t *cr,
478 caller_context_t *ct)
479 {
480 int rc = 0;
481
482 if (ct != &smb_ct)
483 rc = smb_fem_oplock_break(arg, ct, SMB_OPLOCK_BREAK_TO_NONE);
484 if (rc == 0)
485 rc = vnext_write(arg, uiop, ioflag, cr, ct);
486
487 return (rc);
488 }
489
490 static int
491 smb_fem_oplock_setattr(
492 femarg_t *arg,
493 vattr_t *vap,
494 int flags,
495 cred_t *cr,
496 caller_context_t *ct)
497 {
498 int rc = 0;
499
500 if (ct != &smb_ct && (vap->va_mask & AT_SIZE) != 0)
501 rc = smb_fem_oplock_break(arg, ct, SMB_OPLOCK_BREAK_TO_NONE);
502 if (rc == 0)
503 rc = vnext_setattr(arg, vap, flags, cr, ct);
504 return (rc);
505 }
506
507 static int
508 smb_fem_oplock_rwlock(
509 femarg_t *arg,
510 int write_lock,
511 caller_context_t *ct)
512 {
513 uint32_t flags;
514 int rc = 0;
515
516 if (ct != &smb_ct) {
517 if (write_lock)
518 flags = SMB_OPLOCK_BREAK_TO_NONE;
519 else
520 flags = SMB_OPLOCK_BREAK_TO_LEVEL_II;
521 rc = smb_fem_oplock_break(arg, ct, flags);
522 }
523 if (rc == 0)
524 rc = vnext_rwlock(arg, write_lock, ct);
525
526 return (rc);
527 }
528
529 static int
530 smb_fem_oplock_space(
531 femarg_t *arg,
532 int cmd,
533 flock64_t *bfp,
534 int flag,
535 offset_t offset,
536 cred_t *cr,
537 caller_context_t *ct)
538 {
539 int rc = 0;
540
541 if (ct != &smb_ct)
542 rc = smb_fem_oplock_break(arg, ct, SMB_OPLOCK_BREAK_TO_NONE);
543 if (rc == 0)
544 rc = vnext_space(arg, cmd, bfp, flag, offset, cr, ct);
545 return (rc);
546 }
547
548 /*
549 * smb_fem_oplock_vnevent()
550 *
551 * To intercept NFS and local renames and removes in order to break any
552 * existing oplock prior to the operation.
553 *
554 * Note: Currently, this monitor is traversed only when an FS is mounted
555 * non-nbmand. (When the FS is mounted nbmand, share reservation checking
556 * will detect a share violation and return an error prior to the VOP layer
557 * being reached.) Thus, for nbmand NFS and local renames and removes,
558 * an existing oplock is never broken prior to share checking (contrary to
559 * how it is with intra-CIFS remove and rename requests).
560 */
561
562 static int
563 smb_fem_oplock_vnevent(
564 femarg_t *arg,
565 vnevent_t vnevent,
566 vnode_t *dvp,
567 char *name,
568 caller_context_t *ct)
569 {
570 uint32_t flags;
571 int rc = 0;
572
573 if (ct != &smb_ct) {
574 switch (vnevent) {
575 case VE_REMOVE:
576 case VE_PRE_RENAME_DEST:
577 case VE_RENAME_DEST:
578 flags = SMB_OPLOCK_BREAK_TO_NONE |
579 SMB_OPLOCK_BREAK_BATCH;
580 rc = smb_fem_oplock_break(arg, ct, flags);
581 break;
582 case VE_PRE_RENAME_SRC:
583 case VE_RENAME_SRC:
584 flags = SMB_OPLOCK_BREAK_TO_LEVEL_II |
585 SMB_OPLOCK_BREAK_BATCH;
586 rc = smb_fem_oplock_break(arg, ct, flags);
587 break;
588 default:
589 rc = 0;
590 break;
591 }
592 }
593 if (rc == 0)
594 rc = vnext_vnevent(arg, vnevent, dvp, name, ct);
595
596 return (rc);
597 }
598
599 static int
600 smb_fem_oplock_break(femarg_t *arg, caller_context_t *ct, uint32_t flags)
601 {
602 smb_node_t *node;
603 int rc;
604
605 node = (smb_node_t *)((arg)->fa_fnode->fn_available);
606 SMB_NODE_VALID(node);
607
608 ASSERT(ct != &smb_ct);
609
610 if (ct && (ct->cc_flags & CC_DONTBLOCK)) {
611 flags |= SMB_OPLOCK_BREAK_NOWAIT;
612 rc = smb_oplock_break(NULL, node, flags);
613 if (rc == EAGAIN)
614 ct->cc_flags |= CC_WOULDBLOCK;
615 } else {
616 rc = smb_oplock_break(NULL, node, flags);
617 }
618
619 return (rc);
620 }
|
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 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
24 * Copyright 2015 Joyent, Inc.
25 */
26
27 #include <smbsrv/smb_kproto.h>
28 #include <smbsrv/smb_fsops.h>
29 #include <sys/sdt.h>
30 #include <sys/fcntl.h>
31 #include <sys/vfs.h>
32 #include <sys/vfs_opreg.h>
33 #include <sys/vnode.h>
34 #include <sys/fem.h>
35
36 extern caller_context_t smb_ct;
37
38 static boolean_t smb_fem_initialized = B_FALSE;
39 static fem_t *smb_fcn_ops = NULL;
40 static fem_t *smb_oplock_ops = NULL;
41
42 /*
43 * Declarations for FCN (file change notification) FEM monitors
64 VOPNAME_RENAME, {.femop_rename = smb_fem_fcn_rename},
65 VOPNAME_MKDIR, {.femop_mkdir = smb_fem_fcn_mkdir},
66 VOPNAME_RMDIR, {.femop_rmdir = smb_fem_fcn_rmdir},
67 VOPNAME_LINK, {.femop_link = smb_fem_fcn_link},
68 VOPNAME_SYMLINK, {.femop_symlink = smb_fem_fcn_symlink},
69 NULL, NULL
70 };
71
72 /*
73 * Declarations for oplock FEM monitors
74 */
75
76 static int smb_fem_oplock_open(femarg_t *, int, cred_t *,
77 struct caller_context *);
78 static int smb_fem_oplock_read(femarg_t *, uio_t *, int, cred_t *,
79 struct caller_context *);
80 static int smb_fem_oplock_write(femarg_t *, uio_t *, int, cred_t *,
81 struct caller_context *);
82 static int smb_fem_oplock_setattr(femarg_t *, vattr_t *, int, cred_t *,
83 caller_context_t *);
84 static int smb_fem_oplock_space(femarg_t *, int, flock64_t *, int,
85 offset_t, cred_t *, caller_context_t *);
86 static int smb_fem_oplock_vnevent(femarg_t *, vnevent_t, vnode_t *, char *,
87 caller_context_t *);
88
89 static const fs_operation_def_t smb_oplock_tmpl[] = {
90 VOPNAME_OPEN, { .femop_open = smb_fem_oplock_open },
91 VOPNAME_READ, { .femop_read = smb_fem_oplock_read },
92 VOPNAME_WRITE, { .femop_write = smb_fem_oplock_write },
93 VOPNAME_SETATTR, { .femop_setattr = smb_fem_oplock_setattr },
94 VOPNAME_SPACE, { .femop_space = smb_fem_oplock_space },
95 VOPNAME_VNEVENT, { .femop_vnevent = smb_fem_oplock_vnevent },
96 NULL, NULL
97 };
98
99 static int smb_fem_oplock_wait(smb_node_t *, caller_context_t *);
100
101 /*
102 * smb_fem_init
103 *
104 * This function is not multi-thread safe. The caller must make sure only one
105 * thread makes the call.
106 */
107 int
108 smb_fem_init(void)
109 {
110 int rc = 0;
111
112 if (smb_fem_initialized)
113 return (0);
114
115 rc = fem_create("smb_fcn_ops", smb_fcn_tmpl, &smb_fcn_ops);
116 if (rc)
117 return (rc);
118
119 rc = fem_create("smb_oplock_ops", smb_oplock_tmpl,
136 * This function is not multi-thread safe. The caller must make sure only one
137 * thread makes the call.
138 */
139 void
140 smb_fem_fini(void)
141 {
142 if (!smb_fem_initialized)
143 return;
144
145 if (smb_fcn_ops != NULL) {
146 fem_free(smb_fcn_ops);
147 smb_fcn_ops = NULL;
148 }
149 if (smb_oplock_ops != NULL) {
150 fem_free(smb_oplock_ops);
151 smb_oplock_ops = NULL;
152 }
153 smb_fem_initialized = B_FALSE;
154 }
155
156 /*
157 * Install our fem hooks for change notify.
158 * Not using hold/rele function here because we
159 * remove the fem hooks before node destroy.
160 */
161 int
162 smb_fem_fcn_install(smb_node_t *node)
163 {
164 int rc;
165
166 if (smb_fcn_ops == NULL)
167 return (ENOSYS);
168 rc = fem_install(node->vp, smb_fcn_ops, (void *)node, OPARGUNIQ,
169 NULL, NULL);
170 return (rc);
171 }
172
173 void
174 smb_fem_fcn_uninstall(smb_node_t *node)
175 {
176 if (smb_fcn_ops == NULL)
177 return;
178 VERIFY0(fem_uninstall(node->vp, smb_fcn_ops, (void *)node));
179 }
180
181 int
182 smb_fem_oplock_install(smb_node_t *node)
183 {
184 int rc;
185
186 if (smb_oplock_ops == NULL)
187 return (ENOSYS);
188 rc = fem_install(node->vp, smb_oplock_ops, (void *)node, OPARGUNIQ,
189 (fem_func_t)smb_node_ref, (fem_func_t)smb_node_release);
409 if (error == 0 && ct != &smb_ct)
410 smb_node_notify_change(dnode, FILE_ACTION_ADDED, linkname);
411
412 return (error);
413 }
414
415 /*
416 * FEM oplock monitors
417 *
418 * The monitors below are not intended to intercept CIFS calls.
419 * CIFS higher-level routines will break oplocks as needed prior
420 * to getting to the VFS layer.
421 */
422 static int
423 smb_fem_oplock_open(
424 femarg_t *arg,
425 int mode,
426 cred_t *cr,
427 caller_context_t *ct)
428 {
429 smb_node_t *node;
430 uint32_t status;
431 int rc = 0;
432
433 if (ct != &smb_ct) {
434 uint32_t req_acc = FILE_READ_DATA;
435 uint32_t cr_disp = FILE_OPEN_IF;
436
437 node = (smb_node_t *)(arg->fa_fnode->fn_available);
438 SMB_NODE_VALID(node);
439
440 /*
441 * Get req_acc, cr_disp just accurate enough so
442 * the oplock break call does the right thing.
443 */
444 if (mode & FWRITE) {
445 req_acc = FILE_READ_DATA | FILE_WRITE_DATA;
446 cr_disp = (mode & FTRUNC) ?
447 FILE_OVERWRITE_IF : FILE_OPEN_IF;
448 } else {
449 req_acc = FILE_READ_DATA;
450 cr_disp = FILE_OPEN_IF;
451 }
452
453 status = smb_oplock_break_OPEN(node, NULL,
454 req_acc, cr_disp);
455 if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS)
456 rc = smb_fem_oplock_wait(node, ct);
457 else if (status != 0)
458 rc = EIO;
459 }
460 if (rc == 0)
461 rc = vnext_open(arg, mode, cr, ct);
462
463 return (rc);
464 }
465
466 /*
467 * Should normally be hit only via NFSv2/v3. All other accesses
468 * (CIFS/NFS/local) should call VOP_OPEN first.
469 */
470
471 static int
472 smb_fem_oplock_read(
473 femarg_t *arg,
474 uio_t *uiop,
475 int ioflag,
476 cred_t *cr,
477 caller_context_t *ct)
478 {
479 smb_node_t *node;
480 uint32_t status;
481 int rc = 0;
482
483 if (ct != &smb_ct) {
484 node = (smb_node_t *)(arg->fa_fnode->fn_available);
485 SMB_NODE_VALID(node);
486
487 status = smb_oplock_break_READ(node, NULL);
488 if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS)
489 rc = smb_fem_oplock_wait(node, ct);
490 else if (status != 0)
491 rc = EIO;
492 }
493 if (rc == 0)
494 rc = vnext_read(arg, uiop, ioflag, cr, ct);
495
496 return (rc);
497 }
498
499 /*
500 * Should normally be hit only via NFSv2/v3. All other accesses
501 * (CIFS/NFS/local) should call VOP_OPEN first.
502 */
503
504 static int
505 smb_fem_oplock_write(
506 femarg_t *arg,
507 uio_t *uiop,
508 int ioflag,
509 cred_t *cr,
510 caller_context_t *ct)
511 {
512 smb_node_t *node;
513 uint32_t status;
514 int rc = 0;
515
516 if (ct != &smb_ct) {
517 node = (smb_node_t *)(arg->fa_fnode->fn_available);
518 SMB_NODE_VALID(node);
519
520 status = smb_oplock_break_WRITE(node, NULL);
521 if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS)
522 rc = smb_fem_oplock_wait(node, ct);
523 else if (status != 0)
524 rc = EIO;
525 }
526 if (rc == 0)
527 rc = vnext_write(arg, uiop, ioflag, cr, ct);
528
529 return (rc);
530 }
531
532 static int
533 smb_fem_oplock_setattr(
534 femarg_t *arg,
535 vattr_t *vap,
536 int flags,
537 cred_t *cr,
538 caller_context_t *ct)
539 {
540 smb_node_t *node;
541 uint32_t status;
542 int rc = 0;
543
544 if (ct != &smb_ct && (vap->va_mask & AT_SIZE) != 0) {
545 node = (smb_node_t *)(arg->fa_fnode->fn_available);
546 SMB_NODE_VALID(node);
547
548 status = smb_oplock_break_SETINFO(node, NULL,
549 FileEndOfFileInformation);
550 if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS)
551 rc = smb_fem_oplock_wait(node, ct);
552 else if (status != 0)
553 rc = EIO;
554 }
555 if (rc == 0)
556 rc = vnext_setattr(arg, vap, flags, cr, ct);
557 return (rc);
558 }
559
560 static int
561 smb_fem_oplock_space(
562 femarg_t *arg,
563 int cmd,
564 flock64_t *bfp,
565 int flag,
566 offset_t offset,
567 cred_t *cr,
568 caller_context_t *ct)
569 {
570 smb_node_t *node;
571 uint32_t status;
572 int rc = 0;
573
574 if (ct != &smb_ct) {
575 node = (smb_node_t *)(arg->fa_fnode->fn_available);
576 SMB_NODE_VALID(node);
577
578 status = smb_oplock_break_SETINFO(node, NULL,
579 FileAllocationInformation);
580 if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS)
581 rc = smb_fem_oplock_wait(node, ct);
582 else if (status != 0)
583 rc = EIO;
584 }
585 if (rc == 0)
586 rc = vnext_space(arg, cmd, bfp, flag, offset, cr, ct);
587 return (rc);
588 }
589
590 /*
591 * smb_fem_oplock_vnevent()
592 *
593 * To intercept NFS and local renames and removes in order to break any
594 * existing oplock prior to the operation.
595 *
596 * Note: Currently, this monitor is traversed only when an FS is mounted
597 * non-nbmand. (When the FS is mounted nbmand, share reservation checking
598 * will detect a share violation and return an error prior to the VOP layer
599 * being reached.) Thus, for nbmand NFS and local renames and removes,
600 * an existing oplock is never broken prior to share checking (contrary to
601 * how it is with intra-CIFS remove and rename requests).
602 */
603
604 static int
605 smb_fem_oplock_vnevent(
606 femarg_t *arg,
607 vnevent_t vnevent,
608 vnode_t *dvp,
609 char *name,
610 caller_context_t *ct)
611 {
612 smb_node_t *node;
613 uint32_t status;
614 int rc = 0;
615
616 if (ct != &smb_ct) {
617 node = (smb_node_t *)(arg->fa_fnode->fn_available);
618 SMB_NODE_VALID(node);
619
620 switch (vnevent) {
621 case VE_REMOVE:
622 case VE_PRE_RENAME_DEST:
623 case VE_RENAME_DEST:
624 status = smb_oplock_break_HANDLE(node, NULL);
625 break;
626 case VE_PRE_RENAME_SRC:
627 case VE_RENAME_SRC:
628 status = smb_oplock_break_SETINFO(node, NULL,
629 FileRenameInformation);
630 break;
631 default:
632 status = 0;
633 break;
634 }
635 if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS)
636 rc = smb_fem_oplock_wait(node, ct);
637 else if (status != 0)
638 rc = EIO;
639 }
640 if (rc == 0)
641 rc = vnext_vnevent(arg, vnevent, dvp, name, ct);
642
643 return (rc);
644 }
645
646 int smb_fem_oplock_timeout = 5000; /* mSec. */
647
648 static int
649 smb_fem_oplock_wait(smb_node_t *node, caller_context_t *ct)
650 {
651 int rc = 0;
652
653 ASSERT(ct != &smb_ct);
654
655 if (ct && (ct->cc_flags & CC_DONTBLOCK)) {
656 ct->cc_flags |= CC_WOULDBLOCK;
657 rc = EAGAIN;
658 } else {
659 (void) smb_oplock_wait_break(node,
660 smb_fem_oplock_timeout);
661 rc = 0;
662 }
663
664 return (rc);
665 }
|