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 #include "vxfs_extern.h" 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 struct vxfs_sb_info *sbi = VXFS_SBI(sb); 72 unsigned long bsize = sb->s_blocksize; 73 u32 indsize = fs32_to_cpu(sbi, vip->vii_ext4.ve4_indsize); 74 int i; 75 76 if (indsize > sb->s_blocksize) 77 goto fail_size; 78 79 for (i = 0; i < VXFS_NDADDR; i++) { 80 struct direct *d = vip->vii_ext4.ve4_direct + i; 81 if (bn >= 0 && bn < fs32_to_cpu(sbi, d->size)) 82 return (bn + fs32_to_cpu(sbi, d->extent)); 83 bn -= fs32_to_cpu(sbi, d->size); 84 } 85 86 if ((bn / (indsize * indsize * bsize / 4)) == 0) { 87 struct buffer_head *buf; 88 daddr_t bno; 89 __fs32 *indir; 90 91 buf = sb_bread(sb, 92 fs32_to_cpu(sbi, vip->vii_ext4.ve4_indir[0])); 93 if (!buf || !buffer_mapped(buf)) 94 goto fail_buf; 95 96 indir = (__fs32 *)buf->b_data; 97 bno = fs32_to_cpu(sbi, indir[(bn / indsize) % (indsize * bn)]) + 98 (bn % indsize); 99 100 brelse(buf); 101 return bno; 102 } else 103 printk(KERN_WARNING "no matching indir?"); 104 105 return 0; 106 107 fail_size: 108 printk("vxfs: indirect extent too big!\n"); 109 fail_buf: 110 return 0; 111 } 112 113 /** 114 * vxfs_bmap_indir - recursion for vxfs_bmap_typed 115 * @ip: pointer to the inode we do bmap for 116 * @indir: indirect block we start reading at 117 * @size: size of the typed area to search 118 * @block: partially result from further searches 119 * 120 * Description: 121 * vxfs_bmap_indir reads a &struct vxfs_typed at @indir 122 * and performs the type-defined action. 123 * 124 * Return Value: 125 * The physical block number on success, else Zero. 126 * 127 * Note: 128 * Kernelstack is rare. Unrecurse? 129 */ 130 static daddr_t 131 vxfs_bmap_indir(struct inode *ip, long indir, int size, long block) 132 { 133 struct vxfs_sb_info *sbi = VXFS_SBI(ip->i_sb); 134 struct buffer_head *bp = NULL; 135 daddr_t pblock = 0; 136 int i; 137 138 for (i = 0; i < size * VXFS_TYPED_PER_BLOCK(ip->i_sb); i++) { 139 struct vxfs_typed *typ; 140 int64_t off; 141 142 bp = sb_bread(ip->i_sb, 143 indir + (i / VXFS_TYPED_PER_BLOCK(ip->i_sb))); 144 if (!bp || !buffer_mapped(bp)) 145 return 0; 146 147 typ = ((struct vxfs_typed *)bp->b_data) + 148 (i % VXFS_TYPED_PER_BLOCK(ip->i_sb)); 149 off = fs64_to_cpu(sbi, typ->vt_hdr) & VXFS_TYPED_OFFSETMASK; 150 151 if (block < off) { 152 brelse(bp); 153 continue; 154 } 155 156 switch ((u_int32_t)(fs64_to_cpu(sbi, typ->vt_hdr) >> 157 VXFS_TYPED_TYPESHIFT)) { 158 case VXFS_TYPED_INDIRECT: 159 pblock = vxfs_bmap_indir(ip, 160 fs32_to_cpu(sbi, typ->vt_block), 161 fs32_to_cpu(sbi, typ->vt_size), 162 block - off); 163 if (pblock == -2) 164 break; 165 goto out; 166 case VXFS_TYPED_DATA: 167 if ((block - off) >= fs32_to_cpu(sbi, typ->vt_size)) 168 break; 169 pblock = fs32_to_cpu(sbi, typ->vt_block) + block - off; 170 goto out; 171 case VXFS_TYPED_INDIRECT_DEV4: 172 case VXFS_TYPED_DATA_DEV4: { 173 struct vxfs_typed_dev4 *typ4 = 174 (struct vxfs_typed_dev4 *)typ; 175 176 printk(KERN_INFO "\n\nTYPED_DEV4 detected!\n"); 177 printk(KERN_INFO "block: %llu\tsize: %lld\tdev: %d\n", 178 fs64_to_cpu(sbi, typ4->vd4_block), 179 fs64_to_cpu(sbi, typ4->vd4_size), 180 fs32_to_cpu(sbi, typ4->vd4_dev)); 181 goto fail; 182 } 183 default: 184 printk(KERN_ERR "%s:%d vt_hdr %llu\n", __func__, 185 __LINE__, fs64_to_cpu(sbi, typ->vt_hdr)); 186 BUG(); 187 } 188 brelse(bp); 189 } 190 191 fail: 192 pblock = 0; 193 out: 194 brelse(bp); 195 return (pblock); 196 } 197 198 /** 199 * vxfs_bmap_typed - bmap for typed extents 200 * @ip: pointer to the inode we do bmap for 201 * @iblock: logical block 202 * 203 * Description: 204 * Performs the bmap operation for typed extents. 205 * 206 * Return Value: 207 * The physical block number on success, else Zero. 208 */ 209 static daddr_t 210 vxfs_bmap_typed(struct inode *ip, long iblock) 211 { 212 struct vxfs_inode_info *vip = VXFS_INO(ip); 213 struct vxfs_sb_info *sbi = VXFS_SBI(ip->i_sb); 214 daddr_t pblock = 0; 215 int i; 216 217 for (i = 0; i < VXFS_NTYPED; i++) { 218 struct vxfs_typed *typ = vip->vii_org.typed + i; 219 u64 hdr = fs64_to_cpu(sbi, typ->vt_hdr); 220 int64_t off = (hdr & VXFS_TYPED_OFFSETMASK); 221 222 #ifdef DIAGNOSTIC 223 vxfs_typdump(typ); 224 #endif 225 if (iblock < off) 226 continue; 227 switch ((u32)(hdr >> VXFS_TYPED_TYPESHIFT)) { 228 case VXFS_TYPED_INDIRECT: 229 pblock = vxfs_bmap_indir(ip, 230 fs32_to_cpu(sbi, typ->vt_block), 231 fs32_to_cpu(sbi, typ->vt_size), 232 iblock - off); 233 if (pblock == -2) 234 break; 235 return (pblock); 236 case VXFS_TYPED_DATA: 237 if ((iblock - off) < fs32_to_cpu(sbi, typ->vt_size)) 238 return (fs32_to_cpu(sbi, typ->vt_block) + 239 iblock - off); 240 break; 241 case VXFS_TYPED_INDIRECT_DEV4: 242 case VXFS_TYPED_DATA_DEV4: { 243 struct vxfs_typed_dev4 *typ4 = 244 (struct vxfs_typed_dev4 *)typ; 245 246 printk(KERN_INFO "\n\nTYPED_DEV4 detected!\n"); 247 printk(KERN_INFO "block: %llu\tsize: %lld\tdev: %d\n", 248 fs64_to_cpu(sbi, typ4->vd4_block), 249 fs64_to_cpu(sbi, typ4->vd4_size), 250 fs32_to_cpu(sbi, typ4->vd4_dev)); 251 return 0; 252 } 253 default: 254 BUG(); 255 } 256 } 257 258 return 0; 259 } 260 261 /** 262 * vxfs_bmap1 - vxfs-internal bmap operation 263 * @ip: pointer to the inode we do bmap for 264 * @iblock: logical block 265 * 266 * Description: 267 * vxfs_bmap1 perfoms a logical to physical block mapping 268 * for vxfs-internal purposes. 269 * 270 * Return Value: 271 * The physical block number on success, else Zero. 272 */ 273 daddr_t 274 vxfs_bmap1(struct inode *ip, long iblock) 275 { 276 struct vxfs_inode_info *vip = VXFS_INO(ip); 277 278 if (VXFS_ISEXT4(vip)) 279 return vxfs_bmap_ext4(ip, iblock); 280 if (VXFS_ISTYPED(vip)) 281 return vxfs_bmap_typed(ip, iblock); 282 if (VXFS_ISNONE(vip)) 283 goto unsupp; 284 if (VXFS_ISIMMED(vip)) 285 goto unsupp; 286 287 printk(KERN_WARNING "vxfs: inode %ld has no valid orgtype (%x)\n", 288 ip->i_ino, vip->vii_orgtype); 289 BUG(); 290 291 unsupp: 292 printk(KERN_WARNING "vxfs: inode %ld has an unsupported orgtype (%x)\n", 293 ip->i_ino, vip->vii_orgtype); 294 return 0; 295 } 296