* RHEL 4 and RHEL 5/SLES 10 clients behaves differently on 'cd' to a
removed cwd "./" (refer to Bugzilla 14399).
+Severity : normal
+Bugzilla : 15975
+Frequency : only patchless client
+Description: add workaround for race between add/remove dentry from hash
+
Severity : enhancement
Bugzilla : 16845
Description: Allow OST glimpses to return PW locks
#include "llite_internal.h"
+spinlock_t ll_lookup_lock = SPIN_LOCK_UNLOCKED;
+
/* should NOT be called with the dcache lock, see fs/dcache.c */
void ll_release(struct dentry *de)
{
__d_drop(dentry);
unlock_dentry(dentry);
spin_unlock(&dcache_lock);
+ spin_unlock(&ll_lookup_lock);
dput(dentry);
+ spin_lock(&ll_lookup_lock);
spin_lock(&dcache_lock);
return 1;
}
inode->i_ino, inode->i_generation, inode);
head = &inode->i_dentry;
+ spin_lock(&ll_lookup_lock);
spin_lock(&dcache_lock);
restart:
tmp = head;
goto restart;
}
spin_unlock(&dcache_lock);
+ spin_unlock(&ll_lookup_lock);
+
EXIT;
}
/* unfortunately ll_intent_lock may cause a callback and revoke our
* dentry */
+ spin_lock(&ll_lookup_lock);
spin_lock(&dcache_lock);
lock_dentry(de);
__d_drop(de);
unlock_dentry(de);
d_rehash_cond(de, 0);
spin_unlock(&dcache_lock);
+ spin_unlock(&ll_lookup_lock);
out:
/* We do not free request as it may be reused during following lookup
here to preserve get_cwd functionality on 2.6.
Bug 10503 */
if (!dentry->d_inode->i_nlink) {
+ spin_lock(&ll_lookup_lock);
spin_lock(&dcache_lock);
ll_drop_dentry(dentry);
spin_unlock(&dcache_lock);
+ spin_unlock(&ll_lookup_lock);
}
ll_lookup_finish_locks(&oit, dentry);
void *data, int flag);
/* llite/dcache.c */
+/* llite/namei.c */
+/**
+ * protect race ll_find_aliases vs ll_revalidate_it vs ll_unhash_aliases
+ */
+extern spinlock_t ll_lookup_lock;
extern struct dentry_operations ll_init_d_ops;
extern struct dentry_operations ll_d_ops;
extern struct dentry_operations ll_fini_d_ops;
{
struct dentry *dentry, *tmp_alias, *tmp_subdir;
+ spin_lock(&ll_lookup_lock);
spin_lock(&dcache_lock);
restart:
list_for_each_entry_safe(dentry, tmp_alias,
}
}
spin_unlock(&dcache_lock);
+ spin_unlock(&ll_lookup_lock);
}
struct dentry *dentry;
struct dentry *last_discon = NULL;
+ spin_lock(&ll_lookup_lock);
spin_lock(&dcache_lock);
list_for_each(tmp, &inode->i_dentry) {
dentry = list_entry(tmp, struct dentry, d_alias);
unlock_dentry(dentry);
d_rehash_cond(dentry, 0); /* avoid taking dcache_lock inside */
spin_unlock(&dcache_lock);
+ spin_unlock(&ll_lookup_lock);
iput(inode);
CDEBUG(D_DENTRY, "alias dentry %.*s (%p) parent %p inode %p "
"refc %d\n", de->d_name.len, de->d_name.name, de,
atomic_read(&last_discon->d_count));
dget_locked(last_discon);
spin_unlock(&dcache_lock);
+ spin_unlock(&ll_lookup_lock);
d_rehash(de);
d_move(last_discon, de);
iput(inode);
ll_d_add(de, inode);
spin_unlock(&dcache_lock);
+ spin_unlock(&ll_lookup_lock);
return de;
}