Browse Source

fs: dcache remove dcache_lock

dcache_lock no longer protects anything. remove it.

Signed-off-by: Nick Piggin <npiggin@kernel.dk>
master
Nick Piggin 11 years ago
parent
commit
b5c84bf6f6
  1. 16
      Documentation/filesystems/Locking
  2. 40
      Documentation/filesystems/dentry-locking.txt
  3. 8
      Documentation/filesystems/porting
  4. 5
      arch/powerpc/platforms/cell/spufs/inode.c
  5. 6
      drivers/infiniband/hw/ipath/ipath_fs.c
  6. 3
      drivers/infiniband/hw/qib/qib_fs.c
  7. 2
      drivers/staging/pohmelfs/path_entry.c
  8. 4
      drivers/staging/smbfs/cache.c
  9. 3
      drivers/usb/core/inode.c
  10. 2
      fs/9p/vfs_inode.c
  11. 2
      fs/affs/amigaffs.c
  12. 3
      fs/autofs4/autofs_i.h
  13. 10
      fs/autofs4/expire.c
  14. 44
      fs/autofs4/root.c
  15. 7
      fs/autofs4/waitq.c
  16. 6
      fs/ceph/dir.c
  17. 4
      fs/ceph/inode.c
  18. 3
      fs/cifs/inode.c
  19. 2
      fs/coda/cache.c
  20. 2
      fs/configfs/configfs_internal.h
  21. 6
      fs/configfs/inode.c
  22. 160
      fs/dcache.c
  23. 4
      fs/exportfs/expfs.c
  24. 8
      fs/libfs.c
  25. 9
      fs/namei.c
  26. 3
      fs/ncpfs/dir.c
  27. 4
      fs/ncpfs/ncplib_kernel.h
  28. 3
      fs/nfs/dir.c
  29. 2
      fs/nfs/getroot.c
  30. 3
      fs/nfs/namespace.c
  31. 2
      fs/notify/fsnotify.c
  32. 2
      fs/ocfs2/dcache.c
  33. 5
      include/linux/dcache.h
  34. 6
      include/linux/fs.h
  35. 2
      include/linux/fsnotify.h
  36. 11
      include/linux/fsnotify_backend.h
  37. 1
      include/linux/namei.h
  38. 6
      kernel/cgroup.c
  39. 3
      mm/filemap.c
  40. 4
      security/selinux/selinuxfs.c

16
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:

40
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.
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.
hlist_add_head_rcu() since we don't have lock protection
while traversing the hash chain.
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

8
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.

5
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);

6
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:

3
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;

2
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;

4
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;
}

3
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;
}

2
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;
}

2
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);
}

3
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

10
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;
}

44
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);

7
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;

6
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);

4
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;

3
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;
}

2
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;
}

2
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;
}

6
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);
}
}
}

160
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));