mirror of
https://github.com/adulau/aha.git
synced 2024-12-27 19:26:25 +00:00
Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jlbec/ocfs2
* 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jlbec/ocfs2: ocfs2: Set i_nlink properly during reflink. ocfs2: Add reflinked file's inode to inode hash eariler. ocfs2: refcounttree.c cleanup. ocfs2: Find proper end cpos for a leaf refcount block.
This commit is contained in:
commit
849254e9bb
4 changed files with 131 additions and 39 deletions
|
@ -1765,9 +1765,9 @@ set_and_inc:
|
||||||
*
|
*
|
||||||
* The array index of the subtree root is passed back.
|
* The array index of the subtree root is passed back.
|
||||||
*/
|
*/
|
||||||
static int ocfs2_find_subtree_root(struct ocfs2_extent_tree *et,
|
int ocfs2_find_subtree_root(struct ocfs2_extent_tree *et,
|
||||||
struct ocfs2_path *left,
|
struct ocfs2_path *left,
|
||||||
struct ocfs2_path *right)
|
struct ocfs2_path *right)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
|
@ -2872,8 +2872,8 @@ out:
|
||||||
* This looks similar, but is subtly different to
|
* This looks similar, but is subtly different to
|
||||||
* ocfs2_find_cpos_for_left_leaf().
|
* ocfs2_find_cpos_for_left_leaf().
|
||||||
*/
|
*/
|
||||||
static int ocfs2_find_cpos_for_right_leaf(struct super_block *sb,
|
int ocfs2_find_cpos_for_right_leaf(struct super_block *sb,
|
||||||
struct ocfs2_path *path, u32 *cpos)
|
struct ocfs2_path *path, u32 *cpos)
|
||||||
{
|
{
|
||||||
int i, j, ret = 0;
|
int i, j, ret = 0;
|
||||||
u64 blkno;
|
u64 blkno;
|
||||||
|
|
|
@ -317,4 +317,9 @@ int ocfs2_path_bh_journal_access(handle_t *handle,
|
||||||
int ocfs2_journal_access_path(struct ocfs2_caching_info *ci,
|
int ocfs2_journal_access_path(struct ocfs2_caching_info *ci,
|
||||||
handle_t *handle,
|
handle_t *handle,
|
||||||
struct ocfs2_path *path);
|
struct ocfs2_path *path);
|
||||||
|
int ocfs2_find_cpos_for_right_leaf(struct super_block *sb,
|
||||||
|
struct ocfs2_path *path, u32 *cpos);
|
||||||
|
int ocfs2_find_subtree_root(struct ocfs2_extent_tree *et,
|
||||||
|
struct ocfs2_path *left,
|
||||||
|
struct ocfs2_path *right);
|
||||||
#endif /* OCFS2_ALLOC_H */
|
#endif /* OCFS2_ALLOC_H */
|
||||||
|
|
|
@ -2108,6 +2108,7 @@ int ocfs2_create_inode_in_orphan(struct inode *dir,
|
||||||
}
|
}
|
||||||
did_quota_inode = 1;
|
did_quota_inode = 1;
|
||||||
|
|
||||||
|
inode->i_nlink = 0;
|
||||||
/* do the real work now. */
|
/* do the real work now. */
|
||||||
status = ocfs2_mknod_locked(osb, dir, inode,
|
status = ocfs2_mknod_locked(osb, dir, inode,
|
||||||
0, &new_di_bh, parent_di_bh, handle,
|
0, &new_di_bh, parent_di_bh, handle,
|
||||||
|
@ -2136,6 +2137,7 @@ int ocfs2_create_inode_in_orphan(struct inode *dir,
|
||||||
if (status < 0)
|
if (status < 0)
|
||||||
mlog_errno(status);
|
mlog_errno(status);
|
||||||
|
|
||||||
|
insert_inode_hash(inode);
|
||||||
leave:
|
leave:
|
||||||
if (status < 0 && did_quota_inode)
|
if (status < 0 && did_quota_inode)
|
||||||
vfs_dq_free_inode(inode);
|
vfs_dq_free_inode(inode);
|
||||||
|
@ -2267,6 +2269,8 @@ int ocfs2_mv_orphaned_inode_to_new(struct inode *dir,
|
||||||
di = (struct ocfs2_dinode *)di_bh->b_data;
|
di = (struct ocfs2_dinode *)di_bh->b_data;
|
||||||
le32_add_cpu(&di->i_flags, -OCFS2_ORPHANED_FL);
|
le32_add_cpu(&di->i_flags, -OCFS2_ORPHANED_FL);
|
||||||
di->i_orphaned_slot = 0;
|
di->i_orphaned_slot = 0;
|
||||||
|
inode->i_nlink = 1;
|
||||||
|
ocfs2_set_links_count(di, inode->i_nlink);
|
||||||
ocfs2_journal_dirty(handle, di_bh);
|
ocfs2_journal_dirty(handle, di_bh);
|
||||||
|
|
||||||
status = ocfs2_add_entry(handle, dentry, inode,
|
status = ocfs2_add_entry(handle, dentry, inode,
|
||||||
|
@ -2284,7 +2288,6 @@ int ocfs2_mv_orphaned_inode_to_new(struct inode *dir,
|
||||||
goto out_commit;
|
goto out_commit;
|
||||||
}
|
}
|
||||||
|
|
||||||
insert_inode_hash(inode);
|
|
||||||
dentry->d_op = &ocfs2_dentry_ops;
|
dentry->d_op = &ocfs2_dentry_ops;
|
||||||
d_instantiate(dentry, inode);
|
d_instantiate(dentry, inode);
|
||||||
status = 0;
|
status = 0;
|
||||||
|
|
|
@ -276,7 +276,7 @@ static void ocfs2_erase_refcount_tree_from_list(struct ocfs2_super *osb,
|
||||||
spin_unlock(&osb->osb_lock);
|
spin_unlock(&osb->osb_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ocfs2_kref_remove_refcount_tree(struct kref *kref)
|
static void ocfs2_kref_remove_refcount_tree(struct kref *kref)
|
||||||
{
|
{
|
||||||
struct ocfs2_refcount_tree *tree =
|
struct ocfs2_refcount_tree *tree =
|
||||||
container_of(kref, struct ocfs2_refcount_tree, rf_getcnt);
|
container_of(kref, struct ocfs2_refcount_tree, rf_getcnt);
|
||||||
|
@ -524,23 +524,6 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ocfs2_lock_refcount_tree_by_inode(struct inode *inode, int rw,
|
|
||||||
struct ocfs2_refcount_tree **ret_tree,
|
|
||||||
struct buffer_head **ref_bh)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
u64 ref_blkno;
|
|
||||||
|
|
||||||
ret = ocfs2_get_refcount_block(inode, &ref_blkno);
|
|
||||||
if (ret) {
|
|
||||||
mlog_errno(ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ocfs2_lock_refcount_tree(OCFS2_SB(inode->i_sb), ref_blkno,
|
|
||||||
rw, ret_tree, ref_bh);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ocfs2_unlock_refcount_tree(struct ocfs2_super *osb,
|
void ocfs2_unlock_refcount_tree(struct ocfs2_super *osb,
|
||||||
struct ocfs2_refcount_tree *tree, int rw)
|
struct ocfs2_refcount_tree *tree, int rw)
|
||||||
{
|
{
|
||||||
|
@ -968,6 +951,103 @@ out:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find the end range for a leaf refcount block indicated by
|
||||||
|
* el->l_recs[index].e_blkno.
|
||||||
|
*/
|
||||||
|
static int ocfs2_get_refcount_cpos_end(struct ocfs2_caching_info *ci,
|
||||||
|
struct buffer_head *ref_root_bh,
|
||||||
|
struct ocfs2_extent_block *eb,
|
||||||
|
struct ocfs2_extent_list *el,
|
||||||
|
int index, u32 *cpos_end)
|
||||||
|
{
|
||||||
|
int ret, i, subtree_root;
|
||||||
|
u32 cpos;
|
||||||
|
u64 blkno;
|
||||||
|
struct super_block *sb = ocfs2_metadata_cache_get_super(ci);
|
||||||
|
struct ocfs2_path *left_path = NULL, *right_path = NULL;
|
||||||
|
struct ocfs2_extent_tree et;
|
||||||
|
struct ocfs2_extent_list *tmp_el;
|
||||||
|
|
||||||
|
if (index < le16_to_cpu(el->l_next_free_rec) - 1) {
|
||||||
|
/*
|
||||||
|
* We have a extent rec after index, so just use the e_cpos
|
||||||
|
* of the next extent rec.
|
||||||
|
*/
|
||||||
|
*cpos_end = le32_to_cpu(el->l_recs[index+1].e_cpos);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!eb || (eb && !eb->h_next_leaf_blk)) {
|
||||||
|
/*
|
||||||
|
* We are the last extent rec, so any high cpos should
|
||||||
|
* be stored in this leaf refcount block.
|
||||||
|
*/
|
||||||
|
*cpos_end = UINT_MAX;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the extent block isn't the last one, we have to find
|
||||||
|
* the subtree root between this extent block and the next
|
||||||
|
* leaf extent block and get the corresponding e_cpos from
|
||||||
|
* the subroot. Otherwise we may corrupt the b-tree.
|
||||||
|
*/
|
||||||
|
ocfs2_init_refcount_extent_tree(&et, ci, ref_root_bh);
|
||||||
|
|
||||||
|
left_path = ocfs2_new_path_from_et(&et);
|
||||||
|
if (!left_path) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
mlog_errno(ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
cpos = le32_to_cpu(eb->h_list.l_recs[index].e_cpos);
|
||||||
|
ret = ocfs2_find_path(ci, left_path, cpos);
|
||||||
|
if (ret) {
|
||||||
|
mlog_errno(ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
right_path = ocfs2_new_path_from_path(left_path);
|
||||||
|
if (!right_path) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
mlog_errno(ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ocfs2_find_cpos_for_right_leaf(sb, left_path, &cpos);
|
||||||
|
if (ret) {
|
||||||
|
mlog_errno(ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ocfs2_find_path(ci, right_path, cpos);
|
||||||
|
if (ret) {
|
||||||
|
mlog_errno(ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
subtree_root = ocfs2_find_subtree_root(&et, left_path,
|
||||||
|
right_path);
|
||||||
|
|
||||||
|
tmp_el = left_path->p_node[subtree_root].el;
|
||||||
|
blkno = left_path->p_node[subtree_root+1].bh->b_blocknr;
|
||||||
|
for (i = 0; i < le32_to_cpu(tmp_el->l_next_free_rec); i++) {
|
||||||
|
if (le64_to_cpu(tmp_el->l_recs[i].e_blkno) == blkno) {
|
||||||
|
*cpos_end = le32_to_cpu(tmp_el->l_recs[i+1].e_cpos);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BUG_ON(i == le32_to_cpu(tmp_el->l_next_free_rec));
|
||||||
|
|
||||||
|
out:
|
||||||
|
ocfs2_free_path(left_path);
|
||||||
|
ocfs2_free_path(right_path);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Given a cpos and len, try to find the refcount record which contains cpos.
|
* 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.
|
* 1. If cpos can be found in one refcount record, return the record.
|
||||||
|
@ -983,10 +1063,10 @@ static int ocfs2_get_refcount_rec(struct ocfs2_caching_info *ci,
|
||||||
struct buffer_head **ret_bh)
|
struct buffer_head **ret_bh)
|
||||||
{
|
{
|
||||||
int ret = 0, i, found;
|
int ret = 0, i, found;
|
||||||
u32 low_cpos;
|
u32 low_cpos, uninitialized_var(cpos_end);
|
||||||
struct ocfs2_extent_list *el;
|
struct ocfs2_extent_list *el;
|
||||||
struct ocfs2_extent_rec *tmp, *rec = NULL;
|
struct ocfs2_extent_rec *rec = NULL;
|
||||||
struct ocfs2_extent_block *eb;
|
struct ocfs2_extent_block *eb = NULL;
|
||||||
struct buffer_head *eb_bh = NULL, *ref_leaf_bh = NULL;
|
struct buffer_head *eb_bh = NULL, *ref_leaf_bh = NULL;
|
||||||
struct super_block *sb = ocfs2_metadata_cache_get_super(ci);
|
struct super_block *sb = ocfs2_metadata_cache_get_super(ci);
|
||||||
struct ocfs2_refcount_block *rb =
|
struct ocfs2_refcount_block *rb =
|
||||||
|
@ -1034,12 +1114,16 @@ static int ocfs2_get_refcount_rec(struct ocfs2_caching_info *ci,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* adjust len when we have ocfs2_extent_rec after it. */
|
if (found) {
|
||||||
if (found && i < le16_to_cpu(el->l_next_free_rec) - 1) {
|
ret = ocfs2_get_refcount_cpos_end(ci, ref_root_bh,
|
||||||
tmp = &el->l_recs[i+1];
|
eb, el, i, &cpos_end);
|
||||||
|
if (ret) {
|
||||||
|
mlog_errno(ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (le32_to_cpu(tmp->e_cpos) < cpos + len)
|
if (cpos_end < low_cpos + len)
|
||||||
len = le32_to_cpu(tmp->e_cpos) - cpos;
|
len = cpos_end - low_cpos;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = ocfs2_read_refcount_block(ci, le64_to_cpu(rec->e_blkno),
|
ret = ocfs2_read_refcount_block(ci, le64_to_cpu(rec->e_blkno),
|
||||||
|
@ -1418,7 +1502,7 @@ static int ocfs2_divide_leaf_refcount_block(struct buffer_head *ref_leaf_bh,
|
||||||
|
|
||||||
/* change old and new rl_used accordingly. */
|
/* change old and new rl_used accordingly. */
|
||||||
le16_add_cpu(&rl->rl_used, -num_moved);
|
le16_add_cpu(&rl->rl_used, -num_moved);
|
||||||
new_rl->rl_used = cpu_to_le32(num_moved);
|
new_rl->rl_used = cpu_to_le16(num_moved);
|
||||||
|
|
||||||
sort(&rl->rl_recs, le16_to_cpu(rl->rl_used),
|
sort(&rl->rl_recs, le16_to_cpu(rl->rl_used),
|
||||||
sizeof(struct ocfs2_refcount_rec),
|
sizeof(struct ocfs2_refcount_rec),
|
||||||
|
@ -1797,7 +1881,8 @@ static int ocfs2_split_refcount_rec(handle_t *handle,
|
||||||
recs_need++;
|
recs_need++;
|
||||||
|
|
||||||
/* If the leaf block don't have enough record, expand it. */
|
/* If the leaf block don't have enough record, expand it. */
|
||||||
if (le16_to_cpu(rf_list->rl_used) + recs_need > rf_list->rl_count) {
|
if (le16_to_cpu(rf_list->rl_used) + recs_need >
|
||||||
|
le16_to_cpu(rf_list->rl_count)) {
|
||||||
struct ocfs2_refcount_rec tmp_rec;
|
struct ocfs2_refcount_rec tmp_rec;
|
||||||
u64 cpos = le64_to_cpu(orig_rec->r_cpos);
|
u64 cpos = le64_to_cpu(orig_rec->r_cpos);
|
||||||
len = le32_to_cpu(orig_rec->r_clusters);
|
len = le32_to_cpu(orig_rec->r_clusters);
|
||||||
|
@ -1859,7 +1944,7 @@ static int ocfs2_split_refcount_rec(handle_t *handle,
|
||||||
memcpy(tail_rec, orig_rec, sizeof(struct ocfs2_refcount_rec));
|
memcpy(tail_rec, orig_rec, sizeof(struct ocfs2_refcount_rec));
|
||||||
le64_add_cpu(&tail_rec->r_cpos,
|
le64_add_cpu(&tail_rec->r_cpos,
|
||||||
le32_to_cpu(tail_rec->r_clusters) - len);
|
le32_to_cpu(tail_rec->r_clusters) - len);
|
||||||
tail_rec->r_clusters = le32_to_cpu(len);
|
tail_rec->r_clusters = cpu_to_le32(len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -3840,8 +3925,7 @@ static int ocfs2_add_refcounted_extent(struct inode *inode,
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = ocfs2_insert_extent(handle, et, cpos,
|
ret = ocfs2_insert_extent(handle, et, cpos,
|
||||||
cpu_to_le64(ocfs2_clusters_to_blocks(inode->i_sb,
|
ocfs2_clusters_to_blocks(inode->i_sb, p_cluster),
|
||||||
p_cluster)),
|
|
||||||
num_clusters, ext_flags, meta_ac);
|
num_clusters, ext_flags, meta_ac);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
mlog_errno(ret);
|
mlog_errno(ret);
|
||||||
|
@ -4253,8 +4337,8 @@ static int ocfs2_user_path_parent(const char __user *path,
|
||||||
* @new_dentry: target dentry
|
* @new_dentry: target dentry
|
||||||
* @preserve: if true, preserve all file attributes
|
* @preserve: if true, preserve all file attributes
|
||||||
*/
|
*/
|
||||||
int ocfs2_vfs_reflink(struct dentry *old_dentry, struct inode *dir,
|
static int ocfs2_vfs_reflink(struct dentry *old_dentry, struct inode *dir,
|
||||||
struct dentry *new_dentry, bool preserve)
|
struct dentry *new_dentry, bool preserve)
|
||||||
{
|
{
|
||||||
struct inode *inode = old_dentry->d_inode;
|
struct inode *inode = old_dentry->d_inode;
|
||||||
int error;
|
int error;
|
||||||
|
|
Loading…
Reference in a new issue