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);
}