fs: dcache scale d_unhashed
Protect d_unhashed(dentry) condition with d_lock. This means keeping DCACHE_UNHASHED bit in synch with hash manipulations. Signed-off-by: Nick Piggin <npiggin@kernel.dk>
This commit is contained in:
parent
b7ab39f631
commit
da5029563a
10 changed files with 102 additions and 54 deletions
|
@ -166,6 +166,9 @@ static void spufs_prune_dir(struct dentry *dir)
|
||||||
__d_drop(dentry);
|
__d_drop(dentry);
|
||||||
spin_unlock(&dentry->d_lock);
|
spin_unlock(&dentry->d_lock);
|
||||||
simple_unlink(dir->d_inode, dentry);
|
simple_unlink(dir->d_inode, dentry);
|
||||||
|
/* XXX: what is dcache_lock protecting here? Other
|
||||||
|
* filesystems (IB, configfs) release dcache_lock
|
||||||
|
* before unlink */
|
||||||
spin_unlock(&dcache_lock);
|
spin_unlock(&dcache_lock);
|
||||||
dput(dentry);
|
dput(dentry);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -347,10 +347,13 @@ static int usbfs_empty (struct dentry *dentry)
|
||||||
|
|
||||||
list_for_each(list, &dentry->d_subdirs) {
|
list_for_each(list, &dentry->d_subdirs) {
|
||||||
struct dentry *de = list_entry(list, struct dentry, d_u.d_child);
|
struct dentry *de = list_entry(list, struct dentry, d_u.d_child);
|
||||||
|
spin_lock(&de->d_lock);
|
||||||
if (usbfs_positive(de)) {
|
if (usbfs_positive(de)) {
|
||||||
|
spin_unlock(&de->d_lock);
|
||||||
spin_unlock(&dcache_lock);
|
spin_unlock(&dcache_lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
spin_unlock(&de->d_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock(&dcache_lock);
|
spin_unlock(&dcache_lock);
|
||||||
|
|
|
@ -254,19 +254,6 @@ static inline int simple_positive(struct dentry *dentry)
|
||||||
return dentry->d_inode && !d_unhashed(dentry);
|
return dentry->d_inode && !d_unhashed(dentry);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int __simple_empty(struct dentry *dentry)
|
|
||||||
{
|
|
||||||
struct dentry *child;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child)
|
|
||||||
if (simple_positive(child))
|
|
||||||
goto out;
|
|
||||||
ret = 1;
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void autofs4_add_expiring(struct dentry *dentry)
|
static inline void autofs4_add_expiring(struct dentry *dentry)
|
||||||
{
|
{
|
||||||
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
|
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
|
||||||
|
|
|
@ -160,14 +160,18 @@ static int autofs4_tree_busy(struct vfsmount *mnt,
|
||||||
|
|
||||||
spin_lock(&dcache_lock);
|
spin_lock(&dcache_lock);
|
||||||
for (p = top; p; p = next_dentry(p, top)) {
|
for (p = top; p; p = next_dentry(p, top)) {
|
||||||
|
spin_lock(&p->d_lock);
|
||||||
/* Negative dentry - give up */
|
/* Negative dentry - give up */
|
||||||
if (!simple_positive(p))
|
if (!simple_positive(p)) {
|
||||||
|
spin_unlock(&p->d_lock);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
DPRINTK("dentry %p %.*s",
|
DPRINTK("dentry %p %.*s",
|
||||||
p, (int) p->d_name.len, p->d_name.name);
|
p, (int) p->d_name.len, p->d_name.name);
|
||||||
|
|
||||||
p = dget(p);
|
p = dget_dlock(p);
|
||||||
|
spin_unlock(&p->d_lock);
|
||||||
spin_unlock(&dcache_lock);
|
spin_unlock(&dcache_lock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -228,14 +232,18 @@ static struct dentry *autofs4_check_leaves(struct vfsmount *mnt,
|
||||||
|
|
||||||
spin_lock(&dcache_lock);
|
spin_lock(&dcache_lock);
|
||||||
for (p = parent; p; p = next_dentry(p, parent)) {
|
for (p = parent; p; p = next_dentry(p, parent)) {
|
||||||
|
spin_lock(&p->d_lock);
|
||||||
/* Negative dentry - give up */
|
/* Negative dentry - give up */
|
||||||
if (!simple_positive(p))
|
if (!simple_positive(p)) {
|
||||||
|
spin_unlock(&p->d_lock);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
DPRINTK("dentry %p %.*s",
|
DPRINTK("dentry %p %.*s",
|
||||||
p, (int) p->d_name.len, p->d_name.name);
|
p, (int) p->d_name.len, p->d_name.name);
|
||||||
|
|
||||||
p = dget(p);
|
p = dget_dlock(p);
|
||||||
|
spin_unlock(&p->d_lock);
|
||||||
spin_unlock(&dcache_lock);
|
spin_unlock(&dcache_lock);
|
||||||
|
|
||||||
if (d_mountpoint(p)) {
|
if (d_mountpoint(p)) {
|
||||||
|
@ -324,12 +332,15 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb,
|
||||||
struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child);
|
struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child);
|
||||||
|
|
||||||
/* Negative dentry - give up */
|
/* Negative dentry - give up */
|
||||||
|
spin_lock(&dentry->d_lock);
|
||||||
if (!simple_positive(dentry)) {
|
if (!simple_positive(dentry)) {
|
||||||
next = next->next;
|
next = next->next;
|
||||||
|
spin_unlock(&dentry->d_lock);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
dentry = dget(dentry);
|
dentry = dget_dlock(dentry);
|
||||||
|
spin_unlock(&dentry->d_lock);
|
||||||
spin_unlock(&dcache_lock);
|
spin_unlock(&dcache_lock);
|
||||||
|
|
||||||
spin_lock(&sbi->fs_lock);
|
spin_lock(&sbi->fs_lock);
|
||||||
|
|
|
@ -136,6 +136,7 @@ static int __dcache_readdir(struct file *filp,
|
||||||
fi->at_end = 1;
|
fi->at_end = 1;
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
|
spin_lock(&dentry->d_lock);
|
||||||
if (!d_unhashed(dentry) && dentry->d_inode &&
|
if (!d_unhashed(dentry) && dentry->d_inode &&
|
||||||
ceph_snap(dentry->d_inode) != CEPH_SNAPDIR &&
|
ceph_snap(dentry->d_inode) != CEPH_SNAPDIR &&
|
||||||
ceph_ino(dentry->d_inode) != CEPH_INO_CEPH &&
|
ceph_ino(dentry->d_inode) != CEPH_INO_CEPH &&
|
||||||
|
@ -145,13 +146,13 @@ static int __dcache_readdir(struct file *filp,
|
||||||
dentry->d_name.len, dentry->d_name.name, di->offset,
|
dentry->d_name.len, dentry->d_name.name, di->offset,
|
||||||
filp->f_pos, d_unhashed(dentry) ? " unhashed" : "",
|
filp->f_pos, d_unhashed(dentry) ? " unhashed" : "",
|
||||||
!dentry->d_inode ? " null" : "");
|
!dentry->d_inode ? " null" : "");
|
||||||
|
spin_unlock(&dentry->d_lock);
|
||||||
p = p->prev;
|
p = p->prev;
|
||||||
dentry = list_entry(p, struct dentry, d_u.d_child);
|
dentry = list_entry(p, struct dentry, d_u.d_child);
|
||||||
di = ceph_dentry(dentry);
|
di = ceph_dentry(dentry);
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock(&dentry->d_lock);
|
dget_dlock(dentry);
|
||||||
dentry->d_count++;
|
|
||||||
spin_unlock(&dentry->d_lock);
|
spin_unlock(&dentry->d_lock);
|
||||||
spin_unlock(&dcache_lock);
|
spin_unlock(&dcache_lock);
|
||||||
|
|
||||||
|
|
|
@ -121,6 +121,7 @@ static inline struct config_item *configfs_get_config_item(struct dentry *dentry
|
||||||
struct config_item * item = NULL;
|
struct config_item * item = NULL;
|
||||||
|
|
||||||
spin_lock(&dcache_lock);
|
spin_lock(&dcache_lock);
|
||||||
|
spin_lock(&dentry->d_lock);
|
||||||
if (!d_unhashed(dentry)) {
|
if (!d_unhashed(dentry)) {
|
||||||
struct configfs_dirent * sd = dentry->d_fsdata;
|
struct configfs_dirent * sd = dentry->d_fsdata;
|
||||||
if (sd->s_type & CONFIGFS_ITEM_LINK) {
|
if (sd->s_type & CONFIGFS_ITEM_LINK) {
|
||||||
|
@ -129,6 +130,7 @@ static inline struct config_item *configfs_get_config_item(struct dentry *dentry
|
||||||
} else
|
} else
|
||||||
item = config_item_get(sd->s_element);
|
item = config_item_get(sd->s_element);
|
||||||
}
|
}
|
||||||
|
spin_unlock(&dentry->d_lock);
|
||||||
spin_unlock(&dcache_lock);
|
spin_unlock(&dcache_lock);
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
|
|
74
fs/dcache.c
74
fs/dcache.c
|
@ -46,6 +46,7 @@
|
||||||
* - d_name
|
* - d_name
|
||||||
* - d_lru
|
* - d_lru
|
||||||
* - d_count
|
* - d_count
|
||||||
|
* - d_unhashed()
|
||||||
*
|
*
|
||||||
* Ordering:
|
* Ordering:
|
||||||
* dcache_lock
|
* dcache_lock
|
||||||
|
@ -53,6 +54,13 @@
|
||||||
* dcache_lru_lock
|
* dcache_lru_lock
|
||||||
* dcache_hash_lock
|
* dcache_hash_lock
|
||||||
*
|
*
|
||||||
|
* If there is an ancestor relationship:
|
||||||
|
* dentry->d_parent->...->d_parent->d_lock
|
||||||
|
* ...
|
||||||
|
* dentry->d_parent->d_lock
|
||||||
|
* dentry->d_lock
|
||||||
|
*
|
||||||
|
* If no ancestor relationship:
|
||||||
* if (dentry1 < dentry2)
|
* if (dentry1 < dentry2)
|
||||||
* dentry1->d_lock
|
* dentry1->d_lock
|
||||||
* dentry2->d_lock
|
* dentry2->d_lock
|
||||||
|
@ -379,7 +387,9 @@ int d_invalidate(struct dentry * dentry)
|
||||||
* If it's already been dropped, return OK.
|
* If it's already been dropped, return OK.
|
||||||
*/
|
*/
|
||||||
spin_lock(&dcache_lock);
|
spin_lock(&dcache_lock);
|
||||||
|
spin_lock(&dentry->d_lock);
|
||||||
if (d_unhashed(dentry)) {
|
if (d_unhashed(dentry)) {
|
||||||
|
spin_unlock(&dentry->d_lock);
|
||||||
spin_unlock(&dcache_lock);
|
spin_unlock(&dcache_lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -388,9 +398,11 @@ int d_invalidate(struct dentry * dentry)
|
||||||
* to get rid of unused child entries.
|
* to get rid of unused child entries.
|
||||||
*/
|
*/
|
||||||
if (!list_empty(&dentry->d_subdirs)) {
|
if (!list_empty(&dentry->d_subdirs)) {
|
||||||
|
spin_unlock(&dentry->d_lock);
|
||||||
spin_unlock(&dcache_lock);
|
spin_unlock(&dcache_lock);
|
||||||
shrink_dcache_parent(dentry);
|
shrink_dcache_parent(dentry);
|
||||||
spin_lock(&dcache_lock);
|
spin_lock(&dcache_lock);
|
||||||
|
spin_lock(&dentry->d_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -403,7 +415,6 @@ int d_invalidate(struct dentry * dentry)
|
||||||
* we might still populate it if it was a
|
* we might still populate it if it was a
|
||||||
* working directory or similar).
|
* working directory or similar).
|
||||||
*/
|
*/
|
||||||
spin_lock(&dentry->d_lock);
|
|
||||||
if (dentry->d_count > 1) {
|
if (dentry->d_count > 1) {
|
||||||
if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) {
|
if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) {
|
||||||
spin_unlock(&dentry->d_lock);
|
spin_unlock(&dentry->d_lock);
|
||||||
|
@ -490,35 +501,44 @@ EXPORT_SYMBOL(dget_parent);
|
||||||
* any other hashed alias over that one unless @want_discon is set,
|
* any other hashed alias over that one unless @want_discon is set,
|
||||||
* in which case only return an IS_ROOT, DCACHE_DISCONNECTED alias.
|
* in which case only return an IS_ROOT, DCACHE_DISCONNECTED alias.
|
||||||
*/
|
*/
|
||||||
|
static struct dentry *__d_find_alias(struct inode *inode, int want_discon)
|
||||||
static struct dentry * __d_find_alias(struct inode *inode, int want_discon)
|
|
||||||
{
|
{
|
||||||
struct list_head *head, *next, *tmp;
|
struct dentry *alias, *discon_alias;
|
||||||
struct dentry *alias, *discon_alias=NULL;
|
|
||||||
|
|
||||||
head = &inode->i_dentry;
|
again:
|
||||||
next = inode->i_dentry.next;
|
discon_alias = NULL;
|
||||||
while (next != head) {
|
list_for_each_entry(alias, &inode->i_dentry, d_alias) {
|
||||||
tmp = next;
|
spin_lock(&alias->d_lock);
|
||||||
next = tmp->next;
|
|
||||||
prefetch(next);
|
|
||||||
alias = list_entry(tmp, struct dentry, d_alias);
|
|
||||||
if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) {
|
if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) {
|
||||||
if (IS_ROOT(alias) &&
|
if (IS_ROOT(alias) &&
|
||||||
(alias->d_flags & DCACHE_DISCONNECTED))
|
(alias->d_flags & DCACHE_DISCONNECTED)) {
|
||||||
discon_alias = alias;
|
discon_alias = alias;
|
||||||
else if (!want_discon) {
|
} else if (!want_discon) {
|
||||||
__dget_locked(alias);
|
__dget_locked_dlock(alias);
|
||||||
|
spin_unlock(&alias->d_lock);
|
||||||
return alias;
|
return alias;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
spin_unlock(&alias->d_lock);
|
||||||
}
|
}
|
||||||
if (discon_alias)
|
if (discon_alias) {
|
||||||
__dget_locked(discon_alias);
|
alias = discon_alias;
|
||||||
return discon_alias;
|
spin_lock(&alias->d_lock);
|
||||||
|
if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) {
|
||||||
|
if (IS_ROOT(alias) &&
|
||||||
|
(alias->d_flags & DCACHE_DISCONNECTED)) {
|
||||||
|
__dget_locked_dlock(alias);
|
||||||
|
spin_unlock(&alias->d_lock);
|
||||||
|
return alias;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spin_unlock(&alias->d_lock);
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct dentry * d_find_alias(struct inode *inode)
|
struct dentry *d_find_alias(struct inode *inode)
|
||||||
{
|
{
|
||||||
struct dentry *de = NULL;
|
struct dentry *de = NULL;
|
||||||
|
|
||||||
|
@ -801,8 +821,8 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
|
||||||
spin_lock(&dcache_lock);
|
spin_lock(&dcache_lock);
|
||||||
spin_lock(&dentry->d_lock);
|
spin_lock(&dentry->d_lock);
|
||||||
dentry_lru_del(dentry);
|
dentry_lru_del(dentry);
|
||||||
spin_unlock(&dentry->d_lock);
|
|
||||||
__d_drop(dentry);
|
__d_drop(dentry);
|
||||||
|
spin_unlock(&dentry->d_lock);
|
||||||
spin_unlock(&dcache_lock);
|
spin_unlock(&dcache_lock);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
@ -817,8 +837,8 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
|
||||||
d_u.d_child) {
|
d_u.d_child) {
|
||||||
spin_lock(&loop->d_lock);
|
spin_lock(&loop->d_lock);
|
||||||
dentry_lru_del(loop);
|
dentry_lru_del(loop);
|
||||||
spin_unlock(&loop->d_lock);
|
|
||||||
__d_drop(loop);
|
__d_drop(loop);
|
||||||
|
spin_unlock(&loop->d_lock);
|
||||||
cond_resched_lock(&dcache_lock);
|
cond_resched_lock(&dcache_lock);
|
||||||
}
|
}
|
||||||
spin_unlock(&dcache_lock);
|
spin_unlock(&dcache_lock);
|
||||||
|
@ -1863,7 +1883,10 @@ static void d_move_locked(struct dentry * dentry, struct dentry * target)
|
||||||
/*
|
/*
|
||||||
* XXXX: do we really need to take target->d_lock?
|
* XXXX: do we really need to take target->d_lock?
|
||||||
*/
|
*/
|
||||||
if (target < dentry) {
|
if (d_ancestor(dentry, target)) {
|
||||||
|
spin_lock(&dentry->d_lock);
|
||||||
|
spin_lock_nested(&target->d_lock, DENTRY_D_LOCK_NESTED);
|
||||||
|
} else if (d_ancestor(target, dentry) || target < dentry) {
|
||||||
spin_lock(&target->d_lock);
|
spin_lock(&target->d_lock);
|
||||||
spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
|
spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
|
||||||
} else {
|
} else {
|
||||||
|
@ -2542,13 +2565,16 @@ void d_genocide(struct dentry *root)
|
||||||
struct list_head *tmp = next;
|
struct list_head *tmp = next;
|
||||||
struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child);
|
struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child);
|
||||||
next = tmp->next;
|
next = tmp->next;
|
||||||
if (d_unhashed(dentry)||!dentry->d_inode)
|
spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
|
||||||
|
if (d_unhashed(dentry) || !dentry->d_inode) {
|
||||||
|
spin_unlock(&dentry->d_lock);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
if (!list_empty(&dentry->d_subdirs)) {
|
if (!list_empty(&dentry->d_subdirs)) {
|
||||||
|
spin_unlock(&dentry->d_lock);
|
||||||
this_parent = dentry;
|
this_parent = dentry;
|
||||||
goto repeat;
|
goto repeat;
|
||||||
}
|
}
|
||||||
spin_lock(&dentry->d_lock);
|
|
||||||
dentry->d_count--;
|
dentry->d_count--;
|
||||||
spin_unlock(&dentry->d_lock);
|
spin_unlock(&dentry->d_lock);
|
||||||
}
|
}
|
||||||
|
|
29
fs/libfs.c
29
fs/libfs.c
|
@ -16,6 +16,11 @@
|
||||||
|
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
|
|
||||||
|
static inline int simple_positive(struct dentry *dentry)
|
||||||
|
{
|
||||||
|
return dentry->d_inode && !d_unhashed(dentry);
|
||||||
|
}
|
||||||
|
|
||||||
int simple_getattr(struct vfsmount *mnt, struct dentry *dentry,
|
int simple_getattr(struct vfsmount *mnt, struct dentry *dentry,
|
||||||
struct kstat *stat)
|
struct kstat *stat)
|
||||||
{
|
{
|
||||||
|
@ -100,8 +105,10 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin)
|
||||||
while (n && p != &file->f_path.dentry->d_subdirs) {
|
while (n && p != &file->f_path.dentry->d_subdirs) {
|
||||||
struct dentry *next;
|
struct dentry *next;
|
||||||
next = list_entry(p, struct dentry, d_u.d_child);
|
next = list_entry(p, struct dentry, d_u.d_child);
|
||||||
if (!d_unhashed(next) && next->d_inode)
|
spin_lock(&next->d_lock);
|
||||||
|
if (simple_positive(next))
|
||||||
n--;
|
n--;
|
||||||
|
spin_unlock(&next->d_lock);
|
||||||
p = p->next;
|
p = p->next;
|
||||||
}
|
}
|
||||||
list_add_tail(&cursor->d_u.d_child, p);
|
list_add_tail(&cursor->d_u.d_child, p);
|
||||||
|
@ -155,9 +162,13 @@ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir)
|
||||||
for (p=q->next; p != &dentry->d_subdirs; p=p->next) {
|
for (p=q->next; p != &dentry->d_subdirs; p=p->next) {
|
||||||
struct dentry *next;
|
struct dentry *next;
|
||||||
next = list_entry(p, struct dentry, d_u.d_child);
|
next = list_entry(p, struct dentry, d_u.d_child);
|
||||||
if (d_unhashed(next) || !next->d_inode)
|
spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED);
|
||||||
|
if (!simple_positive(next)) {
|
||||||
|
spin_unlock(&next->d_lock);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_unlock(&next->d_lock);
|
||||||
spin_unlock(&dcache_lock);
|
spin_unlock(&dcache_lock);
|
||||||
if (filldir(dirent, next->d_name.name,
|
if (filldir(dirent, next->d_name.name,
|
||||||
next->d_name.len, filp->f_pos,
|
next->d_name.len, filp->f_pos,
|
||||||
|
@ -259,20 +270,20 @@ int simple_link(struct dentry *old_dentry, struct inode *dir, struct dentry *den
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int simple_positive(struct dentry *dentry)
|
|
||||||
{
|
|
||||||
return dentry->d_inode && !d_unhashed(dentry);
|
|
||||||
}
|
|
||||||
|
|
||||||
int simple_empty(struct dentry *dentry)
|
int simple_empty(struct dentry *dentry)
|
||||||
{
|
{
|
||||||
struct dentry *child;
|
struct dentry *child;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
spin_lock(&dcache_lock);
|
spin_lock(&dcache_lock);
|
||||||
list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child)
|
list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) {
|
||||||
if (simple_positive(child))
|
spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED);
|
||||||
|
if (simple_positive(child)) {
|
||||||
|
spin_unlock(&child->d_lock);
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
|
spin_unlock(&child->d_lock);
|
||||||
|
}
|
||||||
ret = 1;
|
ret = 1;
|
||||||
out:
|
out:
|
||||||
spin_unlock(&dcache_lock);
|
spin_unlock(&dcache_lock);
|
||||||
|
|
|
@ -174,13 +174,16 @@ struct dentry *ocfs2_find_local_alias(struct inode *inode,
|
||||||
list_for_each(p, &inode->i_dentry) {
|
list_for_each(p, &inode->i_dentry) {
|
||||||
dentry = list_entry(p, struct dentry, d_alias);
|
dentry = list_entry(p, struct dentry, d_alias);
|
||||||
|
|
||||||
|
spin_lock(&dentry->d_lock);
|
||||||
if (ocfs2_match_dentry(dentry, parent_blkno, skip_unhashed)) {
|
if (ocfs2_match_dentry(dentry, parent_blkno, skip_unhashed)) {
|
||||||
mlog(0, "dentry found: %.*s\n",
|
mlog(0, "dentry found: %.*s\n",
|
||||||
dentry->d_name.len, dentry->d_name.name);
|
dentry->d_name.len, dentry->d_name.name);
|
||||||
|
|
||||||
dget_locked(dentry);
|
dget_locked_dlock(dentry);
|
||||||
|
spin_unlock(&dentry->d_lock);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
spin_unlock(&dentry->d_lock);
|
||||||
|
|
||||||
dentry = NULL;
|
dentry = NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <net/sock.h>
|
#include <net/sock.h>
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "../../fs/internal.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tomoyo_encode: Convert binary string to ascii string.
|
* tomoyo_encode: Convert binary string to ascii string.
|
||||||
|
|
Loading…
Reference in a new issue