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,11 +18,11 @@
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. 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,11 +79,10 @@
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 *);
@@ -90,17 +89,16 @@
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);
+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,19 +151,24 @@
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,
- (fem_func_t)smb_node_ref, (fem_func_t)smb_node_release);
+ NULL, NULL);
return (rc);
}
void
smb_fem_fcn_uninstall(smb_node_t *node)
@@ -421,20 +424,41 @@
femarg_t *arg,
int mode,
cred_t *cr,
caller_context_t *ct)
{
- uint32_t flags;
+ smb_node_t *node;
+ uint32_t status;
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);
+ 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,15 +474,23 @@
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) {
- rc = smb_fem_oplock_break(arg, ct,
- SMB_OPLOCK_BREAK_TO_LEVEL_II);
+ 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,14 +507,24 @@
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)
- rc = smb_fem_oplock_break(arg, ct, SMB_OPLOCK_BREAK_TO_NONE);
+ 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,38 +535,27 @@
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)
- 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);
-}
+ if (ct != &smb_ct && (vap->va_mask & AT_SIZE) != 0) {
+ node = (smb_node_t *)(arg->fa_fnode->fn_available);
+ SMB_NODE_VALID(node);
-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);
+ 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_rwlock(arg, write_lock, ct);
-
+ rc = vnext_setattr(arg, vap, flags, cr, ct);
return (rc);
}
static int
smb_fem_oplock_space(
@@ -534,14 +565,25 @@
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)
- rc = smb_fem_oplock_break(arg, ct, SMB_OPLOCK_BREAK_TO_NONE);
+ 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,56 +607,59 @@
vnevent_t vnevent,
vnode_t *dvp,
char *name,
caller_context_t *ct)
{
- uint32_t flags;
+ 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:
- flags = SMB_OPLOCK_BREAK_TO_NONE |
- SMB_OPLOCK_BREAK_BATCH;
- rc = smb_fem_oplock_break(arg, ct, flags);
+ status = smb_oplock_break_HANDLE(node, NULL);
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);
+ status = smb_oplock_break_SETINFO(node, NULL,
+ FileRenameInformation);
break;
default:
- rc = 0;
+ 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_break(femarg_t *arg, caller_context_t *ct, uint32_t flags)
+smb_fem_oplock_wait(smb_node_t *node, caller_context_t *ct)
{
- smb_node_t *node;
- int rc;
+ int rc = 0;
- 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;
+ rc = EAGAIN;
} else {
- rc = smb_oplock_break(NULL, node, flags);
+ (void) smb_oplock_wait_break(node,
+ smb_fem_oplock_timeout);
+ rc = 0;
}
return (rc);
}