Skip to content

Commit 9e51460

Browse files
author
Andreas Gruenbacher
committed
gfs2: Add local resource group locking
Prepare for treating resource group glocks as exclusive among nodes but shared among all tasks running on a node: introduce another layer of node-specific locking that the local tasks can use to coordinate their accesses. Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
1 parent 725d0e9 commit 9e51460

4 files changed

Lines changed: 59 additions & 7 deletions

File tree

fs/gfs2/incore.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <linux/percpu.h>
2121
#include <linux/lockref.h>
2222
#include <linux/rhashtable.h>
23+
#include <linux/mutex.h>
2324

2425
#define DIO_WAIT 0x00000010
2526
#define DIO_METADATA 0x00000020
@@ -123,6 +124,7 @@ struct gfs2_rgrpd {
123124
#define GFS2_RDF_PREFERRED 0x80000000 /* This rgrp is preferred */
124125
#define GFS2_RDF_MASK 0xf0000000 /* mask for internal flags */
125126
spinlock_t rd_rsspin; /* protects reservation related vars */
127+
struct mutex rd_mutex;
126128
struct rb_root rd_rstree; /* multi-block reservation tree */
127129
};
128130

fs/gfs2/lops.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,9 @@ static void maybe_release_space(struct gfs2_bufdata *bd)
7676
unsigned int index = bd->bd_bh->b_blocknr - gl->gl_name.ln_number;
7777
struct gfs2_bitmap *bi = rgd->rd_bits + index;
7878

79+
rgrp_lock_local(rgd);
7980
if (bi->bi_clone == NULL)
80-
return;
81+
goto out;
8182
if (sdp->sd_args.ar_discard)
8283
gfs2_rgrp_send_discards(sdp, rgd->rd_data0, bd->bd_bh, bi, 1, NULL);
8384
memcpy(bi->bi_clone + bi->bi_offset,
@@ -86,6 +87,9 @@ static void maybe_release_space(struct gfs2_bufdata *bd)
8687
rgd->rd_free_clone = rgd->rd_free;
8788
BUG_ON(rgd->rd_free_clone < rgd->rd_reserved);
8889
rgd->rd_extfail_pt = rgd->rd_free;
90+
91+
out:
92+
rgrp_unlock_local(rgd);
8993
}
9094

9195
/**

fs/gfs2/rgrp.c

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -920,6 +920,7 @@ static int read_rindex_entry(struct gfs2_inode *ip)
920920
rgd->rd_data = be32_to_cpu(buf.ri_data);
921921
rgd->rd_bitbytes = be32_to_cpu(buf.ri_bitbytes);
922922
spin_lock_init(&rgd->rd_rsspin);
923+
mutex_init(&rgd->rd_mutex);
923924

924925
error = compute_bitstructs(rgd);
925926
if (error)
@@ -1449,9 +1450,11 @@ int gfs2_fitrim(struct file *filp, void __user *argp)
14491450
/* Trim each bitmap in the rgrp */
14501451
for (x = 0; x < rgd->rd_length; x++) {
14511452
struct gfs2_bitmap *bi = rgd->rd_bits + x;
1453+
rgrp_lock_local(rgd);
14521454
ret = gfs2_rgrp_send_discards(sdp,
14531455
rgd->rd_data0, NULL, bi, minlen,
14541456
&amt);
1457+
rgrp_unlock_local(rgd);
14551458
if (ret) {
14561459
gfs2_glock_dq_uninit(&gh);
14571460
goto out;
@@ -1463,9 +1466,11 @@ int gfs2_fitrim(struct file *filp, void __user *argp)
14631466
ret = gfs2_trans_begin(sdp, RES_RG_HDR, 0);
14641467
if (ret == 0) {
14651468
bh = rgd->rd_bits[0].bi_bh;
1469+
rgrp_lock_local(rgd);
14661470
rgd->rd_flags |= GFS2_RGF_TRIMMED;
14671471
gfs2_trans_add_meta(rgd->rd_gl, bh);
14681472
gfs2_rgrp_out(rgd, bh->b_data);
1473+
rgrp_unlock_local(rgd);
14691474
gfs2_trans_end(sdp);
14701475
}
14711476
}
@@ -2050,7 +2055,8 @@ int gfs2_inplace_reserve(struct gfs2_inode *ip, struct gfs2_alloc_parms *ap)
20502055
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
20512056
struct gfs2_rgrpd *begin = NULL;
20522057
struct gfs2_blkreserv *rs = &ip->i_res;
2053-
int error = 0, rg_locked, flags = 0;
2058+
int error = 0, flags = 0;
2059+
bool rg_locked;
20542060
u64 last_unlinked = NO_BLOCK;
20552061
u32 target = ap->target;
20562062
int loops = 0;
@@ -2079,10 +2085,10 @@ int gfs2_inplace_reserve(struct gfs2_inode *ip, struct gfs2_alloc_parms *ap)
20792085
while (loops < 3) {
20802086
struct gfs2_rgrpd *rgd;
20812087

2082-
rg_locked = 1;
2083-
2084-
if (!gfs2_glock_is_locked_by_me(rs->rs_rgd->rd_gl)) {
2085-
rg_locked = 0;
2088+
rg_locked = gfs2_glock_is_locked_by_me(rs->rs_rgd->rd_gl);
2089+
if (rg_locked) {
2090+
rgrp_lock_local(rs->rs_rgd);
2091+
} else {
20862092
if (skip && skip--)
20872093
goto next_rgrp;
20882094
if (!gfs2_rs_active(rs)) {
@@ -2099,12 +2105,14 @@ int gfs2_inplace_reserve(struct gfs2_inode *ip, struct gfs2_alloc_parms *ap)
20992105
&ip->i_rgd_gh);
21002106
if (unlikely(error))
21012107
return error;
2108+
rgrp_lock_local(rs->rs_rgd);
21022109
if (!gfs2_rs_active(rs) && (loops < 2) &&
21032110
gfs2_rgrp_congested(rs->rs_rgd, loops))
21042111
goto skip_rgrp;
21052112
if (sdp->sd_args.ar_rgrplvb) {
21062113
error = update_rgrp_lvb(rs->rs_rgd);
21072114
if (unlikely(error)) {
2115+
rgrp_unlock_local(rs->rs_rgd);
21082116
gfs2_glock_dq_uninit(&ip->i_rgd_gh);
21092117
return error;
21102118
}
@@ -2142,13 +2150,16 @@ int gfs2_inplace_reserve(struct gfs2_inode *ip, struct gfs2_alloc_parms *ap)
21422150
rs->rs_reserved = blocks_available;
21432151
rgd->rd_reserved += rs->rs_reserved;
21442152
spin_unlock(&rgd->rd_rsspin);
2153+
rgrp_unlock_local(rs->rs_rgd);
21452154
return 0;
21462155
check_rgrp:
21472156
/* Check for unlinked inodes which can be reclaimed */
21482157
if (rs->rs_rgd->rd_flags & GFS2_RDF_CHECK)
21492158
try_rgrp_unlink(rs->rs_rgd, &last_unlinked,
21502159
ip->i_no_addr);
21512160
skip_rgrp:
2161+
rgrp_unlock_local(rs->rs_rgd);
2162+
21522163
/* Drop reservation, if we couldn't use reserved rgrp */
21532164
if (gfs2_rs_active(rs))
21542165
gfs2_rs_deltree(rs);
@@ -2293,6 +2304,7 @@ void gfs2_rgrp_dump(struct seq_file *seq, struct gfs2_rgrpd *rgd,
22932304
struct gfs2_blkreserv *trs;
22942305
const struct rb_node *n;
22952306

2307+
spin_lock(&rgd->rd_rsspin);
22962308
gfs2_print_dbg(seq, "%s R: n:%llu f:%02x b:%u/%u i:%u q:%u r:%u e:%u\n",
22972309
fs_id_buf,
22982310
(unsigned long long)rgd->rd_addr, rgd->rd_flags,
@@ -2306,7 +2318,6 @@ void gfs2_rgrp_dump(struct seq_file *seq, struct gfs2_rgrpd *rgd,
23062318
be32_to_cpu(rgl->rl_free),
23072319
be32_to_cpu(rgl->rl_dinodes));
23082320
}
2309-
spin_lock(&rgd->rd_rsspin);
23102321
for (n = rb_first(&rgd->rd_rstree); n; n = rb_next(&trs->rs_node)) {
23112322
trs = rb_entry(n, struct gfs2_blkreserv, rs_node);
23122323
dump_rs(seq, trs, fs_id_buf);
@@ -2421,6 +2432,7 @@ int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *nblocks,
24212432

24222433
BUG_ON(ip->i_res.rs_reserved < *nblocks);
24232434

2435+
rgrp_lock_local(rbm.rgd);
24242436
if (gfs2_rs_active(&ip->i_res)) {
24252437
gfs2_set_alloc_start(&rbm, ip, dinode);
24262438
error = gfs2_rbm_find(&rbm, GFS2_BLKST_FREE, &minext, &ip->i_res, false);
@@ -2477,6 +2489,7 @@ int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *nblocks,
24772489

24782490
gfs2_trans_add_meta(rbm.rgd->rd_gl, rbm.rgd->rd_bits[0].bi_bh);
24792491
gfs2_rgrp_out(rbm.rgd, rbm.rgd->rd_bits[0].bi_bh->b_data);
2492+
rgrp_unlock_local(rbm.rgd);
24802493

24812494
gfs2_statfs_change(sdp, 0, -(s64)*nblocks, dinode ? 1 : 0);
24822495
if (dinode)
@@ -2490,6 +2503,7 @@ int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *nblocks,
24902503
return 0;
24912504

24922505
rgrp_error:
2506+
rgrp_unlock_local(rbm.rgd);
24932507
gfs2_rgrp_error(rbm.rgd);
24942508
return -EIO;
24952509
}
@@ -2509,12 +2523,14 @@ void __gfs2_free_blocks(struct gfs2_inode *ip, struct gfs2_rgrpd *rgd,
25092523
{
25102524
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
25112525

2526+
rgrp_lock_local(rgd);
25122527
rgblk_free(sdp, rgd, bstart, blen, GFS2_BLKST_FREE);
25132528
trace_gfs2_block_alloc(ip, rgd, bstart, blen, GFS2_BLKST_FREE);
25142529
rgd->rd_free += blen;
25152530
rgd->rd_flags &= ~GFS2_RGF_TRIMMED;
25162531
gfs2_trans_add_meta(rgd->rd_gl, rgd->rd_bits[0].bi_bh);
25172532
gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data);
2533+
rgrp_unlock_local(rgd);
25182534

25192535
/* Directories keep their data in the metadata address space */
25202536
if (meta || ip->i_depth || gfs2_is_jdata(ip))
@@ -2550,17 +2566,20 @@ void gfs2_unlink_di(struct inode *inode)
25502566
rgd = gfs2_blk2rgrpd(sdp, blkno, true);
25512567
if (!rgd)
25522568
return;
2569+
rgrp_lock_local(rgd);
25532570
rgblk_free(sdp, rgd, blkno, 1, GFS2_BLKST_UNLINKED);
25542571
trace_gfs2_block_alloc(ip, rgd, blkno, 1, GFS2_BLKST_UNLINKED);
25552572
gfs2_trans_add_meta(rgd->rd_gl, rgd->rd_bits[0].bi_bh);
25562573
gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data);
25572574
be32_add_cpu(&rgd->rd_rgl->rl_unlinked, 1);
2575+
rgrp_unlock_local(rgd);
25582576
}
25592577

25602578
void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip)
25612579
{
25622580
struct gfs2_sbd *sdp = rgd->rd_sbd;
25632581

2582+
rgrp_lock_local(rgd);
25642583
rgblk_free(sdp, rgd, ip->i_no_addr, 1, GFS2_BLKST_FREE);
25652584
if (!rgd->rd_dinodes)
25662585
gfs2_consist_rgrpd(rgd);
@@ -2569,6 +2588,7 @@ void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip)
25692588

25702589
gfs2_trans_add_meta(rgd->rd_gl, rgd->rd_bits[0].bi_bh);
25712590
gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data);
2591+
rgrp_unlock_local(rgd);
25722592
be32_add_cpu(&rgd->rd_rgl->rl_unlinked, -1);
25732593

25742594
gfs2_statfs_change(sdp, 0, +1, -1);
@@ -2583,6 +2603,10 @@ void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip)
25832603
* @no_addr: The block number to check
25842604
* @type: The block type we are looking for
25852605
*
2606+
* The inode glock of @no_addr must be held. The @type to check for is either
2607+
* GFS2_BLKST_DINODE or GFS2_BLKST_UNLINKED; checking for type GFS2_BLKST_FREE
2608+
* or GFS2_BLKST_USED would make no sense.
2609+
*
25862610
* Returns: 0 if the block type matches the expected type
25872611
* -ESTALE if it doesn't match
25882612
* or -ve errno if something went wrong while checking
@@ -2606,6 +2630,13 @@ int gfs2_check_blk_type(struct gfs2_sbd *sdp, u64 no_addr, unsigned int type)
26062630
rbm.rgd = rgd;
26072631
error = gfs2_rbm_from_block(&rbm, no_addr);
26082632
if (!WARN_ON_ONCE(error)) {
2633+
/*
2634+
* No need to take the local resource group lock here; the
2635+
* inode glock of @no_addr provides the necessary
2636+
* synchronization in case the block is an inode. (In case
2637+
* the block is not an inode, the block type will not match
2638+
* the @type we are looking for.)
2639+
*/
26092640
if (gfs2_testbit(&rbm, false) != type)
26102641
error = -ESTALE;
26112642
}
@@ -2730,3 +2761,14 @@ void gfs2_rlist_free(struct gfs2_rgrp_list *rlist)
27302761
}
27312762
}
27322763

2764+
void rgrp_lock_local(struct gfs2_rgrpd *rgd)
2765+
{
2766+
BUG_ON(!gfs2_glock_is_held_excl(rgd->rd_gl) &&
2767+
!test_bit(SDF_NORECOVERY, &rgd->rd_sbd->sd_flags));
2768+
mutex_lock(&rgd->rd_mutex);
2769+
}
2770+
2771+
void rgrp_unlock_local(struct gfs2_rgrpd *rgd)
2772+
{
2773+
mutex_unlock(&rgd->rd_mutex);
2774+
}

fs/gfs2/rgrp.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,8 @@ static inline int rgrp_contains_block(struct gfs2_rgrpd *rgd, u64 block)
8888
}
8989

9090
extern void check_and_update_goal(struct gfs2_inode *ip);
91+
92+
extern void rgrp_lock_local(struct gfs2_rgrpd *rgd);
93+
extern void rgrp_unlock_local(struct gfs2_rgrpd *rgd);
94+
9195
#endif /* __RGRP_DOT_H__ */

0 commit comments

Comments
 (0)