Skip to content

Commit

Permalink
ocfs2: Trim suballocations if they cross discontiguous regions
Browse files Browse the repository at this point in the history
A discontiguous block group can find a range of free bits that straddle
more than one region of its space.  Callers can't handle that, so we
trim the returned bits until they fit within one region.

Only cluster allocations ask for min_bits>1.  Discontiguous block groups
are only for block allocations.  So min_bits doesn't matter here.

Signed-off-by: Joel Becker <joel.becker@oracle.com>
  • Loading branch information
Joel Becker authored and Tao Ma committed Mar 26, 2010
1 parent aa8f8e9 commit 13e434c
Showing 1 changed file with 48 additions and 0 deletions.
48 changes: 48 additions & 0 deletions fs/ocfs2/suballoc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1579,6 +1579,48 @@ static int ocfs2_alloc_dinode_update_counts(struct inode *inode,
return ret;
}

static int ocfs2_bg_discontig_trim_by_rec(struct ocfs2_suballoc_result *res,
struct ocfs2_extent_rec *rec,
struct ocfs2_chain_list *cl)
{
unsigned int bpc = le16_to_cpu(cl->cl_bpc);
unsigned int bitoff = le32_to_cpu(rec->e_cpos) * bpc;
unsigned int bitcount = le32_to_cpu(rec->e_leaf_clusters) * bpc;

if (res->sr_bit_offset < bitoff)
return 0;
if (res->sr_bit_offset >= (bitoff + bitcount))
return 0;
if ((res->sr_bit_offset + res->sr_bits) > (bitoff + bitcount))
res->sr_bits = (bitoff + bitcount) - res->sr_bit_offset;
return 1;
}

static void ocfs2_bg_discontig_trim_result(struct ocfs2_alloc_context *ac,
struct ocfs2_group_desc *bg,
struct ocfs2_suballoc_result *res)
{
int i;
struct ocfs2_extent_rec *rec;
struct ocfs2_dinode *di = (struct ocfs2_dinode *)ac->ac_bh->b_data;
struct ocfs2_chain_list *cl = &di->id2.i_chain;

if (!ocfs2_supports_discontig_bh(OCFS2_SB(ac->ac_inode->i_sb)))
return;

if (ocfs2_is_cluster_bitmap(ac->ac_inode))
return;

if (!bg->bg_list.l_next_free_rec)
return;

for (i = 0; i < le16_to_cpu(bg->bg_list.l_next_free_rec); i++) {
rec = &bg->bg_list.l_recs[i];
if (ocfs2_bg_discontig_trim_by_rec(res, rec, cl))
break;
}
}

static int ocfs2_search_one_group(struct ocfs2_alloc_context *ac,
handle_t *handle,
u32 bits_wanted,
Expand Down Expand Up @@ -1608,6 +1650,9 @@ static int ocfs2_search_one_group(struct ocfs2_alloc_context *ac,
goto out;
}

if (!ret)
ocfs2_bg_discontig_trim_result(ac, gd, res);

ret = ocfs2_alloc_dinode_update_counts(alloc_inode, handle, ac->ac_bh,
res->sr_bits,
le16_to_cpu(gd->bg_chain));
Expand Down Expand Up @@ -1697,6 +1742,9 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac,
res->sr_bg_blkno = le64_to_cpu(bg->bg_blkno);

BUG_ON(res->sr_bits == 0);
if (!status)
ocfs2_bg_discontig_trim_result(ac, bg, res);


/*
* Keep track of previous block descriptor read. When
Expand Down

0 comments on commit 13e434c

Please sign in to comment.