xref: /linux/fs/freevxfs/vxfs_bmap.c (revision 06d07429858317ded2db7986113a9e0129cd599b)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2000-2001 Christoph Hellwig.
4  */
5 
6 /*
7  * Veritas filesystem driver - filesystem to disk block mapping.
8  */
9 #include <linux/fs.h>
10 #include <linux/buffer_head.h>
11 #include <linux/kernel.h>
12 
13 #include "vxfs.h"
14 #include "vxfs_inode.h"
15 #include "vxfs_extern.h"
16 
17 
18 #ifdef DIAGNOSTIC
19 static void
vxfs_typdump(struct vxfs_typed * typ)20 vxfs_typdump(struct vxfs_typed *typ)
21 {
22 	printk(KERN_DEBUG "type=%Lu ", typ->vt_hdr >> VXFS_TYPED_TYPESHIFT);
23 	printk("offset=%Lx ", typ->vt_hdr & VXFS_TYPED_OFFSETMASK);
24 	printk("block=%x ", typ->vt_block);
25 	printk("size=%x\n", typ->vt_size);
26 }
27 #endif
28 
29 /**
30  * vxfs_bmap_ext4 - do bmap for ext4 extents
31  * @ip:		pointer to the inode we do bmap for
32  * @bn:		logical block.
33  *
34  * Description:
35  *   vxfs_bmap_ext4 performs the bmap operation for inodes with
36  *   ext4-style extents (which are much like the traditional UNIX
37  *   inode organisation).
38  *
39  * Returns:
40  *   The physical block number on success, else Zero.
41  */
42 static daddr_t
vxfs_bmap_ext4(struct inode * ip,long bn)43 vxfs_bmap_ext4(struct inode *ip, long bn)
44 {
45 	struct super_block *sb = ip->i_sb;
46 	struct vxfs_inode_info *vip = VXFS_INO(ip);
47 	struct vxfs_sb_info *sbi = VXFS_SBI(sb);
48 	unsigned long bsize = sb->s_blocksize;
49 	u32 indsize = fs32_to_cpu(sbi, vip->vii_ext4.ve4_indsize);
50 	int i;
51 
52 	if (indsize > sb->s_blocksize)
53 		goto fail_size;
54 
55 	for (i = 0; i < VXFS_NDADDR; i++) {
56 		struct direct *d = vip->vii_ext4.ve4_direct + i;
57 		if (bn >= 0 && bn < fs32_to_cpu(sbi, d->size))
58 			return (bn + fs32_to_cpu(sbi, d->extent));
59 		bn -= fs32_to_cpu(sbi, d->size);
60 	}
61 
62 	if ((bn / (indsize * indsize * bsize / 4)) == 0) {
63 		struct buffer_head *buf;
64 		daddr_t	bno;
65 		__fs32 *indir;
66 
67 		buf = sb_bread(sb,
68 			fs32_to_cpu(sbi, vip->vii_ext4.ve4_indir[0]));
69 		if (!buf || !buffer_mapped(buf))
70 			goto fail_buf;
71 
72 		indir = (__fs32 *)buf->b_data;
73 		bno = fs32_to_cpu(sbi, indir[(bn / indsize) % (indsize * bn)]) +
74 			(bn % indsize);
75 
76 		brelse(buf);
77 		return bno;
78 	} else
79 		printk(KERN_WARNING "no matching indir?");
80 
81 	return 0;
82 
83 fail_size:
84 	printk("vxfs: indirect extent too big!\n");
85 fail_buf:
86 	return 0;
87 }
88 
89 /**
90  * vxfs_bmap_indir - recursion for vxfs_bmap_typed
91  * @ip:		pointer to the inode we do bmap for
92  * @indir:	indirect block we start reading at
93  * @size:	size of the typed area to search
94  * @block:	partially result from further searches
95  *
96  * Description:
97  *   vxfs_bmap_indir reads a &struct vxfs_typed at @indir
98  *   and performs the type-defined action.
99  *
100  * Returns:
101  *   The physical block number on success, else Zero.
102  *
103  * Note:
104  *   Kernelstack is rare.  Unrecurse?
105  */
106 static daddr_t
vxfs_bmap_indir(struct inode * ip,long indir,int size,long block)107 vxfs_bmap_indir(struct inode *ip, long indir, int size, long block)
108 {
109 	struct vxfs_sb_info		*sbi = VXFS_SBI(ip->i_sb);
110 	struct buffer_head		*bp = NULL;
111 	daddr_t				pblock = 0;
112 	int				i;
113 
114 	for (i = 0; i < size * VXFS_TYPED_PER_BLOCK(ip->i_sb); i++) {
115 		struct vxfs_typed	*typ;
116 		int64_t			off;
117 
118 		bp = sb_bread(ip->i_sb,
119 				indir + (i / VXFS_TYPED_PER_BLOCK(ip->i_sb)));
120 		if (!bp || !buffer_mapped(bp))
121 			return 0;
122 
123 		typ = ((struct vxfs_typed *)bp->b_data) +
124 			(i % VXFS_TYPED_PER_BLOCK(ip->i_sb));
125 		off = fs64_to_cpu(sbi, typ->vt_hdr) & VXFS_TYPED_OFFSETMASK;
126 
127 		if (block < off) {
128 			brelse(bp);
129 			continue;
130 		}
131 
132 		switch ((u_int32_t)(fs64_to_cpu(sbi, typ->vt_hdr) >>
133 				VXFS_TYPED_TYPESHIFT)) {
134 		case VXFS_TYPED_INDIRECT:
135 			pblock = vxfs_bmap_indir(ip,
136 					fs32_to_cpu(sbi, typ->vt_block),
137 					fs32_to_cpu(sbi, typ->vt_size),
138 					block - off);
139 			if (pblock == -2)
140 				break;
141 			goto out;
142 		case VXFS_TYPED_DATA:
143 			if ((block - off) >= fs32_to_cpu(sbi, typ->vt_size))
144 				break;
145 			pblock = fs32_to_cpu(sbi, typ->vt_block) + block - off;
146 			goto out;
147 		case VXFS_TYPED_INDIRECT_DEV4:
148 		case VXFS_TYPED_DATA_DEV4: {
149 			struct vxfs_typed_dev4	*typ4 =
150 				(struct vxfs_typed_dev4 *)typ;
151 
152 			printk(KERN_INFO "\n\nTYPED_DEV4 detected!\n");
153 			printk(KERN_INFO "block: %llu\tsize: %lld\tdev: %d\n",
154 			       fs64_to_cpu(sbi, typ4->vd4_block),
155 			       fs64_to_cpu(sbi, typ4->vd4_size),
156 			       fs32_to_cpu(sbi, typ4->vd4_dev));
157 			goto fail;
158 		}
159 		default:
160 			printk(KERN_ERR "%s:%d vt_hdr %llu\n", __func__,
161 				__LINE__, fs64_to_cpu(sbi, typ->vt_hdr));
162 			BUG();
163 		}
164 		brelse(bp);
165 	}
166 
167 fail:
168 	pblock = 0;
169 out:
170 	brelse(bp);
171 	return (pblock);
172 }
173 
174 /**
175  * vxfs_bmap_typed - bmap for typed extents
176  * @ip:		pointer to the inode we do bmap for
177  * @iblock:	logical block
178  *
179  * Description:
180  *   Performs the bmap operation for typed extents.
181  *
182  * Returns:
183  *   The physical block number on success, else Zero.
184  */
185 static daddr_t
vxfs_bmap_typed(struct inode * ip,long iblock)186 vxfs_bmap_typed(struct inode *ip, long iblock)
187 {
188 	struct vxfs_inode_info		*vip = VXFS_INO(ip);
189 	struct vxfs_sb_info		*sbi = VXFS_SBI(ip->i_sb);
190 	daddr_t				pblock = 0;
191 	int				i;
192 
193 	for (i = 0; i < VXFS_NTYPED; i++) {
194 		struct vxfs_typed	*typ = vip->vii_org.typed + i;
195 		u64			hdr = fs64_to_cpu(sbi, typ->vt_hdr);
196 		int64_t			off = (hdr & VXFS_TYPED_OFFSETMASK);
197 
198 #ifdef DIAGNOSTIC
199 		vxfs_typdump(typ);
200 #endif
201 		if (iblock < off)
202 			continue;
203 		switch ((u32)(hdr >> VXFS_TYPED_TYPESHIFT)) {
204 		case VXFS_TYPED_INDIRECT:
205 			pblock = vxfs_bmap_indir(ip,
206 					fs32_to_cpu(sbi, typ->vt_block),
207 					fs32_to_cpu(sbi, typ->vt_size),
208 					iblock - off);
209 			if (pblock == -2)
210 				break;
211 			return (pblock);
212 		case VXFS_TYPED_DATA:
213 			if ((iblock - off) < fs32_to_cpu(sbi, typ->vt_size))
214 				return (fs32_to_cpu(sbi, typ->vt_block) +
215 						iblock - off);
216 			break;
217 		case VXFS_TYPED_INDIRECT_DEV4:
218 		case VXFS_TYPED_DATA_DEV4: {
219 			struct vxfs_typed_dev4	*typ4 =
220 				(struct vxfs_typed_dev4 *)typ;
221 
222 			printk(KERN_INFO "\n\nTYPED_DEV4 detected!\n");
223 			printk(KERN_INFO "block: %llu\tsize: %lld\tdev: %d\n",
224 			       fs64_to_cpu(sbi, typ4->vd4_block),
225 			       fs64_to_cpu(sbi, typ4->vd4_size),
226 			       fs32_to_cpu(sbi, typ4->vd4_dev));
227 			return 0;
228 		}
229 		default:
230 			BUG();
231 		}
232 	}
233 
234 	return 0;
235 }
236 
237 /**
238  * vxfs_bmap1 - vxfs-internal bmap operation
239  * @ip:			pointer to the inode we do bmap for
240  * @iblock:		logical block
241  *
242  * Description:
243  *   vxfs_bmap1 perfoms a logical to physical block mapping
244  *   for vxfs-internal purposes.
245  *
246  * Returns:
247  *   The physical block number on success, else Zero.
248  */
249 daddr_t
vxfs_bmap1(struct inode * ip,long iblock)250 vxfs_bmap1(struct inode *ip, long iblock)
251 {
252 	struct vxfs_inode_info		*vip = VXFS_INO(ip);
253 
254 	if (VXFS_ISEXT4(vip))
255 		return vxfs_bmap_ext4(ip, iblock);
256 	if (VXFS_ISTYPED(vip))
257 		return vxfs_bmap_typed(ip, iblock);
258 	if (VXFS_ISNONE(vip))
259 		goto unsupp;
260 	if (VXFS_ISIMMED(vip))
261 		goto unsupp;
262 
263 	printk(KERN_WARNING "vxfs: inode %ld has no valid orgtype (%x)\n",
264 			ip->i_ino, vip->vii_orgtype);
265 	BUG();
266 
267 unsupp:
268 	printk(KERN_WARNING "vxfs: inode %ld has an unsupported orgtype (%x)\n",
269 			ip->i_ino, vip->vii_orgtype);
270 	return 0;
271 }
272