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 43static void 44vxfs_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 */ 66static daddr_t 67vxfs_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 104fail_size: 105 printk("vxfs: indirect extent too big!\n"); 106fail_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 */ 127static daddr_t 128vxfs_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))); 140 if (!bp || !buffer_mapped(bp)) 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 182fail: 183 pblock = 0; 184out: 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 */ 200static daddr_t 201vxfs_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 */ 259daddr_t 260vxfs_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 277unsupp: 278 printk(KERN_WARNING "vxfs: inode %ld has an unsupported orgtype (%x)\n", 279 ip->i_ino, vip->vii_orgtype); 280 return 0; 281} 282