summaryrefslogtreecommitdiff
path: root/fs/aufs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/aufs')
-rw-r--r--fs/aufs/branch.c15
-rw-r--r--fs/aufs/dbgaufs.c3
-rw-r--r--fs/aufs/dcsub.c3
-rw-r--r--fs/aufs/dentry.c8
-rw-r--r--fs/aufs/dentry.h2
-rw-r--r--fs/aufs/dinfo.c5
-rw-r--r--fs/aufs/file.c12
-rw-r--r--fs/aufs/file.h2
-rw-r--r--fs/aufs/finfo.c4
-rw-r--r--fs/aufs/iinfo.c5
-rw-r--r--fs/aufs/inode.c6
-rw-r--r--fs/aufs/inode.h2
-rw-r--r--fs/aufs/loop.c3
-rw-r--r--fs/aufs/module.c60
-rw-r--r--fs/aufs/module.h14
-rw-r--r--fs/aufs/sbinfo.c5
-rw-r--r--fs/aufs/super.h2
-rw-r--r--fs/aufs/vdir.c11
18 files changed, 120 insertions, 42 deletions
diff --git a/fs/aufs/branch.c b/fs/aufs/branch.c
index 80b018f57..3bfbe5b51 100644
--- a/fs/aufs/branch.c
+++ b/fs/aufs/branch.c
@@ -141,12 +141,12 @@ static struct au_branch *au_br_alloc(struct super_block *sb, int new_nbranch,
goto out_wbr;
}
- err = au_sbr_realloc(au_sbi(sb), new_nbranch);
+ err = au_sbr_realloc(au_sbi(sb), new_nbranch, /*may_shrink*/0);
if (!err)
- err = au_di_realloc(au_di(root), new_nbranch);
+ err = au_di_realloc(au_di(root), new_nbranch, /*may_shrink*/0);
if (!err) {
inode = d_inode(root);
- err = au_hinode_realloc(au_ii(inode), new_nbranch);
+ err = au_hinode_realloc(au_ii(inode), new_nbranch, /*may_shrink*/0);
}
if (!err)
return add_branch; /* success */
@@ -890,7 +890,8 @@ static void au_br_do_del_brp(struct au_sbinfo *sbinfo,
sbinfo->si_branch[0 + bbot] = NULL;
sbinfo->si_bbot--;
- p = krealloc(sbinfo->si_branch, sizeof(*p) * bbot, AuGFP_SBILIST);
+ p = au_krealloc(sbinfo->si_branch, sizeof(*p) * bbot, AuGFP_SBILIST,
+ /*may_shrink*/1);
if (p)
sbinfo->si_branch = p;
/* harmless error */
@@ -909,7 +910,8 @@ static void au_br_do_del_hdp(struct au_dinfo *dinfo, const aufs_bindex_t bindex,
/* au_h_dentry_init(au_hdentry(dinfo, bbot); */
dinfo->di_bbot--;
- p = krealloc(dinfo->di_hdentry, sizeof(*p) * bbot, AuGFP_SBILIST);
+ p = au_krealloc(dinfo->di_hdentry, sizeof(*p) * bbot, AuGFP_SBILIST,
+ /*may_shrink*/1);
if (p)
dinfo->di_hdentry = p;
/* harmless error */
@@ -928,7 +930,8 @@ static void au_br_do_del_hip(struct au_iinfo *iinfo, const aufs_bindex_t bindex,
/* au_hinode_init(au_hinode(iinfo, bbot)); */
iinfo->ii_bbot--;
- p = krealloc(iinfo->ii_hinode, sizeof(*p) * bbot, AuGFP_SBILIST);
+ p = au_krealloc(iinfo->ii_hinode, sizeof(*p) * bbot, AuGFP_SBILIST,
+ /*may_shrink*/1);
if (p)
iinfo->ii_hinode = p;
/* harmless error */
diff --git a/fs/aufs/dbgaufs.c b/fs/aufs/dbgaufs.c
index f85a813a4..4db01e853 100644
--- a/fs/aufs/dbgaufs.c
+++ b/fs/aufs/dbgaufs.c
@@ -256,7 +256,10 @@ void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex)
for (; bindex <= bbot; bindex++) {
br = au_sbr(sb, bindex);
xi = &br->br_xino;
+ /* debugfs acquires the parent i_mutex */
+ lockdep_off();
debugfs_remove(xi->xi_dbgaufs);
+ lockdep_on();
xi->xi_dbgaufs = NULL;
}
}
diff --git a/fs/aufs/dcsub.c b/fs/aufs/dcsub.c
index 09bc36af7..5d4639838 100644
--- a/fs/aufs/dcsub.c
+++ b/fs/aufs/dcsub.c
@@ -69,7 +69,8 @@ static int au_dpages_append(struct au_dcsub_pages *dpages,
err = -ENOMEM;
sz = dpages->ndpage * sizeof(*dpages->dpages);
p = au_kzrealloc(dpages->dpages, sz,
- sz + sizeof(*dpages->dpages), gfp);
+ sz + sizeof(*dpages->dpages), gfp,
+ /*may_shrink*/0);
if (unlikely(!p))
goto out;
diff --git a/fs/aufs/dentry.c b/fs/aufs/dentry.c
index 51af2cc72..5eb4f3620 100644
--- a/fs/aufs/dentry.c
+++ b/fs/aufs/dentry.c
@@ -36,7 +36,7 @@ au_do_lookup(struct dentry *h_parent, struct dentry *dentry,
br = au_sbr(dentry->d_sb, bindex);
wh_able = !!au_br_whable(br->br_perm);
if (wh_able)
- wh_found = au_wh_test(h_parent, wh_name, /*try_sio*/0);
+ wh_found = au_wh_test(h_parent, wh_name, ignore_perm);
h_dentry = ERR_PTR(wh_found);
if (!wh_found)
goto real_lookup;
@@ -701,7 +701,7 @@ void au_refresh_dop(struct dentry *dentry, int force_reval)
int au_refresh_dentry(struct dentry *dentry, struct dentry *parent)
{
- int err, ebrange;
+ int err, ebrange, nbr;
unsigned int sigen;
struct au_dinfo *dinfo, *tmp;
struct super_block *sb;
@@ -717,8 +717,9 @@ int au_refresh_dentry(struct dentry *dentry, struct dentry *parent)
if (unlikely(err))
goto out;
+ nbr = au_sbbot(sb) + 1;
dinfo = au_di(dentry);
- err = au_di_realloc(dinfo, au_sbbot(sb) + 1);
+ err = au_di_realloc(dinfo, nbr, /*may_shrink*/0);
if (unlikely(err))
goto out;
ebrange = au_dbrange_test(dentry);
@@ -761,6 +762,7 @@ int au_refresh_dentry(struct dentry *dentry, struct dentry *parent)
au_dbg_verify_dinode(dentry);
AuTraceErr(err);
}
+ au_di_realloc(dinfo, nbr, /*may_shrink*/1); /* harmless if err */
au_rw_write_unlock(&tmp->di_rwsem);
au_di_free(tmp);
if (unlikely(err))
diff --git a/fs/aufs/dentry.h b/fs/aufs/dentry.h
index dc027191c..01211d220 100644
--- a/fs/aufs/dentry.h
+++ b/fs/aufs/dentry.h
@@ -66,7 +66,7 @@ void au_di_swap(struct au_dinfo *a, struct au_dinfo *b);
void au_di_cp(struct au_dinfo *dst, struct au_dinfo *src);
int au_di_init(struct dentry *dentry);
void au_di_fin(struct dentry *dentry);
-int au_di_realloc(struct au_dinfo *dinfo, int nbr);
+int au_di_realloc(struct au_dinfo *dinfo, int nbr, int may_shrink);
void di_read_lock(struct dentry *d, int flags, unsigned int lsc);
void di_read_unlock(struct dentry *d, int flags);
diff --git a/fs/aufs/dinfo.c b/fs/aufs/dinfo.c
index 361e86142..2626c0cca 100644
--- a/fs/aufs/dinfo.c
+++ b/fs/aufs/dinfo.c
@@ -129,7 +129,7 @@ void au_di_fin(struct dentry *dentry)
au_di_free(dinfo);
}
-int au_di_realloc(struct au_dinfo *dinfo, int nbr)
+int au_di_realloc(struct au_dinfo *dinfo, int nbr, int may_shrink)
{
int err, sz;
struct au_hdentry *hdp;
@@ -140,7 +140,8 @@ int au_di_realloc(struct au_dinfo *dinfo, int nbr)
sz = sizeof(*hdp) * (dinfo->di_bbot + 1);
if (!sz)
sz = sizeof(*hdp);
- hdp = au_kzrealloc(dinfo->di_hdentry, sz, sizeof(*hdp) * nbr, GFP_NOFS);
+ hdp = au_kzrealloc(dinfo->di_hdentry, sz, sizeof(*hdp) * nbr, GFP_NOFS,
+ may_shrink);
if (hdp) {
dinfo->di_hdentry = hdp;
err = 0;
diff --git a/fs/aufs/file.c b/fs/aufs/file.c
index 429b56840..8d5ca6f7f 100644
--- a/fs/aufs/file.c
+++ b/fs/aufs/file.c
@@ -655,23 +655,26 @@ static void au_do_refresh_dir(struct file *file)
*/
static int refresh_file(struct file *file, int (*reopen)(struct file *file))
{
- int err, need_reopen;
+ int err, need_reopen, nbr;
aufs_bindex_t bbot, bindex;
struct dentry *dentry;
+ struct super_block *sb;
struct au_finfo *finfo;
struct au_hfile *hfile;
dentry = file->f_path.dentry;
+ sb = dentry->d_sb;
+ nbr = au_sbbot(sb) + 1;
finfo = au_fi(file);
if (!finfo->fi_hdir) {
hfile = &finfo->fi_htop;
AuDebugOn(!hfile->hf_file);
- bindex = au_br_index(dentry->d_sb, hfile->hf_br->br_id);
+ bindex = au_br_index(sb, hfile->hf_br->br_id);
AuDebugOn(bindex < 0);
if (bindex != finfo->fi_btop)
au_set_fbtop(file, bindex);
} else {
- err = au_fidir_realloc(finfo, au_sbbot(dentry->d_sb) + 1);
+ err = au_fidir_realloc(finfo, nbr, /*may_shrink*/0);
if (unlikely(err))
goto out;
au_do_refresh_dir(file);
@@ -681,6 +684,9 @@ static int refresh_file(struct file *file, int (*reopen)(struct file *file))
need_reopen = 1;
if (!au_test_mmapped(file))
err = au_file_refresh_by_inode(file, &need_reopen);
+ if (finfo->fi_hdir)
+ /* harmless if err */
+ au_fidir_realloc(finfo, nbr, /*may_shrink*/1);
if (!err && need_reopen && !d_unlinked(dentry))
err = reopen(file);
if (!err) {
diff --git a/fs/aufs/file.h b/fs/aufs/file.h
index 6ecd0df33..f53b381a7 100644
--- a/fs/aufs/file.h
+++ b/fs/aufs/file.h
@@ -110,7 +110,7 @@ void au_set_h_fptr(struct file *file, aufs_bindex_t bindex,
void au_update_figen(struct file *file);
struct au_fidir *au_fidir_alloc(struct super_block *sb);
-int au_fidir_realloc(struct au_finfo *finfo, int nbr);
+int au_fidir_realloc(struct au_finfo *finfo, int nbr, int may_shrink);
void au_fi_init_once(void *_fi);
void au_finfo_fin(struct file *file, int atonce);
diff --git a/fs/aufs/finfo.c b/fs/aufs/finfo.c
index e0c16b2f1..0f016ed54 100644
--- a/fs/aufs/finfo.c
+++ b/fs/aufs/finfo.c
@@ -66,7 +66,7 @@ struct au_fidir *au_fidir_alloc(struct super_block *sb)
return fidir;
}
-int au_fidir_realloc(struct au_finfo *finfo, int nbr)
+int au_fidir_realloc(struct au_finfo *finfo, int nbr, int may_shrink)
{
int err;
struct au_fidir *fidir, *p;
@@ -77,7 +77,7 @@ int au_fidir_realloc(struct au_finfo *finfo, int nbr)
err = -ENOMEM;
p = au_kzrealloc(fidir, au_fidir_sz(fidir->fd_nent), au_fidir_sz(nbr),
- GFP_NOFS);
+ GFP_NOFS, may_shrink);
if (p) {
p->fd_nent = nbr;
finfo->fi_hdir = p;
diff --git a/fs/aufs/iinfo.c b/fs/aufs/iinfo.c
index c83db695d..975cff389 100644
--- a/fs/aufs/iinfo.c
+++ b/fs/aufs/iinfo.c
@@ -205,7 +205,7 @@ int au_iinfo_init(struct inode *inode)
return -ENOMEM;
}
-int au_hinode_realloc(struct au_iinfo *iinfo, int nbr)
+int au_hinode_realloc(struct au_iinfo *iinfo, int nbr, int may_shrink)
{
int err, i;
struct au_hinode *hip;
@@ -213,7 +213,8 @@ int au_hinode_realloc(struct au_iinfo *iinfo, int nbr)
AuRwMustWriteLock(&iinfo->ii_rwsem);
err = -ENOMEM;
- hip = krealloc(iinfo->ii_hinode, sizeof(*hip) * nbr, GFP_NOFS);
+ hip = au_krealloc(iinfo->ii_hinode, sizeof(*hip) * nbr, GFP_NOFS,
+ may_shrink);
if (hip) {
iinfo->ii_hinode = hip;
i = iinfo->ii_bbot + 1;
diff --git a/fs/aufs/inode.c b/fs/aufs/inode.c
index a4b994e8c..8f7446df6 100644
--- a/fs/aufs/inode.c
+++ b/fs/aufs/inode.c
@@ -27,7 +27,7 @@ static void au_refresh_hinode_attr(struct inode *inode, int do_version)
static int au_ii_refresh(struct inode *inode, int *update)
{
- int err, e;
+ int err, e, nbr;
umode_t type;
aufs_bindex_t bindex, new_bindex;
struct super_block *sb;
@@ -39,9 +39,10 @@ static int au_ii_refresh(struct inode *inode, int *update)
*update = 0;
sb = inode->i_sb;
+ nbr = au_sbbot(sb) + 1;
type = inode->i_mode & S_IFMT;
iinfo = au_ii(inode);
- err = au_hinode_realloc(iinfo, au_sbbot(sb) + 1);
+ err = au_hinode_realloc(iinfo, nbr, /*may_shrink*/0);
if (unlikely(err))
goto out;
@@ -79,6 +80,7 @@ static int au_ii_refresh(struct inode *inode, int *update)
}
}
au_update_ibrange(inode, /*do_put_zero*/0);
+ au_hinode_realloc(iinfo, nbr, /*may_shrink*/1); /* harmless if err */
e = au_dy_irefresh(inode);
if (unlikely(e && !err))
err = e;
diff --git a/fs/aufs/inode.h b/fs/aufs/inode.h
index 60995c054..33d9f5e8f 100644
--- a/fs/aufs/inode.h
+++ b/fs/aufs/inode.h
@@ -258,7 +258,7 @@ void au_icntnr_init_once(void *_c);
void au_hinode_init(struct au_hinode *hinode);
int au_iinfo_init(struct inode *inode);
void au_iinfo_fin(struct inode *inode);
-int au_hinode_realloc(struct au_iinfo *iinfo, int nbr);
+int au_hinode_realloc(struct au_iinfo *iinfo, int nbr, int may_shrink);
#ifdef CONFIG_PROC_FS
/* plink.c */
diff --git a/fs/aufs/loop.c b/fs/aufs/loop.c
index e92a34599..c3ca50f16 100644
--- a/fs/aufs/loop.c
+++ b/fs/aufs/loop.c
@@ -91,7 +91,8 @@ void au_warn_loopback(struct super_block *h_sb)
new_nelem = au_warn_loopback_nelem + au_warn_loopback_step;
a = au_kzrealloc(au_warn_loopback_array,
au_warn_loopback_nelem * sizeof(unsigned long),
- new_nelem * sizeof(unsigned long), GFP_ATOMIC);
+ new_nelem * sizeof(unsigned long), GFP_ATOMIC,
+ /*may_shrink*/0);
if (a) {
au_warn_loopback_nelem = new_nelem;
au_warn_loopback_array = a;
diff --git a/fs/aufs/module.c b/fs/aufs/module.c
index ede9a232a..5092b4bd6 100644
--- a/fs/aufs/module.c
+++ b/fs/aufs/module.c
@@ -10,13 +10,57 @@
#include <linux/seq_file.h>
#include "aufs.h"
-void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp)
+/* shrinkable realloc */
+void *au_krealloc(void *p, unsigned int new_sz, gfp_t gfp, int may_shrink)
{
- if (new_sz <= nused)
- return p;
+ size_t sz;
+ int diff;
+
+ sz = 0;
+ diff = -1;
+ if (p) {
+#if 0 /* unused */
+ if (!new_sz) {
+ au_delayed_kfree(p);
+ p = NULL;
+ goto out;
+ }
+#else
+ AuDebugOn(!new_sz);
+#endif
+ sz = ksize(p);
+ diff = au_kmidx_sub(sz, new_sz);
+ }
+ if (sz && !diff)
+ goto out;
+
+ if (sz < new_sz)
+ /* expand or SLOB */
+ p = krealloc(p, new_sz, gfp);
+ else if (new_sz < sz && may_shrink) {
+ /* shrink */
+ void *q;
+
+ q = kmalloc(new_sz, gfp);
+ if (q) {
+ if (p) {
+ memcpy(q, p, new_sz);
+ au_delayed_kfree(p);
+ }
+ p = q;
+ } else
+ p = NULL;
+ }
- p = krealloc(p, new_sz, gfp);
- if (p)
+out:
+ return p;
+}
+
+void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp,
+ int may_shrink)
+{
+ p = au_krealloc(p, new_sz, gfp, may_shrink);
+ if (p && new_sz > nused)
memset(p + nused, 0, new_sz - nused);
return p;
}
@@ -38,9 +82,9 @@ static void au_do_dfree(struct work_struct *work __maybe_unused)
head = &au_dfree.cache[AuCache_##idx].llist; \
node = llist_del_all(head); \
for (; node; node = next) { \
- struct au_##name *p = \
- p = llist_entry(node, struct au_##name, \
- lnode); \
+ struct au_##name *p \
+ = llist_entry(node, struct au_##name, \
+ lnode); \
next = llist_next(node); \
au_cache_free_##name(p); \
} \
diff --git a/fs/aufs/module.h b/fs/aufs/module.h
index 681dc75f5..6f968ba41 100644
--- a/fs/aufs/module.h
+++ b/fs/aufs/module.h
@@ -25,7 +25,19 @@ extern bool au_userns;
extern int au_dir_roflags;
-void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp);
+void *au_krealloc(void *p, unsigned int new_sz, gfp_t gfp, int may_shrink);
+void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp,
+ int may_shrink);
+
+static inline int au_kmidx_sub(size_t sz, size_t new_sz)
+{
+#ifndef CONFIG_SLOB
+ return kmalloc_index(sz) - kmalloc_index(new_sz);
+#else
+ return -1; /* SLOB is untested */
+#endif
+}
+
int au_seq_path(struct seq_file *seq, struct path *path);
#ifdef CONFIG_PROC_FS
diff --git a/fs/aufs/sbinfo.c b/fs/aufs/sbinfo.c
index 25f60549c..e113b5119 100644
--- a/fs/aufs/sbinfo.c
+++ b/fs/aufs/sbinfo.c
@@ -118,7 +118,7 @@ out:
return err;
}
-int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr)
+int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr, int may_shrink)
{
int err, sz;
struct au_branch **brp;
@@ -129,7 +129,8 @@ int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr)
sz = sizeof(*brp) * (sbinfo->si_bbot + 1);
if (unlikely(!sz))
sz = sizeof(*brp);
- brp = au_kzrealloc(sbinfo->si_branch, sz, sizeof(*brp) * nbr, GFP_NOFS);
+ brp = au_kzrealloc(sbinfo->si_branch, sz, sizeof(*brp) * nbr, GFP_NOFS,
+ may_shrink);
if (brp) {
sbinfo->si_branch = brp;
err = 0;
diff --git a/fs/aufs/super.h b/fs/aufs/super.h
index b8ca14994..e4ac866e7 100644
--- a/fs/aufs/super.h
+++ b/fs/aufs/super.h
@@ -266,7 +266,7 @@ void au_iarray_free(struct inode **a, unsigned long long max);
/* sbinfo.c */
void au_si_free(struct kobject *kobj);
int au_si_alloc(struct super_block *sb);
-int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr);
+int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr, int may_shrink);
unsigned int au_sigen_inc(struct super_block *sb);
aufs_bindex_t au_new_br_id(struct super_block *sb);
diff --git a/fs/aufs/vdir.c b/fs/aufs/vdir.c
index e6e3a1eaa..b2eb4c058 100644
--- a/fs/aufs/vdir.c
+++ b/fs/aufs/vdir.c
@@ -266,8 +266,8 @@ static int append_deblk(struct au_vdir *vdir)
unsigned char **o;
err = -ENOMEM;
- o = krealloc(vdir->vd_deblk, sizeof(*o) * (vdir->vd_nblk + 1),
- GFP_NOFS);
+ o = au_krealloc(vdir->vd_deblk, sizeof(*o) * (vdir->vd_nblk + 1),
+ GFP_NOFS, /*may_shrink*/0);
if (unlikely(!o))
goto out;
@@ -690,8 +690,8 @@ static int copy_vdir(struct au_vdir *tgt, struct au_vdir *src)
if (tgt->vd_nblk < src->vd_nblk) {
unsigned char **p;
- p = krealloc(tgt->vd_deblk, sizeof(*p) * src->vd_nblk,
- GFP_NOFS);
+ p = au_krealloc(tgt->vd_deblk, sizeof(*p) * src->vd_nblk,
+ GFP_NOFS, /*may_shrink*/0);
if (unlikely(!p))
goto out;
tgt->vd_deblk = p;
@@ -701,7 +701,8 @@ static int copy_vdir(struct au_vdir *tgt, struct au_vdir *src)
unsigned char *p;
tgt->vd_deblk_sz = deblk_sz;
- p = krealloc(tgt->vd_deblk[0], deblk_sz, GFP_NOFS);
+ p = au_krealloc(tgt->vd_deblk[0], deblk_sz, GFP_NOFS,
+ /*may_shrink*/1);
if (unlikely(!p))
goto out;
tgt->vd_deblk[0] = p;