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 file changed, 25 insertions(+), 6 deletions(-)

Index: b/fs/ceph/dir.c
===================================================================
--- a/fs/ceph/dir.c
+++ b/fs/ceph/dir.c
@@ -1099,9 +1099,20 @@ static int ceph_snapdir_d_revalidate(str
        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;
@@ -1109,10 +1120,10 @@ static struct dentry * __d_find_any_alia
        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;
@@ -1124,6 +1135,9 @@ static struct dentry * d_find_any_alias(
 }
 /* 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);
@@ -1136,6 +1150,7 @@ void ceph_dir_set_complete(struct inode
                        set_bit(CEPH_D_COMPLETE, &ceph_dentry(dentry)->flags);
                }
        }
+       dput(dentry);
 }
 
 void ceph_dir_clear_complete(struct inode *inode)
@@ -1146,15 +1161,19 @@ void ceph_dir_clear_complete(struct inod
                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;
 }
 
 /*


--
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