162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * extent_map.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Block/Cluster mapping functions 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) 2004 Oracle. All rights reserved. 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/fs.h> 1162306a36Sopenharmony_ci#include <linux/init.h> 1262306a36Sopenharmony_ci#include <linux/slab.h> 1362306a36Sopenharmony_ci#include <linux/types.h> 1462306a36Sopenharmony_ci#include <linux/fiemap.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <cluster/masklog.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "ocfs2.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include "alloc.h" 2162306a36Sopenharmony_ci#include "dlmglue.h" 2262306a36Sopenharmony_ci#include "extent_map.h" 2362306a36Sopenharmony_ci#include "inode.h" 2462306a36Sopenharmony_ci#include "super.h" 2562306a36Sopenharmony_ci#include "symlink.h" 2662306a36Sopenharmony_ci#include "aops.h" 2762306a36Sopenharmony_ci#include "ocfs2_trace.h" 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include "buffer_head_io.h" 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* 3262306a36Sopenharmony_ci * The extent caching implementation is intentionally trivial. 3362306a36Sopenharmony_ci * 3462306a36Sopenharmony_ci * We only cache a small number of extents stored directly on the 3562306a36Sopenharmony_ci * inode, so linear order operations are acceptable. If we ever want 3662306a36Sopenharmony_ci * to increase the size of the extent map, then these algorithms must 3762306a36Sopenharmony_ci * get smarter. 3862306a36Sopenharmony_ci */ 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_civoid ocfs2_extent_map_init(struct inode *inode) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci struct ocfs2_inode_info *oi = OCFS2_I(inode); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci oi->ip_extent_map.em_num_items = 0; 4562306a36Sopenharmony_ci INIT_LIST_HEAD(&oi->ip_extent_map.em_list); 4662306a36Sopenharmony_ci} 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic void __ocfs2_extent_map_lookup(struct ocfs2_extent_map *em, 4962306a36Sopenharmony_ci unsigned int cpos, 5062306a36Sopenharmony_ci struct ocfs2_extent_map_item **ret_emi) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci unsigned int range; 5362306a36Sopenharmony_ci struct ocfs2_extent_map_item *emi; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci *ret_emi = NULL; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci list_for_each_entry(emi, &em->em_list, ei_list) { 5862306a36Sopenharmony_ci range = emi->ei_cpos + emi->ei_clusters; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci if (cpos >= emi->ei_cpos && cpos < range) { 6162306a36Sopenharmony_ci list_move(&emi->ei_list, &em->em_list); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci *ret_emi = emi; 6462306a36Sopenharmony_ci break; 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic int ocfs2_extent_map_lookup(struct inode *inode, unsigned int cpos, 7062306a36Sopenharmony_ci unsigned int *phys, unsigned int *len, 7162306a36Sopenharmony_ci unsigned int *flags) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci unsigned int coff; 7462306a36Sopenharmony_ci struct ocfs2_inode_info *oi = OCFS2_I(inode); 7562306a36Sopenharmony_ci struct ocfs2_extent_map_item *emi; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci spin_lock(&oi->ip_lock); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci __ocfs2_extent_map_lookup(&oi->ip_extent_map, cpos, &emi); 8062306a36Sopenharmony_ci if (emi) { 8162306a36Sopenharmony_ci coff = cpos - emi->ei_cpos; 8262306a36Sopenharmony_ci *phys = emi->ei_phys + coff; 8362306a36Sopenharmony_ci if (len) 8462306a36Sopenharmony_ci *len = emi->ei_clusters - coff; 8562306a36Sopenharmony_ci if (flags) 8662306a36Sopenharmony_ci *flags = emi->ei_flags; 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci spin_unlock(&oi->ip_lock); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci if (emi == NULL) 9262306a36Sopenharmony_ci return -ENOENT; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci return 0; 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci/* 9862306a36Sopenharmony_ci * Forget about all clusters equal to or greater than cpos. 9962306a36Sopenharmony_ci */ 10062306a36Sopenharmony_civoid ocfs2_extent_map_trunc(struct inode *inode, unsigned int cpos) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci struct ocfs2_extent_map_item *emi, *n; 10362306a36Sopenharmony_ci struct ocfs2_inode_info *oi = OCFS2_I(inode); 10462306a36Sopenharmony_ci struct ocfs2_extent_map *em = &oi->ip_extent_map; 10562306a36Sopenharmony_ci LIST_HEAD(tmp_list); 10662306a36Sopenharmony_ci unsigned int range; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci spin_lock(&oi->ip_lock); 10962306a36Sopenharmony_ci list_for_each_entry_safe(emi, n, &em->em_list, ei_list) { 11062306a36Sopenharmony_ci if (emi->ei_cpos >= cpos) { 11162306a36Sopenharmony_ci /* Full truncate of this record. */ 11262306a36Sopenharmony_ci list_move(&emi->ei_list, &tmp_list); 11362306a36Sopenharmony_ci BUG_ON(em->em_num_items == 0); 11462306a36Sopenharmony_ci em->em_num_items--; 11562306a36Sopenharmony_ci continue; 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci range = emi->ei_cpos + emi->ei_clusters; 11962306a36Sopenharmony_ci if (range > cpos) { 12062306a36Sopenharmony_ci /* Partial truncate */ 12162306a36Sopenharmony_ci emi->ei_clusters = cpos - emi->ei_cpos; 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci spin_unlock(&oi->ip_lock); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci list_for_each_entry_safe(emi, n, &tmp_list, ei_list) { 12762306a36Sopenharmony_ci list_del(&emi->ei_list); 12862306a36Sopenharmony_ci kfree(emi); 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci/* 13362306a36Sopenharmony_ci * Is any part of emi2 contained within emi1 13462306a36Sopenharmony_ci */ 13562306a36Sopenharmony_cistatic int ocfs2_ei_is_contained(struct ocfs2_extent_map_item *emi1, 13662306a36Sopenharmony_ci struct ocfs2_extent_map_item *emi2) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci unsigned int range1, range2; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci /* 14162306a36Sopenharmony_ci * Check if logical start of emi2 is inside emi1 14262306a36Sopenharmony_ci */ 14362306a36Sopenharmony_ci range1 = emi1->ei_cpos + emi1->ei_clusters; 14462306a36Sopenharmony_ci if (emi2->ei_cpos >= emi1->ei_cpos && emi2->ei_cpos < range1) 14562306a36Sopenharmony_ci return 1; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci /* 14862306a36Sopenharmony_ci * Check if logical end of emi2 is inside emi1 14962306a36Sopenharmony_ci */ 15062306a36Sopenharmony_ci range2 = emi2->ei_cpos + emi2->ei_clusters; 15162306a36Sopenharmony_ci if (range2 > emi1->ei_cpos && range2 <= range1) 15262306a36Sopenharmony_ci return 1; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci return 0; 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic void ocfs2_copy_emi_fields(struct ocfs2_extent_map_item *dest, 15862306a36Sopenharmony_ci struct ocfs2_extent_map_item *src) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci dest->ei_cpos = src->ei_cpos; 16162306a36Sopenharmony_ci dest->ei_phys = src->ei_phys; 16262306a36Sopenharmony_ci dest->ei_clusters = src->ei_clusters; 16362306a36Sopenharmony_ci dest->ei_flags = src->ei_flags; 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci/* 16762306a36Sopenharmony_ci * Try to merge emi with ins. Returns 1 if merge succeeds, zero 16862306a36Sopenharmony_ci * otherwise. 16962306a36Sopenharmony_ci */ 17062306a36Sopenharmony_cistatic int ocfs2_try_to_merge_extent_map(struct ocfs2_extent_map_item *emi, 17162306a36Sopenharmony_ci struct ocfs2_extent_map_item *ins) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci /* 17462306a36Sopenharmony_ci * Handle contiguousness 17562306a36Sopenharmony_ci */ 17662306a36Sopenharmony_ci if (ins->ei_phys == (emi->ei_phys + emi->ei_clusters) && 17762306a36Sopenharmony_ci ins->ei_cpos == (emi->ei_cpos + emi->ei_clusters) && 17862306a36Sopenharmony_ci ins->ei_flags == emi->ei_flags) { 17962306a36Sopenharmony_ci emi->ei_clusters += ins->ei_clusters; 18062306a36Sopenharmony_ci return 1; 18162306a36Sopenharmony_ci } else if ((ins->ei_phys + ins->ei_clusters) == emi->ei_phys && 18262306a36Sopenharmony_ci (ins->ei_cpos + ins->ei_clusters) == emi->ei_cpos && 18362306a36Sopenharmony_ci ins->ei_flags == emi->ei_flags) { 18462306a36Sopenharmony_ci emi->ei_phys = ins->ei_phys; 18562306a36Sopenharmony_ci emi->ei_cpos = ins->ei_cpos; 18662306a36Sopenharmony_ci emi->ei_clusters += ins->ei_clusters; 18762306a36Sopenharmony_ci return 1; 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci /* 19162306a36Sopenharmony_ci * Overlapping extents - this shouldn't happen unless we've 19262306a36Sopenharmony_ci * split an extent to change it's flags. That is exceedingly 19362306a36Sopenharmony_ci * rare, so there's no sense in trying to optimize it yet. 19462306a36Sopenharmony_ci */ 19562306a36Sopenharmony_ci if (ocfs2_ei_is_contained(emi, ins) || 19662306a36Sopenharmony_ci ocfs2_ei_is_contained(ins, emi)) { 19762306a36Sopenharmony_ci ocfs2_copy_emi_fields(emi, ins); 19862306a36Sopenharmony_ci return 1; 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci /* No merge was possible. */ 20262306a36Sopenharmony_ci return 0; 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci/* 20662306a36Sopenharmony_ci * In order to reduce complexity on the caller, this insert function 20762306a36Sopenharmony_ci * is intentionally liberal in what it will accept. 20862306a36Sopenharmony_ci * 20962306a36Sopenharmony_ci * The only rule is that the truncate call *must* be used whenever 21062306a36Sopenharmony_ci * records have been deleted. This avoids inserting overlapping 21162306a36Sopenharmony_ci * records with different physical mappings. 21262306a36Sopenharmony_ci */ 21362306a36Sopenharmony_civoid ocfs2_extent_map_insert_rec(struct inode *inode, 21462306a36Sopenharmony_ci struct ocfs2_extent_rec *rec) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci struct ocfs2_inode_info *oi = OCFS2_I(inode); 21762306a36Sopenharmony_ci struct ocfs2_extent_map *em = &oi->ip_extent_map; 21862306a36Sopenharmony_ci struct ocfs2_extent_map_item *emi, *new_emi = NULL; 21962306a36Sopenharmony_ci struct ocfs2_extent_map_item ins; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci ins.ei_cpos = le32_to_cpu(rec->e_cpos); 22262306a36Sopenharmony_ci ins.ei_phys = ocfs2_blocks_to_clusters(inode->i_sb, 22362306a36Sopenharmony_ci le64_to_cpu(rec->e_blkno)); 22462306a36Sopenharmony_ci ins.ei_clusters = le16_to_cpu(rec->e_leaf_clusters); 22562306a36Sopenharmony_ci ins.ei_flags = rec->e_flags; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cisearch: 22862306a36Sopenharmony_ci spin_lock(&oi->ip_lock); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci list_for_each_entry(emi, &em->em_list, ei_list) { 23162306a36Sopenharmony_ci if (ocfs2_try_to_merge_extent_map(emi, &ins)) { 23262306a36Sopenharmony_ci list_move(&emi->ei_list, &em->em_list); 23362306a36Sopenharmony_ci spin_unlock(&oi->ip_lock); 23462306a36Sopenharmony_ci goto out; 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci /* 23962306a36Sopenharmony_ci * No item could be merged. 24062306a36Sopenharmony_ci * 24162306a36Sopenharmony_ci * Either allocate and add a new item, or overwrite the last recently 24262306a36Sopenharmony_ci * inserted. 24362306a36Sopenharmony_ci */ 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if (em->em_num_items < OCFS2_MAX_EXTENT_MAP_ITEMS) { 24662306a36Sopenharmony_ci if (new_emi == NULL) { 24762306a36Sopenharmony_ci spin_unlock(&oi->ip_lock); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci new_emi = kmalloc(sizeof(*new_emi), GFP_NOFS); 25062306a36Sopenharmony_ci if (new_emi == NULL) 25162306a36Sopenharmony_ci goto out; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci goto search; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci ocfs2_copy_emi_fields(new_emi, &ins); 25762306a36Sopenharmony_ci list_add(&new_emi->ei_list, &em->em_list); 25862306a36Sopenharmony_ci em->em_num_items++; 25962306a36Sopenharmony_ci new_emi = NULL; 26062306a36Sopenharmony_ci } else { 26162306a36Sopenharmony_ci BUG_ON(list_empty(&em->em_list) || em->em_num_items == 0); 26262306a36Sopenharmony_ci emi = list_entry(em->em_list.prev, 26362306a36Sopenharmony_ci struct ocfs2_extent_map_item, ei_list); 26462306a36Sopenharmony_ci list_move(&emi->ei_list, &em->em_list); 26562306a36Sopenharmony_ci ocfs2_copy_emi_fields(emi, &ins); 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci spin_unlock(&oi->ip_lock); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ciout: 27162306a36Sopenharmony_ci kfree(new_emi); 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cistatic int ocfs2_last_eb_is_empty(struct inode *inode, 27562306a36Sopenharmony_ci struct ocfs2_dinode *di) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci int ret, next_free; 27862306a36Sopenharmony_ci u64 last_eb_blk = le64_to_cpu(di->i_last_eb_blk); 27962306a36Sopenharmony_ci struct buffer_head *eb_bh = NULL; 28062306a36Sopenharmony_ci struct ocfs2_extent_block *eb; 28162306a36Sopenharmony_ci struct ocfs2_extent_list *el; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci ret = ocfs2_read_extent_block(INODE_CACHE(inode), last_eb_blk, &eb_bh); 28462306a36Sopenharmony_ci if (ret) { 28562306a36Sopenharmony_ci mlog_errno(ret); 28662306a36Sopenharmony_ci goto out; 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci eb = (struct ocfs2_extent_block *) eb_bh->b_data; 29062306a36Sopenharmony_ci el = &eb->h_list; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci if (el->l_tree_depth) { 29362306a36Sopenharmony_ci ocfs2_error(inode->i_sb, 29462306a36Sopenharmony_ci "Inode %lu has non zero tree depth in leaf block %llu\n", 29562306a36Sopenharmony_ci inode->i_ino, 29662306a36Sopenharmony_ci (unsigned long long)eb_bh->b_blocknr); 29762306a36Sopenharmony_ci ret = -EROFS; 29862306a36Sopenharmony_ci goto out; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci next_free = le16_to_cpu(el->l_next_free_rec); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci if (next_free == 0 || 30462306a36Sopenharmony_ci (next_free == 1 && ocfs2_is_empty_extent(&el->l_recs[0]))) 30562306a36Sopenharmony_ci ret = 1; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ciout: 30862306a36Sopenharmony_ci brelse(eb_bh); 30962306a36Sopenharmony_ci return ret; 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci/* 31362306a36Sopenharmony_ci * Return the 1st index within el which contains an extent start 31462306a36Sopenharmony_ci * larger than v_cluster. 31562306a36Sopenharmony_ci */ 31662306a36Sopenharmony_cistatic int ocfs2_search_for_hole_index(struct ocfs2_extent_list *el, 31762306a36Sopenharmony_ci u32 v_cluster) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci int i; 32062306a36Sopenharmony_ci struct ocfs2_extent_rec *rec; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci for(i = 0; i < le16_to_cpu(el->l_next_free_rec); i++) { 32362306a36Sopenharmony_ci rec = &el->l_recs[i]; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci if (v_cluster < le32_to_cpu(rec->e_cpos)) 32662306a36Sopenharmony_ci break; 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci return i; 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci/* 33362306a36Sopenharmony_ci * Figure out the size of a hole which starts at v_cluster within the given 33462306a36Sopenharmony_ci * extent list. 33562306a36Sopenharmony_ci * 33662306a36Sopenharmony_ci * If there is no more allocation past v_cluster, we return the maximum 33762306a36Sopenharmony_ci * cluster size minus v_cluster. 33862306a36Sopenharmony_ci * 33962306a36Sopenharmony_ci * If we have in-inode extents, then el points to the dinode list and 34062306a36Sopenharmony_ci * eb_bh is NULL. Otherwise, eb_bh should point to the extent block 34162306a36Sopenharmony_ci * containing el. 34262306a36Sopenharmony_ci */ 34362306a36Sopenharmony_ciint ocfs2_figure_hole_clusters(struct ocfs2_caching_info *ci, 34462306a36Sopenharmony_ci struct ocfs2_extent_list *el, 34562306a36Sopenharmony_ci struct buffer_head *eb_bh, 34662306a36Sopenharmony_ci u32 v_cluster, 34762306a36Sopenharmony_ci u32 *num_clusters) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci int ret, i; 35062306a36Sopenharmony_ci struct buffer_head *next_eb_bh = NULL; 35162306a36Sopenharmony_ci struct ocfs2_extent_block *eb, *next_eb; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci i = ocfs2_search_for_hole_index(el, v_cluster); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci if (i == le16_to_cpu(el->l_next_free_rec) && eb_bh) { 35662306a36Sopenharmony_ci eb = (struct ocfs2_extent_block *)eb_bh->b_data; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci /* 35962306a36Sopenharmony_ci * Check the next leaf for any extents. 36062306a36Sopenharmony_ci */ 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci if (le64_to_cpu(eb->h_next_leaf_blk) == 0ULL) 36362306a36Sopenharmony_ci goto no_more_extents; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci ret = ocfs2_read_extent_block(ci, 36662306a36Sopenharmony_ci le64_to_cpu(eb->h_next_leaf_blk), 36762306a36Sopenharmony_ci &next_eb_bh); 36862306a36Sopenharmony_ci if (ret) { 36962306a36Sopenharmony_ci mlog_errno(ret); 37062306a36Sopenharmony_ci goto out; 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci next_eb = (struct ocfs2_extent_block *)next_eb_bh->b_data; 37462306a36Sopenharmony_ci el = &next_eb->h_list; 37562306a36Sopenharmony_ci i = ocfs2_search_for_hole_index(el, v_cluster); 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_cino_more_extents: 37962306a36Sopenharmony_ci if (i == le16_to_cpu(el->l_next_free_rec)) { 38062306a36Sopenharmony_ci /* 38162306a36Sopenharmony_ci * We're at the end of our existing allocation. Just 38262306a36Sopenharmony_ci * return the maximum number of clusters we could 38362306a36Sopenharmony_ci * possibly allocate. 38462306a36Sopenharmony_ci */ 38562306a36Sopenharmony_ci *num_clusters = UINT_MAX - v_cluster; 38662306a36Sopenharmony_ci } else { 38762306a36Sopenharmony_ci *num_clusters = le32_to_cpu(el->l_recs[i].e_cpos) - v_cluster; 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci ret = 0; 39162306a36Sopenharmony_ciout: 39262306a36Sopenharmony_ci brelse(next_eb_bh); 39362306a36Sopenharmony_ci return ret; 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_cistatic int ocfs2_get_clusters_nocache(struct inode *inode, 39762306a36Sopenharmony_ci struct buffer_head *di_bh, 39862306a36Sopenharmony_ci u32 v_cluster, unsigned int *hole_len, 39962306a36Sopenharmony_ci struct ocfs2_extent_rec *ret_rec, 40062306a36Sopenharmony_ci unsigned int *is_last) 40162306a36Sopenharmony_ci{ 40262306a36Sopenharmony_ci int i, ret, tree_height, len; 40362306a36Sopenharmony_ci struct ocfs2_dinode *di; 40462306a36Sopenharmony_ci struct ocfs2_extent_block *eb; 40562306a36Sopenharmony_ci struct ocfs2_extent_list *el; 40662306a36Sopenharmony_ci struct ocfs2_extent_rec *rec; 40762306a36Sopenharmony_ci struct buffer_head *eb_bh = NULL; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci memset(ret_rec, 0, sizeof(*ret_rec)); 41062306a36Sopenharmony_ci if (is_last) 41162306a36Sopenharmony_ci *is_last = 0; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci di = (struct ocfs2_dinode *) di_bh->b_data; 41462306a36Sopenharmony_ci el = &di->id2.i_list; 41562306a36Sopenharmony_ci tree_height = le16_to_cpu(el->l_tree_depth); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci if (tree_height > 0) { 41862306a36Sopenharmony_ci ret = ocfs2_find_leaf(INODE_CACHE(inode), el, v_cluster, 41962306a36Sopenharmony_ci &eb_bh); 42062306a36Sopenharmony_ci if (ret) { 42162306a36Sopenharmony_ci mlog_errno(ret); 42262306a36Sopenharmony_ci goto out; 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci eb = (struct ocfs2_extent_block *) eb_bh->b_data; 42662306a36Sopenharmony_ci el = &eb->h_list; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci if (el->l_tree_depth) { 42962306a36Sopenharmony_ci ocfs2_error(inode->i_sb, 43062306a36Sopenharmony_ci "Inode %lu has non zero tree depth in leaf block %llu\n", 43162306a36Sopenharmony_ci inode->i_ino, 43262306a36Sopenharmony_ci (unsigned long long)eb_bh->b_blocknr); 43362306a36Sopenharmony_ci ret = -EROFS; 43462306a36Sopenharmony_ci goto out; 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci i = ocfs2_search_extent_list(el, v_cluster); 43962306a36Sopenharmony_ci if (i == -1) { 44062306a36Sopenharmony_ci /* 44162306a36Sopenharmony_ci * Holes can be larger than the maximum size of an 44262306a36Sopenharmony_ci * extent, so we return their lengths in a separate 44362306a36Sopenharmony_ci * field. 44462306a36Sopenharmony_ci */ 44562306a36Sopenharmony_ci if (hole_len) { 44662306a36Sopenharmony_ci ret = ocfs2_figure_hole_clusters(INODE_CACHE(inode), 44762306a36Sopenharmony_ci el, eb_bh, 44862306a36Sopenharmony_ci v_cluster, &len); 44962306a36Sopenharmony_ci if (ret) { 45062306a36Sopenharmony_ci mlog_errno(ret); 45162306a36Sopenharmony_ci goto out; 45262306a36Sopenharmony_ci } 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci *hole_len = len; 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci goto out_hole; 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci rec = &el->l_recs[i]; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci BUG_ON(v_cluster < le32_to_cpu(rec->e_cpos)); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci if (!rec->e_blkno) { 46462306a36Sopenharmony_ci ocfs2_error(inode->i_sb, 46562306a36Sopenharmony_ci "Inode %lu has bad extent record (%u, %u, 0)\n", 46662306a36Sopenharmony_ci inode->i_ino, 46762306a36Sopenharmony_ci le32_to_cpu(rec->e_cpos), 46862306a36Sopenharmony_ci ocfs2_rec_clusters(el, rec)); 46962306a36Sopenharmony_ci ret = -EROFS; 47062306a36Sopenharmony_ci goto out; 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci *ret_rec = *rec; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci /* 47662306a36Sopenharmony_ci * Checking for last extent is potentially expensive - we 47762306a36Sopenharmony_ci * might have to look at the next leaf over to see if it's 47862306a36Sopenharmony_ci * empty. 47962306a36Sopenharmony_ci * 48062306a36Sopenharmony_ci * The first two checks are to see whether the caller even 48162306a36Sopenharmony_ci * cares for this information, and if the extent is at least 48262306a36Sopenharmony_ci * the last in it's list. 48362306a36Sopenharmony_ci * 48462306a36Sopenharmony_ci * If those hold true, then the extent is last if any of the 48562306a36Sopenharmony_ci * additional conditions hold true: 48662306a36Sopenharmony_ci * - Extent list is in-inode 48762306a36Sopenharmony_ci * - Extent list is right-most 48862306a36Sopenharmony_ci * - Extent list is 2nd to rightmost, with empty right-most 48962306a36Sopenharmony_ci */ 49062306a36Sopenharmony_ci if (is_last) { 49162306a36Sopenharmony_ci if (i == (le16_to_cpu(el->l_next_free_rec) - 1)) { 49262306a36Sopenharmony_ci if (tree_height == 0) 49362306a36Sopenharmony_ci *is_last = 1; 49462306a36Sopenharmony_ci else if (eb->h_blkno == di->i_last_eb_blk) 49562306a36Sopenharmony_ci *is_last = 1; 49662306a36Sopenharmony_ci else if (eb->h_next_leaf_blk == di->i_last_eb_blk) { 49762306a36Sopenharmony_ci ret = ocfs2_last_eb_is_empty(inode, di); 49862306a36Sopenharmony_ci if (ret < 0) { 49962306a36Sopenharmony_ci mlog_errno(ret); 50062306a36Sopenharmony_ci goto out; 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci if (ret == 1) 50362306a36Sopenharmony_ci *is_last = 1; 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci } 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ciout_hole: 50962306a36Sopenharmony_ci ret = 0; 51062306a36Sopenharmony_ciout: 51162306a36Sopenharmony_ci brelse(eb_bh); 51262306a36Sopenharmony_ci return ret; 51362306a36Sopenharmony_ci} 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_cistatic void ocfs2_relative_extent_offsets(struct super_block *sb, 51662306a36Sopenharmony_ci u32 v_cluster, 51762306a36Sopenharmony_ci struct ocfs2_extent_rec *rec, 51862306a36Sopenharmony_ci u32 *p_cluster, u32 *num_clusters) 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci{ 52162306a36Sopenharmony_ci u32 coff = v_cluster - le32_to_cpu(rec->e_cpos); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci *p_cluster = ocfs2_blocks_to_clusters(sb, le64_to_cpu(rec->e_blkno)); 52462306a36Sopenharmony_ci *p_cluster = *p_cluster + coff; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci if (num_clusters) 52762306a36Sopenharmony_ci *num_clusters = le16_to_cpu(rec->e_leaf_clusters) - coff; 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ciint ocfs2_xattr_get_clusters(struct inode *inode, u32 v_cluster, 53162306a36Sopenharmony_ci u32 *p_cluster, u32 *num_clusters, 53262306a36Sopenharmony_ci struct ocfs2_extent_list *el, 53362306a36Sopenharmony_ci unsigned int *extent_flags) 53462306a36Sopenharmony_ci{ 53562306a36Sopenharmony_ci int ret = 0, i; 53662306a36Sopenharmony_ci struct buffer_head *eb_bh = NULL; 53762306a36Sopenharmony_ci struct ocfs2_extent_block *eb; 53862306a36Sopenharmony_ci struct ocfs2_extent_rec *rec; 53962306a36Sopenharmony_ci u32 coff; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci if (el->l_tree_depth) { 54262306a36Sopenharmony_ci ret = ocfs2_find_leaf(INODE_CACHE(inode), el, v_cluster, 54362306a36Sopenharmony_ci &eb_bh); 54462306a36Sopenharmony_ci if (ret) { 54562306a36Sopenharmony_ci mlog_errno(ret); 54662306a36Sopenharmony_ci goto out; 54762306a36Sopenharmony_ci } 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci eb = (struct ocfs2_extent_block *) eb_bh->b_data; 55062306a36Sopenharmony_ci el = &eb->h_list; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci if (el->l_tree_depth) { 55362306a36Sopenharmony_ci ocfs2_error(inode->i_sb, 55462306a36Sopenharmony_ci "Inode %lu has non zero tree depth in xattr leaf block %llu\n", 55562306a36Sopenharmony_ci inode->i_ino, 55662306a36Sopenharmony_ci (unsigned long long)eb_bh->b_blocknr); 55762306a36Sopenharmony_ci ret = -EROFS; 55862306a36Sopenharmony_ci goto out; 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci i = ocfs2_search_extent_list(el, v_cluster); 56362306a36Sopenharmony_ci if (i == -1) { 56462306a36Sopenharmony_ci ret = -EROFS; 56562306a36Sopenharmony_ci mlog_errno(ret); 56662306a36Sopenharmony_ci goto out; 56762306a36Sopenharmony_ci } else { 56862306a36Sopenharmony_ci rec = &el->l_recs[i]; 56962306a36Sopenharmony_ci BUG_ON(v_cluster < le32_to_cpu(rec->e_cpos)); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci if (!rec->e_blkno) { 57262306a36Sopenharmony_ci ocfs2_error(inode->i_sb, 57362306a36Sopenharmony_ci "Inode %lu has bad extent record (%u, %u, 0) in xattr\n", 57462306a36Sopenharmony_ci inode->i_ino, 57562306a36Sopenharmony_ci le32_to_cpu(rec->e_cpos), 57662306a36Sopenharmony_ci ocfs2_rec_clusters(el, rec)); 57762306a36Sopenharmony_ci ret = -EROFS; 57862306a36Sopenharmony_ci goto out; 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci coff = v_cluster - le32_to_cpu(rec->e_cpos); 58162306a36Sopenharmony_ci *p_cluster = ocfs2_blocks_to_clusters(inode->i_sb, 58262306a36Sopenharmony_ci le64_to_cpu(rec->e_blkno)); 58362306a36Sopenharmony_ci *p_cluster = *p_cluster + coff; 58462306a36Sopenharmony_ci if (num_clusters) 58562306a36Sopenharmony_ci *num_clusters = ocfs2_rec_clusters(el, rec) - coff; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci if (extent_flags) 58862306a36Sopenharmony_ci *extent_flags = rec->e_flags; 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ciout: 59162306a36Sopenharmony_ci brelse(eb_bh); 59262306a36Sopenharmony_ci return ret; 59362306a36Sopenharmony_ci} 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ciint ocfs2_get_clusters(struct inode *inode, u32 v_cluster, 59662306a36Sopenharmony_ci u32 *p_cluster, u32 *num_clusters, 59762306a36Sopenharmony_ci unsigned int *extent_flags) 59862306a36Sopenharmony_ci{ 59962306a36Sopenharmony_ci int ret; 60062306a36Sopenharmony_ci unsigned int hole_len, flags = 0; 60162306a36Sopenharmony_ci struct buffer_head *di_bh = NULL; 60262306a36Sopenharmony_ci struct ocfs2_extent_rec rec; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { 60562306a36Sopenharmony_ci ret = -ERANGE; 60662306a36Sopenharmony_ci mlog_errno(ret); 60762306a36Sopenharmony_ci goto out; 60862306a36Sopenharmony_ci } 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci ret = ocfs2_extent_map_lookup(inode, v_cluster, p_cluster, 61162306a36Sopenharmony_ci num_clusters, extent_flags); 61262306a36Sopenharmony_ci if (ret == 0) 61362306a36Sopenharmony_ci goto out; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci ret = ocfs2_read_inode_block(inode, &di_bh); 61662306a36Sopenharmony_ci if (ret) { 61762306a36Sopenharmony_ci mlog_errno(ret); 61862306a36Sopenharmony_ci goto out; 61962306a36Sopenharmony_ci } 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci ret = ocfs2_get_clusters_nocache(inode, di_bh, v_cluster, &hole_len, 62262306a36Sopenharmony_ci &rec, NULL); 62362306a36Sopenharmony_ci if (ret) { 62462306a36Sopenharmony_ci mlog_errno(ret); 62562306a36Sopenharmony_ci goto out; 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci if (rec.e_blkno == 0ULL) { 62962306a36Sopenharmony_ci /* 63062306a36Sopenharmony_ci * A hole was found. Return some canned values that 63162306a36Sopenharmony_ci * callers can key on. If asked for, num_clusters will 63262306a36Sopenharmony_ci * be populated with the size of the hole. 63362306a36Sopenharmony_ci */ 63462306a36Sopenharmony_ci *p_cluster = 0; 63562306a36Sopenharmony_ci if (num_clusters) { 63662306a36Sopenharmony_ci *num_clusters = hole_len; 63762306a36Sopenharmony_ci } 63862306a36Sopenharmony_ci } else { 63962306a36Sopenharmony_ci ocfs2_relative_extent_offsets(inode->i_sb, v_cluster, &rec, 64062306a36Sopenharmony_ci p_cluster, num_clusters); 64162306a36Sopenharmony_ci flags = rec.e_flags; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci ocfs2_extent_map_insert_rec(inode, &rec); 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci if (extent_flags) 64762306a36Sopenharmony_ci *extent_flags = flags; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ciout: 65062306a36Sopenharmony_ci brelse(di_bh); 65162306a36Sopenharmony_ci return ret; 65262306a36Sopenharmony_ci} 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci/* 65562306a36Sopenharmony_ci * This expects alloc_sem to be held. The allocation cannot change at 65662306a36Sopenharmony_ci * all while the map is in the process of being updated. 65762306a36Sopenharmony_ci */ 65862306a36Sopenharmony_ciint ocfs2_extent_map_get_blocks(struct inode *inode, u64 v_blkno, u64 *p_blkno, 65962306a36Sopenharmony_ci u64 *ret_count, unsigned int *extent_flags) 66062306a36Sopenharmony_ci{ 66162306a36Sopenharmony_ci int ret; 66262306a36Sopenharmony_ci int bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1); 66362306a36Sopenharmony_ci u32 cpos, num_clusters, p_cluster; 66462306a36Sopenharmony_ci u64 boff = 0; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci cpos = ocfs2_blocks_to_clusters(inode->i_sb, v_blkno); 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci ret = ocfs2_get_clusters(inode, cpos, &p_cluster, &num_clusters, 66962306a36Sopenharmony_ci extent_flags); 67062306a36Sopenharmony_ci if (ret) { 67162306a36Sopenharmony_ci mlog_errno(ret); 67262306a36Sopenharmony_ci goto out; 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci /* 67662306a36Sopenharmony_ci * p_cluster == 0 indicates a hole. 67762306a36Sopenharmony_ci */ 67862306a36Sopenharmony_ci if (p_cluster) { 67962306a36Sopenharmony_ci boff = ocfs2_clusters_to_blocks(inode->i_sb, p_cluster); 68062306a36Sopenharmony_ci boff += (v_blkno & (u64)(bpc - 1)); 68162306a36Sopenharmony_ci } 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci *p_blkno = boff; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci if (ret_count) { 68662306a36Sopenharmony_ci *ret_count = ocfs2_clusters_to_blocks(inode->i_sb, num_clusters); 68762306a36Sopenharmony_ci *ret_count -= v_blkno & (u64)(bpc - 1); 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ciout: 69162306a36Sopenharmony_ci return ret; 69262306a36Sopenharmony_ci} 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci/* 69562306a36Sopenharmony_ci * The ocfs2_fiemap_inline() may be a little bit misleading, since 69662306a36Sopenharmony_ci * it not only handles the fiemap for inlined files, but also deals 69762306a36Sopenharmony_ci * with the fast symlink, cause they have no difference for extent 69862306a36Sopenharmony_ci * mapping per se. 69962306a36Sopenharmony_ci */ 70062306a36Sopenharmony_cistatic int ocfs2_fiemap_inline(struct inode *inode, struct buffer_head *di_bh, 70162306a36Sopenharmony_ci struct fiemap_extent_info *fieinfo, 70262306a36Sopenharmony_ci u64 map_start) 70362306a36Sopenharmony_ci{ 70462306a36Sopenharmony_ci int ret; 70562306a36Sopenharmony_ci unsigned int id_count; 70662306a36Sopenharmony_ci struct ocfs2_dinode *di; 70762306a36Sopenharmony_ci u64 phys; 70862306a36Sopenharmony_ci u32 flags = FIEMAP_EXTENT_DATA_INLINE|FIEMAP_EXTENT_LAST; 70962306a36Sopenharmony_ci struct ocfs2_inode_info *oi = OCFS2_I(inode); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci di = (struct ocfs2_dinode *)di_bh->b_data; 71262306a36Sopenharmony_ci if (ocfs2_inode_is_fast_symlink(inode)) 71362306a36Sopenharmony_ci id_count = ocfs2_fast_symlink_chars(inode->i_sb); 71462306a36Sopenharmony_ci else 71562306a36Sopenharmony_ci id_count = le16_to_cpu(di->id2.i_data.id_count); 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci if (map_start < id_count) { 71862306a36Sopenharmony_ci phys = oi->ip_blkno << inode->i_sb->s_blocksize_bits; 71962306a36Sopenharmony_ci if (ocfs2_inode_is_fast_symlink(inode)) 72062306a36Sopenharmony_ci phys += offsetof(struct ocfs2_dinode, id2.i_symlink); 72162306a36Sopenharmony_ci else 72262306a36Sopenharmony_ci phys += offsetof(struct ocfs2_dinode, 72362306a36Sopenharmony_ci id2.i_data.id_data); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci ret = fiemap_fill_next_extent(fieinfo, 0, phys, id_count, 72662306a36Sopenharmony_ci flags); 72762306a36Sopenharmony_ci if (ret < 0) 72862306a36Sopenharmony_ci return ret; 72962306a36Sopenharmony_ci } 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci return 0; 73262306a36Sopenharmony_ci} 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ciint ocfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, 73562306a36Sopenharmony_ci u64 map_start, u64 map_len) 73662306a36Sopenharmony_ci{ 73762306a36Sopenharmony_ci int ret, is_last; 73862306a36Sopenharmony_ci u32 mapping_end, cpos; 73962306a36Sopenharmony_ci unsigned int hole_size; 74062306a36Sopenharmony_ci struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 74162306a36Sopenharmony_ci u64 len_bytes, phys_bytes, virt_bytes; 74262306a36Sopenharmony_ci struct buffer_head *di_bh = NULL; 74362306a36Sopenharmony_ci struct ocfs2_extent_rec rec; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci ret = fiemap_prep(inode, fieinfo, map_start, &map_len, 0); 74662306a36Sopenharmony_ci if (ret) 74762306a36Sopenharmony_ci return ret; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci ret = ocfs2_inode_lock(inode, &di_bh, 0); 75062306a36Sopenharmony_ci if (ret) { 75162306a36Sopenharmony_ci mlog_errno(ret); 75262306a36Sopenharmony_ci goto out; 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci down_read(&OCFS2_I(inode)->ip_alloc_sem); 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci /* 75862306a36Sopenharmony_ci * Handle inline-data and fast symlink separately. 75962306a36Sopenharmony_ci */ 76062306a36Sopenharmony_ci if ((OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) || 76162306a36Sopenharmony_ci ocfs2_inode_is_fast_symlink(inode)) { 76262306a36Sopenharmony_ci ret = ocfs2_fiemap_inline(inode, di_bh, fieinfo, map_start); 76362306a36Sopenharmony_ci goto out_unlock; 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci cpos = map_start >> osb->s_clustersize_bits; 76762306a36Sopenharmony_ci mapping_end = ocfs2_clusters_for_bytes(inode->i_sb, 76862306a36Sopenharmony_ci map_start + map_len); 76962306a36Sopenharmony_ci is_last = 0; 77062306a36Sopenharmony_ci while (cpos < mapping_end && !is_last) { 77162306a36Sopenharmony_ci u32 fe_flags; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci ret = ocfs2_get_clusters_nocache(inode, di_bh, cpos, 77462306a36Sopenharmony_ci &hole_size, &rec, &is_last); 77562306a36Sopenharmony_ci if (ret) { 77662306a36Sopenharmony_ci mlog_errno(ret); 77762306a36Sopenharmony_ci goto out_unlock; 77862306a36Sopenharmony_ci } 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci if (rec.e_blkno == 0ULL) { 78162306a36Sopenharmony_ci cpos += hole_size; 78262306a36Sopenharmony_ci continue; 78362306a36Sopenharmony_ci } 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci fe_flags = 0; 78662306a36Sopenharmony_ci if (rec.e_flags & OCFS2_EXT_UNWRITTEN) 78762306a36Sopenharmony_ci fe_flags |= FIEMAP_EXTENT_UNWRITTEN; 78862306a36Sopenharmony_ci if (rec.e_flags & OCFS2_EXT_REFCOUNTED) 78962306a36Sopenharmony_ci fe_flags |= FIEMAP_EXTENT_SHARED; 79062306a36Sopenharmony_ci if (is_last) 79162306a36Sopenharmony_ci fe_flags |= FIEMAP_EXTENT_LAST; 79262306a36Sopenharmony_ci len_bytes = (u64)le16_to_cpu(rec.e_leaf_clusters) << osb->s_clustersize_bits; 79362306a36Sopenharmony_ci phys_bytes = le64_to_cpu(rec.e_blkno) << osb->sb->s_blocksize_bits; 79462306a36Sopenharmony_ci virt_bytes = (u64)le32_to_cpu(rec.e_cpos) << osb->s_clustersize_bits; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci ret = fiemap_fill_next_extent(fieinfo, virt_bytes, phys_bytes, 79762306a36Sopenharmony_ci len_bytes, fe_flags); 79862306a36Sopenharmony_ci if (ret) 79962306a36Sopenharmony_ci break; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci cpos = le32_to_cpu(rec.e_cpos)+ le16_to_cpu(rec.e_leaf_clusters); 80262306a36Sopenharmony_ci } 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci if (ret > 0) 80562306a36Sopenharmony_ci ret = 0; 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ciout_unlock: 80862306a36Sopenharmony_ci brelse(di_bh); 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci up_read(&OCFS2_I(inode)->ip_alloc_sem); 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci ocfs2_inode_unlock(inode, 0); 81362306a36Sopenharmony_ciout: 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci return ret; 81662306a36Sopenharmony_ci} 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci/* Is IO overwriting allocated blocks? */ 81962306a36Sopenharmony_ciint ocfs2_overwrite_io(struct inode *inode, struct buffer_head *di_bh, 82062306a36Sopenharmony_ci u64 map_start, u64 map_len) 82162306a36Sopenharmony_ci{ 82262306a36Sopenharmony_ci int ret = 0, is_last; 82362306a36Sopenharmony_ci u32 mapping_end, cpos; 82462306a36Sopenharmony_ci struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 82562306a36Sopenharmony_ci struct ocfs2_extent_rec rec; 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { 82862306a36Sopenharmony_ci if (ocfs2_size_fits_inline_data(di_bh, map_start + map_len)) 82962306a36Sopenharmony_ci return ret; 83062306a36Sopenharmony_ci else 83162306a36Sopenharmony_ci return -EAGAIN; 83262306a36Sopenharmony_ci } 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci cpos = map_start >> osb->s_clustersize_bits; 83562306a36Sopenharmony_ci mapping_end = ocfs2_clusters_for_bytes(inode->i_sb, 83662306a36Sopenharmony_ci map_start + map_len); 83762306a36Sopenharmony_ci is_last = 0; 83862306a36Sopenharmony_ci while (cpos < mapping_end && !is_last) { 83962306a36Sopenharmony_ci ret = ocfs2_get_clusters_nocache(inode, di_bh, cpos, 84062306a36Sopenharmony_ci NULL, &rec, &is_last); 84162306a36Sopenharmony_ci if (ret) { 84262306a36Sopenharmony_ci mlog_errno(ret); 84362306a36Sopenharmony_ci goto out; 84462306a36Sopenharmony_ci } 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci if (rec.e_blkno == 0ULL) 84762306a36Sopenharmony_ci break; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci if (rec.e_flags & OCFS2_EXT_REFCOUNTED) 85062306a36Sopenharmony_ci break; 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci cpos = le32_to_cpu(rec.e_cpos) + 85362306a36Sopenharmony_ci le16_to_cpu(rec.e_leaf_clusters); 85462306a36Sopenharmony_ci } 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci if (cpos < mapping_end) 85762306a36Sopenharmony_ci ret = -EAGAIN; 85862306a36Sopenharmony_ciout: 85962306a36Sopenharmony_ci return ret; 86062306a36Sopenharmony_ci} 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ciint ocfs2_seek_data_hole_offset(struct file *file, loff_t *offset, int whence) 86362306a36Sopenharmony_ci{ 86462306a36Sopenharmony_ci struct inode *inode = file->f_mapping->host; 86562306a36Sopenharmony_ci int ret; 86662306a36Sopenharmony_ci unsigned int is_last = 0, is_data = 0; 86762306a36Sopenharmony_ci u16 cs_bits = OCFS2_SB(inode->i_sb)->s_clustersize_bits; 86862306a36Sopenharmony_ci u32 cpos, cend, clen, hole_size; 86962306a36Sopenharmony_ci u64 extoff, extlen; 87062306a36Sopenharmony_ci struct buffer_head *di_bh = NULL; 87162306a36Sopenharmony_ci struct ocfs2_extent_rec rec; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci BUG_ON(whence != SEEK_DATA && whence != SEEK_HOLE); 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci ret = ocfs2_inode_lock(inode, &di_bh, 0); 87662306a36Sopenharmony_ci if (ret) { 87762306a36Sopenharmony_ci mlog_errno(ret); 87862306a36Sopenharmony_ci goto out; 87962306a36Sopenharmony_ci } 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci down_read(&OCFS2_I(inode)->ip_alloc_sem); 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci if (*offset >= i_size_read(inode)) { 88462306a36Sopenharmony_ci ret = -ENXIO; 88562306a36Sopenharmony_ci goto out_unlock; 88662306a36Sopenharmony_ci } 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { 88962306a36Sopenharmony_ci if (whence == SEEK_HOLE) 89062306a36Sopenharmony_ci *offset = i_size_read(inode); 89162306a36Sopenharmony_ci goto out_unlock; 89262306a36Sopenharmony_ci } 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci clen = 0; 89562306a36Sopenharmony_ci cpos = *offset >> cs_bits; 89662306a36Sopenharmony_ci cend = ocfs2_clusters_for_bytes(inode->i_sb, i_size_read(inode)); 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci while (cpos < cend && !is_last) { 89962306a36Sopenharmony_ci ret = ocfs2_get_clusters_nocache(inode, di_bh, cpos, &hole_size, 90062306a36Sopenharmony_ci &rec, &is_last); 90162306a36Sopenharmony_ci if (ret) { 90262306a36Sopenharmony_ci mlog_errno(ret); 90362306a36Sopenharmony_ci goto out_unlock; 90462306a36Sopenharmony_ci } 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci extoff = cpos; 90762306a36Sopenharmony_ci extoff <<= cs_bits; 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci if (rec.e_blkno == 0ULL) { 91062306a36Sopenharmony_ci clen = hole_size; 91162306a36Sopenharmony_ci is_data = 0; 91262306a36Sopenharmony_ci } else { 91362306a36Sopenharmony_ci clen = le16_to_cpu(rec.e_leaf_clusters) - 91462306a36Sopenharmony_ci (cpos - le32_to_cpu(rec.e_cpos)); 91562306a36Sopenharmony_ci is_data = (rec.e_flags & OCFS2_EXT_UNWRITTEN) ? 0 : 1; 91662306a36Sopenharmony_ci } 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci if ((!is_data && whence == SEEK_HOLE) || 91962306a36Sopenharmony_ci (is_data && whence == SEEK_DATA)) { 92062306a36Sopenharmony_ci if (extoff > *offset) 92162306a36Sopenharmony_ci *offset = extoff; 92262306a36Sopenharmony_ci goto out_unlock; 92362306a36Sopenharmony_ci } 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci if (!is_last) 92662306a36Sopenharmony_ci cpos += clen; 92762306a36Sopenharmony_ci } 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci if (whence == SEEK_HOLE) { 93062306a36Sopenharmony_ci extoff = cpos; 93162306a36Sopenharmony_ci extoff <<= cs_bits; 93262306a36Sopenharmony_ci extlen = clen; 93362306a36Sopenharmony_ci extlen <<= cs_bits; 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci if ((extoff + extlen) > i_size_read(inode)) 93662306a36Sopenharmony_ci extlen = i_size_read(inode) - extoff; 93762306a36Sopenharmony_ci extoff += extlen; 93862306a36Sopenharmony_ci if (extoff > *offset) 93962306a36Sopenharmony_ci *offset = extoff; 94062306a36Sopenharmony_ci goto out_unlock; 94162306a36Sopenharmony_ci } 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci ret = -ENXIO; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ciout_unlock: 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci brelse(di_bh); 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci up_read(&OCFS2_I(inode)->ip_alloc_sem); 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci ocfs2_inode_unlock(inode, 0); 95262306a36Sopenharmony_ciout: 95362306a36Sopenharmony_ci return ret; 95462306a36Sopenharmony_ci} 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ciint ocfs2_read_virt_blocks(struct inode *inode, u64 v_block, int nr, 95762306a36Sopenharmony_ci struct buffer_head *bhs[], int flags, 95862306a36Sopenharmony_ci int (*validate)(struct super_block *sb, 95962306a36Sopenharmony_ci struct buffer_head *bh)) 96062306a36Sopenharmony_ci{ 96162306a36Sopenharmony_ci int rc = 0; 96262306a36Sopenharmony_ci u64 p_block, p_count; 96362306a36Sopenharmony_ci int i, count, done = 0; 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci trace_ocfs2_read_virt_blocks( 96662306a36Sopenharmony_ci inode, (unsigned long long)v_block, nr, bhs, flags, 96762306a36Sopenharmony_ci validate); 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci if (((v_block + nr - 1) << inode->i_sb->s_blocksize_bits) >= 97062306a36Sopenharmony_ci i_size_read(inode)) { 97162306a36Sopenharmony_ci BUG_ON(!(flags & OCFS2_BH_READAHEAD)); 97262306a36Sopenharmony_ci goto out; 97362306a36Sopenharmony_ci } 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci while (done < nr) { 97662306a36Sopenharmony_ci down_read(&OCFS2_I(inode)->ip_alloc_sem); 97762306a36Sopenharmony_ci rc = ocfs2_extent_map_get_blocks(inode, v_block + done, 97862306a36Sopenharmony_ci &p_block, &p_count, NULL); 97962306a36Sopenharmony_ci up_read(&OCFS2_I(inode)->ip_alloc_sem); 98062306a36Sopenharmony_ci if (rc) { 98162306a36Sopenharmony_ci mlog_errno(rc); 98262306a36Sopenharmony_ci break; 98362306a36Sopenharmony_ci } 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci if (!p_block) { 98662306a36Sopenharmony_ci rc = -EIO; 98762306a36Sopenharmony_ci mlog(ML_ERROR, 98862306a36Sopenharmony_ci "Inode #%llu contains a hole at offset %llu\n", 98962306a36Sopenharmony_ci (unsigned long long)OCFS2_I(inode)->ip_blkno, 99062306a36Sopenharmony_ci (unsigned long long)(v_block + done) << 99162306a36Sopenharmony_ci inode->i_sb->s_blocksize_bits); 99262306a36Sopenharmony_ci break; 99362306a36Sopenharmony_ci } 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci count = nr - done; 99662306a36Sopenharmony_ci if (p_count < count) 99762306a36Sopenharmony_ci count = p_count; 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci /* 100062306a36Sopenharmony_ci * If the caller passed us bhs, they should have come 100162306a36Sopenharmony_ci * from a previous readahead call to this function. Thus, 100262306a36Sopenharmony_ci * they should have the right b_blocknr. 100362306a36Sopenharmony_ci */ 100462306a36Sopenharmony_ci for (i = 0; i < count; i++) { 100562306a36Sopenharmony_ci if (!bhs[done + i]) 100662306a36Sopenharmony_ci continue; 100762306a36Sopenharmony_ci BUG_ON(bhs[done + i]->b_blocknr != (p_block + i)); 100862306a36Sopenharmony_ci } 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci rc = ocfs2_read_blocks(INODE_CACHE(inode), p_block, count, 101162306a36Sopenharmony_ci bhs + done, flags, validate); 101262306a36Sopenharmony_ci if (rc) { 101362306a36Sopenharmony_ci mlog_errno(rc); 101462306a36Sopenharmony_ci break; 101562306a36Sopenharmony_ci } 101662306a36Sopenharmony_ci done += count; 101762306a36Sopenharmony_ci } 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ciout: 102062306a36Sopenharmony_ci return rc; 102162306a36Sopenharmony_ci} 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci 1024