Revert "[PATCH] Fix d_path for lazy unmounts"

This reverts commit eb3dfb0cb1.

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: walt <wa1ter@myrealbox.com>
Reported-by: Greg KH <greg@kroah.com>
Acked-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Linus Torvalds 2007-02-13 12:08:18 -08:00
parent ec2f9d1331
commit 552ce544ed

View file

@ -1739,41 +1739,45 @@ shouldnt_be_hashed:
* @rootmnt: vfsmnt to which the root dentry belongs * @rootmnt: vfsmnt to which the root dentry belongs
* @buffer: buffer to return value in * @buffer: buffer to return value in
* @buflen: buffer length * @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, * 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 string " (deleted)" is appended. Note that this is ambiguous.
* the 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, static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt,
struct dentry *root, struct vfsmount *rootmnt, struct dentry *root, struct vfsmount *rootmnt,
char *buffer, int buflen, int fail_deleted) char *buffer, int buflen)
{ {
int namelen, is_slash; char * end = buffer+buflen;
char * retval;
int namelen;
if (buflen < 2) *--end = '\0';
return ERR_PTR(-ENAMETOOLONG); buflen--;
buffer += --buflen;
*buffer = '\0';
spin_lock(&dcache_lock);
if (!IS_ROOT(dentry) && d_unhashed(dentry)) { if (!IS_ROOT(dentry) && d_unhashed(dentry)) {
if (fail_deleted) {
buffer = ERR_PTR(-ENOENT);
goto out;
}
if (buflen < 10)
goto Elong;
buflen -= 10; buflen -= 10;
buffer -= 10; end -= 10;
memcpy(buffer, " (deleted)", 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; struct dentry * parent;
if (dentry == root && vfsmnt == rootmnt)
break;
if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
/* Global root? */
spin_lock(&vfsmount_lock); spin_lock(&vfsmount_lock);
if (vfsmnt->mnt_parent == vfsmnt) { if (vfsmnt->mnt_parent == vfsmnt) {
spin_unlock(&vfsmount_lock); spin_unlock(&vfsmount_lock);
@ -1787,60 +1791,33 @@ static char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
parent = dentry->d_parent; parent = dentry->d_parent;
prefetch(parent); prefetch(parent);
namelen = dentry->d_name.len; namelen = dentry->d_name.len;
if (buflen <= namelen)
goto Elong;
buflen -= namelen + 1; buflen -= namelen + 1;
buffer -= namelen; if (buflen < 0)
memcpy(buffer, dentry->d_name.name, namelen); goto Elong;
*--buffer = '/'; end -= namelen;
memcpy(end, dentry->d_name.name, namelen);
*--end = '/';
retval = end;
dentry = parent; dentry = parent;
} }
/* Get '/' right */
if (*buffer != '/')
*--buffer = '/';
out: return retval;
spin_unlock(&dcache_lock);
return buffer;
global_root: 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; namelen = dentry->d_name.len;
is_slash = (namelen == 1 && *dentry->d_name.name == '/'); buflen -= namelen;
if (is_slash || (dentry->d_sb->s_flags & MS_NOUSER)) { if (buflen < 0)
/*
* 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)
goto Elong; goto Elong;
buffer -= namelen; retval -= namelen-1; /* hit the slash */
memcpy(buffer, dentry->d_name.name, namelen); memcpy(retval, dentry->d_name.name, namelen);
goto out; return retval;
Elong: Elong:
buffer = ERR_PTR(-ENAMETOOLONG); return ERR_PTR(-ENAMETOOLONG);
goto out;
} }
/* write full pathname into buffer and return start of pathname */ /* write full pathname into buffer and return start of pathname */
char *d_path(struct dentry *dentry, struct vfsmount *vfsmnt, char *buf, char * d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
int buflen) char *buf, int buflen)
{ {
char *res; char *res;
struct vfsmount *rootmnt; struct vfsmount *rootmnt;
@ -1850,7 +1827,9 @@ char *d_path(struct dentry *dentry, struct vfsmount *vfsmnt, char *buf,
rootmnt = mntget(current->fs->rootmnt); rootmnt = mntget(current->fs->rootmnt);
root = dget(current->fs->root); root = dget(current->fs->root);
read_unlock(&current->fs->lock); 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); dput(root);
mntput(rootmnt); mntput(rootmnt);
return res; 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) asmlinkage long sys_getcwd(char __user *buf, unsigned long size)
{ {
int error, len; int error;
struct vfsmount *pwdmnt, *rootmnt; struct vfsmount *pwdmnt, *rootmnt;
struct dentry *pwd, *root; struct dentry *pwd, *root;
char *page = (char *) __get_free_page(GFP_USER), *cwd; char *page = (char *) __get_free_page(GFP_USER);
if (!page) if (!page)
return -ENOMEM; return -ENOMEM;
@ -1891,7 +1870,16 @@ asmlinkage long sys_getcwd(char __user *buf, unsigned long size)
root = dget(current->fs->root); root = dget(current->fs->root);
read_unlock(&current->fs->lock); 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); error = PTR_ERR(cwd);
if (IS_ERR(cwd)) if (IS_ERR(cwd))
goto out; goto out;
@ -1903,6 +1891,8 @@ asmlinkage long sys_getcwd(char __user *buf, unsigned long size)
if (copy_to_user(buf, cwd, len)) if (copy_to_user(buf, cwd, len))
error = -EFAULT; error = -EFAULT;
} }
} else
spin_unlock(&dcache_lock);
out: out:
dput(pwd); dput(pwd);