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