Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 23 Oct 2013 17:18:54 +0000 (UTC)
From:      Will Andrews <will@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r256993 - in projects/vps/sys: fs/vpsfs kern sys vps
Message-ID:  <201310231718.r9NHIso4065429@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: will
Date: Wed Oct 23 17:18:53 2013
New Revision: 256993
URL: http://svnweb.freebsd.org/changeset/base/256993

Log:
  Sync with svn.7he.at/vps/trunk r194.
  
  r194 | klaus | 2013-07-26 13:49:49 -0600 (Fri, 26 Jul 2013) | 4 lines
  Added a failsafe vn_fullpath1() version, that still needs a little
  bit of work.
  
  Submitted by:	Klaus P. Ohrhallinger <k@7he.at>

Modified:
  projects/vps/sys/fs/vpsfs/vpsfs_quota.c
  projects/vps/sys/kern/vfs_cache.c
  projects/vps/sys/kern/vfs_default.c
  projects/vps/sys/sys/vnode.h
  projects/vps/sys/vps/vps_snapst.c
  projects/vps/sys/vps/vps_suspend.c

Modified: projects/vps/sys/fs/vpsfs/vpsfs_quota.c
==============================================================================
--- projects/vps/sys/fs/vpsfs/vpsfs_quota.c	Wed Oct 23 17:17:57 2013	(r256992)
+++ projects/vps/sys/fs/vpsfs/vpsfs_quota.c	Wed Oct 23 17:18:53 2013	(r256993)
@@ -67,10 +67,6 @@ static int vpsfs_readdir(struct thread *
     int dirbuflen, struct vpsfs_limits *,
     void (*cbfunc)(struct vnode *, struct vpsfs_limits *, struct thread *));
 
-static int get_next_dirent(struct vnode *vp, struct dirent **dpp,
-    char *dirbuf, int dirbuflen, off_t *off, char **cpos, int *len,
-    int *eofflag, struct thread *td);
-
 static void vpsfs_calcvnode(struct vnode *vp, struct vpsfs_limits *limits,
     struct thread *td);
 
@@ -610,63 +606,6 @@ vpsfs_readdir(struct thread *td, struct 
 	return (error);
 }
 
-/* copied from kern/vfs_default.c */
-static int
-get_next_dirent(struct vnode *vp, struct dirent **dpp, char *dirbuf,
-		int dirbuflen, off_t *off, char **cpos, int *len,
-		int *eofflag, struct thread *td)
-{
-	int error, reclen;
-	struct uio uio;
-	struct iovec iov;
-	struct dirent *dp;
-
-	KASSERT(VOP_ISLOCKED(vp), ("vp %p is not locked", vp));
-	KASSERT(vp->v_type == VDIR, ("vp %p is not a directory", vp));
-
-	if (*len == 0) {
-		iov.iov_base = dirbuf;
-		iov.iov_len = dirbuflen;
-
-		uio.uio_iov = &iov;
-		uio.uio_iovcnt = 1;
-		uio.uio_offset = *off;
-		uio.uio_resid = dirbuflen;
-		uio.uio_segflg = UIO_SYSSPACE;
-		uio.uio_rw = UIO_READ;
-		uio.uio_td = td;
-
-		*eofflag = 0;
-
-#ifdef MAC
-		error = mac_vnode_check_readdir(td->td_ucred, vp);
-		if (error == 0)
-#endif
-			error = VOP_READDIR(vp, &uio, td->td_ucred, eofflag,
-				NULL, NULL);
-		if (error)
-			return (error);
-
-		*off = uio.uio_offset;
-
-		*cpos = dirbuf;
-		*len = (dirbuflen - uio.uio_resid);
-	}
-
-	dp = (struct dirent *)(*cpos);
-	reclen = dp->d_reclen;
-	*dpp = dp;
-
-	/* check for malformed directory.. */
-	if (reclen < DIRENT_MINSIZE)
-		return (EINVAL);
-
-	*cpos += reclen;
-	*len -= reclen;
-
-	return (0);
-}
-
 #endif /* VPS */
 
 /* EOF */

Modified: projects/vps/sys/kern/vfs_cache.c
==============================================================================
--- projects/vps/sys/kern/vfs_cache.c	Wed Oct 23 17:17:57 2013	(r256992)
+++ projects/vps/sys/kern/vfs_cache.c	Wed Oct 23 17:18:53 2013	(r256993)
@@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/dirent.h>
 #include <sys/filedesc.h>
 #include <sys/fnv_hash.h>
 #include <sys/kernel.h>
@@ -309,13 +310,8 @@ SYSCTL_OPAQUE(_vfs_cache, OID_AUTO, nchs
 static void cache_zap(struct namecache *ncp);
 static int vn_vptocnp_locked(struct vnode **vp, struct ucred *cred, char *buf,
     u_int *buflen);
-#ifdef VPS
-int vn_fullpath1(struct thread *td, struct vnode *vp, struct vnode *rdir,
-    char *buf, char **retbuf, u_int buflen);
-#else
 static int vn_fullpath1(struct thread *td, struct vnode *vp, struct vnode *rdir,
     char *buf, char **retbuf, u_int buflen);
-#endif
 
 static MALLOC_DEFINE(M_VFSCACHE, "vfscache", "VFS name cache entries");
 
@@ -1269,11 +1265,7 @@ vn_vptocnp_locked(struct vnode **vp, str
 /*
  * The magic behind kern___getcwd() and vn_fullpath().
  */
-#ifdef VPS
-int
-#else
 static int
-#endif
 vn_fullpath1(struct thread *td, struct vnode *vp, struct vnode *rdir,
     char *buf, char **retbuf, u_int buflen)
 {
@@ -1368,6 +1360,357 @@ vn_fullpath1(struct thread *td, struct v
 	return (0);
 }
 
+
+/* ----------------------------------------------------------- */
+
+/*
+   XXX lookup for /dev/console doesn't work, altough td->td_vps and
+       td->td_ucred->cr_vps are right.
+   XXX for this failure no error is returned
+   XXX limit recursion depth !!!
+ */
+
+/*
+ * Search a directory for a given inode number, recursing into
+ * subdirectories.
+ */
+static int
+vn_fullpath1_findparentdir_recurse(struct vnode *dvp, struct ucred *cred,
+    int inodenum, struct vnode **retvp)
+{
+	struct componentname cnp;
+	struct dirent *dp;
+	struct vnode *vp;
+	char *dirbuf;
+	char *cpos;
+	off_t off;
+	int dirbuflen;
+	int eofflag;
+	int error;
+	int len;
+
+	dirbuflen = PATH_MAX;
+	dirbuf = malloc(dirbuflen, M_TEMP, M_WAITOK);
+
+	cpos = NULL;
+	off = 0;
+	len = 0;
+
+	do {
+		error = get_next_dirent(dvp, &dp, dirbuf, dirbuflen,
+		    &off, &cpos, &len, &eofflag, curthread);
+		if (error != 0)
+			goto out;
+
+		if (!strcmp(dp->d_name, ".") ||
+		    !strcmp(dp->d_name, "..") ||
+		    dp->d_fileno == 0)
+			continue;
+
+		cnp.cn_pnbuf = NULL;
+		cnp.cn_consume = 0;
+		cnp.cn_nameptr = dp->d_name;
+		cnp.cn_namelen = strlen(dp->d_name);
+		cnp.cn_lkflags = LK_SHARED | LK_RETRY;
+		cnp.cn_thread = curthread;
+		cnp.cn_cred = cred;
+		error = VOP_LOOKUP(dvp, &vp, &cnp);
+		if (error != 0)
+			goto out;
+
+		if (dp->d_fileno == inodenum) {
+			*retvp = dvp;
+			vunref(vp);
+			VOP_UNLOCK(vp, 0);
+			error = 0;
+			goto out;
+		}
+
+		if (vp->v_type == VDIR) {
+			error = vn_fullpath1_findparentdir_recurse(vp, cred,
+			    inodenum, retvp);
+			if (error != ENOENT) {
+				vunref(vp);
+				VOP_UNLOCK(vp, 0);
+				error = 0;
+				goto out;
+			}
+		}
+
+		vunref(vp);
+		VOP_UNLOCK(vp, 0);
+		
+	} while (len > 0 || !eofflag);
+
+	error = ENOENT;
+
+  out:
+	free(dirbuf, M_TEMP);
+
+	return (error);
+}
+
+/*
+ * Search through the filesystem that owns 'vp' for (one of) its
+ * parent directories.
+ */
+static int
+vn_fullpath1_findparentdir(struct vnode *vp, struct ucred *cred,
+    struct vnode **outvp)
+{
+	struct vattr vattr;
+	struct vnode *rootvp;
+	struct vnode *dvp;
+	int error;
+
+	if (VOP_ISLOCKED(vp) == 0)
+		vn_lock(vp, LK_SHARED | LK_RETRY);
+
+	/* Get inode number of file. */
+	error = VOP_GETATTR(vp, &vattr, cred);
+	VOP_UNLOCK(vp, 0);
+	if (error != 0)
+		return (error);
+
+	error = VFS_ROOT(vp->v_mount, LK_EXCLUSIVE | LK_RETRY, &rootvp);
+	if (error != 0)
+		return (error);
+
+	error = vn_fullpath1_findparentdir_recurse(rootvp, cred,
+	    vattr.va_fileid, &dvp);
+	if (error == 0)
+		*outvp = dvp;
+
+	vunref(rootvp);
+	VOP_UNLOCK(rootvp, 0);
+
+	return (error);
+}
+
+static int
+vn_fullpath1_fallback(struct thread *td, struct vnode *vp,
+    struct vnode *rdir, char *buf, char **retbuf, u_int buflen)
+{
+	struct componentname cnp;
+	struct vattr vattr;
+	struct vnode *dvp2;
+	struct vnode *dvp;
+	struct dirent *dp;
+	char *dirbuf;
+	char *cpos;
+	off_t off;
+	int dirbuflen;
+	int inodenum;
+	int eofflag;
+	int error;
+	int len;
+
+	dirbuflen = PATH_MAX;
+	dirbuf = malloc(dirbuflen, M_TEMP, M_WAITOK);
+
+	buflen -= 1;
+	buf[buflen] = 0;
+
+	if (vp->v_type == VDIR) {
+		dvp = vp;
+
+		if (VOP_ISLOCKED(dvp) == 0)
+			vn_lock(dvp, LK_SHARED | LK_RETRY);
+
+	} else {
+		char buf2[MAXPATHLEN];
+		int buflen2;
+
+		/* Get the parent directory. */
+
+		buflen2 = sizeof(buf2);
+		memset(buf2, 0, sizeof(buf2));
+
+		/*
+		 * Since this step is the most expensive one,
+		 * try the namecache for this one.
+		 */
+		vref(vp);
+		CACHE_RLOCK();
+		error = vn_vptocnp_locked(&vp, td->td_ucred, buf2, &buflen2);
+		if (error == 0)
+			CACHE_RUNLOCK();
+		vrele(vp);
+		dvp = vp;
+		/*
+		// debugging
+		dvp = NULL;
+		error = ENOENT;
+		*/
+
+		if (error == 0) {
+			buflen -= sizeof(buf2)-buflen2;
+			memcpy(buf+buflen, buf2+buflen2, sizeof(buf2)-buflen2);
+
+		} else {
+			/* Do it the *expensive* way. */
+
+			printf("%s: WARNING: looking up by "
+			    "vn_fullpath1_findparentdir(vp=%p, ...)\n",
+			    __func__, vp);
+			error = vn_fullpath1_findparentdir(vp, td->td_ucred, &dvp);
+			if (error != 0)
+				goto out;
+
+			vn_lock(dvp, LK_SHARED | LK_RETRY);
+
+			/* Get inode number of file. */
+			if (VOP_ISLOCKED(vp) == 0)
+				vn_lock(vp, LK_SHARED | LK_RETRY);
+			error = VOP_GETATTR(vp, &vattr, td->td_ucred);
+			VOP_UNLOCK(vp, 0);
+			if (error != 0) {
+				VOP_UNLOCK(dvp, 0);
+				goto out;
+			}
+			inodenum = vattr.va_fileid;
+
+			/* Now we know the parent directory so search it for the file. */
+			cpos = NULL;
+			off = 0;
+			len = 0;
+			error = ENOENT;
+
+			do {
+				error = get_next_dirent(dvp, &dp, dirbuf, dirbuflen,
+				    &off, &cpos, &len, &eofflag, td);	
+				if (error != 0) {
+					VOP_UNLOCK(dvp, 0);
+					goto out;
+				}
+	
+				if (dp->d_fileno == inodenum) {
+					/* Found it ! */
+					if (buflen < strlen(dp->d_name)) {
+						error = ENOMEM;
+						VOP_UNLOCK(dvp, 0);
+						goto out;
+					}
+					buflen -= strlen(dp->d_name);
+					memcpy(buf+buflen, dp->d_name, strlen(dp->d_name));
+					error = 0;
+					break;
+				}
+				error = ENOENT;
+			} while (len > 0 || !eofflag);
+
+			if (error != 0) {
+				printf("%s: line %d\n", __func__, __LINE__);
+				VOP_UNLOCK(dvp, 0);
+				goto out;
+			}
+		}
+
+	}
+
+	for (;;) {
+
+		/* Separate component names with '/'. */
+		if (buflen < 1) {
+			error = ENOMEM;
+			VOP_UNLOCK(dvp, 0);
+			goto out;
+		}
+		buflen -= 1;
+		memcpy(buf+buflen, "/", 1);
+		*retbuf = buf+buflen;
+
+		if (dvp == rdir) {
+			/* Reached (relative) root directory. */
+			VOP_UNLOCK(dvp, 0);
+			break;
+		}
+
+		if (dvp->v_vflag & VV_ROOT) {
+			/* Crossing filesystems. */
+			dvp2 = dvp->v_mount->mnt_vnodecovered;
+			VOP_UNLOCK(dvp, 0);
+			vn_lock(dvp2, LK_SHARED | LK_RETRY);
+			dvp = dvp2;
+		}
+
+		/* Get inode number of directory. */
+		error = VOP_GETATTR(dvp, &vattr, td->td_ucred);
+		if (error != 0) {
+			VOP_UNLOCK(dvp, 0);
+			goto out;
+		}
+		inodenum = vattr.va_fileid;
+
+		/* Lookup "..". */
+		cnp.cn_pnbuf = NULL;
+		cnp.cn_consume = 0;
+		cnp.cn_nameptr = "..";
+		cnp.cn_namelen = 2;
+		cnp.cn_lkflags = LK_SHARED;
+		cnp.cn_thread = curthread;
+		cnp.cn_cred = td->td_ucred;
+		error = VOP_LOOKUP(dvp, &dvp2, &cnp);
+		if (error != 0) {
+			VOP_UNLOCK(dvp, 0);
+			goto out;
+		}
+
+		vunref(dvp2);
+		VOP_UNLOCK(dvp, 0);
+		dvp = dvp2;
+
+		cpos = NULL;
+		off = 0;
+		len = 0;
+		error = ENOENT;
+
+		do {
+			error = get_next_dirent(dvp2, &dp, dirbuf, dirbuflen,
+			    &off, &cpos, &len, &eofflag, td);	
+			if (error != 0) {
+				VOP_UNLOCK(dvp2, 0);
+				goto out;
+			}
+
+			if (dp->d_fileno == inodenum) {
+				/* Found it ! */
+				if (buflen < strlen(dp->d_name)) {
+					error = ENOMEM;
+					VOP_UNLOCK(dvp2, 0);
+					goto out;
+				}
+				buflen -= strlen(dp->d_name);
+				memcpy(buf+buflen, dp->d_name, strlen(dp->d_name));
+				break;
+			}
+			error = ENOENT;
+		} while (len > 0 || !eofflag);
+	}
+
+  out:
+	free(dirbuf, M_TEMP);
+
+	return (error);
+}
+
+int
+vn_fullpath1_failsafe(struct thread *td, struct vnode *vp,
+     struct vnode *rdir, char *buf, char **retbuf, u_int buflen)
+{
+	int error;
+
+	error = vn_fullpath1(td, vp, rdir, buf, retbuf, buflen);
+	if (error != ENOENT)
+		return (error);
+
+	error = vn_fullpath1_fallback(td, vp, rdir, buf, retbuf, buflen);
+
+	return (error);
+}
+
+/* ----------------------------------------------------------- */
+
 struct vnode *
 vn_dir_dd_ino(struct vnode *vp)
 {

Modified: projects/vps/sys/kern/vfs_default.c
==============================================================================
--- projects/vps/sys/kern/vfs_default.c	Wed Oct 23 17:17:57 2013	(r256992)
+++ projects/vps/sys/kern/vfs_default.c	Wed Oct 23 17:18:53 2013	(r256993)
@@ -69,10 +69,6 @@ __FBSDID("$FreeBSD$");
 static int	vop_nolookup(struct vop_lookup_args *);
 static int	vop_norename(struct vop_rename_args *);
 static int	vop_nostrategy(struct vop_strategy_args *);
-static int	get_next_dirent(struct vnode *vp, struct dirent **dpp,
-				char *dirbuf, int dirbuflen, off_t *off,
-				char **cpos, int *len, int *eofflag,
-				struct thread *td);
 static int	dirent_exists(struct vnode *vp, const char *dirname,
 			      struct thread *td);
 
@@ -261,7 +257,7 @@ vop_nostrategy (struct vop_strategy_args
 	return (EOPNOTSUPP);
 }
 
-static int
+int
 get_next_dirent(struct vnode *vp, struct dirent **dpp, char *dirbuf,
 		int dirbuflen, off_t *off, char **cpos, int *len,
 		int *eofflag, struct thread *td)

Modified: projects/vps/sys/sys/vnode.h
==============================================================================
--- projects/vps/sys/sys/vnode.h	Wed Oct 23 17:17:57 2013	(r256992)
+++ projects/vps/sys/sys/vnode.h	Wed Oct 23 17:18:53 2013	(r256993)
@@ -577,6 +577,7 @@ vn_canvmio(struct vnode *vp)
  * Public vnode manipulation functions.
  */
 struct componentname;
+struct dirent;
 struct file;
 struct mount;
 struct nameidata;
@@ -609,6 +610,10 @@ int	getnewvnode(const char *tag, struct 
 	    struct vnode **vpp);
 void	getnewvnode_reserve(u_int count);
 void	getnewvnode_drop_reserve(void);
+int	get_next_dirent(struct vnode *vp, struct dirent **dpp,
+	    char *dirbuf, int dirbuflen, off_t *off,
+	    char **cpos, int *len, int *eofflag,
+	    struct thread *td);
 int	insmntque1(struct vnode *vp, struct mount *mp,
 	    void (*dtr)(struct vnode *, void *), void *dtr_arg);
 int	insmntque(struct vnode *vp, struct mount *mp);
@@ -659,6 +664,8 @@ int	vn_close(struct vnode *vp,
 	    int flags, struct ucred *file_cred, struct thread *td);
 void	vn_finished_write(struct mount *mp);
 void	vn_finished_secondary_write(struct mount *mp);
+int	vn_fullpath1_failsafe(struct thread *td, struct vnode *vp,
+	    struct vnode *rdir, char *buf, char **retbuf, u_int buflen);
 int	vn_isdisk(struct vnode *vp, int *errp);
 int	_vn_lock(struct vnode *vp, int flags, char *file, int line);
 #define vn_lock(vp, flags) _vn_lock(vp, flags, __FILE__, __LINE__)

Modified: projects/vps/sys/vps/vps_snapst.c
==============================================================================
--- projects/vps/sys/vps/vps_snapst.c	Wed Oct 23 17:17:57 2013	(r256992)
+++ projects/vps/sys/vps/vps_snapst.c	Wed Oct 23 17:18:53 2013	(r256993)
@@ -656,6 +656,11 @@ vps_snapshot_vnodepath(struct vps_snapst
 {
 	struct vps_dumpobj *o1;
 	struct vps_dump_filepath *vdfp;
+	/*
+	struct ucred *save_ucred;
+	struct vps *save_vps;
+	struct thread *td;
+	*/
 	char *retbuf, *buf;
 	int error;
 
@@ -671,9 +676,29 @@ vps_snapshot_vnodepath(struct vps_snapst
 		vrele(vp);
 		return (ENOMEM);
 	}
+
+#if 0
+// not yet ... for devfs lookups
+	td = curthread;
+	save_ucred = td->td_ucred;
+	save_vps = td->td_vps;
+	td->td_ucred = crdup(save_ucred);
+	vps_deref(td->td_ucred->cr_vps, td->td_ucred);
+	td->td_ucred->cr_vps = vps;
+	vps_ref(td->td_ucred->cr_vps, td->td_ucred);
+	td->td_vps = vps;
+#endif
+	
 	retbuf = "-";
-	error = vn_fullpath1(curthread, vp, vps->_rootvnode,
+	error = vn_fullpath1_failsafe(curthread, vp, vps->_rootvnode,
 				buf, &retbuf, MAXPATHLEN);
+
+#if 0
+	crfree(td->td_ucred);
+	td->td_ucred = save_ucred;
+	td->td_vps = save_vps;
+#endif
+
 	if (error != 0) {
 		free(buf, M_TEMP);
 		vrele(vp);

Modified: projects/vps/sys/vps/vps_suspend.c
==============================================================================
--- projects/vps/sys/vps/vps_suspend.c	Wed Oct 23 17:17:57 2013	(r256992)
+++ projects/vps/sys/vps/vps_suspend.c	Wed Oct 23 17:18:53 2013	(r256993)
@@ -118,9 +118,6 @@ static int vps_access_vmspace(struct vms
     size_t len, void *buf, int prot);
 
 static int vps_resume_relinkvnodes(struct vps *vps);
-static int get_next_dirent(struct vnode *vp, struct dirent **dpp,
-    char *dirbuf, int dirbuflen, off_t *off, char **cpos,
-    int *len, int *eofflag, struct thread *td);
 static int vps_suspend_relink_delete(struct vnode *vp);
 
 static int vps_suspend_mod_refcnt;
@@ -981,65 +978,6 @@ vps_suspend_relink_delete(struct vnode *
 	return (error);
 }
 
-#define DIRENT_MINSIZE (sizeof(struct dirent) - (MAXNAMLEN+1) + 4)
-
-/* copied from kern/vfs_default.c */
-static int
-get_next_dirent(struct vnode *vp, struct dirent **dpp, char *dirbuf,
-                int dirbuflen, off_t *off, char **cpos, int *len,
-                int *eofflag, struct thread *td)
-{
-        int error, reclen;
-        struct uio uio;
-        struct iovec iov;
-        struct dirent *dp;
-
-        KASSERT(VOP_ISLOCKED(vp), ("vp %p is not locked", vp));
-        KASSERT(vp->v_type == VDIR, ("vp %p is not a directory", vp));
-
-        if (*len == 0) {
-                iov.iov_base = dirbuf;
-                iov.iov_len = dirbuflen;
-
-                uio.uio_iov = &iov;
-                uio.uio_iovcnt = 1;
-                uio.uio_offset = *off;
-                uio.uio_resid = dirbuflen;
-                uio.uio_segflg = UIO_SYSSPACE;
-                uio.uio_rw = UIO_READ;
-                uio.uio_td = td;
-
-                *eofflag = 0;
-
-#ifdef MAC
-                error = mac_vnode_check_readdir(td->td_ucred, vp);
-                if (error == 0)
-#endif
-                        error = VOP_READDIR(vp, &uio, td->td_ucred, eofflag,
-                                NULL, NULL);
-                if (error)
-                        return (error);
-
-                *off = uio.uio_offset;
-
-                *cpos = dirbuf;
-                *len = (dirbuflen - uio.uio_resid);
-        }
-
-        dp = (struct dirent *)(*cpos);
-        reclen = dp->d_reclen;
-        *dpp = dp;
-
-        /* check for malformed directory.. */
-        if (reclen < DIRENT_MINSIZE)
-                return (EINVAL);
-
-        *cpos += reclen;
-        *len -= reclen;
-
-        return (0);
-}
-
 static int
 vps_suspend_modevent(module_t mod, int type, void *data)
 {



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201310231718.r9NHIso4065429>