[Lustre-discuss] Looping in __d_lookup
Andreas Dilger
adilger at sun.com
Fri Jun 13 03:26:44 PDT 2008
On Jun 13, 2008 10:16 +0200, Johann Lombardi wrote:
> On Wed, Jun 04, 2008 at 11:25:34AM +0200, Jakob Goldbach wrote:
> > > > > @@ -470,8 +470,8 @@ revalidate_finish:
> > > > > spin_lock(&dcache_lock);
> > > > > lock_dentry(de);
> > > > > __d_drop(de);
> > > > > + _d_rehash(de);
> > > > > unlock_dentry(de);
> > > > > - __d_rehash(de, 0);
> > > > > spin_unlock(&dcache_lock);
>
> Actually, _d_rehash() is not exported by the kernel, so I assume that you have
> patched the kernel. At least, that's what I understand from the OpenVZ ticket:
> http://bugzilla.openvz.org/show_bug.cgi?id=895#c27
>
> Of course, we cannot do this for patchless clients :(
> > Im calling _d_rehash which Andres suggest
> > to be defined in lustre_pathcless_compat.h. Your cut is from kernel
> > pathces anyway. My race happens on _patchless_ client.
>
> As Yangsheng pointed out, the problem is that d_hash() cannot be used
> by Lustre since the dentry_hashtable symbol is not exported.
Doh! I looked at this code a couple of times, but didn't think that
d_hash() would be using an internal pointer. What could be pretty easy
to do is to extract the value for the dentry_hashtable pointer during
the filesystem init and make our own pointer with the same value.
struct hlist_head *ll_dentry_hashtable;
struct hlist_head *ll_d_hash(struct dentry *parent, unsigned long hash)
{
hash += ((unsigned long) parent ^ GOLDEN_RATIO_PRIME) / L1_CACHE_BYTES;
hash = hash ^ ((hash ^ GOLDEN_RATIO_PRIME) >> D_HASHBITS);
return ll_dentry_hashtable + (hash & D_HASHMASK);
}
static inline void ll_d_rehash(struct dentry *dentry)
{
dentry->d_flags &= ~DCACHE_UNHASHED;
hlist_add_head_rcu(&dentry->d_hash, ll_d_hash(dentry->d_parent,
dentry->d_name.hash));
}
static int init_lustre_lite()
{
struct dentry dummy;
unsigned int dummy_hash;
struct hlist_node *pprev = NULL, *pprev2;
/* The first time ll_d_hash() is called, ll_dentry_hashtable == NULL,
* so it returns only the hash table bucket offset. We use this to
* figure out the un-exported dentry_hashtable pointer. This might
* be racy (we aren't guaranteed to still be the first entry on the
* hash chain, so it should be called a few times to verify. */
memset(&dummy, 0, sizeof(dummy));
spin_lock_init(&dummy.d_lock);
dummy_hash = ll_d_hash(&dummy, 0);
while (pprev != pprev2) {
d_rehash(&dummy);
pprev2 = pprev;
pprev = dummy.d_hash.pprev
hlist_del_rcu(&dummy.d_hash);
}
ll_dentry_hashtable = pprev - dummy_hash;
Cheers, Andreas
--
Andreas Dilger
Sr. Staff Engineer, Lustre Group
Sun Microsystems of Canada, Inc.
More information about the lustre-discuss
mailing list