Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/external/cddl/osnet/dist/uts/common/fs/zfs Implement the ZFS...
details: https://anonhg.NetBSD.org/src/rev/a12338a0a6e2
branches: trunk
changeset: 448574:a12338a0a6e2
user: hannken <hannken%NetBSD.org@localhost>
date: Tue Feb 05 09:55:48 2019 +0000
description:
Implement the ZFS control directory ".zfs" and its subdirectory 'snapshot".
Automatically mount snapshots on access of ".zfs/snapshot/<snapname>".
diffstat:
external/cddl/osnet/dist/uts/common/fs/zfs/zfs_ctldir.c | 681 +++++++++++++++-
1 files changed, 672 insertions(+), 9 deletions(-)
diffs (truncated from 742 to 300 lines):
diff -r 6881a2ebae40 -r a12338a0a6e2 external/cddl/osnet/dist/uts/common/fs/zfs/zfs_ctldir.c
--- a/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_ctldir.c Tue Feb 05 09:54:36 2019 +0000
+++ b/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_ctldir.c Tue Feb 05 09:55:48 2019 +0000
@@ -1261,14 +1261,584 @@
#ifdef __NetBSD__
+#include <sys/fstrans.h>
+#include <sys/malloc.h>
#include <sys/pathname.h>
+#include <miscfs/genfs/genfs.h>
#include <sys/zfs_context.h>
#include <sys/zfs_ctldir.h>
+#include <sys/dsl_dataset.h>
+#include <sys/zap.h>
+
+struct zfsctl_root {
+ timestruc_t zc_cmtime;
+};
+
+struct sfs_node_key {
+ uint64_t parent_id;
+ uint64_t id;
+};
+struct sfs_node {
+ struct sfs_node_key sn_key;
+#define sn_parent_id sn_key.parent_id
+#define sn_id sn_key.id
+ lwp_t *sn_mounting;
+};
+
+#define ZFS_SNAPDIR_NAME "snapshot"
+
+#define VTOSFS(vp) ((struct sfs_node *)((vp)->v_data))
+
+#define SFS_NODE_ASSERT(vp) \
+ do { \
+ struct sfs_node *np = VTOSFS(vp); \
+ ASSERT((vp)->v_op == zfs_sfsop_p); \
+ ASSERT((vp)->v_type == VDIR); \
+ } while (/*CONSTCOND*/ 0)
static int (**zfs_sfsop_p)(void *);
-static const struct vnodeopv_entry_desc zfs_sfsop_entries[] = {
+/*
+ * Mount a snapshot. Cannot use do_sys_umount() as it
+ * doesn't allow its "path" argument from SYSSPACE.
+ */
+static int
+sfs_snapshot_mount(vnode_t *vp, const char *snapname)
+{
+ struct sfs_node *node = VTOSFS(vp);
+ zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data;
+ vfs_t *vfsp;
+ char *path, *osname;
+ int error;
+ extern int zfs_domount(vfs_t *, char *);
+
+ path = PNBUF_GET();
+ osname = PNBUF_GET();
+
+ dmu_objset_name(zfsvfs->z_os, path);
+ snprintf(osname, MAXPATHLEN, "%s@%s", path, snapname);
+ snprintf(path, MAXPATHLEN,
+ "%s/" ZFS_CTLDIR_NAME "/" ZFS_SNAPDIR_NAME "/%s",
+ vp->v_vfsp->mnt_stat.f_mntonname, snapname);
+
+ vfsp = vfs_mountalloc(vp->v_vfsp->mnt_op, vp);
+ if (vfsp == NULL) {
+ error = ENOMEM;
+ goto out;
+ }
+ vfsp->mnt_op->vfs_refcount++;
+ vfsp->mnt_stat.f_owner = 0;
+ vfsp->mnt_flag = MNT_RDONLY | MNT_NOSUID | MNT_IGNORE;
+
+ mutex_enter(&vfsp->mnt_updating);
+
+ error = zfs_domount(vfsp, osname);
+ if (error)
+ goto out;
+
+ vfs_getnewfsid(vfsp);
+ strlcpy(vfsp->mnt_stat.f_mntfromname, osname,
+ sizeof(vfsp->mnt_stat.f_mntfromname));
+ set_statvfs_info(path, UIO_SYSSPACE, vfsp->mnt_stat.f_mntfromname,
+ UIO_SYSSPACE, vfsp->mnt_op->vfs_name, vfsp, curlwp);
+
+ vfsp->mnt_lower = vp->v_vfsp;
+
+ mountlist_append(vfsp);
+ vref(vp);
+ vp->v_mountedhere = vfsp;
+
+ mutex_exit(&vfsp->mnt_updating);
+ (void) VFS_STATVFS(vfsp, &vfsp->mnt_stat);
+
+out:;
+ if (error && vfsp) {
+ mutex_exit(&vfsp->mnt_updating);
+ fstrans_unmount(vfsp);
+ vfs_rele(vfsp);
+ }
+ PNBUF_PUT(osname);
+ PNBUF_PUT(path);
+
+ return error;
+}
+
+static int
+sfs_lookup_snapshot(vnode_t *dvp, struct componentname *cnp, vnode_t **vpp)
+{
+ zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data;
+ vnode_t *vp;
+ struct sfs_node *node;
+ struct sfs_node_key key;
+ char snapname[ZFS_MAX_DATASET_NAME_LEN];
+ int error;
+
+ /* Retrieve the snapshot object id and the to be mounted on vnode. */
+ if (cnp->cn_namelen >= sizeof(snapname))
+ return ENOENT;
+
+ strlcpy(snapname, cnp->cn_nameptr, cnp->cn_namelen + 1);
+ error = dsl_dataset_snap_lookup( dmu_objset_ds(zfsvfs->z_os),
+ snapname, &key.id);
+ if (error)
+ return error;
+ key.parent_id = ZFSCTL_INO_SNAPDIR;
+ error = vcache_get(zfsvfs->z_vfs, &key, sizeof(key), vpp);
+ if (error)
+ return error;
+
+ /* Handle case where the vnode is currently mounting. */
+ vp = *vpp;
+ mutex_enter(vp->v_interlock);
+ node = VTOSFS(vp);
+ if (node->sn_mounting) {
+ if (node->sn_mounting == curlwp)
+ error = 0;
+ else
+ error = ERESTART;
+ mutex_exit(vp->v_interlock);
+ if (error)
+ yield();
+ return error;
+ }
+
+ /* If not yet mounted mount the snapshot. */
+ if (vp->v_mountedhere == NULL) {
+ ASSERT(node->sn_mounting == NULL);
+ node->sn_mounting = curlwp;
+ mutex_exit(vp->v_interlock);
+
+ VOP_UNLOCK(dvp, 0);
+ error = sfs_snapshot_mount(vp, snapname);
+ if (vn_lock(dvp, LK_EXCLUSIVE) != 0) {
+ vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
+ error = ENOENT;
+ }
+
+ mutex_enter(vp->v_interlock);
+ if ((node = VTOSFS(vp)))
+ node->sn_mounting = NULL;
+ mutex_exit(vp->v_interlock);
+
+ if (error) {
+ vrele(vp);
+ *vpp = NULL;
+ return error;
+ }
+ } else
+ mutex_exit(vp->v_interlock);
+
+ /* Return the mounted root rather than the covered mount point. */
+ ASSERT(vp->v_mountedhere);
+ error = VFS_ROOT(vp->v_mountedhere, vpp);
+ vrele(vp);
+ if (error)
+ return error;
+
+ /*
+ * Fix up the root vnode mounted on .zfs/snapshot/<snapname>
+ *
+ * Here we make .zfs/snapshot/<snapname> accessible over NFS
+ * without requiring manual mounts of <snapname>.
+ */
+ if (((*vpp)->v_vflag & VV_ROOT)) {
+ ASSERT(VTOZ(*vpp)->z_zfsvfs != zfsvfs);
+ VTOZ(*vpp)->z_zfsvfs->z_parent = zfsvfs;
+ (*vpp)->v_vflag &= ~VV_ROOT;
+ }
+ VOP_UNLOCK(*vpp, 0);
+
+ return 0;
+}
+
+static int
+sfs_lookup(void *v)
+{
+ struct vop_lookup_v2_args /* {
+ struct vnode *a_dvp;
+ struct vnode **a_vpp;
+ struct componentname *a_cnp;
+ } */ *ap = v;
+ vnode_t *dvp = ap->a_dvp;
+ vnode_t **vpp = ap->a_vpp;
+ struct componentname *cnp = ap->a_cnp;
+ zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data;
+ struct sfs_node *dnode = VTOSFS(dvp);
+ int error;
+
+ SFS_NODE_ASSERT(dvp);
+ ZFS_ENTER(zfsvfs);
+
+ /*
+ * No CREATE, DELETE or RENAME.
+ */
+ if ((cnp->cn_flags & ISLASTCN) && cnp->cn_nameiop != LOOKUP) {
+ ZFS_EXIT(zfsvfs);
+
+ return ENOTSUP;
+ }
+
+ /*
+ * Handle DOT and DOTDOT.
+ */
+ if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') {
+ vref(dvp);
+ *vpp = dvp;
+ ZFS_EXIT(zfsvfs);
+
+ return 0;
+ }
+ if ((cnp->cn_flags & ISDOTDOT)) {
+ if (dnode->sn_parent_id == 0) {
+ error = vcache_get(zfsvfs->z_vfs,
+ &zfsvfs->z_root, sizeof(zfsvfs->z_root), vpp);
+ } else if (dnode->sn_parent_id == ZFSCTL_INO_ROOT) {
+ error = zfsctl_root(zfsvfs, vpp);
+ } else if (dnode->sn_parent_id == ZFSCTL_INO_SNAPDIR) {
+ error = zfsctl_snapshot(zfsvfs, vpp);
+ } else {
+ error = ENOENT;
+ }
+ ZFS_EXIT(zfsvfs);
+
+ return error;
+ }
+
+ /*
+ * Lookup in ".zfs".
+ */
+ if (dnode->sn_id == ZFSCTL_INO_ROOT) {
+ if (cnp->cn_namelen == strlen(ZFS_SNAPDIR_NAME) &&
+ strncmp(cnp->cn_nameptr, ZFS_SNAPDIR_NAME,
+ cnp->cn_namelen) == 0) {
+ error = zfsctl_snapshot(zfsvfs, vpp);
+ } else {
+ error = ENOENT;
+ }
+ ZFS_EXIT(zfsvfs);
+
+ return error;
+ }
+
+ /*
+ * Lookup in ".zfs/snapshot".
+ */
+ if (dnode->sn_id == ZFSCTL_INO_SNAPDIR) {
+ error = sfs_lookup_snapshot(dvp, cnp, vpp);
+ ZFS_EXIT(zfsvfs);
+
+ return error;
+ }
+
+ vprint("sfs_lookup: unexpected node for lookup", dvp);
+ ZFS_EXIT(zfsvfs);
+
+ return ENOENT;
+}
+
+static int
+sfs_open(void *v)
+{
+ struct vop_open_args /* {
+ struct vnode *a_vp;
+ int a_mode;
+ kauth_cred_t a_cred;
+ } */ *ap = v;
+ zfsvfs_t *zfsvfs = ap->a_vp->v_vfsp->vfs_data;
+ int error = 0;
+
+ SFS_NODE_ASSERT(ap->a_vp);
+ ZFS_ENTER(zfsvfs);
+
+ if (ap->a_mode & FWRITE)
+ error = EACCES;
+
Home |
Main Index |
Thread Index |
Old Index