diff options
Diffstat (limited to 'fs/dcache.c')
| -rw-r--r-- | fs/dcache.c | 68 | 
1 files changed, 34 insertions, 34 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index 3ee588d5f58..6068c25b393 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -17,6 +17,7 @@  #include <linux/syscalls.h>  #include <linux/string.h>  #include <linux/mm.h> +#include <linux/fdtable.h>  #include <linux/fs.h>  #include <linux/fsnotify.h>  #include <linux/slab.h> @@ -106,9 +107,10 @@ static void dentry_lru_remove(struct dentry *dentry)  /*   * Release the dentry's inode, using the filesystem   * d_iput() operation if defined. - * Called with dcache_lock and per dentry lock held, drops both.   */  static void dentry_iput(struct dentry * dentry) +	__releases(dentry->d_lock) +	__releases(dcache_lock)  {  	struct inode *inode = dentry->d_inode;  	if (inode) { @@ -132,12 +134,13 @@ static void dentry_iput(struct dentry * dentry)   * d_kill - kill dentry and return parent   * @dentry: dentry to kill   * - * Called with dcache_lock and d_lock, releases both.  The dentry must - * already be unhashed and removed from the LRU. + * The dentry must already be unhashed and removed from the LRU.   *   * If this is the root of the dentry tree, return NULL.   */  static struct dentry *d_kill(struct dentry *dentry) +	__releases(dentry->d_lock) +	__releases(dcache_lock)  {  	struct dentry *parent; @@ -383,11 +386,11 @@ restart:   * Try to prune ancestors as well.  This is necessary to prevent   * quadratic behavior of shrink_dcache_parent(), but is also expected   * to be beneficial in reducing dentry cache fragmentation. - * - * Called with dcache_lock, drops it and then regains. - * Called with dentry->d_lock held, drops it.   */  static void prune_one_dentry(struct dentry * dentry) +	__releases(dentry->d_lock) +	__releases(dcache_lock) +	__acquires(dcache_lock)  {  	__d_drop(dentry);  	dentry = d_kill(dentry); @@ -1604,10 +1607,9 @@ static int d_isparent(struct dentry *p1, struct dentry *p2)   *   * Note: If ever the locking in lock_rename() changes, then please   * remember to update this too... - * - * On return, dcache_lock will have been unlocked.   */  static struct dentry *__d_unalias(struct dentry *dentry, struct dentry *alias) +	__releases(dcache_lock)  {  	struct mutex *m1 = NULL, *m2 = NULL;  	struct dentry *ret; @@ -1743,11 +1745,9 @@ out_nolock:  shouldnt_be_hashed:  	spin_unlock(&dcache_lock);  	BUG(); -	goto shouldnt_be_hashed;  } -static int prepend(char **buffer, int *buflen, const char *str, -			  int namelen) +static int prepend(char **buffer, int *buflen, const char *str, int namelen)  {  	*buflen -= namelen;  	if (*buflen < 0) @@ -1757,8 +1757,13 @@ static int prepend(char **buffer, int *buflen, const char *str,  	return 0;  } +static int prepend_name(char **buffer, int *buflen, struct qstr *name) +{ +	return prepend(buffer, buflen, name->name, name->len); +} +  /** - * d_path - return the path of a dentry + * __d_path - return the path of a dentry   * @path: the dentry/vfsmount to report   * @root: root vfsmnt/dentry (may be modified by this function)   * @buffer: buffer to return value in @@ -1779,9 +1784,10 @@ char *__d_path(const struct path *path, struct path *root,  {  	struct dentry *dentry = path->dentry;  	struct vfsmount *vfsmnt = path->mnt; -	char * end = buffer+buflen; -	char * retval; +	char *end = buffer + buflen; +	char *retval; +	spin_lock(&vfsmount_lock);  	prepend(&end, &buflen, "\0", 1);  	if (!IS_ROOT(dentry) && d_unhashed(dentry) &&  		(prepend(&end, &buflen, " (deleted)", 10) != 0)) @@ -1800,38 +1806,37 @@ char *__d_path(const struct path *path, struct path *root,  			break;  		if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {  			/* Global root? */ -			spin_lock(&vfsmount_lock);  			if (vfsmnt->mnt_parent == vfsmnt) { -				spin_unlock(&vfsmount_lock);  				goto global_root;  			}  			dentry = vfsmnt->mnt_mountpoint;  			vfsmnt = vfsmnt->mnt_parent; -			spin_unlock(&vfsmount_lock);  			continue;  		}  		parent = dentry->d_parent;  		prefetch(parent); -		if ((prepend(&end, &buflen, dentry->d_name.name, -				dentry->d_name.len) != 0) || +		if ((prepend_name(&end, &buflen, &dentry->d_name) != 0) ||  		    (prepend(&end, &buflen, "/", 1) != 0))  			goto Elong;  		retval = end;  		dentry = parent;  	} +out: +	spin_unlock(&vfsmount_lock);  	return retval;  global_root:  	retval += 1;	/* hit the slash */ -	if (prepend(&retval, &buflen, dentry->d_name.name, -		    dentry->d_name.len) != 0) +	if (prepend_name(&retval, &buflen, &dentry->d_name) != 0)  		goto Elong;  	root->mnt = vfsmnt;  	root->dentry = dentry; -	return retval; +	goto out; +  Elong: -	return ERR_PTR(-ENAMETOOLONG); +	retval = ERR_PTR(-ENAMETOOLONG); +	goto out;  }  /** @@ -1845,9 +1850,9 @@ Elong:   *   * Returns the buffer or an error code if the path was too long.   * - * "buflen" should be positive. Caller holds the dcache_lock. + * "buflen" should be positive.   */ -char *d_path(struct path *path, char *buf, int buflen) +char *d_path(const struct path *path, char *buf, int buflen)  {  	char *res;  	struct path root; @@ -1915,16 +1920,11 @@ char *dentry_path(struct dentry *dentry, char *buf, int buflen)  	retval = end-1;  	*retval = '/'; -	for (;;) { -		struct dentry *parent; -		if (IS_ROOT(dentry)) -			break; +	while (!IS_ROOT(dentry)) { +		struct dentry *parent = dentry->d_parent; -		parent = dentry->d_parent;  		prefetch(parent); - -		if ((prepend(&end, &buflen, dentry->d_name.name, -				dentry->d_name.len) != 0) || +		if ((prepend_name(&end, &buflen, &dentry->d_name) != 0) ||  		    (prepend(&end, &buflen, "/", 1) != 0))  			goto Elong; @@ -1975,7 +1975,7 @@ asmlinkage long sys_getcwd(char __user *buf, unsigned long size)  	error = -ENOENT;  	/* Has the current directory has been unlinked? */  	spin_lock(&dcache_lock); -	if (pwd.dentry->d_parent == pwd.dentry || !d_unhashed(pwd.dentry)) { +	if (IS_ROOT(pwd.dentry) || !d_unhashed(pwd.dentry)) {  		unsigned long len;  		struct path tmp = root;  		char * cwd;  |