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