Signed-off-by: Andreas Gruenbacher <agrue...@redhat.com>
---
fs/gfs2/bmap.c | 2 +-
fs/gfs2/incore.h | 30 +--------
fs/gfs2/rgrp.c | 156 ++++++++++++++++++++++++++-----------------
fs/gfs2/trace_gfs2.h | 10 +--
fs/gfs2/trans.h | 2 +-
5 files changed, 103 insertions(+), 97 deletions(-)
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index 03128ed1f34e..c192906bb5f6 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -1503,7 +1503,7 @@ static int sweep_bh_for_rgrps(struct gfs2_inode *ip,
struct gfs2_holder *rd_gh,
/* Must be done with the rgrp glock held: */
if (gfs2_rs_active(&ip->i_res) &&
- rgd == ip->i_res.rs_rbm.rgd)
+ rgd == ip->i_res.rs_rgd)
gfs2_rs_deltree(&ip->i_res);
}
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index a1771d8a93be..0ed28fbc73b4 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -124,31 +124,6 @@ struct gfs2_rgrpd {
struct rb_root rd_rstree; /* multi-block reservation tree */
};
-struct gfs2_rbm {
- struct gfs2_rgrpd *rgd;
- u32 offset; /* The offset is bitmap relative */
- int bii; /* Bitmap index */
-};
-
-static inline struct gfs2_bitmap *rbm_bi(const struct gfs2_rbm *rbm)
-{
- return rbm->rgd->rd_bits + rbm->bii;
-}
-
-static inline u64 gfs2_rbm_to_block(const struct gfs2_rbm *rbm)
-{
- BUG_ON(rbm->offset >= rbm->rgd->rd_data);
- return rbm->rgd->rd_data0 + (rbm_bi(rbm)->bi_start * GFS2_NBBY) +
- rbm->offset;
-}
-
-static inline bool gfs2_rbm_eq(const struct gfs2_rbm *rbm1,
- const struct gfs2_rbm *rbm2)
-{
- return (rbm1->rgd == rbm2->rgd) && (rbm1->bii == rbm2->bii) &&
- (rbm1->offset == rbm2->offset);
-}
-
enum gfs2_state_bits {
BH_Pinned = BH_PrivateStart,
BH_Escaped = BH_PrivateStart + 1,
@@ -309,8 +284,9 @@ struct gfs2_qadata { /* quota allocation data */
*/
struct gfs2_blkreserv {
- struct rb_node rs_node; /* link to other block reservations */
- struct gfs2_rbm rs_rbm; /* Start of reservation */
+ struct rb_node rs_node; /* node within rd_rstree */
+ struct gfs2_rgrpd *rs_rgd;
+ u64 rs_start; /* start of reservation */
u32 rs_free; /* how many blocks are still free */
};
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c
index 070ad493a4ec..ee6ea7d8cf44 100644
--- a/fs/gfs2/rgrp.c
+++ b/fs/gfs2/rgrp.c
@@ -49,6 +49,24 @@
#define LBITSKIP00 (0x0000000000000000UL)
#endif
+struct gfs2_rbm {
+ struct gfs2_rgrpd *rgd;
+ u32 offset; /* The offset is bitmap relative */
+ int bii; /* Bitmap index */
+};
+
+static inline struct gfs2_bitmap *rbm_bi(const struct gfs2_rbm *rbm)
+{
+ return rbm->rgd->rd_bits + rbm->bii;
+}
+
+static inline u64 gfs2_rbm_to_block(const struct gfs2_rbm *rbm)
+{
+ BUG_ON(rbm->offset >= rbm->rgd->rd_data);
+ return rbm->rgd->rd_data0 + (rbm_bi(rbm)->bi_start * GFS2_NBBY) +
+ rbm->offset;
+}
+
/*
* These routines are used by the resource group routines (rgrp.c)
* to keep track of block allocation. Each block is represented by two
@@ -184,7 +202,7 @@ static inline u64 gfs2_bit_search(const __le64 *ptr, u64
mask, u8 state)
/**
* rs_cmp - multi-block reservation range compare
- * @blk: absolute file system block number of the new reservation
+ * @start: start of the new reservation
* @len: number of blocks in the new reservation
* @rs: existing reservation to compare against
*
@@ -192,13 +210,11 @@ static inline u64 gfs2_bit_search(const __le64 *ptr, u64
mask, u8 state)
* -1 if the block range is before the start of the reservation
* 0 if the block range overlaps with the reservation
*/
-static inline int rs_cmp(u64 blk, u32 len, struct gfs2_blkreserv *rs)
+static inline int rs_cmp(u64 start, u32 len, struct gfs2_blkreserv *rs)
{
- u64 startblk = gfs2_rbm_to_block(&rs->rs_rbm);
-
- if (blk >= startblk + rs->rs_free)
+ if (start >= rs->rs_start + rs->rs_free)
return 1;
- if (blk + len - 1 < startblk)
+ if (rs->rs_start >= start + len)
return -1;
return 0;
}
@@ -269,12 +285,11 @@ static u32 gfs2_bitfit(const u8 *buf, const unsigned int
len,
static int gfs2_rbm_from_block(struct gfs2_rbm *rbm, u64 block)
{
- u64 rblock = block - rbm->rgd->rd_data0;
+ u64 rblock;
- if (WARN_ON_ONCE(rblock > UINT_MAX))
- return -EINVAL;
- if (block >= rbm->rgd->rd_data0 + rbm->rgd->rd_data)
+ if (!rgrp_contains_block(rbm->rgd, block))
return -E2BIG;
+ rblock = block - rbm->rgd->rd_data0;
rbm->bii = 0;
rbm->offset = (u32)(rblock);
@@ -316,13 +331,28 @@ static bool gfs2_rbm_incr(struct gfs2_rbm *rbm)
return false;
}
+static struct gfs2_bitmap *gfs2_block_to_bitmap(struct gfs2_rgrpd *rgd,
+ u64 block)
+{
+ unsigned int delta = (sizeof(struct gfs2_rgrp) -
+ sizeof(struct gfs2_meta_header)) * GFS2_NBBY;
+ unsigned int rblock, bii;
+
+ if (!rgrp_contains_block(rgd, block))
+ return NULL;
+ rblock = block - rgd->rd_data0;
+ bii = (rblock + delta) / rgd->rd_sbd->sd_blocks_per_bitmap;
+ return rgd->rd_bits + bii;
+}
+
/**
* gfs2_unaligned_extlen - Look for free blocks which are not byte aligned
* @rbm: Position to search (value/result)
* @n_unaligned: Number of unaligned blocks to check
* @len: Decremented for each block found (terminate on zero)
*
- * Returns: true if a non-free block is encountered
+ * Returns: true if a non-free block is encountered or the end of the resource
+ * group is reached.
*/
static bool gfs2_unaligned_extlen(struct gfs2_rbm *rbm, u32 n_unaligned, u32 *len)
@@ -618,10 +648,10 @@ static void dump_rs(struct seq_file *seq, const struct
gfs2_blkreserv *rs)
{
struct gfs2_inode *ip = container_of(rs, struct gfs2_inode, i_res);
- gfs2_print_dbg(seq, " B: n:%llu s:%llu b:%u f:%u\n",
+ gfs2_print_dbg(seq, " B: n:%llu s:%llu f:%u\n",
(unsigned long long)ip->i_no_addr,
- (unsigned long long)gfs2_rbm_to_block(&rs->rs_rbm),
- rs->rs_rbm.offset, rs->rs_free);
+ (unsigned long long)rs->rs_start,
+ rs->rs_free);
}
/**
@@ -636,24 +666,26 @@ static void __rs_deltree(struct gfs2_blkreserv *rs)
if (!gfs2_rs_active(rs))
return;
- rgd = rs->rs_rbm.rgd;
+ rgd = rs->rs_rgd;
trace_gfs2_rs(rs, TRACE_RS_TREEDEL);
rb_erase(&rs->rs_node, &rgd->rd_rstree);
RB_CLEAR_NODE(&rs->rs_node);
if (rs->rs_free) {
- struct gfs2_bitmap *bi = rbm_bi(&rs->rs_rbm);
+ struct gfs2_bitmap *bi;
/* return reserved blocks to the rgrp */
- BUG_ON(rs->rs_rbm.rgd->rd_reserved < rs->rs_free);
- rs->rs_rbm.rgd->rd_reserved -= rs->rs_free;
+ BUG_ON(rs->rs_rgd->rd_reserved < rs->rs_free);
+ rs->rs_rgd->rd_reserved -= rs->rs_free;
/* The rgrp extent failure point is likely not to increase;
it will only do so if the freed blocks are somehow
contiguous with a span of free blocks that follows. Still,
it will force the number to be recalculated later. */
rgd->rd_extfail_pt += rs->rs_free;
rs->rs_free = 0;
- clear_bit(GBF_FULL, &bi->bi_flags);
+ bi = gfs2_block_to_bitmap(rgd, rs->rs_start);
+ if (bi)
+ clear_bit(GBF_FULL, &bi->bi_flags);
}
}
@@ -666,7 +698,7 @@ void gfs2_rs_deltree(struct gfs2_blkreserv *rs)
{
struct gfs2_rgrpd *rgd;
- rgd = rs->rs_rbm.rgd;
+ rgd = rs->rs_rgd;
if (rgd) {
spin_lock(&rgd->rd_rsspin);
__rs_deltree(rs);
@@ -1481,8 +1513,7 @@ static void rs_insert(struct gfs2_inode *ip)
struct rb_node **newn, *parent = NULL;
int rc;
struct gfs2_blkreserv *rs = &ip->i_res;
- struct gfs2_rgrpd *rgd = rs->rs_rbm.rgd;
- u64 fsblock = gfs2_rbm_to_block(&rs->rs_rbm);
+ struct gfs2_rgrpd *rgd = rs->rs_rgd;
BUG_ON(gfs2_rs_active(rs));
@@ -1493,7 +1524,7 @@ static void rs_insert(struct gfs2_inode *ip)
rb_entry(*newn, struct gfs2_blkreserv, rs_node);
parent = *newn;
- rc = rs_cmp(fsblock, rs->rs_free, cur);
+ rc = rs_cmp(rs->rs_start, rs->rs_free, cur);
if (rc > 0)
newn = &((*newn)->rb_right);
else if (rc < 0)
@@ -1581,7 +1612,7 @@ static void rg_mblk_search(struct gfs2_rgrpd *rgd, struct
gfs2_inode *ip,
ret = gfs2_rbm_find(&rbm, GFS2_BLKST_FREE, &extlen, ip, true);
if (ret == 0) {
- rs->rs_rbm = rbm;
+ rs->rs_start = gfs2_rbm_to_block(&rbm);
rs->rs_free = extlen;
rs_insert(ip);
} else {
@@ -1626,7 +1657,7 @@ static u64 gfs2_next_unreserved_block(struct gfs2_rgrpd
*rgd, u64 block,
if (n) {
while ((rs_cmp(block, length, rs) == 0) && (&ip->i_res != rs)) {
- block = gfs2_rbm_to_block(&rs->rs_rbm) + rs->rs_free;
+ block = rs->rs_start + rs->rs_free;
n = n->rb_right;
if (n == NULL)
break;
@@ -1967,7 +1998,7 @@ static bool gfs2_rgrp_used_recently(const struct
gfs2_blkreserv *rs,
u64 tdiff;
tdiff = ktime_to_ns(ktime_sub(ktime_get_real(),
- rs->rs_rbm.rgd->rd_gl->gl_dstamp));
+ rs->rs_rgd->rd_gl->gl_dstamp));
return tdiff > (msecs * 1000 * 1000);
}
@@ -2045,45 +2076,45 @@ int gfs2_inplace_reserve(struct gfs2_inode *ip, struct
gfs2_alloc_parms *ap)
if (gfs2_assert_warn(sdp, ap->target))
return -EINVAL;
if (gfs2_rs_active(rs)) {
- begin = rs->rs_rbm.rgd;
- } else if (rs->rs_rbm.rgd &&
- rgrp_contains_block(rs->rs_rbm.rgd, ip->i_goal)) {
- begin = rs->rs_rbm.rgd;
+ begin = rs->rs_rgd;
+ } else if (rs->rs_rgd &&
+ rgrp_contains_block(rs->rs_rgd, ip->i_goal)) {
+ begin = rs->rs_rgd;
} else {
check_and_update_goal(ip);
- rs->rs_rbm.rgd = begin = gfs2_blk2rgrpd(sdp, ip->i_goal, 1);
+ rs->rs_rgd = begin = gfs2_blk2rgrpd(sdp, ip->i_goal, 1);
}
if (S_ISDIR(ip->i_inode.i_mode) && (ap->aflags & GFS2_AF_ORLOV))
skip = gfs2_orlov_skip(ip);
- if (rs->rs_rbm.rgd == NULL)
+ if (rs->rs_rgd == NULL)
return -EBADSLT;
while (loops < 3) {
rg_locked = 1;
- if (!gfs2_glock_is_locked_by_me(rs->rs_rbm.rgd->rd_gl)) {
+ if (!gfs2_glock_is_locked_by_me(rs->rs_rgd->rd_gl)) {
rg_locked = 0;
if (skip && skip--)
goto next_rgrp;
if (!gfs2_rs_active(rs)) {
if (loops == 0 &&
- !fast_to_acquire(rs->rs_rbm.rgd))
+ !fast_to_acquire(rs->rs_rgd))
goto next_rgrp;
if ((loops < 2) &&
gfs2_rgrp_used_recently(rs, 1000) &&
- gfs2_rgrp_congested(rs->rs_rbm.rgd, loops))
+ gfs2_rgrp_congested(rs->rs_rgd, loops))
goto next_rgrp;
}
- error = gfs2_glock_nq_init(rs->rs_rbm.rgd->rd_gl,
+ error = gfs2_glock_nq_init(rs->rs_rgd->rd_gl,
LM_ST_EXCLUSIVE, flags,
&ip->i_rgd_gh);
if (unlikely(error))
return error;
if (!gfs2_rs_active(rs) && (loops < 2) &&
- gfs2_rgrp_congested(rs->rs_rbm.rgd, loops))
+ gfs2_rgrp_congested(rs->rs_rgd, loops))
goto skip_rgrp;
if (sdp->sd_args.ar_rgrplvb) {
- error = update_rgrp_lvb(rs->rs_rbm.rgd);
+ error = update_rgrp_lvb(rs->rs_rgd);
if (unlikely(error)) {
gfs2_glock_dq_uninit(&ip->i_rgd_gh);
return error;
@@ -2092,24 +2123,24 @@ int gfs2_inplace_reserve(struct gfs2_inode *ip, struct
gfs2_alloc_parms *ap)
}
/* Skip unusable resource groups */
- if ((rs->rs_rbm.rgd->rd_flags & (GFS2_RGF_NOALLOC |
+ if ((rs->rs_rgd->rd_flags & (GFS2_RGF_NOALLOC |
GFS2_RDF_ERROR)) ||
- (loops == 0 && ap->target > rs->rs_rbm.rgd->rd_extfail_pt))
+ (loops == 0 && ap->target > rs->rs_rgd->rd_extfail_pt))
goto skip_rgrp;
if (sdp->sd_args.ar_rgrplvb)
- gfs2_rgrp_bh_get(rs->rs_rbm.rgd);
+ gfs2_rgrp_bh_get(rs->rs_rgd);
/* Get a reservation if we don't already have one */
if (!gfs2_rs_active(rs))
- rg_mblk_search(rs->rs_rbm.rgd, ip, ap);
+ rg_mblk_search(rs->rs_rgd, ip, ap);
/* Skip rgrps when we can't get a reservation on first pass */
if (!gfs2_rs_active(rs) && (loops < 1))
goto check_rgrp;
/* If rgrp has enough free space, use it */
- free_blocks = rgd_free(rs->rs_rbm.rgd, rs);
+ free_blocks = rgd_free(rs->rs_rgd, rs);
if (free_blocks >= ap->target ||
(loops == 2 && ap->min_target &&
free_blocks >= ap->min_target)) {
@@ -2118,8 +2149,8 @@ int gfs2_inplace_reserve(struct gfs2_inode *ip, struct
gfs2_alloc_parms *ap)
}
check_rgrp:
/* Check for unlinked inodes which can be reclaimed */
- if (rs->rs_rbm.rgd->rd_flags & GFS2_RDF_CHECK)
- try_rgrp_unlink(rs->rs_rbm.rgd, &last_unlinked,
+ if (rs->rs_rgd->rd_flags & GFS2_RDF_CHECK)
+ try_rgrp_unlink(rs->rs_rgd, &last_unlinked,
ip->i_no_addr);
skip_rgrp:
/* Drop reservation, if we couldn't use reserved rgrp */
@@ -2131,7 +2162,7 @@ int gfs2_inplace_reserve(struct gfs2_inode *ip, struct
gfs2_alloc_parms *ap)
gfs2_glock_dq_uninit(&ip->i_rgd_gh);
next_rgrp:
/* Find the next rgrp, and continue looking */
- if (gfs2_select_rgrp(&rs->rs_rbm.rgd, begin))
+ if (gfs2_select_rgrp(&rs->rs_rgd, begin))
continue;
if (skip)
continue;
@@ -2307,20 +2338,21 @@ static void gfs2_adjust_reservation(struct gfs2_inode
*ip,
{
struct gfs2_blkreserv *rs = &ip->i_res;
struct gfs2_rgrpd *rgd = rbm->rgd;
- unsigned rlen;
- u64 block;
- int ret;
spin_lock(&rgd->rd_rsspin);
if (gfs2_rs_active(rs)) {
- if (gfs2_rbm_eq(&rs->rs_rbm, rbm)) {
- block = gfs2_rbm_to_block(rbm);
- ret = gfs2_rbm_from_block(&rs->rs_rbm, block + len);
+ u64 start = gfs2_rbm_to_block(rbm);
+
+ if (rs->rs_start == start) {
+ unsigned int rlen;
+
+ rs->rs_start += len;
rlen = min(rs->rs_free, len);
rs->rs_free -= rlen;
rgd->rd_reserved -= rlen;
trace_gfs2_rs(rs, TRACE_RS_CLAIM);
- if (rs->rs_free && !ret)
+ if (rs->rs_start < rgd->rd_data0 + rgd->rd_data &&
+ rs->rs_free)
goto out;
/* We used up our block reservation, so we should
reserve more blocks next time. */
@@ -2349,15 +2381,13 @@ static void gfs2_set_alloc_start(struct gfs2_rbm *rbm,
u64 goal;
if (gfs2_rs_active(&ip->i_res)) {
- *rbm = ip->i_res.rs_rbm;
- return;
+ goal = ip->i_res.rs_start;
+ } else {
+ if (!dinode && rgrp_contains_block(rbm->rgd, ip->i_goal))
+ goal = ip->i_goal;
+ else
+ goal = rbm->rgd->rd_last_alloc + rbm->rgd->rd_data0;
}
-
- if (!dinode && rgrp_contains_block(rbm->rgd, ip->i_goal))
- goal = ip->i_goal;
- else
- goal = rbm->rgd->rd_last_alloc + rbm->rgd->rd_data0;
-
BUG_ON(gfs2_rbm_from_block(rbm, goal));
}
@@ -2377,7 +2407,7 @@ int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *nblocks,
{
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct buffer_head *dibh;
- struct gfs2_rbm rbm = { .rgd = ip->i_res.rs_rbm.rgd, };
+ struct gfs2_rbm rbm = { .rgd = ip->i_res.rs_rgd, };
unsigned int ndata;
u64 block; /* block, within the file system scope */
int error;
@@ -2612,7 +2642,7 @@ void gfs2_rlist_add(struct gfs2_inode *ip, struct
gfs2_rgrp_list *rlist,
return;
rgd = gfs2_blk2rgrpd(sdp, block, 1);
} else {
- rgd = ip->i_res.rs_rbm.rgd;
+ rgd = ip->i_res.rs_rgd;
if (!rgd || !rgrp_contains_block(rgd, block))
rgd = gfs2_blk2rgrpd(sdp, block, 1);
}
diff --git a/fs/gfs2/trace_gfs2.h b/fs/gfs2/trace_gfs2.h
index e0025258107a..7586c7629497 100644
--- a/fs/gfs2/trace_gfs2.h
+++ b/fs/gfs2/trace_gfs2.h
@@ -602,13 +602,13 @@ TRACE_EVENT(gfs2_rs,
),
TP_fast_assign(
- __entry->dev = rs->rs_rbm.rgd->rd_sbd->sd_vfs->s_dev;
- __entry->rd_addr = rs->rs_rbm.rgd->rd_addr;
- __entry->rd_free_clone = rs->rs_rbm.rgd->rd_free_clone;
- __entry->rd_reserved = rs->rs_rbm.rgd->rd_reserved;
+ __entry->dev = rs->rs_rgd->rd_sbd->sd_vfs->s_dev;
+ __entry->rd_addr = rs->rs_rgd->rd_addr;
+ __entry->rd_free_clone = rs->rs_rgd->rd_free_clone;
+ __entry->rd_reserved = rs->rs_rgd->rd_reserved;
__entry->inum = container_of(rs, struct
gfs2_inode,
i_res)->i_no_addr;
- __entry->start = gfs2_rbm_to_block(&rs->rs_rbm);
+ __entry->start = rs->rs_start;
__entry->free = rs->rs_free;
__entry->func = func;
),
diff --git a/fs/gfs2/trans.h b/fs/gfs2/trans.h
index ad70087d0597..a27078f98e7a 100644
--- a/fs/gfs2/trans.h
+++ b/fs/gfs2/trans.h
@@ -30,7 +30,7 @@ struct gfs2_glock;
* block, or all of the blocks in the rg, whichever is smaller */
static inline unsigned int gfs2_rg_blocks(const struct gfs2_inode *ip,
unsigned requested)
{
- struct gfs2_rgrpd *rgd = ip->i_res.rs_rbm.rgd;
+ struct gfs2_rgrpd *rgd = ip->i_res.rs_rgd;
if (requested < rgd->rd_length)
return requested + 1;