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