linux/fs/freevxfs/vxfs_bmap.c
<<
>>
Prefs
   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        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
 107fail_size:
 108        printk("vxfs: indirect extent too big!\n");
 109fail_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 */
 130static daddr_t
 131vxfs_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
 191fail:
 192        pblock = 0;
 193out:
 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 */
 209static daddr_t
 210vxfs_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 */
 273daddr_t
 274vxfs_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
 291unsupp:
 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