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