Commit 6dbd8224 authored by Steven Whitehouse's avatar Steven Whitehouse

[GFS2] Reduce inode size by moving i_alloc out of line

It is possible to reduce the size of GFS2 inodes by taking the i_alloc
structure out of the gfs2_inode. This patch allocates the i_alloc
structure whenever its needed, and frees it afterward. This decreases
the amount of low memory we use at the expense of requiring a memory
allocation for each page or partial page that we write. A quick test
with postmark shows that the overhead is not measurable and I also note
that OCFS2 use the same approach.

In the future I'd like to solve the problem by shrinking down the size
of the members of the i_alloc structure, but for now, this reduces the
immediate problem of using too much low-memory on x86 and doesn't add
too much overhead.
Signed-off-by: default avatarSteven Whitehouse <swhiteho@redhat.com>
parent ac39aadd
...@@ -683,7 +683,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, ...@@ -683,7 +683,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
if (metadata) if (metadata)
revokes = (height) ? sdp->sd_inptrs : sdp->sd_diptrs; revokes = (height) ? sdp->sd_inptrs : sdp->sd_diptrs;
error = gfs2_rindex_hold(sdp, &ip->i_alloc.al_ri_gh); error = gfs2_rindex_hold(sdp, &ip->i_alloc->al_ri_gh);
if (error) if (error)
return error; return error;
...@@ -785,7 +785,7 @@ out_rg_gunlock: ...@@ -785,7 +785,7 @@ out_rg_gunlock:
out_rlist: out_rlist:
gfs2_rlist_free(&rlist); gfs2_rlist_free(&rlist);
out: out:
gfs2_glock_dq_uninit(&ip->i_alloc.al_ri_gh); gfs2_glock_dq_uninit(&ip->i_alloc->al_ri_gh);
return error; return error;
} }
......
...@@ -1876,7 +1876,7 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len, ...@@ -1876,7 +1876,7 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len,
if (error) if (error)
goto out; goto out;
error = gfs2_rindex_hold(sdp, &dip->i_alloc.al_ri_gh); error = gfs2_rindex_hold(sdp, &dip->i_alloc->al_ri_gh);
if (error) if (error)
goto out_qs; goto out_qs;
...@@ -1949,7 +1949,7 @@ out_rg_gunlock: ...@@ -1949,7 +1949,7 @@ out_rg_gunlock:
gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs); gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs);
out_rlist: out_rlist:
gfs2_rlist_free(&rlist); gfs2_rlist_free(&rlist);
gfs2_glock_dq_uninit(&dip->i_alloc.al_ri_gh); gfs2_glock_dq_uninit(&dip->i_alloc->al_ri_gh);
out_qs: out_qs:
gfs2_quota_unhold(dip); gfs2_quota_unhold(dip);
out: out:
......
...@@ -1418,7 +1418,7 @@ out: ...@@ -1418,7 +1418,7 @@ out:
static int ea_dealloc_block(struct gfs2_inode *ip) static int ea_dealloc_block(struct gfs2_inode *ip)
{ {
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_alloc *al = &ip->i_alloc; struct gfs2_alloc *al = ip->i_alloc;
struct gfs2_rgrpd *rgd; struct gfs2_rgrpd *rgd;
struct buffer_head *dibh; struct buffer_head *dibh;
int error; int error;
......
...@@ -264,7 +264,7 @@ struct gfs2_inode { ...@@ -264,7 +264,7 @@ struct gfs2_inode {
struct gfs2_glock *i_gl; /* Move into i_gh? */ struct gfs2_glock *i_gl; /* Move into i_gh? */
struct gfs2_holder i_iopen_gh; struct gfs2_holder i_iopen_gh;
struct gfs2_holder i_gh; /* for prepare/commit_write only */ struct gfs2_holder i_gh; /* for prepare/commit_write only */
struct gfs2_alloc i_alloc; struct gfs2_alloc *i_alloc;
u64 i_last_rg_alloc; u64 i_last_rg_alloc;
spinlock_t i_spin; spinlock_t i_spin;
......
...@@ -711,9 +711,10 @@ static int alloc_dinode(struct gfs2_inode *dip, u64 *no_addr, u64 *generation) ...@@ -711,9 +711,10 @@ static int alloc_dinode(struct gfs2_inode *dip, u64 *no_addr, u64 *generation)
struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
int error; int error;
gfs2_alloc_get(dip); if (gfs2_alloc_get(dip) == NULL)
return -ENOMEM;
dip->i_alloc.al_requested = RES_DINODE; dip->i_alloc->al_requested = RES_DINODE;
error = gfs2_inplace_reserve(dip); error = gfs2_inplace_reserve(dip);
if (error) if (error)
goto out; goto out;
...@@ -900,7 +901,7 @@ fail_end_trans: ...@@ -900,7 +901,7 @@ fail_end_trans:
gfs2_trans_end(sdp); gfs2_trans_end(sdp);
fail_ipreserv: fail_ipreserv:
if (dip->i_alloc.al_rgd) if (dip->i_alloc->al_rgd)
gfs2_inplace_release(dip); gfs2_inplace_release(dip);
fail_quota_locks: fail_quota_locks:
......
...@@ -31,6 +31,7 @@ static void gfs2_init_inode_once(struct kmem_cache *cachep, void *foo) ...@@ -31,6 +31,7 @@ static void gfs2_init_inode_once(struct kmem_cache *cachep, void *foo)
inode_init_once(&ip->i_inode); inode_init_once(&ip->i_inode);
spin_lock_init(&ip->i_spin); spin_lock_init(&ip->i_spin);
init_rwsem(&ip->i_rw_mutex); init_rwsem(&ip->i_rw_mutex);
ip->i_alloc = NULL;
} }
static void gfs2_init_glock_once(struct kmem_cache *cachep, void *foo) static void gfs2_init_glock_once(struct kmem_cache *cachep, void *foo)
......
...@@ -646,7 +646,6 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping, ...@@ -646,7 +646,6 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
if (error) if (error)
goto out_unlock; goto out_unlock;
ip->i_alloc.al_requested = 0;
if (alloc_required) { if (alloc_required) {
al = gfs2_alloc_get(ip); al = gfs2_alloc_get(ip);
...@@ -823,7 +822,7 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping, ...@@ -823,7 +822,7 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping,
struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_sbd *sdp = GFS2_SB(inode); struct gfs2_sbd *sdp = GFS2_SB(inode);
struct buffer_head *dibh; struct buffer_head *dibh;
struct gfs2_alloc *al = &ip->i_alloc; struct gfs2_alloc *al = ip->i_alloc;
struct gfs2_dinode *di; struct gfs2_dinode *di;
unsigned int from = pos & (PAGE_CACHE_SIZE - 1); unsigned int from = pos & (PAGE_CACHE_SIZE - 1);
unsigned int to = from + len; unsigned int to = from + len;
...@@ -861,7 +860,7 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping, ...@@ -861,7 +860,7 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping,
brelse(dibh); brelse(dibh);
gfs2_trans_end(sdp); gfs2_trans_end(sdp);
failed: failed:
if (al->al_requested) { if (al) {
gfs2_inplace_release(ip); gfs2_inplace_release(ip);
gfs2_quota_unlock(ip); gfs2_quota_unlock(ip);
gfs2_alloc_put(ip); gfs2_alloc_put(ip);
......
...@@ -364,9 +364,11 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct page *page) ...@@ -364,9 +364,11 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct page *page)
ret = gfs2_write_alloc_required(ip, pos, PAGE_CACHE_SIZE, &alloc_required); ret = gfs2_write_alloc_required(ip, pos, PAGE_CACHE_SIZE, &alloc_required);
if (ret || !alloc_required) if (ret || !alloc_required)
goto out_unlock; goto out_unlock;
ret = -ENOMEM;
ip->i_alloc.al_requested = 0;
al = gfs2_alloc_get(ip); al = gfs2_alloc_get(ip);
if (al == NULL)
goto out_unlock;
ret = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); ret = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
if (ret) if (ret)
goto out_alloc_put; goto out_alloc_put;
......
...@@ -61,7 +61,7 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry, ...@@ -61,7 +61,7 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry,
inode = gfs2_createi(ghs, &dentry->d_name, S_IFREG | mode, 0); inode = gfs2_createi(ghs, &dentry->d_name, S_IFREG | mode, 0);
if (!IS_ERR(inode)) { if (!IS_ERR(inode)) {
gfs2_trans_end(sdp); gfs2_trans_end(sdp);
if (dip->i_alloc.al_rgd) if (dip->i_alloc->al_rgd)
gfs2_inplace_release(dip); gfs2_inplace_release(dip);
gfs2_quota_unlock(dip); gfs2_quota_unlock(dip);
gfs2_alloc_put(dip); gfs2_alloc_put(dip);
...@@ -376,7 +376,7 @@ static int gfs2_symlink(struct inode *dir, struct dentry *dentry, ...@@ -376,7 +376,7 @@ static int gfs2_symlink(struct inode *dir, struct dentry *dentry,
} }
gfs2_trans_end(sdp); gfs2_trans_end(sdp);
if (dip->i_alloc.al_rgd) if (dip->i_alloc->al_rgd)
gfs2_inplace_release(dip); gfs2_inplace_release(dip);
gfs2_quota_unlock(dip); gfs2_quota_unlock(dip);
gfs2_alloc_put(dip); gfs2_alloc_put(dip);
...@@ -452,7 +452,7 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) ...@@ -452,7 +452,7 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode)
gfs2_assert_withdraw(sdp, !error); /* dip already pinned */ gfs2_assert_withdraw(sdp, !error); /* dip already pinned */
gfs2_trans_end(sdp); gfs2_trans_end(sdp);
if (dip->i_alloc.al_rgd) if (dip->i_alloc->al_rgd)
gfs2_inplace_release(dip); gfs2_inplace_release(dip);
gfs2_quota_unlock(dip); gfs2_quota_unlock(dip);
gfs2_alloc_put(dip); gfs2_alloc_put(dip);
...@@ -558,7 +558,7 @@ static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode, ...@@ -558,7 +558,7 @@ static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode,
} }
gfs2_trans_end(sdp); gfs2_trans_end(sdp);
if (dip->i_alloc.al_rgd) if (dip->i_alloc->al_rgd)
gfs2_inplace_release(dip); gfs2_inplace_release(dip);
gfs2_quota_unlock(dip); gfs2_quota_unlock(dip);
gfs2_alloc_put(dip); gfs2_alloc_put(dip);
......
...@@ -453,7 +453,7 @@ static void qdsb_put(struct gfs2_quota_data *qd) ...@@ -453,7 +453,7 @@ static void qdsb_put(struct gfs2_quota_data *qd)
int gfs2_quota_hold(struct gfs2_inode *ip, u32 uid, u32 gid) int gfs2_quota_hold(struct gfs2_inode *ip, u32 uid, u32 gid)
{ {
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_alloc *al = &ip->i_alloc; struct gfs2_alloc *al = ip->i_alloc;
struct gfs2_quota_data **qd = al->al_qd; struct gfs2_quota_data **qd = al->al_qd;
int error; int error;
...@@ -501,7 +501,7 @@ out: ...@@ -501,7 +501,7 @@ out:
void gfs2_quota_unhold(struct gfs2_inode *ip) void gfs2_quota_unhold(struct gfs2_inode *ip)
{ {
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_alloc *al = &ip->i_alloc; struct gfs2_alloc *al = ip->i_alloc;
unsigned int x; unsigned int x;
gfs2_assert_warn(sdp, !test_bit(GIF_QD_LOCKED, &ip->i_flags)); gfs2_assert_warn(sdp, !test_bit(GIF_QD_LOCKED, &ip->i_flags));
...@@ -853,7 +853,7 @@ fail: ...@@ -853,7 +853,7 @@ fail:
int gfs2_quota_lock(struct gfs2_inode *ip, u32 uid, u32 gid) int gfs2_quota_lock(struct gfs2_inode *ip, u32 uid, u32 gid)
{ {
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_alloc *al = &ip->i_alloc; struct gfs2_alloc *al = ip->i_alloc;
unsigned int x; unsigned int x;
int error = 0; int error = 0;
...@@ -921,7 +921,7 @@ static int need_sync(struct gfs2_quota_data *qd) ...@@ -921,7 +921,7 @@ static int need_sync(struct gfs2_quota_data *qd)
void gfs2_quota_unlock(struct gfs2_inode *ip) void gfs2_quota_unlock(struct gfs2_inode *ip)
{ {
struct gfs2_alloc *al = &ip->i_alloc; struct gfs2_alloc *al = ip->i_alloc;
struct gfs2_quota_data *qda[4]; struct gfs2_quota_data *qda[4];
unsigned int count = 0; unsigned int count = 0;
unsigned int x; unsigned int x;
...@@ -969,7 +969,7 @@ static int print_message(struct gfs2_quota_data *qd, char *type) ...@@ -969,7 +969,7 @@ static int print_message(struct gfs2_quota_data *qd, char *type)
int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid) int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
{ {
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_alloc *al = &ip->i_alloc; struct gfs2_alloc *al = ip->i_alloc;
struct gfs2_quota_data *qd; struct gfs2_quota_data *qd;
s64 value; s64 value;
unsigned int x; unsigned int x;
...@@ -1013,7 +1013,7 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid) ...@@ -1013,7 +1013,7 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
void gfs2_quota_change(struct gfs2_inode *ip, s64 change, void gfs2_quota_change(struct gfs2_inode *ip, s64 change,
u32 uid, u32 gid) u32 uid, u32 gid)
{ {
struct gfs2_alloc *al = &ip->i_alloc; struct gfs2_alloc *al = ip->i_alloc;
struct gfs2_quota_data *qd; struct gfs2_quota_data *qd;
unsigned int x; unsigned int x;
......
...@@ -819,11 +819,9 @@ void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd) ...@@ -819,11 +819,9 @@ void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd)
struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip) struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip)
{ {
struct gfs2_alloc *al = &ip->i_alloc; BUG_ON(ip->i_alloc != NULL);
ip->i_alloc = kzalloc(sizeof(struct gfs2_alloc), GFP_KERNEL);
/* FIXME: Should assert that the correct locks are held here... */ return ip->i_alloc;
memset(al, 0, sizeof(*al));
return al;
} }
/** /**
...@@ -1061,7 +1059,7 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked) ...@@ -1061,7 +1059,7 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
struct inode *inode = NULL; struct inode *inode = NULL;
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_rgrpd *rgd, *begin = NULL; struct gfs2_rgrpd *rgd, *begin = NULL;
struct gfs2_alloc *al = &ip->i_alloc; struct gfs2_alloc *al = ip->i_alloc;
int flags = LM_FLAG_TRY; int flags = LM_FLAG_TRY;
int skipped = 0; int skipped = 0;
int loops = 0; int loops = 0;
...@@ -1176,7 +1174,7 @@ out: ...@@ -1176,7 +1174,7 @@ out:
int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, unsigned int line) int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, unsigned int line)
{ {
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_alloc *al = &ip->i_alloc; struct gfs2_alloc *al = ip->i_alloc;
struct inode *inode; struct inode *inode;
int error = 0; int error = 0;
u64 last_unlinked = NO_BLOCK; u64 last_unlinked = NO_BLOCK;
...@@ -1222,7 +1220,7 @@ try_again: ...@@ -1222,7 +1220,7 @@ try_again:
void gfs2_inplace_release(struct gfs2_inode *ip) void gfs2_inplace_release(struct gfs2_inode *ip)
{ {
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_alloc *al = &ip->i_alloc; struct gfs2_alloc *al = ip->i_alloc;
if (gfs2_assert_warn(sdp, al->al_alloced <= al->al_requested) == -1) if (gfs2_assert_warn(sdp, al->al_alloced <= al->al_requested) == -1)
fs_warn(sdp, "al_alloced = %u, al_requested = %u " fs_warn(sdp, "al_alloced = %u, al_requested = %u "
...@@ -1412,7 +1410,7 @@ static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, u64 bstart, ...@@ -1412,7 +1410,7 @@ static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, u64 bstart,
u64 gfs2_alloc_data(struct gfs2_inode *ip) u64 gfs2_alloc_data(struct gfs2_inode *ip)
{ {
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_alloc *al = &ip->i_alloc; struct gfs2_alloc *al = ip->i_alloc;
struct gfs2_rgrpd *rgd = al->al_rgd; struct gfs2_rgrpd *rgd = al->al_rgd;
u32 goal, blk; u32 goal, blk;
u64 block; u64 block;
...@@ -1457,7 +1455,7 @@ u64 gfs2_alloc_data(struct gfs2_inode *ip) ...@@ -1457,7 +1455,7 @@ u64 gfs2_alloc_data(struct gfs2_inode *ip)
u64 gfs2_alloc_meta(struct gfs2_inode *ip) u64 gfs2_alloc_meta(struct gfs2_inode *ip)
{ {
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_alloc *al = &ip->i_alloc; struct gfs2_alloc *al = ip->i_alloc;
struct gfs2_rgrpd *rgd = al->al_rgd; struct gfs2_rgrpd *rgd = al->al_rgd;
u32 goal, blk; u32 goal, blk;
u64 block; u64 block;
...@@ -1503,7 +1501,7 @@ u64 gfs2_alloc_meta(struct gfs2_inode *ip) ...@@ -1503,7 +1501,7 @@ u64 gfs2_alloc_meta(struct gfs2_inode *ip)
u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation) u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation)
{ {
struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
struct gfs2_alloc *al = &dip->i_alloc; struct gfs2_alloc *al = dip->i_alloc;
struct gfs2_rgrpd *rgd = al->al_rgd; struct gfs2_rgrpd *rgd = al->al_rgd;
u32 blk; u32 blk;
u64 block; u64 block;
......
...@@ -32,7 +32,9 @@ void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd); ...@@ -32,7 +32,9 @@ void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd);
struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip); struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip);
static inline void gfs2_alloc_put(struct gfs2_inode *ip) static inline void gfs2_alloc_put(struct gfs2_inode *ip)
{ {
return; /* So we can see where ip->i_alloc is used */ BUG_ON(ip->i_alloc == NULL);
kfree(ip->i_alloc);
ip->i_alloc = NULL;
} }
int gfs2_inplace_reserve_i(struct gfs2_inode *ip, int gfs2_inplace_reserve_i(struct gfs2_inode *ip,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment