Remove zfs_ctldir.[ch]
authorBrian Behlendorf <behlendorf1@llnl.gov>
Wed, 26 Jan 2011 20:45:24 +0000 (12:45 -0800)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Thu, 10 Feb 2011 17:27:21 +0000 (09:27 -0800)
This code is used for snapshot and heavily leverages Solaris
functionality we do not want to reimplement.  These files have
been removed, including references to them, and will be replaced
by a zfs_snap.c/zpl_snap.c implementation which handles snapshots.

12 files changed:
include/sys/Makefile.am
include/sys/Makefile.in
include/sys/zfs_ctldir.h [deleted file]
include/sys/zfs_vfsops.h
lib/libzpool/Makefile.am
lib/libzpool/Makefile.in
module/zfs/Makefile.in
module/zfs/zfs_ctldir.c [deleted file]
module/zfs/zfs_dir.c
module/zfs/zfs_ioctl.c
module/zfs/zfs_vfsops.c
module/zfs/zfs_vnops.c

index a2e8dd0..63dc24e 100644 (file)
@@ -54,7 +54,6 @@ COMMON_H = \
        $(top_srcdir)/include/sys/zap_leaf.h \
        $(top_srcdir)/include/sys/zfs_acl.h \
        $(top_srcdir)/include/sys/zfs_context.h \
-       $(top_srcdir)/include/sys/zfs_ctldir.h \
        $(top_srcdir)/include/sys/zfs_debug.h \
        $(top_srcdir)/include/sys/zfs_dir.h \
        $(top_srcdir)/include/sys/zfs_fuid.h \
index 4ab3927..9243f75 100644 (file)
@@ -144,7 +144,6 @@ am__kernel_HEADERS_DIST = $(top_srcdir)/include/sys/arc.h \
        $(top_srcdir)/include/sys/zap_leaf.h \
        $(top_srcdir)/include/sys/zfs_acl.h \
        $(top_srcdir)/include/sys/zfs_context.h \
-       $(top_srcdir)/include/sys/zfs_ctldir.h \
        $(top_srcdir)/include/sys/zfs_debug.h \
        $(top_srcdir)/include/sys/zfs_dir.h \
        $(top_srcdir)/include/sys/zfs_fuid.h \
@@ -240,7 +239,6 @@ am__libzfs_HEADERS_DIST = $(top_srcdir)/include/sys/arc.h \
        $(top_srcdir)/include/sys/zap_leaf.h \
        $(top_srcdir)/include/sys/zfs_acl.h \
        $(top_srcdir)/include/sys/zfs_context.h \
-       $(top_srcdir)/include/sys/zfs_ctldir.h \
        $(top_srcdir)/include/sys/zfs_debug.h \
        $(top_srcdir)/include/sys/zfs_dir.h \
        $(top_srcdir)/include/sys/zfs_fuid.h \
@@ -512,7 +510,6 @@ COMMON_H = \
        $(top_srcdir)/include/sys/zap_leaf.h \
        $(top_srcdir)/include/sys/zfs_acl.h \
        $(top_srcdir)/include/sys/zfs_context.h \
-       $(top_srcdir)/include/sys/zfs_ctldir.h \
        $(top_srcdir)/include/sys/zfs_debug.h \
        $(top_srcdir)/include/sys/zfs_dir.h \
        $(top_srcdir)/include/sys/zfs_fuid.h \
diff --git a/include/sys/zfs_ctldir.h b/include/sys/zfs_ctldir.h
deleted file mode 100644 (file)
index f88ef95..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- */
-
-#ifndef        _ZFS_CTLDIR_H
-#define        _ZFS_CTLDIR_H
-
-#include <sys/pathname.h>
-#include <sys/vnode.h>
-#include <sys/zfs_vfsops.h>
-#include <sys/zfs_znode.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define        ZFS_CTLDIR_NAME         ".zfs"
-
-#define        zfs_has_ctldir(zdp)     \
-       ((zdp)->z_id == (zdp)->z_zfsvfs->z_root && \
-       ((zdp)->z_zfsvfs->z_ctldir != NULL))
-#define        zfs_show_ctldir(zdp)    \
-       (zfs_has_ctldir(zdp) && \
-       ((zdp)->z_zfsvfs->z_show_ctldir))
-
-void zfsctl_create(zfsvfs_t *);
-void zfsctl_destroy(zfsvfs_t *);
-vnode_t *zfsctl_root(znode_t *);
-void zfsctl_init(void);
-void zfsctl_fini(void);
-boolean_t zfsctl_is_node(vnode_t *);
-
-int zfsctl_rename_snapshot(const char *from, const char *to);
-int zfsctl_destroy_snapshot(const char *snapname, int force);
-int zfsctl_umount_snapshots(vfs_t *, int, cred_t *);
-
-int zfsctl_root_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp,
-    int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
-    int *direntflags, pathname_t *realpnp);
-
-int zfsctl_make_fid(zfsvfs_t *zfsvfsp, uint64_t object, uint32_t gen,
-    fid_t *fidp);
-int zfsctl_lookup_objset(vfs_t *vfsp, uint64_t objsetid, zfsvfs_t **zfsvfsp);
-
-#define        ZFSCTL_INO_ROOT         0x1
-#define        ZFSCTL_INO_SNAPDIR      0x2
-#define        ZFSCTL_INO_SHARES       0x3
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _ZFS_CTLDIR_H */
index ec40977..34a8715 100644 (file)
@@ -67,7 +67,7 @@ struct zfsvfs {
        krwlock_t       z_teardown_inactive_lock;
        list_t          z_all_znodes;   /* all vnodes in the fs */
        kmutex_t        z_znodes_lock;  /* lock for z_all_znodes */
-       vnode_t         *z_ctldir;      /* .zfs directory pointer */
+       struct inode    *z_ctldir;      /* .zfs directory inode */
        boolean_t       z_show_ctldir;  /* expose .zfs in the root dir */
        boolean_t       z_issnap;       /* true if this is a snapshot */
        boolean_t       z_vscan;        /* virus scan on/off */
@@ -83,7 +83,34 @@ struct zfsvfs {
        sa_attr_type_t  *z_attr_table;  /* SA attr mapping->id */
 #define        ZFS_OBJ_MTX_SZ  64
        kmutex_t        z_hold_mtx[ZFS_OBJ_MTX_SZ];     /* znode hold locks */
-};
+} zfs_sb_t;
+
+#define        ZFS_SUPER_MAGIC 0x2fc12fc1
+
+
+/*
+ * Minimal snapshot helpers, the bulk of the Linux snapshot implementation
+ * lives in the zpl_snap.c file which is part of the zpl source.
+ */
+#define        ZFS_CTLDIR_NAME         ".zfs"
+
+#define        zfs_has_ctldir(zdp)     \
+       ((zdp)->z_id == ZTOZSB(zdp)->z_root && \
+       (ZTOZSB(zdp)->z_ctldir != NULL))
+#define        zfs_show_ctldir(zdp)    \
+       (zfs_has_ctldir(zdp) && \
+       (ZTOZSB(zdp)->z_show_ctldir))
+
+#define        ZFSCTL_INO_ROOT         0x1
+#define        ZFSCTL_INO_SNAPDIR      0x2
+#define        ZFSCTL_INO_SHARES       0x3
+
+/*
+ * Allow a maximum number of links.  While ZFS does not internally limit
+ * this most Linux filesystems do.  It's probably a good idea to limit
+ * this to a large value until it is validated that this is safe.
+ */
+#define ZFS_LINK_MAX           65536
 
 /*
  * Normal filesystems (those not under .zfs/snapshot) have a total
index 0c22b8c..450f4cc 100644 (file)
@@ -98,7 +98,6 @@ libzpool_la_LDFLAGS = -pthread
 EXTRA_DIST = \
        $(top_srcdir)/module/zfs/vdev_disk.c \
        $(top_srcdir)/module/zfs/zfs_acl.c \
-       $(top_srcdir)/module/zfs/zfs_ctldir.c \
        $(top_srcdir)/module/zfs/zfs_dir.c \
        $(top_srcdir)/module/zfs/zfs_ioctl.c \
        $(top_srcdir)/module/zfs/zfs_log.c \
index 17f70e6..29d312f 100644 (file)
@@ -419,7 +419,6 @@ libzpool_la_LDFLAGS = -pthread
 EXTRA_DIST = \
        $(top_srcdir)/module/zfs/vdev_disk.c \
        $(top_srcdir)/module/zfs/zfs_acl.c \
-       $(top_srcdir)/module/zfs/zfs_ctldir.c \
        $(top_srcdir)/module/zfs/zfs_dir.c \
        $(top_srcdir)/module/zfs/zfs_ioctl.c \
        $(top_srcdir)/module/zfs/zfs_log.c \
index 71dbb39..7d42481 100644 (file)
@@ -64,7 +64,6 @@ $(MODULE)-objs += @top_srcdir@/module/zfs/zap_leaf.o
 $(MODULE)-objs += @top_srcdir@/module/zfs/zap_micro.o
 $(MODULE)-objs += @top_srcdir@/module/zfs/zfs_acl.o
 $(MODULE)-objs += @top_srcdir@/module/zfs/zfs_byteswap.o
-$(MODULE)-objs += @top_srcdir@/module/zfs/zfs_ctldir.o
 $(MODULE)-objs += @top_srcdir@/module/zfs/zfs_debug.o
 $(MODULE)-objs += @top_srcdir@/module/zfs/zfs_dir.o
 $(MODULE)-objs += @top_srcdir@/module/zfs/zfs_fm.o
diff --git a/module/zfs/zfs_ctldir.c b/module/zfs/zfs_ctldir.c
deleted file mode 100644 (file)
index c2b8b75..0000000
+++ /dev/null
@@ -1,1342 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- */
-
-/*
- * ZFS control directory (a.k.a. ".zfs")
- *
- * This directory provides a common location for all ZFS meta-objects.
- * Currently, this is only the 'snapshot' directory, but this may expand in the
- * future.  The elements are built using the GFS primitives, as the hierarchy
- * does not actually exist on disk.
- *
- * For 'snapshot', we don't want to have all snapshots always mounted, because
- * this would take up a huge amount of space in /etc/mtab.  We have three
- * types of objects:
- *
- *     ctldir ------> snapshotdir -------> snapshot
- *                                             |
- *                                             |
- *                                             V
- *                                         mounted fs
- *
- * The 'snapshot' node contains just enough information to lookup '..' and act
- * as a mountpoint for the snapshot.  Whenever we lookup a specific snapshot, we
- * perform an automount of the underlying filesystem and return the
- * corresponding vnode.
- *
- * All mounts are handled automatically by the kernel, but unmounts are
- * (currently) handled from user land.  The main reason is that there is no
- * reliable way to auto-unmount the filesystem when it's "no longer in use".
- * When the user unmounts a filesystem, we call zfsctl_unmount(), which
- * unmounts any snapshots within the snapshot directory.
- *
- * The '.zfs', '.zfs/snapshot', and all directories created under
- * '.zfs/snapshot' (ie: '.zfs/snapshot/<snapname>') are all GFS nodes and
- * share the same vfs_t as the head filesystem (what '.zfs' lives under).
- *
- * File systems mounted ontop of the GFS nodes '.zfs/snapshot/<snapname>'
- * (ie: snapshots) are ZFS nodes and have their own unique vfs_t.
- * However, vnodes within these mounted on file systems have their v_vfsp
- * fields set to the head filesystem to make NFS happy (see
- * zfsctl_snapdir_lookup()). We VFS_HOLD the head filesystem's vfs_t
- * so that it cannot be freed until all snapshots have been unmounted.
- */
-
-#ifdef HAVE_ZPL
-
-#include <fs/fs_subr.h>
-#include <sys/zfs_ctldir.h>
-#include <sys/zfs_ioctl.h>
-#include <sys/zfs_vfsops.h>
-#include <sys/vfs_opreg.h>
-#include <sys/gfs.h>
-#include <sys/stat.h>
-#include <sys/dmu.h>
-#include <sys/dsl_deleg.h>
-#include <sys/mount.h>
-#include <sys/sunddi.h>
-
-#include "zfs_namecheck.h"
-
-typedef struct zfsctl_node {
-       gfs_dir_t       zc_gfs_private;
-       uint64_t        zc_id;
-       timestruc_t     zc_cmtime;      /* ctime and mtime, always the same */
-} zfsctl_node_t;
-
-typedef struct zfsctl_snapdir {
-       zfsctl_node_t   sd_node;
-       kmutex_t        sd_lock;
-       avl_tree_t      sd_snaps;
-} zfsctl_snapdir_t;
-
-typedef struct {
-       char            *se_name;
-       vnode_t         *se_root;
-       avl_node_t      se_node;
-} zfs_snapentry_t;
-
-static int
-snapentry_compare(const void *a, const void *b)
-{
-       const zfs_snapentry_t *sa = a;
-       const zfs_snapentry_t *sb = b;
-       int ret = strcmp(sa->se_name, sb->se_name);
-
-       if (ret < 0)
-               return (-1);
-       else if (ret > 0)
-               return (1);
-       else
-               return (0);
-}
-
-vnodeops_t *zfsctl_ops_root;
-vnodeops_t *zfsctl_ops_snapdir;
-vnodeops_t *zfsctl_ops_snapshot;
-vnodeops_t *zfsctl_ops_shares;
-vnodeops_t *zfsctl_ops_shares_dir;
-
-static const fs_operation_def_t zfsctl_tops_root[];
-static const fs_operation_def_t zfsctl_tops_snapdir[];
-static const fs_operation_def_t zfsctl_tops_snapshot[];
-static const fs_operation_def_t zfsctl_tops_shares[];
-
-static vnode_t *zfsctl_mknode_snapdir(vnode_t *);
-static vnode_t *zfsctl_mknode_shares(vnode_t *);
-static vnode_t *zfsctl_snapshot_mknode(vnode_t *, uint64_t objset);
-static int zfsctl_unmount_snap(zfs_snapentry_t *, int, cred_t *);
-
-/*
- * Root directory elements.  We only have two entries
- * snapshot and shares.
- */
-static gfs_dirent_t zfsctl_root_entries[] = {
-       { "snapshot", zfsctl_mknode_snapdir, GFS_CACHE_VNODE },
-       { "shares", zfsctl_mknode_shares, GFS_CACHE_VNODE },
-       { NULL }
-};
-
-/* include . and .. in the calculation */
-#define        NROOT_ENTRIES   ((sizeof (zfsctl_root_entries) / \
-    sizeof (gfs_dirent_t)) + 1)
-
-
-/*
- * Initialize the various GFS pieces we'll need to create and manipulate .zfs
- * directories.  This is called from the ZFS init routine, and initializes the
- * vnode ops vectors that we'll be using.
- */
-void
-zfsctl_init(void)
-{
-}
-
-void
-zfsctl_fini(void)
-{
-       /*
-        * Remove vfsctl vnode ops
-        */
-       if (zfsctl_ops_root)
-               vn_freevnodeops(zfsctl_ops_root);
-       if (zfsctl_ops_snapdir)
-               vn_freevnodeops(zfsctl_ops_snapdir);
-       if (zfsctl_ops_snapshot)
-               vn_freevnodeops(zfsctl_ops_snapshot);
-       if (zfsctl_ops_shares)
-               vn_freevnodeops(zfsctl_ops_shares);
-       if (zfsctl_ops_shares_dir)
-               vn_freevnodeops(zfsctl_ops_shares_dir);
-
-       zfsctl_ops_root = NULL;
-       zfsctl_ops_snapdir = NULL;
-       zfsctl_ops_snapshot = NULL;
-       zfsctl_ops_shares = NULL;
-       zfsctl_ops_shares_dir = NULL;
-}
-
-boolean_t
-zfsctl_is_node(vnode_t *vp)
-{
-       return (vn_matchops(vp, zfsctl_ops_root) ||
-           vn_matchops(vp, zfsctl_ops_snapdir) ||
-           vn_matchops(vp, zfsctl_ops_snapshot) ||
-           vn_matchops(vp, zfsctl_ops_shares) ||
-           vn_matchops(vp, zfsctl_ops_shares_dir));
-
-}
-
-/*
- * Return the inode number associated with the 'snapshot' or
- * 'shares' directory.
- */
-/* ARGSUSED */
-static ino64_t
-zfsctl_root_inode_cb(vnode_t *vp, int index)
-{
-       zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data;
-
-       ASSERT(index <= 2);
-
-       if (index == 0)
-               return (ZFSCTL_INO_SNAPDIR);
-
-       return (zfsvfs->z_shares_dir);
-}
-
-/*
- * Create the '.zfs' directory.  This directory is cached as part of the VFS
- * structure.  This results in a hold on the vfs_t.  The code in zfs_umount()
- * therefore checks against a vfs_count of 2 instead of 1.  This reference
- * is removed when the ctldir is destroyed in the unmount.
- */
-void
-zfsctl_create(zfsvfs_t *zfsvfs)
-{
-       vnode_t *vp, *rvp;
-       zfsctl_node_t *zcp;
-       uint64_t crtime[2];
-
-       ASSERT(zfsvfs->z_ctldir == NULL);
-
-       vp = gfs_root_create(sizeof (zfsctl_node_t), zfsvfs->z_vfs,
-           zfsctl_ops_root, ZFSCTL_INO_ROOT, zfsctl_root_entries,
-           zfsctl_root_inode_cb, MAXNAMELEN, NULL, NULL);
-       zcp = vp->v_data;
-       zcp->zc_id = ZFSCTL_INO_ROOT;
-
-       VERIFY(VFS_ROOT(zfsvfs->z_vfs, &rvp) == 0);
-       VERIFY(0 == sa_lookup(VTOZ(rvp)->z_sa_hdl, SA_ZPL_CRTIME(zfsvfs),
-           &crtime, sizeof (crtime)));
-       ZFS_TIME_DECODE(&zcp->zc_cmtime, crtime);
-       VN_RELE(rvp);
-
-       /*
-        * We're only faking the fact that we have a root of a filesystem for
-        * the sake of the GFS interfaces.  Undo the flag manipulation it did
-        * for us.
-        */
-       vp->v_flag &= ~(VROOT | VNOCACHE | VNOMAP | VNOSWAP | VNOMOUNT);
-
-       zfsvfs->z_ctldir = vp;
-}
-
-/*
- * Destroy the '.zfs' directory.  Only called when the filesystem is unmounted.
- * There might still be more references if we were force unmounted, but only
- * new zfs_inactive() calls can occur and they don't reference .zfs
- */
-void
-zfsctl_destroy(zfsvfs_t *zfsvfs)
-{
-       VN_RELE(zfsvfs->z_ctldir);
-       zfsvfs->z_ctldir = NULL;
-}
-
-/*
- * Given a root znode, retrieve the associated .zfs directory.
- * Add a hold to the vnode and return it.
- */
-vnode_t *
-zfsctl_root(znode_t *zp)
-{
-       ASSERT(zfs_has_ctldir(zp));
-       VN_HOLD(zp->z_zfsvfs->z_ctldir);
-       return (zp->z_zfsvfs->z_ctldir);
-}
-
-/*
- * Common open routine.  Disallow any write access.
- */
-/* ARGSUSED */
-static int
-zfsctl_common_open(vnode_t **vpp, int flags, cred_t *cr, caller_context_t *ct)
-{
-       if (flags & FWRITE)
-               return (EACCES);
-
-       return (0);
-}
-
-/*
- * Common close routine.  Nothing to do here.
- */
-/* ARGSUSED */
-static int
-zfsctl_common_close(vnode_t *vpp, int flags, int count, offset_t off,
-    cred_t *cr, caller_context_t *ct)
-{
-       return (0);
-}
-
-/*
- * Common access routine.  Disallow writes.
- */
-/* ARGSUSED */
-static int
-zfsctl_common_access(vnode_t *vp, int mode, int flags, cred_t *cr,
-    caller_context_t *ct)
-{
-       if (flags & V_ACE_MASK) {
-               if (mode & ACE_ALL_WRITE_PERMS)
-                       return (EACCES);
-       } else {
-               if (mode & VWRITE)
-                       return (EACCES);
-       }
-
-       return (0);
-}
-
-/*
- * Common getattr function.  Fill in basic information.
- */
-static void
-zfsctl_common_getattr(vnode_t *vp, vattr_t *vap)
-{
-       timestruc_t     now;
-
-       vap->va_uid = 0;
-       vap->va_gid = 0;
-       vap->va_rdev = 0;
-       /*
-        * We are a purely virtual object, so we have no
-        * blocksize or allocated blocks.
-        */
-       vap->va_blksize = 0;
-       vap->va_nblocks = 0;
-       vap->va_seq = 0;
-       vap->va_fsid = vp->v_vfsp->vfs_dev;
-       vap->va_mode = S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP |
-           S_IROTH | S_IXOTH;
-       vap->va_type = VDIR;
-       /*
-        * We live in the now (for atime).
-        */
-       gethrestime(&now);
-       vap->va_atime = now;
-}
-
-/*ARGSUSED*/
-static int
-zfsctl_common_fid(vnode_t *vp, fid_t *fidp, caller_context_t *ct)
-{
-       zfsvfs_t        *zfsvfs = vp->v_vfsp->vfs_data;
-       zfsctl_node_t   *zcp = vp->v_data;
-       uint64_t        object = zcp->zc_id;
-       zfid_short_t    *zfid;
-       int             i;
-
-       ZFS_ENTER(zfsvfs);
-
-       if (fidp->fid_len < SHORT_FID_LEN) {
-               fidp->fid_len = SHORT_FID_LEN;
-               ZFS_EXIT(zfsvfs);
-               return (ENOSPC);
-       }
-
-       zfid = (zfid_short_t *)fidp;
-
-       zfid->zf_len = SHORT_FID_LEN;
-
-       for (i = 0; i < sizeof (zfid->zf_object); i++)
-               zfid->zf_object[i] = (uint8_t)(object >> (8 * i));
-
-       /* .zfs znodes always have a generation number of 0 */
-       for (i = 0; i < sizeof (zfid->zf_gen); i++)
-               zfid->zf_gen[i] = 0;
-
-       ZFS_EXIT(zfsvfs);
-       return (0);
-}
-
-
-/*ARGSUSED*/
-static int
-zfsctl_shares_fid(vnode_t *vp, fid_t *fidp, caller_context_t *ct)
-{
-       zfsvfs_t        *zfsvfs = vp->v_vfsp->vfs_data;
-       znode_t         *dzp;
-       int             error;
-
-       ZFS_ENTER(zfsvfs);
-
-       if (zfsvfs->z_shares_dir == 0) {
-               ZFS_EXIT(zfsvfs);
-               return (ENOTSUP);
-       }
-
-       if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp)) == 0) {
-               error = VOP_FID(ZTOV(dzp), fidp, ct);
-               VN_RELE(ZTOV(dzp));
-       }
-
-       ZFS_EXIT(zfsvfs);
-       return (error);
-}
-/*
- * .zfs inode namespace
- *
- * We need to generate unique inode numbers for all files and directories
- * within the .zfs pseudo-filesystem.  We use the following scheme:
- *
- *     ENTRY                   ZFSCTL_INODE
- *     .zfs                    1
- *     .zfs/snapshot           2
- *     .zfs/snapshot/<snap>    objectid(snap)
- */
-
-#define        ZFSCTL_INO_SNAP(id)     (id)
-
-/*
- * Get root directory attributes.
- */
-/* ARGSUSED */
-static int
-zfsctl_root_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
-    caller_context_t *ct)
-{
-       zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data;
-       zfsctl_node_t *zcp = vp->v_data;
-
-       ZFS_ENTER(zfsvfs);
-       vap->va_nodeid = ZFSCTL_INO_ROOT;
-       vap->va_nlink = vap->va_size = NROOT_ENTRIES;
-       vap->va_mtime = vap->va_ctime = zcp->zc_cmtime;
-
-       zfsctl_common_getattr(vp, vap);
-       ZFS_EXIT(zfsvfs);
-
-       return (0);
-}
-
-/*
- * Special case the handling of "..".
- */
-/* ARGSUSED */
-int
-zfsctl_root_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp,
-    int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
-    int *direntflags, pathname_t *realpnp)
-{
-       zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data;
-       int err;
-
-       /*
-        * No extended attributes allowed under .zfs
-        */
-       if (flags & LOOKUP_XATTR)
-               return (EINVAL);
-
-       ZFS_ENTER(zfsvfs);
-
-       if (strcmp(nm, "..") == 0) {
-               err = VFS_ROOT(dvp->v_vfsp, vpp);
-       } else {
-               err = gfs_vop_lookup(dvp, nm, vpp, pnp, flags, rdir,
-                   cr, ct, direntflags, realpnp);
-       }
-
-       ZFS_EXIT(zfsvfs);
-
-       return (err);
-}
-
-static int
-zfsctl_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
-    caller_context_t *ct)
-{
-       /*
-        * We only care about ACL_ENABLED so that libsec can
-        * display ACL correctly and not default to POSIX draft.
-        */
-       if (cmd == _PC_ACL_ENABLED) {
-               *valp = _ACL_ACE_ENABLED;
-               return (0);
-       }
-
-       return (fs_pathconf(vp, cmd, valp, cr, ct));
-}
-
-static const fs_operation_def_t zfsctl_tops_root[] = {
-       { VOPNAME_OPEN,         { .vop_open = zfsctl_common_open }      },
-       { VOPNAME_CLOSE,        { .vop_close = zfsctl_common_close }    },
-       { VOPNAME_IOCTL,        { .error = fs_inval }                   },
-       { VOPNAME_GETATTR,      { .vop_getattr = zfsctl_root_getattr }  },
-       { VOPNAME_ACCESS,       { .vop_access = zfsctl_common_access }  },
-       { VOPNAME_READDIR,      { .vop_readdir = gfs_vop_readdir }      },
-       { VOPNAME_LOOKUP,       { .vop_lookup = zfsctl_root_lookup }    },
-       { VOPNAME_SEEK,         { .vop_seek = fs_seek }                 },
-       { VOPNAME_INACTIVE,     { .vop_inactive = gfs_vop_inactive }    },
-       { VOPNAME_PATHCONF,     { .vop_pathconf = zfsctl_pathconf }     },
-       { VOPNAME_FID,          { .vop_fid = zfsctl_common_fid  }       },
-       { NULL }
-};
-
-static int
-zfsctl_snapshot_zname(vnode_t *vp, const char *name, int len, char *zname)
-{
-       objset_t *os = ((zfsvfs_t *)((vp)->v_vfsp->vfs_data))->z_os;
-
-       if (snapshot_namecheck(name, NULL, NULL) != 0)
-               return (EILSEQ);
-       dmu_objset_name(os, zname);
-       if (strlen(zname) + 1 + strlen(name) >= len)
-               return (ENAMETOOLONG);
-       (void) strcat(zname, "@");
-       (void) strcat(zname, name);
-       return (0);
-}
-
-static int
-zfsctl_unmount_snap(zfs_snapentry_t *sep, int fflags, cred_t *cr)
-{
-       vnode_t *svp = sep->se_root;
-       int error;
-
-       ASSERT(vn_ismntpt(svp));
-
-       /* this will be dropped by dounmount() */
-       if ((error = vn_vfswlock(svp)) != 0)
-               return (error);
-
-       VN_HOLD(svp);
-       error = dounmount(vn_mountedvfs(svp), fflags, cr);
-       if (error) {
-               VN_RELE(svp);
-               return (error);
-       }
-
-       /*
-        * We can't use VN_RELE(), as that will try to invoke
-        * zfsctl_snapdir_inactive(), which would cause us to destroy
-        * the sd_lock mutex held by our caller.
-        */
-       ASSERT(svp->v_count == 1);
-       gfs_vop_inactive(svp, cr, NULL);
-
-       kmem_free(sep->se_name, strlen(sep->se_name) + 1);
-       kmem_free(sep, sizeof (zfs_snapentry_t));
-
-       return (0);
-}
-
-static void
-zfsctl_rename_snap(zfsctl_snapdir_t *sdp, zfs_snapentry_t *sep, const char *nm)
-{
-       avl_index_t where;
-       vfs_t *vfsp;
-       refstr_t *pathref;
-       char newpath[MAXNAMELEN];
-       char *tail;
-
-       ASSERT(MUTEX_HELD(&sdp->sd_lock));
-       ASSERT(sep != NULL);
-
-       vfsp = vn_mountedvfs(sep->se_root);
-       ASSERT(vfsp != NULL);
-
-       vfs_lock_wait(vfsp);
-
-       /*
-        * Change the name in the AVL tree.
-        */
-       avl_remove(&sdp->sd_snaps, sep);
-       kmem_free(sep->se_name, strlen(sep->se_name) + 1);
-       sep->se_name = kmem_alloc(strlen(nm) + 1, KM_SLEEP);
-       (void) strcpy(sep->se_name, nm);
-       VERIFY(avl_find(&sdp->sd_snaps, sep, &where) == NULL);
-       avl_insert(&sdp->sd_snaps, sep, where);
-
-       /*
-        * Change the current mountpoint info:
-        *      - update the tail of the mntpoint path
-        *      - update the tail of the resource path
-        */
-       pathref = vfs_getmntpoint(vfsp);
-       (void) strncpy(newpath, refstr_value(pathref), sizeof (newpath));
-       VERIFY((tail = strrchr(newpath, '/')) != NULL);
-       *(tail+1) = '\0';
-       ASSERT3U(strlen(newpath) + strlen(nm), <, sizeof (newpath));
-       (void) strcat(newpath, nm);
-       refstr_rele(pathref);
-       vfs_setmntpoint(vfsp, newpath, 0);
-
-       pathref = vfs_getresource(vfsp);
-       (void) strncpy(newpath, refstr_value(pathref), sizeof (newpath));
-       VERIFY((tail = strrchr(newpath, '@')) != NULL);
-       *(tail+1) = '\0';
-       ASSERT3U(strlen(newpath) + strlen(nm), <, sizeof (newpath));
-       (void) strcat(newpath, nm);
-       refstr_rele(pathref);
-       vfs_setresource(vfsp, newpath, 0);
-
-       vfs_unlock(vfsp);
-}
-
-/*ARGSUSED*/
-static int
-zfsctl_snapdir_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
-    cred_t *cr, caller_context_t *ct, int flags)
-{
-       zfsctl_snapdir_t *sdp = sdvp->v_data;
-       zfs_snapentry_t search, *sep;
-       zfsvfs_t *zfsvfs;
-       avl_index_t where;
-       char from[MAXNAMELEN], to[MAXNAMELEN];
-       char real[MAXNAMELEN];
-       int err;
-
-       zfsvfs = sdvp->v_vfsp->vfs_data;
-       ZFS_ENTER(zfsvfs);
-
-       if ((flags & FIGNORECASE) || zfsvfs->z_case == ZFS_CASE_INSENSITIVE) {
-               err = dmu_snapshot_realname(zfsvfs->z_os, snm, real,
-                   MAXNAMELEN, NULL);
-               if (err == 0) {
-                       snm = real;
-               } else if (err != ENOTSUP) {
-                       ZFS_EXIT(zfsvfs);
-                       return (err);
-               }
-       }
-
-       ZFS_EXIT(zfsvfs);
-
-       err = zfsctl_snapshot_zname(sdvp, snm, MAXNAMELEN, from);
-       if (!err)
-               err = zfsctl_snapshot_zname(tdvp, tnm, MAXNAMELEN, to);
-       if (!err)
-               err = zfs_secpolicy_rename_perms(from, to, cr);
-       if (err)
-               return (err);
-
-       /*
-        * Cannot move snapshots out of the snapdir.
-        */
-       if (sdvp != tdvp)
-               return (EINVAL);
-
-       if (strcmp(snm, tnm) == 0)
-               return (0);
-
-       mutex_enter(&sdp->sd_lock);
-
-       search.se_name = (char *)snm;
-       if ((sep = avl_find(&sdp->sd_snaps, &search, &where)) == NULL) {
-               mutex_exit(&sdp->sd_lock);
-               return (ENOENT);
-       }
-
-       err = dmu_objset_rename(from, to, B_FALSE);
-       if (err == 0)
-               zfsctl_rename_snap(sdp, sep, tnm);
-
-       mutex_exit(&sdp->sd_lock);
-
-       return (err);
-}
-
-/* ARGSUSED */
-static int
-zfsctl_snapdir_remove(vnode_t *dvp, char *name, vnode_t *cwd, cred_t *cr,
-    caller_context_t *ct, int flags)
-{
-       zfsctl_snapdir_t *sdp = dvp->v_data;
-       zfs_snapentry_t *sep;
-       zfs_snapentry_t search;
-       zfsvfs_t *zfsvfs;
-       char snapname[MAXNAMELEN];
-       char real[MAXNAMELEN];
-       int err;
-
-       zfsvfs = dvp->v_vfsp->vfs_data;
-       ZFS_ENTER(zfsvfs);
-
-       if ((flags & FIGNORECASE) || zfsvfs->z_case == ZFS_CASE_INSENSITIVE) {
-
-               err = dmu_snapshot_realname(zfsvfs->z_os, name, real,
-                   MAXNAMELEN, NULL);
-               if (err == 0) {
-                       name = real;
-               } else if (err != ENOTSUP) {
-                       ZFS_EXIT(zfsvfs);
-                       return (err);
-               }
-       }
-
-       ZFS_EXIT(zfsvfs);
-
-       err = zfsctl_snapshot_zname(dvp, name, MAXNAMELEN, snapname);
-       if (!err)
-               err = zfs_secpolicy_destroy_perms(snapname, cr);
-       if (err)
-               return (err);
-
-       mutex_enter(&sdp->sd_lock);
-
-       search.se_name = name;
-       sep = avl_find(&sdp->sd_snaps, &search, NULL);
-       if (sep) {
-               avl_remove(&sdp->sd_snaps, sep);
-               err = zfsctl_unmount_snap(sep, MS_FORCE, cr);
-               if (err)
-                       avl_add(&sdp->sd_snaps, sep);
-               else
-                       err = dmu_objset_destroy(snapname, B_FALSE);
-       } else {
-               err = ENOENT;
-       }
-
-       mutex_exit(&sdp->sd_lock);
-
-       return (err);
-}
-
-/*
- * This creates a snapshot under '.zfs/snapshot'.
- */
-/* ARGSUSED */
-static int
-zfsctl_snapdir_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t  **vpp,
-    cred_t *cr, caller_context_t *cc, int flags, vsecattr_t *vsecp)
-{
-       zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data;
-       char name[MAXNAMELEN];
-       int err;
-       static enum symfollow follow = NO_FOLLOW;
-       static enum uio_seg seg = UIO_SYSSPACE;
-
-       if (snapshot_namecheck(dirname, NULL, NULL) != 0)
-               return (EILSEQ);
-
-       dmu_objset_name(zfsvfs->z_os, name);
-
-       *vpp = NULL;
-
-       err = zfs_secpolicy_snapshot_perms(name, cr);
-       if (err)
-               return (err);
-
-       if (err == 0) {
-               err = dmu_objset_snapshot(name, dirname, NULL, NULL,
-                   B_FALSE, B_FALSE, -1);
-               if (err)
-                       return (err);
-               err = lookupnameat(dirname, seg, follow, NULL, vpp, dvp);
-       }
-
-       return (err);
-}
-
-/*
- * Lookup entry point for the 'snapshot' directory.  Try to open the
- * snapshot if it exist, creating the pseudo filesystem vnode as necessary.
- * Perform a mount of the associated dataset on top of the vnode.
- */
-/* ARGSUSED */
-static int
-zfsctl_snapdir_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp,
-    int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
-    int *direntflags, pathname_t *realpnp)
-{
-       zfsctl_snapdir_t *sdp = dvp->v_data;
-       objset_t *snap;
-       char snapname[MAXNAMELEN];
-       char real[MAXNAMELEN];
-       char *mountpoint;
-       zfs_snapentry_t *sep, search;
-       struct mounta margs;
-       vfs_t *vfsp;
-       size_t mountpoint_len;
-       avl_index_t where;
-       zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data;
-       int err;
-
-       /*
-        * No extended attributes allowed under .zfs
-        */
-       if (flags & LOOKUP_XATTR)
-               return (EINVAL);
-
-       ASSERT(dvp->v_type == VDIR);
-
-       /*
-        * If we get a recursive call, that means we got called
-        * from the domount() code while it was trying to look up the
-        * spec (which looks like a local path for zfs).  We need to
-        * add some flag to domount() to tell it not to do this lookup.
-        */
-       if (MUTEX_HELD(&sdp->sd_lock))
-               return (ENOENT);
-
-       ZFS_ENTER(zfsvfs);
-
-       if (gfs_lookup_dot(vpp, dvp, zfsvfs->z_ctldir, nm) == 0) {
-               ZFS_EXIT(zfsvfs);
-               return (0);
-       }
-
-       if (flags & FIGNORECASE) {
-               boolean_t conflict = B_FALSE;
-
-               err = dmu_snapshot_realname(zfsvfs->z_os, nm, real,
-                   MAXNAMELEN, &conflict);
-               if (err == 0) {
-                       nm = real;
-               } else if (err != ENOTSUP) {
-                       ZFS_EXIT(zfsvfs);
-                       return (err);
-               }
-               if (realpnp)
-                       (void) strlcpy(realpnp->pn_buf, nm,
-                           realpnp->pn_bufsize);
-               if (conflict && direntflags)
-                       *direntflags = ED_CASE_CONFLICT;
-       }
-
-       mutex_enter(&sdp->sd_lock);
-       search.se_name = (char *)nm;
-       if ((sep = avl_find(&sdp->sd_snaps, &search, &where)) != NULL) {
-               *vpp = sep->se_root;
-               VN_HOLD(*vpp);
-               err = traverse(vpp);
-               if (err) {
-                       VN_RELE(*vpp);
-                       *vpp = NULL;
-               } else if (*vpp == sep->se_root) {
-                       /*
-                        * The snapshot was unmounted behind our backs,
-                        * try to remount it.
-                        */
-                       goto domount;
-               } else {
-                       /*
-                        * VROOT was set during the traverse call.  We need
-                        * to clear it since we're pretending to be part
-                        * of our parent's vfs.
-                        */
-                       (*vpp)->v_flag &= ~VROOT;
-               }
-               mutex_exit(&sdp->sd_lock);
-               ZFS_EXIT(zfsvfs);
-               return (err);
-       }
-
-       /*
-        * The requested snapshot is not currently mounted, look it up.
-        */
-       err = zfsctl_snapshot_zname(dvp, nm, MAXNAMELEN, snapname);
-       if (err) {
-               mutex_exit(&sdp->sd_lock);
-               ZFS_EXIT(zfsvfs);
-               /*
-                * handle "ls *" or "?" in a graceful manner,
-                * forcing EILSEQ to ENOENT.
-                * Since shell ultimately passes "*" or "?" as name to lookup
-                */
-               return (err == EILSEQ ? ENOENT : err);
-       }
-       if (dmu_objset_hold(snapname, FTAG, &snap) != 0) {
-               mutex_exit(&sdp->sd_lock);
-               ZFS_EXIT(zfsvfs);
-               return (ENOENT);
-       }
-
-       sep = kmem_alloc(sizeof (zfs_snapentry_t), KM_SLEEP);
-       sep->se_name = kmem_alloc(strlen(nm) + 1, KM_SLEEP);
-       (void) strcpy(sep->se_name, nm);
-       *vpp = sep->se_root = zfsctl_snapshot_mknode(dvp, dmu_objset_id(snap));
-       avl_insert(&sdp->sd_snaps, sep, where);
-
-       dmu_objset_rele(snap, FTAG);
-domount:
-       mountpoint_len = strlen(refstr_value(dvp->v_vfsp->vfs_mntpt)) +
-           strlen("/.zfs/snapshot/") + strlen(nm) + 1;
-       mountpoint = kmem_alloc(mountpoint_len, KM_SLEEP);
-       (void) snprintf(mountpoint, mountpoint_len, "%s/.zfs/snapshot/%s",
-           refstr_value(dvp->v_vfsp->vfs_mntpt), nm);
-
-       margs.spec = snapname;
-       margs.dir = mountpoint;
-       margs.flags = MS_SYSSPACE | MS_NOMNTTAB;
-       margs.fstype = "zfs";
-       margs.dataptr = NULL;
-       margs.datalen = 0;
-       margs.optptr = NULL;
-       margs.optlen = 0;
-
-       err = domount("zfs", &margs, *vpp, kcred, &vfsp);
-       kmem_free(mountpoint, mountpoint_len);
-
-       if (err == 0) {
-               /*
-                * Return the mounted root rather than the covered mount point.
-                * Takes the GFS vnode at .zfs/snapshot/<snapname> and returns
-                * the ZFS vnode mounted on top of the GFS node.  This ZFS
-                * vnode is the root of the newly created vfsp.
-                */
-               VFS_RELE(vfsp);
-               err = traverse(vpp);
-       }
-
-       if (err == 0) {
-               /*
-                * Fix up the root vnode mounted on .zfs/snapshot/<snapname>.
-                *
-                * This is where we lie about our v_vfsp in order to
-                * make .zfs/snapshot/<snapname> accessible over NFS
-                * without requiring manual mounts of <snapname>.
-                */
-               ASSERT(VTOZ(*vpp)->z_zfsvfs != zfsvfs);
-               VTOZ(*vpp)->z_zfsvfs->z_parent = zfsvfs;
-               (*vpp)->v_vfsp = zfsvfs->z_vfs;
-               (*vpp)->v_flag &= ~VROOT;
-       }
-       mutex_exit(&sdp->sd_lock);
-       ZFS_EXIT(zfsvfs);
-
-       /*
-        * If we had an error, drop our hold on the vnode and
-        * zfsctl_snapshot_inactive() will clean up.
-        */
-       if (err) {
-               VN_RELE(*vpp);
-               *vpp = NULL;
-       }
-       return (err);
-}
-
-/* ARGSUSED */
-static int
-zfsctl_shares_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp,
-    int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
-    int *direntflags, pathname_t *realpnp)
-{
-       zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data;
-       znode_t *dzp;
-       int error;
-
-       ZFS_ENTER(zfsvfs);
-
-       if (gfs_lookup_dot(vpp, dvp, zfsvfs->z_ctldir, nm) == 0) {
-               ZFS_EXIT(zfsvfs);
-               return (0);
-       }
-
-       if (zfsvfs->z_shares_dir == 0) {
-               ZFS_EXIT(zfsvfs);
-               return (ENOTSUP);
-       }
-       if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp)) == 0)
-               error = VOP_LOOKUP(ZTOV(dzp), nm, vpp, pnp,
-                   flags, rdir, cr, ct, direntflags, realpnp);
-
-       VN_RELE(ZTOV(dzp));
-       ZFS_EXIT(zfsvfs);
-
-       return (error);
-}
-
-/* ARGSUSED */
-static int
-zfsctl_snapdir_readdir_cb(vnode_t *vp, void *dp, int *eofp,
-    offset_t *offp, offset_t *nextp, void *data, int flags)
-{
-       zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data;
-       char snapname[MAXNAMELEN];
-       uint64_t id, cookie;
-       boolean_t case_conflict;
-       int error;
-
-       ZFS_ENTER(zfsvfs);
-
-       cookie = *offp;
-       error = dmu_snapshot_list_next(zfsvfs->z_os, MAXNAMELEN, snapname, &id,
-           &cookie, &case_conflict);
-       if (error) {
-               ZFS_EXIT(zfsvfs);
-               if (error == ENOENT) {
-                       *eofp = 1;
-                       return (0);
-               }
-               return (error);
-       }
-
-       if (flags & V_RDDIR_ENTFLAGS) {
-               edirent_t *eodp = dp;
-
-               (void) strcpy(eodp->ed_name, snapname);
-               eodp->ed_ino = ZFSCTL_INO_SNAP(id);
-               eodp->ed_eflags = case_conflict ? ED_CASE_CONFLICT : 0;
-       } else {
-               struct dirent64 *odp = dp;
-
-               (void) strcpy(odp->d_name, snapname);
-               odp->d_ino = ZFSCTL_INO_SNAP(id);
-       }
-       *nextp = cookie;
-
-       ZFS_EXIT(zfsvfs);
-
-       return (0);
-}
-
-/* ARGSUSED */
-static int
-zfsctl_shares_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp,
-    caller_context_t *ct, int flags)
-{
-       zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data;
-       znode_t *dzp;
-       int error;
-
-       ZFS_ENTER(zfsvfs);
-
-       if (zfsvfs->z_shares_dir == 0) {
-               ZFS_EXIT(zfsvfs);
-               return (ENOTSUP);
-       }
-       if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp)) == 0) {
-               error = VOP_READDIR(ZTOV(dzp), uiop, cr, eofp, ct, flags);
-               VN_RELE(ZTOV(dzp));
-       } else {
-               *eofp = 1;
-               error = ENOENT;
-       }
-
-       ZFS_EXIT(zfsvfs);
-       return (error);
-}
-
-/*
- * pvp is the '.zfs' directory (zfsctl_node_t).
- * Creates vp, which is '.zfs/snapshot' (zfsctl_snapdir_t).
- *
- * This function is the callback to create a GFS vnode for '.zfs/snapshot'
- * when a lookup is performed on .zfs for "snapshot".
- */
-vnode_t *
-zfsctl_mknode_snapdir(vnode_t *pvp)
-{
-       vnode_t *vp;
-       zfsctl_snapdir_t *sdp;
-
-       vp = gfs_dir_create(sizeof (zfsctl_snapdir_t), pvp,
-           zfsctl_ops_snapdir, NULL, NULL, MAXNAMELEN,
-           zfsctl_snapdir_readdir_cb, NULL);
-       sdp = vp->v_data;
-       sdp->sd_node.zc_id = ZFSCTL_INO_SNAPDIR;
-       sdp->sd_node.zc_cmtime = ((zfsctl_node_t *)pvp->v_data)->zc_cmtime;
-       mutex_init(&sdp->sd_lock, NULL, MUTEX_DEFAULT, NULL);
-       avl_create(&sdp->sd_snaps, snapentry_compare,
-           sizeof (zfs_snapentry_t), offsetof(zfs_snapentry_t, se_node));
-       return (vp);
-}
-
-vnode_t *
-zfsctl_mknode_shares(vnode_t *pvp)
-{
-       vnode_t *vp;
-       zfsctl_node_t *sdp;
-
-       vp = gfs_dir_create(sizeof (zfsctl_node_t), pvp,
-           zfsctl_ops_shares, NULL, NULL, MAXNAMELEN,
-           NULL, NULL);
-       sdp = vp->v_data;
-       sdp->zc_cmtime = ((zfsctl_node_t *)pvp->v_data)->zc_cmtime;
-       return (vp);
-
-}
-
-/* ARGSUSED */
-static int
-zfsctl_shares_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
-    caller_context_t *ct)
-{
-       zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data;
-       znode_t *dzp;
-       int error;
-
-       ZFS_ENTER(zfsvfs);
-       if (zfsvfs->z_shares_dir == 0) {
-               ZFS_EXIT(zfsvfs);
-               return (ENOTSUP);
-       }
-       if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp)) == 0) {
-               error = VOP_GETATTR(ZTOV(dzp), vap, flags, cr, ct);
-               VN_RELE(ZTOV(dzp));
-       }
-       ZFS_EXIT(zfsvfs);
-       return (error);
-
-
-}
-
-/* ARGSUSED */
-static int
-zfsctl_snapdir_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
-    caller_context_t *ct)
-{
-       zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data;
-       zfsctl_snapdir_t *sdp = vp->v_data;
-
-       ZFS_ENTER(zfsvfs);
-       zfsctl_common_getattr(vp, vap);
-       vap->va_nodeid = gfs_file_inode(vp);
-       vap->va_nlink = vap->va_size = avl_numnodes(&sdp->sd_snaps) + 2;
-       vap->va_ctime = vap->va_mtime = dmu_objset_snap_cmtime(zfsvfs->z_os);
-       ZFS_EXIT(zfsvfs);
-
-       return (0);
-}
-
-/* ARGSUSED */
-static void
-zfsctl_snapdir_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
-{
-       zfsctl_snapdir_t *sdp = vp->v_data;
-       void *private;
-
-       private = gfs_dir_inactive(vp);
-       if (private != NULL) {
-               ASSERT(avl_numnodes(&sdp->sd_snaps) == 0);
-               mutex_destroy(&sdp->sd_lock);
-               avl_destroy(&sdp->sd_snaps);
-               kmem_free(private, sizeof (zfsctl_snapdir_t));
-       }
-}
-
-static const fs_operation_def_t zfsctl_tops_snapdir[] = {
-       { VOPNAME_OPEN,         { .vop_open = zfsctl_common_open }      },
-       { VOPNAME_CLOSE,        { .vop_close = zfsctl_common_close }    },
-       { VOPNAME_IOCTL,        { .error = fs_inval }                   },
-       { VOPNAME_GETATTR,      { .vop_getattr = zfsctl_snapdir_getattr } },
-       { VOPNAME_ACCESS,       { .vop_access = zfsctl_common_access }  },
-       { VOPNAME_RENAME,       { .vop_rename = zfsctl_snapdir_rename } },
-       { VOPNAME_RMDIR,        { .vop_rmdir = zfsctl_snapdir_remove }  },
-       { VOPNAME_MKDIR,        { .vop_mkdir = zfsctl_snapdir_mkdir }   },
-       { VOPNAME_READDIR,      { .vop_readdir = gfs_vop_readdir }      },
-       { VOPNAME_LOOKUP,       { .vop_lookup = zfsctl_snapdir_lookup } },
-       { VOPNAME_SEEK,         { .vop_seek = fs_seek }                 },
-       { VOPNAME_INACTIVE,     { .vop_inactive = zfsctl_snapdir_inactive } },
-       { VOPNAME_FID,          { .vop_fid = zfsctl_common_fid }        },
-       { NULL }
-};
-
-static const fs_operation_def_t zfsctl_tops_shares[] = {
-       { VOPNAME_OPEN,         { .vop_open = zfsctl_common_open }      },
-       { VOPNAME_CLOSE,        { .vop_close = zfsctl_common_close }    },
-       { VOPNAME_IOCTL,        { .error = fs_inval }                   },
-       { VOPNAME_GETATTR,      { .vop_getattr = zfsctl_shares_getattr } },
-       { VOPNAME_ACCESS,       { .vop_access = zfsctl_common_access }  },
-       { VOPNAME_READDIR,      { .vop_readdir = zfsctl_shares_readdir } },
-       { VOPNAME_LOOKUP,       { .vop_lookup = zfsctl_shares_lookup }  },
-       { VOPNAME_SEEK,         { .vop_seek = fs_seek }                 },
-       { VOPNAME_INACTIVE,     { .vop_inactive = gfs_vop_inactive } },
-       { VOPNAME_FID,          { .vop_fid = zfsctl_shares_fid } },
-       { NULL }
-};
-
-/*
- * pvp is the GFS vnode '.zfs/snapshot'.
- *
- * This creates a GFS node under '.zfs/snapshot' representing each
- * snapshot.  This newly created GFS node is what we mount snapshot
- * vfs_t's ontop of.
- */
-static vnode_t *
-zfsctl_snapshot_mknode(vnode_t *pvp, uint64_t objset)
-{
-       vnode_t *vp;
-       zfsctl_node_t *zcp;
-
-       vp = gfs_dir_create(sizeof (zfsctl_node_t), pvp,
-           zfsctl_ops_snapshot, NULL, NULL, MAXNAMELEN, NULL, NULL);
-       zcp = vp->v_data;
-       zcp->zc_id = objset;
-
-       return (vp);
-}
-
-static void
-zfsctl_snapshot_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
-{
-       zfsctl_snapdir_t *sdp;
-       zfs_snapentry_t *sep, *next;
-       vnode_t *dvp;
-
-       VERIFY(gfs_dir_lookup(vp, "..", &dvp, cr, 0, NULL, NULL) == 0);
-       sdp = dvp->v_data;
-
-       mutex_enter(&sdp->sd_lock);
-
-       if (vp->v_count > 1) {
-               mutex_exit(&sdp->sd_lock);
-               return;
-       }
-       ASSERT(!vn_ismntpt(vp));
-
-       sep = avl_first(&sdp->sd_snaps);
-       while (sep != NULL) {
-               next = AVL_NEXT(&sdp->sd_snaps, sep);
-
-               if (sep->se_root == vp) {
-                       avl_remove(&sdp->sd_snaps, sep);
-                       kmem_free(sep->se_name, strlen(sep->se_name) + 1);
-                       kmem_free(sep, sizeof (zfs_snapentry_t));
-                       break;
-               }
-               sep = next;
-       }
-       ASSERT(sep != NULL);
-
-       mutex_exit(&sdp->sd_lock);
-       VN_RELE(dvp);
-
-       /*
-        * Dispose of the vnode for the snapshot mount point.
-        * This is safe to do because once this entry has been removed
-        * from the AVL tree, it can't be found again, so cannot become
-        * "active".  If we lookup the same name again we will end up
-        * creating a new vnode.
-        */
-       gfs_vop_inactive(vp, cr, ct);
-}
-
-
-/*
- * These VP's should never see the light of day.  They should always
- * be covered.
- */
-static const fs_operation_def_t zfsctl_tops_snapshot[] = {
-       VOPNAME_INACTIVE, { .vop_inactive =  zfsctl_snapshot_inactive },
-       NULL, NULL
-};
-
-int
-zfsctl_lookup_objset(vfs_t *vfsp, uint64_t objsetid, zfsvfs_t **zfsvfsp)
-{
-       zfsvfs_t *zfsvfs = vfsp->vfs_data;
-       vnode_t *dvp, *vp;
-       zfsctl_snapdir_t *sdp;
-       zfsctl_node_t *zcp;
-       zfs_snapentry_t *sep;
-       int error;
-
-       ASSERT(zfsvfs->z_ctldir != NULL);
-       error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", &dvp,
-           NULL, 0, NULL, kcred, NULL, NULL, NULL);
-       if (error != 0)
-               return (error);
-       sdp = dvp->v_data;
-
-       mutex_enter(&sdp->sd_lock);
-       sep = avl_first(&sdp->sd_snaps);
-       while (sep != NULL) {
-               vp = sep->se_root;
-               zcp = vp->v_data;
-               if (zcp->zc_id == objsetid)
-                       break;
-
-               sep = AVL_NEXT(&sdp->sd_snaps, sep);
-       }
-
-       if (sep != NULL) {
-               VN_HOLD(vp);
-               /*
-                * Return the mounted root rather than the covered mount point.
-                * Takes the GFS vnode at .zfs/snapshot/<snapshot objsetid>
-                * and returns the ZFS vnode mounted on top of the GFS node.
-                * This ZFS vnode is the root of the vfs for objset 'objsetid'.
-                */
-               error = traverse(&vp);
-               if (error == 0) {
-                       if (vp == sep->se_root)
-                               error = EINVAL;
-                       else
-                               *zfsvfsp = VTOZ(vp)->z_zfsvfs;
-               }
-               mutex_exit(&sdp->sd_lock);
-               VN_RELE(vp);
-       } else {
-               error = EINVAL;
-               mutex_exit(&sdp->sd_lock);
-       }
-
-       VN_RELE(dvp);
-
-       return (error);
-}
-
-/*
- * Unmount any snapshots for the given filesystem.  This is called from
- * zfs_umount() - if we have a ctldir, then go through and unmount all the
- * snapshots.
- */
-int
-zfsctl_umount_snapshots(vfs_t *vfsp, int fflags, cred_t *cr)
-{
-       zfsvfs_t *zfsvfs = vfsp->vfs_data;
-       vnode_t *dvp;
-       zfsctl_snapdir_t *sdp;
-       zfs_snapentry_t *sep, *next;
-       int error;
-
-       ASSERT(zfsvfs->z_ctldir != NULL);
-       error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", &dvp,
-           NULL, 0, NULL, cr, NULL, NULL, NULL);
-       if (error != 0)
-               return (error);
-       sdp = dvp->v_data;
-
-       mutex_enter(&sdp->sd_lock);
-
-       sep = avl_first(&sdp->sd_snaps);
-       while (sep != NULL) {
-               next = AVL_NEXT(&sdp->sd_snaps, sep);
-
-               /*
-                * If this snapshot is not mounted, then it must
-                * have just been unmounted by somebody else, and
-                * will be cleaned up by zfsctl_snapdir_inactive().
-                */
-               if (vn_ismntpt(sep->se_root)) {
-                       avl_remove(&sdp->sd_snaps, sep);
-                       error = zfsctl_unmount_snap(sep, fflags, cr);
-                       if (error) {
-                               avl_add(&sdp->sd_snaps, sep);
-                               break;
-                       }
-               }
-               sep = next;
-       }
-
-       mutex_exit(&sdp->sd_lock);
-       VN_RELE(dvp);
-
-       return (error);
-}
-#endif /* HAVE_ZPL */
index a1f3df1..aced288 100644 (file)
@@ -51,7 +51,6 @@
 #include <sys/zap.h>
 #include <sys/dmu.h>
 #include <sys/atomic.h>
-#include <sys/zfs_ctldir.h>
 #include <sys/zfs_fuid.h>
 #include <sys/sa.h>
 #include <sys/zfs_sa.h>
index 6a7623c..593ed74 100644 (file)
@@ -58,7 +58,6 @@
 #include <sys/mount.h>
 #include <sys/sdt.h>
 #include <sys/fs/zfs.h>
-#include <sys/zfs_ctldir.h>
 #include <sys/zfs_dir.h>
 #include <sys/zfs_onexit.h>
 #include <sys/zvol.h>
index 14411b8..7c980b1 100644 (file)
@@ -55,7 +55,6 @@
 #include <sys/modctl.h>
 #include <sys/refstr.h>
 #include <sys/zfs_ioctl.h>
-#include <sys/zfs_ctldir.h>
 #include <sys/zfs_fuid.h>
 #include <sys/bootconf.h>
 #include <sys/sunddi.h>
index e5e187b..764f530 100644 (file)
 #include <sys/dirent.h>
 #include <sys/policy.h>
 #include <sys/sunddi.h>
-#include <sys/filio.h>
 #include <sys/sid.h>
+#include <sys/mode.h>
 #include "fs/fs_subr.h"
-#include <sys/zfs_ctldir.h>
 #include <sys/zfs_fuid.h>
 #include <sys/zfs_sa.h>
 #include <sys/zfs_vnops.h>