Print this page
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-15069 smtorture smb2.create.blob is failed
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-6276 SMB sparse file support
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-5844 want SMB2 ioctl FSCTL_SRV_COPYCHUNK
NEX-6124 smb_fsop_read/write should allow file != sr->fid_ofile
NEX-6125 smbtorture invalid response with smb2.ioctl
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@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-4239 smbtorture create failures re. allocation size
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@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-2831 panic in smb_make_link
NEX-2442 regression with smbtorture test raw.sfileinfo.rename
SMB-122 smbd core dumps in smbd_dc_update / smb_log
SMB-117 Win7 fails to open security properties
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>

@@ -8,15 +8,16 @@
  * source.  A copy of the CDDL is also available via the Internet at
  * http://www.illumos.org/license/CDDL.
  */
 
 /*
- * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
  */
 
 #include <sys/types.h>
 #include <sys/param.h>
+#include <sys/systm.h>
 #include <sys/t_lock.h>
 #include <sys/errno.h>
 #include <sys/cred.h>
 #include <sys/user.h>
 #include <sys/uio.h>

@@ -25,13 +26,15 @@
 #include <sys/vfs.h>
 #include <sys/vnode.h>
 #include <sys/stat.h>
 #include <sys/mode.h>
 #include <sys/kmem.h>
+#include <sys/cmn_err.h>
 #include <sys/debug.h>
 #include <sys/atomic.h>
 #include <sys/acl.h>
+#include <sys/filio.h>
 #include <sys/flock.h>
 #include <sys/nbmlock.h>
 #include <sys/fcntl.h>
 #include <sys/poll.h>
 #include <sys/time.h>

@@ -48,10 +51,11 @@
 
 int stat_to_vattr(const struct stat *, vattr_t *);
 int fop__getxvattr(vnode_t *, xvattr_t *);
 int fop__setxvattr(vnode_t *, xvattr_t *);
 
+static void fake_inactive_xattrdir(vnode_t *);
 
 /* ARGSUSED */
 int
 fop_open(
         vnode_t **vpp,

@@ -212,11 +216,33 @@
         int flag,
         cred_t *cr,
         int *rvalp,
         caller_context_t *ct)
 {
-        return (ENOSYS);
+        off64_t off;
+        int rv, whence;
+
+        switch (cmd) {
+        case _FIO_SEEK_DATA:
+        case _FIO_SEEK_HOLE:
+                whence = (cmd == _FIO_SEEK_DATA) ? SEEK_DATA : SEEK_HOLE;
+                bcopy((void *)arg, &off, sizeof (off));
+                off = lseek(vp->v_fd, off, whence);
+                if (off == (off64_t)-1) {
+                        rv = errno;
+                } else {
+                        bcopy(&off, (void *)arg, sizeof (off));
+                        rv = 0;
+                }
+                break;
+
+        default:
+                rv = ENOTTY;
+                break;
+        }
+
+        return (rv);
 }
 
 /* ARGSUSED */
 int
 fop_setfl(

@@ -260,15 +286,20 @@
         int flags,
         cred_t *cr,
         caller_context_t *ct)
 {
         timespec_t times[2];
+        int err;
 
         if (vap->va_mask & AT_SIZE) {
-                if (ftruncate(vp->v_fd, vap->va_size) == -1)
-                        return (errno);
+                if (ftruncate(vp->v_fd, vap->va_size) == -1) {
+                        err = errno;
+                        if (err == EBADF)
+                                err = EACCES;
+                        return (err);
         }
+        }
 
         /* AT_MODE or anything else? */
 
         if (vap->va_mask & AT_XVATTR)
                 (void) fop__setxvattr(vp, (xvattr_t *)vap);

@@ -303,10 +334,79 @@
         caller_context_t *ct)
 {
         return (0);
 }
 
+/*
+ * Conceptually like xattr_dir_lookup()
+ */
+static int
+fake_lookup_xattrdir(
+        vnode_t *dvp,
+        vnode_t **vpp)
+{
+        int len, fd;
+        int omode = O_RDWR | O_NOFOLLOW;
+        vnode_t *vp;
+
+        *vpp = NULL;
+
+        if (dvp->v_type != VDIR && dvp->v_type != VREG)
+                return (EINVAL);
+
+        /*
+         * If we're already in sysattr space, don't allow creation
+         * of another level of sysattrs.
+         */
+        if (dvp->v_flag & V_SYSATTR)
+                return (EINVAL);
+
+        mutex_enter(&dvp->v_lock);
+        if (dvp->v_xattrdir != NULL) {
+                *vpp = dvp->v_xattrdir;
+                VN_HOLD(*vpp);
+                mutex_exit(&dvp->v_lock);
+                return (0);
+        }
+        mutex_exit(&dvp->v_lock);
+
+        omode = O_RDONLY|O_XATTR;
+        fd = openat(dvp->v_fd, ".", omode);
+        if (fd < 0)
+                return (errno);
+
+        vp = vn_alloc(KM_SLEEP);
+        vp->v_fd = fd;
+        vp->v_flag = V_XATTRDIR|V_SYSATTR;
+        vp->v_type = VDIR;
+        vp->v_vfsp = dvp->v_vfsp;
+
+        /* Set v_path to parent path + "/@" (like NFS) */
+        len = strlen(dvp->v_path) + 3;
+        vp->v_path = kmem_alloc(len, KM_SLEEP);
+        (void) snprintf(vp->v_path, len, "%s/@", dvp->v_path);
+
+        /*
+         * Keep a pointer to the parent and a hold on it.
+         * Both are cleaned up in fake_inactive_xattrdir
+         */
+        vp->v_data = dvp;
+        vn_hold(dvp);
+
+        mutex_enter(&dvp->v_lock);
+        if (dvp->v_xattrdir == NULL) {
+                *vpp = dvp->v_xattrdir = vp;
+                mutex_exit(&dvp->v_lock);
+        } else {
+                *vpp = dvp->v_xattrdir;
+                mutex_exit(&dvp->v_lock);
+                fake_inactive_xattrdir(vp);
+        }
+
+        return (0);
+}
+
 /* ARGSUSED */
 int
 fop_lookup(
         vnode_t *dvp,
         char *name,

@@ -323,11 +423,11 @@
         int omode = O_RDWR | O_NOFOLLOW;
         vnode_t *vp;
         struct stat st;
 
         if (flags & LOOKUP_XATTR)
-                return (ENOENT);
+                return (fake_lookup_xattrdir(dvp, vpp));
 
         /*
          * If lookup is for "", just return dvp.
          */
         if (name[0] == '\0') {

@@ -679,13 +779,49 @@
 fop_inactive(
         vnode_t *vp,
         cred_t *cr,
         caller_context_t *ct)
 {
+        if (vp->v_flag & V_XATTRDIR) {
+                fake_inactive_xattrdir(vp);
+        } else {
         vncache_inactive(vp);
+        }
 }
 
+/*
+ * The special xattr directories are not in the vncache AVL, but
+ * hang off the parent's v_xattrdir field.  When vn_rele finds
+ * an xattr dir at v_count == 1 it calls here, but until we
+ * take locks on both the parent and the xattrdir, we don't
+ * know if we're really at the last reference.  So in here we
+ * take both locks, re-check the count, and either bail out
+ * or proceed with "inactive" vnode cleanup.  Part of that
+ * cleanup includes releasing the hold on the parent and
+ * clearing the parent's v_xattrdir field, which were
+ * setup in fake_lookup_xattrdir()
+ */
+static void
+fake_inactive_xattrdir(vnode_t *vp)
+{
+        vnode_t *dvp = vp->v_data; /* parent */
+        mutex_enter(&dvp->v_lock);
+        mutex_enter(&vp->v_lock);
+        if (vp->v_count > 1) {
+                /* new ref. via v_xattrdir */
+                mutex_exit(&vp->v_lock);
+                mutex_exit(&dvp->v_lock);
+                return;
+        }
+        ASSERT(dvp->v_xattrdir == vp);
+        dvp->v_xattrdir = NULL;
+        mutex_exit(&vp->v_lock);
+        mutex_exit(&dvp->v_lock);
+        vn_rele(dvp);
+        vn_free(vp);
+}
+
 /* ARGSUSED */
 int
 fop_fid(
         vnode_t *vp,
         fid_t *fidp,

@@ -747,10 +883,22 @@
         offset_t offset,
         struct flk_callback *flk_cbp,
         cred_t *cr,
         caller_context_t *ct)
 {
+#if defined(_LP64)
+        offset_t maxoffset = INT64_MAX;
+#elif defined(_ILP32)
+        /*
+         * Sadly, the fcntl API enforces 32-bit offsets,
+         * even though we have _FILE_OFFSET_BITS=64
+         */
+        offset_t maxoffset = INT32_MAX;
+#else
+#error "unsupported env."
+#endif
+
         /* See fs_frlock */
 
         switch (cmd) {
         case F_GETLK:
         case F_SETLK_NBMAND:

@@ -759,10 +907,34 @@
                 break;
         default:
                 return (EINVAL);
         }
 
+        /* We only get SEEK_SET ranges here. */
+        if (bfp->l_whence != 0)
+                return (EINVAL);
+
+        /*
+         * One limitation of using fcntl(2) F_SETLK etc is that
+         * the real kernel limits the offsets we can use.
+         * (Maybe the fcntl API should loosen that up?)
+         * See syscall/fcntl.c:flock_check()
+         *
+         * Here in libfksmbsrv we can just ignore such locks,
+         * or ignore the part that extends beyond maxoffset.
+         * The SMB layer still keeps track of such locks for
+         * conflict detection, so not reflecting such locks
+         * into the real FS layer is OK.  Note: this may
+         * modify the pased bfp->l_len.
+         */
+        if (bfp->l_start < 0 || bfp->l_start > maxoffset)
+                return (0);
+        if (bfp->l_len < 0 || bfp->l_len > maxoffset)
+                return (0);
+        if (bfp->l_len > (maxoffset - bfp->l_start + 1))
+                bfp->l_len = (maxoffset - bfp->l_start + 1);
+
         if (fcntl(vp->v_fd, cmd, bfp) == -1)
                 return (errno);
 
         return (0);
 }

@@ -981,11 +1153,11 @@
         case _PC_FILESIZEBITS:
                 val = (ulong_t)-1;    /* large file support */
                 break;
 
         case _PC_ACL_ENABLED:
-                val = 0;
+                val = _ACL_ACE_ENABLED;
                 break;
 
         case _PC_CASE_BEHAVIOR:
                 val = _CASE_SENSITIVE;
                 break;

@@ -1265,11 +1437,11 @@
 {
         VERIFY3U(vp->v_count, !=, 0);
         mutex_enter(&vp->v_lock);
         if (vp->v_count == 1) {
                 mutex_exit(&vp->v_lock);
-                vncache_inactive(vp);
+                fop_inactive(vp, NULL, NULL);
         } else {
                 vp->v_count--;
                 mutex_exit(&vp->v_lock);
         }
 }