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:
		
							parent
							
								
									ec2f9d1331
								
							
						
					
					
						commit
						552ce544ed
					
				
							
								
								
									
										150
									
								
								fs/dcache.c
									
									
									
									
									
								
							
							
						
						
									
										150
									
								
								fs/dcache.c
									
									
									
									
									
								
							| @ -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) | ||||
| static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt, | ||||
| 			struct dentry *root, struct vfsmount *rootmnt, | ||||
| 			char *buffer, int buflen) | ||||
| { | ||||
| 	int namelen, is_slash; | ||||
| 	char * end = buffer+buflen; | ||||
| 	char * retval; | ||||
| 	int namelen; | ||||
| 
 | ||||
| 	if (buflen < 2) | ||||
| 		return ERR_PTR(-ENAMETOOLONG); | ||||
| 	buffer += --buflen; | ||||
| 	*buffer = '\0'; | ||||
| 
 | ||||
| 	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(¤t->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,18 +1870,29 @@ asmlinkage long sys_getcwd(char __user *buf, unsigned long size) | ||||
| 	root = dget(current->fs->root); | ||||
| 	read_unlock(¤t->fs->lock); | ||||
| 
 | ||||
| 	cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE, 1); | ||||
| 	error = PTR_ERR(cwd); | ||||
| 	if (IS_ERR(cwd)) | ||||
| 		goto out; | ||||
| 	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; | ||||
| 
 | ||||
| 	error = -ERANGE; | ||||
| 	len = PAGE_SIZE + page - cwd; | ||||
| 	if (len <= size) { | ||||
| 		error = len; | ||||
| 		if (copy_to_user(buf, cwd, len)) | ||||
| 			error = -EFAULT; | ||||
| 	} | ||||
| 		cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE); | ||||
| 		spin_unlock(&dcache_lock); | ||||
| 
 | ||||
| 		error = PTR_ERR(cwd); | ||||
| 		if (IS_ERR(cwd)) | ||||
| 			goto out; | ||||
| 
 | ||||
| 		error = -ERANGE; | ||||
| 		len = PAGE_SIZE + page - cwd; | ||||
| 		if (len <= size) { | ||||
| 			error = len; | ||||
| 			if (copy_to_user(buf, cwd, len)) | ||||
| 				error = -EFAULT; | ||||
| 		} | ||||
| 	} else | ||||
| 		spin_unlock(&dcache_lock); | ||||
| 
 | ||||
| out: | ||||
| 	dput(pwd); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user