aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Behlendorf <[email protected]>2011-01-26 12:45:24 -0800
committerBrian Behlendorf <[email protected]>2011-02-10 09:27:21 -0800
commitbcf308227c9aa51ef9d5a1fe3f2f1342ff2aee94 (patch)
tree484ca7bef221459560dedfe2c6bd77bf9e914d81
parentb516a07b997a8c3006788963f6b6128e505cf56c (diff)
Remove zfs_ctldir.[ch]
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.
-rw-r--r--include/sys/Makefile.am1
-rw-r--r--include/sys/Makefile.in3
-rw-r--r--include/sys/zfs_ctldir.h73
-rw-r--r--include/sys/zfs_vfsops.h31
-rw-r--r--lib/libzpool/Makefile.am1
-rw-r--r--lib/libzpool/Makefile.in1
-rw-r--r--module/zfs/Makefile.in1
-rw-r--r--module/zfs/zfs_ctldir.c1342
-rw-r--r--module/zfs/zfs_dir.c1
-rw-r--r--module/zfs/zfs_ioctl.c1
-rw-r--r--module/zfs/zfs_vfsops.c1
-rw-r--r--module/zfs/zfs_vnops.c3
12 files changed, 30 insertions, 1429 deletions
diff --git a/include/sys/Makefile.am b/include/sys/Makefile.am
index a2e8dd01b..63dc24e5b 100644
--- a/include/sys/Makefile.am
+++ b/include/sys/Makefile.am
@@ -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 \
diff --git a/include/sys/Makefile.in b/include/sys/Makefile.in
index 4ab3927b0..9243f75ab 100644
--- a/include/sys/Makefile.in
+++ b/include/sys/Makefile.in
@@ -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
index f88ef95fd..000000000
--- a/include/sys/zfs_ctldir.h
+++ /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 */
diff --git a/include/sys/zfs_vfsops.h b/include/sys/zfs_vfsops.h
index ec4097768..34a871587 100644
--- a/include/sys/zfs_vfsops.h
+++ b/include/sys/zfs_vfsops.h
@@ -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
diff --git a/lib/libzpool/Makefile.am b/lib/libzpool/Makefile.am
index 0c22b8cf7..450f4cca1 100644
--- a/lib/libzpool/Makefile.am
+++ b/lib/libzpool/Makefile.am
@@ -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 \
diff --git a/lib/libzpool/Makefile.in b/lib/libzpool/Makefile.in
index 17f70e6fe..29d312f9d 100644
--- a/lib/libzpool/Makefile.in
+++ b/lib/libzpool/Makefile.in
@@ -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 \
diff --git a/module/zfs/Makefile.in b/module/zfs/Makefile.in
index 71dbb39fc..7d42481d1 100644
--- a/module/zfs/Makefile.in
+++ b/module/zfs/Makefile.in
@@ -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
index c2b8b75e6..000000000
--- a/module/zfs/zfs_ctldir.c
+++ /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 */
diff --git a/module/zfs/zfs_dir.c b/module/zfs/zfs_dir.c
index a1f3df1a0..aced2886a 100644
--- a/module/zfs/zfs_dir.c
+++ b/module/zfs/zfs_dir.c
@@ -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>
diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c
index 6a7623cae..593ed74bb 100644
--- a/module/zfs/zfs_ioctl.c
+++ b/module/zfs/zfs_ioctl.c
@@ -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>
diff --git a/module/zfs/zfs_vfsops.c b/module/zfs/zfs_vfsops.c
index 14411b8c4..7c980b118 100644
--- a/module/zfs/zfs_vfsops.c
+++ b/module/zfs/zfs_vfsops.c
@@ -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>
diff --git a/module/zfs/zfs_vnops.c b/module/zfs/zfs_vnops.c
index e5e187b15..764f53040 100644
--- a/module/zfs/zfs_vnops.c
+++ b/module/zfs/zfs_vnops.c
@@ -68,10 +68,9 @@
#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>