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>


  19  *
  20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30  * SUCH DAMAGE.
  31  *
  32  * $Id: smbfs_vfsops.c,v 1.73.64.1 2005/05/27 02:35:28 lindak Exp $
  33  */
  34 
  35 /*
  36  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  37  * Copyright 2013, Joyent, Inc. All rights reserved.
  38  * Copyright (c) 2016 by Delphix. All rights reserved.

  39  */
  40 
  41 #include <sys/systm.h>
  42 #include <sys/cred.h>
  43 #include <sys/time.h>
  44 #include <sys/vfs.h>
  45 #include <sys/vnode.h>
  46 #include <fs/fs_subr.h>
  47 #include <sys/sysmacros.h>
  48 #include <sys/kmem.h>
  49 #include <sys/mkdev.h>
  50 #include <sys/mount.h>
  51 #include <sys/statvfs.h>
  52 #include <sys/errno.h>
  53 #include <sys/debug.h>

  54 #include <sys/cmn_err.h>
  55 #include <sys/modctl.h>
  56 #include <sys/policy.h>
  57 #include <sys/atomic.h>
  58 #include <sys/zone.h>
  59 #include <sys/vfs_opreg.h>
  60 #include <sys/mntent.h>
  61 #include <sys/priv.h>

  62 #include <sys/tsol/label.h>
  63 #include <sys/tsol/tndb.h>
  64 #include <inet/ip.h>
  65 
  66 #include <netsmb/smb_osdep.h>
  67 #include <netsmb/smb.h>
  68 #include <netsmb/smb_conn.h>
  69 #include <netsmb/smb_subr.h>
  70 #include <netsmb/smb_dev.h>
  71 
  72 #include <smbfs/smbfs.h>
  73 #include <smbfs/smbfs_node.h>
  74 #include <smbfs/smbfs_subr.h>
  75 











  76 /*

















  77  * Local functions definitions.
  78  */
  79 int             smbfsinit(int fstyp, char *name);
  80 void            smbfsfini();


  81 static int      smbfs_mount_label_policy(vfs_t *, void *, int, cred_t *);

  82 
  83 /*
  84  * SMBFS Mount options table for MS_OPTIONSTR
  85  * Note: These are not all the options.
  86  * Some options come in via MS_DATA.
  87  * Others are generic (see vfs.c)
  88  */
  89 static char *intr_cancel[] = { MNTOPT_NOINTR, NULL };
  90 static char *nointr_cancel[] = { MNTOPT_INTR, NULL };
  91 static char *acl_cancel[] = { MNTOPT_NOACL, NULL };
  92 static char *noacl_cancel[] = { MNTOPT_ACL, NULL };
  93 static char *xattr_cancel[] = { MNTOPT_NOXATTR, NULL };
  94 static char *noxattr_cancel[] = { MNTOPT_XATTR, NULL };
  95 
  96 static mntopt_t mntopts[] = {
  97 /*
  98  *      option name             cancel option   default arg     flags
  99  *              ufs arg flag
 100  */
 101         { MNTOPT_INTR,          intr_cancel,    NULL,   MO_DEFAULT, 0 },
 102         { MNTOPT_NOINTR,        nointr_cancel,  NULL,   0,      0 },
 103         { MNTOPT_ACL,           acl_cancel,     NULL,   MO_DEFAULT, 0 },
 104         { MNTOPT_NOACL,         noacl_cancel,   NULL,   0,      0 },
 105         { MNTOPT_XATTR,         xattr_cancel,   NULL,   MO_DEFAULT, 0 },
 106         { MNTOPT_NOXATTR,       noxattr_cancel, NULL,   0,      0 }




 107 };
 108 
 109 static mntopts_t smbfs_mntopts = {
 110         sizeof (mntopts) / sizeof (mntopt_t),
 111         mntopts
 112 };
 113 
 114 static const char fs_type_name[FSTYPSZ] = "smbfs";
 115 
 116 static vfsdef_t vfw = {
 117         VFSDEF_VERSION,
 118         (char *)fs_type_name,
 119         smbfsinit,              /* init routine */
 120         VSW_HASPROTO|VSW_NOTZONESAFE,   /* flags */
 121         &smbfs_mntopts                      /* mount options table prototype */
 122 };
 123 

 124 static struct modlfs modlfs = {
 125         &mod_fsops,
 126         "SMBFS filesystem",
 127         &vfw
 128 };
 129 
 130 static struct modlinkage modlinkage = {
 131         MODREV_1, (void *)&modlfs, NULL
 132 };

 133 
 134 /*
 135  * Mutex to protect the following variables:
 136  *        smbfs_major
 137  *        smbfs_minor
 138  */
 139 extern  kmutex_t        smbfs_minor_lock;
 140 extern  int             smbfs_major;
 141 extern  int             smbfs_minor;
 142 
 143 /*
 144  * Prevent unloads while we have mounts
 145  */
 146 uint32_t        smbfs_mountcount;
 147 
 148 /*
 149  * smbfs vfs operations.
 150  */
 151 static int      smbfs_mount(vfs_t *, vnode_t *, struct mounta *, cred_t *);
 152 static int      smbfs_unmount(vfs_t *, int, cred_t *);


 185          * Easier to follow this way.
 186          */
 187         if ((error = smbfs_subrinit()) != 0) {
 188                 cmn_err(CE_WARN, "_init: smbfs_subrinit failed");
 189                 return (error);
 190         }
 191 
 192         if ((error = smbfs_vfsinit()) != 0) {
 193                 cmn_err(CE_WARN, "_init: smbfs_vfsinit failed");
 194                 smbfs_subrfini();
 195                 return (error);
 196         }
 197 
 198         if ((error = smbfs_clntinit()) != 0) {
 199                 cmn_err(CE_WARN, "_init: smbfs_clntinit failed");
 200                 smbfs_vfsfini();
 201                 smbfs_subrfini();
 202                 return (error);
 203         }
 204 

 205         error = mod_install((struct modlinkage *)&modlinkage);




 206         return (error);
 207 }
 208 
 209 /*
 210  * Free kernel module resources that were allocated in _init
 211  * and remove the linkage information into the kernel
 212  */
 213 int
 214 _fini(void)
 215 {
 216         int     error;
 217 
 218         /*
 219          * If a forcedly unmounted instance is still hanging around,
 220          * we cannot allow the module to be unloaded because that would
 221          * cause panics once the VFS framework decides it's time to call
 222          * into VFS_FREEVFS().
 223          */
 224         if (smbfs_mountcount)
 225                 return (EBUSY);
 226 

 227         error = mod_remove(&modlinkage);



 228         if (error)
 229                 return (error);
 230 
 231         /*
 232          * Free the allocated smbnodes, etc.
 233          */
 234         smbfs_clntfini();
 235 
 236         /* NFS calls these two in _clntfini */
 237         smbfs_vfsfini();
 238         smbfs_subrfini();
 239 
 240         /*
 241          * Free the ops vectors
 242          */
 243         smbfsfini();
 244         return (0);
 245 }
 246 
 247 /*
 248  * Return information about the module
 249  */

 250 int
 251 _info(struct modinfo *modinfop)
 252 {
 253         return (mod_info((struct modlinkage *)&modlinkage, modinfop));
 254 }

 255 
 256 /*
 257  * Initialize the vfs structure
 258  */
 259 
 260 int smbfsfstyp;
 261 vfsops_t *smbfs_vfsops = NULL;
 262 
 263 static const fs_operation_def_t smbfs_vfsops_template[] = {
 264         { VFSNAME_MOUNT, { .vfs_mount = smbfs_mount } },
 265         { VFSNAME_UNMOUNT, { .vfs_unmount = smbfs_unmount } },
 266         { VFSNAME_ROOT, { .vfs_root = smbfs_root } },
 267         { VFSNAME_STATVFS, { .vfs_statvfs = smbfs_statvfs } },
 268         { VFSNAME_SYNC, { .vfs_sync = smbfs_sync } },
 269         { VFSNAME_VGET, { .error = fs_nosys } },
 270         { VFSNAME_MOUNTROOT, { .error = fs_nosys } },
 271         { VFSNAME_FREEVFS, { .vfs_freevfs = smbfs_freevfs } },
 272         { NULL, NULL }
 273 };
 274 




 275 int
 276 smbfsinit(int fstyp, char *name)
 277 {
 278         int             error;
 279 
 280         error = vfs_setfsops(fstyp, smbfs_vfsops_template, &smbfs_vfsops);
 281         if (error != 0) {
 282                 zcmn_err(GLOBAL_ZONEID, CE_WARN,
 283                     "smbfsinit: bad vfs ops template");
 284                 return (error);
 285         }
 286 
 287         error = vn_make_ops(name, smbfs_vnodeops_template, &smbfs_vnodeops);
 288         if (error != 0) {
 289                 (void) vfs_freevfsops_by_type(fstyp);
 290                 zcmn_err(GLOBAL_ZONEID, CE_WARN,
 291                     "smbfsinit: bad vnode ops template");
 292                 return (error);
 293         }
 294 
 295         smbfsfstyp = fstyp;
 296 
 297         return (0);
 298 }
 299 
 300 void
 301 smbfsfini()
 302 {
 303         if (smbfs_vfsops) {
 304                 (void) vfs_freevfsops_by_type(smbfsfstyp);
 305                 smbfs_vfsops = NULL;
 306         }
 307         if (smbfs_vnodeops) {
 308                 vn_freevnodeops(smbfs_vnodeops);
 309                 smbfs_vnodeops = NULL;
 310         }
 311 }
 312 
 313 void
 314 smbfs_free_smi(smbmntinfo_t *smi)
 315 {
 316         if (smi == NULL)
 317                 return;
 318 

 319         if (smi->smi_zone_ref.zref_zone != NULL)
 320                 zone_rele_ref(&smi->smi_zone_ref, ZONE_REF_SMBFS);

 321 
 322         if (smi->smi_share != NULL)
 323                 smb_share_rele(smi->smi_share);
 324 
 325         avl_destroy(&smi->smi_hash_avl);
 326         rw_destroy(&smi->smi_hash_lk);
 327         cv_destroy(&smi->smi_statvfs_cv);
 328         mutex_destroy(&smi->smi_lock);
 329 
 330         kmem_free(smi, sizeof (smbmntinfo_t));
 331 }
 332 
 333 /*
 334  * smbfs mount vfsop
 335  * Set up mount info record and attach it to vfs struct.
 336  */
 337 static int
 338 smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
 339 {
 340         char            *data = uap->dataptr;
 341         int             error;
 342         smbnode_t       *rtnp = NULL;   /* root of this fs */
 343         smbmntinfo_t    *smi = NULL;
 344         dev_t           smbfs_dev;
 345         int             version;
 346         int             devfd;
 347         zone_t          *zone = curproc->p_zone;

 348         zone_t          *mntzone = NULL;



 349         smb_share_t     *ssp = NULL;
 350         smb_cred_t      scred;
 351         int             flags, sec;
 352 
 353         STRUCT_DECL(smbfs_args, args);          /* smbfs mount arguments */
 354 

 355         if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0)
 356                 return (error);

 357 
 358         if (mvp->v_type != VDIR)
 359                 return (ENOTDIR);
 360 
 361         /*
 362          * get arguments
 363          *
 364          * uap->datalen might be different from sizeof (args)
 365          * in a compatible situation.
 366          */

 367         STRUCT_INIT(args, get_udatamodel());
 368         bzero(STRUCT_BUF(args), SIZEOF_STRUCT(smbfs_args, DATAMODEL_NATIVE));
 369         if (copyin(data, STRUCT_BUF(args), MIN(uap->datalen,
 370             SIZEOF_STRUCT(smbfs_args, DATAMODEL_NATIVE))))
 371                 return (EFAULT);





 372 
 373         /*
 374          * Check mount program version
 375          */
 376         version = STRUCT_FGET(args, version);
 377         if (version != SMBFS_VERSION) {
 378                 cmn_err(CE_WARN, "mount version mismatch:"
 379                     " kernel=%d, mount=%d\n",
 380                     SMBFS_VERSION, version);
 381                 return (EINVAL);
 382         }
 383 
 384         /*
 385          * Deal with re-mount requests.
 386          */
 387         if (uap->flags & MS_REMOUNT) {
 388                 cmn_err(CE_WARN, "MS_REMOUNT not implemented");
 389                 return (ENOTSUP);
 390         }
 391 


 402 
 403         /*
 404          * Get the "share" from the netsmb driver (ssp).
 405          * It is returned with a "ref" (hold) for us.
 406          * Release this hold: at errout below, or in
 407          * smbfs_freevfs().
 408          */
 409         devfd = STRUCT_FGET(args, devfd);
 410         error = smb_dev2share(devfd, &ssp);
 411         if (error) {
 412                 cmn_err(CE_WARN, "invalid device handle %d (%d)\n",
 413                     devfd, error);
 414                 return (error);
 415         }
 416 
 417         /*
 418          * Use "goto errout" from here on.
 419          * See: ssp, smi, rtnp, mntzone
 420          */
 421 

 422         /*
 423          * Determine the zone we're being mounted into.
 424          */
 425         zone_hold(mntzone = zone);              /* start with this assumption */
 426         if (getzoneid() == GLOBAL_ZONEID) {
 427                 zone_rele(mntzone);
 428                 mntzone = zone_find_by_path(refstr_value(vfsp->vfs_mntpt));
 429                 ASSERT(mntzone != NULL);
 430                 if (mntzone != zone) {
 431                         error = EBUSY;
 432                         goto errout;
 433                 }
 434         }
 435 
 436         /*
 437          * Stop the mount from going any further if the zone is going away.
 438          */
 439         if (zone_status_get(mntzone) >= ZONE_IS_SHUTTING_DOWN) {
 440                 error = EBUSY;
 441                 goto errout;


 445          * On a Trusted Extensions client, we may have to force read-only
 446          * for read-down mounts.
 447          */
 448         if (is_system_labeled()) {
 449                 void *addr;
 450                 int ipvers = 0;
 451                 struct smb_vc *vcp;
 452 
 453                 vcp = SSTOVC(ssp);
 454                 addr = smb_vc_getipaddr(vcp, &ipvers);
 455                 error = smbfs_mount_label_policy(vfsp, addr, ipvers, cr);
 456 
 457                 if (error > 0)
 458                         goto errout;
 459 
 460                 if (error == -1) {
 461                         /* change mount to read-only to prevent write-down */
 462                         vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0);
 463                 }
 464         }

 465 
 466         /* Prevent unload. */
 467         atomic_inc_32(&smbfs_mountcount);
 468 
 469         /*
 470          * Create a mount record and link it to the vfs struct.
 471          * No more possiblities for errors from here on.
 472          * Tear-down of this stuff is in smbfs_free_smi()
 473          *
 474          * Compare with NFS: nfsrootvp()
 475          */
 476         smi = kmem_zalloc(sizeof (*smi), KM_SLEEP);
 477 
 478         mutex_init(&smi->smi_lock, NULL, MUTEX_DEFAULT, NULL);
 479         cv_init(&smi->smi_statvfs_cv, NULL, CV_DEFAULT, NULL);
 480 
 481         rw_init(&smi->smi_hash_lk, NULL, RW_DEFAULT, NULL);
 482         smbfs_init_hash_avl(&smi->smi_hash_avl);
 483 
 484         smi->smi_share = ssp;
 485         ssp = NULL;
 486 

 487         /*
 488          * Convert the anonymous zone hold acquired via zone_hold() above
 489          * into a zone reference.
 490          */
 491         zone_init_ref(&smi->smi_zone_ref);
 492         zone_hold_ref(mntzone, &smi->smi_zone_ref, ZONE_REF_SMBFS);
 493         zone_rele(mntzone);
 494         mntzone = NULL;



 495 
 496         /*
 497          * Initialize option defaults
 498          */
 499         smi->smi_flags       = SMI_LLOCK;
 500         smi->smi_acregmin = SEC2HR(SMBFS_ACREGMIN);
 501         smi->smi_acregmax = SEC2HR(SMBFS_ACREGMAX);
 502         smi->smi_acdirmin = SEC2HR(SMBFS_ACDIRMIN);
 503         smi->smi_acdirmax = SEC2HR(SMBFS_ACDIRMAX);





 504 
 505         /*
 506          * All "generic" mount options have already been
 507          * handled in vfs.c:domount() - see mntopts stuff.
 508          * Query generic options using vfs_optionisset().

 509          */





 510         if (vfs_optionisset(vfsp, MNTOPT_INTR, NULL))
 511                 smi->smi_flags |= SMI_INT;
 512         if (vfs_optionisset(vfsp, MNTOPT_ACL, NULL))
 513                 smi->smi_flags |= SMI_ACL;
 514 
 515         /*
 516          * Get the mount options that come in as smbfs_args,
 517          * starting with args.flags (SMBFS_MF_xxx)
 518          */
 519         flags = STRUCT_FGET(args, flags);
 520         smi->smi_uid         = STRUCT_FGET(args, uid);
 521         smi->smi_gid         = STRUCT_FGET(args, gid);
 522         smi->smi_fmode       = STRUCT_FGET(args, file_mode) & 0777;
 523         smi->smi_dmode       = STRUCT_FGET(args, dir_mode) & 0777;










 524 
 525         /*












 526          * Hande the SMBFS_MF_xxx flags.
 527          */
 528         if (flags & SMBFS_MF_NOAC)
 529                 smi->smi_flags |= SMI_NOAC;
 530         if (flags & SMBFS_MF_ACREGMIN) {
 531                 sec = STRUCT_FGET(args, acregmin);
 532                 if (sec < 0 || sec > SMBFS_ACMINMAX)
 533                         sec = SMBFS_ACMINMAX;
 534                 smi->smi_acregmin = SEC2HR(sec);
 535         }
 536         if (flags & SMBFS_MF_ACREGMAX) {
 537                 sec = STRUCT_FGET(args, acregmax);
 538                 if (sec < 0 || sec > SMBFS_ACMAXMAX)
 539                         sec = SMBFS_ACMAXMAX;
 540                 smi->smi_acregmax = SEC2HR(sec);
 541         }
 542         if (flags & SMBFS_MF_ACDIRMIN) {
 543                 sec = STRUCT_FGET(args, acdirmin);
 544                 if (sec < 0 || sec > SMBFS_ACMINMAX)
 545                         sec = SMBFS_ACMINMAX;


 574 
 575         /*
 576          * Ditto ACLs (disable if not supported on this share)
 577          */
 578         if ((smi->smi_fsattr & FILE_PERSISTENT_ACLS) == 0) {
 579                 vfs_setmntopt(vfsp, MNTOPT_NOACL, NULL, 0);
 580                 smi->smi_flags &= ~SMI_ACL;
 581         }
 582 
 583         /*
 584          * Assign a unique device id to the mount
 585          */
 586         mutex_enter(&smbfs_minor_lock);
 587         do {
 588                 smbfs_minor = (smbfs_minor + 1) & MAXMIN32;
 589                 smbfs_dev = makedevice(smbfs_major, smbfs_minor);
 590         } while (vfs_devismounted(smbfs_dev));
 591         mutex_exit(&smbfs_minor_lock);
 592 
 593         vfsp->vfs_dev        = smbfs_dev;
 594         vfs_make_fsid(&vfsp->vfs_fsid, smbfs_dev, smbfsfstyp);
 595         vfsp->vfs_data       = (caddr_t)smi;
 596         vfsp->vfs_fstype = smbfsfstyp;
 597         vfsp->vfs_bsize = MAXBSIZE;
 598         vfsp->vfs_bcount = 0;
 599 
 600         smi->smi_vfsp        = vfsp;
 601         smbfs_zonelist_add(smi);        /* undo in smbfs_freevfs */
 602 
 603         /* PSARC 2007/227 VFS Feature Registration */
 604         vfs_set_feature(vfsp, VFSFT_XVATTR);
 605         vfs_set_feature(vfsp, VFSFT_SYSATTR_VIEWS);
 606 
 607         /*
 608          * Create the root vnode, which we need in unmount
 609          * for the call to smbfs_check_table(), etc.
 610          * Release this hold in smbfs_unmount.
 611          */
 612         rtnp = smbfs_node_findcreate(smi, "\\", 1, NULL, 0, 0,
 613             &smbfs_fattr0);
 614         ASSERT(rtnp != NULL);
 615         rtnp->r_vnode->v_type = VDIR;
 616         rtnp->r_vnode->v_flag |= VROOT;
 617         smi->smi_root = rtnp;
 618 
 619         /*








 620          * NFS does other stuff here too:
 621          *   async worker threads
 622          *   init kstats
 623          *
 624          * End of code from NFS nfsrootvp()
 625          */
 626         return (0);
 627 

 628 errout:
 629         vfsp->vfs_data = NULL;
 630         if (smi != NULL)
 631                 smbfs_free_smi(smi);
 632 
 633         if (mntzone != NULL)
 634                 zone_rele(mntzone);
 635 
 636         if (ssp != NULL)
 637                 smb_share_rele(ssp);
 638 
 639         return (error);

 640 }
 641 
 642 /*
 643  * vfs operations
 644  */
 645 static int
 646 smbfs_unmount(vfs_t *vfsp, int flag, cred_t *cr)
 647 {
 648         smbmntinfo_t    *smi;
 649         smbnode_t       *rtnp;
 650 
 651         smi = VFTOSMI(vfsp);
 652 

 653         if (secpolicy_fs_unmount(cr, vfsp) != 0)
 654                 return (EPERM);

 655 
 656         if ((flag & MS_FORCE) == 0) {
 657                 smbfs_rflush(vfsp, cr);
 658 
 659                 /*
 660                  * If there are any active vnodes on this file system,
 661                  * (other than the root vnode) then the file system is
 662                  * busy and can't be umounted.
 663                  */
 664                 if (smbfs_check_table(vfsp, smi->smi_root))
 665                         return (EBUSY);
 666 
 667                 /*
 668                  * We normally hold a ref to the root vnode, so
 669                  * check for references beyond the one we expect:
 670                  *   smbmntinfo_t -> smi_root
 671                  * Note that NFS does not hold the root vnode.
 672                  */
 673                 if (smi->smi_root &&
 674                     smi->smi_root->r_vnode->v_count > 1)
 675                         return (EBUSY);
 676         }
 677 
 678         /*
 679          * common code for both forced and non-forced
 680          *
 681          * Setting VFS_UNMOUNTED prevents new operations.
 682          * Operations already underway may continue,
 683          * but not for long.
 684          */
 685         vfsp->vfs_flag |= VFS_UNMOUNTED;
 686 
 687         /*
 688          * Shutdown any outstanding I/O requests on this share,
 689          * and force a tree disconnect.  The share object will
 690          * continue to hang around until smb_share_rele().
 691          * This should also cause most active nodes to be
 692          * released as their operations fail with EIO.
 693          */
 694         smb_share_kill(smi->smi_share);
 695 
 696         /*
 697          * If we hold the root VP (and we normally do)
 698          * then it's safe to release it now.
 699          */
 700         if (smi->smi_root) {
 701                 rtnp = smi->smi_root;
 702                 smi->smi_root = NULL;
 703                 VN_RELE(rtnp->r_vnode);      /* release root vnode */
 704         }
 705 
 706         /*
 707          * Remove all nodes from the node hash tables.
 708          * This (indirectly) calls: smbfs_addfree, smbinactive,
 709          * which will try to flush dirty pages, etc. so
 710          * don't destroy the underlying share just yet.
 711          *
 712          * Also, with a forced unmount, some nodes may
 713          * remain active, and those will get cleaned up
 714          * after their last vn_rele.
 715          */
 716         smbfs_destroy_table(vfsp);
 717 
 718         /*















 719          * Delete our kstats...
 720          *
 721          * Doing it here, rather than waiting until
 722          * smbfs_freevfs so these are not visible
 723          * after the unmount.
 724          */
 725         if (smi->smi_io_kstats) {
 726                 kstat_delete(smi->smi_io_kstats);
 727                 smi->smi_io_kstats = NULL;
 728         }
 729         if (smi->smi_ro_kstats) {
 730                 kstat_delete(smi->smi_ro_kstats);
 731                 smi->smi_ro_kstats = NULL;
 732         }
 733 
 734         /*
 735          * The rest happens in smbfs_freevfs()
 736          */
 737         return (0);
 738 }


 848                     (SM_MAX_STATFSTIME * (hrtime_t)NANOSEC);
 849                 smi->smi_statvfsbuf = stvfs; /* struct assign! */
 850         }
 851 
 852         mutex_enter(&smi->smi_lock);
 853         if (smi->smi_status & SM_STATUS_STATFS_WANT)
 854                 cv_broadcast(&smi->smi_statvfs_cv);
 855         smi->smi_status &= ~(SM_STATUS_STATFS_BUSY | SM_STATUS_STATFS_WANT);
 856 
 857         /*
 858          * Copy the statvfs data to caller's buf.
 859          * Note: struct assignment
 860          */
 861 cache_hit:
 862         if (error == 0)
 863                 *sbp = smi->smi_statvfsbuf;
 864         mutex_exit(&smi->smi_lock);
 865         return (error);
 866 }
 867 
 868 static kmutex_t smbfs_syncbusy;
 869 
 870 /*
 871  * Flush dirty smbfs files for file system vfsp.
 872  * If vfsp == NULL, all smbfs files are flushed.
 873  */
 874 /*ARGSUSED*/
 875 static int
 876 smbfs_sync(vfs_t *vfsp, short flag, cred_t *cr)
 877 {

 878         /*
 879          * Cross-zone calls are OK here, since this translates to a
 880          * VOP_PUTPAGE(B_ASYNC), which gets picked up by the right zone.


 881          */
 882         if (!(flag & SYNC_ATTR) && mutex_tryenter(&smbfs_syncbusy) != 0) {
 883                 smbfs_rflush(vfsp, cr);
 884                 mutex_exit(&smbfs_syncbusy);






 885         }
 886 


 887         return (0);
 888 }
 889 
 890 /*
 891  * Initialization routine for VFS routines.  Should only be called once
 892  */
 893 int
 894 smbfs_vfsinit(void)
 895 {
 896         mutex_init(&smbfs_syncbusy, NULL, MUTEX_DEFAULT, NULL);
 897         return (0);
 898 }
 899 
 900 /*
 901  * Shutdown routine for VFS routines.  Should only be called once
 902  */
 903 void
 904 smbfs_vfsfini(void)
 905 {
 906         mutex_destroy(&smbfs_syncbusy);
 907 }
 908 
 909 void
 910 smbfs_freevfs(vfs_t *vfsp)
 911 {
 912         smbmntinfo_t    *smi;
 913 
 914         /* free up the resources */
 915         smi = VFTOSMI(vfsp);
 916 
 917         /*
 918          * By this time we should have already deleted the
 919          * smi kstats in the unmount code.  If they are still around
 920          * something is wrong
 921          */
 922         ASSERT(smi->smi_io_kstats == NULL);
 923 
 924         smbfs_zonelist_remove(smi);
 925 
 926         smbfs_free_smi(smi);
 927 
 928         /*
 929          * Allow _fini() to succeed now, if so desired.
 930          */
 931         atomic_dec_32(&smbfs_mountcount);
 932 }
 933 

 934 /*
 935  * smbfs_mount_label_policy:
 936  *      Determine whether the mount is allowed according to MAC check,
 937  *      by comparing (where appropriate) label of the remote server
 938  *      against the label of the zone being mounted into.
 939  *
 940  *      Returns:
 941  *               0 :    access allowed
 942  *              -1 :    read-only access allowed (i.e., read-down)
 943  *              >0 : error code, such as EACCES
 944  *
 945  * NB:
 946  * NFS supports Cipso labels by parsing the vfs_resource
 947  * to see what the Solaris server global zone has shared.
 948  * We can't support that for CIFS since resource names
 949  * contain share names, not paths.
 950  */
 951 static int
 952 smbfs_mount_label_policy(vfs_t *vfsp, void *ipaddr, int addr_type, cred_t *cr)
 953 {


1004                 else
1005                         retv = 0;               /* access OK */
1006         } else if (bldominates(mntlabel, server_sl)) {
1007                 retv = -1;                      /* read-only */
1008         } else {
1009                 retv = EACCES;
1010         }
1011 
1012         if (tsl != NULL)
1013                 label_rele(tsl);
1014 
1015 rel_tpc:
1016         /*LINTED*/
1017         TPC_RELE(tp);
1018 out:
1019         if (mntzone)
1020                 zone_rele(mntzone);
1021         label_rele(zlabel);
1022         return (retv);
1023 }



  19  *
  20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30  * SUCH DAMAGE.
  31  *
  32  * $Id: smbfs_vfsops.c,v 1.73.64.1 2005/05/27 02:35:28 lindak Exp $
  33  */
  34 
  35 /*
  36  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  37  * Copyright 2013, Joyent, Inc. All rights reserved.
  38  * Copyright (c) 2016 by Delphix. All rights reserved.
  39  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
  40  */
  41 
  42 #include <sys/systm.h>
  43 #include <sys/cred.h>
  44 #include <sys/time.h>
  45 #include <sys/vfs.h>
  46 #include <sys/vnode.h>
  47 #include <fs/fs_subr.h>
  48 #include <sys/sysmacros.h>
  49 #include <sys/kmem.h>
  50 #include <sys/mkdev.h>
  51 #include <sys/mount.h>
  52 #include <sys/statvfs.h>
  53 #include <sys/errno.h>
  54 #include <sys/debug.h>
  55 #include <sys/disp.h>
  56 #include <sys/cmn_err.h>
  57 #include <sys/modctl.h>
  58 #include <sys/policy.h>
  59 #include <sys/atomic.h>
  60 #include <sys/zone.h>
  61 #include <sys/vfs_opreg.h>
  62 #include <sys/mntent.h>
  63 #include <sys/priv.h>
  64 #include <sys/taskq.h>
  65 #include <sys/tsol/label.h>
  66 #include <sys/tsol/tndb.h>
  67 #include <inet/ip.h>
  68 
  69 #include <netsmb/smb_osdep.h>
  70 #include <netsmb/smb.h>
  71 #include <netsmb/smb_conn.h>
  72 #include <netsmb/smb_subr.h>
  73 #include <netsmb/smb_dev.h>
  74 
  75 #include <smbfs/smbfs.h>
  76 #include <smbfs/smbfs_node.h>
  77 #include <smbfs/smbfs_subr.h>
  78 
  79 #ifndef _KERNEL
  80 
  81 #include <libfksmbfs.h>
  82 
  83 #define STRUCT_DECL(s, a) struct s a
  84 #define STRUCT_FGET(handle, field) ((handle).field)
  85 #define _init(v)        fksmbfs_init(v)
  86 #define _fini(v)        fksmbfs_fini(v)
  87 
  88 #endif  /* !_KERNEL */
  89 
  90 /*
  91  * Should smbfs mount enable "-o acl" by default?  There are good
  92  * arguments for both.  The most common use case is individual users
  93  * accessing files on some SMB server, for which "noacl" is the more
  94  * convenient default.  A less common use case is data migration,
  95  * where the "acl" option might be a desirable default.  We'll make
  96  * the common use case the default.  This default can be changed via
  97  * /etc/system, and/or set per-mount via the "acl" mount option.
  98  */
  99 int smbfs_default_opt_acl = 0;
 100 
 101 /*
 102  * How many taskq threads per-mount should we use.
 103  * Just one is fine (until we do more async work).
 104  */
 105 int smbfs_tq_nthread = 1;
 106 
 107 /*
 108  * Local functions definitions.
 109  */
 110 int             smbfsinit(int fstyp, char *name);
 111 void            smbfsfini();
 112 
 113 #ifdef  _KERNEL
 114 static int      smbfs_mount_label_policy(vfs_t *, void *, int, cred_t *);
 115 #endif  /* _KERNEL */
 116 
 117 /*
 118  * SMBFS Mount options table for MS_OPTIONSTR
 119  * Note: These are not all the options.
 120  * Some options come in via MS_DATA.
 121  * Others are generic (see vfs.c)
 122  */
 123 static char *intr_cancel[] = { MNTOPT_NOINTR, NULL };
 124 static char *nointr_cancel[] = { MNTOPT_INTR, NULL };
 125 static char *acl_cancel[] = { MNTOPT_NOACL, NULL };
 126 static char *noacl_cancel[] = { MNTOPT_ACL, NULL };
 127 static char *xattr_cancel[] = { MNTOPT_NOXATTR, NULL };
 128 static char *noxattr_cancel[] = { MNTOPT_XATTR, NULL };
 129 
 130 static mntopt_t mntopts[] = {
 131 /*
 132  *      option name             cancel option   default arg     flags
 133  *              ufs arg flag
 134  */
 135         { MNTOPT_INTR,          intr_cancel,    NULL,   MO_DEFAULT, 0 },
 136         { MNTOPT_NOINTR,        nointr_cancel,  NULL,   0,      0 },
 137         { MNTOPT_ACL,           acl_cancel,     NULL,   0,      0 },
 138         { MNTOPT_NOACL,         noacl_cancel,   NULL,   0,      0 },
 139         { MNTOPT_XATTR,         xattr_cancel,   NULL,   MO_DEFAULT, 0 },
 140         { MNTOPT_NOXATTR,       noxattr_cancel, NULL,   0,      0 },
 141 #ifndef _KERNEL
 142         /* See vfs_optionisset MNTOPT_NOAC below. */
 143         { MNTOPT_NOAC,          NULL,           NULL,   0,      0 },
 144 #endif  /* !_KERNEL */
 145 };
 146 
 147 static mntopts_t smbfs_mntopts = {
 148         sizeof (mntopts) / sizeof (mntopt_t),
 149         mntopts
 150 };
 151 
 152 static const char fs_type_name[FSTYPSZ] = "smbfs";
 153 
 154 static vfsdef_t vfw = {
 155         VFSDEF_VERSION,
 156         (char *)fs_type_name,
 157         smbfsinit,              /* init routine */
 158         VSW_HASPROTO|VSW_NOTZONESAFE,   /* flags */
 159         &smbfs_mntopts                      /* mount options table prototype */
 160 };
 161 
 162 #ifdef  _KERNEL
 163 static struct modlfs modlfs = {
 164         &mod_fsops,
 165         "SMBFS filesystem",
 166         &vfw
 167 };
 168 
 169 static struct modlinkage modlinkage = {
 170         MODREV_1, (void *)&modlfs, NULL
 171 };
 172 #endif  /* _KERNEL */
 173 
 174 /*
 175  * Mutex to protect the following variables:
 176  *        smbfs_major
 177  *        smbfs_minor
 178  */
 179 extern  kmutex_t        smbfs_minor_lock;
 180 extern  int             smbfs_major;
 181 extern  int             smbfs_minor;
 182 
 183 /*
 184  * Prevent unloads while we have mounts
 185  */
 186 uint32_t        smbfs_mountcount;
 187 
 188 /*
 189  * smbfs vfs operations.
 190  */
 191 static int      smbfs_mount(vfs_t *, vnode_t *, struct mounta *, cred_t *);
 192 static int      smbfs_unmount(vfs_t *, int, cred_t *);


 225          * Easier to follow this way.
 226          */
 227         if ((error = smbfs_subrinit()) != 0) {
 228                 cmn_err(CE_WARN, "_init: smbfs_subrinit failed");
 229                 return (error);
 230         }
 231 
 232         if ((error = smbfs_vfsinit()) != 0) {
 233                 cmn_err(CE_WARN, "_init: smbfs_vfsinit failed");
 234                 smbfs_subrfini();
 235                 return (error);
 236         }
 237 
 238         if ((error = smbfs_clntinit()) != 0) {
 239                 cmn_err(CE_WARN, "_init: smbfs_clntinit failed");
 240                 smbfs_vfsfini();
 241                 smbfs_subrfini();
 242                 return (error);
 243         }
 244 
 245 #ifdef  _KERNEL
 246         error = mod_install((struct modlinkage *)&modlinkage);
 247 #else   /* _KERNEL */
 248         error = fake_installfs(&vfw);
 249 #endif  /* _KERNEL */
 250 
 251         return (error);
 252 }
 253 
 254 /*
 255  * Free kernel module resources that were allocated in _init
 256  * and remove the linkage information into the kernel
 257  */
 258 int
 259 _fini(void)
 260 {
 261         int     error;
 262 
 263         /*
 264          * If a forcedly unmounted instance is still hanging around,
 265          * we cannot allow the module to be unloaded because that would
 266          * cause panics once the VFS framework decides it's time to call
 267          * into VFS_FREEVFS().
 268          */
 269         if (smbfs_mountcount)
 270                 return (EBUSY);
 271 
 272 #ifdef  _KERNEL
 273         error = mod_remove(&modlinkage);
 274 #else   /* _KERNEL */
 275         error = fake_removefs(&vfw);
 276 #endif  /* _KERNEL */
 277         if (error)
 278                 return (error);
 279 
 280         /*
 281          * Free the allocated smbnodes, etc.
 282          */
 283         smbfs_clntfini();
 284 
 285         /* NFS calls these two in _clntfini */
 286         smbfs_vfsfini();
 287         smbfs_subrfini();
 288 
 289         /*
 290          * Free the ops vectors
 291          */
 292         smbfsfini();
 293         return (0);
 294 }
 295 
 296 /*
 297  * Return information about the module
 298  */
 299 #ifdef  _KERNEL
 300 int
 301 _info(struct modinfo *modinfop)
 302 {
 303         return (mod_info((struct modlinkage *)&modlinkage, modinfop));
 304 }
 305 #endif  /* _KERNEL */
 306 
 307 /*
 308  * Initialize the vfs structure
 309  */
 310 
 311 int smbfs_fstyp;
 312 vfsops_t *smbfs_vfsops = NULL;
 313 
 314 static const fs_operation_def_t smbfs_vfsops_template[] = {
 315         { VFSNAME_MOUNT, { .vfs_mount = smbfs_mount } },
 316         { VFSNAME_UNMOUNT, { .vfs_unmount = smbfs_unmount } },
 317         { VFSNAME_ROOT, { .vfs_root = smbfs_root } },
 318         { VFSNAME_STATVFS, { .vfs_statvfs = smbfs_statvfs } },
 319         { VFSNAME_SYNC, { .vfs_sync = smbfs_sync } },
 320         { VFSNAME_VGET, { .error = fs_nosys } },
 321         { VFSNAME_MOUNTROOT, { .error = fs_nosys } },
 322         { VFSNAME_FREEVFS, { .vfs_freevfs = smbfs_freevfs } },
 323         { NULL, NULL }
 324 };
 325 
 326 /*
 327  * This is the VFS switch initialization routine, normally called
 328  * via vfssw[x].vsw_init by vfsinit() or mod_install
 329  */
 330 int
 331 smbfsinit(int fstyp, char *name)
 332 {
 333         int             error;
 334 
 335         error = vfs_setfsops(fstyp, smbfs_vfsops_template, &smbfs_vfsops);
 336         if (error != 0) {
 337                 cmn_err(CE_WARN,
 338                     "smbfsinit: bad vfs ops template");
 339                 return (error);
 340         }
 341 
 342         error = vn_make_ops(name, smbfs_vnodeops_template, &smbfs_vnodeops);
 343         if (error != 0) {
 344                 (void) vfs_freevfsops_by_type(fstyp);
 345                 cmn_err(CE_WARN,
 346                     "smbfsinit: bad vnode ops template");
 347                 return (error);
 348         }
 349 
 350         smbfs_fstyp = fstyp;
 351 
 352         return (0);
 353 }
 354 
 355 void
 356 smbfsfini()
 357 {
 358         if (smbfs_vfsops) {
 359                 (void) vfs_freevfsops_by_type(smbfs_fstyp);
 360                 smbfs_vfsops = NULL;
 361         }
 362         if (smbfs_vnodeops) {
 363                 vn_freevnodeops(smbfs_vnodeops);
 364                 smbfs_vnodeops = NULL;
 365         }
 366 }
 367 
 368 void
 369 smbfs_free_smi(smbmntinfo_t *smi)
 370 {
 371         if (smi == NULL)
 372                 return;
 373 
 374 #ifdef  _KERNEL
 375         if (smi->smi_zone_ref.zref_zone != NULL)
 376                 zone_rele_ref(&smi->smi_zone_ref, ZONE_REF_SMBFS);
 377 #endif  /* _KERNEL */
 378 
 379         if (smi->smi_share != NULL)
 380                 smb_share_rele(smi->smi_share);
 381 
 382         avl_destroy(&smi->smi_hash_avl);
 383         rw_destroy(&smi->smi_hash_lk);
 384         cv_destroy(&smi->smi_statvfs_cv);
 385         mutex_destroy(&smi->smi_lock);
 386 
 387         kmem_free(smi, sizeof (smbmntinfo_t));
 388 }
 389 
 390 /*
 391  * smbfs mount vfsop
 392  * Set up mount info record and attach it to vfs struct.
 393  */
 394 static int
 395 smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
 396 {
 397         char            *data = uap->dataptr;
 398         int             error;
 399         smbnode_t       *rtnp = NULL;   /* root of this fs */
 400         smbmntinfo_t    *smi = NULL;
 401         dev_t           smbfs_dev;
 402         int             version;
 403         int             devfd;
 404         zone_t          *zone = curzone;
 405 #ifdef  _KERNEL
 406         zone_t          *mntzone = NULL;
 407 #else   /* _KERNEL */
 408         short           minclsyspri = MINCLSYSPRI;
 409 #endif  /* _KERNEL */
 410         smb_share_t     *ssp = NULL;
 411         smb_cred_t      scred;
 412         int             flags, sec;

 413         STRUCT_DECL(smbfs_args, args);          /* smbfs mount arguments */
 414 
 415 #ifdef  _KERNEL
 416         if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0)
 417                 return (error);
 418 #endif  /* _KERNEL */
 419 
 420         if (mvp->v_type != VDIR)
 421                 return (ENOTDIR);
 422 
 423         /*
 424          * get arguments
 425          *
 426          * uap->datalen might be different from sizeof (args)
 427          * in a compatible situation.
 428          */
 429 #ifdef  _KERNEL
 430         STRUCT_INIT(args, get_udatamodel());
 431         bzero(STRUCT_BUF(args), SIZEOF_STRUCT(smbfs_args, DATAMODEL_NATIVE));
 432         if (copyin(data, STRUCT_BUF(args), MIN(uap->datalen,
 433             SIZEOF_STRUCT(smbfs_args, DATAMODEL_NATIVE))))
 434                 return (EFAULT);
 435 #else   /* _KERNEL */
 436         bzero(&args, sizeof (args));
 437         if (copyin(data, &args, MIN(uap->datalen, sizeof (args))))
 438                 return (EFAULT);
 439 #endif  /* _KERNEL */
 440 
 441         /*
 442          * Check mount program version
 443          */
 444         version = STRUCT_FGET(args, version);
 445         if (version != SMBFS_VERSION) {
 446                 cmn_err(CE_WARN, "mount version mismatch:"
 447                     " kernel=%d, mount=%d\n",
 448                     SMBFS_VERSION, version);
 449                 return (EINVAL);
 450         }
 451 
 452         /*
 453          * Deal with re-mount requests.
 454          */
 455         if (uap->flags & MS_REMOUNT) {
 456                 cmn_err(CE_WARN, "MS_REMOUNT not implemented");
 457                 return (ENOTSUP);
 458         }
 459 


 470 
 471         /*
 472          * Get the "share" from the netsmb driver (ssp).
 473          * It is returned with a "ref" (hold) for us.
 474          * Release this hold: at errout below, or in
 475          * smbfs_freevfs().
 476          */
 477         devfd = STRUCT_FGET(args, devfd);
 478         error = smb_dev2share(devfd, &ssp);
 479         if (error) {
 480                 cmn_err(CE_WARN, "invalid device handle %d (%d)\n",
 481                     devfd, error);
 482                 return (error);
 483         }
 484 
 485         /*
 486          * Use "goto errout" from here on.
 487          * See: ssp, smi, rtnp, mntzone
 488          */
 489 
 490 #ifdef  _KERNEL
 491         /*
 492          * Determine the zone we're being mounted into.
 493          */
 494         zone_hold(mntzone = zone);              /* start with this assumption */
 495         if (getzoneid() == GLOBAL_ZONEID) {
 496                 zone_rele(mntzone);
 497                 mntzone = zone_find_by_path(refstr_value(vfsp->vfs_mntpt));
 498                 ASSERT(mntzone != NULL);
 499                 if (mntzone != zone) {
 500                         error = EBUSY;
 501                         goto errout;
 502                 }
 503         }
 504 
 505         /*
 506          * Stop the mount from going any further if the zone is going away.
 507          */
 508         if (zone_status_get(mntzone) >= ZONE_IS_SHUTTING_DOWN) {
 509                 error = EBUSY;
 510                 goto errout;


 514          * On a Trusted Extensions client, we may have to force read-only
 515          * for read-down mounts.
 516          */
 517         if (is_system_labeled()) {
 518                 void *addr;
 519                 int ipvers = 0;
 520                 struct smb_vc *vcp;
 521 
 522                 vcp = SSTOVC(ssp);
 523                 addr = smb_vc_getipaddr(vcp, &ipvers);
 524                 error = smbfs_mount_label_policy(vfsp, addr, ipvers, cr);
 525 
 526                 if (error > 0)
 527                         goto errout;
 528 
 529                 if (error == -1) {
 530                         /* change mount to read-only to prevent write-down */
 531                         vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0);
 532                 }
 533         }
 534 #endif  /* _KERNEL */
 535 
 536         /* Prevent unload. */
 537         atomic_inc_32(&smbfs_mountcount);
 538 
 539         /*
 540          * Create a mount record and link it to the vfs struct.
 541          * No more possiblities for errors from here on.
 542          * Tear-down of this stuff is in smbfs_free_smi()
 543          *
 544          * Compare with NFS: nfsrootvp()
 545          */
 546         smi = kmem_zalloc(sizeof (*smi), KM_SLEEP);
 547 
 548         mutex_init(&smi->smi_lock, NULL, MUTEX_DEFAULT, NULL);
 549         cv_init(&smi->smi_statvfs_cv, NULL, CV_DEFAULT, NULL);
 550 
 551         rw_init(&smi->smi_hash_lk, NULL, RW_DEFAULT, NULL);
 552         smbfs_init_hash_avl(&smi->smi_hash_avl);
 553 
 554         smi->smi_share = ssp;
 555         ssp = NULL;
 556 
 557 #ifdef  _KERNEL
 558         /*
 559          * Convert the anonymous zone hold acquired via zone_hold() above
 560          * into a zone reference.
 561          */
 562         zone_init_ref(&smi->smi_zone_ref);
 563         zone_hold_ref(mntzone, &smi->smi_zone_ref, ZONE_REF_SMBFS);
 564         zone_rele(mntzone);
 565         mntzone = NULL;
 566 #else   /* _KERNEL */
 567         smi->smi_zone_ref.zref_zone = curzone;
 568 #endif  /* _KERNEL */
 569 
 570         /*
 571          * Initialize option defaults
 572          */

 573         smi->smi_acregmin = SEC2HR(SMBFS_ACREGMIN);
 574         smi->smi_acregmax = SEC2HR(SMBFS_ACREGMAX);
 575         smi->smi_acdirmin = SEC2HR(SMBFS_ACDIRMIN);
 576         smi->smi_acdirmax = SEC2HR(SMBFS_ACDIRMAX);
 577         smi->smi_flags       = SMI_LLOCK;
 578 #ifndef _KERNEL
 579         /* Always direct IO with fakekernel */
 580         smi->smi_flags       |= SMI_DIRECTIO;
 581 #endif  /* _KERNEL */
 582 
 583         /*
 584          * All "generic" mount options have already been
 585          * handled in vfs.c:domount() - see mntopts stuff.
 586          * Query generic options using vfs_optionisset().
 587          * Give ACL an adjustable system-wide default.
 588          */
 589         if (smbfs_default_opt_acl ||
 590             vfs_optionisset(vfsp, MNTOPT_ACL, NULL))
 591                 smi->smi_flags |= SMI_ACL;
 592         if (vfs_optionisset(vfsp, MNTOPT_NOACL, NULL))
 593                 smi->smi_flags &= ~SMI_ACL;
 594         if (vfs_optionisset(vfsp, MNTOPT_INTR, NULL))
 595                 smi->smi_flags |= SMI_INT;


 596 
 597         /*
 598          * Get the mount options that come in as smbfs_args,
 599          * starting with args.flags (SMBFS_MF_xxx)
 600          */
 601         flags = STRUCT_FGET(args, flags);


 602         smi->smi_fmode       = STRUCT_FGET(args, file_mode) & 0777;
 603         smi->smi_dmode       = STRUCT_FGET(args, dir_mode) & 0777;
 604 #ifdef  _KERNEL
 605         smi->smi_uid = STRUCT_FGET(args, uid);
 606         smi->smi_gid = STRUCT_FGET(args, gid);
 607 #else   /* _KERNEL */
 608         /*
 609          * Need uid/gid to match our fake cred we'll fail in
 610          * smbfs_access_rwx later.
 611          */
 612         smi->smi_uid = crgetuid(cr);
 613         smi->smi_gid = crgetgid(cr);
 614 
 615         /*
 616          * Our user-level do_mount() passes the mount options sting
 617          * as-is, where the real mount program would convert some
 618          * of those options to bits set in smbfs_args.flags.
 619          * To avoid replicating all that conversion code, this
 620          * uses the generic vfs option support to handle those
 621          * option flag bits we need, i.e.: "noac"
 622          */
 623         if (vfs_optionisset(vfsp, MNTOPT_NOAC, NULL))
 624                 flags |= SMBFS_MF_NOAC;
 625 #endif  /* _KERNEL */
 626 
 627         /*
 628          * Hande the SMBFS_MF_xxx flags.
 629          */
 630         if (flags & SMBFS_MF_NOAC)
 631                 smi->smi_flags |= SMI_NOAC;
 632         if (flags & SMBFS_MF_ACREGMIN) {
 633                 sec = STRUCT_FGET(args, acregmin);
 634                 if (sec < 0 || sec > SMBFS_ACMINMAX)
 635                         sec = SMBFS_ACMINMAX;
 636                 smi->smi_acregmin = SEC2HR(sec);
 637         }
 638         if (flags & SMBFS_MF_ACREGMAX) {
 639                 sec = STRUCT_FGET(args, acregmax);
 640                 if (sec < 0 || sec > SMBFS_ACMAXMAX)
 641                         sec = SMBFS_ACMAXMAX;
 642                 smi->smi_acregmax = SEC2HR(sec);
 643         }
 644         if (flags & SMBFS_MF_ACDIRMIN) {
 645                 sec = STRUCT_FGET(args, acdirmin);
 646                 if (sec < 0 || sec > SMBFS_ACMINMAX)
 647                         sec = SMBFS_ACMINMAX;


 676 
 677         /*
 678          * Ditto ACLs (disable if not supported on this share)
 679          */
 680         if ((smi->smi_fsattr & FILE_PERSISTENT_ACLS) == 0) {
 681                 vfs_setmntopt(vfsp, MNTOPT_NOACL, NULL, 0);
 682                 smi->smi_flags &= ~SMI_ACL;
 683         }
 684 
 685         /*
 686          * Assign a unique device id to the mount
 687          */
 688         mutex_enter(&smbfs_minor_lock);
 689         do {
 690                 smbfs_minor = (smbfs_minor + 1) & MAXMIN32;
 691                 smbfs_dev = makedevice(smbfs_major, smbfs_minor);
 692         } while (vfs_devismounted(smbfs_dev));
 693         mutex_exit(&smbfs_minor_lock);
 694 
 695         vfsp->vfs_dev        = smbfs_dev;
 696         vfs_make_fsid(&vfsp->vfs_fsid, smbfs_dev, smbfs_fstyp);
 697         vfsp->vfs_data       = (caddr_t)smi;
 698         vfsp->vfs_fstype = smbfs_fstyp;
 699         vfsp->vfs_bsize = MAXBSIZE;
 700         vfsp->vfs_bcount = 0;
 701 
 702         smi->smi_vfsp        = vfsp;
 703         smbfs_zonelist_add(smi);        /* undo in smbfs_freevfs */
 704 
 705         /* PSARC 2007/227 VFS Feature Registration */
 706         vfs_set_feature(vfsp, VFSFT_XVATTR);
 707         vfs_set_feature(vfsp, VFSFT_SYSATTR_VIEWS);
 708 
 709         /*
 710          * Create the root vnode, which we need in unmount
 711          * for the call to smbfs_check_table(), etc.
 712          * Release this hold in smbfs_unmount.
 713          */
 714         rtnp = smbfs_node_findcreate(smi, "\\", 1, NULL, 0, 0,
 715             &smbfs_fattr0);
 716         ASSERT(rtnp != NULL);
 717         rtnp->r_vnode->v_type = VDIR;
 718         rtnp->r_vnode->v_flag |= VROOT;
 719         smi->smi_root = rtnp;
 720 
 721         /*
 722          * Create a taskq for async work (i.e. putpage)
 723          */
 724         smi->smi_taskq = taskq_create_proc("smbfs",
 725             smbfs_tq_nthread, minclsyspri,
 726             smbfs_tq_nthread, smbfs_tq_nthread * 2,
 727             zone->zone_zsched, TASKQ_PREPOPULATE);
 728 
 729         /*
 730          * NFS does other stuff here too:
 731          *   async worker threads
 732          *   init kstats
 733          *
 734          * End of code from NFS nfsrootvp()
 735          */
 736         return (0);
 737 
 738 #ifdef  _KERNEL
 739 errout:
 740         vfsp->vfs_data = NULL;
 741         if (smi != NULL)
 742                 smbfs_free_smi(smi);
 743 
 744         if (mntzone != NULL)
 745                 zone_rele(mntzone);
 746 
 747         if (ssp != NULL)
 748                 smb_share_rele(ssp);
 749 
 750         return (error);
 751 #endif  /* _KERNEL */
 752 }
 753 
 754 /*
 755  * vfs operations
 756  */
 757 static int
 758 smbfs_unmount(vfs_t *vfsp, int flag, cred_t *cr)
 759 {
 760         smbmntinfo_t    *smi;
 761         smbnode_t       *rtnp;
 762 
 763         smi = VFTOSMI(vfsp);
 764 
 765 #ifdef  _KERNEL
 766         if (secpolicy_fs_unmount(cr, vfsp) != 0)
 767                 return (EPERM);
 768 #endif  /* _KERNEL */
 769 
 770         if ((flag & MS_FORCE) == 0) {
 771                 smbfs_rflush(vfsp, cr);
 772 
 773                 /*
 774                  * If there are any active vnodes on this file system,
 775                  * (other than the root vnode) then the file system is
 776                  * busy and can't be umounted.
 777                  */
 778                 if (smbfs_check_table(vfsp, smi->smi_root))
 779                         return (EBUSY);
 780 
 781                 /*
 782                  * We normally hold a ref to the root vnode, so
 783                  * check for references beyond the one we expect:
 784                  *   smbmntinfo_t -> smi_root
 785                  * Note that NFS does not hold the root vnode.
 786                  */
 787                 if (smi->smi_root &&
 788                     smi->smi_root->r_vnode->v_count > 1)
 789                         return (EBUSY);
 790         }
 791 
 792         /*
 793          * common code for both forced and non-forced
 794          *
 795          * Setting VFS_UNMOUNTED prevents new operations.
 796          * Operations already underway may continue,
 797          * but not for long.
 798          */
 799         vfsp->vfs_flag |= VFS_UNMOUNTED;
 800 
 801         /*









 802          * If we hold the root VP (and we normally do)
 803          * then it's safe to release it now.
 804          */
 805         if (smi->smi_root) {
 806                 rtnp = smi->smi_root;
 807                 smi->smi_root = NULL;
 808                 VN_RELE(rtnp->r_vnode);      /* release root vnode */
 809         }
 810 
 811         /*
 812          * Remove all nodes from the node hash tables.
 813          * This (indirectly) calls: smbfs_addfree, smbinactive,
 814          * which will try to flush dirty pages, etc. so
 815          * don't destroy the underlying share just yet.
 816          *
 817          * Also, with a forced unmount, some nodes may
 818          * remain active, and those will get cleaned up
 819          * after their last vn_rele.
 820          */
 821         smbfs_destroy_table(vfsp);
 822 
 823         /*
 824          * Shutdown any outstanding I/O requests on this share,
 825          * and force a tree disconnect.  The share object will
 826          * continue to hang around until smb_share_rele().
 827          * This should also cause most active nodes to be
 828          * released as their operations fail with EIO.
 829          */
 830         smb_share_kill(smi->smi_share);
 831 
 832         /*
 833          * Any async taskq work should be giving up.
 834          * Wait for those to exit.
 835          */
 836         taskq_destroy(smi->smi_taskq);
 837 
 838         /*
 839          * Delete our kstats...
 840          *
 841          * Doing it here, rather than waiting until
 842          * smbfs_freevfs so these are not visible
 843          * after the unmount.
 844          */
 845         if (smi->smi_io_kstats) {
 846                 kstat_delete(smi->smi_io_kstats);
 847                 smi->smi_io_kstats = NULL;
 848         }
 849         if (smi->smi_ro_kstats) {
 850                 kstat_delete(smi->smi_ro_kstats);
 851                 smi->smi_ro_kstats = NULL;
 852         }
 853 
 854         /*
 855          * The rest happens in smbfs_freevfs()
 856          */
 857         return (0);
 858 }


 968                     (SM_MAX_STATFSTIME * (hrtime_t)NANOSEC);
 969                 smi->smi_statvfsbuf = stvfs; /* struct assign! */
 970         }
 971 
 972         mutex_enter(&smi->smi_lock);
 973         if (smi->smi_status & SM_STATUS_STATFS_WANT)
 974                 cv_broadcast(&smi->smi_statvfs_cv);
 975         smi->smi_status &= ~(SM_STATUS_STATFS_BUSY | SM_STATUS_STATFS_WANT);
 976 
 977         /*
 978          * Copy the statvfs data to caller's buf.
 979          * Note: struct assignment
 980          */
 981 cache_hit:
 982         if (error == 0)
 983                 *sbp = smi->smi_statvfsbuf;
 984         mutex_exit(&smi->smi_lock);
 985         return (error);
 986 }
 987 


 988 /*
 989  * Flush dirty smbfs files for file system vfsp.
 990  * If vfsp == NULL, all smbfs files are flushed.
 991  */
 992 /*ARGSUSED*/
 993 static int
 994 smbfs_sync(vfs_t *vfsp, short flag, cred_t *cr)
 995 {
 996 
 997         /*
 998          * SYNC_ATTR is used by fsflush() to force old filesystems like UFS
 999          * to sync metadata, which they would otherwise cache indefinitely.
1000          * Semantically, the only requirement is that the sync be initiated.
1001          * Assume the server-side takes care of attribute sync.
1002          */
1003         if (flag & SYNC_ATTR)
1004                 return (0);
1005 
1006         if (vfsp == NULL) {
1007                 /*
1008                  * Flush ALL smbfs mounts in this zone.
1009                  */
1010                 smbfs_flushall(cr);
1011                 return (0);
1012         }
1013 
1014         smbfs_rflush(vfsp, cr);
1015 
1016         return (0);
1017 }
1018 
1019 /*
1020  * Initialization routine for VFS routines.  Should only be called once
1021  */
1022 int
1023 smbfs_vfsinit(void)
1024 {

1025         return (0);
1026 }
1027 
1028 /*
1029  * Shutdown routine for VFS routines.  Should only be called once
1030  */
1031 void
1032 smbfs_vfsfini(void)
1033 {

1034 }
1035 
1036 void
1037 smbfs_freevfs(vfs_t *vfsp)
1038 {
1039         smbmntinfo_t    *smi;
1040 
1041         /* free up the resources */
1042         smi = VFTOSMI(vfsp);
1043 
1044         /*
1045          * By this time we should have already deleted the
1046          * smi kstats in the unmount code.  If they are still around
1047          * something is wrong
1048          */
1049         ASSERT(smi->smi_io_kstats == NULL);
1050 
1051         smbfs_zonelist_remove(smi);
1052 
1053         smbfs_free_smi(smi);
1054 
1055         /*
1056          * Allow _fini() to succeed now, if so desired.
1057          */
1058         atomic_dec_32(&smbfs_mountcount);
1059 }
1060 
1061 #ifdef  _KERNEL
1062 /*
1063  * smbfs_mount_label_policy:
1064  *      Determine whether the mount is allowed according to MAC check,
1065  *      by comparing (where appropriate) label of the remote server
1066  *      against the label of the zone being mounted into.
1067  *
1068  *      Returns:
1069  *               0 :    access allowed
1070  *              -1 :    read-only access allowed (i.e., read-down)
1071  *              >0 : error code, such as EACCES
1072  *
1073  * NB:
1074  * NFS supports Cipso labels by parsing the vfs_resource
1075  * to see what the Solaris server global zone has shared.
1076  * We can't support that for CIFS since resource names
1077  * contain share names, not paths.
1078  */
1079 static int
1080 smbfs_mount_label_policy(vfs_t *vfsp, void *ipaddr, int addr_type, cred_t *cr)
1081 {


1132                 else
1133                         retv = 0;               /* access OK */
1134         } else if (bldominates(mntlabel, server_sl)) {
1135                 retv = -1;                      /* read-only */
1136         } else {
1137                 retv = EACCES;
1138         }
1139 
1140         if (tsl != NULL)
1141                 label_rele(tsl);
1142 
1143 rel_tpc:
1144         /*LINTED*/
1145         TPC_RELE(tp);
1146 out:
1147         if (mntzone)
1148                 zone_rele(mntzone);
1149         label_rele(zlabel);
1150         return (retv);
1151 }
1152 #endif  /* _KERNEL */