ocfs2: plug truncate into cached dealloc routines
Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>
This commit is contained in:
parent
2b604351bc
commit
59a5e416d1
102
fs/ocfs2/alloc.c
102
fs/ocfs2/alloc.c
|
@ -50,6 +50,8 @@
|
||||||
#include "buffer_head_io.h"
|
#include "buffer_head_io.h"
|
||||||
|
|
||||||
static void ocfs2_free_truncate_context(struct ocfs2_truncate_context *tc);
|
static void ocfs2_free_truncate_context(struct ocfs2_truncate_context *tc);
|
||||||
|
static int ocfs2_cache_extent_block_free(struct ocfs2_cached_dealloc_ctxt *ctxt,
|
||||||
|
struct ocfs2_extent_block *eb);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Structures which describe a path through a btree, and functions to
|
* Structures which describe a path through a btree, and functions to
|
||||||
|
@ -3161,6 +3163,15 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ocfs2_cache_extent_block_free(struct ocfs2_cached_dealloc_ctxt *ctxt,
|
||||||
|
struct ocfs2_extent_block *eb)
|
||||||
|
{
|
||||||
|
return ocfs2_cache_block_dealloc(ctxt, EXTENT_ALLOC_SYSTEM_INODE,
|
||||||
|
le16_to_cpu(eb->h_suballoc_slot),
|
||||||
|
le64_to_cpu(eb->h_blkno),
|
||||||
|
le16_to_cpu(eb->h_suballoc_bit));
|
||||||
|
}
|
||||||
|
|
||||||
/* This function will figure out whether the currently last extent
|
/* This function will figure out whether the currently last extent
|
||||||
* block will be deleted, and if it will, what the new last extent
|
* block will be deleted, and if it will, what the new last extent
|
||||||
* block will be so we can update his h_next_leaf_blk field, as well
|
* block will be so we can update his h_next_leaf_blk field, as well
|
||||||
|
@ -3442,27 +3453,10 @@ delete:
|
||||||
BUG_ON(le32_to_cpu(el->l_recs[0].e_cpos));
|
BUG_ON(le32_to_cpu(el->l_recs[0].e_cpos));
|
||||||
BUG_ON(le64_to_cpu(el->l_recs[0].e_blkno));
|
BUG_ON(le64_to_cpu(el->l_recs[0].e_blkno));
|
||||||
|
|
||||||
if (le16_to_cpu(eb->h_suballoc_slot) == 0) {
|
ret = ocfs2_cache_extent_block_free(&tc->tc_dealloc, eb);
|
||||||
/*
|
/* An error here is not fatal. */
|
||||||
* This code only understands how to
|
if (ret < 0)
|
||||||
* lock the suballocator in slot 0,
|
mlog_errno(ret);
|
||||||
* which is fine because allocation is
|
|
||||||
* only ever done out of that
|
|
||||||
* suballocator too. A future version
|
|
||||||
* might change that however, so avoid
|
|
||||||
* a free if we don't know how to
|
|
||||||
* handle it. This way an fs incompat
|
|
||||||
* bit will not be necessary.
|
|
||||||
*/
|
|
||||||
ret = ocfs2_free_extent_block(handle,
|
|
||||||
tc->tc_ext_alloc_inode,
|
|
||||||
tc->tc_ext_alloc_bh,
|
|
||||||
eb);
|
|
||||||
|
|
||||||
/* An error here is not fatal. */
|
|
||||||
if (ret < 0)
|
|
||||||
mlog_errno(ret);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
deleted_eb = 0;
|
deleted_eb = 0;
|
||||||
}
|
}
|
||||||
|
@ -3965,6 +3959,8 @@ bail:
|
||||||
if (handle)
|
if (handle)
|
||||||
ocfs2_commit_trans(osb, handle);
|
ocfs2_commit_trans(osb, handle);
|
||||||
|
|
||||||
|
ocfs2_run_deallocs(osb, &tc->tc_dealloc);
|
||||||
|
|
||||||
ocfs2_free_path(path);
|
ocfs2_free_path(path);
|
||||||
|
|
||||||
/* This will drop the ext_alloc cluster lock for us */
|
/* This will drop the ext_alloc cluster lock for us */
|
||||||
|
@ -3975,23 +3971,18 @@ bail:
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Expects the inode to already be locked. This will figure out which
|
* Expects the inode to already be locked.
|
||||||
* inodes need to be locked and will put them on the returned truncate
|
|
||||||
* context.
|
|
||||||
*/
|
*/
|
||||||
int ocfs2_prepare_truncate(struct ocfs2_super *osb,
|
int ocfs2_prepare_truncate(struct ocfs2_super *osb,
|
||||||
struct inode *inode,
|
struct inode *inode,
|
||||||
struct buffer_head *fe_bh,
|
struct buffer_head *fe_bh,
|
||||||
struct ocfs2_truncate_context **tc)
|
struct ocfs2_truncate_context **tc)
|
||||||
{
|
{
|
||||||
int status, metadata_delete, i;
|
int status;
|
||||||
unsigned int new_i_clusters;
|
unsigned int new_i_clusters;
|
||||||
struct ocfs2_dinode *fe;
|
struct ocfs2_dinode *fe;
|
||||||
struct ocfs2_extent_block *eb;
|
struct ocfs2_extent_block *eb;
|
||||||
struct ocfs2_extent_list *el;
|
|
||||||
struct buffer_head *last_eb_bh = NULL;
|
struct buffer_head *last_eb_bh = NULL;
|
||||||
struct inode *ext_alloc_inode = NULL;
|
|
||||||
struct buffer_head *ext_alloc_bh = NULL;
|
|
||||||
|
|
||||||
mlog_entry_void();
|
mlog_entry_void();
|
||||||
|
|
||||||
|
@ -4011,12 +4002,9 @@ int ocfs2_prepare_truncate(struct ocfs2_super *osb,
|
||||||
mlog_errno(status);
|
mlog_errno(status);
|
||||||
goto bail;
|
goto bail;
|
||||||
}
|
}
|
||||||
|
ocfs2_init_dealloc_ctxt(&(*tc)->tc_dealloc);
|
||||||
|
|
||||||
metadata_delete = 0;
|
|
||||||
if (fe->id2.i_list.l_tree_depth) {
|
if (fe->id2.i_list.l_tree_depth) {
|
||||||
/* If we have a tree, then the truncate may result in
|
|
||||||
* metadata deletes. Figure this out from the
|
|
||||||
* rightmost leaf block.*/
|
|
||||||
status = ocfs2_read_block(osb, le64_to_cpu(fe->i_last_eb_blk),
|
status = ocfs2_read_block(osb, le64_to_cpu(fe->i_last_eb_blk),
|
||||||
&last_eb_bh, OCFS2_BH_CACHED, inode);
|
&last_eb_bh, OCFS2_BH_CACHED, inode);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
|
@ -4031,43 +4019,10 @@ int ocfs2_prepare_truncate(struct ocfs2_super *osb,
|
||||||
status = -EIO;
|
status = -EIO;
|
||||||
goto bail;
|
goto bail;
|
||||||
}
|
}
|
||||||
el = &(eb->h_list);
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
if (ocfs2_is_empty_extent(&el->l_recs[0]))
|
|
||||||
i = 1;
|
|
||||||
/*
|
|
||||||
* XXX: Should we check that next_free_rec contains
|
|
||||||
* the extent?
|
|
||||||
*/
|
|
||||||
if (le32_to_cpu(el->l_recs[i].e_cpos) >= new_i_clusters)
|
|
||||||
metadata_delete = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
(*tc)->tc_last_eb_bh = last_eb_bh;
|
(*tc)->tc_last_eb_bh = last_eb_bh;
|
||||||
|
|
||||||
if (metadata_delete) {
|
|
||||||
mlog(0, "Will have to delete metadata for this trunc. "
|
|
||||||
"locking allocator.\n");
|
|
||||||
ext_alloc_inode = ocfs2_get_system_file_inode(osb, EXTENT_ALLOC_SYSTEM_INODE, 0);
|
|
||||||
if (!ext_alloc_inode) {
|
|
||||||
status = -ENOMEM;
|
|
||||||
mlog_errno(status);
|
|
||||||
goto bail;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_lock(&ext_alloc_inode->i_mutex);
|
|
||||||
(*tc)->tc_ext_alloc_inode = ext_alloc_inode;
|
|
||||||
|
|
||||||
status = ocfs2_meta_lock(ext_alloc_inode, &ext_alloc_bh, 1);
|
|
||||||
if (status < 0) {
|
|
||||||
mlog_errno(status);
|
|
||||||
goto bail;
|
|
||||||
}
|
|
||||||
(*tc)->tc_ext_alloc_bh = ext_alloc_bh;
|
|
||||||
(*tc)->tc_ext_alloc_locked = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = 0;
|
status = 0;
|
||||||
bail:
|
bail:
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
|
@ -4081,16 +4036,13 @@ bail:
|
||||||
|
|
||||||
static void ocfs2_free_truncate_context(struct ocfs2_truncate_context *tc)
|
static void ocfs2_free_truncate_context(struct ocfs2_truncate_context *tc)
|
||||||
{
|
{
|
||||||
if (tc->tc_ext_alloc_inode) {
|
/*
|
||||||
if (tc->tc_ext_alloc_locked)
|
* The caller is responsible for completing deallocation
|
||||||
ocfs2_meta_unlock(tc->tc_ext_alloc_inode, 1);
|
* before freeing the context.
|
||||||
|
*/
|
||||||
mutex_unlock(&tc->tc_ext_alloc_inode->i_mutex);
|
if (tc->tc_dealloc.c_first_suballocator != NULL)
|
||||||
iput(tc->tc_ext_alloc_inode);
|
mlog(ML_NOTICE,
|
||||||
}
|
"Truncate completion has non-empty dealloc context\n");
|
||||||
|
|
||||||
if (tc->tc_ext_alloc_bh)
|
|
||||||
brelse(tc->tc_ext_alloc_bh);
|
|
||||||
|
|
||||||
if (tc->tc_last_eb_bh)
|
if (tc->tc_last_eb_bh)
|
||||||
brelse(tc->tc_last_eb_bh);
|
brelse(tc->tc_last_eb_bh);
|
||||||
|
|
|
@ -83,8 +83,7 @@ int ocfs2_run_deallocs(struct ocfs2_super *osb,
|
||||||
struct ocfs2_cached_dealloc_ctxt *ctxt);
|
struct ocfs2_cached_dealloc_ctxt *ctxt);
|
||||||
|
|
||||||
struct ocfs2_truncate_context {
|
struct ocfs2_truncate_context {
|
||||||
struct inode *tc_ext_alloc_inode;
|
struct ocfs2_cached_dealloc_ctxt tc_dealloc;
|
||||||
struct buffer_head *tc_ext_alloc_bh;
|
|
||||||
int tc_ext_alloc_locked; /* is it cluster locked? */
|
int tc_ext_alloc_locked; /* is it cluster locked? */
|
||||||
/* these get destroyed once it's passed to ocfs2_commit_truncate. */
|
/* these get destroyed once it's passed to ocfs2_commit_truncate. */
|
||||||
struct buffer_head *tc_last_eb_bh;
|
struct buffer_head *tc_last_eb_bh;
|
||||||
|
|
|
@ -1498,6 +1498,7 @@ int ocfs2_write_end_nolock(struct address_space *mapping,
|
||||||
ocfs2_journal_dirty(handle, wc->w_di_bh);
|
ocfs2_journal_dirty(handle, wc->w_di_bh);
|
||||||
|
|
||||||
ocfs2_commit_trans(osb, handle);
|
ocfs2_commit_trans(osb, handle);
|
||||||
|
|
||||||
ocfs2_free_write_ctxt(wc);
|
ocfs2_free_write_ctxt(wc);
|
||||||
|
|
||||||
return copied;
|
return copied;
|
||||||
|
|
|
@ -1708,19 +1708,6 @@ int ocfs2_free_dinode(handle_t *handle,
|
||||||
inode_alloc_bh, bit, bg_blkno, 1);
|
inode_alloc_bh, bit, bg_blkno, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ocfs2_free_extent_block(handle_t *handle,
|
|
||||||
struct inode *eb_alloc_inode,
|
|
||||||
struct buffer_head *eb_alloc_bh,
|
|
||||||
struct ocfs2_extent_block *eb)
|
|
||||||
{
|
|
||||||
u64 blk = le64_to_cpu(eb->h_blkno);
|
|
||||||
u16 bit = le16_to_cpu(eb->h_suballoc_bit);
|
|
||||||
u64 bg_blkno = ocfs2_which_suballoc_group(blk, bit);
|
|
||||||
|
|
||||||
return ocfs2_free_suballoc_bits(handle, eb_alloc_inode, eb_alloc_bh,
|
|
||||||
bit, bg_blkno, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ocfs2_free_clusters(handle_t *handle,
|
int ocfs2_free_clusters(handle_t *handle,
|
||||||
struct inode *bitmap_inode,
|
struct inode *bitmap_inode,
|
||||||
struct buffer_head *bitmap_bh,
|
struct buffer_head *bitmap_bh,
|
||||||
|
|
|
@ -96,10 +96,6 @@ int ocfs2_free_dinode(handle_t *handle,
|
||||||
struct inode *inode_alloc_inode,
|
struct inode *inode_alloc_inode,
|
||||||
struct buffer_head *inode_alloc_bh,
|
struct buffer_head *inode_alloc_bh,
|
||||||
struct ocfs2_dinode *di);
|
struct ocfs2_dinode *di);
|
||||||
int ocfs2_free_extent_block(handle_t *handle,
|
|
||||||
struct inode *eb_alloc_inode,
|
|
||||||
struct buffer_head *eb_alloc_bh,
|
|
||||||
struct ocfs2_extent_block *eb);
|
|
||||||
int ocfs2_free_clusters(handle_t *handle,
|
int ocfs2_free_clusters(handle_t *handle,
|
||||||
struct inode *bitmap_inode,
|
struct inode *bitmap_inode,
|
||||||
struct buffer_head *bitmap_bh,
|
struct buffer_head *bitmap_bh,
|
||||||
|
|
Loading…
Reference in New Issue