From: Erez_Zadok Date: Fri, 16 Nov 2007 19:51:39 +0000 (-0500) Subject: Unionfs: Cleanup new_dentry_private_data X-Git-Url: https://git.fsl.cs.sunysb.edu/?a=commitdiff_plain;h=b1c27b05c1dd73591d7d9f3bd48e9d67fde863bc;p=unionfs-odf.git Unionfs: Cleanup new_dentry_private_data Signed-off-by: Josef 'Jeff' Sipek Conflicts: fs/unionfs/lookup.c --- diff --git a/fs/unionfs/lookup.c b/fs/unionfs/lookup.c index 2372682a98..61c6119015 100644 --- a/fs/unionfs/lookup.c +++ b/fs/unionfs/lookup.c @@ -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; } diff --git a/fs/unionfs/union.h b/fs/unionfs/union.h index 54d45ce826..aafd2a2a87 100644 --- a/fs/unionfs/union.h +++ b/fs/unionfs/union.h @@ -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);