xref: /kernel/linux/linux-6.6/fs/freevxfs/vxfs_bmap.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2000-2001 Christoph Hellwig.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci/*
762306a36Sopenharmony_ci * Veritas filesystem driver - filesystem to disk block mapping.
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci#include <linux/fs.h>
1062306a36Sopenharmony_ci#include <linux/buffer_head.h>
1162306a36Sopenharmony_ci#include <linux/kernel.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include "vxfs.h"
1462306a36Sopenharmony_ci#include "vxfs_inode.h"
1562306a36Sopenharmony_ci#include "vxfs_extern.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#ifdef DIAGNOSTIC
1962306a36Sopenharmony_cistatic void
2062306a36Sopenharmony_civxfs_typdump(struct vxfs_typed *typ)
2162306a36Sopenharmony_ci{
2262306a36Sopenharmony_ci	printk(KERN_DEBUG "type=%Lu ", typ->vt_hdr >> VXFS_TYPED_TYPESHIFT);
2362306a36Sopenharmony_ci	printk("offset=%Lx ", typ->vt_hdr & VXFS_TYPED_OFFSETMASK);
2462306a36Sopenharmony_ci	printk("block=%x ", typ->vt_block);
2562306a36Sopenharmony_ci	printk("size=%x\n", typ->vt_size);
2662306a36Sopenharmony_ci}
2762306a36Sopenharmony_ci#endif
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci/**
3062306a36Sopenharmony_ci * vxfs_bmap_ext4 - do bmap for ext4 extents
3162306a36Sopenharmony_ci * @ip:		pointer to the inode we do bmap for
3262306a36Sopenharmony_ci * @iblock:	logical block.
3362306a36Sopenharmony_ci *
3462306a36Sopenharmony_ci * Description:
3562306a36Sopenharmony_ci *   vxfs_bmap_ext4 performs the bmap operation for inodes with
3662306a36Sopenharmony_ci *   ext4-style extents (which are much like the traditional UNIX
3762306a36Sopenharmony_ci *   inode organisation).
3862306a36Sopenharmony_ci *
3962306a36Sopenharmony_ci * Returns:
4062306a36Sopenharmony_ci *   The physical block number on success, else Zero.
4162306a36Sopenharmony_ci */
4262306a36Sopenharmony_cistatic daddr_t
4362306a36Sopenharmony_civxfs_bmap_ext4(struct inode *ip, long bn)
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci	struct super_block *sb = ip->i_sb;
4662306a36Sopenharmony_ci	struct vxfs_inode_info *vip = VXFS_INO(ip);
4762306a36Sopenharmony_ci	struct vxfs_sb_info *sbi = VXFS_SBI(sb);
4862306a36Sopenharmony_ci	unsigned long bsize = sb->s_blocksize;
4962306a36Sopenharmony_ci	u32 indsize = fs32_to_cpu(sbi, vip->vii_ext4.ve4_indsize);
5062306a36Sopenharmony_ci	int i;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	if (indsize > sb->s_blocksize)
5362306a36Sopenharmony_ci		goto fail_size;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	for (i = 0; i < VXFS_NDADDR; i++) {
5662306a36Sopenharmony_ci		struct direct *d = vip->vii_ext4.ve4_direct + i;
5762306a36Sopenharmony_ci		if (bn >= 0 && bn < fs32_to_cpu(sbi, d->size))
5862306a36Sopenharmony_ci			return (bn + fs32_to_cpu(sbi, d->extent));
5962306a36Sopenharmony_ci		bn -= fs32_to_cpu(sbi, d->size);
6062306a36Sopenharmony_ci	}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	if ((bn / (indsize * indsize * bsize / 4)) == 0) {
6362306a36Sopenharmony_ci		struct buffer_head *buf;
6462306a36Sopenharmony_ci		daddr_t	bno;
6562306a36Sopenharmony_ci		__fs32 *indir;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci		buf = sb_bread(sb,
6862306a36Sopenharmony_ci			fs32_to_cpu(sbi, vip->vii_ext4.ve4_indir[0]));
6962306a36Sopenharmony_ci		if (!buf || !buffer_mapped(buf))
7062306a36Sopenharmony_ci			goto fail_buf;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci		indir = (__fs32 *)buf->b_data;
7362306a36Sopenharmony_ci		bno = fs32_to_cpu(sbi, indir[(bn / indsize) % (indsize * bn)]) +
7462306a36Sopenharmony_ci			(bn % indsize);
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci		brelse(buf);
7762306a36Sopenharmony_ci		return bno;
7862306a36Sopenharmony_ci	} else
7962306a36Sopenharmony_ci		printk(KERN_WARNING "no matching indir?");
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	return 0;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cifail_size:
8462306a36Sopenharmony_ci	printk("vxfs: indirect extent too big!\n");
8562306a36Sopenharmony_cifail_buf:
8662306a36Sopenharmony_ci	return 0;
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci/**
9062306a36Sopenharmony_ci * vxfs_bmap_indir - recursion for vxfs_bmap_typed
9162306a36Sopenharmony_ci * @ip:		pointer to the inode we do bmap for
9262306a36Sopenharmony_ci * @indir:	indirect block we start reading at
9362306a36Sopenharmony_ci * @size:	size of the typed area to search
9462306a36Sopenharmony_ci * @block:	partially result from further searches
9562306a36Sopenharmony_ci *
9662306a36Sopenharmony_ci * Description:
9762306a36Sopenharmony_ci *   vxfs_bmap_indir reads a &struct vxfs_typed at @indir
9862306a36Sopenharmony_ci *   and performs the type-defined action.
9962306a36Sopenharmony_ci *
10062306a36Sopenharmony_ci * Return Value:
10162306a36Sopenharmony_ci *   The physical block number on success, else Zero.
10262306a36Sopenharmony_ci *
10362306a36Sopenharmony_ci * Note:
10462306a36Sopenharmony_ci *   Kernelstack is rare.  Unrecurse?
10562306a36Sopenharmony_ci */
10662306a36Sopenharmony_cistatic daddr_t
10762306a36Sopenharmony_civxfs_bmap_indir(struct inode *ip, long indir, int size, long block)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	struct vxfs_sb_info		*sbi = VXFS_SBI(ip->i_sb);
11062306a36Sopenharmony_ci	struct buffer_head		*bp = NULL;
11162306a36Sopenharmony_ci	daddr_t				pblock = 0;
11262306a36Sopenharmony_ci	int				i;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	for (i = 0; i < size * VXFS_TYPED_PER_BLOCK(ip->i_sb); i++) {
11562306a36Sopenharmony_ci		struct vxfs_typed	*typ;
11662306a36Sopenharmony_ci		int64_t			off;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci		bp = sb_bread(ip->i_sb,
11962306a36Sopenharmony_ci				indir + (i / VXFS_TYPED_PER_BLOCK(ip->i_sb)));
12062306a36Sopenharmony_ci		if (!bp || !buffer_mapped(bp))
12162306a36Sopenharmony_ci			return 0;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci		typ = ((struct vxfs_typed *)bp->b_data) +
12462306a36Sopenharmony_ci			(i % VXFS_TYPED_PER_BLOCK(ip->i_sb));
12562306a36Sopenharmony_ci		off = fs64_to_cpu(sbi, typ->vt_hdr) & VXFS_TYPED_OFFSETMASK;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci		if (block < off) {
12862306a36Sopenharmony_ci			brelse(bp);
12962306a36Sopenharmony_ci			continue;
13062306a36Sopenharmony_ci		}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci		switch ((u_int32_t)(fs64_to_cpu(sbi, typ->vt_hdr) >>
13362306a36Sopenharmony_ci				VXFS_TYPED_TYPESHIFT)) {
13462306a36Sopenharmony_ci		case VXFS_TYPED_INDIRECT:
13562306a36Sopenharmony_ci			pblock = vxfs_bmap_indir(ip,
13662306a36Sopenharmony_ci					fs32_to_cpu(sbi, typ->vt_block),
13762306a36Sopenharmony_ci					fs32_to_cpu(sbi, typ->vt_size),
13862306a36Sopenharmony_ci					block - off);
13962306a36Sopenharmony_ci			if (pblock == -2)
14062306a36Sopenharmony_ci				break;
14162306a36Sopenharmony_ci			goto out;
14262306a36Sopenharmony_ci		case VXFS_TYPED_DATA:
14362306a36Sopenharmony_ci			if ((block - off) >= fs32_to_cpu(sbi, typ->vt_size))
14462306a36Sopenharmony_ci				break;
14562306a36Sopenharmony_ci			pblock = fs32_to_cpu(sbi, typ->vt_block) + block - off;
14662306a36Sopenharmony_ci			goto out;
14762306a36Sopenharmony_ci		case VXFS_TYPED_INDIRECT_DEV4:
14862306a36Sopenharmony_ci		case VXFS_TYPED_DATA_DEV4: {
14962306a36Sopenharmony_ci			struct vxfs_typed_dev4	*typ4 =
15062306a36Sopenharmony_ci				(struct vxfs_typed_dev4 *)typ;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci			printk(KERN_INFO "\n\nTYPED_DEV4 detected!\n");
15362306a36Sopenharmony_ci			printk(KERN_INFO "block: %llu\tsize: %lld\tdev: %d\n",
15462306a36Sopenharmony_ci			       fs64_to_cpu(sbi, typ4->vd4_block),
15562306a36Sopenharmony_ci			       fs64_to_cpu(sbi, typ4->vd4_size),
15662306a36Sopenharmony_ci			       fs32_to_cpu(sbi, typ4->vd4_dev));
15762306a36Sopenharmony_ci			goto fail;
15862306a36Sopenharmony_ci		}
15962306a36Sopenharmony_ci		default:
16062306a36Sopenharmony_ci			printk(KERN_ERR "%s:%d vt_hdr %llu\n", __func__,
16162306a36Sopenharmony_ci				__LINE__, fs64_to_cpu(sbi, typ->vt_hdr));
16262306a36Sopenharmony_ci			BUG();
16362306a36Sopenharmony_ci		}
16462306a36Sopenharmony_ci		brelse(bp);
16562306a36Sopenharmony_ci	}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_cifail:
16862306a36Sopenharmony_ci	pblock = 0;
16962306a36Sopenharmony_ciout:
17062306a36Sopenharmony_ci	brelse(bp);
17162306a36Sopenharmony_ci	return (pblock);
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci/**
17562306a36Sopenharmony_ci * vxfs_bmap_typed - bmap for typed extents
17662306a36Sopenharmony_ci * @ip:		pointer to the inode we do bmap for
17762306a36Sopenharmony_ci * @iblock:	logical block
17862306a36Sopenharmony_ci *
17962306a36Sopenharmony_ci * Description:
18062306a36Sopenharmony_ci *   Performs the bmap operation for typed extents.
18162306a36Sopenharmony_ci *
18262306a36Sopenharmony_ci * Return Value:
18362306a36Sopenharmony_ci *   The physical block number on success, else Zero.
18462306a36Sopenharmony_ci */
18562306a36Sopenharmony_cistatic daddr_t
18662306a36Sopenharmony_civxfs_bmap_typed(struct inode *ip, long iblock)
18762306a36Sopenharmony_ci{
18862306a36Sopenharmony_ci	struct vxfs_inode_info		*vip = VXFS_INO(ip);
18962306a36Sopenharmony_ci	struct vxfs_sb_info		*sbi = VXFS_SBI(ip->i_sb);
19062306a36Sopenharmony_ci	daddr_t				pblock = 0;
19162306a36Sopenharmony_ci	int				i;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	for (i = 0; i < VXFS_NTYPED; i++) {
19462306a36Sopenharmony_ci		struct vxfs_typed	*typ = vip->vii_org.typed + i;
19562306a36Sopenharmony_ci		u64			hdr = fs64_to_cpu(sbi, typ->vt_hdr);
19662306a36Sopenharmony_ci		int64_t			off = (hdr & VXFS_TYPED_OFFSETMASK);
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci#ifdef DIAGNOSTIC
19962306a36Sopenharmony_ci		vxfs_typdump(typ);
20062306a36Sopenharmony_ci#endif
20162306a36Sopenharmony_ci		if (iblock < off)
20262306a36Sopenharmony_ci			continue;
20362306a36Sopenharmony_ci		switch ((u32)(hdr >> VXFS_TYPED_TYPESHIFT)) {
20462306a36Sopenharmony_ci		case VXFS_TYPED_INDIRECT:
20562306a36Sopenharmony_ci			pblock = vxfs_bmap_indir(ip,
20662306a36Sopenharmony_ci					fs32_to_cpu(sbi, typ->vt_block),
20762306a36Sopenharmony_ci					fs32_to_cpu(sbi, typ->vt_size),
20862306a36Sopenharmony_ci					iblock - off);
20962306a36Sopenharmony_ci			if (pblock == -2)
21062306a36Sopenharmony_ci				break;
21162306a36Sopenharmony_ci			return (pblock);
21262306a36Sopenharmony_ci		case VXFS_TYPED_DATA:
21362306a36Sopenharmony_ci			if ((iblock - off) < fs32_to_cpu(sbi, typ->vt_size))
21462306a36Sopenharmony_ci				return (fs32_to_cpu(sbi, typ->vt_block) +
21562306a36Sopenharmony_ci						iblock - off);
21662306a36Sopenharmony_ci			break;
21762306a36Sopenharmony_ci		case VXFS_TYPED_INDIRECT_DEV4:
21862306a36Sopenharmony_ci		case VXFS_TYPED_DATA_DEV4: {
21962306a36Sopenharmony_ci			struct vxfs_typed_dev4	*typ4 =
22062306a36Sopenharmony_ci				(struct vxfs_typed_dev4 *)typ;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci			printk(KERN_INFO "\n\nTYPED_DEV4 detected!\n");
22362306a36Sopenharmony_ci			printk(KERN_INFO "block: %llu\tsize: %lld\tdev: %d\n",
22462306a36Sopenharmony_ci			       fs64_to_cpu(sbi, typ4->vd4_block),
22562306a36Sopenharmony_ci			       fs64_to_cpu(sbi, typ4->vd4_size),
22662306a36Sopenharmony_ci			       fs32_to_cpu(sbi, typ4->vd4_dev));
22762306a36Sopenharmony_ci			return 0;
22862306a36Sopenharmony_ci		}
22962306a36Sopenharmony_ci		default:
23062306a36Sopenharmony_ci			BUG();
23162306a36Sopenharmony_ci		}
23262306a36Sopenharmony_ci	}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	return 0;
23562306a36Sopenharmony_ci}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci/**
23862306a36Sopenharmony_ci * vxfs_bmap1 - vxfs-internal bmap operation
23962306a36Sopenharmony_ci * @ip:			pointer to the inode we do bmap for
24062306a36Sopenharmony_ci * @iblock:		logical block
24162306a36Sopenharmony_ci *
24262306a36Sopenharmony_ci * Description:
24362306a36Sopenharmony_ci *   vxfs_bmap1 perfoms a logical to physical block mapping
24462306a36Sopenharmony_ci *   for vxfs-internal purposes.
24562306a36Sopenharmony_ci *
24662306a36Sopenharmony_ci * Return Value:
24762306a36Sopenharmony_ci *   The physical block number on success, else Zero.
24862306a36Sopenharmony_ci */
24962306a36Sopenharmony_cidaddr_t
25062306a36Sopenharmony_civxfs_bmap1(struct inode *ip, long iblock)
25162306a36Sopenharmony_ci{
25262306a36Sopenharmony_ci	struct vxfs_inode_info		*vip = VXFS_INO(ip);
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	if (VXFS_ISEXT4(vip))
25562306a36Sopenharmony_ci		return vxfs_bmap_ext4(ip, iblock);
25662306a36Sopenharmony_ci	if (VXFS_ISTYPED(vip))
25762306a36Sopenharmony_ci		return vxfs_bmap_typed(ip, iblock);
25862306a36Sopenharmony_ci	if (VXFS_ISNONE(vip))
25962306a36Sopenharmony_ci		goto unsupp;
26062306a36Sopenharmony_ci	if (VXFS_ISIMMED(vip))
26162306a36Sopenharmony_ci		goto unsupp;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	printk(KERN_WARNING "vxfs: inode %ld has no valid orgtype (%x)\n",
26462306a36Sopenharmony_ci			ip->i_ino, vip->vii_orgtype);
26562306a36Sopenharmony_ci	BUG();
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ciunsupp:
26862306a36Sopenharmony_ci	printk(KERN_WARNING "vxfs: inode %ld has an unsupported orgtype (%x)\n",
26962306a36Sopenharmony_ci			ip->i_ino, vip->vii_orgtype);
27062306a36Sopenharmony_ci	return 0;
27162306a36Sopenharmony_ci}
272