xref: /openbmc/linux/fs/freevxfs/vxfs_bmap.c (revision d5cb9783536a41df9f9cba5b0a1d78047ed787f7)
1 /*
2  * Copyright (c) 2000-2001 Christoph Hellwig.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions, and the following disclaimer,
10  *    without modification.
11  * 2. The name of the author may not be used to endorse or promote products
12  *    derived from this software without specific prior written permission.
13  *
14  * Alternatively, this software may be distributed under the terms of the
15  * GNU General Public License ("GPL").
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
21  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 /*
31  * Veritas filesystem driver - filesystem to disk block mapping.
32  */
33 #include <linux/fs.h>
34 #include <linux/buffer_head.h>
35 #include <linux/kernel.h>
36 
37 #include "vxfs.h"
38 #include "vxfs_inode.h"
39 
40 
41 #ifdef DIAGNOSTIC
42 static void
43 vxfs_typdump(struct vxfs_typed *typ)
44 {
45 	printk(KERN_DEBUG "type=%Lu ", typ->vt_hdr >> VXFS_TYPED_TYPESHIFT);
46 	printk("offset=%Lx ", typ->vt_hdr & VXFS_TYPED_OFFSETMASK);
47 	printk("block=%x ", typ->vt_block);
48 	printk("size=%x\n", typ->vt_size);
49 }
50 #endif
51 
52 /**
53  * vxfs_bmap_ext4 - do bmap for ext4 extents
54  * @ip:		pointer to the inode we do bmap for
55  * @iblock:	logical block.
56  *
57  * Description:
58  *   vxfs_bmap_ext4 performs the bmap operation for inodes with
59  *   ext4-style extents (which are much like the traditional UNIX
60  *   inode organisation).
61  *
62  * Returns:
63  *   The physical block number on success, else Zero.
64  */
65 static daddr_t
66 vxfs_bmap_ext4(struct inode *ip, long bn)
67 {
68 	struct super_block *sb = ip->i_sb;
69 	struct vxfs_inode_info *vip = VXFS_INO(ip);
70 	unsigned long bsize = sb->s_blocksize;
71 	u32 indsize = vip->vii_ext4.ve4_indsize;
72 	int i;
73 
74 	if (indsize > sb->s_blocksize)
75 		goto fail_size;
76 
77 	for (i = 0; i < VXFS_NDADDR; i++) {
78 		struct direct *d = vip->vii_ext4.ve4_direct + i;
79 		if (bn >= 0 && bn < d->size)
80 			return (bn + d->extent);
81 		bn -= d->size;
82 	}
83 
84 	if ((bn / (indsize * indsize * bsize / 4)) == 0) {
85 		struct buffer_head *buf;
86 		daddr_t	bno;
87 		u32 *indir;
88 
89 		buf = sb_bread(sb, vip->vii_ext4.ve4_indir[0]);
90 		if (!buf || !buffer_mapped(buf))
91 			goto fail_buf;
92 
93 		indir = (u32 *)buf->b_data;
94 		bno = indir[(bn/indsize) % (indsize*bn)] + (bn%indsize);
95 
96 		brelse(buf);
97 		return bno;
98 	} else
99 		printk(KERN_WARNING "no matching indir?");
100 
101 	return 0;
102 
103 fail_size:
104 	printk("vxfs: indirect extent too big!\n");
105 fail_buf:
106 	return 0;
107 }
108 
109 /**
110  * vxfs_bmap_indir - recursion for vxfs_bmap_typed
111  * @ip:		pointer to the inode we do bmap for
112  * @indir:	indirect block we start reading at
113  * @size:	size of the typed area to search
114  * @block:	partially result from further searches
115  *
116  * Description:
117  *   vxfs_bmap_indir reads a &struct vxfs_typed at @indir
118  *   and performs the type-defined action.
119  *
120  * Return Value:
121  *   The physical block number on success, else Zero.
122  *
123  * Note:
124  *   Kernelstack is rare.  Unrecurse?
125  */
126 static daddr_t
127 vxfs_bmap_indir(struct inode *ip, long indir, int size, long block)
128 {
129 	struct buffer_head		*bp = NULL;
130 	daddr_t				pblock = 0;
131 	int				i;
132 
133 	for (i = 0; i < size * VXFS_TYPED_PER_BLOCK(ip->i_sb); i++) {
134 		struct vxfs_typed	*typ;
135 		int64_t			off;
136 
137 		bp = sb_bread(ip->i_sb,
138 				indir + (i / VXFS_TYPED_PER_BLOCK(ip->i_sb)));
139 		if (!buffer_mapped(bp))
140 			return 0;
141 
142 		typ = ((struct vxfs_typed *)bp->b_data) +
143 			(i % VXFS_TYPED_PER_BLOCK(ip->i_sb));
144 		off = (typ->vt_hdr & VXFS_TYPED_OFFSETMASK);
145 
146 		if (block < off) {
147 			brelse(bp);
148 			continue;
149 		}
150 
151 		switch ((u_int32_t)(typ->vt_hdr >> VXFS_TYPED_TYPESHIFT)) {
152 		case VXFS_TYPED_INDIRECT:
153 			pblock = vxfs_bmap_indir(ip, typ->vt_block,
154 					typ->vt_size, block - off);
155 			if (pblock == -2)
156 				break;
157 			goto out;
158 		case VXFS_TYPED_DATA:
159 			if ((block - off) >= typ->vt_size)
160 				break;
161 			pblock = (typ->vt_block + block - off);
162 			goto out;
163 		case VXFS_TYPED_INDIRECT_DEV4:
164 		case VXFS_TYPED_DATA_DEV4: {
165 			struct vxfs_typed_dev4	*typ4 =
166 				(struct vxfs_typed_dev4 *)typ;
167 
168 			printk(KERN_INFO "\n\nTYPED_DEV4 detected!\n");
169 			printk(KERN_INFO "block: %Lu\tsize: %Ld\tdev: %d\n",
170 			       (unsigned long long) typ4->vd4_block,
171 			       (unsigned long long) typ4->vd4_size,
172 			       typ4->vd4_dev);
173 			goto fail;
174 		}
175 		default:
176 			BUG();
177 		}
178 		brelse(bp);
179 	}
180 
181 fail:
182 	pblock = 0;
183 out:
184 	brelse(bp);
185 	return (pblock);
186 }
187 
188 /**
189  * vxfs_bmap_typed - bmap for typed extents
190  * @ip:		pointer to the inode we do bmap for
191  * @iblock:	logical block
192  *
193  * Description:
194  *   Performs the bmap operation for typed extents.
195  *
196  * Return Value:
197  *   The physical block number on success, else Zero.
198  */
199 static daddr_t
200 vxfs_bmap_typed(struct inode *ip, long iblock)
201 {
202 	struct vxfs_inode_info		*vip = VXFS_INO(ip);
203 	daddr_t				pblock = 0;
204 	int				i;
205 
206 	for (i = 0; i < VXFS_NTYPED; i++) {
207 		struct vxfs_typed	*typ = vip->vii_org.typed + i;
208 		int64_t			off = (typ->vt_hdr & VXFS_TYPED_OFFSETMASK);
209 
210 #ifdef DIAGNOSTIC
211 		vxfs_typdump(typ);
212 #endif
213 		if (iblock < off)
214 			continue;
215 		switch ((u_int32_t)(typ->vt_hdr >> VXFS_TYPED_TYPESHIFT)) {
216 		case VXFS_TYPED_INDIRECT:
217 			pblock = vxfs_bmap_indir(ip, typ->vt_block,
218 					typ->vt_size, iblock - off);
219 			if (pblock == -2)
220 				break;
221 			return (pblock);
222 		case VXFS_TYPED_DATA:
223 			if ((iblock - off) < typ->vt_size)
224 				return (typ->vt_block + iblock - off);
225 			break;
226 		case VXFS_TYPED_INDIRECT_DEV4:
227 		case VXFS_TYPED_DATA_DEV4: {
228 			struct vxfs_typed_dev4	*typ4 =
229 				(struct vxfs_typed_dev4 *)typ;
230 
231 			printk(KERN_INFO "\n\nTYPED_DEV4 detected!\n");
232 			printk(KERN_INFO "block: %Lu\tsize: %Ld\tdev: %d\n",
233 			       (unsigned long long) typ4->vd4_block,
234 			       (unsigned long long) typ4->vd4_size,
235 			       typ4->vd4_dev);
236 			return 0;
237 		}
238 		default:
239 			BUG();
240 		}
241 	}
242 
243 	return 0;
244 }
245 
246 /**
247  * vxfs_bmap1 - vxfs-internal bmap operation
248  * @ip:			pointer to the inode we do bmap for
249  * @iblock:		logical block
250  *
251  * Description:
252  *   vxfs_bmap1 perfoms a logical to physical block mapping
253  *   for vxfs-internal purposes.
254  *
255  * Return Value:
256  *   The physical block number on success, else Zero.
257  */
258 daddr_t
259 vxfs_bmap1(struct inode *ip, long iblock)
260 {
261 	struct vxfs_inode_info		*vip = VXFS_INO(ip);
262 
263 	if (VXFS_ISEXT4(vip))
264 		return vxfs_bmap_ext4(ip, iblock);
265 	if (VXFS_ISTYPED(vip))
266 		return vxfs_bmap_typed(ip, iblock);
267 	if (VXFS_ISNONE(vip))
268 		goto unsupp;
269 	if (VXFS_ISIMMED(vip))
270 		goto unsupp;
271 
272 	printk(KERN_WARNING "vxfs: inode %ld has no valid orgtype (%x)\n",
273 			ip->i_ino, vip->vii_orgtype);
274 	BUG();
275 
276 unsupp:
277 	printk(KERN_WARNING "vxfs: inode %ld has an unsupported orgtype (%x)\n",
278 			ip->i_ino, vip->vii_orgtype);
279 	return 0;
280 }
281