aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2011-09-01 08:31:59 -0400
committerSteven Whitehouse <swhiteho@redhat.com>2011-10-21 07:39:34 -0400
commit54335b1fca27b84baa75b1f45985d98262003837 (patch)
treec6b21aff1759d86be56208e9981117e4383c3f47 /fs/gfs2
parent8339ee543ece6e2dcc1bbd97d5350163c198cf00 (diff)
GFS2: Cache the most recently used resource group in the inode
This means that after the initial allocation for any inode, the last used resource group is cached in the inode for future use. This drastically reduces the number of lookups of resource groups in the common case, and this the contention on that data structure. The allocation algorithm is the same as previously, except that we always check to see if the goal block is within the cached rgrp first before going to the rbtree to look one up. Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2')
-rw-r--r--fs/gfs2/aops.c2
-rw-r--r--fs/gfs2/file.c6
-rw-r--r--fs/gfs2/incore.h3
-rw-r--r--fs/gfs2/inode.c12
-rw-r--r--fs/gfs2/quota.c4
-rw-r--r--fs/gfs2/rgrp.c51
-rw-r--r--fs/gfs2/super.c1
-rw-r--r--fs/gfs2/trans.h8
-rw-r--r--fs/gfs2/xattr.c2
9 files changed, 44 insertions, 45 deletions
diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c
index 212fe74927ba..4858e1fed8b1 100644
--- a/fs/gfs2/aops.c
+++ b/fs/gfs2/aops.c
@@ -663,7 +663,7 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
663 if (&ip->i_inode == sdp->sd_rindex) 663 if (&ip->i_inode == sdp->sd_rindex)
664 rblocks += 2 * RES_STATFS; 664 rblocks += 2 * RES_STATFS;
665 if (alloc_required) 665 if (alloc_required)
666 rblocks += gfs2_rg_blocks(al); 666 rblocks += gfs2_rg_blocks(ip);
667 667
668 error = gfs2_trans_begin(sdp, rblocks, 668 error = gfs2_trans_begin(sdp, rblocks,
669 PAGE_CACHE_SIZE/sdp->sd_sb.sb_bsize); 669 PAGE_CACHE_SIZE/sdp->sd_sb.sb_bsize);
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
index d717b72500a4..3467f3662149 100644
--- a/fs/gfs2/file.c
+++ b/fs/gfs2/file.c
@@ -397,7 +397,7 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
397 rblocks += data_blocks ? data_blocks : 1; 397 rblocks += data_blocks ? data_blocks : 1;
398 if (ind_blocks || data_blocks) { 398 if (ind_blocks || data_blocks) {
399 rblocks += RES_STATFS + RES_QUOTA; 399 rblocks += RES_STATFS + RES_QUOTA;
400 rblocks += gfs2_rg_blocks(al); 400 rblocks += gfs2_rg_blocks(ip);
401 } 401 }
402 ret = gfs2_trans_begin(sdp, rblocks, 0); 402 ret = gfs2_trans_begin(sdp, rblocks, 0);
403 if (ret) 403 if (ret)
@@ -823,7 +823,7 @@ static void calc_max_reserv(struct gfs2_inode *ip, loff_t max, loff_t *len,
823 unsigned int *data_blocks, unsigned int *ind_blocks) 823 unsigned int *data_blocks, unsigned int *ind_blocks)
824{ 824{
825 const struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); 825 const struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
826 unsigned int max_blocks = ip->i_alloc->al_rgd->rd_free_clone; 826 unsigned int max_blocks = ip->i_rgd->rd_free_clone;
827 unsigned int tmp, max_data = max_blocks - 3 * (sdp->sd_max_height - 1); 827 unsigned int tmp, max_data = max_blocks - 3 * (sdp->sd_max_height - 1);
828 828
829 for (tmp = max_data; tmp > sdp->sd_diptrs;) { 829 for (tmp = max_data; tmp > sdp->sd_diptrs;) {
@@ -912,7 +912,7 @@ retry:
912 al->al_requested = data_blocks + ind_blocks; 912 al->al_requested = data_blocks + ind_blocks;
913 913
914 rblocks = RES_DINODE + ind_blocks + RES_STATFS + RES_QUOTA + 914 rblocks = RES_DINODE + ind_blocks + RES_STATFS + RES_QUOTA +
915 RES_RG_HDR + gfs2_rg_blocks(al); 915 RES_RG_HDR + gfs2_rg_blocks(ip);
916 if (gfs2_is_jdata(ip)) 916 if (gfs2_is_jdata(ip))
917 rblocks += data_blocks ? data_blocks : 1; 917 rblocks += data_blocks ? data_blocks : 1;
918 918
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index 56847f5903ae..55e335b52839 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -256,8 +256,6 @@ struct gfs2_alloc {
256 unsigned int al_line; 256 unsigned int al_line;
257 char *al_file; 257 char *al_file;
258 struct gfs2_holder al_rgd_gh; 258 struct gfs2_holder al_rgd_gh;
259 struct gfs2_rgrpd *al_rgd;
260
261}; 259};
262 260
263enum { 261enum {
@@ -279,6 +277,7 @@ struct gfs2_inode {
279 struct gfs2_holder i_iopen_gh; 277 struct gfs2_holder i_iopen_gh;
280 struct gfs2_holder i_gh; /* for prepare/commit_write only */ 278 struct gfs2_holder i_gh; /* for prepare/commit_write only */
281 struct gfs2_alloc *i_alloc; 279 struct gfs2_alloc *i_alloc;
280 struct gfs2_rgrpd *i_rgd;
282 u64 i_goal; /* goal block for allocations */ 281 u64 i_goal; /* goal block for allocations */
283 struct rw_semaphore i_rw_mutex; 282 struct rw_semaphore i_rw_mutex;
284 struct list_head i_trunc_list; 283 struct list_head i_trunc_list;
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 29703dd97dc9..55b3bbaf2f25 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -583,7 +583,7 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name,
583 goto fail_quota_locks; 583 goto fail_quota_locks;
584 584
585 error = gfs2_trans_begin(sdp, sdp->sd_max_dirres + 585 error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
586 al->al_rgd->rd_length + 586 dip->i_rgd->rd_length +
587 2 * RES_DINODE + 587 2 * RES_DINODE +
588 RES_STATFS + RES_QUOTA, 0); 588 RES_STATFS + RES_QUOTA, 0);
589 if (error) 589 if (error)
@@ -613,8 +613,7 @@ fail_end_trans:
613 gfs2_trans_end(sdp); 613 gfs2_trans_end(sdp);
614 614
615fail_ipreserv: 615fail_ipreserv:
616 if (dip->i_alloc->al_rgd) 616 gfs2_inplace_release(dip);
617 gfs2_inplace_release(dip);
618 617
619fail_quota_locks: 618fail_quota_locks:
620 gfs2_quota_unlock(dip); 619 gfs2_quota_unlock(dip);
@@ -731,8 +730,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
731 brelse(bh); 730 brelse(bh);
732 731
733 gfs2_trans_end(sdp); 732 gfs2_trans_end(sdp);
734 if (dip->i_alloc->al_rgd) 733 gfs2_inplace_release(dip);
735 gfs2_inplace_release(dip);
736 gfs2_quota_unlock(dip); 734 gfs2_quota_unlock(dip);
737 gfs2_alloc_put(dip); 735 gfs2_alloc_put(dip);
738 mark_inode_dirty(inode); 736 mark_inode_dirty(inode);
@@ -896,7 +894,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
896 goto out_gunlock_q; 894 goto out_gunlock_q;
897 895
898 error = gfs2_trans_begin(sdp, sdp->sd_max_dirres + 896 error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
899 gfs2_rg_blocks(al) + 897 gfs2_rg_blocks(dip) +
900 2 * RES_DINODE + RES_STATFS + 898 2 * RES_DINODE + RES_STATFS +
901 RES_QUOTA, 0); 899 RES_QUOTA, 0);
902 if (error) 900 if (error)
@@ -1371,7 +1369,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
1371 goto out_gunlock_q; 1369 goto out_gunlock_q;
1372 1370
1373 error = gfs2_trans_begin(sdp, sdp->sd_max_dirres + 1371 error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
1374 gfs2_rg_blocks(al) + 1372 gfs2_rg_blocks(ndip) +
1375 4 * RES_DINODE + 4 * RES_LEAF + 1373 4 * RES_DINODE + 4 * RES_LEAF +
1376 RES_STATFS + RES_QUOTA + 4, 0); 1374 RES_STATFS + RES_QUOTA + 4, 0);
1377 if (error) 1375 if (error)
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
index 3a9a9749f496..10a59cd21f0c 100644
--- a/fs/gfs2/quota.c
+++ b/fs/gfs2/quota.c
@@ -813,7 +813,7 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda)
813 goto out_alloc; 813 goto out_alloc;
814 814
815 if (nalloc) 815 if (nalloc)
816 blocks += gfs2_rg_blocks(al) + nalloc * ind_blocks + RES_STATFS; 816 blocks += gfs2_rg_blocks(ip) + nalloc * ind_blocks + RES_STATFS;
817 817
818 error = gfs2_trans_begin(sdp, blocks, 0); 818 error = gfs2_trans_begin(sdp, blocks, 0);
819 if (error) 819 if (error)
@@ -1598,7 +1598,7 @@ static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
1598 error = gfs2_inplace_reserve(ip); 1598 error = gfs2_inplace_reserve(ip);
1599 if (error) 1599 if (error)
1600 goto out_alloc; 1600 goto out_alloc;
1601 blocks += gfs2_rg_blocks(al); 1601 blocks += gfs2_rg_blocks(ip);
1602 } 1602 }
1603 1603
1604 /* Some quotas span block boundaries and can update two blocks, 1604 /* Some quotas span block boundaries and can update two blocks,
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c
index 88d5b75067a8..5bfb97002c2a 100644
--- a/fs/gfs2/rgrp.c
+++ b/fs/gfs2/rgrp.c
@@ -882,24 +882,21 @@ struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip)
882/** 882/**
883 * try_rgrp_fit - See if a given reservation will fit in a given RG 883 * try_rgrp_fit - See if a given reservation will fit in a given RG
884 * @rgd: the RG data 884 * @rgd: the RG data
885 * @al: the struct gfs2_alloc structure describing the reservation 885 * @ip: the inode
886 * 886 *
887 * If there's room for the requested blocks to be allocated from the RG: 887 * If there's room for the requested blocks to be allocated from the RG:
888 * Sets the $al_rgd field in @al.
889 * 888 *
890 * Returns: 1 on success (it fits), 0 on failure (it doesn't fit) 889 * Returns: 1 on success (it fits), 0 on failure (it doesn't fit)
891 */ 890 */
892 891
893static int try_rgrp_fit(struct gfs2_rgrpd *rgd, struct gfs2_alloc *al) 892static int try_rgrp_fit(const struct gfs2_rgrpd *rgd, const struct gfs2_inode *ip)
894{ 893{
894 const struct gfs2_alloc *al = ip->i_alloc;
895
895 if (rgd->rd_flags & (GFS2_RGF_NOALLOC | GFS2_RDF_ERROR)) 896 if (rgd->rd_flags & (GFS2_RGF_NOALLOC | GFS2_RDF_ERROR))
896 return 0; 897 return 0;
897 898 if (rgd->rd_free_clone >= al->al_requested)
898 if (rgd->rd_free_clone >= al->al_requested) {
899 al->al_rgd = rgd;
900 return 1; 899 return 1;
901 }
902
903 return 0; 900 return 0;
904} 901}
905 902
@@ -985,7 +982,10 @@ static int get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
985 int error, rg_locked; 982 int error, rg_locked;
986 int loops = 0; 983 int loops = 0;
987 984
988 rgd = begin = gfs2_blk2rgrpd(sdp, ip->i_goal); 985 if (ip->i_rgd && rgrp_contains_block(ip->i_rgd, ip->i_goal))
986 rgd = begin = ip->i_rgd;
987 else
988 rgd = begin = gfs2_blk2rgrpd(sdp, ip->i_goal);
989 989
990 if (rgd == NULL) 990 if (rgd == NULL)
991 return -EBADSLT; 991 return -EBADSLT;
@@ -1002,8 +1002,10 @@ static int get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
1002 } 1002 }
1003 switch (error) { 1003 switch (error) {
1004 case 0: 1004 case 0:
1005 if (try_rgrp_fit(rgd, al)) 1005 if (try_rgrp_fit(rgd, ip)) {
1006 ip->i_rgd = rgd;
1006 return 0; 1007 return 0;
1008 }
1007 if (rgd->rd_flags & GFS2_RDF_CHECK) 1009 if (rgd->rd_flags & GFS2_RDF_CHECK)
1008 try_rgrp_unlink(rgd, last_unlinked, ip->i_no_addr); 1010 try_rgrp_unlink(rgd, last_unlinked, ip->i_no_addr);
1009 if (!rg_locked) 1011 if (!rg_locked)
@@ -1014,7 +1016,6 @@ static int get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
1014 if (rgd == begin) 1016 if (rgd == begin)
1015 loops++; 1017 loops++;
1016 break; 1018 break;
1017
1018 default: 1019 default:
1019 return error; 1020 return error;
1020 } 1021 }
@@ -1042,21 +1043,20 @@ int gfs2_inplace_reserve_i(struct gfs2_inode *ip,
1042 if (gfs2_assert_warn(sdp, al->al_requested)) 1043 if (gfs2_assert_warn(sdp, al->al_requested))
1043 return -EINVAL; 1044 return -EINVAL;
1044 1045
1045try_again:
1046 do { 1046 do {
1047 error = get_local_rgrp(ip, &last_unlinked); 1047 error = get_local_rgrp(ip, &last_unlinked);
1048 /* If there is no space, flushing the log may release some */ 1048 if (error != -ENOSPC)
1049 if (error) { 1049 break;
1050 if (ip == GFS2_I(sdp->sd_rindex) && 1050 /* Check that fs hasn't grown if writing to rindex */
1051 !sdp->sd_rindex_uptodate) { 1051 if (ip == GFS2_I(sdp->sd_rindex) && !sdp->sd_rindex_uptodate) {
1052 error = gfs2_ri_update(ip); 1052 error = gfs2_ri_update(ip);
1053 if (error) 1053 if (error)
1054 return error; 1054 break;
1055 goto try_again; 1055 continue;
1056 }
1057 gfs2_log_flush(sdp, NULL);
1058 } 1056 }
1059 } while (error && tries++ < 3); 1057 /* Flushing the log may release space */
1058 gfs2_log_flush(sdp, NULL);
1059 } while (tries++ < 3);
1060 1060
1061 if (error) 1061 if (error)
1062 return error; 1062 return error;
@@ -1086,7 +1086,6 @@ void gfs2_inplace_release(struct gfs2_inode *ip)
1086 al->al_alloced, al->al_requested, al->al_file, 1086 al->al_alloced, al->al_requested, al->al_file,
1087 al->al_line); 1087 al->al_line);
1088 1088
1089 al->al_rgd = NULL;
1090 if (al->al_rgd_gh.gh_gl) 1089 if (al->al_rgd_gh.gh_gl)
1091 gfs2_glock_dq_uninit(&al->al_rgd_gh); 1090 gfs2_glock_dq_uninit(&al->al_rgd_gh);
1092} 1091}
@@ -1339,7 +1338,7 @@ int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n)
1339 if (al == NULL) 1338 if (al == NULL)
1340 return -ECANCELED; 1339 return -ECANCELED;
1341 1340
1342 rgd = al->al_rgd; 1341 rgd = ip->i_rgd;
1343 1342
1344 if (rgrp_contains_block(rgd, ip->i_goal)) 1343 if (rgrp_contains_block(rgd, ip->i_goal))
1345 goal = ip->i_goal - rgd->rd_data0; 1344 goal = ip->i_goal - rgd->rd_data0;
@@ -1398,7 +1397,7 @@ int gfs2_alloc_di(struct gfs2_inode *dip, u64 *bn, u64 *generation)
1398{ 1397{
1399 struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); 1398 struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
1400 struct gfs2_alloc *al = dip->i_alloc; 1399 struct gfs2_alloc *al = dip->i_alloc;
1401 struct gfs2_rgrpd *rgd = al->al_rgd; 1400 struct gfs2_rgrpd *rgd = dip->i_rgd;
1402 u32 blk; 1401 u32 blk;
1403 u64 block; 1402 u64 block;
1404 unsigned int n = 1; 1403 unsigned int n = 1;
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index f716c4f8b252..87e9141a4def 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -1574,6 +1574,7 @@ static struct inode *gfs2_alloc_inode(struct super_block *sb)
1574 if (ip) { 1574 if (ip) {
1575 ip->i_flags = 0; 1575 ip->i_flags = 0;
1576 ip->i_gl = NULL; 1576 ip->i_gl = NULL;
1577 ip->i_rgd = NULL;
1577 } 1578 }
1578 return &ip->i_inode; 1579 return &ip->i_inode;
1579} 1580}
diff --git a/fs/gfs2/trans.h b/fs/gfs2/trans.h
index 980c5c05398a..f8f101ef600c 100644
--- a/fs/gfs2/trans.h
+++ b/fs/gfs2/trans.h
@@ -28,10 +28,12 @@ struct gfs2_glock;
28 28
29/* reserve either the number of blocks to be allocated plus the rg header 29/* reserve either the number of blocks to be allocated plus the rg header
30 * block, or all of the blocks in the rg, whichever is smaller */ 30 * block, or all of the blocks in the rg, whichever is smaller */
31static inline unsigned int gfs2_rg_blocks(const struct gfs2_alloc *al) 31static inline unsigned int gfs2_rg_blocks(const struct gfs2_inode *ip)
32{ 32{
33 return (al->al_requested < al->al_rgd->rd_length)? 33 const struct gfs2_alloc *al = ip->i_alloc;
34 al->al_requested + 1 : al->al_rgd->rd_length; 34 if (al->al_requested < ip->i_rgd->rd_length)
35 return al->al_requested + 1;
36 return ip->i_rgd->rd_length;
35} 37}
36 38
37extern int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks, 39extern int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks,
diff --git a/fs/gfs2/xattr.c b/fs/gfs2/xattr.c
index 167f4af53b1d..e7bf0ea1c3cc 100644
--- a/fs/gfs2/xattr.c
+++ b/fs/gfs2/xattr.c
@@ -727,7 +727,7 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er,
727 goto out_gunlock_q; 727 goto out_gunlock_q;
728 728
729 error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), 729 error = gfs2_trans_begin(GFS2_SB(&ip->i_inode),
730 blks + gfs2_rg_blocks(al) + 730 blks + gfs2_rg_blocks(ip) +
731 RES_DINODE + RES_STATFS + RES_QUOTA, 0); 731 RES_DINODE + RES_STATFS + RES_QUOTA, 0);
732 if (error) 732 if (error)
733 goto out_ipres; 733 goto out_ipres;