From: Alex Elder <[email protected]>

The ceph code duplicates __d_find_any_alias(), but it currently
does not take a reference to the returned dentry as it should.
Replace the ceph implementation with an exact copy of what's
found in "fs/dcache.c", and update the callers so they drop
their reference when they're done with it.

Unfortunately this requires the wholesale copy of the functions
that implement __dget().  It would be much nicer to just export
d_find_any_alias() from "fs/dcache.c" instead.

Signed-off-by: Alex Elder <[email protected]>
---
 fs/ceph/dir.c |   31 +++++++++++++++++++++++++------
 1 files changed, 25 insertions(+), 6 deletions(-)

diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
index e58b0d1..caddb7d 100644
--- a/fs/ceph/dir.c
+++ b/fs/ceph/dir.c
@@ -1091,9 +1091,20 @@ static int ceph_snapdir_d_revalidate(struct dentry 
*dentry,
        return 1;
 }
 
-/*
- * Set/clear/test dir complete flag on the dir's dentry.
- */
+/* The following code copied from "fs/dcache.c" */
+/* This must be called with d_lock held */
+static inline void __dget_dlock(struct dentry *dentry)
+{
+       dentry->d_count++;
+}
+
+static inline void __dget(struct dentry *dentry)
+{
+       spin_lock(&dentry->d_lock);
+       __dget_dlock(dentry);
+       spin_unlock(&dentry->d_lock);
+}
+
 static struct dentry * __d_find_any_alias(struct inode *inode)
 {
        struct dentry *alias;
@@ -1101,10 +1112,10 @@ static struct dentry * __d_find_any_alias(struct inode 
*inode)
        if (list_empty(&inode->i_dentry))
                return NULL;
        alias = list_first_entry(&inode->i_dentry, struct dentry, d_alias);
+       __dget(alias);
        return alias;
 }
 
-/* The following code copied from "fs/dcache.c" */
 static struct dentry * d_find_any_alias(struct inode *inode)
 {
        struct dentry *de;
@@ -1116,6 +1127,9 @@ static struct dentry * d_find_any_alias(struct inode 
*inode)
 }
 /* End of code copied from "fs/dcache.c" */
 
+/*
+ * Set/clear/test dir complete flag on the dir's dentry.
+ */
 void ceph_dir_set_complete(struct inode *inode)
 {
        struct dentry *dentry = d_find_any_alias(inode);
@@ -1124,6 +1138,7 @@ void ceph_dir_set_complete(struct inode *inode)
                dout(" marking %p (%p) complete\n", inode, dentry);
                set_bit(CEPH_D_COMPLETE, &ceph_dentry(dentry)->flags);
        }
+       dput(dentry);
 }
 
 void ceph_dir_clear_complete(struct inode *inode)
@@ -1134,15 +1149,19 @@ void ceph_dir_clear_complete(struct inode *inode)
                dout(" marking %p (%p) NOT complete\n", inode, dentry);
                clear_bit(CEPH_D_COMPLETE, &ceph_dentry(dentry)->flags);
        }
+       dput(dentry);
 }
 
 bool ceph_dir_test_complete(struct inode *inode)
 {
        struct dentry *dentry = d_find_any_alias(inode);
+       bool ret = false;
 
        if (dentry && ceph_dentry(dentry))
-               return test_bit(CEPH_D_COMPLETE, &ceph_dentry(dentry)->flags);
-       return false;
+               ret = test_bit(CEPH_D_COMPLETE, &ceph_dentry(dentry)->flags);
+       dput(dentry);
+
+       return ret;
 }
 
 /*
-- 
1.7.2.5

--
To unsubscribe from this list: send the line "unsubscribe ceph-devel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to