From: Pekka Enberg This changes unionfs to use krealloc() for reallocating memory so that we don't need to play tricks with slab internals. Cc: Josef Sipek Signed-off-by: Pekka Enberg Signed-off-by: Andrew Morton --- fs/unionfs/copyup.c | 35 +++++++++++++---------------------- fs/unionfs/lookup.c | 34 ++++++++++++++-------------------- 2 files changed, 27 insertions(+), 42 deletions(-) diff -puN fs/unionfs/copyup.c~unionfs-fix-slab-abuses-with-krealloc fs/unionfs/copyup.c --- a/fs/unionfs/copyup.c~unionfs-fix-slab-abuses-with-krealloc +++ a/fs/unionfs/copyup.c @@ -612,23 +612,16 @@ static struct dentry *create_parents_nam const char *childname; unsigned int childnamelen; - int old_kmalloc_size; - int kmalloc_size; - int num_dentry; + int nr_dentry; int count; int old_bstart; int old_bend; struct dentry **path = NULL; - struct dentry **tmp_path; struct super_block *sb; verify_locked(dentry); - /* There is no sense allocating any less than the minimum. */ - kmalloc_size = malloc_sizes[0].cs_size; - num_dentry = kmalloc_size / sizeof(struct dentry *); - if ((err = is_robranch_super(dir->i_sb, bindex))) { hidden_dentry = ERR_PTR(err); goto out; @@ -638,7 +631,10 @@ static struct dentry *create_parents_nam old_bend = dbend(dentry); hidden_dentry = ERR_PTR(-ENOMEM); - path = kzalloc(kmalloc_size, GFP_KERNEL); + + /* There is no sense allocating any less than the minimum. */ + nr_dentry = 1; + path = kmalloc(nr_dentry * sizeof(struct dentry *), GFP_KERNEL); if (!path) goto out; @@ -664,26 +660,21 @@ static struct dentry *create_parents_nam /* find out the hidden_parent_dentry in the given branch */ hidden_parent_dentry = unionfs_lower_dentry_idx(parent_dentry, bindex); - /* store the child dentry */ - path[count++] = child_dentry; - /* grow path table */ - if (count == num_dentry) { - old_kmalloc_size = kmalloc_size; - kmalloc_size *= 2; - num_dentry = kmalloc_size / sizeof(struct dentry *); + if (count == nr_dentry) { + void *p; - tmp_path = kzalloc(kmalloc_size, GFP_KERNEL); - if (!tmp_path) { + nr_dentry *= 2; + p = krealloc(path, nr_dentry * sizeof(struct dentry *), GFP_KERNEL); + if (!p) { hidden_dentry = ERR_PTR(-ENOMEM); goto out; } - memcpy(tmp_path, path, old_kmalloc_size); - kfree(path); - path = tmp_path; - tmp_path = NULL; + path = p; } + /* store the child dentry */ + path[count++] = child_dentry; } while (!hidden_parent_dentry); count--; diff -puN fs/unionfs/lookup.c~unionfs-fix-slab-abuses-with-krealloc fs/unionfs/lookup.c --- a/fs/unionfs/lookup.c~unionfs-fix-slab-abuses-with-krealloc +++ a/fs/unionfs/lookup.c @@ -431,8 +431,8 @@ void free_dentry_private_data(struct uni /* allocate new dentry private data, free old one if necessary */ int new_dentry_private_data(struct dentry *dentry) { - int newsize; - int oldsize = 0; + int new_size; + int size; struct unionfs_dentry_info *info = UNIONFS_D(dentry); int unlock_on_err = 0; @@ -450,8 +450,9 @@ int new_dentry_private_data(struct dentr unlock_on_err = 1; info->lower_paths = NULL; + size = 0; } else - oldsize = sizeof(struct path) * info->bcount; + size = sizeof(struct path) * info->bcount; info->bstart = -1; info->bend = -1; @@ -459,28 +460,21 @@ int new_dentry_private_data(struct dentr info->bcount = sbmax(dentry->d_sb); atomic_set(&info->generation, atomic_read(&UNIONFS_SB(dentry->d_sb)->generation)); - newsize = sizeof(struct path) * sbmax(dentry->d_sb); + + new_size = sizeof(struct path) * sbmax(dentry->d_sb); /* Don't reallocate when we already have enough space. */ - /* It would be ideal if we could actually use the slab macros to - * determine what our object sizes is, but those are not exported. - */ - if (oldsize) { - int minsize = malloc_sizes[0].cs_size; - - if (!newsize || ((oldsize < newsize) && (newsize > minsize))) { - kfree(info->lower_paths); - info->lower_paths = NULL; - } - } + if (new_size > size) { + void *p; - if (!info->lower_paths && newsize) { - info->lower_paths = kmalloc(newsize, GFP_ATOMIC); - if (!info->lower_paths) + p = krealloc(info->lower_paths, new_size, GFP_ATOMIC); + if (!p) goto out_free; - } - memset(info->lower_paths, 0, (oldsize > newsize ? oldsize : newsize)); + info->lower_paths = p; + size = new_size; + } + memset(info->lower_paths, 0, size); spin_unlock(&dentry->d_lock); return 0; _