|
|
@@ -660,6 +660,7 @@ static int read_rindex_entry(struct gfs2_inode *ip)
|
|
|
goto fail;
|
|
|
|
|
|
rgd->rd_gl->gl_object = rgd;
|
|
|
+ rgd->rd_rgl = (struct gfs2_rgrp_lvb *)rgd->rd_gl->gl_lvb;
|
|
|
rgd->rd_flags &= ~GFS2_RDF_UPTODATE;
|
|
|
if (rgd->rd_data > sdp->sd_max_rg_data)
|
|
|
sdp->sd_max_rg_data = rgd->rd_data;
|
|
|
@@ -769,9 +770,65 @@ static void gfs2_rgrp_out(struct gfs2_rgrpd *rgd, void *buf)
|
|
|
memset(&str->rg_reserved, 0, sizeof(str->rg_reserved));
|
|
|
}
|
|
|
|
|
|
+static int gfs2_rgrp_lvb_valid(struct gfs2_rgrpd *rgd)
|
|
|
+{
|
|
|
+ struct gfs2_rgrp_lvb *rgl = rgd->rd_rgl;
|
|
|
+ struct gfs2_rgrp *str = (struct gfs2_rgrp *)rgd->rd_bits[0].bi_bh->b_data;
|
|
|
+
|
|
|
+ if (rgl->rl_flags != str->rg_flags || rgl->rl_free != str->rg_free ||
|
|
|
+ rgl->rl_dinodes != str->rg_dinodes ||
|
|
|
+ rgl->rl_igeneration != str->rg_igeneration)
|
|
|
+ return 0;
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
+static void gfs2_rgrp_ondisk2lvb(struct gfs2_rgrp_lvb *rgl, const void *buf)
|
|
|
+{
|
|
|
+ const struct gfs2_rgrp *str = buf;
|
|
|
+
|
|
|
+ rgl->rl_magic = cpu_to_be32(GFS2_MAGIC);
|
|
|
+ rgl->rl_flags = str->rg_flags;
|
|
|
+ rgl->rl_free = str->rg_free;
|
|
|
+ rgl->rl_dinodes = str->rg_dinodes;
|
|
|
+ rgl->rl_igeneration = str->rg_igeneration;
|
|
|
+ rgl->__pad = 0UL;
|
|
|
+}
|
|
|
+
|
|
|
+static void update_rgrp_lvb_unlinked(struct gfs2_rgrpd *rgd, u32 change)
|
|
|
+{
|
|
|
+ struct gfs2_rgrp_lvb *rgl = rgd->rd_rgl;
|
|
|
+ u32 unlinked = be32_to_cpu(rgl->rl_unlinked) + change;
|
|
|
+ rgl->rl_unlinked = cpu_to_be32(unlinked);
|
|
|
+}
|
|
|
+
|
|
|
+static u32 count_unlinked(struct gfs2_rgrpd *rgd)
|
|
|
+{
|
|
|
+ struct gfs2_bitmap *bi;
|
|
|
+ const u32 length = rgd->rd_length;
|
|
|
+ const u8 *buffer = NULL;
|
|
|
+ u32 i, goal, count = 0;
|
|
|
+
|
|
|
+ for (i = 0, bi = rgd->rd_bits; i < length; i++, bi++) {
|
|
|
+ goal = 0;
|
|
|
+ buffer = bi->bi_bh->b_data + bi->bi_offset;
|
|
|
+ WARN_ON(!buffer_uptodate(bi->bi_bh));
|
|
|
+ while (goal < bi->bi_len * GFS2_NBBY) {
|
|
|
+ goal = gfs2_bitfit(buffer, bi->bi_len, goal,
|
|
|
+ GFS2_BLKST_UNLINKED);
|
|
|
+ if (goal == BFITNOENT)
|
|
|
+ break;
|
|
|
+ count++;
|
|
|
+ goal++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return count;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
/**
|
|
|
- * gfs2_rgrp_go_lock - Read in a RG's header and bitmaps
|
|
|
- * @gh: The glock holder for the resource group
|
|
|
+ * gfs2_rgrp_bh_get - Read in a RG's header and bitmaps
|
|
|
+ * @rgd: the struct gfs2_rgrpd describing the RG to read in
|
|
|
*
|
|
|
* Read in all of a Resource Group's header and bitmap blocks.
|
|
|
* Caller must eventually call gfs2_rgrp_relse() to free the bitmaps.
|
|
|
@@ -779,9 +836,8 @@ static void gfs2_rgrp_out(struct gfs2_rgrpd *rgd, void *buf)
|
|
|
* Returns: errno
|
|
|
*/
|
|
|
|
|
|
-int gfs2_rgrp_go_lock(struct gfs2_holder *gh)
|
|
|
+int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd)
|
|
|
{
|
|
|
- struct gfs2_rgrpd *rgd = gh->gh_gl->gl_object;
|
|
|
struct gfs2_sbd *sdp = rgd->rd_sbd;
|
|
|
struct gfs2_glock *gl = rgd->rd_gl;
|
|
|
unsigned int length = rgd->rd_length;
|
|
|
@@ -789,6 +845,9 @@ int gfs2_rgrp_go_lock(struct gfs2_holder *gh)
|
|
|
unsigned int x, y;
|
|
|
int error;
|
|
|
|
|
|
+ if (rgd->rd_bits[0].bi_bh != NULL)
|
|
|
+ return 0;
|
|
|
+
|
|
|
for (x = 0; x < length; x++) {
|
|
|
bi = rgd->rd_bits + x;
|
|
|
error = gfs2_meta_read(gl, rgd->rd_addr + x, 0, &bi->bi_bh);
|
|
|
@@ -815,7 +874,20 @@ int gfs2_rgrp_go_lock(struct gfs2_holder *gh)
|
|
|
rgd->rd_flags |= (GFS2_RDF_UPTODATE | GFS2_RDF_CHECK);
|
|
|
rgd->rd_free_clone = rgd->rd_free;
|
|
|
}
|
|
|
-
|
|
|
+ if (be32_to_cpu(GFS2_MAGIC) != rgd->rd_rgl->rl_magic) {
|
|
|
+ rgd->rd_rgl->rl_unlinked = cpu_to_be32(count_unlinked(rgd));
|
|
|
+ gfs2_rgrp_ondisk2lvb(rgd->rd_rgl,
|
|
|
+ rgd->rd_bits[0].bi_bh->b_data);
|
|
|
+ }
|
|
|
+ else if (sdp->sd_args.ar_rgrplvb) {
|
|
|
+ if (!gfs2_rgrp_lvb_valid(rgd)){
|
|
|
+ gfs2_consist_rgrpd(rgd);
|
|
|
+ error = -EIO;
|
|
|
+ goto fail;
|
|
|
+ }
|
|
|
+ if (rgd->rd_rgl->rl_unlinked == 0)
|
|
|
+ rgd->rd_flags &= ~GFS2_RDF_CHECK;
|
|
|
+ }
|
|
|
return 0;
|
|
|
|
|
|
fail:
|
|
|
@@ -829,6 +901,39 @@ int gfs2_rgrp_go_lock(struct gfs2_holder *gh)
|
|
|
return error;
|
|
|
}
|
|
|
|
|
|
+int update_rgrp_lvb(struct gfs2_rgrpd *rgd)
|
|
|
+{
|
|
|
+ u32 rl_flags;
|
|
|
+
|
|
|
+ if (rgd->rd_flags & GFS2_RDF_UPTODATE)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ if (be32_to_cpu(GFS2_MAGIC) != rgd->rd_rgl->rl_magic)
|
|
|
+ return gfs2_rgrp_bh_get(rgd);
|
|
|
+
|
|
|
+ rl_flags = be32_to_cpu(rgd->rd_rgl->rl_flags);
|
|
|
+ rl_flags &= ~GFS2_RDF_MASK;
|
|
|
+ rgd->rd_flags &= GFS2_RDF_MASK;
|
|
|
+ rgd->rd_flags |= (rl_flags | GFS2_RDF_UPTODATE | GFS2_RDF_CHECK);
|
|
|
+ if (rgd->rd_rgl->rl_unlinked == 0)
|
|
|
+ rgd->rd_flags &= ~GFS2_RDF_CHECK;
|
|
|
+ rgd->rd_free = be32_to_cpu(rgd->rd_rgl->rl_free);
|
|
|
+ rgd->rd_free_clone = rgd->rd_free;
|
|
|
+ rgd->rd_dinodes = be32_to_cpu(rgd->rd_rgl->rl_dinodes);
|
|
|
+ rgd->rd_igeneration = be64_to_cpu(rgd->rd_rgl->rl_igeneration);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int gfs2_rgrp_go_lock(struct gfs2_holder *gh)
|
|
|
+{
|
|
|
+ struct gfs2_rgrpd *rgd = gh->gh_gl->gl_object;
|
|
|
+ struct gfs2_sbd *sdp = rgd->rd_sbd;
|
|
|
+
|
|
|
+ if (gh->gh_flags & GL_SKIP && sdp->sd_args.ar_rgrplvb)
|
|
|
+ return 0;
|
|
|
+ return gfs2_rgrp_bh_get((struct gfs2_rgrpd *)gh->gh_gl->gl_object);
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* gfs2_rgrp_go_unlock - Release RG bitmaps read in with gfs2_rgrp_bh_get()
|
|
|
* @gh: The glock holder for the resource group
|
|
|
@@ -842,8 +947,10 @@ void gfs2_rgrp_go_unlock(struct gfs2_holder *gh)
|
|
|
|
|
|
for (x = 0; x < length; x++) {
|
|
|
struct gfs2_bitmap *bi = rgd->rd_bits + x;
|
|
|
- brelse(bi->bi_bh);
|
|
|
- bi->bi_bh = NULL;
|
|
|
+ if (bi->bi_bh) {
|
|
|
+ brelse(bi->bi_bh);
|
|
|
+ bi->bi_bh = NULL;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
}
|
|
|
@@ -987,6 +1094,7 @@ int gfs2_fitrim(struct file *filp, void __user *argp)
|
|
|
rgd->rd_flags |= GFS2_RGF_TRIMMED;
|
|
|
gfs2_trans_add_bh(rgd->rd_gl, bh, 1);
|
|
|
gfs2_rgrp_out(rgd, bh->b_data);
|
|
|
+ gfs2_rgrp_ondisk2lvb(rgd->rd_rgl, bh->b_data);
|
|
|
gfs2_trans_end(sdp);
|
|
|
}
|
|
|
}
|
|
|
@@ -1116,6 +1224,9 @@ static int get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
|
|
|
int error, rg_locked, flags = LM_FLAG_TRY;
|
|
|
int loops = 0;
|
|
|
|
|
|
+ if (sdp->sd_args.ar_rgrplvb)
|
|
|
+ flags |= GL_SKIP;
|
|
|
+
|
|
|
if (ip->i_rgd && rgrp_contains_block(ip->i_rgd, ip->i_goal))
|
|
|
rgd = begin = ip->i_rgd;
|
|
|
else
|
|
|
@@ -1133,22 +1244,34 @@ static int get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
|
|
|
} else {
|
|
|
error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE,
|
|
|
flags, &rs->rs_rgd_gh);
|
|
|
+ if (!error && sdp->sd_args.ar_rgrplvb) {
|
|
|
+ error = update_rgrp_lvb(rgd);
|
|
|
+ if (error) {
|
|
|
+ gfs2_glock_dq_uninit(&rs->rs_rgd_gh);
|
|
|
+ return error;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
switch (error) {
|
|
|
case 0:
|
|
|
if (try_rgrp_fit(rgd, ip)) {
|
|
|
+ if (sdp->sd_args.ar_rgrplvb)
|
|
|
+ gfs2_rgrp_bh_get(rgd);
|
|
|
ip->i_rgd = rgd;
|
|
|
return 0;
|
|
|
}
|
|
|
- if (rgd->rd_flags & GFS2_RDF_CHECK)
|
|
|
+ if (rgd->rd_flags & GFS2_RDF_CHECK) {
|
|
|
+ if (sdp->sd_args.ar_rgrplvb)
|
|
|
+ gfs2_rgrp_bh_get(rgd);
|
|
|
try_rgrp_unlink(rgd, last_unlinked, ip->i_no_addr);
|
|
|
+ }
|
|
|
if (!rg_locked)
|
|
|
gfs2_glock_dq_uninit(&rs->rs_rgd_gh);
|
|
|
/* fall through */
|
|
|
case GLR_TRYFAILED:
|
|
|
rgd = gfs2_rgrpd_get_next(rgd);
|
|
|
if (rgd == begin) {
|
|
|
- flags = 0;
|
|
|
+ flags &= ~LM_FLAG_TRY;
|
|
|
loops++;
|
|
|
}
|
|
|
break;
|
|
|
@@ -1529,6 +1652,7 @@ int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *nblocks,
|
|
|
|
|
|
gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
|
|
|
gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data);
|
|
|
+ gfs2_rgrp_ondisk2lvb(rgd->rd_rgl, rgd->rd_bits[0].bi_bh->b_data);
|
|
|
|
|
|
gfs2_statfs_change(sdp, 0, -(s64)*nblocks, dinode ? 1 : 0);
|
|
|
if (dinode)
|
|
|
@@ -1575,6 +1699,7 @@ void __gfs2_free_blocks(struct gfs2_inode *ip, u64 bstart, u32 blen, int meta)
|
|
|
rgd->rd_flags &= ~GFS2_RGF_TRIMMED;
|
|
|
gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
|
|
|
gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data);
|
|
|
+ gfs2_rgrp_ondisk2lvb(rgd->rd_rgl, rgd->rd_bits[0].bi_bh->b_data);
|
|
|
|
|
|
/* Directories keep their data in the metadata address space */
|
|
|
if (meta || ip->i_depth)
|
|
|
@@ -1611,6 +1736,8 @@ void gfs2_unlink_di(struct inode *inode)
|
|
|
trace_gfs2_block_alloc(ip, rgd, blkno, 1, GFS2_BLKST_UNLINKED);
|
|
|
gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
|
|
|
gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data);
|
|
|
+ gfs2_rgrp_ondisk2lvb(rgd->rd_rgl, rgd->rd_bits[0].bi_bh->b_data);
|
|
|
+ update_rgrp_lvb_unlinked(rgd, 1);
|
|
|
}
|
|
|
|
|
|
static void gfs2_free_uninit_di(struct gfs2_rgrpd *rgd, u64 blkno)
|
|
|
@@ -1630,6 +1757,8 @@ static void gfs2_free_uninit_di(struct gfs2_rgrpd *rgd, u64 blkno)
|
|
|
|
|
|
gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
|
|
|
gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data);
|
|
|
+ gfs2_rgrp_ondisk2lvb(rgd->rd_rgl, rgd->rd_bits[0].bi_bh->b_data);
|
|
|
+ update_rgrp_lvb_unlinked(rgd, -1);
|
|
|
|
|
|
gfs2_statfs_change(sdp, 0, +1, -1);
|
|
|
}
|