Unionfs: Cleanup new_dentry_private_data
authorErez_Zadok <ezk@cs.sunysb.edu>
Fri, 29 Jun 2007 04:36:08 +0000 (00:36 -0400)
committerErez Zadok <ezk@cs.sunysb.edu>
Mon, 12 Jan 2009 23:20:32 +0000 (18:20 -0500)
Signed-off-by: Josef 'Jeff' Sipek <jsipek@cs.sunysb.edu>
Conflicts:

fs/unionfs/lookup.c

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

index ea5bba1350b57f9f8f1d5b067a331c11df0d3c9f..93b92988c05455f74553be772ebc9fcf36de0127 100644 (file)
@@ -111,11 +111,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;
 
@@ -474,62 +485,71 @@ void free_dentry_private_data(struct unionfs_dentry_info *udi)
        kmem_cache_free(unionfs_dentry_cachep, udi);
 }
 
-/*
- * 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;
-
-       if (!info) {
-               dentry->d_fsdata = kmem_cache_alloc(unionfs_dentry_cachep,
-                                                   GFP_ATOMIC);
-               info = UNIONFS_D(dentry);
-               if (!info)
-                       goto out;
-
-               mutex_init(&info->lock);
-               unionfs_lock_dentry(dentry);
-               unlock_on_err = 1;
-
-               info->lower_paths = NULL;
-       }
-
+       int size;
 
-       info->bstart = info->bend = info->bopaque = -1;
-       info->bcount = sbmax(dentry->d_sb);
-       atomic_set(&info->generation,
-                  atomic_read(&UNIONFS_SB(dentry->d_sb)->generation));
+       BUG_ON(!info);
 
        size = sizeof(struct path) * sbmax(dentry->d_sb);
-
        p = krealloc(info->lower_paths, size, GFP_ATOMIC);
        if (!p)
-               goto out_free;
+               return -ENOMEM;
 
        info->lower_paths = p;
+
+       info->bstart = -1;
+       info->bend = -1;
+       info->bopaque = -1;
+       info->bcount = sbmax(dentry->d_sb);
+       atomic_set(&info->generation,
+                       atomic_read(&UNIONFS_SB(dentry->d_sb)->generation));
+
        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 */
+int realloc_dentry_private_data(struct dentry *dentry)
+{
+       if (!__realloc_dentry_private_data(dentry))
+               return 0;
 
-out:
-       free_dentry_private_data(info);
+       kfree(UNIONFS_D(dentry)->lower_paths);
+       free_dentry_private_data(UNIONFS_D(dentry));
        dentry->d_fsdata = NULL;
        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 (!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;
+}
+
 /*
  * scan through the lower dentry objects, and set bstart to reflect the
  * starting branch
index d15770827a6d71528a00c5ca58b6a212d4dbffa9..325a45167aa48a41899ceb4c4537bb0531998caa 100644 (file)
@@ -239,6 +239,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);