Print this page
NEX-16818 Add fksmbcl development tool
NEX-17264 SMB client test tp_smbutil_013 fails after NEX-14666
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
and: (fix ref leaks)
NEX-16783 Panic in smbfs_delmap_callback (cstyle)
NEX-16783 Panic in smbfs_delmap_callback (fix leak)
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Dan Fields <dan.fields@nexenta.com>
5404 smbfs needs mmap support
Portions contributed by: Gordon Ross <gordon.w.ross@gmail.com>
Reviewed by: C Fraire <cfraire@me.com>
Reviewed by: Toomas Soome <tsoome@me.com>
Reviewed by: Jason King <jason.brian.king@gmail.com>
Reviewed by: Andrew Stormont <andyjstormont@gmail.com>
Approved by: Richard Lowe <richlowe@richlowe.net>
1586 mount_smbfs doesn't document noacl
Reviewed by: Jason King <jason.brian.king@gmail.com>
Reviewed by: C Fraire <cfraire@me.com>
Approved by: Richard Lowe <richlowe@richlowe.net>

*** 34,43 **** --- 34,44 ---- /* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2013, Joyent, Inc. All rights reserved. * Copyright (c) 2016 by Delphix. All rights reserved. + * Copyright 2017 Nexenta Systems, Inc. All rights reserved. */ #include <sys/systm.h> #include <sys/cred.h> #include <sys/time.h>
*** 49,66 **** --- 50,69 ---- #include <sys/mkdev.h> #include <sys/mount.h> #include <sys/statvfs.h> #include <sys/errno.h> #include <sys/debug.h> + #include <sys/disp.h> #include <sys/cmn_err.h> #include <sys/modctl.h> #include <sys/policy.h> #include <sys/atomic.h> #include <sys/zone.h> #include <sys/vfs_opreg.h> #include <sys/mntent.h> #include <sys/priv.h> + #include <sys/taskq.h> #include <sys/tsol/label.h> #include <sys/tsol/tndb.h> #include <inet/ip.h> #include <netsmb/smb_osdep.h>
*** 71,86 **** --- 74,120 ---- #include <smbfs/smbfs.h> #include <smbfs/smbfs_node.h> #include <smbfs/smbfs_subr.h> + #ifndef _KERNEL + + #include <libfksmbfs.h> + + #define STRUCT_DECL(s, a) struct s a + #define STRUCT_FGET(handle, field) ((handle).field) + #define _init(v) fksmbfs_init(v) + #define _fini(v) fksmbfs_fini(v) + + #endif /* !_KERNEL */ + /* + * Should smbfs mount enable "-o acl" by default? There are good + * arguments for both. The most common use case is individual users + * accessing files on some SMB server, for which "noacl" is the more + * convenient default. A less common use case is data migration, + * where the "acl" option might be a desirable default. We'll make + * the common use case the default. This default can be changed via + * /etc/system, and/or set per-mount via the "acl" mount option. + */ + int smbfs_default_opt_acl = 0; + + /* + * How many taskq threads per-mount should we use. + * Just one is fine (until we do more async work). + */ + int smbfs_tq_nthread = 1; + + /* * Local functions definitions. */ int smbfsinit(int fstyp, char *name); void smbfsfini(); + + #ifdef _KERNEL static int smbfs_mount_label_policy(vfs_t *, void *, int, cred_t *); + #endif /* _KERNEL */ /* * SMBFS Mount options table for MS_OPTIONSTR * Note: These are not all the options. * Some options come in via MS_DATA.
*** 98,111 **** * option name cancel option default arg flags * ufs arg flag */ { MNTOPT_INTR, intr_cancel, NULL, MO_DEFAULT, 0 }, { MNTOPT_NOINTR, nointr_cancel, NULL, 0, 0 }, ! { MNTOPT_ACL, acl_cancel, NULL, MO_DEFAULT, 0 }, { MNTOPT_NOACL, noacl_cancel, NULL, 0, 0 }, { MNTOPT_XATTR, xattr_cancel, NULL, MO_DEFAULT, 0 }, ! { MNTOPT_NOXATTR, noxattr_cancel, NULL, 0, 0 } }; static mntopts_t smbfs_mntopts = { sizeof (mntopts) / sizeof (mntopt_t), mntopts --- 132,149 ---- * option name cancel option default arg flags * ufs arg flag */ { MNTOPT_INTR, intr_cancel, NULL, MO_DEFAULT, 0 }, { MNTOPT_NOINTR, nointr_cancel, NULL, 0, 0 }, ! { MNTOPT_ACL, acl_cancel, NULL, 0, 0 }, { MNTOPT_NOACL, noacl_cancel, NULL, 0, 0 }, { MNTOPT_XATTR, xattr_cancel, NULL, MO_DEFAULT, 0 }, ! { MNTOPT_NOXATTR, noxattr_cancel, NULL, 0, 0 }, ! #ifndef _KERNEL ! /* See vfs_optionisset MNTOPT_NOAC below. */ ! { MNTOPT_NOAC, NULL, NULL, 0, 0 }, ! #endif /* !_KERNEL */ }; static mntopts_t smbfs_mntopts = { sizeof (mntopts) / sizeof (mntopt_t), mntopts
*** 119,137 **** --- 157,177 ---- smbfsinit, /* init routine */ VSW_HASPROTO|VSW_NOTZONESAFE, /* flags */ &smbfs_mntopts /* mount options table prototype */ }; + #ifdef _KERNEL static struct modlfs modlfs = { &mod_fsops, "SMBFS filesystem", &vfw }; static struct modlinkage modlinkage = { MODREV_1, (void *)&modlfs, NULL }; + #endif /* _KERNEL */ /* * Mutex to protect the following variables: * smbfs_major * smbfs_minor
*** 200,210 **** --- 240,255 ---- smbfs_vfsfini(); smbfs_subrfini(); return (error); } + #ifdef _KERNEL error = mod_install((struct modlinkage *)&modlinkage); + #else /* _KERNEL */ + error = fake_installfs(&vfw); + #endif /* _KERNEL */ + return (error); } /* * Free kernel module resources that were allocated in _init
*** 222,232 **** --- 267,281 ---- * into VFS_FREEVFS(). */ if (smbfs_mountcount) return (EBUSY); + #ifdef _KERNEL error = mod_remove(&modlinkage); + #else /* _KERNEL */ + error = fake_removefs(&vfw); + #endif /* _KERNEL */ if (error) return (error); /* * Free the allocated smbnodes, etc.
*** 245,265 **** } /* * Return information about the module */ int _info(struct modinfo *modinfop) { return (mod_info((struct modlinkage *)&modlinkage, modinfop)); } /* * Initialize the vfs structure */ ! int smbfsfstyp; vfsops_t *smbfs_vfsops = NULL; static const fs_operation_def_t smbfs_vfsops_template[] = { { VFSNAME_MOUNT, { .vfs_mount = smbfs_mount } }, { VFSNAME_UNMOUNT, { .vfs_unmount = smbfs_unmount } }, --- 294,316 ---- } /* * Return information about the module */ + #ifdef _KERNEL int _info(struct modinfo *modinfop) { return (mod_info((struct modlinkage *)&modlinkage, modinfop)); } + #endif /* _KERNEL */ /* * Initialize the vfs structure */ ! int smbfs_fstyp; vfsops_t *smbfs_vfsops = NULL; static const fs_operation_def_t smbfs_vfsops_template[] = { { VFSNAME_MOUNT, { .vfs_mount = smbfs_mount } }, { VFSNAME_UNMOUNT, { .vfs_unmount = smbfs_unmount } },
*** 270,309 **** { VFSNAME_MOUNTROOT, { .error = fs_nosys } }, { VFSNAME_FREEVFS, { .vfs_freevfs = smbfs_freevfs } }, { NULL, NULL } }; int smbfsinit(int fstyp, char *name) { int error; error = vfs_setfsops(fstyp, smbfs_vfsops_template, &smbfs_vfsops); if (error != 0) { ! zcmn_err(GLOBAL_ZONEID, CE_WARN, "smbfsinit: bad vfs ops template"); return (error); } error = vn_make_ops(name, smbfs_vnodeops_template, &smbfs_vnodeops); if (error != 0) { (void) vfs_freevfsops_by_type(fstyp); ! zcmn_err(GLOBAL_ZONEID, CE_WARN, "smbfsinit: bad vnode ops template"); return (error); } ! smbfsfstyp = fstyp; return (0); } void smbfsfini() { if (smbfs_vfsops) { ! (void) vfs_freevfsops_by_type(smbfsfstyp); smbfs_vfsops = NULL; } if (smbfs_vnodeops) { vn_freevnodeops(smbfs_vnodeops); smbfs_vnodeops = NULL; --- 321,364 ---- { VFSNAME_MOUNTROOT, { .error = fs_nosys } }, { VFSNAME_FREEVFS, { .vfs_freevfs = smbfs_freevfs } }, { NULL, NULL } }; + /* + * This is the VFS switch initialization routine, normally called + * via vfssw[x].vsw_init by vfsinit() or mod_install + */ int smbfsinit(int fstyp, char *name) { int error; error = vfs_setfsops(fstyp, smbfs_vfsops_template, &smbfs_vfsops); if (error != 0) { ! cmn_err(CE_WARN, "smbfsinit: bad vfs ops template"); return (error); } error = vn_make_ops(name, smbfs_vnodeops_template, &smbfs_vnodeops); if (error != 0) { (void) vfs_freevfsops_by_type(fstyp); ! cmn_err(CE_WARN, "smbfsinit: bad vnode ops template"); return (error); } ! smbfs_fstyp = fstyp; return (0); } void smbfsfini() { if (smbfs_vfsops) { ! (void) vfs_freevfsops_by_type(smbfs_fstyp); smbfs_vfsops = NULL; } if (smbfs_vnodeops) { vn_freevnodeops(smbfs_vnodeops); smbfs_vnodeops = NULL;
*** 314,325 **** --- 369,382 ---- smbfs_free_smi(smbmntinfo_t *smi) { if (smi == NULL) return; + #ifdef _KERNEL if (smi->smi_zone_ref.zref_zone != NULL) zone_rele_ref(&smi->smi_zone_ref, ZONE_REF_SMBFS); + #endif /* _KERNEL */ if (smi->smi_share != NULL) smb_share_rele(smi->smi_share); avl_destroy(&smi->smi_hash_avl);
*** 342,361 **** smbnode_t *rtnp = NULL; /* root of this fs */ smbmntinfo_t *smi = NULL; dev_t smbfs_dev; int version; int devfd; ! zone_t *zone = curproc->p_zone; zone_t *mntzone = NULL; smb_share_t *ssp = NULL; smb_cred_t scred; int flags, sec; - STRUCT_DECL(smbfs_args, args); /* smbfs mount arguments */ if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0) return (error); if (mvp->v_type != VDIR) return (ENOTDIR); /* --- 399,423 ---- smbnode_t *rtnp = NULL; /* root of this fs */ smbmntinfo_t *smi = NULL; dev_t smbfs_dev; int version; int devfd; ! zone_t *zone = curzone; ! #ifdef _KERNEL zone_t *mntzone = NULL; + #else /* _KERNEL */ + short minclsyspri = MINCLSYSPRI; + #endif /* _KERNEL */ smb_share_t *ssp = NULL; smb_cred_t scred; int flags, sec; STRUCT_DECL(smbfs_args, args); /* smbfs mount arguments */ + #ifdef _KERNEL if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0) return (error); + #endif /* _KERNEL */ if (mvp->v_type != VDIR) return (ENOTDIR); /*
*** 362,376 **** --- 424,444 ---- * get arguments * * uap->datalen might be different from sizeof (args) * in a compatible situation. */ + #ifdef _KERNEL STRUCT_INIT(args, get_udatamodel()); bzero(STRUCT_BUF(args), SIZEOF_STRUCT(smbfs_args, DATAMODEL_NATIVE)); if (copyin(data, STRUCT_BUF(args), MIN(uap->datalen, SIZEOF_STRUCT(smbfs_args, DATAMODEL_NATIVE)))) return (EFAULT); + #else /* _KERNEL */ + bzero(&args, sizeof (args)); + if (copyin(data, &args, MIN(uap->datalen, sizeof (args)))) + return (EFAULT); + #endif /* _KERNEL */ /* * Check mount program version */ version = STRUCT_FGET(args, version);
*** 417,426 **** --- 485,495 ---- /* * Use "goto errout" from here on. * See: ssp, smi, rtnp, mntzone */ + #ifdef _KERNEL /* * Determine the zone we're being mounted into. */ zone_hold(mntzone = zone); /* start with this assumption */ if (getzoneid() == GLOBAL_ZONEID) {
*** 460,469 **** --- 529,539 ---- if (error == -1) { /* change mount to read-only to prevent write-down */ vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0); } } + #endif /* _KERNEL */ /* Prevent unload. */ atomic_inc_32(&smbfs_mountcount); /*
*** 482,530 **** smbfs_init_hash_avl(&smi->smi_hash_avl); smi->smi_share = ssp; ssp = NULL; /* * Convert the anonymous zone hold acquired via zone_hold() above * into a zone reference. */ zone_init_ref(&smi->smi_zone_ref); zone_hold_ref(mntzone, &smi->smi_zone_ref, ZONE_REF_SMBFS); zone_rele(mntzone); mntzone = NULL; /* * Initialize option defaults */ - smi->smi_flags = SMI_LLOCK; smi->smi_acregmin = SEC2HR(SMBFS_ACREGMIN); smi->smi_acregmax = SEC2HR(SMBFS_ACREGMAX); smi->smi_acdirmin = SEC2HR(SMBFS_ACDIRMIN); smi->smi_acdirmax = SEC2HR(SMBFS_ACDIRMAX); /* * All "generic" mount options have already been * handled in vfs.c:domount() - see mntopts stuff. * Query generic options using vfs_optionisset(). */ if (vfs_optionisset(vfsp, MNTOPT_INTR, NULL)) smi->smi_flags |= SMI_INT; - if (vfs_optionisset(vfsp, MNTOPT_ACL, NULL)) - smi->smi_flags |= SMI_ACL; /* * Get the mount options that come in as smbfs_args, * starting with args.flags (SMBFS_MF_xxx) */ flags = STRUCT_FGET(args, flags); - smi->smi_uid = STRUCT_FGET(args, uid); - smi->smi_gid = STRUCT_FGET(args, gid); smi->smi_fmode = STRUCT_FGET(args, file_mode) & 0777; smi->smi_dmode = STRUCT_FGET(args, dir_mode) & 0777; /* * Hande the SMBFS_MF_xxx flags. */ if (flags & SMBFS_MF_NOAC) smi->smi_flags |= SMI_NOAC; if (flags & SMBFS_MF_ACREGMIN) { --- 552,632 ---- smbfs_init_hash_avl(&smi->smi_hash_avl); smi->smi_share = ssp; ssp = NULL; + #ifdef _KERNEL /* * Convert the anonymous zone hold acquired via zone_hold() above * into a zone reference. */ zone_init_ref(&smi->smi_zone_ref); zone_hold_ref(mntzone, &smi->smi_zone_ref, ZONE_REF_SMBFS); zone_rele(mntzone); mntzone = NULL; + #else /* _KERNEL */ + smi->smi_zone_ref.zref_zone = curzone; + #endif /* _KERNEL */ /* * Initialize option defaults */ smi->smi_acregmin = SEC2HR(SMBFS_ACREGMIN); smi->smi_acregmax = SEC2HR(SMBFS_ACREGMAX); smi->smi_acdirmin = SEC2HR(SMBFS_ACDIRMIN); smi->smi_acdirmax = SEC2HR(SMBFS_ACDIRMAX); + smi->smi_flags = SMI_LLOCK; + #ifndef _KERNEL + /* Always direct IO with fakekernel */ + smi->smi_flags |= SMI_DIRECTIO; + #endif /* _KERNEL */ /* * All "generic" mount options have already been * handled in vfs.c:domount() - see mntopts stuff. * Query generic options using vfs_optionisset(). + * Give ACL an adjustable system-wide default. */ + if (smbfs_default_opt_acl || + vfs_optionisset(vfsp, MNTOPT_ACL, NULL)) + smi->smi_flags |= SMI_ACL; + if (vfs_optionisset(vfsp, MNTOPT_NOACL, NULL)) + smi->smi_flags &= ~SMI_ACL; if (vfs_optionisset(vfsp, MNTOPT_INTR, NULL)) smi->smi_flags |= SMI_INT; /* * Get the mount options that come in as smbfs_args, * starting with args.flags (SMBFS_MF_xxx) */ flags = STRUCT_FGET(args, flags); smi->smi_fmode = STRUCT_FGET(args, file_mode) & 0777; smi->smi_dmode = STRUCT_FGET(args, dir_mode) & 0777; + #ifdef _KERNEL + smi->smi_uid = STRUCT_FGET(args, uid); + smi->smi_gid = STRUCT_FGET(args, gid); + #else /* _KERNEL */ + /* + * Need uid/gid to match our fake cred we'll fail in + * smbfs_access_rwx later. + */ + smi->smi_uid = crgetuid(cr); + smi->smi_gid = crgetgid(cr); /* + * Our user-level do_mount() passes the mount options sting + * as-is, where the real mount program would convert some + * of those options to bits set in smbfs_args.flags. + * To avoid replicating all that conversion code, this + * uses the generic vfs option support to handle those + * option flag bits we need, i.e.: "noac" + */ + if (vfs_optionisset(vfsp, MNTOPT_NOAC, NULL)) + flags |= SMBFS_MF_NOAC; + #endif /* _KERNEL */ + + /* * Hande the SMBFS_MF_xxx flags. */ if (flags & SMBFS_MF_NOAC) smi->smi_flags |= SMI_NOAC; if (flags & SMBFS_MF_ACREGMIN) {
*** 589,601 **** smbfs_dev = makedevice(smbfs_major, smbfs_minor); } while (vfs_devismounted(smbfs_dev)); mutex_exit(&smbfs_minor_lock); vfsp->vfs_dev = smbfs_dev; ! vfs_make_fsid(&vfsp->vfs_fsid, smbfs_dev, smbfsfstyp); vfsp->vfs_data = (caddr_t)smi; ! vfsp->vfs_fstype = smbfsfstyp; vfsp->vfs_bsize = MAXBSIZE; vfsp->vfs_bcount = 0; smi->smi_vfsp = vfsp; smbfs_zonelist_add(smi); /* undo in smbfs_freevfs */ --- 691,703 ---- smbfs_dev = makedevice(smbfs_major, smbfs_minor); } while (vfs_devismounted(smbfs_dev)); mutex_exit(&smbfs_minor_lock); vfsp->vfs_dev = smbfs_dev; ! vfs_make_fsid(&vfsp->vfs_fsid, smbfs_dev, smbfs_fstyp); vfsp->vfs_data = (caddr_t)smi; ! vfsp->vfs_fstype = smbfs_fstyp; vfsp->vfs_bsize = MAXBSIZE; vfsp->vfs_bcount = 0; smi->smi_vfsp = vfsp; smbfs_zonelist_add(smi); /* undo in smbfs_freevfs */
*** 615,632 **** --- 717,743 ---- rtnp->r_vnode->v_type = VDIR; rtnp->r_vnode->v_flag |= VROOT; smi->smi_root = rtnp; /* + * Create a taskq for async work (i.e. putpage) + */ + smi->smi_taskq = taskq_create_proc("smbfs", + smbfs_tq_nthread, minclsyspri, + smbfs_tq_nthread, smbfs_tq_nthread * 2, + zone->zone_zsched, TASKQ_PREPOPULATE); + + /* * NFS does other stuff here too: * async worker threads * init kstats * * End of code from NFS nfsrootvp() */ return (0); + #ifdef _KERNEL errout: vfsp->vfs_data = NULL; if (smi != NULL) smbfs_free_smi(smi);
*** 635,644 **** --- 746,756 ---- if (ssp != NULL) smb_share_rele(ssp); return (error); + #endif /* _KERNEL */ } /* * vfs operations */
*** 648,659 **** --- 760,773 ---- smbmntinfo_t *smi; smbnode_t *rtnp; smi = VFTOSMI(vfsp); + #ifdef _KERNEL if (secpolicy_fs_unmount(cr, vfsp) != 0) return (EPERM); + #endif /* _KERNEL */ if ((flag & MS_FORCE) == 0) { smbfs_rflush(vfsp, cr); /*
*** 683,701 **** * but not for long. */ vfsp->vfs_flag |= VFS_UNMOUNTED; /* - * Shutdown any outstanding I/O requests on this share, - * and force a tree disconnect. The share object will - * continue to hang around until smb_share_rele(). - * This should also cause most active nodes to be - * released as their operations fail with EIO. - */ - smb_share_kill(smi->smi_share); - - /* * If we hold the root VP (and we normally do) * then it's safe to release it now. */ if (smi->smi_root) { rtnp = smi->smi_root; --- 797,806 ----
*** 714,723 **** --- 819,843 ---- * after their last vn_rele. */ smbfs_destroy_table(vfsp); /* + * Shutdown any outstanding I/O requests on this share, + * and force a tree disconnect. The share object will + * continue to hang around until smb_share_rele(). + * This should also cause most active nodes to be + * released as their operations fail with EIO. + */ + smb_share_kill(smi->smi_share); + + /* + * Any async taskq work should be giving up. + * Wait for those to exit. + */ + taskq_destroy(smi->smi_taskq); + + /* * Delete our kstats... * * Doing it here, rather than waiting until * smbfs_freevfs so these are not visible * after the unmount.
*** 863,911 **** *sbp = smi->smi_statvfsbuf; mutex_exit(&smi->smi_lock); return (error); } - static kmutex_t smbfs_syncbusy; - /* * Flush dirty smbfs files for file system vfsp. * If vfsp == NULL, all smbfs files are flushed. */ /*ARGSUSED*/ static int smbfs_sync(vfs_t *vfsp, short flag, cred_t *cr) { /* ! * Cross-zone calls are OK here, since this translates to a ! * VOP_PUTPAGE(B_ASYNC), which gets picked up by the right zone. */ ! if (!(flag & SYNC_ATTR) && mutex_tryenter(&smbfs_syncbusy) != 0) { ! smbfs_rflush(vfsp, cr); ! mutex_exit(&smbfs_syncbusy); } return (0); } /* * Initialization routine for VFS routines. Should only be called once */ int smbfs_vfsinit(void) { - mutex_init(&smbfs_syncbusy, NULL, MUTEX_DEFAULT, NULL); return (0); } /* * Shutdown routine for VFS routines. Should only be called once */ void smbfs_vfsfini(void) { - mutex_destroy(&smbfs_syncbusy); } void smbfs_freevfs(vfs_t *vfsp) { --- 983,1038 ---- *sbp = smi->smi_statvfsbuf; mutex_exit(&smi->smi_lock); return (error); } /* * Flush dirty smbfs files for file system vfsp. * If vfsp == NULL, all smbfs files are flushed. */ /*ARGSUSED*/ static int smbfs_sync(vfs_t *vfsp, short flag, cred_t *cr) { + /* ! * SYNC_ATTR is used by fsflush() to force old filesystems like UFS ! * to sync metadata, which they would otherwise cache indefinitely. ! * Semantically, the only requirement is that the sync be initiated. ! * Assume the server-side takes care of attribute sync. */ ! if (flag & SYNC_ATTR) ! return (0); ! ! if (vfsp == NULL) { ! /* ! * Flush ALL smbfs mounts in this zone. ! */ ! smbfs_flushall(cr); ! return (0); } + smbfs_rflush(vfsp, cr); + return (0); } /* * Initialization routine for VFS routines. Should only be called once */ int smbfs_vfsinit(void) { return (0); } /* * Shutdown routine for VFS routines. Should only be called once */ void smbfs_vfsfini(void) { } void smbfs_freevfs(vfs_t *vfsp) {
*** 929,938 **** --- 1056,1066 ---- * Allow _fini() to succeed now, if so desired. */ atomic_dec_32(&smbfs_mountcount); } + #ifdef _KERNEL /* * smbfs_mount_label_policy: * Determine whether the mount is allowed according to MAC check, * by comparing (where appropriate) label of the remote server * against the label of the zone being mounted into.
*** 1019,1023 **** --- 1147,1152 ---- if (mntzone) zone_rele(mntzone); label_rele(zlabel); return (retv); } + #endif /* _KERNEL */