summaryrefslogtreecommitdiffstats
path: root/fs/gfs2/rgrp.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/gfs2/rgrp.c')
-rw-r--r--fs/gfs2/rgrp.c104
1 files changed, 60 insertions, 44 deletions
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c
index 708c287e1d0..3552110b2e5 100644
--- a/fs/gfs2/rgrp.c
+++ b/fs/gfs2/rgrp.c
@@ -25,10 +25,10 @@
#include "rgrp.h"
#include "super.h"
#include "trans.h"
-#include "ops_file.h"
#include "util.h"
#include "log.h"
#include "inode.h"
+#include "ops_address.h"
#define BFITNOENT ((u32)~0)
#define NO_BLOCK ((u64)~0)
@@ -126,41 +126,43 @@ static unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd, unsigned char *buffer,
* Return: the block number (bitmap buffer scope) that was found
*/
-static u32 gfs2_bitfit(struct gfs2_rgrpd *rgd, unsigned char *buffer,
- unsigned int buflen, u32 goal,
- unsigned char old_state)
+static u32 gfs2_bitfit(unsigned char *buffer, unsigned int buflen, u32 goal,
+ unsigned char old_state)
{
- unsigned char *byte, *end, alloc;
+ unsigned char *byte;
u32 blk = goal;
- unsigned int bit;
+ unsigned int bit, bitlong;
+ unsigned long *plong, plong55;
byte = buffer + (goal / GFS2_NBBY);
+ plong = (unsigned long *)(buffer + (goal / GFS2_NBBY));
bit = (goal % GFS2_NBBY) * GFS2_BIT_SIZE;
- end = buffer + buflen;
- alloc = (old_state == GFS2_BLKST_FREE) ? 0x55 : 0;
-
- while (byte < end) {
- /* If we're looking for a free block we can eliminate all
- bitmap settings with 0x55, which represents four data
- blocks in a row. If we're looking for a data block, we can
- eliminate 0x00 which corresponds to four free blocks. */
- if ((*byte & 0x55) == alloc) {
- blk += (8 - bit) >> 1;
-
- bit = 0;
- byte++;
-
+ bitlong = bit;
+#if BITS_PER_LONG == 32
+ plong55 = 0x55555555;
+#else
+ plong55 = 0x5555555555555555;
+#endif
+ while (byte < buffer + buflen) {
+
+ if (bitlong == 0 && old_state == 0 && *plong == plong55) {
+ plong++;
+ byte += sizeof(unsigned long);
+ blk += sizeof(unsigned long) * GFS2_NBBY;
continue;
}
-
if (((*byte >> bit) & GFS2_BIT_MASK) == old_state)
return blk;
-
bit += GFS2_BIT_SIZE;
if (bit >= 8) {
bit = 0;
byte++;
}
+ bitlong += GFS2_BIT_SIZE;
+ if (bitlong >= sizeof(unsigned long) * 8) {
+ bitlong = 0;
+ plong++;
+ }
blk++;
}
@@ -817,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 *al = &ip->i_alloc;
-
- /* FIXME: Should assert that the correct locks are held here... */
- memset(al, 0, sizeof(*al));
- return al;
+ BUG_ON(ip->i_alloc != NULL);
+ ip->i_alloc = kzalloc(sizeof(struct gfs2_alloc), GFP_KERNEL);
+ return ip->i_alloc;
}
/**
@@ -1059,26 +1059,34 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
struct inode *inode = NULL;
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
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 skipped = 0;
int loops = 0;
- int error;
+ int error, rg_locked;
/* Try recently successful rgrps */
rgd = recent_rgrp_first(sdp, ip->i_last_rg_alloc);
while (rgd) {
- error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE,
- LM_FLAG_TRY, &al->al_rgd_gh);
+ rg_locked = 0;
+
+ if (gfs2_glock_is_locked_by_me(rgd->rd_gl)) {
+ rg_locked = 1;
+ error = 0;
+ } else {
+ error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE,
+ LM_FLAG_TRY, &al->al_rgd_gh);
+ }
switch (error) {
case 0:
if (try_rgrp_fit(rgd, al))
goto out;
if (rgd->rd_flags & GFS2_RDF_CHECK)
inode = try_rgrp_unlink(rgd, last_unlinked);
- gfs2_glock_dq_uninit(&al->al_rgd_gh);
+ if (!rg_locked)
+ gfs2_glock_dq_uninit(&al->al_rgd_gh);
if (inode)
return inode;
rgd = recent_rgrp_next(rgd, 1);
@@ -1098,15 +1106,23 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
begin = rgd = forward_rgrp_get(sdp);
for (;;) {
- error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, flags,
- &al->al_rgd_gh);
+ rg_locked = 0;
+
+ if (gfs2_glock_is_locked_by_me(rgd->rd_gl)) {
+ rg_locked = 1;
+ error = 0;
+ } else {
+ error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, flags,
+ &al->al_rgd_gh);
+ }
switch (error) {
case 0:
if (try_rgrp_fit(rgd, al))
goto out;
if (rgd->rd_flags & GFS2_RDF_CHECK)
inode = try_rgrp_unlink(rgd, last_unlinked);
- gfs2_glock_dq_uninit(&al->al_rgd_gh);
+ if (!rg_locked)
+ gfs2_glock_dq_uninit(&al->al_rgd_gh);
if (inode)
return inode;
break;
@@ -1158,7 +1174,7 @@ out:
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_alloc *al = &ip->i_alloc;
+ struct gfs2_alloc *al = ip->i_alloc;
struct inode *inode;
int error = 0;
u64 last_unlinked = NO_BLOCK;
@@ -1204,7 +1220,7 @@ try_again:
void gfs2_inplace_release(struct gfs2_inode *ip)
{
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)
fs_warn(sdp, "al_alloced = %u, al_requested = %u "
@@ -1213,7 +1229,8 @@ void gfs2_inplace_release(struct gfs2_inode *ip)
al->al_line);
al->al_rgd = NULL;
- gfs2_glock_dq_uninit(&al->al_rgd_gh);
+ if (al->al_rgd_gh.gh_gl)
+ gfs2_glock_dq_uninit(&al->al_rgd_gh);
if (ip != GFS2_I(sdp->sd_rindex))
gfs2_glock_dq_uninit(&al->al_ri_gh);
}
@@ -1301,11 +1318,10 @@ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal,
/* The GFS2_BLKST_UNLINKED state doesn't apply to the clone
bitmaps, so we must search the originals for that. */
if (old_state != GFS2_BLKST_UNLINKED && bi->bi_clone)
- blk = gfs2_bitfit(rgd, bi->bi_clone + bi->bi_offset,
+ blk = gfs2_bitfit(bi->bi_clone + bi->bi_offset,
bi->bi_len, goal, old_state);
else
- blk = gfs2_bitfit(rgd,
- bi->bi_bh->b_data + bi->bi_offset,
+ blk = gfs2_bitfit(bi->bi_bh->b_data + bi->bi_offset,
bi->bi_len, goal, old_state);
if (blk != BFITNOENT)
break;
@@ -1394,7 +1410,7 @@ static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, u64 bstart,
u64 gfs2_alloc_data(struct gfs2_inode *ip)
{
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;
u32 goal, blk;
u64 block;
@@ -1439,7 +1455,7 @@ u64 gfs2_alloc_data(struct gfs2_inode *ip)
u64 gfs2_alloc_meta(struct gfs2_inode *ip)
{
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;
u32 goal, blk;
u64 block;
@@ -1485,7 +1501,7 @@ u64 gfs2_alloc_meta(struct gfs2_inode *ip)
u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation)
{
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;
u32 blk;
u64 block;