Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 195745
b: refs/heads/master
c: c1631d4
h: refs/heads/master
i:
  195743: 3de9852
v: v3
  • Loading branch information
Tristan Ye authored and Joel Becker committed May 18, 2010
1 parent c40a5a1 commit 7a5dbb0
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 25 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: ee149a7c6cbaee0e3a1a7d9e9f92711228ef5236
refs/heads/master: c1631d4a484fbb498e35d661f1aebd64c86b66bf
164 changes: 140 additions & 24 deletions trunk/fs/ocfs2/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -1418,18 +1418,90 @@ static int ocfs2_zero_partial_clusters(struct inode *inode,
return ret;
}

static int ocfs2_find_rec(struct ocfs2_extent_list *el, u32 pos)
{
int i;
struct ocfs2_extent_rec *rec = NULL;

for (i = le16_to_cpu(el->l_next_free_rec) - 1; i >= 0; i--) {

rec = &el->l_recs[i];

if (le32_to_cpu(rec->e_cpos) < pos)
break;
}

return i;
}

/*
* Helper to calculate the punching pos and length in one run, we handle the
* following three cases in order:
*
* - remove the entire record
* - remove a partial record
* - no record needs to be removed (hole-punching completed)
*/
static void ocfs2_calc_trunc_pos(struct inode *inode,
struct ocfs2_extent_list *el,
struct ocfs2_extent_rec *rec,
u32 trunc_start, u32 *trunc_cpos,
u32 *trunc_len, u32 *trunc_end,
u64 *blkno, int *done)
{
int ret = 0;
u32 coff, range;

range = le32_to_cpu(rec->e_cpos) + ocfs2_rec_clusters(el, rec);

if (le32_to_cpu(rec->e_cpos) >= trunc_start) {
*trunc_cpos = le32_to_cpu(rec->e_cpos);
/*
* Skip holes if any.
*/
if (range < *trunc_end)
*trunc_end = range;
*trunc_len = *trunc_end - le32_to_cpu(rec->e_cpos);
*blkno = le64_to_cpu(rec->e_blkno);
*trunc_end = le32_to_cpu(rec->e_cpos);
} else if (range > trunc_start) {
*trunc_cpos = trunc_start;
*trunc_len = *trunc_end - trunc_start;
coff = trunc_start - le32_to_cpu(rec->e_cpos);
*blkno = le64_to_cpu(rec->e_blkno) +
ocfs2_clusters_to_blocks(inode->i_sb, coff);
*trunc_end = trunc_start;
} else {
/*
* It may have two following possibilities:
*
* - last record has been removed
* - trunc_start was within a hole
*
* both two cases mean the completion of hole punching.
*/
ret = 1;
}

*done = ret;
}

static int ocfs2_remove_inode_range(struct inode *inode,
struct buffer_head *di_bh, u64 byte_start,
u64 byte_len)
{
int ret = 0, flags = 0;
u32 trunc_start, trunc_len, cpos, phys_cpos, alloc_size;
int ret = 0, flags = 0, done = 0, i;
u32 trunc_start, trunc_len, trunc_end, trunc_cpos, phys_cpos;
u32 cluster_in_el;
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
struct ocfs2_cached_dealloc_ctxt dealloc;
struct address_space *mapping = inode->i_mapping;
struct ocfs2_extent_tree et;
struct ocfs2_path *path = NULL;
struct ocfs2_extent_list *el = NULL;
struct ocfs2_extent_rec *rec = NULL;
struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
u64 refcount_loc = le64_to_cpu(di->i_refcount_loc);
u64 blkno, refcount_loc = le64_to_cpu(di->i_refcount_loc);

ocfs2_init_dinode_extent_tree(&et, INODE_CACHE(inode), di_bh);
ocfs2_init_dealloc_ctxt(&dealloc);
Expand Down Expand Up @@ -1477,49 +1549,93 @@ static int ocfs2_remove_inode_range(struct inode *inode,
}

trunc_start = ocfs2_clusters_for_bytes(osb->sb, byte_start);
trunc_len = (byte_start + byte_len) >> osb->s_clustersize_bits;
if (trunc_len >= trunc_start)
trunc_len -= trunc_start;
else
trunc_len = 0;
trunc_end = (byte_start + byte_len) >> osb->s_clustersize_bits;
cluster_in_el = trunc_end;

mlog(0, "Inode: %llu, start: %llu, len: %llu, cstart: %u, clen: %u\n",
mlog(0, "Inode: %llu, start: %llu, len: %llu, cstart: %u, cend: %u\n",
(unsigned long long)OCFS2_I(inode)->ip_blkno,
(unsigned long long)byte_start,
(unsigned long long)byte_len, trunc_start, trunc_len);
(unsigned long long)byte_len, trunc_start, trunc_end);

ret = ocfs2_zero_partial_clusters(inode, byte_start, byte_len);
if (ret) {
mlog_errno(ret);
goto out;
}

cpos = trunc_start;
while (trunc_len) {
ret = ocfs2_get_clusters(inode, cpos, &phys_cpos,
&alloc_size, &flags);
path = ocfs2_new_path_from_et(&et);
if (!path) {
ret = -ENOMEM;
mlog_errno(ret);
goto out;
}

while (trunc_end > trunc_start) {

ret = ocfs2_find_path(INODE_CACHE(inode), path,
cluster_in_el);
if (ret) {
mlog_errno(ret);
goto out;
}

if (alloc_size > trunc_len)
alloc_size = trunc_len;
el = path_leaf_el(path);

i = ocfs2_find_rec(el, trunc_end);
/*
* Need to go to previous extent block.
*/
if (i < 0) {
if (path->p_tree_depth == 0)
break;

/* Only do work for non-holes */
if (phys_cpos != 0) {
ret = ocfs2_remove_btree_range(inode, &et, cpos,
phys_cpos, alloc_size,
flags, &dealloc,
refcount_loc);
ret = ocfs2_find_cpos_for_left_leaf(inode->i_sb,
path,
&cluster_in_el);
if (ret) {
mlog_errno(ret);
goto out;
}

/*
* We've reached the leftmost extent block,
* it's safe to leave.
*/
if (cluster_in_el == 0)
break;

/*
* The 'pos' searched for previous extent block is
* always one cluster less than actual trunc_end.
*/
trunc_end = cluster_in_el + 1;

ocfs2_reinit_path(path, 1);

continue;

} else
rec = &el->l_recs[i];

ocfs2_calc_trunc_pos(inode, el, rec, trunc_start, &trunc_cpos,
&trunc_len, &trunc_end, &blkno, &done);
if (done)
break;

flags = rec->e_flags;
phys_cpos = ocfs2_blocks_to_clusters(inode->i_sb, blkno);

ret = ocfs2_remove_btree_range(inode, &et, trunc_cpos,
phys_cpos, trunc_len, flags,
&dealloc, refcount_loc);
if (ret < 0) {
mlog_errno(ret);
goto out;
}

cpos += alloc_size;
trunc_len -= alloc_size;
cluster_in_el = trunc_end;

ocfs2_reinit_path(path, 1);
}

ocfs2_truncate_cluster_pages(inode, byte_start, byte_len);
Expand Down

0 comments on commit 7a5dbb0

Please sign in to comment.