diff options
40 files changed, 108 insertions, 306 deletions
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index a15ee207b44..bdad6414dfa 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking @@ -21,14 +21,14 @@ prototypes:  	char *(*d_dname)((struct dentry *dentry, char *buffer, int buflen);  locking rules: -		dcache_lock	rename_lock	->d_lock	may block -d_revalidate:	no		no		no		yes -d_hash		no		no		no		no -d_compare:	no		yes		no		no  -d_delete:	yes		no		yes		no -d_release:	no		no		no		yes -d_iput:		no		no		no		yes -d_dname:	no		no		no		no +		rename_lock	->d_lock	may block +d_revalidate:	no		no		yes +d_hash		no		no		no +d_compare:	yes		no		no +d_delete:	no		yes		no +d_release:	no		no		yes +d_iput:		no		no		yes +d_dname:	no		no		no  --------------------------- inode_operations ---------------------------   prototypes: diff --git a/Documentation/filesystems/dentry-locking.txt b/Documentation/filesystems/dentry-locking.txt index 79334ed5daa..30b6a40f565 100644 --- a/Documentation/filesystems/dentry-locking.txt +++ b/Documentation/filesystems/dentry-locking.txt @@ -31,6 +31,7 @@ significant change is the way d_lookup traverses the hash chain, it  doesn't acquire the dcache_lock for this and rely on RCU to ensure  that the dentry has not been *freed*. +dcache_lock no longer exists, dentry locking is explained in fs/dcache.c  Dcache locking details  ====================== @@ -50,14 +51,12 @@ Safe lock-free look-up of dcache hash table  Dcache is a complex data structure with the hash table entries also  linked together in other lists. In 2.4 kernel, dcache_lock protected -all the lists. We applied RCU only on hash chain walking. The rest of -the lists are still protected by dcache_lock.  Some of the important -changes are : +all the lists. RCU dentry hash walking works like this:  1. The deletion from hash chain is done using hlist_del_rcu() macro     which doesn't initialize next pointer of the deleted dentry and     this allows us to walk safely lock-free while a deletion is -   happening. +   happening. This is a standard hlist_rcu iteration.  2. Insertion of a dentry into the hash table is done using     hlist_add_head_rcu() which take care of ordering the writes - the @@ -66,19 +65,18 @@ changes are :     which has since been replaced by hlist_for_each_entry_rcu(), while     walking the hash chain. The only requirement is that all     initialization to the dentry must be done before -   hlist_add_head_rcu() since we don't have dcache_lock protection -   while traversing the hash chain. This isn't different from the -   existing code. +   hlist_add_head_rcu() since we don't have lock protection +   while traversing the hash chain. -3. The dentry looked up without holding dcache_lock by cannot be -   returned for walking if it is unhashed. It then may have a NULL -   d_inode or other bogosity since RCU doesn't protect the other -   fields in the dentry. We therefore use a flag DCACHE_UNHASHED to -   indicate unhashed dentries and use this in conjunction with a -   per-dentry lock (d_lock). Once looked up without the dcache_lock, -   we acquire the per-dentry lock (d_lock) and check if the dentry is -   unhashed. If so, the look-up is failed. If not, the reference count -   of the dentry is increased and the dentry is returned. +3. The dentry looked up without holding locks cannot be returned for +   walking if it is unhashed. It then may have a NULL d_inode or other +   bogosity since RCU doesn't protect the other fields in the dentry. We +   therefore use a flag DCACHE_UNHASHED to indicate unhashed dentries +   and use this in conjunction with a per-dentry lock (d_lock). Once +   looked up without locks, we acquire the per-dentry lock (d_lock) and +   check if the dentry is unhashed. If so, the look-up is failed. If not, +   the reference count of the dentry is increased and the dentry is +   returned.  4. Once a dentry is looked up, it must be ensured during the path walk     for that component it doesn't go away. In pre-2.5.10 code, this was @@ -86,10 +84,10 @@ changes are :     In some sense, dcache_rcu path walking looks like the pre-2.5.10     version. -5. All dentry hash chain updates must take the dcache_lock as well as -   the per-dentry lock in that order. dput() does this to ensure that -   a dentry that has just been looked up in another CPU doesn't get -   deleted before dget() can be done on it. +5. All dentry hash chain updates must take the per-dentry lock (see +   fs/dcache.c). This excludes dput() to ensure that a dentry that has +   been looked up concurrently does not get deleted before dget() can +   take a ref.  6. There are several ways to do reference counting of RCU protected     objects. One such example is in ipv4 route cache where deferred diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting index 9fd31940a8e..1eb76959d09 100644 --- a/Documentation/filesystems/porting +++ b/Documentation/filesystems/porting @@ -216,7 +216,6 @@ had ->revalidate()) add calls in ->follow_link()/->readlink().  ->d_parent changes are not protected by BKL anymore.  Read access is safe  if at least one of the following is true:  	* filesystem has no cross-directory rename() -	* dcache_lock is held  	* we know that parent had been locked (e.g. we are looking at  ->d_parent of ->lookup() argument).  	* we are called from ->rename(). @@ -340,3 +339,10 @@ look at examples of other filesystems) for guidance.  	.d_hash() calling convention and locking rules are significantly  changed. Read updated documentation in Documentation/filesystems/vfs.txt (and  look at examples of other filesystems) for guidance. + +--- +[mandatory] +	dcache_lock is gone, replaced by fine grained locks. See fs/dcache.c +for details of what locks to replace dcache_lock with in order to protect +particular things. Most of the time, a filesystem only needs ->d_lock, which +protects *all* the dcache state of a given dentry. diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index 5aef1a7f5e4..2662b50ea8d 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -159,21 +159,18 @@ static void spufs_prune_dir(struct dentry *dir)  	mutex_lock(&dir->d_inode->i_mutex);  	list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_u.d_child) { -		spin_lock(&dcache_lock);  		spin_lock(&dentry->d_lock);  		if (!(d_unhashed(dentry)) && dentry->d_inode) {  			dget_locked_dlock(dentry);  			__d_drop(dentry);  			spin_unlock(&dentry->d_lock);  			simple_unlink(dir->d_inode, dentry); -			/* XXX: what is dcache_lock protecting here? Other +			/* XXX: what was dcache_lock protecting here? Other  			 * filesystems (IB, configfs) release dcache_lock  			 * before unlink */ -			spin_unlock(&dcache_lock);  			dput(dentry);  		} else {  			spin_unlock(&dentry->d_lock); -			spin_unlock(&dcache_lock);  		}  	}  	shrink_dcache_parent(dir); diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c index 18aee04a841..925e88227de 100644 --- a/drivers/infiniband/hw/ipath/ipath_fs.c +++ b/drivers/infiniband/hw/ipath/ipath_fs.c @@ -277,18 +277,14 @@ static int remove_file(struct dentry *parent, char *name)  		goto bail;  	} -	spin_lock(&dcache_lock);  	spin_lock(&tmp->d_lock);  	if (!(d_unhashed(tmp) && tmp->d_inode)) {  		dget_locked_dlock(tmp);  		__d_drop(tmp);  		spin_unlock(&tmp->d_lock); -		spin_unlock(&dcache_lock);  		simple_unlink(parent->d_inode, tmp); -	} else { +	} else  		spin_unlock(&tmp->d_lock); -		spin_unlock(&dcache_lock); -	}  	ret = 0;  bail: diff --git a/drivers/infiniband/hw/qib/qib_fs.c b/drivers/infiniband/hw/qib/qib_fs.c index fe4b242f009..49af4a6538b 100644 --- a/drivers/infiniband/hw/qib/qib_fs.c +++ b/drivers/infiniband/hw/qib/qib_fs.c @@ -453,17 +453,14 @@ static int remove_file(struct dentry *parent, char *name)  		goto bail;  	} -	spin_lock(&dcache_lock);  	spin_lock(&tmp->d_lock);  	if (!(d_unhashed(tmp) && tmp->d_inode)) {  		dget_locked_dlock(tmp);  		__d_drop(tmp);  		spin_unlock(&tmp->d_lock); -		spin_unlock(&dcache_lock);  		simple_unlink(parent->d_inode, tmp);  	} else {  		spin_unlock(&tmp->d_lock); -		spin_unlock(&dcache_lock);  	}  	ret = 0; diff --git a/drivers/staging/pohmelfs/path_entry.c b/drivers/staging/pohmelfs/path_entry.c index bbe42f42ca8..400a9fc386a 100644 --- a/drivers/staging/pohmelfs/path_entry.c +++ b/drivers/staging/pohmelfs/path_entry.c @@ -101,7 +101,6 @@ rename_retry:  	d = first;  	seq = read_seqbegin(&rename_lock);  	rcu_read_lock(); -	spin_lock(&dcache_lock);  	if (!IS_ROOT(d) && d_unhashed(d))  		len += UNHASHED_OBSCURE_STRING_SIZE; /* Obscure " (deleted)" string */ @@ -110,7 +109,6 @@ rename_retry:  		len += d->d_name.len + 1; /* Plus slash */  		d = d->d_parent;  	} -	spin_unlock(&dcache_lock);  	rcu_read_unlock();  	if (read_seqretry(&rename_lock, seq))  		goto rename_retry; diff --git a/drivers/staging/smbfs/cache.c b/drivers/staging/smbfs/cache.c index 920434b6c07..75dfd403fb9 100644 --- a/drivers/staging/smbfs/cache.c +++ b/drivers/staging/smbfs/cache.c @@ -62,7 +62,6 @@ smb_invalidate_dircache_entries(struct dentry *parent)  	struct list_head *next;  	struct dentry *dentry; -	spin_lock(&dcache_lock);  	spin_lock(&parent->d_lock);  	next = parent->d_subdirs.next;  	while (next != &parent->d_subdirs) { @@ -72,7 +71,6 @@ smb_invalidate_dircache_entries(struct dentry *parent)  		next = next->next;  	}  	spin_unlock(&parent->d_lock); -	spin_unlock(&dcache_lock);  }  /* @@ -98,7 +96,6 @@ smb_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)  	}  	/* If a pointer is invalid, we search the dentry. */ -	spin_lock(&dcache_lock);  	spin_lock(&parent->d_lock);  	next = parent->d_subdirs.next;  	while (next != &parent->d_subdirs) { @@ -115,7 +112,6 @@ smb_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)  	dent = NULL;  out_unlock:  	spin_unlock(&parent->d_lock); -	spin_unlock(&dcache_lock);  	return dent;  } diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index 89a0e836658..1b125c224dc 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -343,7 +343,6 @@ static int usbfs_empty (struct dentry *dentry)  {  	struct list_head *list; -	spin_lock(&dcache_lock);  	spin_lock(&dentry->d_lock);  	list_for_each(list, &dentry->d_subdirs) {  		struct dentry *de = list_entry(list, struct dentry, d_u.d_child); @@ -352,13 +351,11 @@ static int usbfs_empty (struct dentry *dentry)  		if (usbfs_positive(de)) {  			spin_unlock(&de->d_lock);  			spin_unlock(&dentry->d_lock); -			spin_unlock(&dcache_lock);  			return 0;  		}  		spin_unlock(&de->d_lock);  	}  	spin_unlock(&dentry->d_lock); -	spin_unlock(&dcache_lock);  	return 1;  } diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 47dfd5d29a6..1073bca8488 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -270,13 +270,11 @@ static struct dentry *v9fs_dentry_from_dir_inode(struct inode *inode)  {  	struct dentry *dentry; -	spin_lock(&dcache_lock);  	spin_lock(&dcache_inode_lock);  	/* Directory should have only one entry. */  	BUG_ON(S_ISDIR(inode->i_mode) && !list_is_singular(&inode->i_dentry));  	dentry = list_entry(inode->i_dentry.next, struct dentry, d_alias);  	spin_unlock(&dcache_inode_lock); -	spin_unlock(&dcache_lock);  	return dentry;  } diff --git a/fs/affs/amigaffs.c b/fs/affs/amigaffs.c index 2321cc92d44..600101a21ba 100644 --- a/fs/affs/amigaffs.c +++ b/fs/affs/amigaffs.c @@ -128,7 +128,6 @@ affs_fix_dcache(struct dentry *dentry, u32 entry_ino)  	void *data = dentry->d_fsdata;  	struct list_head *head, *next; -	spin_lock(&dcache_lock);  	spin_lock(&dcache_inode_lock);  	head = &inode->i_dentry;  	next = head->next; @@ -141,7 +140,6 @@ affs_fix_dcache(struct dentry *dentry, u32 entry_ino)  		next = next->next;  	}  	spin_unlock(&dcache_inode_lock); -	spin_unlock(&dcache_lock);  } diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index 9d2ae9b30d9..0fffe1c24ce 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h @@ -16,6 +16,7 @@  #include <linux/auto_fs4.h>  #include <linux/auto_dev-ioctl.h>  #include <linux/mutex.h> +#include <linux/spinlock.h>  #include <linux/list.h>  /* This is the range of ioctl() numbers we claim as ours */ @@ -60,6 +61,8 @@ do {							\  		current->pid, __func__, ##args);	\  } while (0) +extern spinlock_t autofs4_lock; +  /* Unified info structure.  This is pointed to by both the dentry and     inode structures.  Each file in the filesystem has an instance of this     structure.  It holds a reference to the dentry, so dentries are never diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index 968c1434af6..2f7951d67d1 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c @@ -102,7 +102,7 @@ static struct dentry *get_next_positive_dentry(struct dentry *prev,  	if (prev == NULL)  		return dget(prev); -	spin_lock(&dcache_lock); +	spin_lock(&autofs4_lock);  relock:  	p = prev;  	spin_lock(&p->d_lock); @@ -114,7 +114,7 @@ again:  			if (p == root) {  				spin_unlock(&p->d_lock); -				spin_unlock(&dcache_lock); +				spin_unlock(&autofs4_lock);  				dput(prev);  				return NULL;  			} @@ -144,7 +144,7 @@ again:  	dget_dlock(ret);  	spin_unlock(&ret->d_lock);  	spin_unlock(&p->d_lock); -	spin_unlock(&dcache_lock); +	spin_unlock(&autofs4_lock);  	dput(prev); @@ -408,13 +408,13 @@ found:  	ino->flags |= AUTOFS_INF_EXPIRING;  	init_completion(&ino->expire_complete);  	spin_unlock(&sbi->fs_lock); -	spin_lock(&dcache_lock); +	spin_lock(&autofs4_lock);  	spin_lock(&expired->d_parent->d_lock);  	spin_lock_nested(&expired->d_lock, DENTRY_D_LOCK_NESTED);  	list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child);  	spin_unlock(&expired->d_lock);  	spin_unlock(&expired->d_parent->d_lock); -	spin_unlock(&dcache_lock); +	spin_unlock(&autofs4_lock);  	return expired;  } diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 7a9ed6b8829..10ca68a96dc 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c @@ -23,6 +23,8 @@  #include "autofs_i.h" +DEFINE_SPINLOCK(autofs4_lock); +  static int autofs4_dir_symlink(struct inode *,struct dentry *,const char *);  static int autofs4_dir_unlink(struct inode *,struct dentry *);  static int autofs4_dir_rmdir(struct inode *,struct dentry *); @@ -142,15 +144,15 @@ static int autofs4_dir_open(struct inode *inode, struct file *file)  	 * autofs file system so just let the libfs routines handle  	 * it.  	 */ -	spin_lock(&dcache_lock); +	spin_lock(&autofs4_lock);  	spin_lock(&dentry->d_lock);  	if (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) {  		spin_unlock(&dentry->d_lock); -		spin_unlock(&dcache_lock); +		spin_unlock(&autofs4_lock);  		return -ENOENT;  	}  	spin_unlock(&dentry->d_lock); -	spin_unlock(&dcache_lock); +	spin_unlock(&autofs4_lock);  out:  	return dcache_dir_open(inode, file); @@ -255,11 +257,11 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd)  	/* We trigger a mount for almost all flags */  	lookup_type = autofs4_need_mount(nd->flags);  	spin_lock(&sbi->fs_lock); -	spin_lock(&dcache_lock); +	spin_lock(&autofs4_lock);  	spin_lock(&dentry->d_lock);  	if (!(lookup_type || ino->flags & AUTOFS_INF_PENDING)) {  		spin_unlock(&dentry->d_lock); -		spin_unlock(&dcache_lock); +		spin_unlock(&autofs4_lock);  		spin_unlock(&sbi->fs_lock);  		goto follow;  	} @@ -272,7 +274,7 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd)  	if (ino->flags & AUTOFS_INF_PENDING ||  	    (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs))) {  		spin_unlock(&dentry->d_lock); -		spin_unlock(&dcache_lock); +		spin_unlock(&autofs4_lock);  		spin_unlock(&sbi->fs_lock);  		status = try_to_fill_dentry(dentry, nd->flags); @@ -282,7 +284,7 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd)  		goto follow;  	}  	spin_unlock(&dentry->d_lock); -	spin_unlock(&dcache_lock); +	spin_unlock(&autofs4_lock);  	spin_unlock(&sbi->fs_lock);  follow:  	/* @@ -353,14 +355,14 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd)  		return 0;  	/* Check for a non-mountpoint directory with no contents */ -	spin_lock(&dcache_lock); +	spin_lock(&autofs4_lock);  	spin_lock(&dentry->d_lock);  	if (S_ISDIR(dentry->d_inode->i_mode) &&  	    !d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) {  		DPRINTK("dentry=%p %.*s, emptydir",  			 dentry, dentry->d_name.len, dentry->d_name.name);  		spin_unlock(&dentry->d_lock); -		spin_unlock(&dcache_lock); +		spin_unlock(&autofs4_lock);  		/* The daemon never causes a mount to trigger */  		if (oz_mode) @@ -377,7 +379,7 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd)  		return status;  	}  	spin_unlock(&dentry->d_lock); -	spin_unlock(&dcache_lock); +	spin_unlock(&autofs4_lock);  	return 1;  } @@ -432,7 +434,7 @@ static struct dentry *autofs4_lookup_active(struct dentry *dentry)  	const unsigned char *str = name->name;  	struct list_head *p, *head; -	spin_lock(&dcache_lock); +	spin_lock(&autofs4_lock);  	spin_lock(&sbi->lookup_lock);  	head = &sbi->active_list;  	list_for_each(p, head) { @@ -465,14 +467,14 @@ static struct dentry *autofs4_lookup_active(struct dentry *dentry)  			dget_dlock(active);  			spin_unlock(&active->d_lock);  			spin_unlock(&sbi->lookup_lock); -			spin_unlock(&dcache_lock); +			spin_unlock(&autofs4_lock);  			return active;  		}  next:  		spin_unlock(&active->d_lock);  	}  	spin_unlock(&sbi->lookup_lock); -	spin_unlock(&dcache_lock); +	spin_unlock(&autofs4_lock);  	return NULL;  } @@ -487,7 +489,7 @@ static struct dentry *autofs4_lookup_expiring(struct dentry *dentry)  	const unsigned char *str = name->name;  	struct list_head *p, *head; -	spin_lock(&dcache_lock); +	spin_lock(&autofs4_lock);  	spin_lock(&sbi->lookup_lock);  	head = &sbi->expiring_list;  	list_for_each(p, head) { @@ -520,14 +522,14 @@ static struct dentry *autofs4_lookup_expiring(struct dentry *dentry)  			dget_dlock(expiring);  			spin_unlock(&expiring->d_lock);  			spin_unlock(&sbi->lookup_lock); -			spin_unlock(&dcache_lock); +			spin_unlock(&autofs4_lock);  			return expiring;  		}  next:  		spin_unlock(&expiring->d_lock);  	}  	spin_unlock(&sbi->lookup_lock); -	spin_unlock(&dcache_lock); +	spin_unlock(&autofs4_lock);  	return NULL;  } @@ -763,12 +765,12 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry)  	dir->i_mtime = CURRENT_TIME; -	spin_lock(&dcache_lock); +	spin_lock(&autofs4_lock);  	autofs4_add_expiring(dentry);  	spin_lock(&dentry->d_lock);  	__d_drop(dentry);  	spin_unlock(&dentry->d_lock); -	spin_unlock(&dcache_lock); +	spin_unlock(&autofs4_lock);  	return 0;  } @@ -785,20 +787,20 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry)  	if (!autofs4_oz_mode(sbi))  		return -EACCES; -	spin_lock(&dcache_lock); +	spin_lock(&autofs4_lock);  	spin_lock(&sbi->lookup_lock);  	spin_lock(&dentry->d_lock);  	if (!list_empty(&dentry->d_subdirs)) {  		spin_unlock(&dentry->d_lock);  		spin_unlock(&sbi->lookup_lock); -		spin_unlock(&dcache_lock); +		spin_unlock(&autofs4_lock);  		return -ENOTEMPTY;  	}  	__autofs4_add_expiring(dentry);  	spin_unlock(&sbi->lookup_lock);  	__d_drop(dentry);  	spin_unlock(&dentry->d_lock); -	spin_unlock(&dcache_lock); +	spin_unlock(&autofs4_lock);  	if (atomic_dec_and_test(&ino->count)) {  		p_ino = autofs4_dentry_ino(dentry->d_parent); diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c index 4be8f778a41..c5f8459c905 100644 --- a/fs/autofs4/waitq.c +++ b/fs/autofs4/waitq.c @@ -194,14 +194,15 @@ static int autofs4_getpath(struct autofs_sb_info *sbi,  rename_retry:  	buf = *name;  	len = 0; +  	seq = read_seqbegin(&rename_lock);  	rcu_read_lock(); -	spin_lock(&dcache_lock); +	spin_lock(&autofs4_lock);  	for (tmp = dentry ; tmp != root ; tmp = tmp->d_parent)  		len += tmp->d_name.len + 1;  	if (!len || --len > NAME_MAX) { -		spin_unlock(&dcache_lock); +		spin_unlock(&autofs4_lock);  		rcu_read_unlock();  		if (read_seqretry(&rename_lock, seq))  			goto rename_retry; @@ -217,7 +218,7 @@ rename_retry:  		p -= tmp->d_name.len;  		strncpy(p, tmp->d_name.name, tmp->d_name.len);  	} -	spin_unlock(&dcache_lock); +	spin_unlock(&autofs4_lock);  	rcu_read_unlock();  	if (read_seqretry(&rename_lock, seq))  		goto rename_retry; diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 2c924e8d85f..58abc3da611 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -112,7 +112,6 @@ static int __dcache_readdir(struct file *filp,  	dout("__dcache_readdir %p at %llu (last %p)\n", dir, filp->f_pos,  	     last); -	spin_lock(&dcache_lock);  	spin_lock(&parent->d_lock);  	/* start at beginning? */ @@ -156,7 +155,6 @@ more:  	dget_dlock(dentry);  	spin_unlock(&dentry->d_lock);  	spin_unlock(&parent->d_lock); -	spin_unlock(&dcache_lock);  	dout(" %llu (%llu) dentry %p %.*s %p\n", di->offset, filp->f_pos,  	     dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode); @@ -182,21 +180,19 @@ more:  	filp->f_pos++; -	/* make sure a dentry wasn't dropped while we didn't have dcache_lock */ +	/* make sure a dentry wasn't dropped while we didn't have parent lock */  	if (!ceph_i_test(dir, CEPH_I_COMPLETE)) {  		dout(" lost I_COMPLETE on %p; falling back to mds\n", dir);  		err = -EAGAIN;  		goto out;  	} -	spin_lock(&dcache_lock);  	spin_lock(&parent->d_lock);  	p = p->prev;	/* advance to next dentry */  	goto more;  out_unlock:  	spin_unlock(&parent->d_lock); -	spin_unlock(&dcache_lock);  out:  	if (last)  		dput(last); diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 2c694447336..2a48cafc174 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -841,7 +841,6 @@ static void ceph_set_dentry_offset(struct dentry *dn)  	di->offset = ceph_inode(inode)->i_max_offset++;  	spin_unlock(&inode->i_lock); -	spin_lock(&dcache_lock);  	spin_lock(&dir->d_lock);  	spin_lock_nested(&dn->d_lock, DENTRY_D_LOCK_NESTED);  	list_move(&dn->d_u.d_child, &dir->d_subdirs); @@ -849,7 +848,6 @@ static void ceph_set_dentry_offset(struct dentry *dn)  	     dn->d_u.d_child.prev, dn->d_u.d_child.next);  	spin_unlock(&dn->d_lock);  	spin_unlock(&dir->d_lock); -	spin_unlock(&dcache_lock);  }  /* @@ -1233,13 +1231,11 @@ retry_lookup:  			goto retry_lookup;  		} else {  			/* reorder parent's d_subdirs */ -			spin_lock(&dcache_lock);  			spin_lock(&parent->d_lock);  			spin_lock_nested(&dn->d_lock, DENTRY_D_LOCK_NESTED);  			list_move(&dn->d_u.d_child, &parent->d_subdirs);  			spin_unlock(&dn->d_lock);  			spin_unlock(&parent->d_lock); -			spin_unlock(&dcache_lock);  		}  		di = dn->d_fsdata; diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 003698365ec..99b9a2cc14b 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -809,17 +809,14 @@ inode_has_hashed_dentries(struct inode *inode)  {  	struct dentry *dentry; -	spin_lock(&dcache_lock);  	spin_lock(&dcache_inode_lock);  	list_for_each_entry(dentry, &inode->i_dentry, d_alias) {  		if (!d_unhashed(dentry) || IS_ROOT(dentry)) {  			spin_unlock(&dcache_inode_lock); -			spin_unlock(&dcache_lock);  			return true;  		}  	}  	spin_unlock(&dcache_inode_lock); -	spin_unlock(&dcache_lock);  	return false;  } diff --git a/fs/coda/cache.c b/fs/coda/cache.c index 859393fca2b..5525e1c660f 100644 --- a/fs/coda/cache.c +++ b/fs/coda/cache.c @@ -93,7 +93,6 @@ static void coda_flag_children(struct dentry *parent, int flag)  	struct list_head *child;  	struct dentry *de; -	spin_lock(&dcache_lock);  	spin_lock(&parent->d_lock);  	list_for_each(child, &parent->d_subdirs)  	{ @@ -104,7 +103,6 @@ static void coda_flag_children(struct dentry *parent, int flag)  		coda_flag_inode(de->d_inode, flag);  	}  	spin_unlock(&parent->d_lock); -	spin_unlock(&dcache_lock);  	return;   } diff --git a/fs/configfs/configfs_internal.h b/fs/configfs/configfs_internal.h index e58b4c30e21..026cf68553a 100644 --- a/fs/configfs/configfs_internal.h +++ b/fs/configfs/configfs_internal.h @@ -120,7 +120,6 @@ static inline struct config_item *configfs_get_config_item(struct dentry *dentry  {  	struct config_item * item = NULL; -	spin_lock(&dcache_lock);  	spin_lock(&dentry->d_lock);  	if (!d_unhashed(dentry)) {  		struct configfs_dirent * sd = dentry->d_fsdata; @@ -131,7 +130,6 @@ static inline struct config_item *configfs_get_config_item(struct dentry *dentry  			item = config_item_get(sd->s_element);  	}  	spin_unlock(&dentry->d_lock); -	spin_unlock(&dcache_lock);  	return item;  } diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c index 79b37765d8f..fb3a55fff82 100644 --- a/fs/configfs/inode.c +++ b/fs/configfs/inode.c @@ -250,18 +250,14 @@ void configfs_drop_dentry(struct configfs_dirent * sd, struct dentry * parent)  	struct dentry * dentry = sd->s_dentry;  	if (dentry) { -		spin_lock(&dcache_lock);  		spin_lock(&dentry->d_lock);  		if (!(d_unhashed(dentry) && dentry->d_inode)) {  			dget_locked_dlock(dentry);  			__d_drop(dentry);  			spin_unlock(&dentry->d_lock); -			spin_unlock(&dcache_lock);  			simple_unlink(parent->d_inode, dentry); -		} else { +		} else  			spin_unlock(&dentry->d_lock); -			spin_unlock(&dcache_lock); -		}  	}  } diff --git a/fs/dcache.c b/fs/dcache.c index a9bc4ecc21e..0dbae053b66 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -54,11 +54,10 @@   *   - d_alias, d_inode   *   * Ordering: - * dcache_lock - *   dcache_inode_lock - *     dentry->d_lock - *       dcache_lru_lock - *       dcache_hash_lock + * dcache_inode_lock + *   dentry->d_lock + *     dcache_lru_lock + *     dcache_hash_lock   *   * If there is an ancestor relationship:   * dentry->d_parent->...->d_parent->d_lock @@ -77,12 +76,10 @@ EXPORT_SYMBOL_GPL(sysctl_vfs_cache_pressure);  __cacheline_aligned_in_smp DEFINE_SPINLOCK(dcache_inode_lock);  static __cacheline_aligned_in_smp DEFINE_SPINLOCK(dcache_hash_lock);  static __cacheline_aligned_in_smp DEFINE_SPINLOCK(dcache_lru_lock); -__cacheline_aligned_in_smp DEFINE_SPINLOCK(dcache_lock);  __cacheline_aligned_in_smp DEFINE_SEQLOCK(rename_lock);  EXPORT_SYMBOL(rename_lock);  EXPORT_SYMBOL(dcache_inode_lock); -EXPORT_SYMBOL(dcache_lock);  static struct kmem_cache *dentry_cache __read_mostly; @@ -139,7 +136,7 @@ static void __d_free(struct rcu_head *head)  }  /* - * no dcache_lock, please. + * no locks, please.   */  static void d_free(struct dentry *dentry)  { @@ -162,7 +159,6 @@ static void d_free(struct dentry *dentry)  static void dentry_iput(struct dentry * dentry)  	__releases(dentry->d_lock)  	__releases(dcache_inode_lock) -	__releases(dcache_lock)  {  	struct inode *inode = dentry->d_inode;  	if (inode) { @@ -170,7 +166,6 @@ static void dentry_iput(struct dentry * dentry)  		list_del_init(&dentry->d_alias);  		spin_unlock(&dentry->d_lock);  		spin_unlock(&dcache_inode_lock); -		spin_unlock(&dcache_lock);  		if (!inode->i_nlink)  			fsnotify_inoderemove(inode);  		if (dentry->d_op && dentry->d_op->d_iput) @@ -180,7 +175,6 @@ static void dentry_iput(struct dentry * dentry)  	} else {  		spin_unlock(&dentry->d_lock);  		spin_unlock(&dcache_inode_lock); -		spin_unlock(&dcache_lock);  	}  } @@ -235,14 +229,13 @@ static void dentry_lru_move_tail(struct dentry *dentry)   *   * If this is the root of the dentry tree, return NULL.   * - * dcache_lock and d_lock and d_parent->d_lock must be held by caller, and - * are dropped by d_kill. + * dentry->d_lock and parent->d_lock must be held by caller, and are dropped by + * d_kill.   */  static struct dentry *d_kill(struct dentry *dentry, struct dentry *parent)  	__releases(dentry->d_lock)  	__releases(parent->d_lock)  	__releases(dcache_inode_lock) -	__releases(dcache_lock)  {  	dentry->d_parent = NULL;  	list_del(&dentry->d_u.d_child); @@ -285,11 +278,9 @@ EXPORT_SYMBOL(__d_drop);  void d_drop(struct dentry *dentry)  { -	spin_lock(&dcache_lock);  	spin_lock(&dentry->d_lock);  	__d_drop(dentry);  	spin_unlock(&dentry->d_lock); -	spin_unlock(&dcache_lock);  }  EXPORT_SYMBOL(d_drop); @@ -337,21 +328,10 @@ repeat:  	else  		parent = dentry->d_parent;  	if (dentry->d_count == 1) { -		if (!spin_trylock(&dcache_lock)) { -			/* -			 * Something of a livelock possibility we could avoid -			 * by taking dcache_lock and trying again, but we -			 * want to reduce dcache_lock anyway so this will -			 * get improved. -			 */ -drop1: -			spin_unlock(&dentry->d_lock); -			goto repeat; -		}  		if (!spin_trylock(&dcache_inode_lock)) {  drop2: -			spin_unlock(&dcache_lock); -			goto drop1; +			spin_unlock(&dentry->d_lock); +			goto repeat;  		}  		if (parent && !spin_trylock(&parent->d_lock)) {  			spin_unlock(&dcache_inode_lock); @@ -363,7 +343,6 @@ drop2:  		spin_unlock(&dentry->d_lock);  		if (parent)  			spin_unlock(&parent->d_lock); -		spin_unlock(&dcache_lock);  		return;  	} @@ -387,7 +366,6 @@ drop2:  	if (parent)  		spin_unlock(&parent->d_lock);  	spin_unlock(&dcache_inode_lock); -	spin_unlock(&dcache_lock);  	return;  unhash_it: @@ -418,11 +396,9 @@ int d_invalidate(struct dentry * dentry)  	/*  	 * If it's already been dropped, return OK.  	 */ -	spin_lock(&dcache_lock);  	spin_lock(&dentry->d_lock);  	if (d_unhashed(dentry)) {  		spin_unlock(&dentry->d_lock); -		spin_unlock(&dcache_lock);  		return 0;  	}  	/* @@ -431,9 +407,7 @@ int d_invalidate(struct dentry * dentry)  	 */  	if (!list_empty(&dentry->d_subdirs)) {  		spin_unlock(&dentry->d_lock); -		spin_unlock(&dcache_lock);  		shrink_dcache_parent(dentry); -		spin_lock(&dcache_lock);  		spin_lock(&dentry->d_lock);  	} @@ -450,19 +424,17 @@ int d_invalidate(struct dentry * dentry)  	if (dentry->d_count > 1) {  		if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) {  			spin_unlock(&dentry->d_lock); -			spin_unlock(&dcache_lock);  			return -EBUSY;  		}  	}  	__d_drop(dentry);  	spin_unlock(&dentry->d_lock); -	spin_unlock(&dcache_lock);  	return 0;  }  EXPORT_SYMBOL(d_invalidate); -/* This must be called with dcache_lock and d_lock held */ +/* This must be called with d_lock held */  static inline struct dentry * __dget_locked_dlock(struct dentry *dentry)  {  	dentry->d_count++; @@ -470,7 +442,7 @@ static inline struct dentry * __dget_locked_dlock(struct dentry *dentry)  	return dentry;  } -/* This should be called _only_ with dcache_lock held */ +/* This must be called with d_lock held */  static inline struct dentry * __dget_locked(struct dentry *dentry)  {  	spin_lock(&dentry->d_lock); @@ -575,11 +547,9 @@ struct dentry *d_find_alias(struct inode *inode)  	struct dentry *de = NULL;  	if (!list_empty(&inode->i_dentry)) { -		spin_lock(&dcache_lock);  		spin_lock(&dcache_inode_lock);  		de = __d_find_alias(inode, 0);  		spin_unlock(&dcache_inode_lock); -		spin_unlock(&dcache_lock);  	}  	return de;  } @@ -593,7 +563,6 @@ void d_prune_aliases(struct inode *inode)  {  	struct dentry *dentry;  restart: -	spin_lock(&dcache_lock);  	spin_lock(&dcache_inode_lock);  	list_for_each_entry(dentry, &inode->i_dentry, d_alias) {  		spin_lock(&dentry->d_lock); @@ -602,14 +571,12 @@ restart:  			__d_drop(dentry);  			spin_unlock(&dentry->d_lock);  			spin_unlock(&dcache_inode_lock); -			spin_unlock(&dcache_lock);  			dput(dentry);  			goto restart;  		}  		spin_unlock(&dentry->d_lock);  	}  	spin_unlock(&dcache_inode_lock); -	spin_unlock(&dcache_lock);  }  EXPORT_SYMBOL(d_prune_aliases); @@ -625,17 +592,14 @@ static void prune_one_dentry(struct dentry *dentry, struct dentry *parent)  	__releases(dentry->d_lock)  	__releases(parent->d_lock)  	__releases(dcache_inode_lock) -	__releases(dcache_lock)  {  	__d_drop(dentry);  	dentry = d_kill(dentry, parent);  	/* -	 * Prune ancestors.  Locking is simpler than in dput(), -	 * because dcache_lock needs to be taken anyway. +	 * Prune ancestors.  	 */  	while (dentry) { -		spin_lock(&dcache_lock);  		spin_lock(&dcache_inode_lock);  again:  		spin_lock(&dentry->d_lock); @@ -653,7 +617,6 @@ again:  				spin_unlock(&parent->d_lock);  			spin_unlock(&dentry->d_lock);  			spin_unlock(&dcache_inode_lock); -			spin_unlock(&dcache_lock);  			return;  		} @@ -702,8 +665,7 @@ relock:  		spin_unlock(&dcache_lru_lock);  		prune_one_dentry(dentry, parent); -		/* dcache_lock, dcache_inode_lock and dentry->d_lock dropped */ -		spin_lock(&dcache_lock); +		/* dcache_inode_lock and dentry->d_lock dropped */  		spin_lock(&dcache_inode_lock);  		spin_lock(&dcache_lru_lock);  	} @@ -725,7 +687,6 @@ static void __shrink_dcache_sb(struct super_block *sb, int *count, int flags)  	LIST_HEAD(tmp);  	int cnt = *count; -	spin_lock(&dcache_lock);  	spin_lock(&dcache_inode_lock);  relock:  	spin_lock(&dcache_lru_lock); @@ -766,7 +727,6 @@ relock:  		list_splice(&referenced, &sb->s_dentry_lru);  	spin_unlock(&dcache_lru_lock);  	spin_unlock(&dcache_inode_lock); -	spin_unlock(&dcache_lock);  }  /** @@ -788,7 +748,6 @@ static void prune_dcache(int count)  	if (unused == 0 || count == 0)  		return; -	spin_lock(&dcache_lock);  	if (count >= unused)  		prune_ratio = 1;  	else @@ -825,11 +784,9 @@ static void prune_dcache(int count)  		if (down_read_trylock(&sb->s_umount)) {  			if ((sb->s_root != NULL) &&  			    (!list_empty(&sb->s_dentry_lru))) { -				spin_unlock(&dcache_lock);  				__shrink_dcache_sb(sb, &w_count,  						DCACHE_REFERENCED);  				pruned -= w_count; -				spin_lock(&dcache_lock);  			}  			up_read(&sb->s_umount);  		} @@ -845,7 +802,6 @@ static void prune_dcache(int count)  	if (p)  		__put_super(p);  	spin_unlock(&sb_lock); -	spin_unlock(&dcache_lock);  }  /** @@ -859,7 +815,6 @@ void shrink_dcache_sb(struct super_block *sb)  {  	LIST_HEAD(tmp); -	spin_lock(&dcache_lock);  	spin_lock(&dcache_inode_lock);  	spin_lock(&dcache_lru_lock);  	while (!list_empty(&sb->s_dentry_lru)) { @@ -868,7 +823,6 @@ void shrink_dcache_sb(struct super_block *sb)  	}  	spin_unlock(&dcache_lru_lock);  	spin_unlock(&dcache_inode_lock); -	spin_unlock(&dcache_lock);  }  EXPORT_SYMBOL(shrink_dcache_sb); @@ -885,12 +839,10 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)  	BUG_ON(!IS_ROOT(dentry));  	/* detach this root from the system */ -	spin_lock(&dcache_lock);  	spin_lock(&dentry->d_lock);  	dentry_lru_del(dentry);  	__d_drop(dentry);  	spin_unlock(&dentry->d_lock); -	spin_unlock(&dcache_lock);  	for (;;) {  		/* descend to the first leaf in the current subtree */ @@ -899,7 +851,6 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)  			/* this is a branch with children - detach all of them  			 * from the system in one go */ -			spin_lock(&dcache_lock);  			spin_lock(&dentry->d_lock);  			list_for_each_entry(loop, &dentry->d_subdirs,  					    d_u.d_child) { @@ -910,7 +861,6 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)  				spin_unlock(&loop->d_lock);  			}  			spin_unlock(&dentry->d_lock); -			spin_unlock(&dcache_lock);  			/* move to the first child */  			dentry = list_entry(dentry->d_subdirs.next, @@ -977,8 +927,7 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)  /*   * destroy the dentries attached to a superblock on unmounting - * - we don't need to use dentry->d_lock, and only need dcache_lock when - *   removing the dentry from the system lists and hashes because: + * - we don't need to use dentry->d_lock because:   *   - the superblock is detached from all mountings and open files, so the   *     dentry trees will not be rearranged by the VFS   *   - s_umount is write-locked, so the memory pressure shrinker will ignore @@ -1029,7 +978,6 @@ rename_retry:  	this_parent = parent;  	seq = read_seqbegin(&rename_lock); -	spin_lock(&dcache_lock);  	if (d_mountpoint(parent))  		goto positive;  	spin_lock(&this_parent->d_lock); @@ -1075,7 +1023,6 @@ resume:  		if (this_parent != child->d_parent ||  				read_seqretry(&rename_lock, seq)) {  			spin_unlock(&this_parent->d_lock); -			spin_unlock(&dcache_lock);  			rcu_read_unlock();  			goto rename_retry;  		} @@ -1084,12 +1031,10 @@ resume:  		goto resume;  	}  	spin_unlock(&this_parent->d_lock); -	spin_unlock(&dcache_lock);  	if (read_seqretry(&rename_lock, seq))  		goto rename_retry;  	return 0; /* No mount points found in tree */  positive: -	spin_unlock(&dcache_lock);  	if (read_seqretry(&rename_lock, seq))  		goto rename_retry;  	return 1; @@ -1121,7 +1066,6 @@ rename_retry:  	this_parent = parent;  	seq = read_seqbegin(&rename_lock); -	spin_lock(&dcache_lock);  	spin_lock(&this_parent->d_lock);  repeat:  	next = this_parent->d_subdirs.next; @@ -1185,7 +1129,6 @@ resume:  		if (this_parent != child->d_parent ||  				read_seqretry(&rename_lock, seq)) {  			spin_unlock(&this_parent->d_lock); -			spin_unlock(&dcache_lock);  			rcu_read_unlock();  			goto rename_retry;  		} @@ -1195,7 +1138,6 @@ resume:  	}  out:  	spin_unlock(&this_parent->d_lock); -	spin_unlock(&dcache_lock);  	if (read_seqretry(&rename_lock, seq))  		goto rename_retry;  	return found; @@ -1297,7 +1239,6 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)  	INIT_LIST_HEAD(&dentry->d_u.d_child);  	if (parent) { -		spin_lock(&dcache_lock);  		spin_lock(&parent->d_lock);  		spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);  		dentry->d_parent = dget_dlock(parent); @@ -1305,7 +1246,6 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)  		list_add(&dentry->d_u.d_child, &parent->d_subdirs);  		spin_unlock(&dentry->d_lock);  		spin_unlock(&parent->d_lock); -		spin_unlock(&dcache_lock);  	}  	this_cpu_inc(nr_dentry); @@ -1325,7 +1265,6 @@ struct dentry *d_alloc_name(struct dentry *parent, const char *name)  }  EXPORT_SYMBOL(d_alloc_name); -/* the caller must hold dcache_lock */  static void __d_instantiate(struct dentry *dentry, struct inode *inode)  {  	spin_lock(&dentry->d_lock); @@ -1354,11 +1293,9 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode)  void d_instantiate(struct dentry *entry, struct inode * inode)  {  	BUG_ON(!list_empty(&entry->d_alias)); -	spin_lock(&dcache_lock);  	spin_lock(&dcache_inode_lock);  	__d_instantiate(entry, inode);  	spin_unlock(&dcache_inode_lock); -	spin_unlock(&dcache_lock);  	security_d_instantiate(entry, inode);  }  EXPORT_SYMBOL(d_instantiate); @@ -1422,11 +1359,9 @@ struct dentry *d_instantiate_unique(struct dentry *entry, struct inode *inode)  	BUG_ON(!list_empty(&entry->d_alias)); -	spin_lock(&dcache_lock);  	spin_lock(&dcache_inode_lock);  	result = __d_instantiate_unique(entry, inode);  	spin_unlock(&dcache_inode_lock); -	spin_unlock(&dcache_lock);  	if (!result) {  		security_d_instantiate(entry, inode); @@ -1515,12 +1450,11 @@ struct dentry *d_obtain_alias(struct inode *inode)  	}  	tmp->d_parent = tmp; /* make sure dput doesn't croak */ -	spin_lock(&dcache_lock); +  	spin_lock(&dcache_inode_lock);  	res = __d_find_alias(inode, 0);  	if (res) {  		spin_unlock(&dcache_inode_lock); -		spin_unlock(&dcache_lock);  		dput(tmp);  		goto out_iput;  	} @@ -1538,7 +1472,6 @@ struct dentry *d_obtain_alias(struct inode *inode)  	spin_unlock(&tmp->d_lock);  	spin_unlock(&dcache_inode_lock); -	spin_unlock(&dcache_lock);  	return tmp;   out_iput: @@ -1568,21 +1501,18 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)  	struct dentry *new = NULL;  	if (inode && S_ISDIR(inode->i_mode)) { -		spin_lock(&dcache_lock);  		spin_lock(&dcache_inode_lock);  		new = __d_find_alias(inode, 1);  		if (new) {  			BUG_ON(!(new->d_flags & DCACHE_DISCONNECTED));  			spin_unlock(&dcache_inode_lock); -			spin_unlock(&dcache_lock);  			security_d_instantiate(new, inode);  			d_move(new, dentry);  			iput(inode);  		} else { -			/* already taking dcache_lock, so d_add() by hand */ +			/* already taking dcache_inode_lock, so d_add() by hand */  			__d_instantiate(dentry, inode);  			spin_unlock(&dcache_inode_lock); -			spin_unlock(&dcache_lock);  			security_d_instantiate(dentry, inode);  			d_rehash(dentry);  		} @@ -1655,12 +1585,10 @@ struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode,  	 * Negative dentry: instantiate it unless the inode is a directory and  	 * already has a dentry.  	 */ -	spin_lock(&dcache_lock);  	spin_lock(&dcache_inode_lock);  	if (!S_ISDIR(inode->i_mode) || list_empty(&inode->i_dentry)) {  		__d_instantiate(found, inode);  		spin_unlock(&dcache_inode_lock); -		spin_unlock(&dcache_lock);  		security_d_instantiate(found, inode);  		return found;  	} @@ -1672,7 +1600,6 @@ struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode,  	new = list_entry(inode->i_dentry.next, struct dentry, d_alias);  	dget_locked(new);  	spin_unlock(&dcache_inode_lock); -	spin_unlock(&dcache_lock);  	security_d_instantiate(found, inode);  	d_move(new, found);  	iput(inode); @@ -1843,7 +1770,6 @@ int d_validate(struct dentry *dentry, struct dentry *dparent)  {  	struct dentry *child; -	spin_lock(&dcache_lock);  	spin_lock(&dparent->d_lock);  	list_for_each_entry(child, &dparent->d_subdirs, d_u.d_child) {  		if (dentry == child) { @@ -1851,12 +1777,10 @@ int d_validate(struct dentry *dentry, struct dentry *dparent)  			__dget_locked_dlock(dentry);  			spin_unlock(&dentry->d_lock);  			spin_unlock(&dparent->d_lock); -			spin_unlock(&dcache_lock);  			return 1;  		}  	}  	spin_unlock(&dparent->d_lock); -	spin_unlock(&dcache_lock);  	return 0;  } @@ -1889,7 +1813,6 @@ void d_delete(struct dentry * dentry)  	/*  	 * Are we the only user?  	 */ -	spin_lock(&dcache_lock);  	spin_lock(&dcache_inode_lock);  	spin_lock(&dentry->d_lock);  	isdir = S_ISDIR(dentry->d_inode->i_mode); @@ -1905,7 +1828,6 @@ void d_delete(struct dentry * dentry)  	spin_unlock(&dentry->d_lock);  	spin_unlock(&dcache_inode_lock); -	spin_unlock(&dcache_lock);  	fsnotify_nameremove(dentry, isdir);  } @@ -1932,13 +1854,11 @@ static void _d_rehash(struct dentry * entry)  void d_rehash(struct dentry * entry)  { -	spin_lock(&dcache_lock);  	spin_lock(&entry->d_lock);  	spin_lock(&dcache_hash_lock);  	_d_rehash(entry);  	spin_unlock(&dcache_hash_lock);  	spin_unlock(&entry->d_lock); -	spin_unlock(&dcache_lock);  }  EXPORT_SYMBOL(d_rehash); @@ -1961,11 +1881,9 @@ void dentry_update_name_case(struct dentry *dentry, struct qstr *name)  	BUG_ON(!mutex_is_locked(&dentry->d_inode->i_mutex));  	BUG_ON(dentry->d_name.len != name->len); /* d_lookup gives this */ -	spin_lock(&dcache_lock);  	spin_lock(&dentry->d_lock);  	memcpy((unsigned char *)dentry->d_name.name, name->name, name->len);  	spin_unlock(&dentry->d_lock); -	spin_unlock(&dcache_lock);  }  EXPORT_SYMBOL(dentry_update_name_case); @@ -2058,14 +1976,14 @@ static void dentry_unlock_parents_for_move(struct dentry *dentry,   * The hash value has to match the hash queue that the dentry is on..   */  /* - * d_move_locked - move a dentry + * d_move - move a dentry   * @dentry: entry to move   * @target: new dentry   *   * Update the dcache to reflect the move of a file name. Negative   * dcache entries should not be moved in this way.   */ -static void d_move_locked(struct dentry * dentry, struct dentry * target) +void d_move(struct dentry * dentry, struct dentry * target)  {  	if (!dentry->d_inode)  		printk(KERN_WARNING "VFS: moving negative dcache entry\n"); @@ -2114,22 +2032,6 @@ static void d_move_locked(struct dentry * dentry, struct dentry * target)  	spin_unlock(&dentry->d_lock);  	write_sequnlock(&rename_lock);  } - -/** - * d_move - move a dentry - * @dentry: entry to move - * @target: new dentry - * - * Update the dcache to reflect the move of a file name. Negative - * dcache entries should not be moved in this way. - */ - -void d_move(struct dentry * dentry, struct dentry * target) -{ -	spin_lock(&dcache_lock); -	d_move_locked(dentry, target); -	spin_unlock(&dcache_lock); -}  EXPORT_SYMBOL(d_move);  /** @@ -2155,13 +2057,12 @@ struct dentry *d_ancestor(struct dentry *p1, struct dentry *p2)   * This helper attempts to cope with remotely renamed directories   *   * It assumes that the caller is already holding - * dentry->d_parent->d_inode->i_mutex and the dcache_lock + * dentry->d_parent->d_inode->i_mutex and the dcache_inode_lock   *   * Note: If ever the locking in lock_rename() changes, then please   * remember to update this too...   */  static struct dentry *__d_unalias(struct dentry *dentry, struct dentry *alias) -	__releases(dcache_lock)  	__releases(dcache_inode_lock)  {  	struct mutex *m1 = NULL, *m2 = NULL; @@ -2185,11 +2086,10 @@ static struct dentry *__d_unalias(struct dentry *dentry, struct dentry *alias)  		goto out_err;  	m2 = &alias->d_parent->d_inode->i_mutex;  out_unalias: -	d_move_locked(alias, dentry); +	d_move(alias, dentry);  	ret = alias;  out_err:  	spin_unlock(&dcache_inode_lock); -	spin_unlock(&dcache_lock);  	if (m2)  		mutex_unlock(m2);  	if (m1) @@ -2249,7 +2149,6 @@ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode)  	BUG_ON(!d_unhashed(dentry)); -	spin_lock(&dcache_lock);  	spin_lock(&dcache_inode_lock);  	if (!inode) { @@ -2295,7 +2194,6 @@ found:  	spin_unlock(&dcache_hash_lock);  	spin_unlock(&actual->d_lock);  	spin_unlock(&dcache_inode_lock); -	spin_unlock(&dcache_lock);  out_nolock:  	if (actual == dentry) {  		security_d_instantiate(dentry, inode); @@ -2307,7 +2205,6 @@ out_nolock:  shouldnt_be_hashed:  	spin_unlock(&dcache_inode_lock); -	spin_unlock(&dcache_lock);  	BUG();  }  EXPORT_SYMBOL_GPL(d_materialise_unique); @@ -2421,11 +2318,9 @@ char *__d_path(const struct path *path, struct path *root,  	int error;  	prepend(&res, &buflen, "\0", 1); -	spin_lock(&dcache_lock);  	write_seqlock(&rename_lock);  	error = prepend_path(path, root, &res, &buflen);  	write_sequnlock(&rename_lock); -	spin_unlock(&dcache_lock);  	if (error)  		return ERR_PTR(error); @@ -2487,14 +2382,12 @@ char *d_path(const struct path *path, char *buf, int buflen)  		return path->dentry->d_op->d_dname(path->dentry, buf, buflen);  	get_fs_root(current->fs, &root); -	spin_lock(&dcache_lock);  	write_seqlock(&rename_lock);  	tmp = root;  	error = path_with_deleted(path, &tmp, &res, &buflen);  	if (error)  		res = ERR_PTR(error);  	write_sequnlock(&rename_lock); -	spin_unlock(&dcache_lock);  	path_put(&root);  	return res;  } @@ -2520,14 +2413,12 @@ char *d_path_with_unreachable(const struct path *path, char *buf, int buflen)  		return path->dentry->d_op->d_dname(path->dentry, buf, buflen);  	get_fs_root(current->fs, &root); -	spin_lock(&dcache_lock);  	write_seqlock(&rename_lock);  	tmp = root;  	error = path_with_deleted(path, &tmp, &res, &buflen);  	if (!error && !path_equal(&tmp, &root))  		error = prepend_unreachable(&res, &buflen);  	write_sequnlock(&rename_lock); -	spin_unlock(&dcache_lock);  	path_put(&root);  	if (error)  		res =  ERR_PTR(error); @@ -2594,11 +2485,9 @@ char *dentry_path_raw(struct dentry *dentry, char *buf, int buflen)  {  	char *retval; -	spin_lock(&dcache_lock);  	write_seqlock(&rename_lock);  	retval = __dentry_path(dentry, buf, buflen);  	write_sequnlock(&rename_lock); -	spin_unlock(&dcache_lock);  	return retval;  } @@ -2609,7 +2498,6 @@ char *dentry_path(struct dentry *dentry, char *buf, int buflen)  	char *p = NULL;  	char *retval; -	spin_lock(&dcache_lock);  	write_seqlock(&rename_lock);  	if (d_unlinked(dentry)) {  		p = buf + buflen; @@ -2619,12 +2507,10 @@ char *dentry_path(struct dentry *dentry, char *buf, int buflen)  	}  	retval = __dentry_path(dentry, buf, buflen);  	write_sequnlock(&rename_lock); -	spin_unlock(&dcache_lock);  	if (!IS_ERR(retval) && p)  		*p = '/';	/* restore '/' overriden with '\0' */  	return retval;  Elong: -	spin_unlock(&dcache_lock);  	return ERR_PTR(-ENAMETOOLONG);  } @@ -2658,7 +2544,6 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)  	get_fs_root_and_pwd(current->fs, &root, &pwd);  	error = -ENOENT; -	spin_lock(&dcache_lock);  	write_seqlock(&rename_lock);  	if (!d_unlinked(pwd.dentry)) {  		unsigned long len; @@ -2669,7 +2554,6 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)  		prepend(&cwd, &buflen, "\0", 1);  		error = prepend_path(&pwd, &tmp, &cwd, &buflen);  		write_sequnlock(&rename_lock); -		spin_unlock(&dcache_lock);  		if (error)  			goto out; @@ -2690,7 +2574,6 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)  		}  	} else {  		write_sequnlock(&rename_lock); -		spin_unlock(&dcache_lock);  	}  out: @@ -2776,7 +2659,6 @@ void d_genocide(struct dentry *root)  rename_retry:  	this_parent = root;  	seq = read_seqbegin(&rename_lock); -	spin_lock(&dcache_lock);  	spin_lock(&this_parent->d_lock);  repeat:  	next = this_parent->d_subdirs.next; @@ -2823,7 +2705,6 @@ resume:  		if (this_parent != child->d_parent ||  				read_seqretry(&rename_lock, seq)) {  			spin_unlock(&this_parent->d_lock); -			spin_unlock(&dcache_lock);  			rcu_read_unlock();  			goto rename_retry;  		} @@ -2832,7 +2713,6 @@ resume:  		goto resume;  	}  	spin_unlock(&this_parent->d_lock); -	spin_unlock(&dcache_lock);  	if (read_seqretry(&rename_lock, seq))  		goto rename_retry;  } diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c index 84b8c460a78..53a5c08fb63 100644 --- a/fs/exportfs/expfs.c +++ b/fs/exportfs/expfs.c @@ -47,24 +47,20 @@ find_acceptable_alias(struct dentry *result,  	if (acceptable(context, result))  		return result; -	spin_lock(&dcache_lock);  	spin_lock(&dcache_inode_lock);  	list_for_each_entry(dentry, &result->d_inode->i_dentry, d_alias) {  		dget_locked(dentry);  		spin_unlock(&dcache_inode_lock); -		spin_unlock(&dcache_lock);  		if (toput)  			dput(toput);  		if (dentry != result && acceptable(context, dentry)) {  			dput(result);  			return dentry;  		} -		spin_lock(&dcache_lock);  		spin_lock(&dcache_inode_lock);  		toput = dentry;  	}  	spin_unlock(&dcache_inode_lock); -	spin_unlock(&dcache_lock);  	if (toput)  		dput(toput); diff --git a/fs/libfs.c b/fs/libfs.c index cc4794914b5..28b36663c44 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -100,7 +100,6 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin)  			struct dentry *cursor = file->private_data;  			loff_t n = file->f_pos - 2; -			spin_lock(&dcache_lock);  			spin_lock(&dentry->d_lock);  			/* d_lock not required for cursor */  			list_del(&cursor->d_u.d_child); @@ -116,7 +115,6 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin)  			}  			list_add_tail(&cursor->d_u.d_child, p);  			spin_unlock(&dentry->d_lock); -			spin_unlock(&dcache_lock);  		}  	}  	mutex_unlock(&dentry->d_inode->i_mutex); @@ -159,7 +157,6 @@ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir)  			i++;  			/* fallthrough */  		default: -			spin_lock(&dcache_lock);  			spin_lock(&dentry->d_lock);  			if (filp->f_pos == 2)  				list_move(q, &dentry->d_subdirs); @@ -175,13 +172,11 @@ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir)  				spin_unlock(&next->d_lock);  				spin_unlock(&dentry->d_lock); -				spin_unlock(&dcache_lock);  				if (filldir(dirent, next->d_name.name,   					    next->d_name.len, filp->f_pos,   					    next->d_inode->i_ino,   					    dt_type(next->d_inode)) < 0)  					return 0; -				spin_lock(&dcache_lock);  				spin_lock(&dentry->d_lock);  				spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED);  				/* next is still alive */ @@ -191,7 +186,6 @@ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir)  				filp->f_pos++;  			}  			spin_unlock(&dentry->d_lock); -			spin_unlock(&dcache_lock);  	}  	return 0;  } @@ -285,7 +279,6 @@ int simple_empty(struct dentry *dentry)  	struct dentry *child;  	int ret = 0; -	spin_lock(&dcache_lock);  	spin_lock(&dentry->d_lock);  	list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) {  		spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED); @@ -298,7 +291,6 @@ int simple_empty(struct dentry *dentry)  	ret = 1;  out:  	spin_unlock(&dentry->d_lock); -	spin_unlock(&dcache_lock);  	return ret;  } diff --git a/fs/namei.c b/fs/namei.c index cbfa5fb3107..5642bc2be41 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -612,8 +612,8 @@ int follow_up(struct path *path)  	return 1;  } -/* no need for dcache_lock, as serialization is taken care in - * namespace.c +/* + * serialization is taken care of in namespace.c   */  static int __follow_mount(struct path *path)  { @@ -645,9 +645,6 @@ static void follow_mount(struct path *path)  	}  } -/* no need for dcache_lock, as serialization is taken care in - * namespace.c - */  int follow_down(struct path *path)  {  	struct vfsmount *mounted; @@ -2131,12 +2128,10 @@ void dentry_unhash(struct dentry *dentry)  {  	dget(dentry);  	shrink_dcache_parent(dentry); -	spin_lock(&dcache_lock);  	spin_lock(&dentry->d_lock);  	if (dentry->d_count == 2)  		__d_drop(dentry);  	spin_unlock(&dentry->d_lock); -	spin_unlock(&dcache_lock);  }  int vfs_rmdir(struct inode *dir, struct dentry *dentry) diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index 102278ed38b..de15c533311 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c @@ -391,7 +391,6 @@ ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)  	}  	/* If a pointer is invalid, we search the dentry. */ -	spin_lock(&dcache_lock);  	spin_lock(&parent->d_lock);  	next = parent->d_subdirs.next;  	while (next != &parent->d_subdirs) { @@ -402,13 +401,11 @@ ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)  			else  				dent = NULL;  			spin_unlock(&parent->d_lock); -			spin_unlock(&dcache_lock);  			goto out;  		}  		next = next->next;  	}  	spin_unlock(&parent->d_lock); -	spin_unlock(&dcache_lock);  	return NULL;  out: diff --git a/fs/ncpfs/ncplib_kernel.h b/fs/ncpfs/ncplib_kernel.h index c4b718ff9a6..1220df75ff2 100644 --- a/fs/ncpfs/ncplib_kernel.h +++ b/fs/ncpfs/ncplib_kernel.h @@ -193,7 +193,6 @@ ncp_renew_dentries(struct dentry *parent)  	struct list_head *next;  	struct dentry *dentry; -	spin_lock(&dcache_lock);  	spin_lock(&parent->d_lock);  	next = parent->d_subdirs.next;  	while (next != &parent->d_subdirs) { @@ -207,7 +206,6 @@ ncp_renew_dentries(struct dentry *parent)  		next = next->next;  	}  	spin_unlock(&parent->d_lock); -	spin_unlock(&dcache_lock);  }  static inline void @@ -217,7 +215,6 @@ ncp_invalidate_dircache_entries(struct dentry *parent)  	struct list_head *next;  	struct dentry *dentry; -	spin_lock(&dcache_lock);  	spin_lock(&parent->d_lock);  	next = parent->d_subdirs.next;  	while (next != &parent->d_subdirs) { @@ -227,7 +224,6 @@ ncp_invalidate_dircache_entries(struct dentry *parent)  		next = next->next;  	}  	spin_unlock(&parent->d_lock); -	spin_unlock(&dcache_lock);  }  struct ncp_cache_head { diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 12de824edb5..eb77471b882 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1718,11 +1718,9 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry)  	dfprintk(VFS, "NFS: unlink(%s/%ld, %s)\n", dir->i_sb->s_id,  		dir->i_ino, dentry->d_name.name); -	spin_lock(&dcache_lock);  	spin_lock(&dentry->d_lock);  	if (dentry->d_count > 1) {  		spin_unlock(&dentry->d_lock); -		spin_unlock(&dcache_lock);  		/* Start asynchronous writeout of the inode */  		write_inode_now(dentry->d_inode, 0);  		error = nfs_sillyrename(dir, dentry); @@ -1733,7 +1731,6 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry)  		need_rehash = 1;  	}  	spin_unlock(&dentry->d_lock); -	spin_unlock(&dcache_lock);  	error = nfs_safe_remove(dentry);  	if (!error || error == -ENOENT) {  		nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c index 850f67d5f0a..b3e36c3430d 100644 --- a/fs/nfs/getroot.c +++ b/fs/nfs/getroot.c @@ -63,13 +63,11 @@ static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *i  		 * This again causes shrink_dcache_for_umount_subtree() to  		 * Oops, since the test for IS_ROOT() will fail.  		 */ -		spin_lock(&dcache_lock);  		spin_lock(&dcache_inode_lock);  		spin_lock(&sb->s_root->d_lock);  		list_del_init(&sb->s_root->d_alias);  		spin_unlock(&sb->s_root->d_lock);  		spin_unlock(&dcache_inode_lock); -		spin_unlock(&dcache_lock);  	}  	return 0;  } diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index 78c0ebb0b07..74aaf3963c1 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c @@ -60,7 +60,6 @@ rename_retry:  	seq = read_seqbegin(&rename_lock);  	rcu_read_lock(); -	spin_lock(&dcache_lock);  	while (!IS_ROOT(dentry) && dentry != droot) {  		namelen = dentry->d_name.len;  		buflen -= namelen + 1; @@ -71,7 +70,6 @@ rename_retry:  		*--end = '/';  		dentry = dentry->d_parent;  	} -	spin_unlock(&dcache_lock);  	rcu_read_unlock();  	if (read_seqretry(&rename_lock, seq))  		goto rename_retry; @@ -91,7 +89,6 @@ rename_retry:  	memcpy(end, base, namelen);  	return end;  Elong_unlock: -	spin_unlock(&dcache_lock);  	rcu_read_unlock();  	if (read_seqretry(&rename_lock, seq))  		goto rename_retry; diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index ae769fc9b66..9be6ec1f36d 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c @@ -59,7 +59,6 @@ void __fsnotify_update_child_dentry_flags(struct inode *inode)  	/* determine if the children should tell inode about their events */  	watched = fsnotify_inode_watches_children(inode); -	spin_lock(&dcache_lock);  	spin_lock(&dcache_inode_lock);  	/* run all of the dentries associated with this inode.  Since this is a  	 * directory, there damn well better only be one item on this list */ @@ -84,7 +83,6 @@ void __fsnotify_update_child_dentry_flags(struct inode *inode)  		spin_unlock(&alias->d_lock);  	}  	spin_unlock(&dcache_inode_lock); -	spin_unlock(&dcache_lock);  }  /* Notify this dentry's parent about a child's events. */ diff --git a/fs/ocfs2/dcache.c b/fs/ocfs2/dcache.c index c31b5c647ac..b7de749bdd1 100644 --- a/fs/ocfs2/dcache.c +++ b/fs/ocfs2/dcache.c @@ -169,7 +169,6 @@ struct dentry *ocfs2_find_local_alias(struct inode *inode,  	struct list_head *p;  	struct dentry *dentry = NULL; -	spin_lock(&dcache_lock);  	spin_lock(&dcache_inode_lock);  	list_for_each(p, &inode->i_dentry) {  		dentry = list_entry(p, struct dentry, d_alias); @@ -189,7 +188,6 @@ struct dentry *ocfs2_find_local_alias(struct inode *inode,  	}  	spin_unlock(&dcache_inode_lock); -	spin_unlock(&dcache_lock);  	return dentry;  } diff --git a/include/linux/dcache.h b/include/linux/dcache.h index c963ebada92..a2ceb94b0e3 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -183,7 +183,6 @@ struct dentry_operations {  #define DCACHE_GENOCIDE		0x0200  extern spinlock_t dcache_inode_lock; -extern spinlock_t dcache_lock;  extern seqlock_t rename_lock;  static inline int dname_external(struct dentry *dentry) @@ -296,8 +295,8 @@ extern char *dentry_path(struct dentry *, char *, int);   *	destroyed when it has references. dget() should never be   *	called for dentries with zero reference counter. For these cases   *	(preferably none, functions in dcache.c are sufficient for normal - *	needs and they take necessary precautions) you should hold dcache_lock - *	and call dget_locked() instead of dget(). + *	needs and they take necessary precautions) you should hold d_lock + *	and call dget_dlock() instead of dget().   */  static inline struct dentry *dget_dlock(struct dentry *dentry)  { diff --git a/include/linux/fs.h b/include/linux/fs.h index 090f0eacde2..296cf2fde94 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1378,7 +1378,7 @@ struct super_block {  #else  	struct list_head	s_files;  #endif -	/* s_dentry_lru and s_nr_dentry_unused are protected by dcache_lock */ +	/* s_dentry_lru, s_nr_dentry_unused protected by dcache.c lru locks */  	struct list_head	s_dentry_lru;	/* unused dentry lru */  	int			s_nr_dentry_unused;	/* # of dentry on lru */ @@ -2446,6 +2446,10 @@ static inline ino_t parent_ino(struct dentry *dentry)  {  	ino_t res; +	/* +	 * Don't strictly need d_lock here? If the parent ino could change +	 * then surely we'd have a deeper race in the caller? +	 */  	spin_lock(&dentry->d_lock);  	res = dentry->d_parent->d_inode->i_ino;  	spin_unlock(&dentry->d_lock); diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h index b10bcdeaef7..2a53f10712b 100644 --- a/include/linux/fsnotify.h +++ b/include/linux/fsnotify.h @@ -17,7 +17,6 @@  /*   * fsnotify_d_instantiate - instantiate a dentry for inode - * Called with dcache_lock held.   */  static inline void fsnotify_d_instantiate(struct dentry *dentry,  					  struct inode *inode) @@ -62,7 +61,6 @@ static inline int fsnotify_perm(struct file *file, int mask)  /*   * fsnotify_d_move - dentry has been moved - * Called with dcache_lock and dentry->d_lock held.   */  static inline void fsnotify_d_move(struct dentry *dentry)  { diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index 7380763595d..69ad89b5048 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -329,9 +329,15 @@ static inline void __fsnotify_update_dcache_flags(struct dentry *dentry)  {  	struct dentry *parent; -	assert_spin_locked(&dcache_lock);  	assert_spin_locked(&dentry->d_lock); +	/* +	 * Serialisation of setting PARENT_WATCHED on the dentries is provided +	 * by d_lock. If inotify_inode_watched changes after we have taken +	 * d_lock, the following __fsnotify_update_child_dentry_flags call will +	 * find our entry, so it will spin until we complete here, and update +	 * us with the new state. +	 */  	parent = dentry->d_parent;  	if (parent->d_inode && fsnotify_inode_watches_children(parent->d_inode))  		dentry->d_flags |= DCACHE_FSNOTIFY_PARENT_WATCHED; @@ -341,15 +347,12 @@ static inline void __fsnotify_update_dcache_flags(struct dentry *dentry)  /*   * fsnotify_d_instantiate - instantiate a dentry for inode - * Called with dcache_lock held.   */  static inline void __fsnotify_d_instantiate(struct dentry *dentry, struct inode *inode)  {  	if (!inode)  		return; -	assert_spin_locked(&dcache_lock); -  	spin_lock(&dentry->d_lock);  	__fsnotify_update_dcache_flags(dentry);  	spin_unlock(&dentry->d_lock); diff --git a/include/linux/namei.h b/include/linux/namei.h index 05b441d9364..aec730b5393 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h @@ -41,7 +41,6 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};   *  - require a directory   *  - ending slashes ok even for nonexistent files   *  - internal "there are more path components" flag - *  - locked when lookup done with dcache_lock held   *  - dentry cache is untrusted; force a real lookup   */  #define LOOKUP_FOLLOW		 1 diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 7b4705b51d4..1864cb6a6a5 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -876,7 +876,6 @@ static void cgroup_clear_directory(struct dentry *dentry)  	struct list_head *node;  	BUG_ON(!mutex_is_locked(&dentry->d_inode->i_mutex)); -	spin_lock(&dcache_lock);  	spin_lock(&dentry->d_lock);  	node = dentry->d_subdirs.next;  	while (node != &dentry->d_subdirs) { @@ -891,18 +890,15 @@ static void cgroup_clear_directory(struct dentry *dentry)  			dget_locked_dlock(d);  			spin_unlock(&d->d_lock);  			spin_unlock(&dentry->d_lock); -			spin_unlock(&dcache_lock);  			d_delete(d);  			simple_unlink(dentry->d_inode, d);  			dput(d); -			spin_lock(&dcache_lock);  			spin_lock(&dentry->d_lock);  		} else  			spin_unlock(&d->d_lock);  		node = dentry->d_subdirs.next;  	}  	spin_unlock(&dentry->d_lock); -	spin_unlock(&dcache_lock);  }  /* @@ -914,14 +910,12 @@ static void cgroup_d_remove_dir(struct dentry *dentry)  	cgroup_clear_directory(dentry); -	spin_lock(&dcache_lock);  	parent = dentry->d_parent;  	spin_lock(&parent->d_lock);  	spin_lock(&dentry->d_lock);  	list_del_init(&dentry->d_u.d_child);  	spin_unlock(&dentry->d_lock);  	spin_unlock(&parent->d_lock); -	spin_unlock(&dcache_lock);  	remove_dir(dentry);  } diff --git a/mm/filemap.c b/mm/filemap.c index 6b9aee20f24..ca389394fa2 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -102,9 +102,6 @@   *    ->inode_lock		(zap_pte_range->set_page_dirty)   *    ->private_lock		(zap_pte_range->__set_page_dirty_buffers)   * - *  ->task->proc_lock - *    ->dcache_lock		(proc_pid_lookup) - *   *  (code doesn't rely on that order, so you could switch it around)   *  ->tasklist_lock             (memory_failure, collect_procs_ao)   *    ->i_mmap_lock diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 017ec096446..2285d693f29 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -1145,7 +1145,6 @@ static void sel_remove_entries(struct dentry *de)  {  	struct list_head *node; -	spin_lock(&dcache_lock);  	spin_lock(&de->d_lock);  	node = de->d_subdirs.next;  	while (node != &de->d_subdirs) { @@ -1158,11 +1157,9 @@ static void sel_remove_entries(struct dentry *de)  			dget_locked_dlock(d);  			spin_unlock(&de->d_lock);  			spin_unlock(&d->d_lock); -			spin_unlock(&dcache_lock);  			d_delete(d);  			simple_unlink(de->d_inode, d);  			dput(d); -			spin_lock(&dcache_lock);  			spin_lock(&de->d_lock);  		} else  			spin_unlock(&d->d_lock); @@ -1170,7 +1167,6 @@ static void sel_remove_entries(struct dentry *de)  	}  	spin_unlock(&de->d_lock); -	spin_unlock(&dcache_lock);  }  #define BOOL_DIR_NAME "booleans"  |