MFC r196309:

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)
This commit is contained in:
Pawel Jakub Dawidek 2009-08-17 10:02:31 +00:00
parent 5adfc444cf
commit 1aefcd39f0
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/stable/8/; revision=196310

View File

@ -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