Signed-off-by: Josef 'Jeff' Sipek <[EMAIL PROTECTED]>
---
 fs/unionfs/lookup.c |   96 +++++++++++++++++++++++++++++++-------------------
 fs/unionfs/union.h  |    1 +
 2 files changed, 60 insertions(+), 37 deletions(-)

diff --git a/fs/unionfs/lookup.c b/fs/unionfs/lookup.c
index 758c813..246a67a 100644
--- a/fs/unionfs/lookup.c
+++ b/fs/unionfs/lookup.c
@@ -106,11 +106,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;
 
@@ -448,58 +459,69 @@ 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 */
-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;
-
-       spin_lock(&dentry->d_lock);
-       if (!info) {
-               dentry->d_fsdata = kmem_cache_alloc(unionfs_dentry_cachep,
-                                                   GFP_ATOMIC);
-               
-               info = UNIONFS_D(dentry);
-               if (!info)
-                       goto out;
+       int size;
 
-               mutex_init(&info->lock);
-               mutex_lock(&info->lock);
-               unlock_on_err = 1;
+       BUG_ON(!info);
 
-               info->lower_paths = NULL;
-       }
+       size = sizeof(struct path) * sbmax(dentry->d_sb);
+       p = krealloc(info->lower_paths, size, GFP_ATOMIC);
+       if (!p)
+               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));
-
-       size = sizeof(struct path) * sbmax(dentry->d_sb);
-
-       p = krealloc(info->lower_paths, size, GFP_ATOMIC);
-       if (!p)
-               goto out_free;
+                       atomic_read(&UNIONFS_SB(dentry->d_sb)->generation));
 
-       info->lower_paths = p;
        memset(info->lower_paths, 0, size);
 
-       spin_unlock(&dentry->d_lock);
        return 0;
+}
 
-out_free:
-       kfree(info->lower_paths);
-       if (unlock_on_err)
-               mutex_unlock(&info->lock);
+/* UNIONFS_D(dentry)->lock must be locked */
+int realloc_dentry_private_data(struct dentry *dentry)
+{
+       if (!__realloc_dentry_private_data(dentry))
+               return 0;
 
-out:
+       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(info);
        dentry->d_fsdata = NULL;
-       spin_unlock(&dentry->d_lock);
        return -ENOMEM;
 }
 
diff --git a/fs/unionfs/union.h b/fs/unionfs/union.h
index 28eb622..7e0c318 100644
--- a/fs/unionfs/union.h
+++ b/fs/unionfs/union.h
@@ -233,6 +233,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);
-- 
1.5.2.rc1.165.gaf9b

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to