Print this page
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-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-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-58 smbsrv should be immune to its own FEM hooks
SMB-65 SMB server in non-global zones (kmem_caches)
common kmem_cache instances across zones
separate GZ-only init from NGZ init
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

*** 18,28 **** * * CDDL HEADER END */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. ! * Copyright 2013 Nexenta Systems, Inc. All rights reserved. * Copyright 2015 Joyent, Inc. */ #include <smbsrv/smb_kproto.h> #include <smbsrv/smb_fsops.h> --- 18,28 ---- * * CDDL HEADER END */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. ! * Copyright 2017 Nexenta Systems, Inc. All rights reserved. * Copyright 2015 Joyent, Inc. */ #include <smbsrv/smb_kproto.h> #include <smbsrv/smb_fsops.h>
*** 79,89 **** struct caller_context *); static int smb_fem_oplock_write(femarg_t *, uio_t *, int, cred_t *, struct caller_context *); static int smb_fem_oplock_setattr(femarg_t *, vattr_t *, int, cred_t *, caller_context_t *); - static int smb_fem_oplock_rwlock(femarg_t *, int, caller_context_t *); static int smb_fem_oplock_space(femarg_t *, int, flock64_t *, int, offset_t, cred_t *, caller_context_t *); static int smb_fem_oplock_vnevent(femarg_t *, vnevent_t, vnode_t *, char *, caller_context_t *); --- 79,88 ----
*** 90,106 **** static const fs_operation_def_t smb_oplock_tmpl[] = { VOPNAME_OPEN, { .femop_open = smb_fem_oplock_open }, VOPNAME_READ, { .femop_read = smb_fem_oplock_read }, VOPNAME_WRITE, { .femop_write = smb_fem_oplock_write }, VOPNAME_SETATTR, { .femop_setattr = smb_fem_oplock_setattr }, - VOPNAME_RWLOCK, { .femop_rwlock = smb_fem_oplock_rwlock }, VOPNAME_SPACE, { .femop_space = smb_fem_oplock_space }, VOPNAME_VNEVENT, { .femop_vnevent = smb_fem_oplock_vnevent }, NULL, NULL }; ! static int smb_fem_oplock_break(femarg_t *, caller_context_t *, uint32_t); /* * smb_fem_init * * This function is not multi-thread safe. The caller must make sure only one --- 89,104 ---- static const fs_operation_def_t smb_oplock_tmpl[] = { VOPNAME_OPEN, { .femop_open = smb_fem_oplock_open }, VOPNAME_READ, { .femop_read = smb_fem_oplock_read }, VOPNAME_WRITE, { .femop_write = smb_fem_oplock_write }, VOPNAME_SETATTR, { .femop_setattr = smb_fem_oplock_setattr }, VOPNAME_SPACE, { .femop_space = smb_fem_oplock_space }, VOPNAME_VNEVENT, { .femop_vnevent = smb_fem_oplock_vnevent }, NULL, NULL }; ! static int smb_fem_oplock_wait(smb_node_t *, caller_context_t *); /* * smb_fem_init * * This function is not multi-thread safe. The caller must make sure only one
*** 153,171 **** smb_oplock_ops = NULL; } smb_fem_initialized = B_FALSE; } int smb_fem_fcn_install(smb_node_t *node) { int rc; if (smb_fcn_ops == NULL) return (ENOSYS); rc = fem_install(node->vp, smb_fcn_ops, (void *)node, OPARGUNIQ, ! (fem_func_t)smb_node_ref, (fem_func_t)smb_node_release); return (rc); } void smb_fem_fcn_uninstall(smb_node_t *node) --- 151,174 ---- smb_oplock_ops = NULL; } smb_fem_initialized = B_FALSE; } + /* + * Install our fem hooks for change notify. + * Not using hold/rele function here because we + * remove the fem hooks before node destroy. + */ int smb_fem_fcn_install(smb_node_t *node) { int rc; if (smb_fcn_ops == NULL) return (ENOSYS); rc = fem_install(node->vp, smb_fcn_ops, (void *)node, OPARGUNIQ, ! NULL, NULL); return (rc); } void smb_fem_fcn_uninstall(smb_node_t *node)
*** 421,440 **** femarg_t *arg, int mode, cred_t *cr, caller_context_t *ct) { ! uint32_t flags; int rc = 0; if (ct != &smb_ct) { ! if (mode & (FWRITE|FTRUNC)) ! flags = SMB_OPLOCK_BREAK_TO_NONE; ! else ! flags = SMB_OPLOCK_BREAK_TO_LEVEL_II; ! rc = smb_fem_oplock_break(arg, ct, flags); } if (rc == 0) rc = vnext_open(arg, mode, cr, ct); return (rc); } --- 424,464 ---- femarg_t *arg, int mode, cred_t *cr, caller_context_t *ct) { ! smb_node_t *node; ! uint32_t status; int rc = 0; if (ct != &smb_ct) { ! uint32_t req_acc = FILE_READ_DATA; ! uint32_t cr_disp = FILE_OPEN_IF; ! ! node = (smb_node_t *)(arg->fa_fnode->fn_available); ! SMB_NODE_VALID(node); ! ! /* ! * Get req_acc, cr_disp just accurate enough so ! * the oplock break call does the right thing. ! */ ! if (mode & FWRITE) { ! req_acc = FILE_READ_DATA | FILE_WRITE_DATA; ! cr_disp = (mode & FTRUNC) ? ! FILE_OVERWRITE_IF : FILE_OPEN_IF; ! } else { ! req_acc = FILE_READ_DATA; ! cr_disp = FILE_OPEN_IF; } + + status = smb_oplock_break_OPEN(node, NULL, + req_acc, cr_disp); + if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) + rc = smb_fem_oplock_wait(node, ct); + else if (status != 0) + rc = EIO; + } if (rc == 0) rc = vnext_open(arg, mode, cr, ct); return (rc); }
*** 450,464 **** uio_t *uiop, int ioflag, cred_t *cr, caller_context_t *ct) { int rc = 0; if (ct != &smb_ct) { ! rc = smb_fem_oplock_break(arg, ct, ! SMB_OPLOCK_BREAK_TO_LEVEL_II); } if (rc == 0) rc = vnext_read(arg, uiop, ioflag, cr, ct); return (rc); --- 474,496 ---- uio_t *uiop, int ioflag, cred_t *cr, caller_context_t *ct) { + smb_node_t *node; + uint32_t status; int rc = 0; if (ct != &smb_ct) { ! node = (smb_node_t *)(arg->fa_fnode->fn_available); ! SMB_NODE_VALID(node); ! ! status = smb_oplock_break_READ(node, NULL); ! if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) ! rc = smb_fem_oplock_wait(node, ct); ! else if (status != 0) ! rc = EIO; } if (rc == 0) rc = vnext_read(arg, uiop, ioflag, cr, ct); return (rc);
*** 475,488 **** uio_t *uiop, int ioflag, cred_t *cr, caller_context_t *ct) { int rc = 0; ! if (ct != &smb_ct) ! rc = smb_fem_oplock_break(arg, ct, SMB_OPLOCK_BREAK_TO_NONE); if (rc == 0) rc = vnext_write(arg, uiop, ioflag, cr, ct); return (rc); } --- 507,530 ---- uio_t *uiop, int ioflag, cred_t *cr, caller_context_t *ct) { + smb_node_t *node; + uint32_t status; int rc = 0; ! if (ct != &smb_ct) { ! node = (smb_node_t *)(arg->fa_fnode->fn_available); ! SMB_NODE_VALID(node); ! ! status = smb_oplock_break_WRITE(node, NULL); ! if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) ! rc = smb_fem_oplock_wait(node, ct); ! else if (status != 0) ! rc = EIO; ! } if (rc == 0) rc = vnext_write(arg, uiop, ioflag, cr, ct); return (rc); }
*** 493,530 **** vattr_t *vap, int flags, cred_t *cr, caller_context_t *ct) { int rc = 0; ! if (ct != &smb_ct && (vap->va_mask & AT_SIZE) != 0) ! rc = smb_fem_oplock_break(arg, ct, SMB_OPLOCK_BREAK_TO_NONE); ! if (rc == 0) ! rc = vnext_setattr(arg, vap, flags, cr, ct); ! return (rc); ! } ! static int ! smb_fem_oplock_rwlock( ! femarg_t *arg, ! int write_lock, ! caller_context_t *ct) ! { ! uint32_t flags; ! int rc = 0; ! ! if (ct != &smb_ct) { ! if (write_lock) ! flags = SMB_OPLOCK_BREAK_TO_NONE; ! else ! flags = SMB_OPLOCK_BREAK_TO_LEVEL_II; ! rc = smb_fem_oplock_break(arg, ct, flags); } if (rc == 0) ! rc = vnext_rwlock(arg, write_lock, ct); ! return (rc); } static int smb_fem_oplock_space( --- 535,561 ---- vattr_t *vap, int flags, cred_t *cr, caller_context_t *ct) { + smb_node_t *node; + uint32_t status; int rc = 0; ! if (ct != &smb_ct && (vap->va_mask & AT_SIZE) != 0) { ! node = (smb_node_t *)(arg->fa_fnode->fn_available); ! SMB_NODE_VALID(node); ! status = smb_oplock_break_SETINFO(node, NULL, ! FileEndOfFileInformation); ! if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) ! rc = smb_fem_oplock_wait(node, ct); ! else if (status != 0) ! rc = EIO; } if (rc == 0) ! rc = vnext_setattr(arg, vap, flags, cr, ct); return (rc); } static int smb_fem_oplock_space(
*** 534,547 **** int flag, offset_t offset, cred_t *cr, caller_context_t *ct) { int rc = 0; ! if (ct != &smb_ct) ! rc = smb_fem_oplock_break(arg, ct, SMB_OPLOCK_BREAK_TO_NONE); if (rc == 0) rc = vnext_space(arg, cmd, bfp, flag, offset, cr, ct); return (rc); } --- 565,589 ---- int flag, offset_t offset, cred_t *cr, caller_context_t *ct) { + smb_node_t *node; + uint32_t status; int rc = 0; ! if (ct != &smb_ct) { ! node = (smb_node_t *)(arg->fa_fnode->fn_available); ! SMB_NODE_VALID(node); ! ! status = smb_oplock_break_SETINFO(node, NULL, ! FileAllocationInformation); ! if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) ! rc = smb_fem_oplock_wait(node, ct); ! else if (status != 0) ! rc = EIO; ! } if (rc == 0) rc = vnext_space(arg, cmd, bfp, flag, offset, cr, ct); return (rc); }
*** 565,620 **** vnevent_t vnevent, vnode_t *dvp, char *name, caller_context_t *ct) { ! uint32_t flags; int rc = 0; if (ct != &smb_ct) { switch (vnevent) { case VE_REMOVE: case VE_PRE_RENAME_DEST: case VE_RENAME_DEST: ! flags = SMB_OPLOCK_BREAK_TO_NONE | ! SMB_OPLOCK_BREAK_BATCH; ! rc = smb_fem_oplock_break(arg, ct, flags); break; case VE_PRE_RENAME_SRC: case VE_RENAME_SRC: ! flags = SMB_OPLOCK_BREAK_TO_LEVEL_II | ! SMB_OPLOCK_BREAK_BATCH; ! rc = smb_fem_oplock_break(arg, ct, flags); break; default: ! rc = 0; break; } } if (rc == 0) rc = vnext_vnevent(arg, vnevent, dvp, name, ct); return (rc); } static int ! smb_fem_oplock_break(femarg_t *arg, caller_context_t *ct, uint32_t flags) { ! smb_node_t *node; ! int rc; - node = (smb_node_t *)((arg)->fa_fnode->fn_available); - SMB_NODE_VALID(node); - ASSERT(ct != &smb_ct); if (ct && (ct->cc_flags & CC_DONTBLOCK)) { - flags |= SMB_OPLOCK_BREAK_NOWAIT; - rc = smb_oplock_break(NULL, node, flags); - if (rc == EAGAIN) ct->cc_flags |= CC_WOULDBLOCK; } else { ! rc = smb_oplock_break(NULL, node, flags); } return (rc); } --- 607,665 ---- vnevent_t vnevent, vnode_t *dvp, char *name, caller_context_t *ct) { ! smb_node_t *node; ! uint32_t status; int rc = 0; if (ct != &smb_ct) { + node = (smb_node_t *)(arg->fa_fnode->fn_available); + SMB_NODE_VALID(node); + switch (vnevent) { case VE_REMOVE: case VE_PRE_RENAME_DEST: case VE_RENAME_DEST: ! status = smb_oplock_break_HANDLE(node, NULL); break; case VE_PRE_RENAME_SRC: case VE_RENAME_SRC: ! status = smb_oplock_break_SETINFO(node, NULL, ! FileRenameInformation); break; default: ! status = 0; break; } + if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) + rc = smb_fem_oplock_wait(node, ct); + else if (status != 0) + rc = EIO; } if (rc == 0) rc = vnext_vnevent(arg, vnevent, dvp, name, ct); return (rc); } + int smb_fem_oplock_timeout = 5000; /* mSec. */ + static int ! smb_fem_oplock_wait(smb_node_t *node, caller_context_t *ct) { ! int rc = 0; ASSERT(ct != &smb_ct); if (ct && (ct->cc_flags & CC_DONTBLOCK)) { ct->cc_flags |= CC_WOULDBLOCK; + rc = EAGAIN; } else { ! (void) smb_oplock_wait_break(node, ! smb_fem_oplock_timeout); ! rc = 0; } return (rc); }