|
@@ -57,6 +57,12 @@ struct ocfs2_suballoc_result {
|
|
|
u64 sr_bg_blkno; /* The bg we allocated from. Set
|
|
|
to 0 when a block group is
|
|
|
contiguous. */
|
|
|
+ u64 sr_bg_stable_blkno; /*
|
|
|
+ * Doesn't change, always
|
|
|
+ * set to target block
|
|
|
+ * group descriptor
|
|
|
+ * block.
|
|
|
+ */
|
|
|
u64 sr_blkno; /* The first allocated block */
|
|
|
unsigned int sr_bit_offset; /* The bit in the bg */
|
|
|
unsigned int sr_bits; /* How many bits we claimed */
|
|
@@ -149,6 +155,10 @@ void ocfs2_free_ac_resource(struct ocfs2_alloc_context *ac)
|
|
|
brelse(ac->ac_bh);
|
|
|
ac->ac_bh = NULL;
|
|
|
ac->ac_resv = NULL;
|
|
|
+ if (ac->ac_find_loc_priv) {
|
|
|
+ kfree(ac->ac_find_loc_priv);
|
|
|
+ ac->ac_find_loc_priv = NULL;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
void ocfs2_free_alloc_context(struct ocfs2_alloc_context *ac)
|
|
@@ -1689,6 +1699,15 @@ static int ocfs2_search_one_group(struct ocfs2_alloc_context *ac,
|
|
|
if (!ret)
|
|
|
ocfs2_bg_discontig_fix_result(ac, gd, res);
|
|
|
|
|
|
+ /*
|
|
|
+ * sr_bg_blkno might have been changed by
|
|
|
+ * ocfs2_bg_discontig_fix_result
|
|
|
+ */
|
|
|
+ res->sr_bg_stable_blkno = group_bh->b_blocknr;
|
|
|
+
|
|
|
+ if (ac->ac_find_loc_only)
|
|
|
+ goto out_loc_only;
|
|
|
+
|
|
|
ret = ocfs2_alloc_dinode_update_counts(alloc_inode, handle, ac->ac_bh,
|
|
|
res->sr_bits,
|
|
|
le16_to_cpu(gd->bg_chain));
|
|
@@ -1702,6 +1721,7 @@ static int ocfs2_search_one_group(struct ocfs2_alloc_context *ac,
|
|
|
if (ret < 0)
|
|
|
mlog_errno(ret);
|
|
|
|
|
|
+out_loc_only:
|
|
|
*bits_left = le16_to_cpu(gd->bg_free_bits_count);
|
|
|
|
|
|
out:
|
|
@@ -1780,6 +1800,11 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac,
|
|
|
if (!status)
|
|
|
ocfs2_bg_discontig_fix_result(ac, bg, res);
|
|
|
|
|
|
+ /*
|
|
|
+ * sr_bg_blkno might have been changed by
|
|
|
+ * ocfs2_bg_discontig_fix_result
|
|
|
+ */
|
|
|
+ res->sr_bg_stable_blkno = group_bh->b_blocknr;
|
|
|
|
|
|
/*
|
|
|
* Keep track of previous block descriptor read. When
|
|
@@ -1806,6 +1831,9 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ if (ac->ac_find_loc_only)
|
|
|
+ goto out_loc_only;
|
|
|
+
|
|
|
status = ocfs2_alloc_dinode_update_counts(alloc_inode, handle,
|
|
|
ac->ac_bh, res->sr_bits,
|
|
|
chain);
|
|
@@ -1828,6 +1856,7 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac,
|
|
|
mlog(0, "Allocated %u bits from suballocator %llu\n", res->sr_bits,
|
|
|
(unsigned long long)le64_to_cpu(fe->i_blkno));
|
|
|
|
|
|
+out_loc_only:
|
|
|
*bits_left = le16_to_cpu(bg->bg_free_bits_count);
|
|
|
bail:
|
|
|
brelse(group_bh);
|
|
@@ -2023,6 +2052,136 @@ static inline void ocfs2_save_inode_ac_group(struct inode *dir,
|
|
|
OCFS2_I(dir)->ip_last_used_slot = ac->ac_alloc_slot;
|
|
|
}
|
|
|
|
|
|
+int ocfs2_find_new_inode_loc(struct inode *dir,
|
|
|
+ struct buffer_head *parent_fe_bh,
|
|
|
+ struct ocfs2_alloc_context *ac,
|
|
|
+ u64 *fe_blkno)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+ handle_t *handle = NULL;
|
|
|
+ struct ocfs2_suballoc_result *res;
|
|
|
+
|
|
|
+ BUG_ON(!ac);
|
|
|
+ BUG_ON(ac->ac_bits_given != 0);
|
|
|
+ BUG_ON(ac->ac_bits_wanted != 1);
|
|
|
+ BUG_ON(ac->ac_which != OCFS2_AC_USE_INODE);
|
|
|
+
|
|
|
+ res = kzalloc(sizeof(*res), GFP_NOFS);
|
|
|
+ if (res == NULL) {
|
|
|
+ ret = -ENOMEM;
|
|
|
+ mlog_errno(ret);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ ocfs2_init_inode_ac_group(dir, parent_fe_bh, ac);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * The handle started here is for chain relink. Alternatively,
|
|
|
+ * we could just disable relink for these calls.
|
|
|
+ */
|
|
|
+ handle = ocfs2_start_trans(OCFS2_SB(dir->i_sb), OCFS2_SUBALLOC_ALLOC);
|
|
|
+ if (IS_ERR(handle)) {
|
|
|
+ ret = PTR_ERR(handle);
|
|
|
+ handle = NULL;
|
|
|
+ mlog_errno(ret);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * This will instruct ocfs2_claim_suballoc_bits and
|
|
|
+ * ocfs2_search_one_group to search but save actual allocation
|
|
|
+ * for later.
|
|
|
+ */
|
|
|
+ ac->ac_find_loc_only = 1;
|
|
|
+
|
|
|
+ ret = ocfs2_claim_suballoc_bits(ac, handle, 1, 1, res);
|
|
|
+ if (ret < 0) {
|
|
|
+ mlog_errno(ret);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ ac->ac_find_loc_priv = res;
|
|
|
+ *fe_blkno = res->sr_blkno;
|
|
|
+
|
|
|
+out:
|
|
|
+ if (handle)
|
|
|
+ ocfs2_commit_trans(OCFS2_SB(dir->i_sb), handle);
|
|
|
+
|
|
|
+ if (ret)
|
|
|
+ kfree(res);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+int ocfs2_claim_new_inode_at_loc(handle_t *handle,
|
|
|
+ struct inode *dir,
|
|
|
+ struct ocfs2_alloc_context *ac,
|
|
|
+ u64 *suballoc_loc,
|
|
|
+ u16 *suballoc_bit,
|
|
|
+ u64 di_blkno)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+ u16 chain;
|
|
|
+ struct ocfs2_suballoc_result *res = ac->ac_find_loc_priv;
|
|
|
+ struct buffer_head *bg_bh = NULL;
|
|
|
+ struct ocfs2_group_desc *bg;
|
|
|
+ struct ocfs2_dinode *di = (struct ocfs2_dinode *) ac->ac_bh->b_data;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Since di_blkno is being passed back in, we check for any
|
|
|
+ * inconsistencies which may have happened between
|
|
|
+ * calls. These are code bugs as di_blkno is not expected to
|
|
|
+ * change once returned from ocfs2_find_new_inode_loc()
|
|
|
+ */
|
|
|
+ BUG_ON(res->sr_blkno != di_blkno);
|
|
|
+
|
|
|
+ ret = ocfs2_read_group_descriptor(ac->ac_inode, di,
|
|
|
+ res->sr_bg_stable_blkno, &bg_bh);
|
|
|
+ if (ret) {
|
|
|
+ mlog_errno(ret);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ bg = (struct ocfs2_group_desc *) bg_bh->b_data;
|
|
|
+ chain = le16_to_cpu(bg->bg_chain);
|
|
|
+
|
|
|
+ ret = ocfs2_alloc_dinode_update_counts(ac->ac_inode, handle,
|
|
|
+ ac->ac_bh, res->sr_bits,
|
|
|
+ chain);
|
|
|
+ if (ret) {
|
|
|
+ mlog_errno(ret);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = ocfs2_block_group_set_bits(handle,
|
|
|
+ ac->ac_inode,
|
|
|
+ bg,
|
|
|
+ bg_bh,
|
|
|
+ res->sr_bit_offset,
|
|
|
+ res->sr_bits);
|
|
|
+ if (ret < 0) {
|
|
|
+ mlog_errno(ret);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ mlog(0, "Allocated %u bits from suballocator %llu\n", res->sr_bits,
|
|
|
+ (unsigned long long)di_blkno);
|
|
|
+
|
|
|
+ atomic_inc(&OCFS2_SB(ac->ac_inode->i_sb)->alloc_stats.bg_allocs);
|
|
|
+
|
|
|
+ BUG_ON(res->sr_bits != 1);
|
|
|
+
|
|
|
+ *suballoc_loc = res->sr_bg_blkno;
|
|
|
+ *suballoc_bit = res->sr_bit_offset;
|
|
|
+ ac->ac_bits_given++;
|
|
|
+ ocfs2_save_inode_ac_group(dir, ac);
|
|
|
+
|
|
|
+out:
|
|
|
+ brelse(bg_bh);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
int ocfs2_claim_new_inode(handle_t *handle,
|
|
|
struct inode *dir,
|
|
|
struct buffer_head *parent_fe_bh,
|