18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2000-2001 Christoph Hellwig. 38c2ecf20Sopenharmony_ci * All rights reserved. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 68c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions 78c2ecf20Sopenharmony_ci * are met: 88c2ecf20Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 98c2ecf20Sopenharmony_ci * notice, this list of conditions, and the following disclaimer, 108c2ecf20Sopenharmony_ci * without modification. 118c2ecf20Sopenharmony_ci * 2. The name of the author may not be used to endorse or promote products 128c2ecf20Sopenharmony_ci * derived from this software without specific prior written permission. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Alternatively, this software may be distributed under the terms of the 158c2ecf20Sopenharmony_ci * GNU General Public License ("GPL"). 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 188c2ecf20Sopenharmony_ci * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 198c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 208c2ecf20Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 218c2ecf20Sopenharmony_ci * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 228c2ecf20Sopenharmony_ci * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 238c2ecf20Sopenharmony_ci * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 248c2ecf20Sopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 258c2ecf20Sopenharmony_ci * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 268c2ecf20Sopenharmony_ci * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 278c2ecf20Sopenharmony_ci * SUCH DAMAGE. 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* 318c2ecf20Sopenharmony_ci * Veritas filesystem driver - filesystem to disk block mapping. 328c2ecf20Sopenharmony_ci */ 338c2ecf20Sopenharmony_ci#include <linux/fs.h> 348c2ecf20Sopenharmony_ci#include <linux/buffer_head.h> 358c2ecf20Sopenharmony_ci#include <linux/kernel.h> 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#include "vxfs.h" 388c2ecf20Sopenharmony_ci#include "vxfs_inode.h" 398c2ecf20Sopenharmony_ci#include "vxfs_extern.h" 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#ifdef DIAGNOSTIC 438c2ecf20Sopenharmony_cistatic void 448c2ecf20Sopenharmony_civxfs_typdump(struct vxfs_typed *typ) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci printk(KERN_DEBUG "type=%Lu ", typ->vt_hdr >> VXFS_TYPED_TYPESHIFT); 478c2ecf20Sopenharmony_ci printk("offset=%Lx ", typ->vt_hdr & VXFS_TYPED_OFFSETMASK); 488c2ecf20Sopenharmony_ci printk("block=%x ", typ->vt_block); 498c2ecf20Sopenharmony_ci printk("size=%x\n", typ->vt_size); 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci#endif 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/** 548c2ecf20Sopenharmony_ci * vxfs_bmap_ext4 - do bmap for ext4 extents 558c2ecf20Sopenharmony_ci * @ip: pointer to the inode we do bmap for 568c2ecf20Sopenharmony_ci * @iblock: logical block. 578c2ecf20Sopenharmony_ci * 588c2ecf20Sopenharmony_ci * Description: 598c2ecf20Sopenharmony_ci * vxfs_bmap_ext4 performs the bmap operation for inodes with 608c2ecf20Sopenharmony_ci * ext4-style extents (which are much like the traditional UNIX 618c2ecf20Sopenharmony_ci * inode organisation). 628c2ecf20Sopenharmony_ci * 638c2ecf20Sopenharmony_ci * Returns: 648c2ecf20Sopenharmony_ci * The physical block number on success, else Zero. 658c2ecf20Sopenharmony_ci */ 668c2ecf20Sopenharmony_cistatic daddr_t 678c2ecf20Sopenharmony_civxfs_bmap_ext4(struct inode *ip, long bn) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci struct super_block *sb = ip->i_sb; 708c2ecf20Sopenharmony_ci struct vxfs_inode_info *vip = VXFS_INO(ip); 718c2ecf20Sopenharmony_ci struct vxfs_sb_info *sbi = VXFS_SBI(sb); 728c2ecf20Sopenharmony_ci unsigned long bsize = sb->s_blocksize; 738c2ecf20Sopenharmony_ci u32 indsize = fs32_to_cpu(sbi, vip->vii_ext4.ve4_indsize); 748c2ecf20Sopenharmony_ci int i; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci if (indsize > sb->s_blocksize) 778c2ecf20Sopenharmony_ci goto fail_size; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci for (i = 0; i < VXFS_NDADDR; i++) { 808c2ecf20Sopenharmony_ci struct direct *d = vip->vii_ext4.ve4_direct + i; 818c2ecf20Sopenharmony_ci if (bn >= 0 && bn < fs32_to_cpu(sbi, d->size)) 828c2ecf20Sopenharmony_ci return (bn + fs32_to_cpu(sbi, d->extent)); 838c2ecf20Sopenharmony_ci bn -= fs32_to_cpu(sbi, d->size); 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci if ((bn / (indsize * indsize * bsize / 4)) == 0) { 878c2ecf20Sopenharmony_ci struct buffer_head *buf; 888c2ecf20Sopenharmony_ci daddr_t bno; 898c2ecf20Sopenharmony_ci __fs32 *indir; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci buf = sb_bread(sb, 928c2ecf20Sopenharmony_ci fs32_to_cpu(sbi, vip->vii_ext4.ve4_indir[0])); 938c2ecf20Sopenharmony_ci if (!buf || !buffer_mapped(buf)) 948c2ecf20Sopenharmony_ci goto fail_buf; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci indir = (__fs32 *)buf->b_data; 978c2ecf20Sopenharmony_ci bno = fs32_to_cpu(sbi, indir[(bn / indsize) % (indsize * bn)]) + 988c2ecf20Sopenharmony_ci (bn % indsize); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci brelse(buf); 1018c2ecf20Sopenharmony_ci return bno; 1028c2ecf20Sopenharmony_ci } else 1038c2ecf20Sopenharmony_ci printk(KERN_WARNING "no matching indir?"); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci return 0; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cifail_size: 1088c2ecf20Sopenharmony_ci printk("vxfs: indirect extent too big!\n"); 1098c2ecf20Sopenharmony_cifail_buf: 1108c2ecf20Sopenharmony_ci return 0; 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci/** 1148c2ecf20Sopenharmony_ci * vxfs_bmap_indir - recursion for vxfs_bmap_typed 1158c2ecf20Sopenharmony_ci * @ip: pointer to the inode we do bmap for 1168c2ecf20Sopenharmony_ci * @indir: indirect block we start reading at 1178c2ecf20Sopenharmony_ci * @size: size of the typed area to search 1188c2ecf20Sopenharmony_ci * @block: partially result from further searches 1198c2ecf20Sopenharmony_ci * 1208c2ecf20Sopenharmony_ci * Description: 1218c2ecf20Sopenharmony_ci * vxfs_bmap_indir reads a &struct vxfs_typed at @indir 1228c2ecf20Sopenharmony_ci * and performs the type-defined action. 1238c2ecf20Sopenharmony_ci * 1248c2ecf20Sopenharmony_ci * Return Value: 1258c2ecf20Sopenharmony_ci * The physical block number on success, else Zero. 1268c2ecf20Sopenharmony_ci * 1278c2ecf20Sopenharmony_ci * Note: 1288c2ecf20Sopenharmony_ci * Kernelstack is rare. Unrecurse? 1298c2ecf20Sopenharmony_ci */ 1308c2ecf20Sopenharmony_cistatic daddr_t 1318c2ecf20Sopenharmony_civxfs_bmap_indir(struct inode *ip, long indir, int size, long block) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci struct vxfs_sb_info *sbi = VXFS_SBI(ip->i_sb); 1348c2ecf20Sopenharmony_ci struct buffer_head *bp = NULL; 1358c2ecf20Sopenharmony_ci daddr_t pblock = 0; 1368c2ecf20Sopenharmony_ci int i; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci for (i = 0; i < size * VXFS_TYPED_PER_BLOCK(ip->i_sb); i++) { 1398c2ecf20Sopenharmony_ci struct vxfs_typed *typ; 1408c2ecf20Sopenharmony_ci int64_t off; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci bp = sb_bread(ip->i_sb, 1438c2ecf20Sopenharmony_ci indir + (i / VXFS_TYPED_PER_BLOCK(ip->i_sb))); 1448c2ecf20Sopenharmony_ci if (!bp || !buffer_mapped(bp)) 1458c2ecf20Sopenharmony_ci return 0; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci typ = ((struct vxfs_typed *)bp->b_data) + 1488c2ecf20Sopenharmony_ci (i % VXFS_TYPED_PER_BLOCK(ip->i_sb)); 1498c2ecf20Sopenharmony_ci off = fs64_to_cpu(sbi, typ->vt_hdr) & VXFS_TYPED_OFFSETMASK; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci if (block < off) { 1528c2ecf20Sopenharmony_ci brelse(bp); 1538c2ecf20Sopenharmony_ci continue; 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci switch ((u_int32_t)(fs64_to_cpu(sbi, typ->vt_hdr) >> 1578c2ecf20Sopenharmony_ci VXFS_TYPED_TYPESHIFT)) { 1588c2ecf20Sopenharmony_ci case VXFS_TYPED_INDIRECT: 1598c2ecf20Sopenharmony_ci pblock = vxfs_bmap_indir(ip, 1608c2ecf20Sopenharmony_ci fs32_to_cpu(sbi, typ->vt_block), 1618c2ecf20Sopenharmony_ci fs32_to_cpu(sbi, typ->vt_size), 1628c2ecf20Sopenharmony_ci block - off); 1638c2ecf20Sopenharmony_ci if (pblock == -2) 1648c2ecf20Sopenharmony_ci break; 1658c2ecf20Sopenharmony_ci goto out; 1668c2ecf20Sopenharmony_ci case VXFS_TYPED_DATA: 1678c2ecf20Sopenharmony_ci if ((block - off) >= fs32_to_cpu(sbi, typ->vt_size)) 1688c2ecf20Sopenharmony_ci break; 1698c2ecf20Sopenharmony_ci pblock = fs32_to_cpu(sbi, typ->vt_block) + block - off; 1708c2ecf20Sopenharmony_ci goto out; 1718c2ecf20Sopenharmony_ci case VXFS_TYPED_INDIRECT_DEV4: 1728c2ecf20Sopenharmony_ci case VXFS_TYPED_DATA_DEV4: { 1738c2ecf20Sopenharmony_ci struct vxfs_typed_dev4 *typ4 = 1748c2ecf20Sopenharmony_ci (struct vxfs_typed_dev4 *)typ; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci printk(KERN_INFO "\n\nTYPED_DEV4 detected!\n"); 1778c2ecf20Sopenharmony_ci printk(KERN_INFO "block: %llu\tsize: %lld\tdev: %d\n", 1788c2ecf20Sopenharmony_ci fs64_to_cpu(sbi, typ4->vd4_block), 1798c2ecf20Sopenharmony_ci fs64_to_cpu(sbi, typ4->vd4_size), 1808c2ecf20Sopenharmony_ci fs32_to_cpu(sbi, typ4->vd4_dev)); 1818c2ecf20Sopenharmony_ci goto fail; 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci default: 1848c2ecf20Sopenharmony_ci printk(KERN_ERR "%s:%d vt_hdr %llu\n", __func__, 1858c2ecf20Sopenharmony_ci __LINE__, fs64_to_cpu(sbi, typ->vt_hdr)); 1868c2ecf20Sopenharmony_ci BUG(); 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci brelse(bp); 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cifail: 1928c2ecf20Sopenharmony_ci pblock = 0; 1938c2ecf20Sopenharmony_ciout: 1948c2ecf20Sopenharmony_ci brelse(bp); 1958c2ecf20Sopenharmony_ci return (pblock); 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci/** 1998c2ecf20Sopenharmony_ci * vxfs_bmap_typed - bmap for typed extents 2008c2ecf20Sopenharmony_ci * @ip: pointer to the inode we do bmap for 2018c2ecf20Sopenharmony_ci * @iblock: logical block 2028c2ecf20Sopenharmony_ci * 2038c2ecf20Sopenharmony_ci * Description: 2048c2ecf20Sopenharmony_ci * Performs the bmap operation for typed extents. 2058c2ecf20Sopenharmony_ci * 2068c2ecf20Sopenharmony_ci * Return Value: 2078c2ecf20Sopenharmony_ci * The physical block number on success, else Zero. 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_cistatic daddr_t 2108c2ecf20Sopenharmony_civxfs_bmap_typed(struct inode *ip, long iblock) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci struct vxfs_inode_info *vip = VXFS_INO(ip); 2138c2ecf20Sopenharmony_ci struct vxfs_sb_info *sbi = VXFS_SBI(ip->i_sb); 2148c2ecf20Sopenharmony_ci daddr_t pblock = 0; 2158c2ecf20Sopenharmony_ci int i; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci for (i = 0; i < VXFS_NTYPED; i++) { 2188c2ecf20Sopenharmony_ci struct vxfs_typed *typ = vip->vii_org.typed + i; 2198c2ecf20Sopenharmony_ci u64 hdr = fs64_to_cpu(sbi, typ->vt_hdr); 2208c2ecf20Sopenharmony_ci int64_t off = (hdr & VXFS_TYPED_OFFSETMASK); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci#ifdef DIAGNOSTIC 2238c2ecf20Sopenharmony_ci vxfs_typdump(typ); 2248c2ecf20Sopenharmony_ci#endif 2258c2ecf20Sopenharmony_ci if (iblock < off) 2268c2ecf20Sopenharmony_ci continue; 2278c2ecf20Sopenharmony_ci switch ((u32)(hdr >> VXFS_TYPED_TYPESHIFT)) { 2288c2ecf20Sopenharmony_ci case VXFS_TYPED_INDIRECT: 2298c2ecf20Sopenharmony_ci pblock = vxfs_bmap_indir(ip, 2308c2ecf20Sopenharmony_ci fs32_to_cpu(sbi, typ->vt_block), 2318c2ecf20Sopenharmony_ci fs32_to_cpu(sbi, typ->vt_size), 2328c2ecf20Sopenharmony_ci iblock - off); 2338c2ecf20Sopenharmony_ci if (pblock == -2) 2348c2ecf20Sopenharmony_ci break; 2358c2ecf20Sopenharmony_ci return (pblock); 2368c2ecf20Sopenharmony_ci case VXFS_TYPED_DATA: 2378c2ecf20Sopenharmony_ci if ((iblock - off) < fs32_to_cpu(sbi, typ->vt_size)) 2388c2ecf20Sopenharmony_ci return (fs32_to_cpu(sbi, typ->vt_block) + 2398c2ecf20Sopenharmony_ci iblock - off); 2408c2ecf20Sopenharmony_ci break; 2418c2ecf20Sopenharmony_ci case VXFS_TYPED_INDIRECT_DEV4: 2428c2ecf20Sopenharmony_ci case VXFS_TYPED_DATA_DEV4: { 2438c2ecf20Sopenharmony_ci struct vxfs_typed_dev4 *typ4 = 2448c2ecf20Sopenharmony_ci (struct vxfs_typed_dev4 *)typ; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci printk(KERN_INFO "\n\nTYPED_DEV4 detected!\n"); 2478c2ecf20Sopenharmony_ci printk(KERN_INFO "block: %llu\tsize: %lld\tdev: %d\n", 2488c2ecf20Sopenharmony_ci fs64_to_cpu(sbi, typ4->vd4_block), 2498c2ecf20Sopenharmony_ci fs64_to_cpu(sbi, typ4->vd4_size), 2508c2ecf20Sopenharmony_ci fs32_to_cpu(sbi, typ4->vd4_dev)); 2518c2ecf20Sopenharmony_ci return 0; 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci default: 2548c2ecf20Sopenharmony_ci BUG(); 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci return 0; 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci/** 2628c2ecf20Sopenharmony_ci * vxfs_bmap1 - vxfs-internal bmap operation 2638c2ecf20Sopenharmony_ci * @ip: pointer to the inode we do bmap for 2648c2ecf20Sopenharmony_ci * @iblock: logical block 2658c2ecf20Sopenharmony_ci * 2668c2ecf20Sopenharmony_ci * Description: 2678c2ecf20Sopenharmony_ci * vxfs_bmap1 perfoms a logical to physical block mapping 2688c2ecf20Sopenharmony_ci * for vxfs-internal purposes. 2698c2ecf20Sopenharmony_ci * 2708c2ecf20Sopenharmony_ci * Return Value: 2718c2ecf20Sopenharmony_ci * The physical block number on success, else Zero. 2728c2ecf20Sopenharmony_ci */ 2738c2ecf20Sopenharmony_cidaddr_t 2748c2ecf20Sopenharmony_civxfs_bmap1(struct inode *ip, long iblock) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci struct vxfs_inode_info *vip = VXFS_INO(ip); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (VXFS_ISEXT4(vip)) 2798c2ecf20Sopenharmony_ci return vxfs_bmap_ext4(ip, iblock); 2808c2ecf20Sopenharmony_ci if (VXFS_ISTYPED(vip)) 2818c2ecf20Sopenharmony_ci return vxfs_bmap_typed(ip, iblock); 2828c2ecf20Sopenharmony_ci if (VXFS_ISNONE(vip)) 2838c2ecf20Sopenharmony_ci goto unsupp; 2848c2ecf20Sopenharmony_ci if (VXFS_ISIMMED(vip)) 2858c2ecf20Sopenharmony_ci goto unsupp; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci printk(KERN_WARNING "vxfs: inode %ld has no valid orgtype (%x)\n", 2888c2ecf20Sopenharmony_ci ip->i_ino, vip->vii_orgtype); 2898c2ecf20Sopenharmony_ci BUG(); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ciunsupp: 2928c2ecf20Sopenharmony_ci printk(KERN_WARNING "vxfs: inode %ld has an unsupported orgtype (%x)\n", 2938c2ecf20Sopenharmony_ci ip->i_ino, vip->vii_orgtype); 2948c2ecf20Sopenharmony_ci return 0; 2958c2ecf20Sopenharmony_ci} 296