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        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