xref: /openbmc/linux/fs/ocfs2/move_extents.c (revision 99e4c750)
1028ba5dfSTristan Ye /* -*- mode: c; c-basic-offset: 8; -*-
2028ba5dfSTristan Ye  * vim: noexpandtab sw=8 ts=8 sts=0:
3028ba5dfSTristan Ye  *
4028ba5dfSTristan Ye  * move_extents.c
5028ba5dfSTristan Ye  *
6028ba5dfSTristan Ye  * Copyright (C) 2011 Oracle.  All rights reserved.
7028ba5dfSTristan Ye  *
8028ba5dfSTristan Ye  * This program is free software; you can redistribute it and/or
9028ba5dfSTristan Ye  * modify it under the terms of the GNU General Public
10028ba5dfSTristan Ye  * License version 2 as published by the Free Software Foundation.
11028ba5dfSTristan Ye  *
12028ba5dfSTristan Ye  * This program is distributed in the hope that it will be useful,
13028ba5dfSTristan Ye  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14028ba5dfSTristan Ye  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15028ba5dfSTristan Ye  * General Public License for more details.
16028ba5dfSTristan Ye  */
17028ba5dfSTristan Ye #include <linux/fs.h>
18028ba5dfSTristan Ye #include <linux/types.h>
19028ba5dfSTristan Ye #include <linux/mount.h>
20028ba5dfSTristan Ye #include <linux/swap.h>
21028ba5dfSTristan Ye 
22028ba5dfSTristan Ye #include <cluster/masklog.h>
23028ba5dfSTristan Ye 
24028ba5dfSTristan Ye #include "ocfs2.h"
25028ba5dfSTristan Ye #include "ocfs2_ioctl.h"
26028ba5dfSTristan Ye 
27028ba5dfSTristan Ye #include "alloc.h"
28028ba5dfSTristan Ye #include "aops.h"
29028ba5dfSTristan Ye #include "dlmglue.h"
30028ba5dfSTristan Ye #include "extent_map.h"
31028ba5dfSTristan Ye #include "inode.h"
32028ba5dfSTristan Ye #include "journal.h"
33028ba5dfSTristan Ye #include "suballoc.h"
34028ba5dfSTristan Ye #include "uptodate.h"
35028ba5dfSTristan Ye #include "super.h"
36028ba5dfSTristan Ye #include "dir.h"
37028ba5dfSTristan Ye #include "buffer_head_io.h"
38028ba5dfSTristan Ye #include "sysfile.h"
39028ba5dfSTristan Ye #include "suballoc.h"
40028ba5dfSTristan Ye #include "refcounttree.h"
41028ba5dfSTristan Ye #include "move_extents.h"
42028ba5dfSTristan Ye 
43028ba5dfSTristan Ye struct ocfs2_move_extents_context {
44028ba5dfSTristan Ye 	struct inode *inode;
45028ba5dfSTristan Ye 	struct file *file;
46028ba5dfSTristan Ye 	int auto_defrag;
47028ba5dfSTristan Ye 	int credits;
48028ba5dfSTristan Ye 	u32 new_phys_cpos;
49028ba5dfSTristan Ye 	u32 clusters_moved;
50028ba5dfSTristan Ye 	u64 refcount_loc;
51028ba5dfSTristan Ye 	struct ocfs2_move_extents *range;
52028ba5dfSTristan Ye 	struct ocfs2_extent_tree et;
53028ba5dfSTristan Ye 	struct ocfs2_alloc_context *meta_ac;
54028ba5dfSTristan Ye 	struct ocfs2_alloc_context *data_ac;
55028ba5dfSTristan Ye 	struct ocfs2_cached_dealloc_ctxt dealloc;
56028ba5dfSTristan Ye };
57de474ee8STristan Ye 
588f603e56STristan Ye static int __ocfs2_move_extent(handle_t *handle,
598f603e56STristan Ye 			       struct ocfs2_move_extents_context *context,
608f603e56STristan Ye 			       u32 cpos, u32 len, u32 p_cpos, u32 new_p_cpos,
618f603e56STristan Ye 			       int ext_flags)
628f603e56STristan Ye {
638f603e56STristan Ye 	int ret = 0, index;
648f603e56STristan Ye 	struct inode *inode = context->inode;
658f603e56STristan Ye 	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
668f603e56STristan Ye 	struct ocfs2_extent_rec *rec, replace_rec;
678f603e56STristan Ye 	struct ocfs2_path *path = NULL;
688f603e56STristan Ye 	struct ocfs2_extent_list *el;
698f603e56STristan Ye 	u64 ino = ocfs2_metadata_cache_owner(context->et.et_ci);
708f603e56STristan Ye 	u64 old_blkno = ocfs2_clusters_to_blocks(inode->i_sb, p_cpos);
718f603e56STristan Ye 
728f603e56STristan Ye 	ret = ocfs2_duplicate_clusters_by_page(handle, context->file, cpos,
738f603e56STristan Ye 					       p_cpos, new_p_cpos, len);
748f603e56STristan Ye 	if (ret) {
758f603e56STristan Ye 		mlog_errno(ret);
768f603e56STristan Ye 		goto out;
778f603e56STristan Ye 	}
788f603e56STristan Ye 
798f603e56STristan Ye 	memset(&replace_rec, 0, sizeof(replace_rec));
808f603e56STristan Ye 	replace_rec.e_cpos = cpu_to_le32(cpos);
818f603e56STristan Ye 	replace_rec.e_leaf_clusters = cpu_to_le16(len);
828f603e56STristan Ye 	replace_rec.e_blkno = cpu_to_le64(ocfs2_clusters_to_blocks(inode->i_sb,
838f603e56STristan Ye 								   new_p_cpos));
848f603e56STristan Ye 
858f603e56STristan Ye 	path = ocfs2_new_path_from_et(&context->et);
868f603e56STristan Ye 	if (!path) {
878f603e56STristan Ye 		ret = -ENOMEM;
888f603e56STristan Ye 		mlog_errno(ret);
898f603e56STristan Ye 		goto out;
908f603e56STristan Ye 	}
918f603e56STristan Ye 
928f603e56STristan Ye 	ret = ocfs2_find_path(INODE_CACHE(inode), path, cpos);
938f603e56STristan Ye 	if (ret) {
948f603e56STristan Ye 		mlog_errno(ret);
958f603e56STristan Ye 		goto out;
968f603e56STristan Ye 	}
978f603e56STristan Ye 
988f603e56STristan Ye 	el = path_leaf_el(path);
998f603e56STristan Ye 
1008f603e56STristan Ye 	index = ocfs2_search_extent_list(el, cpos);
1018f603e56STristan Ye 	if (index == -1 || index >= le16_to_cpu(el->l_next_free_rec)) {
1028f603e56STristan Ye 		ocfs2_error(inode->i_sb,
1038f603e56STristan Ye 			    "Inode %llu has an extent at cpos %u which can no "
1048f603e56STristan Ye 			    "longer be found.\n",
1058f603e56STristan Ye 			    (unsigned long long)ino, cpos);
1068f603e56STristan Ye 		ret = -EROFS;
1078f603e56STristan Ye 		goto out;
1088f603e56STristan Ye 	}
1098f603e56STristan Ye 
1108f603e56STristan Ye 	rec = &el->l_recs[index];
1118f603e56STristan Ye 
1128f603e56STristan Ye 	BUG_ON(ext_flags != rec->e_flags);
1138f603e56STristan Ye 	/*
1148f603e56STristan Ye 	 * after moving/defraging to new location, the extent is not going
1158f603e56STristan Ye 	 * to be refcounted anymore.
1168f603e56STristan Ye 	 */
1178f603e56STristan Ye 	replace_rec.e_flags = ext_flags & ~OCFS2_EXT_REFCOUNTED;
1188f603e56STristan Ye 
1198f603e56STristan Ye 	ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode),
1208f603e56STristan Ye 				      context->et.et_root_bh,
1218f603e56STristan Ye 				      OCFS2_JOURNAL_ACCESS_WRITE);
1228f603e56STristan Ye 	if (ret) {
1238f603e56STristan Ye 		mlog_errno(ret);
1248f603e56STristan Ye 		goto out;
1258f603e56STristan Ye 	}
1268f603e56STristan Ye 
1278f603e56STristan Ye 	ret = ocfs2_split_extent(handle, &context->et, path, index,
1288f603e56STristan Ye 				 &replace_rec, context->meta_ac,
1298f603e56STristan Ye 				 &context->dealloc);
1308f603e56STristan Ye 	if (ret) {
1318f603e56STristan Ye 		mlog_errno(ret);
1328f603e56STristan Ye 		goto out;
1338f603e56STristan Ye 	}
1348f603e56STristan Ye 
1358f603e56STristan Ye 	ocfs2_journal_dirty(handle, context->et.et_root_bh);
1368f603e56STristan Ye 
1378f603e56STristan Ye 	context->new_phys_cpos = new_p_cpos;
1388f603e56STristan Ye 
1398f603e56STristan Ye 	/*
1408f603e56STristan Ye 	 * need I to append truncate log for old clusters?
1418f603e56STristan Ye 	 */
1428f603e56STristan Ye 	if (old_blkno) {
1438f603e56STristan Ye 		if (ext_flags & OCFS2_EXT_REFCOUNTED)
1448f603e56STristan Ye 			ret = ocfs2_decrease_refcount(inode, handle,
1458f603e56STristan Ye 					ocfs2_blocks_to_clusters(osb->sb,
1468f603e56STristan Ye 								 old_blkno),
1478f603e56STristan Ye 					len, context->meta_ac,
1488f603e56STristan Ye 					&context->dealloc, 1);
1498f603e56STristan Ye 		else
1508f603e56STristan Ye 			ret = ocfs2_truncate_log_append(osb, handle,
1518f603e56STristan Ye 							old_blkno, len);
1528f603e56STristan Ye 	}
1538f603e56STristan Ye 
1548f603e56STristan Ye out:
1558f603e56STristan Ye 	return ret;
1568f603e56STristan Ye }
1578f603e56STristan Ye 
158de474ee8STristan Ye /*
159de474ee8STristan Ye  * lock allocators, and reserving appropriate number of bits for
160de474ee8STristan Ye  * meta blocks and data clusters.
161de474ee8STristan Ye  *
162de474ee8STristan Ye  * in some cases, we don't need to reserve clusters, just let data_ac
163de474ee8STristan Ye  * be NULL.
164de474ee8STristan Ye  */
165de474ee8STristan Ye static int ocfs2_lock_allocators_move_extents(struct inode *inode,
166de474ee8STristan Ye 					struct ocfs2_extent_tree *et,
167de474ee8STristan Ye 					u32 clusters_to_move,
168de474ee8STristan Ye 					u32 extents_to_split,
169de474ee8STristan Ye 					struct ocfs2_alloc_context **meta_ac,
170de474ee8STristan Ye 					struct ocfs2_alloc_context **data_ac,
171de474ee8STristan Ye 					int extra_blocks,
172de474ee8STristan Ye 					int *credits)
173de474ee8STristan Ye {
174de474ee8STristan Ye 	int ret, num_free_extents;
175de474ee8STristan Ye 	unsigned int max_recs_needed = 2 * extents_to_split + clusters_to_move;
176de474ee8STristan Ye 	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
177de474ee8STristan Ye 
178de474ee8STristan Ye 	num_free_extents = ocfs2_num_free_extents(osb, et);
179de474ee8STristan Ye 	if (num_free_extents < 0) {
180de474ee8STristan Ye 		ret = num_free_extents;
181de474ee8STristan Ye 		mlog_errno(ret);
182de474ee8STristan Ye 		goto out;
183de474ee8STristan Ye 	}
184de474ee8STristan Ye 
185de474ee8STristan Ye 	if (!num_free_extents ||
186de474ee8STristan Ye 	    (ocfs2_sparse_alloc(osb) && num_free_extents < max_recs_needed))
187de474ee8STristan Ye 		extra_blocks += ocfs2_extend_meta_needed(et->et_root_el);
188de474ee8STristan Ye 
189de474ee8STristan Ye 	ret = ocfs2_reserve_new_metadata_blocks(osb, extra_blocks, meta_ac);
190de474ee8STristan Ye 	if (ret) {
191de474ee8STristan Ye 		mlog_errno(ret);
192de474ee8STristan Ye 		goto out;
193de474ee8STristan Ye 	}
194de474ee8STristan Ye 
195de474ee8STristan Ye 	if (data_ac) {
196de474ee8STristan Ye 		ret = ocfs2_reserve_clusters(osb, clusters_to_move, data_ac);
197de474ee8STristan Ye 		if (ret) {
198de474ee8STristan Ye 			mlog_errno(ret);
199de474ee8STristan Ye 			goto out;
200de474ee8STristan Ye 		}
201de474ee8STristan Ye 	}
202de474ee8STristan Ye 
203de474ee8STristan Ye 	*credits += ocfs2_calc_extend_credits(osb->sb, et->et_root_el,
204de474ee8STristan Ye 					      clusters_to_move + 2);
205de474ee8STristan Ye 
206de474ee8STristan Ye 	mlog(0, "reserve metadata_blocks: %d, data_clusters: %u, credits: %d\n",
207de474ee8STristan Ye 	     extra_blocks, clusters_to_move, *credits);
208de474ee8STristan Ye out:
209de474ee8STristan Ye 	if (ret) {
210de474ee8STristan Ye 		if (*meta_ac) {
211de474ee8STristan Ye 			ocfs2_free_alloc_context(*meta_ac);
212de474ee8STristan Ye 			*meta_ac = NULL;
213de474ee8STristan Ye 		}
214de474ee8STristan Ye 	}
215de474ee8STristan Ye 
216de474ee8STristan Ye 	return ret;
217de474ee8STristan Ye }
218202ee5faSTristan Ye 
219202ee5faSTristan Ye /*
220202ee5faSTristan Ye  * Using one journal handle to guarantee the data consistency in case
221202ee5faSTristan Ye  * crash happens anywhere.
222202ee5faSTristan Ye  */
223202ee5faSTristan Ye static int ocfs2_defrag_extent(struct ocfs2_move_extents_context *context,
224202ee5faSTristan Ye 			       u32 cpos, u32 phys_cpos, u32 len, int ext_flags)
225202ee5faSTristan Ye {
226202ee5faSTristan Ye 	int ret, credits = 0, extra_blocks = 0;
227202ee5faSTristan Ye 	handle_t *handle;
228202ee5faSTristan Ye 	struct inode *inode = context->inode;
229202ee5faSTristan Ye 	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
230202ee5faSTristan Ye 	struct inode *tl_inode = osb->osb_tl_inode;
231202ee5faSTristan Ye 	struct ocfs2_refcount_tree *ref_tree = NULL;
232202ee5faSTristan Ye 	u32 new_phys_cpos, new_len;
233202ee5faSTristan Ye 	u64 phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos);
234202ee5faSTristan Ye 
235202ee5faSTristan Ye 	if ((ext_flags & OCFS2_EXT_REFCOUNTED) && len) {
236202ee5faSTristan Ye 
237202ee5faSTristan Ye 		BUG_ON(!(OCFS2_I(inode)->ip_dyn_features &
238202ee5faSTristan Ye 			 OCFS2_HAS_REFCOUNT_FL));
239202ee5faSTristan Ye 
240202ee5faSTristan Ye 		BUG_ON(!context->refcount_loc);
241202ee5faSTristan Ye 
242202ee5faSTristan Ye 		ret = ocfs2_lock_refcount_tree(osb, context->refcount_loc, 1,
243202ee5faSTristan Ye 					       &ref_tree, NULL);
244202ee5faSTristan Ye 		if (ret) {
245202ee5faSTristan Ye 			mlog_errno(ret);
246202ee5faSTristan Ye 			return ret;
247202ee5faSTristan Ye 		}
248202ee5faSTristan Ye 
249202ee5faSTristan Ye 		ret = ocfs2_prepare_refcount_change_for_del(inode,
250202ee5faSTristan Ye 							context->refcount_loc,
251202ee5faSTristan Ye 							phys_blkno,
252202ee5faSTristan Ye 							len,
253202ee5faSTristan Ye 							&credits,
254202ee5faSTristan Ye 							&extra_blocks);
255202ee5faSTristan Ye 		if (ret) {
256202ee5faSTristan Ye 			mlog_errno(ret);
257202ee5faSTristan Ye 			goto out;
258202ee5faSTristan Ye 		}
259202ee5faSTristan Ye 	}
260202ee5faSTristan Ye 
261202ee5faSTristan Ye 	ret = ocfs2_lock_allocators_move_extents(inode, &context->et, len, 1,
262202ee5faSTristan Ye 						 &context->meta_ac,
263202ee5faSTristan Ye 						 &context->data_ac,
264202ee5faSTristan Ye 						 extra_blocks, &credits);
265202ee5faSTristan Ye 	if (ret) {
266202ee5faSTristan Ye 		mlog_errno(ret);
267202ee5faSTristan Ye 		goto out;
268202ee5faSTristan Ye 	}
269202ee5faSTristan Ye 
270202ee5faSTristan Ye 	/*
271202ee5faSTristan Ye 	 * should be using allocation reservation strategy there?
272202ee5faSTristan Ye 	 *
273202ee5faSTristan Ye 	 * if (context->data_ac)
274202ee5faSTristan Ye 	 *	context->data_ac->ac_resv = &OCFS2_I(inode)->ip_la_data_resv;
275202ee5faSTristan Ye 	 */
276202ee5faSTristan Ye 
277202ee5faSTristan Ye 	mutex_lock(&tl_inode->i_mutex);
278202ee5faSTristan Ye 
279202ee5faSTristan Ye 	if (ocfs2_truncate_log_needs_flush(osb)) {
280202ee5faSTristan Ye 		ret = __ocfs2_flush_truncate_log(osb);
281202ee5faSTristan Ye 		if (ret < 0) {
282202ee5faSTristan Ye 			mlog_errno(ret);
283202ee5faSTristan Ye 			goto out_unlock_mutex;
284202ee5faSTristan Ye 		}
285202ee5faSTristan Ye 	}
286202ee5faSTristan Ye 
287202ee5faSTristan Ye 	handle = ocfs2_start_trans(osb, credits);
288202ee5faSTristan Ye 	if (IS_ERR(handle)) {
289202ee5faSTristan Ye 		ret = PTR_ERR(handle);
290202ee5faSTristan Ye 		mlog_errno(ret);
291202ee5faSTristan Ye 		goto out_unlock_mutex;
292202ee5faSTristan Ye 	}
293202ee5faSTristan Ye 
294202ee5faSTristan Ye 	ret = __ocfs2_claim_clusters(handle, context->data_ac, 1, len,
295202ee5faSTristan Ye 				     &new_phys_cpos, &new_len);
296202ee5faSTristan Ye 	if (ret) {
297202ee5faSTristan Ye 		mlog_errno(ret);
298202ee5faSTristan Ye 		goto out_commit;
299202ee5faSTristan Ye 	}
300202ee5faSTristan Ye 
301202ee5faSTristan Ye 	/*
302202ee5faSTristan Ye 	 * we're not quite patient here to make multiple attempts for claiming
303202ee5faSTristan Ye 	 * enough clusters, failure to claim clusters per-requested is not a
304202ee5faSTristan Ye 	 * disaster though, it can only mean partial range of defragmentation
305202ee5faSTristan Ye 	 * or extent movements gets gone, users anyway is able to have another
306202ee5faSTristan Ye 	 * try as they wish anytime, since they're going to be returned a
307202ee5faSTristan Ye 	 * '-ENOSPC' and completed length of this movement.
308202ee5faSTristan Ye 	 */
309202ee5faSTristan Ye 	if (new_len != len) {
310202ee5faSTristan Ye 		mlog(0, "len_claimed: %u, len: %u\n", new_len, len);
311202ee5faSTristan Ye 		context->range->me_flags &= ~OCFS2_MOVE_EXT_FL_COMPLETE;
312202ee5faSTristan Ye 		ret = -ENOSPC;
313202ee5faSTristan Ye 		goto out_commit;
314202ee5faSTristan Ye 	}
315202ee5faSTristan Ye 
316202ee5faSTristan Ye 	mlog(0, "cpos: %u, phys_cpos: %u, new_phys_cpos: %u\n", cpos,
317202ee5faSTristan Ye 	     phys_cpos, new_phys_cpos);
318202ee5faSTristan Ye 
319202ee5faSTristan Ye 	ret = __ocfs2_move_extent(handle, context, cpos, len, phys_cpos,
320202ee5faSTristan Ye 				  new_phys_cpos, ext_flags);
321202ee5faSTristan Ye 	if (ret)
322202ee5faSTristan Ye 		mlog_errno(ret);
323202ee5faSTristan Ye 
324202ee5faSTristan Ye 	/*
325202ee5faSTristan Ye 	 * Here we should write the new page out first if we are
326202ee5faSTristan Ye 	 * in write-back mode.
327202ee5faSTristan Ye 	 */
328202ee5faSTristan Ye 	ret = ocfs2_cow_sync_writeback(inode->i_sb, context->inode, cpos, len);
329202ee5faSTristan Ye 	if (ret)
330202ee5faSTristan Ye 		mlog_errno(ret);
331202ee5faSTristan Ye 
332202ee5faSTristan Ye out_commit:
333202ee5faSTristan Ye 	ocfs2_commit_trans(osb, handle);
334202ee5faSTristan Ye 
335202ee5faSTristan Ye out_unlock_mutex:
336202ee5faSTristan Ye 	mutex_unlock(&tl_inode->i_mutex);
337202ee5faSTristan Ye 
338202ee5faSTristan Ye 	if (context->data_ac) {
339202ee5faSTristan Ye 		ocfs2_free_alloc_context(context->data_ac);
340202ee5faSTristan Ye 		context->data_ac = NULL;
341202ee5faSTristan Ye 	}
342202ee5faSTristan Ye 
343202ee5faSTristan Ye 	if (context->meta_ac) {
344202ee5faSTristan Ye 		ocfs2_free_alloc_context(context->meta_ac);
345202ee5faSTristan Ye 		context->meta_ac = NULL;
346202ee5faSTristan Ye 	}
347202ee5faSTristan Ye 
348202ee5faSTristan Ye out:
349202ee5faSTristan Ye 	if (ref_tree)
350202ee5faSTristan Ye 		ocfs2_unlock_refcount_tree(osb, ref_tree, 1);
351202ee5faSTristan Ye 
352202ee5faSTristan Ye 	return ret;
353202ee5faSTristan Ye }
3541c06b912STristan Ye 
3551c06b912STristan Ye /*
3561c06b912STristan Ye  * find the victim alloc group, where #blkno fits.
3571c06b912STristan Ye  */
3581c06b912STristan Ye static int ocfs2_find_victim_alloc_group(struct inode *inode,
3591c06b912STristan Ye 					 u64 vict_blkno,
3601c06b912STristan Ye 					 int type, int slot,
3611c06b912STristan Ye 					 int *vict_bit,
3621c06b912STristan Ye 					 struct buffer_head **ret_bh)
3631c06b912STristan Ye {
3641c06b912STristan Ye 	int ret, i, blocks_per_unit = 1;
3651c06b912STristan Ye 	u64 blkno;
3661c06b912STristan Ye 	char namebuf[40];
3671c06b912STristan Ye 
3681c06b912STristan Ye 	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
3691c06b912STristan Ye 	struct buffer_head *ac_bh = NULL, *gd_bh = NULL;
3701c06b912STristan Ye 	struct ocfs2_chain_list *cl;
3711c06b912STristan Ye 	struct ocfs2_chain_rec *rec;
3721c06b912STristan Ye 	struct ocfs2_dinode *ac_dinode;
3731c06b912STristan Ye 	struct ocfs2_group_desc *bg;
3741c06b912STristan Ye 
3751c06b912STristan Ye 	ocfs2_sprintf_system_inode_name(namebuf, sizeof(namebuf), type, slot);
3761c06b912STristan Ye 	ret = ocfs2_lookup_ino_from_name(osb->sys_root_inode, namebuf,
3771c06b912STristan Ye 					 strlen(namebuf), &blkno);
3781c06b912STristan Ye 	if (ret) {
3791c06b912STristan Ye 		ret = -ENOENT;
3801c06b912STristan Ye 		goto out;
3811c06b912STristan Ye 	}
3821c06b912STristan Ye 
3831c06b912STristan Ye 	ret = ocfs2_read_blocks_sync(osb, blkno, 1, &ac_bh);
3841c06b912STristan Ye 	if (ret) {
3851c06b912STristan Ye 		mlog_errno(ret);
3861c06b912STristan Ye 		goto out;
3871c06b912STristan Ye 	}
3881c06b912STristan Ye 
3891c06b912STristan Ye 	ac_dinode = (struct ocfs2_dinode *)ac_bh->b_data;
3901c06b912STristan Ye 	cl = &(ac_dinode->id2.i_chain);
3911c06b912STristan Ye 	rec = &(cl->cl_recs[0]);
3921c06b912STristan Ye 
3931c06b912STristan Ye 	if (type == GLOBAL_BITMAP_SYSTEM_INODE)
3941c06b912STristan Ye 		blocks_per_unit <<= (osb->s_clustersize_bits -
3951c06b912STristan Ye 						inode->i_sb->s_blocksize_bits);
3961c06b912STristan Ye 	/*
3971c06b912STristan Ye 	 * 'vict_blkno' was out of the valid range.
3981c06b912STristan Ye 	 */
3991c06b912STristan Ye 	if ((vict_blkno < le64_to_cpu(rec->c_blkno)) ||
4001c06b912STristan Ye 	    (vict_blkno >= (le32_to_cpu(ac_dinode->id1.bitmap1.i_total) *
4011c06b912STristan Ye 				blocks_per_unit))) {
4021c06b912STristan Ye 		ret = -EINVAL;
4031c06b912STristan Ye 		goto out;
4041c06b912STristan Ye 	}
4051c06b912STristan Ye 
4061c06b912STristan Ye 	for (i = 0; i < le16_to_cpu(cl->cl_next_free_rec); i++) {
4071c06b912STristan Ye 
4081c06b912STristan Ye 		rec = &(cl->cl_recs[i]);
4091c06b912STristan Ye 		if (!rec)
4101c06b912STristan Ye 			continue;
4111c06b912STristan Ye 
4121c06b912STristan Ye 		bg = NULL;
4131c06b912STristan Ye 
4141c06b912STristan Ye 		do {
4151c06b912STristan Ye 			if (!bg)
4161c06b912STristan Ye 				blkno = le64_to_cpu(rec->c_blkno);
4171c06b912STristan Ye 			else
4181c06b912STristan Ye 				blkno = le64_to_cpu(bg->bg_next_group);
4191c06b912STristan Ye 
4201c06b912STristan Ye 			if (gd_bh) {
4211c06b912STristan Ye 				brelse(gd_bh);
4221c06b912STristan Ye 				gd_bh = NULL;
4231c06b912STristan Ye 			}
4241c06b912STristan Ye 
4251c06b912STristan Ye 			ret = ocfs2_read_blocks_sync(osb, blkno, 1, &gd_bh);
4261c06b912STristan Ye 			if (ret) {
4271c06b912STristan Ye 				mlog_errno(ret);
4281c06b912STristan Ye 				goto out;
4291c06b912STristan Ye 			}
4301c06b912STristan Ye 
4311c06b912STristan Ye 			bg = (struct ocfs2_group_desc *)gd_bh->b_data;
4321c06b912STristan Ye 
4331c06b912STristan Ye 			if (vict_blkno < (le64_to_cpu(bg->bg_blkno) +
4341c06b912STristan Ye 						le16_to_cpu(bg->bg_bits))) {
4351c06b912STristan Ye 
4361c06b912STristan Ye 				*ret_bh = gd_bh;
4371c06b912STristan Ye 				*vict_bit = (vict_blkno - blkno) /
4381c06b912STristan Ye 							blocks_per_unit;
4391c06b912STristan Ye 				mlog(0, "find the victim group: #%llu, "
4401c06b912STristan Ye 				     "total_bits: %u, vict_bit: %u\n",
4411c06b912STristan Ye 				     blkno, le16_to_cpu(bg->bg_bits),
4421c06b912STristan Ye 				     *vict_bit);
4431c06b912STristan Ye 				goto out;
4441c06b912STristan Ye 			}
4451c06b912STristan Ye 
4461c06b912STristan Ye 		} while (le64_to_cpu(bg->bg_next_group));
4471c06b912STristan Ye 	}
4481c06b912STristan Ye 
4491c06b912STristan Ye 	ret = -EINVAL;
4501c06b912STristan Ye out:
4511c06b912STristan Ye 	brelse(ac_bh);
4521c06b912STristan Ye 
4531c06b912STristan Ye 	/*
4541c06b912STristan Ye 	 * caller has to release the gd_bh properly.
4551c06b912STristan Ye 	 */
4561c06b912STristan Ye 	return ret;
4571c06b912STristan Ye }
45899e4c750STristan Ye 
45999e4c750STristan Ye /*
46099e4c750STristan Ye  * XXX: helper to validate and adjust moving goal.
46199e4c750STristan Ye  */
46299e4c750STristan Ye static int ocfs2_validate_and_adjust_move_goal(struct inode *inode,
46399e4c750STristan Ye 					       struct ocfs2_move_extents *range)
46499e4c750STristan Ye {
46599e4c750STristan Ye 	int ret, goal_bit = 0;
46699e4c750STristan Ye 
46799e4c750STristan Ye 	struct buffer_head *gd_bh = NULL;
46899e4c750STristan Ye 	struct ocfs2_group_desc *bg;
46999e4c750STristan Ye 	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
47099e4c750STristan Ye 	int c_to_b = 1 << (osb->s_clustersize_bits -
47199e4c750STristan Ye 					inode->i_sb->s_blocksize_bits);
47299e4c750STristan Ye 
47399e4c750STristan Ye 	/*
47499e4c750STristan Ye 	 * validate goal sits within global_bitmap, and return the victim
47599e4c750STristan Ye 	 * group desc
47699e4c750STristan Ye 	 */
47799e4c750STristan Ye 	ret = ocfs2_find_victim_alloc_group(inode, range->me_goal,
47899e4c750STristan Ye 					    GLOBAL_BITMAP_SYSTEM_INODE,
47999e4c750STristan Ye 					    OCFS2_INVALID_SLOT,
48099e4c750STristan Ye 					    &goal_bit, &gd_bh);
48199e4c750STristan Ye 	if (ret)
48299e4c750STristan Ye 		goto out;
48399e4c750STristan Ye 
48499e4c750STristan Ye 	bg = (struct ocfs2_group_desc *)gd_bh->b_data;
48599e4c750STristan Ye 
48699e4c750STristan Ye 	/*
48799e4c750STristan Ye 	 * make goal become cluster aligned.
48899e4c750STristan Ye 	 */
48999e4c750STristan Ye 	if (range->me_goal % c_to_b)
49099e4c750STristan Ye 		range->me_goal = range->me_goal / c_to_b * c_to_b;
49199e4c750STristan Ye 
49299e4c750STristan Ye 	/*
49399e4c750STristan Ye 	 * moving goal is not allowd to start with a group desc blok(#0 blk)
49499e4c750STristan Ye 	 * let's compromise to the latter cluster.
49599e4c750STristan Ye 	 */
49699e4c750STristan Ye 	if (range->me_goal == le64_to_cpu(bg->bg_blkno))
49799e4c750STristan Ye 		range->me_goal += c_to_b;
49899e4c750STristan Ye 
49999e4c750STristan Ye 	/*
50099e4c750STristan Ye 	 * movement is not gonna cross two groups.
50199e4c750STristan Ye 	 */
50299e4c750STristan Ye 	if ((le16_to_cpu(bg->bg_bits) - goal_bit) * osb->s_clustersize <
50399e4c750STristan Ye 								range->me_len) {
50499e4c750STristan Ye 		ret = -EINVAL;
50599e4c750STristan Ye 		goto out;
50699e4c750STristan Ye 	}
50799e4c750STristan Ye 	/*
50899e4c750STristan Ye 	 * more exact validations/adjustments will be performed later during
50999e4c750STristan Ye 	 * moving operation for each extent range.
51099e4c750STristan Ye 	 */
51199e4c750STristan Ye 	mlog(0, "extents get ready to be moved to #%llu block\n",
51299e4c750STristan Ye 	     range->me_goal);
51399e4c750STristan Ye 
51499e4c750STristan Ye out:
51599e4c750STristan Ye 	brelse(gd_bh);
51699e4c750STristan Ye 
51799e4c750STristan Ye 	return ret;
51899e4c750STristan Ye }
519