summaryrefslogtreecommitdiffstats
path: root/sys/kern/vfs_cache.c
diff options
context:
space:
mode:
authormm <mm@FreeBSD.org>2012-01-15 12:08:20 +0000
committermm <mm@FreeBSD.org>2012-01-15 12:08:20 +0000
commit9f44ed5ca827811dd8729bb0ab4397c71161fa9c (patch)
tree7cb3e09e5396eca584100f0f0377b0dd5a33d1ba /sys/kern/vfs_cache.c
parent4642718fb42bef8b06538195461ee680c22cd1f9 (diff)
downloadFreeBSD-src-9f44ed5ca827811dd8729bb0ab4397c71161fa9c.zip
FreeBSD-src-9f44ed5ca827811dd8729bb0ab4397c71161fa9c.tar.gz
Introduce vn_path_to_global_path()
This function updates path string to vnode's full global path and checks the size of the new path string against the pathlen argument. In vfs_domount(), sys_unmount() and kern_jail_set() this new function is used to update the supplied path argument to the respective global path. Unbreaks jailed zfs(8) with enforce_statfs set to 1. Reviewed by: kib MFC after: 1 month
Diffstat (limited to 'sys/kern/vfs_cache.c')
-rw-r--r--sys/kern/vfs_cache.c74
1 files changed, 74 insertions, 0 deletions
diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c
index 3c8338b..9783e80 100644
--- a/sys/kern/vfs_cache.c
+++ b/sys/kern/vfs_cache.c
@@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/malloc.h>
+#include <sys/fcntl.h>
#include <sys/mount.h>
#include <sys/namei.h>
#include <sys/proc.h>
@@ -1278,3 +1279,76 @@ vn_commname(struct vnode *vp, char *buf, u_int buflen)
buf[l] = '\0';
return (0);
}
+
+/*
+ * This function updates path string to vnode's full global path
+ * and checks the size of the new path string against the pathlen argument.
+ *
+ * Requires a locked, referenced vnode and GIANT lock held.
+ * Vnode is re-locked on success or ENODEV, otherwise unlocked.
+ *
+ * If sysctl debug.disablefullpath is set, ENODEV is returned,
+ * vnode is left locked and path remain untouched.
+ *
+ * If vp is a directory, the call to vn_fullpath_global() always succeeds
+ * because it falls back to the ".." lookup if the namecache lookup fails
+ */
+int
+vn_path_to_global_path(struct thread *td, struct vnode *vp, char *path,
+ u_int pathlen)
+{
+ struct nameidata nd;
+ struct vnode *vp1;
+ char *rpath, *fbuf;
+ int error, vfslocked;
+
+ VFS_ASSERT_GIANT(vp->v_mount);
+ ASSERT_VOP_ELOCKED(vp, __func__);
+
+ /* Return ENODEV if sysctl debug.disablefullpath==1 */
+ if (disablefullpath)
+ return (ENODEV);
+
+ /* Construct global filesystem path from vp. */
+ VOP_UNLOCK(vp, 0);
+ error = vn_fullpath_global(td, vp, &rpath, &fbuf);
+
+ if (error != 0) {
+ vrele(vp);
+ return (error);
+ }
+
+ if (strlen(rpath) >= pathlen) {
+ vrele(vp);
+ error = ENAMETOOLONG;
+ goto out;
+ }
+
+ /*
+ * Re-lookup the vnode by path to detect a possible rename.
+ * As a side effect, the vnode is relocked.
+ * If vnode was renamed, return ENOENT.
+ */
+ NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1,
+ UIO_SYSSPACE, path, td);
+ error = namei(&nd);
+ if (error != 0) {
+ vrele(vp);
+ goto out;
+ }
+ vfslocked = NDHASGIANT(&nd);
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+ vp1 = nd.ni_vp;
+ vrele(vp);
+ if (vp1 == vp)
+ strcpy(path, rpath);
+ else {
+ vput(vp1);
+ error = ENOENT;
+ }
+ VFS_UNLOCK_GIANT(vfslocked);
+
+out:
+ free(fbuf, M_TEMP);
+ return (error);
+}
OpenPOWER on IntegriCloud