diff options
Diffstat (limited to 'fs/ocfs2')
-rw-r--r-- | fs/ocfs2/move_extents.c | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/fs/ocfs2/move_extents.c b/fs/ocfs2/move_extents.c index e5ce1495dc77..d1bd5a347e9c 100644 --- a/fs/ocfs2/move_extents.c +++ b/fs/ocfs2/move_extents.c | |||
@@ -55,6 +55,106 @@ struct ocfs2_move_extents_context { | |||
55 | struct ocfs2_cached_dealloc_ctxt dealloc; | 55 | struct ocfs2_cached_dealloc_ctxt dealloc; |
56 | }; | 56 | }; |
57 | 57 | ||
58 | static int __ocfs2_move_extent(handle_t *handle, | ||
59 | struct ocfs2_move_extents_context *context, | ||
60 | u32 cpos, u32 len, u32 p_cpos, u32 new_p_cpos, | ||
61 | int ext_flags) | ||
62 | { | ||
63 | int ret = 0, index; | ||
64 | struct inode *inode = context->inode; | ||
65 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
66 | struct ocfs2_extent_rec *rec, replace_rec; | ||
67 | struct ocfs2_path *path = NULL; | ||
68 | struct ocfs2_extent_list *el; | ||
69 | u64 ino = ocfs2_metadata_cache_owner(context->et.et_ci); | ||
70 | u64 old_blkno = ocfs2_clusters_to_blocks(inode->i_sb, p_cpos); | ||
71 | |||
72 | ret = ocfs2_duplicate_clusters_by_page(handle, context->file, cpos, | ||
73 | p_cpos, new_p_cpos, len); | ||
74 | if (ret) { | ||
75 | mlog_errno(ret); | ||
76 | goto out; | ||
77 | } | ||
78 | |||
79 | memset(&replace_rec, 0, sizeof(replace_rec)); | ||
80 | replace_rec.e_cpos = cpu_to_le32(cpos); | ||
81 | replace_rec.e_leaf_clusters = cpu_to_le16(len); | ||
82 | replace_rec.e_blkno = cpu_to_le64(ocfs2_clusters_to_blocks(inode->i_sb, | ||
83 | new_p_cpos)); | ||
84 | |||
85 | path = ocfs2_new_path_from_et(&context->et); | ||
86 | if (!path) { | ||
87 | ret = -ENOMEM; | ||
88 | mlog_errno(ret); | ||
89 | goto out; | ||
90 | } | ||
91 | |||
92 | ret = ocfs2_find_path(INODE_CACHE(inode), path, cpos); | ||
93 | if (ret) { | ||
94 | mlog_errno(ret); | ||
95 | goto out; | ||
96 | } | ||
97 | |||
98 | el = path_leaf_el(path); | ||
99 | |||
100 | index = ocfs2_search_extent_list(el, cpos); | ||
101 | if (index == -1 || index >= le16_to_cpu(el->l_next_free_rec)) { | ||
102 | ocfs2_error(inode->i_sb, | ||
103 | "Inode %llu has an extent at cpos %u which can no " | ||
104 | "longer be found.\n", | ||
105 | (unsigned long long)ino, cpos); | ||
106 | ret = -EROFS; | ||
107 | goto out; | ||
108 | } | ||
109 | |||
110 | rec = &el->l_recs[index]; | ||
111 | |||
112 | BUG_ON(ext_flags != rec->e_flags); | ||
113 | /* | ||
114 | * after moving/defraging to new location, the extent is not going | ||
115 | * to be refcounted anymore. | ||
116 | */ | ||
117 | replace_rec.e_flags = ext_flags & ~OCFS2_EXT_REFCOUNTED; | ||
118 | |||
119 | ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), | ||
120 | context->et.et_root_bh, | ||
121 | OCFS2_JOURNAL_ACCESS_WRITE); | ||
122 | if (ret) { | ||
123 | mlog_errno(ret); | ||
124 | goto out; | ||
125 | } | ||
126 | |||
127 | ret = ocfs2_split_extent(handle, &context->et, path, index, | ||
128 | &replace_rec, context->meta_ac, | ||
129 | &context->dealloc); | ||
130 | if (ret) { | ||
131 | mlog_errno(ret); | ||
132 | goto out; | ||
133 | } | ||
134 | |||
135 | ocfs2_journal_dirty(handle, context->et.et_root_bh); | ||
136 | |||
137 | context->new_phys_cpos = new_p_cpos; | ||
138 | |||
139 | /* | ||
140 | * need I to append truncate log for old clusters? | ||
141 | */ | ||
142 | if (old_blkno) { | ||
143 | if (ext_flags & OCFS2_EXT_REFCOUNTED) | ||
144 | ret = ocfs2_decrease_refcount(inode, handle, | ||
145 | ocfs2_blocks_to_clusters(osb->sb, | ||
146 | old_blkno), | ||
147 | len, context->meta_ac, | ||
148 | &context->dealloc, 1); | ||
149 | else | ||
150 | ret = ocfs2_truncate_log_append(osb, handle, | ||
151 | old_blkno, len); | ||
152 | } | ||
153 | |||
154 | out: | ||
155 | return ret; | ||
156 | } | ||
157 | |||
58 | /* | 158 | /* |
59 | * lock allocators, and reserving appropriate number of bits for | 159 | * lock allocators, and reserving appropriate number of bits for |
60 | * meta blocks and data clusters. | 160 | * meta blocks and data clusters. |