Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / uts / common / fs / smbclnt / smbfs / smbfs_vfsops.c
blobc0a29f1d447d96702ea2428ff650849b015e63a2
1 /*
2 * Copyright (c) 2000-2001, Boris Popov
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Boris Popov.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
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.
32 * $Id: smbfs_vfsops.c,v 1.73.64.1 2005/05/27 02:35:28 lindak Exp $
36 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
37 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
38 * Copyright 2013, Joyent, Inc. All rights reserved.
39 * Copyright (c) 2016 by Delphix. All rights reserved.
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 <sys/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.h>
62 #include <sys/mntent.h>
63 #include <sys/priv.h>
64 #include <sys/taskq.h>
65 #include <inet/ip.h>
67 #include <netsmb/smb_osdep.h>
68 #include <netsmb/smb.h>
69 #include <netsmb/smb_conn.h>
70 #include <netsmb/smb_subr.h>
71 #include <netsmb/smb_dev.h>
73 #include <smbfs/smbfs.h>
74 #include <smbfs/smbfs_node.h>
75 #include <smbfs/smbfs_subr.h>
78 * Should smbfs mount enable "-o acl" by default? There are good
79 * arguments for both. The most common use case is individual users
80 * accessing files on some SMB server, for which "noacl" is the more
81 * convenient default. A less common use case is data migration,
82 * where the "acl" option might be a desirable default. We'll make
83 * the common use case the default. This default can be changed via
84 * /etc/system, and/or set per-mount via the "acl" mount option.
86 int smbfs_default_opt_acl = 0;
89 * How many taskq threads per-mount should we use.
90 * Just one is fine (until we do more async work).
92 int smbfs_tq_nthread = 1;
95 * Local functions definitions.
97 int smbfsinit(int fstyp, char *name);
98 void smbfsfini();
101 * SMBFS Mount options table for MS_OPTIONSTR
102 * Note: These are not all the options.
103 * Some options come in via MS_DATA.
104 * Others are generic (see vfs.c)
106 static char *intr_cancel[] = { MNTOPT_NOINTR, NULL };
107 static char *nointr_cancel[] = { MNTOPT_INTR, NULL };
108 static char *acl_cancel[] = { MNTOPT_NOACL, NULL };
109 static char *noacl_cancel[] = { MNTOPT_ACL, NULL };
110 static char *xattr_cancel[] = { MNTOPT_NOXATTR, NULL };
111 static char *noxattr_cancel[] = { MNTOPT_XATTR, NULL };
113 static mntopt_t mntopts[] = {
115 * option name cancel option default arg flags
116 * ufs arg flag
118 { MNTOPT_INTR, intr_cancel, NULL, MO_DEFAULT, 0 },
119 { MNTOPT_NOINTR, nointr_cancel, NULL, 0, 0 },
120 { MNTOPT_ACL, acl_cancel, NULL, 0, 0 },
121 { MNTOPT_NOACL, noacl_cancel, NULL, 0, 0 },
122 { MNTOPT_XATTR, xattr_cancel, NULL, MO_DEFAULT, 0 },
123 { MNTOPT_NOXATTR, noxattr_cancel, NULL, 0, 0 }
126 static mntopts_t smbfs_mntopts = {
127 sizeof (mntopts) / sizeof (mntopt_t),
128 mntopts
131 static const char fs_type_name[FSTYPSZ] = "smbfs";
133 static vfsdef_t vfw = {
134 VFSDEF_VERSION,
135 (char *)fs_type_name,
136 smbfsinit, /* init routine */
137 VSW_HASPROTO|VSW_NOTZONESAFE, /* flags */
138 &smbfs_mntopts /* mount options table prototype */
141 static struct modlfs modlfs = {
142 &mod_fsops,
143 "SMBFS filesystem",
144 &vfw
147 static struct modlinkage modlinkage = {
148 MODREV_1, (void *)&modlfs, NULL
152 * Mutex to protect the following variables:
153 * smbfs_major
154 * smbfs_minor
156 extern kmutex_t smbfs_minor_lock;
157 extern int smbfs_major;
158 extern int smbfs_minor;
161 * Prevent unloads while we have mounts
163 uint32_t smbfs_mountcount;
166 * smbfs vfs operations.
168 static int smbfs_mount(vfs_t *, vnode_t *, struct mounta *, cred_t *);
169 static int smbfs_unmount(vfs_t *, int, cred_t *);
170 static int smbfs_root(vfs_t *, vnode_t **);
171 static int smbfs_statvfs(vfs_t *, statvfs64_t *);
172 static int smbfs_sync(vfs_t *, short, cred_t *);
173 static void smbfs_freevfs(vfs_t *);
176 * Module loading
180 * This routine is invoked automatically when the kernel module
181 * containing this routine is loaded. This allows module specific
182 * initialization to be done when the module is loaded.
185 _init(void)
187 int error;
190 * Check compiled-in version of "nsmb"
191 * that we're linked with. (paranoid)
193 if (nsmb_version != NSMB_VERSION) {
194 cmn_err(CE_WARN, "_init: nsmb version mismatch");
195 return (ENOTTY);
198 smbfs_mountcount = 0;
201 * NFS calls these two in _clntinit
202 * Easier to follow this way.
204 if ((error = smbfs_subrinit()) != 0) {
205 cmn_err(CE_WARN, "_init: smbfs_subrinit failed");
206 return (error);
209 if ((error = smbfs_vfsinit()) != 0) {
210 cmn_err(CE_WARN, "_init: smbfs_vfsinit failed");
211 smbfs_subrfini();
212 return (error);
215 if ((error = smbfs_clntinit()) != 0) {
216 cmn_err(CE_WARN, "_init: smbfs_clntinit failed");
217 smbfs_vfsfini();
218 smbfs_subrfini();
219 return (error);
222 error = mod_install((struct modlinkage *)&modlinkage);
223 return (error);
227 * Free kernel module resources that were allocated in _init
228 * and remove the linkage information into the kernel
231 _fini(void)
233 int error;
236 * If a forcedly unmounted instance is still hanging around,
237 * we cannot allow the module to be unloaded because that would
238 * cause panics once the VFS framework decides it's time to call
239 * into VFS_FREEVFS().
241 if (smbfs_mountcount)
242 return (EBUSY);
244 error = mod_remove(&modlinkage);
245 if (error)
246 return (error);
249 * Free the allocated smbnodes, etc.
251 smbfs_clntfini();
253 /* NFS calls these two in _clntfini */
254 smbfs_vfsfini();
255 smbfs_subrfini();
258 * Free the ops vectors
260 smbfsfini();
261 return (0);
265 * Return information about the module
268 _info(struct modinfo *modinfop)
270 return (mod_info((struct modlinkage *)&modlinkage, modinfop));
274 * Initialize the vfs structure
277 int smbfsfstyp;
279 static const struct vfsops smbfs_vfsops = {
280 .vfs_mount = smbfs_mount,
281 .vfs_unmount = smbfs_unmount,
282 .vfs_root = smbfs_root,
283 .vfs_statvfs = smbfs_statvfs,
284 .vfs_sync = smbfs_sync,
285 .vfs_vget = fs_nosys,
286 .vfs_mountroot = fs_nosys,
287 .vfs_freevfs = smbfs_freevfs,
291 smbfsinit(int fstyp, char *name)
293 int error;
295 error = vfs_setfsops(fstyp, &smbfs_vfsops);
296 if (error != 0) {
297 zcmn_err(GLOBAL_ZONEID, CE_WARN,
298 "smbfsinit: bad vfs ops template");
299 return (error);
302 smbfsfstyp = fstyp;
304 return (0);
307 void
308 smbfsfini()
310 (void) vfs_freevfsops_by_type(smbfsfstyp);
313 void
314 smbfs_free_smi(smbmntinfo_t *smi)
316 if (smi == NULL)
317 return;
319 if (smi->smi_zone_ref.zref_zone != NULL)
320 zone_rele_ref(&smi->smi_zone_ref, ZONE_REF_SMBFS);
322 if (smi->smi_share != NULL)
323 smb_share_rele(smi->smi_share);
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);
330 kmem_free(smi, sizeof (smbmntinfo_t));
334 * smbfs mount vfsop
335 * Set up mount info record and attach it to vfs struct.
337 static int
338 smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
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;
353 STRUCT_DECL(smbfs_args, args); /* smbfs mount arguments */
355 if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0)
356 return (error);
358 if (mvp->v_type != VDIR)
359 return (ENOTDIR);
362 * get arguments
364 * uap->datalen might be different from sizeof (args)
365 * in a compatible situation.
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);
374 * Check mount program version
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);
385 * Deal with re-mount requests.
387 if (uap->flags & MS_REMOUNT) {
388 cmn_err(CE_WARN, "MS_REMOUNT not implemented");
389 return (ENOTSUP);
393 * Check for busy
395 mutex_enter(&mvp->v_lock);
396 if (!(uap->flags & MS_OVERLAY) &&
397 (mvp->v_count != 1 || (mvp->v_flag & VROOT))) {
398 mutex_exit(&mvp->v_lock);
399 return (EBUSY);
401 mutex_exit(&mvp->v_lock);
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().
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);
418 * Use "goto errout" from here on.
419 * See: ssp, smi, rtnp, mntzone
423 * Determine the zone we're being mounted into.
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;
437 * Stop the mount from going any further if the zone is going away.
439 if (zone_status_get(mntzone) >= ZONE_IS_SHUTTING_DOWN) {
440 error = EBUSY;
441 goto errout;
444 /* Prevent unload. */
445 atomic_inc_32(&smbfs_mountcount);
448 * Create a mount record and link it to the vfs struct.
449 * No more possiblities for errors from here on.
450 * Tear-down of this stuff is in smbfs_free_smi()
452 * Compare with NFS: nfsrootvp()
454 smi = kmem_zalloc(sizeof (*smi), KM_SLEEP);
456 mutex_init(&smi->smi_lock, NULL, MUTEX_DEFAULT, NULL);
457 cv_init(&smi->smi_statvfs_cv, NULL, CV_DEFAULT, NULL);
459 rw_init(&smi->smi_hash_lk, NULL, RW_DEFAULT, NULL);
460 smbfs_init_hash_avl(&smi->smi_hash_avl);
462 smi->smi_share = ssp;
463 ssp = NULL;
466 * Convert the anonymous zone hold acquired via zone_hold() above
467 * into a zone reference.
469 zone_init_ref(&smi->smi_zone_ref);
470 zone_hold_ref(mntzone, &smi->smi_zone_ref, ZONE_REF_SMBFS);
471 zone_rele(mntzone);
472 mntzone = NULL;
475 * Initialize option defaults
477 smi->smi_flags = SMI_LLOCK;
478 smi->smi_acregmin = SEC2HR(SMBFS_ACREGMIN);
479 smi->smi_acregmax = SEC2HR(SMBFS_ACREGMAX);
480 smi->smi_acdirmin = SEC2HR(SMBFS_ACDIRMIN);
481 smi->smi_acdirmax = SEC2HR(SMBFS_ACDIRMAX);
484 * All "generic" mount options have already been
485 * handled in vfs.c:domount() - see mntopts stuff.
486 * Query generic options using vfs_optionisset().
487 * Give ACL an adjustable system-wide default.
489 if (smbfs_default_opt_acl ||
490 vfs_optionisset(vfsp, MNTOPT_ACL, NULL))
491 smi->smi_flags |= SMI_ACL;
492 if (vfs_optionisset(vfsp, MNTOPT_NOACL, NULL))
493 smi->smi_flags &= ~SMI_ACL;
494 if (vfs_optionisset(vfsp, MNTOPT_INTR, NULL))
495 smi->smi_flags |= SMI_INT;
498 * Get the mount options that come in as smbfs_args,
499 * starting with args.flags (SMBFS_MF_xxx)
501 flags = STRUCT_FGET(args, flags);
502 smi->smi_uid = STRUCT_FGET(args, uid);
503 smi->smi_gid = STRUCT_FGET(args, gid);
504 smi->smi_fmode = STRUCT_FGET(args, file_mode) & 0777;
505 smi->smi_dmode = STRUCT_FGET(args, dir_mode) & 0777;
508 * Hande the SMBFS_MF_xxx flags.
510 if (flags & SMBFS_MF_NOAC)
511 smi->smi_flags |= SMI_NOAC;
512 if (flags & SMBFS_MF_ACREGMIN) {
513 sec = STRUCT_FGET(args, acregmin);
514 if (sec < 0 || sec > SMBFS_ACMINMAX)
515 sec = SMBFS_ACMINMAX;
516 smi->smi_acregmin = SEC2HR(sec);
518 if (flags & SMBFS_MF_ACREGMAX) {
519 sec = STRUCT_FGET(args, acregmax);
520 if (sec < 0 || sec > SMBFS_ACMAXMAX)
521 sec = SMBFS_ACMAXMAX;
522 smi->smi_acregmax = SEC2HR(sec);
524 if (flags & SMBFS_MF_ACDIRMIN) {
525 sec = STRUCT_FGET(args, acdirmin);
526 if (sec < 0 || sec > SMBFS_ACMINMAX)
527 sec = SMBFS_ACMINMAX;
528 smi->smi_acdirmin = SEC2HR(sec);
530 if (flags & SMBFS_MF_ACDIRMAX) {
531 sec = STRUCT_FGET(args, acdirmax);
532 if (sec < 0 || sec > SMBFS_ACMAXMAX)
533 sec = SMBFS_ACMAXMAX;
534 smi->smi_acdirmax = SEC2HR(sec);
538 * Get attributes of the remote file system,
539 * i.e. ACL support, named streams, etc.
541 smb_credinit(&scred, cr);
542 error = smbfs_smb_qfsattr(smi->smi_share, &smi->smi_fsa, &scred);
543 smb_credrele(&scred);
544 if (error) {
545 SMBVDEBUG("smbfs_smb_qfsattr error %d\n", error);
549 * We enable XATTR by default (via smbfs_mntopts)
550 * but if the share does not support named streams,
551 * force the NOXATTR option (also clears XATTR).
552 * Caller will set or clear VFS_XATTR after this.
554 if ((smi->smi_fsattr & FILE_NAMED_STREAMS) == 0)
555 vfs_setmntopt(vfsp, MNTOPT_NOXATTR, NULL, 0);
558 * Ditto ACLs (disable if not supported on this share)
560 if ((smi->smi_fsattr & FILE_PERSISTENT_ACLS) == 0) {
561 vfs_setmntopt(vfsp, MNTOPT_NOACL, NULL, 0);
562 smi->smi_flags &= ~SMI_ACL;
566 * Assign a unique device id to the mount
568 mutex_enter(&smbfs_minor_lock);
569 do {
570 smbfs_minor = (smbfs_minor + 1) & MAXMIN32;
571 smbfs_dev = makedevice(smbfs_major, smbfs_minor);
572 } while (vfs_devismounted(smbfs_dev));
573 mutex_exit(&smbfs_minor_lock);
575 vfsp->vfs_dev = smbfs_dev;
576 vfs_make_fsid(&vfsp->vfs_fsid, smbfs_dev, smbfsfstyp);
577 vfsp->vfs_data = (caddr_t)smi;
578 vfsp->vfs_fstype = smbfsfstyp;
579 vfsp->vfs_bsize = MAXBSIZE;
580 vfsp->vfs_bcount = 0;
582 smi->smi_vfsp = vfsp;
583 smbfs_zonelist_add(smi); /* undo in smbfs_freevfs */
585 /* PSARC 2007/227 VFS Feature Registration */
586 vfs_set_feature(vfsp, VFSFT_XVATTR);
587 vfs_set_feature(vfsp, VFSFT_SYSATTR_VIEWS);
590 * Create the root vnode, which we need in unmount
591 * for the call to smbfs_check_table(), etc.
592 * Release this hold in smbfs_unmount.
594 rtnp = smbfs_node_findcreate(smi, "\\", 1, NULL, 0, 0,
595 &smbfs_fattr0);
596 ASSERT(rtnp != NULL);
597 rtnp->r_vnode->v_type = VDIR;
598 rtnp->r_vnode->v_flag |= VROOT;
599 smi->smi_root = rtnp;
602 * Create a taskq for async work (i.e. putpage)
604 smi->smi_taskq = taskq_create_proc("smbfs",
605 smbfs_tq_nthread, minclsyspri,
606 smbfs_tq_nthread, smbfs_tq_nthread * 2,
607 zone->zone_zsched, TASKQ_PREPOPULATE);
610 * NFS does other stuff here too:
611 * async worker threads
612 * init kstats
614 * End of code from NFS nfsrootvp()
616 return (0);
618 errout:
619 vfsp->vfs_data = NULL;
620 if (smi != NULL)
621 smbfs_free_smi(smi);
623 if (mntzone != NULL)
624 zone_rele(mntzone);
626 if (ssp != NULL)
627 smb_share_rele(ssp);
629 return (error);
633 * vfs operations
635 static int
636 smbfs_unmount(vfs_t *vfsp, int flag, cred_t *cr)
638 smbmntinfo_t *smi;
639 smbnode_t *rtnp;
641 smi = VFTOSMI(vfsp);
643 if (secpolicy_fs_unmount(cr, vfsp) != 0)
644 return (EPERM);
646 if ((flag & MS_FORCE) == 0) {
647 smbfs_rflush(vfsp, cr);
650 * If there are any active vnodes on this file system,
651 * (other than the root vnode) then the file system is
652 * busy and can't be umounted.
654 if (smbfs_check_table(vfsp, smi->smi_root))
655 return (EBUSY);
658 * We normally hold a ref to the root vnode, so
659 * check for references beyond the one we expect:
660 * smbmntinfo_t -> smi_root
661 * Note that NFS does not hold the root vnode.
663 if (smi->smi_root &&
664 smi->smi_root->r_vnode->v_count > 1)
665 return (EBUSY);
669 * common code for both forced and non-forced
671 * Setting VFS_UNMOUNTED prevents new operations.
672 * Operations already underway may continue,
673 * but not for long.
675 vfsp->vfs_flag |= VFS_UNMOUNTED;
678 * If we hold the root VP (and we normally do)
679 * then it's safe to release it now.
681 if (smi->smi_root) {
682 rtnp = smi->smi_root;
683 smi->smi_root = NULL;
684 VN_RELE(rtnp->r_vnode); /* release root vnode */
688 * Remove all nodes from the node hash tables.
689 * This (indirectly) calls: smbfs_addfree, smbinactive,
690 * which will try to flush dirty pages, etc. so
691 * don't destroy the underlying share just yet.
693 * Also, with a forced unmount, some nodes may
694 * remain active, and those will get cleaned up
695 * after their last vn_rele.
697 smbfs_destroy_table(vfsp);
700 * Shutdown any outstanding I/O requests on this share,
701 * and force a tree disconnect. The share object will
702 * continue to hang around until smb_share_rele().
703 * This should also cause most active nodes to be
704 * released as their operations fail with EIO.
706 smb_share_kill(smi->smi_share);
709 * Any async taskq work should be giving up.
710 * Wait for those to exit.
712 taskq_destroy(smi->smi_taskq);
715 * Delete our kstats...
717 * Doing it here, rather than waiting until
718 * smbfs_freevfs so these are not visible
719 * after the unmount.
721 if (smi->smi_io_kstats) {
722 kstat_delete(smi->smi_io_kstats);
723 smi->smi_io_kstats = NULL;
725 if (smi->smi_ro_kstats) {
726 kstat_delete(smi->smi_ro_kstats);
727 smi->smi_ro_kstats = NULL;
731 * The rest happens in smbfs_freevfs()
733 return (0);
738 * find root of smbfs
740 static int
741 smbfs_root(vfs_t *vfsp, vnode_t **vpp)
743 smbmntinfo_t *smi;
744 vnode_t *vp;
746 smi = VFTOSMI(vfsp);
748 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
749 return (EPERM);
751 if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
752 return (EIO);
755 * The root vp is created in mount and held
756 * until unmount, so this is paranoia.
758 if (smi->smi_root == NULL)
759 return (EIO);
761 /* Just take a reference and return it. */
762 vp = SMBTOV(smi->smi_root);
763 VN_HOLD(vp);
764 *vpp = vp;
766 return (0);
770 * Get file system statistics.
772 static int
773 smbfs_statvfs(vfs_t *vfsp, statvfs64_t *sbp)
775 int error;
776 smbmntinfo_t *smi = VFTOSMI(vfsp);
777 smb_share_t *ssp = smi->smi_share;
778 statvfs64_t stvfs;
779 hrtime_t now;
780 smb_cred_t scred;
782 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
783 return (EPERM);
785 if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
786 return (EIO);
788 mutex_enter(&smi->smi_lock);
791 * Use cached result if still valid.
793 recheck:
794 now = gethrtime();
795 if (now < smi->smi_statfstime) {
796 error = 0;
797 goto cache_hit;
801 * FS attributes are stale, so someone
802 * needs to do an OTW call to get them.
803 * Serialize here so only one thread
804 * does the OTW call.
806 if (smi->smi_status & SM_STATUS_STATFS_BUSY) {
807 smi->smi_status |= SM_STATUS_STATFS_WANT;
808 if (!cv_wait_sig(&smi->smi_statvfs_cv, &smi->smi_lock)) {
809 mutex_exit(&smi->smi_lock);
810 return (EINTR);
812 /* Hope status is valid now. */
813 goto recheck;
815 smi->smi_status |= SM_STATUS_STATFS_BUSY;
816 mutex_exit(&smi->smi_lock);
819 * Do the OTW call. Note: lock NOT held.
821 smb_credinit(&scred, NULL);
822 bzero(&stvfs, sizeof (stvfs));
823 error = smbfs_smb_statfs(ssp, &stvfs, &scred);
824 smb_credrele(&scred);
825 if (error) {
826 SMBVDEBUG("statfs error=%d\n", error);
827 } else {
830 * Set a few things the OTW call didn't get.
832 stvfs.f_frsize = stvfs.f_bsize;
833 stvfs.f_favail = stvfs.f_ffree;
834 stvfs.f_fsid = (unsigned long)vfsp->vfs_fsid.val[0];
835 bcopy(fs_type_name, stvfs.f_basetype, FSTYPSZ);
836 stvfs.f_flag = vf_to_stf(vfsp->vfs_flag);
837 stvfs.f_namemax = smi->smi_fsa.fsa_maxname;
840 * Save the result, update lifetime
842 now = gethrtime();
843 smi->smi_statfstime = now +
844 (SM_MAX_STATFSTIME * (hrtime_t)NANOSEC);
845 smi->smi_statvfsbuf = stvfs; /* struct assign! */
848 mutex_enter(&smi->smi_lock);
849 if (smi->smi_status & SM_STATUS_STATFS_WANT)
850 cv_broadcast(&smi->smi_statvfs_cv);
851 smi->smi_status &= ~(SM_STATUS_STATFS_BUSY | SM_STATUS_STATFS_WANT);
854 * Copy the statvfs data to caller's buf.
855 * Note: struct assignment
857 cache_hit:
858 if (error == 0)
859 *sbp = smi->smi_statvfsbuf;
860 mutex_exit(&smi->smi_lock);
861 return (error);
865 * Flush dirty smbfs files for file system vfsp.
866 * If vfsp == NULL, all smbfs files are flushed.
868 /*ARGSUSED*/
869 static int
870 smbfs_sync(vfs_t *vfsp, short flag, cred_t *cr)
874 * SYNC_ATTR is used by fsflush() to force old filesystems like UFS
875 * to sync metadata, which they would otherwise cache indefinitely.
876 * Semantically, the only requirement is that the sync be initiated.
877 * Assume the server-side takes care of attribute sync.
879 if (flag & SYNC_ATTR)
880 return (0);
882 if (vfsp == NULL) {
884 * Flush ALL smbfs mounts in this zone.
886 smbfs_flushall(cr);
887 return (0);
890 smbfs_rflush(vfsp, cr);
892 return (0);
896 * Initialization routine for VFS routines. Should only be called once
899 smbfs_vfsinit(void)
901 return (0);
905 * Shutdown routine for VFS routines. Should only be called once
907 void
908 smbfs_vfsfini(void)
912 void
913 smbfs_freevfs(vfs_t *vfsp)
915 smbmntinfo_t *smi;
917 /* free up the resources */
918 smi = VFTOSMI(vfsp);
921 * By this time we should have already deleted the
922 * smi kstats in the unmount code. If they are still around
923 * something is wrong
925 ASSERT(smi->smi_io_kstats == NULL);
927 smbfs_zonelist_remove(smi);
929 smbfs_free_smi(smi);
932 * Allow _fini() to succeed now, if so desired.
934 atomic_dec_32(&smbfs_mountcount);