summaryrefslogtreecommitdiffstats
path: root/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c
diff options
context:
space:
mode:
authorpjd <pjd@FreeBSD.org>2009-08-17 10:00:18 +0000
committerpjd <pjd@FreeBSD.org>2009-08-17 10:00:18 +0000
commitf10215bfe677cea2d2d8f37934b727b2e4f2a1fc (patch)
tree6bf1c1069660720ee14b4dbed629a2ee0b72a112 /sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c
parent131066d515bbb9cbb5a4fe078b182d438544ade5 (diff)
downloadFreeBSD-src-f10215bfe677cea2d2d8f37934b727b2e4f2a1fc.zip
FreeBSD-src-f10215bfe677cea2d2d8f37934b727b2e4f2a1fc.tar.gz
getcwd() (when __getcwd() fails) works by stating current directory, going up
(..), calling readdir and looking for previous directory inode. In case of .zfs/ directory this doesn't work, because .zfs/ is hidden by default, so it won't be visible in readdir output. Fix this by implementing VPTOCNP for snapshot directories, so __getcwd() doesn't fail and getcwd() doesn't have to use readdir method. This fixes /bin/pwd from within .zfs/snapshot/<name>/. Suggested by: kib Approved by: re (rwatson)
Diffstat (limited to 'sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c')
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c43
1 files changed, 43 insertions, 0 deletions
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c
index eef1d21..cf99d68 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c
@@ -1195,6 +1195,48 @@ zfsctl_snapshot_lookup(ap)
return (error);
}
+static int
+zfsctl_snapshot_vptocnp(struct vop_vptocnp_args *ap)
+{
+ zfsvfs_t *zfsvfs = ap->a_vp->v_vfsp->vfs_data;
+ vnode_t *dvp, *vp;
+ zfsctl_snapdir_t *sdp;
+ 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;
+ if (vp == ap->a_vp)
+ break;
+ sep = AVL_NEXT(&sdp->sd_snaps, sep);
+ }
+ if (sep == NULL) {
+ mutex_exit(&sdp->sd_lock);
+ error = ENOENT;
+ } else {
+ size_t len;
+
+ len = strlen(sep->se_name);
+ *ap->a_buflen -= len;
+ bcopy(sep->se_name, ap->a_buf + *ap->a_buflen, len);
+ mutex_exit(&sdp->sd_lock);
+ vhold(dvp);
+ *ap->a_vpp = dvp;
+ }
+ VN_RELE(dvp);
+
+ return (error);
+}
+
/*
* These VP's should never see the light of day. They should always
* be covered.
@@ -1206,6 +1248,7 @@ static struct vop_vector zfsctl_ops_snapshot = {
.vop_reclaim = zfsctl_common_reclaim,
.vop_getattr = zfsctl_snapshot_getattr,
.vop_fid = zfsctl_snapshot_fid,
+ .vop_vptocnp = zfsctl_snapshot_vptocnp,
};
int
OpenPOWER on IntegriCloud