*/
 static void d_free(struct dentry *dentry)
 {
-       BUG_ON(dentry->d_count);
+       BUG_ON(dentry->d_lockref.count);
        this_cpu_dec(nr_dentry);
        if (dentry->d_op && dentry->d_op->d_release)
                dentry->d_op->d_release(dentry);
        }
 
        if (ref)
-               dentry->d_count--;
+               dentry->d_lockref.count--;
        /*
         * inform the fs via d_prune that this dentry is about to be
         * unhashed and destroyed.
                return;
 
 repeat:
-       if (dentry->d_count == 1)
+       if (dentry->d_lockref.count == 1)
                might_sleep();
-       spin_lock(&dentry->d_lock);
-       BUG_ON(!dentry->d_count);
-       if (dentry->d_count > 1) {
-               dentry->d_count--;
-               spin_unlock(&dentry->d_lock);
+       if (lockref_put_or_lock(&dentry->d_lockref))
                return;
-       }
 
        if (dentry->d_flags & DCACHE_OP_DELETE) {
                if (dentry->d_op->d_delete(dentry))
        dentry->d_flags |= DCACHE_REFERENCED;
        dentry_lru_add(dentry);
 
-       dentry->d_count--;
+       dentry->d_lockref.count--;
        spin_unlock(&dentry->d_lock);
        return;
 
         * We also need to leave mountpoints alone,
         * directory or not.
         */
-       if (dentry->d_count > 1 && dentry->d_inode) {
+       if (dentry->d_lockref.count > 1 && dentry->d_inode) {
                if (S_ISDIR(dentry->d_inode->i_mode) || d_mountpoint(dentry)) {
                        spin_unlock(&dentry->d_lock);
                        return -EBUSY;
 /* This must be called with d_lock held */
 static inline void __dget_dlock(struct dentry *dentry)
 {
-       dentry->d_count++;
+       dentry->d_lockref.count++;
 }
 
 static inline void __dget(struct dentry *dentry)
 {
-       spin_lock(&dentry->d_lock);
-       __dget_dlock(dentry);
-       spin_unlock(&dentry->d_lock);
+       lockref_get(&dentry->d_lockref);
 }
 
 struct dentry *dget_parent(struct dentry *dentry)
                goto repeat;
        }
        rcu_read_unlock();
-       BUG_ON(!ret->d_count);
-       ret->d_count++;
+       BUG_ON(!ret->d_lockref.count);
+       ret->d_lockref.count++;
        spin_unlock(&ret->d_lock);
        return ret;
 }
        spin_lock(&inode->i_lock);
        hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
                spin_lock(&dentry->d_lock);
-               if (!dentry->d_count) {
+               if (!dentry->d_lockref.count) {
                        __dget_dlock(dentry);
                        __d_drop(dentry);
                        spin_unlock(&dentry->d_lock);
        /* Prune ancestors. */
        dentry = parent;
        while (dentry) {
-               spin_lock(&dentry->d_lock);
-               if (dentry->d_count > 1) {
-                       dentry->d_count--;
-                       spin_unlock(&dentry->d_lock);
+               if (lockref_put_or_lock(&dentry->d_lockref))
                        return;
-               }
                dentry = dentry_kill(dentry, 1);
        }
 }
                 * the LRU because of laziness during lookup.  Do not free
                 * it - just keep it off the LRU list.
                 */
-               if (dentry->d_count) {
+               if (dentry->d_lockref.count) {
                        dentry_lru_del(dentry);
                        spin_unlock(&dentry->d_lock);
                        continue;
                        dentry_lru_del(dentry);
                        __d_shrink(dentry);
 
-                       if (dentry->d_count != 0) {
+                       if (dentry->d_lockref.count != 0) {
                                printk(KERN_ERR
                                       "BUG: Dentry %p{i=%lx,n=%s}"
                                       " still in use (%d)"
                                       dentry->d_inode ?
                                       dentry->d_inode->i_ino : 0UL,
                                       dentry->d_name.name,
-                                      dentry->d_count,
+                                      dentry->d_lockref.count,
                                       dentry->d_sb->s_type->name,
                                       dentry->d_sb->s_id);
                                BUG();
                                list_del(&dentry->d_u.d_child);
                        } else {
                                parent = dentry->d_parent;
-                               parent->d_count--;
+                               parent->d_lockref.count--;
                                list_del(&dentry->d_u.d_child);
                        }
 
 
        dentry = sb->s_root;
        sb->s_root = NULL;
-       dentry->d_count--;
+       dentry->d_lockref.count--;
        shrink_dcache_for_umount_subtree(dentry);
 
        while (!hlist_bl_empty(&sb->s_anon)) {
                 * loop in shrink_dcache_parent() might not make any progress
                 * and loop forever.
                 */
-               if (dentry->d_count) {
+               if (dentry->d_lockref.count) {
                        dentry_lru_del(dentry);
                } else if (!(dentry->d_flags & DCACHE_SHRINK_LIST)) {
                        dentry_lru_move_list(dentry, dispose);
        smp_wmb();
        dentry->d_name.name = dname;
 
-       dentry->d_count = 1;
+       dentry->d_lockref.count = 1;
        dentry->d_flags = 0;
        spin_lock_init(&dentry->d_lock);
        seqcount_init(&dentry->d_seq);
                                goto next;
                }
 
-               dentry->d_count++;
+               dentry->d_lockref.count++;
                found = dentry;
                spin_unlock(&dentry->d_lock);
                break;
        spin_lock(&dentry->d_lock);
        inode = dentry->d_inode;
        isdir = S_ISDIR(inode->i_mode);
-       if (dentry->d_count == 1) {
+       if (dentry->d_lockref.count == 1) {
                if (!spin_trylock(&inode->i_lock)) {
                        spin_unlock(&dentry->d_lock);
                        cpu_relax();
                }
                if (!(dentry->d_flags & DCACHE_GENOCIDE)) {
                        dentry->d_flags |= DCACHE_GENOCIDE;
-                       dentry->d_count--;
+                       dentry->d_lockref.count--;
                }
                spin_unlock(&dentry->d_lock);
        }
                struct dentry *child = this_parent;
                if (!(this_parent->d_flags & DCACHE_GENOCIDE)) {
                        this_parent->d_flags |= DCACHE_GENOCIDE;
-                       this_parent->d_count--;
+                       this_parent->d_lockref.count--;
                }
                this_parent = try_to_ascend(this_parent, locked, seq);
                if (!this_parent)
 
 #include <linux/seqlock.h>
 #include <linux/cache.h>
 #include <linux/rcupdate.h>
+#include <linux/lockref.h>
 
 struct nameidata;
 struct path;
 # endif
 #endif
 
+#define d_lock d_lockref.lock
+
 struct dentry {
        /* RCU lookup touched fields */
        unsigned int d_flags;           /* protected by d_lock */
        unsigned char d_iname[DNAME_INLINE_LEN];        /* small names */
 
        /* Ref lookup also touches following */
-       unsigned int d_count;           /* protected by d_lock */
-       spinlock_t d_lock;              /* per dentry lock */
+       struct lockref d_lockref;       /* per-dentry lock and refcount */
        const struct dentry_operations *d_op;
        struct super_block *d_sb;       /* The root of the dentry tree */
        unsigned long d_time;           /* used by d_revalidate */
        assert_spin_locked(&dentry->d_lock);
        if (!read_seqcount_retry(&dentry->d_seq, seq)) {
                ret = 1;
-               dentry->d_count++;
+               dentry->d_lockref.count++;
        }
 
        return ret;
 
 static inline unsigned d_count(const struct dentry *dentry)
 {
-       return dentry->d_count;
+       return dentry->d_lockref.count;
 }
 
 /* validate "insecure" dentry pointer */
 static inline struct dentry *dget_dlock(struct dentry *dentry)
 {
        if (dentry)
-               dentry->d_count++;
+               dentry->d_lockref.count++;
        return dentry;
 }
 
 static inline struct dentry *dget(struct dentry *dentry)
 {
-       if (dentry) {
-               spin_lock(&dentry->d_lock);
-               dget_dlock(dentry);
-               spin_unlock(&dentry->d_lock);
-       }
+       if (dentry)
+               lockref_get(&dentry->d_lockref);
        return dentry;
 }