Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 552ce544 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Revert "[PATCH] Fix d_path for lazy unmounts"



This reverts commit eb3dfb0c.

It causes some strange Gnome problem with dbus-daemon getting stuck, so
we'll revert it until that problem is understood.

Reported by both walt and Greg KH, who both independently git-bisected
the problem to this commit.

Andreas is looking at it.

Reported-by: default avatarwalt <wa1ter@myrealbox.com>
Reported-by: default avatarGreg KH <greg@kroah.com>
Acked-by: default avatarAndreas Gruenbacher <agruen@suse.de>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent ec2f9d13
Loading
Loading
Loading
Loading
+70 −80
Original line number Diff line number Diff line
@@ -1739,41 +1739,45 @@ shouldnt_be_hashed:
 * @rootmnt: vfsmnt to which the root dentry belongs
 * @buffer: buffer to return value in
 * @buflen: buffer length
 * @fail_deleted: what to return for deleted files
 *
 * Convert a dentry into an ASCII path name. If the entry has been deleted,
 * then if @fail_deleted is true, ERR_PTR(-ENOENT) is returned. Otherwise,
 * the the string " (deleted)" is appended. Note that this is ambiguous.
 * Convert a dentry into an ASCII path name. If the entry has been deleted
 * the string " (deleted)" is appended. Note that this is ambiguous.
 *
 * Returns the buffer or an error code.
 * Returns the buffer or an error code if the path was too long.
 *
 * "buflen" should be positive. Caller holds the dcache_lock.
 */
static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt,
			struct dentry *root, struct vfsmount *rootmnt,
		      char *buffer, int buflen, int fail_deleted)
			char *buffer, int buflen)
{
	int namelen, is_slash;

	if (buflen < 2)
		return ERR_PTR(-ENAMETOOLONG);
	buffer += --buflen;
	*buffer = '\0';
	char * end = buffer+buflen;
	char * retval;
	int namelen;

	spin_lock(&dcache_lock);
	*--end = '\0';
	buflen--;
	if (!IS_ROOT(dentry) && d_unhashed(dentry)) {
		if (fail_deleted) {
			buffer = ERR_PTR(-ENOENT);
			goto out;
		}
		if (buflen < 10)
			goto Elong;
		buflen -= 10;
		buffer -= 10;
		memcpy(buffer, " (deleted)", 10);
		end -= 10;
		if (buflen < 0)
			goto Elong;
		memcpy(end, " (deleted)", 10);
	}
	while (dentry != root || vfsmnt != rootmnt) {

	if (buflen < 1)
		goto Elong;
	/* Get '/' right */
	retval = end-1;
	*retval = '/';

	for (;;) {
		struct dentry * parent;

		if (dentry == root && vfsmnt == rootmnt)
			break;
		if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
			/* Global root? */
			spin_lock(&vfsmount_lock);
			if (vfsmnt->mnt_parent == vfsmnt) {
				spin_unlock(&vfsmount_lock);
@@ -1787,60 +1791,33 @@ static char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
		parent = dentry->d_parent;
		prefetch(parent);
		namelen = dentry->d_name.len;
		if (buflen <= namelen)
			goto Elong;
		buflen -= namelen + 1;
		buffer -= namelen;
		memcpy(buffer, dentry->d_name.name, namelen);
		*--buffer = '/';
		if (buflen < 0)
			goto Elong;
		end -= namelen;
		memcpy(end, dentry->d_name.name, namelen);
		*--end = '/';
		retval = end;
		dentry = parent;
	}
	/* Get '/' right */
	if (*buffer != '/')
		*--buffer = '/';

out:
	spin_unlock(&dcache_lock);
	return buffer;
	return retval;

global_root:
	/*
	 * We went past the (vfsmount, dentry) we were looking for and have
	 * either hit a root dentry, a lazily unmounted dentry, an
	 * unconnected dentry, or the file is on a pseudo filesystem.
	 */
	namelen = dentry->d_name.len;
	is_slash = (namelen == 1 && *dentry->d_name.name == '/');
	if (is_slash || (dentry->d_sb->s_flags & MS_NOUSER)) {
		/*
		 * Make sure we won't return a pathname starting with '/'.
		 *
		 * Historically, we also glue together the root dentry and
		 * remaining name for pseudo filesystems like pipefs, which
		 * have the MS_NOUSER flag set. This results in pathnames
		 * like "pipe:[439336]".
		 */
		if (*buffer == '/') {
			buffer++;
			buflen++;
		}
		if (is_slash)
			goto out;
	}
	if (buflen < namelen)
	buflen -= namelen;
	if (buflen < 0)
		goto Elong;
	buffer -= namelen;
	memcpy(buffer, dentry->d_name.name, namelen);
	goto out;

	retval -= namelen-1;	/* hit the slash */
	memcpy(retval, dentry->d_name.name, namelen);
	return retval;
Elong:
	buffer = ERR_PTR(-ENAMETOOLONG);
	goto out;
	return ERR_PTR(-ENAMETOOLONG);
}

/* write full pathname into buffer and return start of pathname */
char *d_path(struct dentry *dentry, struct vfsmount *vfsmnt, char *buf,
	     int buflen)
char * d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
				char *buf, int buflen)
{
	char *res;
	struct vfsmount *rootmnt;
@@ -1850,7 +1827,9 @@ char *d_path(struct dentry *dentry, struct vfsmount *vfsmnt, char *buf,
	rootmnt = mntget(current->fs->rootmnt);
	root = dget(current->fs->root);
	read_unlock(&current->fs->lock);
	res = __d_path(dentry, vfsmnt, root, rootmnt, buf, buflen, 0);
	spin_lock(&dcache_lock);
	res = __d_path(dentry, vfsmnt, root, rootmnt, buf, buflen);
	spin_unlock(&dcache_lock);
	dput(root);
	mntput(rootmnt);
	return res;
@@ -1876,10 +1855,10 @@ char *d_path(struct dentry *dentry, struct vfsmount *vfsmnt, char *buf,
 */
asmlinkage long sys_getcwd(char __user *buf, unsigned long size)
{
	int error, len;
	int error;
	struct vfsmount *pwdmnt, *rootmnt;
	struct dentry *pwd, *root;
	char *page = (char *) __get_free_page(GFP_USER), *cwd;
	char *page = (char *) __get_free_page(GFP_USER);

	if (!page)
		return -ENOMEM;
@@ -1891,7 +1870,16 @@ asmlinkage long sys_getcwd(char __user *buf, unsigned long size)
	root = dget(current->fs->root);
	read_unlock(&current->fs->lock);

	cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE, 1);
	error = -ENOENT;
	/* Has the current directory has been unlinked? */
	spin_lock(&dcache_lock);
	if (pwd->d_parent == pwd || !d_unhashed(pwd)) {
		unsigned long len;
		char * cwd;

		cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE);
		spin_unlock(&dcache_lock);

		error = PTR_ERR(cwd);
		if (IS_ERR(cwd))
			goto out;
@@ -1903,6 +1891,8 @@ asmlinkage long sys_getcwd(char __user *buf, unsigned long size)
			if (copy_to_user(buf, cwd, len))
				error = -EFAULT;
		}
	} else
		spin_unlock(&dcache_lock);

out:
	dput(pwd);