1*0b1e987cSChristoph Hellwig // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * Copyright (c) 2000-2001 Christoph Hellwig.
41da177e4SLinus Torvalds */
51da177e4SLinus Torvalds
61da177e4SLinus Torvalds /*
71da177e4SLinus Torvalds * Veritas filesystem driver - filesystem to disk block mapping.
81da177e4SLinus Torvalds */
91da177e4SLinus Torvalds #include <linux/fs.h>
101da177e4SLinus Torvalds #include <linux/buffer_head.h>
111da177e4SLinus Torvalds #include <linux/kernel.h>
121da177e4SLinus Torvalds
131da177e4SLinus Torvalds #include "vxfs.h"
141da177e4SLinus Torvalds #include "vxfs_inode.h"
156e1e8e11SAdrian Bunk #include "vxfs_extern.h"
161da177e4SLinus Torvalds
171da177e4SLinus Torvalds
181da177e4SLinus Torvalds #ifdef DIAGNOSTIC
191da177e4SLinus Torvalds static void
vxfs_typdump(struct vxfs_typed * typ)201da177e4SLinus Torvalds vxfs_typdump(struct vxfs_typed *typ)
211da177e4SLinus Torvalds {
221da177e4SLinus Torvalds printk(KERN_DEBUG "type=%Lu ", typ->vt_hdr >> VXFS_TYPED_TYPESHIFT);
231da177e4SLinus Torvalds printk("offset=%Lx ", typ->vt_hdr & VXFS_TYPED_OFFSETMASK);
241da177e4SLinus Torvalds printk("block=%x ", typ->vt_block);
251da177e4SLinus Torvalds printk("size=%x\n", typ->vt_size);
261da177e4SLinus Torvalds }
271da177e4SLinus Torvalds #endif
281da177e4SLinus Torvalds
291da177e4SLinus Torvalds /**
301da177e4SLinus Torvalds * vxfs_bmap_ext4 - do bmap for ext4 extents
311da177e4SLinus Torvalds * @ip: pointer to the inode we do bmap for
321da177e4SLinus Torvalds * @iblock: logical block.
331da177e4SLinus Torvalds *
341da177e4SLinus Torvalds * Description:
351da177e4SLinus Torvalds * vxfs_bmap_ext4 performs the bmap operation for inodes with
361da177e4SLinus Torvalds * ext4-style extents (which are much like the traditional UNIX
371da177e4SLinus Torvalds * inode organisation).
381da177e4SLinus Torvalds *
391da177e4SLinus Torvalds * Returns:
401da177e4SLinus Torvalds * The physical block number on success, else Zero.
411da177e4SLinus Torvalds */
421da177e4SLinus Torvalds static daddr_t
vxfs_bmap_ext4(struct inode * ip,long bn)431da177e4SLinus Torvalds vxfs_bmap_ext4(struct inode *ip, long bn)
441da177e4SLinus Torvalds {
451da177e4SLinus Torvalds struct super_block *sb = ip->i_sb;
461da177e4SLinus Torvalds struct vxfs_inode_info *vip = VXFS_INO(ip);
470d83f7fcSKrzysztof Błaszkowski struct vxfs_sb_info *sbi = VXFS_SBI(sb);
481da177e4SLinus Torvalds unsigned long bsize = sb->s_blocksize;
490d83f7fcSKrzysztof Błaszkowski u32 indsize = fs32_to_cpu(sbi, vip->vii_ext4.ve4_indsize);
501da177e4SLinus Torvalds int i;
511da177e4SLinus Torvalds
521da177e4SLinus Torvalds if (indsize > sb->s_blocksize)
531da177e4SLinus Torvalds goto fail_size;
541da177e4SLinus Torvalds
551da177e4SLinus Torvalds for (i = 0; i < VXFS_NDADDR; i++) {
561da177e4SLinus Torvalds struct direct *d = vip->vii_ext4.ve4_direct + i;
570d83f7fcSKrzysztof Błaszkowski if (bn >= 0 && bn < fs32_to_cpu(sbi, d->size))
580d83f7fcSKrzysztof Błaszkowski return (bn + fs32_to_cpu(sbi, d->extent));
590d83f7fcSKrzysztof Błaszkowski bn -= fs32_to_cpu(sbi, d->size);
601da177e4SLinus Torvalds }
611da177e4SLinus Torvalds
621da177e4SLinus Torvalds if ((bn / (indsize * indsize * bsize / 4)) == 0) {
631da177e4SLinus Torvalds struct buffer_head *buf;
641da177e4SLinus Torvalds daddr_t bno;
650d83f7fcSKrzysztof Błaszkowski __fs32 *indir;
661da177e4SLinus Torvalds
670d83f7fcSKrzysztof Błaszkowski buf = sb_bread(sb,
680d83f7fcSKrzysztof Błaszkowski fs32_to_cpu(sbi, vip->vii_ext4.ve4_indir[0]));
691da177e4SLinus Torvalds if (!buf || !buffer_mapped(buf))
701da177e4SLinus Torvalds goto fail_buf;
711da177e4SLinus Torvalds
720d83f7fcSKrzysztof Błaszkowski indir = (__fs32 *)buf->b_data;
730d83f7fcSKrzysztof Błaszkowski bno = fs32_to_cpu(sbi, indir[(bn / indsize) % (indsize * bn)]) +
740d83f7fcSKrzysztof Błaszkowski (bn % indsize);
751da177e4SLinus Torvalds
761da177e4SLinus Torvalds brelse(buf);
771da177e4SLinus Torvalds return bno;
781da177e4SLinus Torvalds } else
791da177e4SLinus Torvalds printk(KERN_WARNING "no matching indir?");
801da177e4SLinus Torvalds
811da177e4SLinus Torvalds return 0;
821da177e4SLinus Torvalds
831da177e4SLinus Torvalds fail_size:
848cb681b9SPekka Enberg printk("vxfs: indirect extent too big!\n");
851da177e4SLinus Torvalds fail_buf:
861da177e4SLinus Torvalds return 0;
871da177e4SLinus Torvalds }
881da177e4SLinus Torvalds
891da177e4SLinus Torvalds /**
901da177e4SLinus Torvalds * vxfs_bmap_indir - recursion for vxfs_bmap_typed
911da177e4SLinus Torvalds * @ip: pointer to the inode we do bmap for
921da177e4SLinus Torvalds * @indir: indirect block we start reading at
931da177e4SLinus Torvalds * @size: size of the typed area to search
941da177e4SLinus Torvalds * @block: partially result from further searches
951da177e4SLinus Torvalds *
961da177e4SLinus Torvalds * Description:
971da177e4SLinus Torvalds * vxfs_bmap_indir reads a &struct vxfs_typed at @indir
981da177e4SLinus Torvalds * and performs the type-defined action.
991da177e4SLinus Torvalds *
1001da177e4SLinus Torvalds * Return Value:
1011da177e4SLinus Torvalds * The physical block number on success, else Zero.
1021da177e4SLinus Torvalds *
1031da177e4SLinus Torvalds * Note:
1041da177e4SLinus Torvalds * Kernelstack is rare. Unrecurse?
1051da177e4SLinus Torvalds */
1061da177e4SLinus Torvalds static daddr_t
vxfs_bmap_indir(struct inode * ip,long indir,int size,long block)1071da177e4SLinus Torvalds vxfs_bmap_indir(struct inode *ip, long indir, int size, long block)
1081da177e4SLinus Torvalds {
1090d83f7fcSKrzysztof Błaszkowski struct vxfs_sb_info *sbi = VXFS_SBI(ip->i_sb);
1101da177e4SLinus Torvalds struct buffer_head *bp = NULL;
1111da177e4SLinus Torvalds daddr_t pblock = 0;
1121da177e4SLinus Torvalds int i;
1131da177e4SLinus Torvalds
1141da177e4SLinus Torvalds for (i = 0; i < size * VXFS_TYPED_PER_BLOCK(ip->i_sb); i++) {
1151da177e4SLinus Torvalds struct vxfs_typed *typ;
1161da177e4SLinus Torvalds int64_t off;
1171da177e4SLinus Torvalds
1181da177e4SLinus Torvalds bp = sb_bread(ip->i_sb,
1191da177e4SLinus Torvalds indir + (i / VXFS_TYPED_PER_BLOCK(ip->i_sb)));
12082f703bbSDmitriy Monakhov if (!bp || !buffer_mapped(bp))
1211da177e4SLinus Torvalds return 0;
1221da177e4SLinus Torvalds
1231da177e4SLinus Torvalds typ = ((struct vxfs_typed *)bp->b_data) +
1241da177e4SLinus Torvalds (i % VXFS_TYPED_PER_BLOCK(ip->i_sb));
1250d83f7fcSKrzysztof Błaszkowski off = fs64_to_cpu(sbi, typ->vt_hdr) & VXFS_TYPED_OFFSETMASK;
1261da177e4SLinus Torvalds
1271da177e4SLinus Torvalds if (block < off) {
1281da177e4SLinus Torvalds brelse(bp);
1291da177e4SLinus Torvalds continue;
1301da177e4SLinus Torvalds }
1311da177e4SLinus Torvalds
1320d83f7fcSKrzysztof Błaszkowski switch ((u_int32_t)(fs64_to_cpu(sbi, typ->vt_hdr) >>
1330d83f7fcSKrzysztof Błaszkowski VXFS_TYPED_TYPESHIFT)) {
1341da177e4SLinus Torvalds case VXFS_TYPED_INDIRECT:
1350d83f7fcSKrzysztof Błaszkowski pblock = vxfs_bmap_indir(ip,
1360d83f7fcSKrzysztof Błaszkowski fs32_to_cpu(sbi, typ->vt_block),
1370d83f7fcSKrzysztof Błaszkowski fs32_to_cpu(sbi, typ->vt_size),
1380d83f7fcSKrzysztof Błaszkowski block - off);
1391da177e4SLinus Torvalds if (pblock == -2)
1401da177e4SLinus Torvalds break;
1411da177e4SLinus Torvalds goto out;
1421da177e4SLinus Torvalds case VXFS_TYPED_DATA:
1430d83f7fcSKrzysztof Błaszkowski if ((block - off) >= fs32_to_cpu(sbi, typ->vt_size))
1441da177e4SLinus Torvalds break;
1450d83f7fcSKrzysztof Błaszkowski pblock = fs32_to_cpu(sbi, typ->vt_block) + block - off;
1461da177e4SLinus Torvalds goto out;
1471da177e4SLinus Torvalds case VXFS_TYPED_INDIRECT_DEV4:
1481da177e4SLinus Torvalds case VXFS_TYPED_DATA_DEV4: {
1491da177e4SLinus Torvalds struct vxfs_typed_dev4 *typ4 =
1501da177e4SLinus Torvalds (struct vxfs_typed_dev4 *)typ;
1511da177e4SLinus Torvalds
1521da177e4SLinus Torvalds printk(KERN_INFO "\n\nTYPED_DEV4 detected!\n");
1530d83f7fcSKrzysztof Błaszkowski printk(KERN_INFO "block: %llu\tsize: %lld\tdev: %d\n",
1540d83f7fcSKrzysztof Błaszkowski fs64_to_cpu(sbi, typ4->vd4_block),
1550d83f7fcSKrzysztof Błaszkowski fs64_to_cpu(sbi, typ4->vd4_size),
1560d83f7fcSKrzysztof Błaszkowski fs32_to_cpu(sbi, typ4->vd4_dev));
1571da177e4SLinus Torvalds goto fail;
1581da177e4SLinus Torvalds }
1591da177e4SLinus Torvalds default:
1600d83f7fcSKrzysztof Błaszkowski printk(KERN_ERR "%s:%d vt_hdr %llu\n", __func__,
1610d83f7fcSKrzysztof Błaszkowski __LINE__, fs64_to_cpu(sbi, typ->vt_hdr));
1621da177e4SLinus Torvalds BUG();
1631da177e4SLinus Torvalds }
1641da177e4SLinus Torvalds brelse(bp);
1651da177e4SLinus Torvalds }
1661da177e4SLinus Torvalds
1671da177e4SLinus Torvalds fail:
1681da177e4SLinus Torvalds pblock = 0;
1691da177e4SLinus Torvalds out:
1701da177e4SLinus Torvalds brelse(bp);
1711da177e4SLinus Torvalds return (pblock);
1721da177e4SLinus Torvalds }
1731da177e4SLinus Torvalds
1741da177e4SLinus Torvalds /**
1751da177e4SLinus Torvalds * vxfs_bmap_typed - bmap for typed extents
1761da177e4SLinus Torvalds * @ip: pointer to the inode we do bmap for
1771da177e4SLinus Torvalds * @iblock: logical block
1781da177e4SLinus Torvalds *
1791da177e4SLinus Torvalds * Description:
1801da177e4SLinus Torvalds * Performs the bmap operation for typed extents.
1811da177e4SLinus Torvalds *
1821da177e4SLinus Torvalds * Return Value:
1831da177e4SLinus Torvalds * The physical block number on success, else Zero.
1841da177e4SLinus Torvalds */
1851da177e4SLinus Torvalds static daddr_t
vxfs_bmap_typed(struct inode * ip,long iblock)1861da177e4SLinus Torvalds vxfs_bmap_typed(struct inode *ip, long iblock)
1871da177e4SLinus Torvalds {
1881da177e4SLinus Torvalds struct vxfs_inode_info *vip = VXFS_INO(ip);
1890d83f7fcSKrzysztof Błaszkowski struct vxfs_sb_info *sbi = VXFS_SBI(ip->i_sb);
1901da177e4SLinus Torvalds daddr_t pblock = 0;
1911da177e4SLinus Torvalds int i;
1921da177e4SLinus Torvalds
1931da177e4SLinus Torvalds for (i = 0; i < VXFS_NTYPED; i++) {
1941da177e4SLinus Torvalds struct vxfs_typed *typ = vip->vii_org.typed + i;
1950d83f7fcSKrzysztof Błaszkowski u64 hdr = fs64_to_cpu(sbi, typ->vt_hdr);
1960d83f7fcSKrzysztof Błaszkowski int64_t off = (hdr & VXFS_TYPED_OFFSETMASK);
1971da177e4SLinus Torvalds
1981da177e4SLinus Torvalds #ifdef DIAGNOSTIC
1991da177e4SLinus Torvalds vxfs_typdump(typ);
2001da177e4SLinus Torvalds #endif
2011da177e4SLinus Torvalds if (iblock < off)
2021da177e4SLinus Torvalds continue;
2030d83f7fcSKrzysztof Błaszkowski switch ((u32)(hdr >> VXFS_TYPED_TYPESHIFT)) {
2041da177e4SLinus Torvalds case VXFS_TYPED_INDIRECT:
2050d83f7fcSKrzysztof Błaszkowski pblock = vxfs_bmap_indir(ip,
2060d83f7fcSKrzysztof Błaszkowski fs32_to_cpu(sbi, typ->vt_block),
2070d83f7fcSKrzysztof Błaszkowski fs32_to_cpu(sbi, typ->vt_size),
2080d83f7fcSKrzysztof Błaszkowski iblock - off);
2091da177e4SLinus Torvalds if (pblock == -2)
2101da177e4SLinus Torvalds break;
2111da177e4SLinus Torvalds return (pblock);
2121da177e4SLinus Torvalds case VXFS_TYPED_DATA:
2130d83f7fcSKrzysztof Błaszkowski if ((iblock - off) < fs32_to_cpu(sbi, typ->vt_size))
2140d83f7fcSKrzysztof Błaszkowski return (fs32_to_cpu(sbi, typ->vt_block) +
2150d83f7fcSKrzysztof Błaszkowski iblock - off);
2161da177e4SLinus Torvalds break;
2171da177e4SLinus Torvalds case VXFS_TYPED_INDIRECT_DEV4:
2181da177e4SLinus Torvalds case VXFS_TYPED_DATA_DEV4: {
2191da177e4SLinus Torvalds struct vxfs_typed_dev4 *typ4 =
2201da177e4SLinus Torvalds (struct vxfs_typed_dev4 *)typ;
2211da177e4SLinus Torvalds
2221da177e4SLinus Torvalds printk(KERN_INFO "\n\nTYPED_DEV4 detected!\n");
2230d83f7fcSKrzysztof Błaszkowski printk(KERN_INFO "block: %llu\tsize: %lld\tdev: %d\n",
2240d83f7fcSKrzysztof Błaszkowski fs64_to_cpu(sbi, typ4->vd4_block),
2250d83f7fcSKrzysztof Błaszkowski fs64_to_cpu(sbi, typ4->vd4_size),
2260d83f7fcSKrzysztof Błaszkowski fs32_to_cpu(sbi, typ4->vd4_dev));
2271da177e4SLinus Torvalds return 0;
2281da177e4SLinus Torvalds }
2291da177e4SLinus Torvalds default:
2301da177e4SLinus Torvalds BUG();
2311da177e4SLinus Torvalds }
2321da177e4SLinus Torvalds }
2331da177e4SLinus Torvalds
2341da177e4SLinus Torvalds return 0;
2351da177e4SLinus Torvalds }
2361da177e4SLinus Torvalds
2371da177e4SLinus Torvalds /**
2381da177e4SLinus Torvalds * vxfs_bmap1 - vxfs-internal bmap operation
2391da177e4SLinus Torvalds * @ip: pointer to the inode we do bmap for
2401da177e4SLinus Torvalds * @iblock: logical block
2411da177e4SLinus Torvalds *
2421da177e4SLinus Torvalds * Description:
2431da177e4SLinus Torvalds * vxfs_bmap1 perfoms a logical to physical block mapping
2441da177e4SLinus Torvalds * for vxfs-internal purposes.
2451da177e4SLinus Torvalds *
2461da177e4SLinus Torvalds * Return Value:
2471da177e4SLinus Torvalds * The physical block number on success, else Zero.
2481da177e4SLinus Torvalds */
2491da177e4SLinus Torvalds daddr_t
vxfs_bmap1(struct inode * ip,long iblock)2501da177e4SLinus Torvalds vxfs_bmap1(struct inode *ip, long iblock)
2511da177e4SLinus Torvalds {
2521da177e4SLinus Torvalds struct vxfs_inode_info *vip = VXFS_INO(ip);
2531da177e4SLinus Torvalds
2541da177e4SLinus Torvalds if (VXFS_ISEXT4(vip))
2551da177e4SLinus Torvalds return vxfs_bmap_ext4(ip, iblock);
2561da177e4SLinus Torvalds if (VXFS_ISTYPED(vip))
2571da177e4SLinus Torvalds return vxfs_bmap_typed(ip, iblock);
2581da177e4SLinus Torvalds if (VXFS_ISNONE(vip))
2591da177e4SLinus Torvalds goto unsupp;
2601da177e4SLinus Torvalds if (VXFS_ISIMMED(vip))
2611da177e4SLinus Torvalds goto unsupp;
2621da177e4SLinus Torvalds
2631da177e4SLinus Torvalds printk(KERN_WARNING "vxfs: inode %ld has no valid orgtype (%x)\n",
2641da177e4SLinus Torvalds ip->i_ino, vip->vii_orgtype);
2651da177e4SLinus Torvalds BUG();
2661da177e4SLinus Torvalds
2671da177e4SLinus Torvalds unsupp:
2681da177e4SLinus Torvalds printk(KERN_WARNING "vxfs: inode %ld has an unsupported orgtype (%x)\n",
2691da177e4SLinus Torvalds ip->i_ino, vip->vii_orgtype);
2701da177e4SLinus Torvalds return 0;
2711da177e4SLinus Torvalds }
272