linux/fs/freevxfs/vxfs_inode.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 - inode routines.
  32 */
  33#include <linux/fs.h>
  34#include <linux/buffer_head.h>
  35#include <linux/pagemap.h>
  36#include <linux/kernel.h>
  37#include <linux/slab.h>
  38
  39#include "vxfs.h"
  40#include "vxfs_inode.h"
  41#include "vxfs_extern.h"
  42
  43
  44struct kmem_cache               *vxfs_inode_cachep;
  45
  46
  47#ifdef DIAGNOSTIC
  48/*
  49 * Dump inode contents (partially).
  50 */
  51void
  52vxfs_dumpi(struct vxfs_inode_info *vip, ino_t ino)
  53{
  54        printk(KERN_DEBUG "\n\n");
  55        if (ino)
  56                printk(KERN_DEBUG "dumping vxfs inode %ld\n", ino);
  57        else
  58                printk(KERN_DEBUG "dumping unknown vxfs inode\n");
  59
  60        printk(KERN_DEBUG "---------------------------\n");
  61        printk(KERN_DEBUG "mode is %x\n", vip->vii_mode);
  62        printk(KERN_DEBUG "nlink:%u, uid:%u, gid:%u\n",
  63                        vip->vii_nlink, vip->vii_uid, vip->vii_gid);
  64        printk(KERN_DEBUG "size:%Lx, blocks:%u\n",
  65                        vip->vii_size, vip->vii_blocks);
  66        printk(KERN_DEBUG "orgtype:%u\n", vip->vii_orgtype);
  67}
  68#endif
  69
  70
  71/**
  72 * vxfs_blkiget - find inode based on extent #
  73 * @sbp:        superblock of the filesystem we search in
  74 * @extent:     number of the extent to search
  75 * @ino:        inode number to search
  76 *
  77 * Description:
  78 *  vxfs_blkiget searches inode @ino in the filesystem described by
  79 *  @sbp in the extent @extent.
  80 *  Returns the matching VxFS inode on success, else a NULL pointer.
  81 *
  82 * NOTE:
  83 *  While __vxfs_iget uses the pagecache vxfs_blkiget uses the
  84 *  buffercache.  This function should not be used outside the
  85 *  read_super() method, otherwise the data may be incoherent.
  86 */
  87struct vxfs_inode_info *
  88vxfs_blkiget(struct super_block *sbp, u_long extent, ino_t ino)
  89{
  90        struct buffer_head              *bp;
  91        u_long                          block, offset;
  92
  93        block = extent + ((ino * VXFS_ISIZE) / sbp->s_blocksize);
  94        offset = ((ino % (sbp->s_blocksize / VXFS_ISIZE)) * VXFS_ISIZE);
  95        bp = sb_bread(sbp, block);
  96
  97        if (bp && buffer_mapped(bp)) {
  98                struct vxfs_inode_info  *vip;
  99                struct vxfs_dinode      *dip;
 100
 101                if (!(vip = kmem_cache_alloc(vxfs_inode_cachep, GFP_KERNEL)))
 102                        goto fail;
 103                dip = (struct vxfs_dinode *)(bp->b_data + offset);
 104                memcpy(vip, dip, sizeof(*vip));
 105#ifdef DIAGNOSTIC
 106                vxfs_dumpi(vip, ino);
 107#endif
 108                brelse(bp);
 109                return (vip);
 110        }
 111
 112fail:
 113        printk(KERN_WARNING "vxfs: unable to read block %ld\n", block);
 114        brelse(bp);
 115        return NULL;
 116}
 117
 118/**
 119 * __vxfs_iget - generic find inode facility
 120 * @sbp:                VFS superblock
 121 * @ino:                inode number
 122 * @ilistp:             inode list
 123 *
 124 * Description:
 125 *  Search the for inode number @ino in the filesystem
 126 *  described by @sbp.  Use the specified inode table (@ilistp).
 127 *  Returns the matching VxFS inode on success, else an error code.
 128 */
 129static struct vxfs_inode_info *
 130__vxfs_iget(ino_t ino, struct inode *ilistp)
 131{
 132        struct page                     *pp;
 133        u_long                          offset;
 134
 135        offset = (ino % (PAGE_SIZE / VXFS_ISIZE)) * VXFS_ISIZE;
 136        pp = vxfs_get_page(ilistp->i_mapping, ino * VXFS_ISIZE / PAGE_SIZE);
 137
 138        if (!IS_ERR(pp)) {
 139                struct vxfs_inode_info  *vip;
 140                struct vxfs_dinode      *dip;
 141                caddr_t                 kaddr = (char *)page_address(pp);
 142
 143                if (!(vip = kmem_cache_alloc(vxfs_inode_cachep, GFP_KERNEL)))
 144                        goto fail;
 145                dip = (struct vxfs_dinode *)(kaddr + offset);
 146                memcpy(vip, dip, sizeof(*vip));
 147#ifdef DIAGNOSTIC
 148                vxfs_dumpi(vip, ino);
 149#endif
 150                vxfs_put_page(pp);
 151                return (vip);
 152        }
 153
 154        printk(KERN_WARNING "vxfs: error on page %p\n", pp);
 155        return ERR_CAST(pp);
 156
 157fail:
 158        printk(KERN_WARNING "vxfs: unable to read inode %ld\n", (unsigned long)ino);
 159        vxfs_put_page(pp);
 160        return ERR_PTR(-ENOMEM);
 161}
 162
 163/**
 164 * vxfs_stiget - find inode using the structural inode list
 165 * @sbp:        VFS superblock
 166 * @ino:        inode #
 167 *
 168 * Description:
 169 *  Find inode @ino in the filesystem described by @sbp using
 170 *  the structural inode list.
 171 *  Returns the matching VxFS inode on success, else a NULL pointer.
 172 */
 173struct vxfs_inode_info *
 174vxfs_stiget(struct super_block *sbp, ino_t ino)
 175{
 176        struct vxfs_inode_info *vip;
 177
 178        vip = __vxfs_iget(ino, VXFS_SBI(sbp)->vsi_stilist);
 179        return IS_ERR(vip) ? NULL : vip;
 180}
 181
 182/**
 183 * vxfs_transmod - mode for a VxFS inode
 184 * @vip:        VxFS inode
 185 *
 186 * Description:
 187 *  vxfs_transmod returns a Linux mode_t for a given
 188 *  VxFS inode structure.
 189 */
 190static __inline__ umode_t
 191vxfs_transmod(struct vxfs_inode_info *vip)
 192{
 193        umode_t                 ret = vip->vii_mode & ~VXFS_TYPE_MASK;
 194
 195        if (VXFS_ISFIFO(vip))
 196                ret |= S_IFIFO;
 197        if (VXFS_ISCHR(vip))
 198                ret |= S_IFCHR;
 199        if (VXFS_ISDIR(vip))
 200                ret |= S_IFDIR;
 201        if (VXFS_ISBLK(vip))
 202                ret |= S_IFBLK;
 203        if (VXFS_ISLNK(vip))
 204                ret |= S_IFLNK;
 205        if (VXFS_ISREG(vip))
 206                ret |= S_IFREG;
 207        if (VXFS_ISSOC(vip))
 208                ret |= S_IFSOCK;
 209
 210        return (ret);
 211}
 212
 213/**
 214 * vxfs_iinit- helper to fill inode fields
 215 * @ip:         VFS inode
 216 * @vip:        VxFS inode
 217 *
 218 * Description:
 219 *  vxfs_instino is a helper function to fill in all relevant
 220 *  fields in @ip from @vip.
 221 */
 222static void
 223vxfs_iinit(struct inode *ip, struct vxfs_inode_info *vip)
 224{
 225
 226        ip->i_mode = vxfs_transmod(vip);
 227        i_uid_write(ip, (uid_t)vip->vii_uid);
 228        i_gid_write(ip, (gid_t)vip->vii_gid);
 229
 230        set_nlink(ip, vip->vii_nlink);
 231        ip->i_size = vip->vii_size;
 232
 233        ip->i_atime.tv_sec = vip->vii_atime;
 234        ip->i_ctime.tv_sec = vip->vii_ctime;
 235        ip->i_mtime.tv_sec = vip->vii_mtime;
 236        ip->i_atime.tv_nsec = 0;
 237        ip->i_ctime.tv_nsec = 0;
 238        ip->i_mtime.tv_nsec = 0;
 239
 240        ip->i_blocks = vip->vii_blocks;
 241        ip->i_generation = vip->vii_gen;
 242
 243        ip->i_private = vip;
 244        
 245}
 246
 247/**
 248 * vxfs_get_fake_inode - get fake inode structure
 249 * @sbp:                filesystem superblock
 250 * @vip:                fspriv inode
 251 *
 252 * Description:
 253 *  vxfs_fake_inode gets a fake inode (not in the inode hash) for a
 254 *  superblock, vxfs_inode pair.
 255 *  Returns the filled VFS inode.
 256 */
 257struct inode *
 258vxfs_get_fake_inode(struct super_block *sbp, struct vxfs_inode_info *vip)
 259{
 260        struct inode                    *ip = NULL;
 261
 262        if ((ip = new_inode(sbp))) {
 263                ip->i_ino = get_next_ino();
 264                vxfs_iinit(ip, vip);
 265                ip->i_mapping->a_ops = &vxfs_aops;
 266        }
 267        return (ip);
 268}
 269
 270/**
 271 * vxfs_put_fake_inode - free faked inode
 272 * *ip:                 VFS inode
 273 *
 274 * Description:
 275 *  vxfs_put_fake_inode frees all data associated with @ip.
 276 */
 277void
 278vxfs_put_fake_inode(struct inode *ip)
 279{
 280        iput(ip);
 281}
 282
 283/**
 284 * vxfs_iget - get an inode
 285 * @sbp:        the superblock to get the inode for
 286 * @ino:        the number of the inode to get
 287 *
 288 * Description:
 289 *  vxfs_read_inode creates an inode, reads the disk inode for @ino and fills
 290 *  in all relevant fields in the new inode.
 291 */
 292struct inode *
 293vxfs_iget(struct super_block *sbp, ino_t ino)
 294{
 295        struct vxfs_inode_info          *vip;
 296        const struct address_space_operations   *aops;
 297        struct inode *ip;
 298
 299        ip = iget_locked(sbp, ino);
 300        if (!ip)
 301                return ERR_PTR(-ENOMEM);
 302        if (!(ip->i_state & I_NEW))
 303                return ip;
 304
 305        vip = __vxfs_iget(ino, VXFS_SBI(sbp)->vsi_ilist);
 306        if (IS_ERR(vip)) {
 307                iget_failed(ip);
 308                return ERR_CAST(vip);
 309        }
 310
 311        vxfs_iinit(ip, vip);
 312
 313        if (VXFS_ISIMMED(vip))
 314                aops = &vxfs_immed_aops;
 315        else
 316                aops = &vxfs_aops;
 317
 318        if (S_ISREG(ip->i_mode)) {
 319                ip->i_fop = &generic_ro_fops;
 320                ip->i_mapping->a_ops = aops;
 321        } else if (S_ISDIR(ip->i_mode)) {
 322                ip->i_op = &vxfs_dir_inode_ops;
 323                ip->i_fop = &vxfs_dir_operations;
 324                ip->i_mapping->a_ops = aops;
 325        } else if (S_ISLNK(ip->i_mode)) {
 326                if (!VXFS_ISIMMED(vip)) {
 327                        ip->i_op = &page_symlink_inode_operations;
 328                        ip->i_mapping->a_ops = &vxfs_aops;
 329                } else {
 330                        ip->i_op = &vxfs_immed_symlink_iops;
 331                        vip->vii_immed.vi_immed[ip->i_size] = '\0';
 332                }
 333        } else
 334                init_special_inode(ip, ip->i_mode, old_decode_dev(vip->vii_rdev));
 335
 336        unlock_new_inode(ip);
 337        return ip;
 338}
 339
 340static void vxfs_i_callback(struct rcu_head *head)
 341{
 342        struct inode *inode = container_of(head, struct inode, i_rcu);
 343        kmem_cache_free(vxfs_inode_cachep, inode->i_private);
 344}
 345
 346/**
 347 * vxfs_evict_inode - remove inode from main memory
 348 * @ip:         inode to discard.
 349 *
 350 * Description:
 351 *  vxfs_evict_inode() is called on the final iput and frees the private
 352 *  inode area.
 353 */
 354void
 355vxfs_evict_inode(struct inode *ip)
 356{
 357        truncate_inode_pages(&ip->i_data, 0);
 358        clear_inode(ip);
 359        call_rcu(&ip->i_rcu, vxfs_i_callback);
 360}
 361