Skip to content

Commit

Permalink
ocfs2: Call refcount tree remove process properly.
Browse files Browse the repository at this point in the history
Now with xattr refcount support, we need to check whether
we have xattr refcounted before we remove the refcount tree.

Now the mechanism is:
1) Check whether i_clusters == 0, if no, exit.
2) check whether we have i_xattr_loc in dinode. if yes, exit.
2) Check whether we have inline xattr stored outside, if yes, exit.
4) Remove the tree.

Signed-off-by: Tao Ma <tao.ma@oracle.com>
  • Loading branch information
Tao Ma authored and Joel Becker committed Sep 23, 2009
1 parent 0129241 commit 8b2c0db
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 0 deletions.
2 changes: 2 additions & 0 deletions fs/ocfs2/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,8 @@ static int ocfs2_truncate_file(struct inode *inode,
up_write(&OCFS2_I(inode)->ip_alloc_sem);

bail:
if (!status && OCFS2_I(inode)->ip_clusters == 0)
status = ocfs2_try_remove_refcount_tree(inode, di_bh);

mlog_exit(status);
return status;
Expand Down
7 changes: 7 additions & 0 deletions fs/ocfs2/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
#include "sysfile.h"
#include "uptodate.h"
#include "xattr.h"
#include "refcounttree.h"

#include "buffer_head_io.h"

Expand Down Expand Up @@ -782,6 +783,12 @@ static int ocfs2_wipe_inode(struct inode *inode,
goto bail_unlock_dir;
}

status = ocfs2_remove_refcount_tree(inode, di_bh);
if (status < 0) {
mlog_errno(status);
goto bail_unlock_dir;
}

status = ocfs2_remove_inode(inode, di_bh, orphan_dir_inode,
orphan_dir_bh);
if (status < 0)
Expand Down
36 changes: 36 additions & 0 deletions fs/ocfs2/refcounttree.c
Original file line number Diff line number Diff line change
Expand Up @@ -926,6 +926,42 @@ static void ocfs2_find_refcount_rec_in_rl(struct ocfs2_caching_info *ci,
*index = i;
}

/*
* Try to remove refcount tree. The mechanism is:
* 1) Check whether i_clusters == 0, if no, exit.
* 2) check whether we have i_xattr_loc in dinode. if yes, exit.
* 3) Check whether we have inline xattr stored outside, if yes, exit.
* 4) Remove the tree.
*/
int ocfs2_try_remove_refcount_tree(struct inode *inode,
struct buffer_head *di_bh)
{
int ret;
struct ocfs2_inode_info *oi = OCFS2_I(inode);
struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;

down_write(&oi->ip_xattr_sem);
down_write(&oi->ip_alloc_sem);

if (oi->ip_clusters)
goto out;

if ((oi->ip_dyn_features & OCFS2_HAS_XATTR_FL) && di->i_xattr_loc)
goto out;

if (oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL &&
ocfs2_has_inline_xattr_value_outside(inode, di))
goto out;

ret = ocfs2_remove_refcount_tree(inode, di_bh);
if (ret)
mlog_errno(ret);
out:
up_write(&oi->ip_alloc_sem);
up_write(&oi->ip_xattr_sem);
return 0;
}

/*
* Given a cpos and len, try to find the refcount record which contains cpos.
* 1. If cpos can be found in one refcount record, return the record.
Expand Down
3 changes: 3 additions & 0 deletions fs/ocfs2/refcounttree.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,7 @@ int ocfs2_add_refcount_flag(struct inode *inode,
u32 cpos, u32 p_cluster, u32 num_clusters,
struct ocfs2_cached_dealloc_ctxt *dealloc,
struct ocfs2_post_refcount *post);
int ocfs2_remove_refcount_tree(struct inode *inode, struct buffer_head *di_bh);
int ocfs2_try_remove_refcount_tree(struct inode *inode,
struct buffer_head *di_bh);
#endif /* OCFS2_REFCOUNTTREE_H */
23 changes: 23 additions & 0 deletions fs/ocfs2/xattr.c
Original file line number Diff line number Diff line change
Expand Up @@ -840,6 +840,23 @@ static int ocfs2_xattr_list_entries(struct inode *inode,
return result;
}

int ocfs2_has_inline_xattr_value_outside(struct inode *inode,
struct ocfs2_dinode *di)
{
struct ocfs2_xattr_header *xh;
int i;

xh = (struct ocfs2_xattr_header *)
((void *)di + inode->i_sb->s_blocksize -
le16_to_cpu(di->i_xattr_inline_size));

for (i = 0; i < le16_to_cpu(xh->xh_count); i++)
if (!ocfs2_xattr_is_local(&xh->xh_entries[i]))
return 1;

return 0;
}

static int ocfs2_xattr_ibody_list(struct inode *inode,
struct ocfs2_dinode *di,
char *buffer,
Expand Down Expand Up @@ -2898,10 +2915,16 @@ int ocfs2_xattr_set(struct inode *inode,
if (ocfs2_dealloc_has_cluster(&ctxt.dealloc))
ocfs2_schedule_truncate_log_flush(osb, 1);
ocfs2_run_deallocs(osb, &ctxt.dealloc);

cleanup:
if (ref_tree)
ocfs2_unlock_refcount_tree(osb, ref_tree, 1);
up_write(&OCFS2_I(inode)->ip_xattr_sem);
if (!value && !ret) {
ret = ocfs2_try_remove_refcount_tree(inode, di_bh);
if (ret)
mlog_errno(ret);
}
ocfs2_inode_unlock(inode, 1);
cleanup_nolock:
brelse(di_bh);
Expand Down
2 changes: 2 additions & 0 deletions fs/ocfs2/xattr.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ int ocfs2_xattr_set_handle(handle_t *, struct inode *, struct buffer_head *,
int, const char *, const void *, size_t, int,
struct ocfs2_alloc_context *,
struct ocfs2_alloc_context *);
int ocfs2_has_inline_xattr_value_outside(struct inode *inode,
struct ocfs2_dinode *di);
int ocfs2_xattr_remove(struct inode *, struct buffer_head *);
int ocfs2_init_security_get(struct inode *, struct inode *,
struct ocfs2_security_xattr_info *);
Expand Down

0 comments on commit 8b2c0db

Please sign in to comment.