Unionfs: Cleanup new_dentry_private_data
authorErez_Zadok <ezk@cs.sunysb.edu>
Fri, 16 Nov 2007 19:51:39 +0000 (14:51 -0500)
committerRachita Kothiyal <rachita@dewey.fsl.cs.sunysb.edu>
Thu, 1 May 2008 23:02:55 +0000 (19:02 -0400)
Signed-off-by: Josef 'Jeff' Sipek <jsipek@cs.sunysb.edu>
Conflicts:

fs/unionfs/lookup.c

fs/unionfs/lookup.c
fs/unionfs/union.h

index 2372682a98f0cd17e8f7da39d41efab0896c5042..61c6119015983cb4e57fef81ac8e412f60da5a61 100644 (file)
@@ -59,11 +59,22 @@ struct dentry *unionfs_lookup_backend(struct dentry *dentry,
                BUG_ON(UNIONFS_D(dentry) != NULL);
                locked_child = 1;
        }
-       if (lookupmode != INTERPOSE_PARTIAL) {
-               if ((err = new_dentry_private_data(dentry)))
-                       goto out;
-               allocated_new_info = 1;
+
+       switch(lookupmode) {
+               case INTERPOSE_PARTIAL:
+                       break;
+               case INTERPOSE_LOOKUP:
+                       if ((err = new_dentry_private_data(dentry)))
+                               goto out;
+                       allocated_new_info = 1;
+                       break;
+               default:
+                       if ((err = realloc_dentry_private_data(dentry)))
+                               goto out;
+                       allocated_new_info = 1;
+                       break;
        }
+
        /* must initialize dentry operations */
        dentry->d_op = &unionfs_dops;
 
@@ -410,69 +421,81 @@ void unionfs_destroy_dentry_cache(void)
                kmem_cache_destroy(unionfs_dentry_cachep);
 }
 
-void free_dentry_private_data(struct unionfs_dentry_info *udi)
+void free_dentry_private_data(struct dentry *dentry)
 {
-       if (!udi)
+       struct unionfs_dentry_info *udi;
+
+       if (!dentry || !dentry->d_fsdata)
                return;
+       udi = UNIONFS_D(dentry);
        dput(udi->odf.dentry);
        udi->odf.dentry = NULL;
-       kmem_cache_free(unionfs_dentry_cachep, udi);
+       kmem_cache_free(unionfs_dentry_cachep, dentry->d_fsdata);
+       dentry->d_fsdata = NULL;
 }
 
-/*
- * Allocate new dentry private data, free old one if necessary.
- * On success, returns a dentry whose ->info node is locked already.
- *
- * Note: this function may get a dentry with an already existing *and*
- * locked info node!
- */
-int new_dentry_private_data(struct dentry *dentry)
+static inline int __realloc_dentry_private_data(struct dentry *dentry)
 {
-       int size;
        struct unionfs_dentry_info *info = UNIONFS_D(dentry);
        void *p;
-       int unlock_on_err = 0;
+       int size;
 
-       if (!info) {
-               dentry->d_fsdata = kmem_cache_alloc(unionfs_dentry_cachep,
-                                                   GFP_ATOMIC);
-               info = UNIONFS_D(dentry);
-               if (!info)
-                       goto out;
+       BUG_ON(!info);
 
-               mutex_init(&info->lock);
-               unionfs_lock_dentry(dentry);
-               unlock_on_err = 1;
+       size = sizeof(struct path) * sbmax(dentry->d_sb);
+       p = krealloc(info->lower_paths, size, GFP_ATOMIC);
+       if (unlikely(!p))
+               return -ENOMEM;
 
-               info->lower_paths = NULL;
-       }
+       info->odf.dentry = NULL;
+
+       info->lower_paths = p;
 
        info->bstart = -1;
        info->bend = -1;
        info->bcount = sbmax(dentry->d_sb);
-       info->odf.dentry = NULL;
        atomic_set(&info->generation,
-                  atomic_read(&UNIONFS_SB(dentry->d_sb)->generation));
-
-       size = sizeof(struct path) * sbmax(dentry->d_sb);
+                       atomic_read(&UNIONFS_SB(dentry->d_sb)->generation));
 
-       p = krealloc(info->lower_paths, size, GFP_ATOMIC);
-       if (!p)
-               goto out_free;
-
-       info->lower_paths = p;
        memset(info->lower_paths, 0, size);
 
        return 0;
+}
 
-out_free:
-       kfree(info->lower_paths);
-       if (unlock_on_err)
-               unionfs_unlock_dentry(dentry);
+/* UNIONFS_D(dentry)->lock must be locked */
+static int realloc_dentry_private_data(struct dentry *dentry)
+{
+       if (!__realloc_dentry_private_data(dentry))
+               return 0;
 
-out:
-       free_dentry_private_data(info);
-       dentry->d_fsdata = NULL;
+       kfree(UNIONFS_D(dentry)->lower_paths);
+       free_dentry_private_data(dentry);
+       return -ENOMEM;
+}
+
+/* allocate new dentry private data */
+int new_dentry_private_data(struct dentry *dentry)
+{
+       struct unionfs_dentry_info *info = UNIONFS_D(dentry);
+
+       BUG_ON(info);
+
+       info = kmem_cache_alloc(unionfs_dentry_cachep, GFP_ATOMIC);
+       if (unlikely(!info))
+               return -ENOMEM;
+
+       mutex_init(&info->lock);
+       mutex_lock(&info->lock);
+
+       info->lower_paths = NULL;
+
+       dentry->d_fsdata = info;
+
+       if (!__realloc_dentry_private_data(dentry))
+               return 0;
+
+       mutex_unlock(&info->lock);
+       free_dentry_private_data(dentry);
        return -ENOMEM;
 }
 
index 54d45ce82687e17c512ca4608837582f103a99ff..aafd2a2a87f98761fe0de0b07a42ac36190d592d 100644 (file)
@@ -254,6 +254,7 @@ static inline void unionfs_double_lock_dentry(struct dentry *d1,
        unionfs_lock_dentry(d2);
 }
 
+extern int realloc_dentry_private_data(struct dentry *dentry);
 extern int new_dentry_private_data(struct dentry *dentry);
 extern void free_dentry_private_data(struct unionfs_dentry_info *udi);
 extern void update_bstart(struct dentry *dentry);