nfsd4: check for negative dentry before use in nfsv4 readdir
[safe/jmp/linux-2.6] / fs / xfs / xfs_inode.c
index 35e4191..e7ae08d 100644 (file)
@@ -23,7 +23,6 @@
 #include "xfs_bit.h"
 #include "xfs_log.h"
 #include "xfs_inum.h"
-#include "xfs_imap.h"
 #include "xfs_trans.h"
 #include "xfs_trans_priv.h"
 #include "xfs_sb.h"
@@ -134,10 +133,10 @@ STATIC int
 xfs_imap_to_bp(
        xfs_mount_t     *mp,
        xfs_trans_t     *tp,
-       xfs_imap_t      *imap,
+       struct xfs_imap *imap,
        xfs_buf_t       **bpp,
        uint            buf_flags,
-       uint            imap_flags)
+       uint            iget_flags)
 {
        int             error;
        int             i;
@@ -174,12 +173,12 @@ xfs_imap_to_bp(
 
                dip = (xfs_dinode_t *)xfs_buf_offset(bp,
                                        (i << mp->m_sb.sb_inodelog));
-               di_ok = be16_to_cpu(dip->di_core.di_magic) == XFS_DINODE_MAGIC &&
-                           XFS_DINODE_GOOD_VERSION(dip->di_core.di_version);
+               di_ok = be16_to_cpu(dip->di_magic) == XFS_DINODE_MAGIC &&
+                           XFS_DINODE_GOOD_VERSION(dip->di_version);
                if (unlikely(XFS_TEST_ERROR(!di_ok, mp,
                                                XFS_ERRTAG_ITOBP_INOTOBP,
                                                XFS_RANDOM_ITOBP_INOTOBP))) {
-                       if (imap_flags & XFS_IMAP_BULKSTAT) {
+                       if (iget_flags & XFS_IGET_BULKSTAT) {
                                xfs_trans_brelse(tp, bp);
                                return XFS_ERROR(EINVAL);
                        }
@@ -191,7 +190,7 @@ xfs_imap_to_bp(
                                        "daddr %lld #%d (magic=%x)",
                                XFS_BUFTARG_NAME(mp->m_ddev_targp),
                                (unsigned long long)imap->im_blkno, i,
-                               be16_to_cpu(dip->di_core.di_magic));
+                               be16_to_cpu(dip->di_magic));
 #endif
                        xfs_trans_brelse(tp, bp);
                        return XFS_ERROR(EFSCORRUPTED);
@@ -232,12 +231,12 @@ xfs_inotobp(
        int             *offset,
        uint            imap_flags)
 {
-       xfs_imap_t      imap;
+       struct xfs_imap imap;
        xfs_buf_t       *bp;
        int             error;
 
        imap.im_blkno = 0;
-       error = xfs_imap(mp, tp, ino, &imap, imap_flags | XFS_IMAP_LOOKUP);
+       error = xfs_imap(mp, tp, ino, &imap, imap_flags);
        if (error)
                return error;
 
@@ -262,15 +261,11 @@ xfs_inotobp(
  * If a non-zero error is returned, then the contents of bpp and
  * dipp are undefined.
  *
- * If the inode is new and has not yet been initialized, use xfs_imap()
- * to determine the size and location of the buffer to read from disk.
- * If the inode has already been mapped to its buffer and read in once,
- * then use the mapping information stored in the inode rather than
- * calling xfs_imap().  This allows us to avoid the overhead of looking
- * at the inode btree for small block file systems (see xfs_dilocate()).
- * We can tell whether the inode has been mapped in before by comparing
- * its disk block address to 0.  Only uninitialized inodes will have
- * 0 for the disk block address.
+ * The inode is expected to already been mapped to its buffer and read
+ * in once, thus we can use the mapping information stored in the inode
+ * rather than calling xfs_imap().  This allows us to avoid the overhead
+ * of looking at the inode btree for small block file systems
+ * (see xfs_imap()).
  */
 int
 xfs_itobp(
@@ -279,40 +274,14 @@ xfs_itobp(
        xfs_inode_t     *ip,
        xfs_dinode_t    **dipp,
        xfs_buf_t       **bpp,
-       xfs_daddr_t     bno,
-       uint            imap_flags,
        uint            buf_flags)
 {
-       xfs_imap_t      imap;
        xfs_buf_t       *bp;
        int             error;
 
-       if (ip->i_blkno == (xfs_daddr_t)0) {
-               imap.im_blkno = bno;
-               error = xfs_imap(mp, tp, ip->i_ino, &imap,
-                                       XFS_IMAP_LOOKUP | imap_flags);
-               if (error)
-                       return error;
-
-               /*
-                * Fill in the fields in the inode that will be used to
-                * map the inode to its buffer from now on.
-                */
-               ip->i_blkno = imap.im_blkno;
-               ip->i_len = imap.im_len;
-               ip->i_boffset = imap.im_boffset;
-       } else {
-               /*
-                * We've already mapped the inode once, so just use the
-                * mapping that we saved the first time.
-                */
-               imap.im_blkno = ip->i_blkno;
-               imap.im_len = ip->i_len;
-               imap.im_boffset = ip->i_boffset;
-       }
-       ASSERT(bno == 0 || bno == imap.im_blkno);
+       ASSERT(ip->i_imap.im_blkno != 0);
 
-       error = xfs_imap_to_bp(mp, tp, &imap, &bp, buf_flags, imap_flags);
+       error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &bp, buf_flags, 0);
        if (error)
                return error;
 
@@ -323,7 +292,7 @@ xfs_itobp(
                return EAGAIN;
        }
 
-       *dipp = (xfs_dinode_t *)xfs_buf_offset(bp, imap.im_boffset);
+       *dipp = (xfs_dinode_t *)xfs_buf_offset(bp, ip->i_imap.im_boffset);
        *bpp = bp;
        return 0;
 }
@@ -350,26 +319,26 @@ xfs_iformat(
                XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t);
        error = 0;
 
-       if (unlikely(be32_to_cpu(dip->di_core.di_nextents) +
-                    be16_to_cpu(dip->di_core.di_anextents) >
-                    be64_to_cpu(dip->di_core.di_nblocks))) {
+       if (unlikely(be32_to_cpu(dip->di_nextents) +
+                    be16_to_cpu(dip->di_anextents) >
+                    be64_to_cpu(dip->di_nblocks))) {
                xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount,
                        "corrupt dinode %Lu, extent total = %d, nblocks = %Lu.",
                        (unsigned long long)ip->i_ino,
-                       (int)(be32_to_cpu(dip->di_core.di_nextents) +
-                             be16_to_cpu(dip->di_core.di_anextents)),
+                       (int)(be32_to_cpu(dip->di_nextents) +
+                             be16_to_cpu(dip->di_anextents)),
                        (unsigned long long)
-                               be64_to_cpu(dip->di_core.di_nblocks));
+                               be64_to_cpu(dip->di_nblocks));
                XFS_CORRUPTION_ERROR("xfs_iformat(1)", XFS_ERRLEVEL_LOW,
                                     ip->i_mount, dip);
                return XFS_ERROR(EFSCORRUPTED);
        }
 
-       if (unlikely(dip->di_core.di_forkoff > ip->i_mount->m_sb.sb_inodesize)) {
+       if (unlikely(dip->di_forkoff > ip->i_mount->m_sb.sb_inodesize)) {
                xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount,
                        "corrupt dinode %Lu, forkoff = 0x%x.",
                        (unsigned long long)ip->i_ino,
-                       dip->di_core.di_forkoff);
+                       dip->di_forkoff);
                XFS_CORRUPTION_ERROR("xfs_iformat(2)", XFS_ERRLEVEL_LOW,
                                     ip->i_mount, dip);
                return XFS_ERROR(EFSCORRUPTED);
@@ -380,25 +349,25 @@ xfs_iformat(
        case S_IFCHR:
        case S_IFBLK:
        case S_IFSOCK:
-               if (unlikely(dip->di_core.di_format != XFS_DINODE_FMT_DEV)) {
+               if (unlikely(dip->di_format != XFS_DINODE_FMT_DEV)) {
                        XFS_CORRUPTION_ERROR("xfs_iformat(3)", XFS_ERRLEVEL_LOW,
                                              ip->i_mount, dip);
                        return XFS_ERROR(EFSCORRUPTED);
                }
                ip->i_d.di_size = 0;
                ip->i_size = 0;
-               ip->i_df.if_u2.if_rdev = be32_to_cpu(dip->di_u.di_dev);
+               ip->i_df.if_u2.if_rdev = xfs_dinode_get_rdev(dip);
                break;
 
        case S_IFREG:
        case S_IFLNK:
        case S_IFDIR:
-               switch (dip->di_core.di_format) {
+               switch (dip->di_format) {
                case XFS_DINODE_FMT_LOCAL:
                        /*
                         * no local regular files yet
                         */
-                       if (unlikely((be16_to_cpu(dip->di_core.di_mode) & S_IFMT) == S_IFREG)) {
+                       if (unlikely((be16_to_cpu(dip->di_mode) & S_IFMT) == S_IFREG)) {
                                xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount,
                                        "corrupt inode %Lu "
                                        "(local format for regular file).",
@@ -409,7 +378,7 @@ xfs_iformat(
                                return XFS_ERROR(EFSCORRUPTED);
                        }
 
-                       di_size = be64_to_cpu(dip->di_core.di_size);
+                       di_size = be64_to_cpu(dip->di_size);
                        if (unlikely(di_size > XFS_DFORK_DSIZE(dip, ip->i_mount))) {
                                xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount,
                                        "corrupt inode %Lu "
@@ -451,10 +420,23 @@ xfs_iformat(
        ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP);
        ip->i_afp->if_ext_max =
                XFS_IFORK_ASIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t);
-       switch (dip->di_core.di_aformat) {
+       switch (dip->di_aformat) {
        case XFS_DINODE_FMT_LOCAL:
                atp = (xfs_attr_shortform_t *)XFS_DFORK_APTR(dip);
                size = be16_to_cpu(atp->hdr.totsize);
+
+               if (unlikely(size < sizeof(struct xfs_attr_sf_hdr))) {
+                       xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount,
+                               "corrupt inode %Lu "
+                               "(bad attr fork size %Ld).",
+                               (unsigned long long) ip->i_ino,
+                               (long long) size);
+                       XFS_CORRUPTION_ERROR("xfs_iformat(8)",
+                                            XFS_ERRLEVEL_LOW,
+                                            ip->i_mount, dip);
+                       return XFS_ERROR(EFSCORRUPTED);
+               }
+
                error = xfs_iformat_local(ip, dip, XFS_ATTR_FORK, size);
                break;
        case XFS_DINODE_FMT_EXTENTS:
@@ -663,7 +645,7 @@ xfs_iformat_btree(
 void
 xfs_dinode_from_disk(
        xfs_icdinode_t          *to,
-       xfs_dinode_core_t       *from)
+       xfs_dinode_t            *from)
 {
        to->di_magic = be16_to_cpu(from->di_magic);
        to->di_mode = be16_to_cpu(from->di_mode);
@@ -697,7 +679,7 @@ xfs_dinode_from_disk(
 
 void
 xfs_dinode_to_disk(
-       xfs_dinode_core_t       *to,
+       xfs_dinode_t            *to,
        xfs_icdinode_t          *from)
 {
        to->di_magic = cpu_to_be16(from->di_magic);
@@ -784,140 +766,57 @@ uint
 xfs_dic2xflags(
        xfs_dinode_t            *dip)
 {
-       xfs_dinode_core_t       *dic = &dip->di_core;
-
-       return _xfs_dic2xflags(be16_to_cpu(dic->di_flags)) |
+       return _xfs_dic2xflags(be16_to_cpu(dip->di_flags)) |
                                (XFS_DFORK_Q(dip) ? XFS_XFLAG_HASATTR : 0);
 }
 
 /*
- * Allocate and initialise an xfs_inode.
- */
-STATIC struct xfs_inode *
-xfs_inode_alloc(
-       struct xfs_mount        *mp,
-       xfs_ino_t               ino)
-{
-       struct xfs_inode        *ip;
-
-       /*
-        * if this didn't occur in transactions, we could use
-        * KM_MAYFAIL and return NULL here on ENOMEM. Set the
-        * code up to do this anyway.
-        */
-       ip = kmem_zone_alloc(xfs_inode_zone, KM_SLEEP);
-       if (!ip)
-               return NULL;
-
-       ASSERT(atomic_read(&ip->i_iocount) == 0);
-       ASSERT(atomic_read(&ip->i_pincount) == 0);
-       ASSERT(!spin_is_locked(&ip->i_flags_lock));
-       ASSERT(completion_done(&ip->i_flush));
-
-       /*
-        * initialise the VFS inode here to get failures
-        * out of the way early.
-        */
-       if (!inode_init_always(mp->m_super, VFS_I(ip))) {
-               kmem_zone_free(xfs_inode_zone, ip);
-               return NULL;
-       }
-
-       /* initialise the xfs inode */
-       ip->i_ino = ino;
-       ip->i_mount = mp;
-       ip->i_blkno = 0;
-       ip->i_len = 0;
-       ip->i_boffset =0;
-       ip->i_afp = NULL;
-       memset(&ip->i_df, 0, sizeof(xfs_ifork_t));
-       ip->i_flags = 0;
-       ip->i_update_core = 0;
-       ip->i_update_size = 0;
-       ip->i_delayed_blks = 0;
-       memset(&ip->i_d, 0, sizeof(xfs_icdinode_t));
-       ip->i_size = 0;
-       ip->i_new_size = 0;
-
-       /*
-        * Initialize inode's trace buffers.
-        */
-#ifdef XFS_INODE_TRACE
-       ip->i_trace = ktrace_alloc(INODE_TRACE_SIZE, KM_NOFS);
-#endif
-#ifdef XFS_BMAP_TRACE
-       ip->i_xtrace = ktrace_alloc(XFS_BMAP_KTRACE_SIZE, KM_NOFS);
-#endif
-#ifdef XFS_BTREE_TRACE
-       ip->i_btrace = ktrace_alloc(XFS_BMBT_KTRACE_SIZE, KM_NOFS);
-#endif
-#ifdef XFS_RW_TRACE
-       ip->i_rwtrace = ktrace_alloc(XFS_RW_KTRACE_SIZE, KM_NOFS);
-#endif
-#ifdef XFS_ILOCK_TRACE
-       ip->i_lock_trace = ktrace_alloc(XFS_ILOCK_KTRACE_SIZE, KM_NOFS);
-#endif
-#ifdef XFS_DIR2_TRACE
-       ip->i_dir_trace = ktrace_alloc(XFS_DIR2_KTRACE_SIZE, KM_NOFS);
-#endif
-
-       return ip;
-}
-
-/*
- * Given a mount structure and an inode number, return a pointer
- * to a newly allocated in-core inode corresponding to the given
- * inode number.
- *
- * Initialize the inode's attributes and extent pointers if it
- * already has them (it will not if the inode has no links).
+ * Read the disk inode attributes into the in-core inode structure.
  */
 int
 xfs_iread(
        xfs_mount_t     *mp,
        xfs_trans_t     *tp,
-       xfs_ino_t       ino,
-       xfs_inode_t     **ipp,
+       xfs_inode_t     *ip,
        xfs_daddr_t     bno,
-       uint            imap_flags)
+       uint            iget_flags)
 {
        xfs_buf_t       *bp;
        xfs_dinode_t    *dip;
-       xfs_inode_t     *ip;
        int             error;
 
-       ip = xfs_inode_alloc(mp, ino);
-       if (!ip)
-               return ENOMEM;
+       /*
+        * Fill in the location information in the in-core inode.
+        */
+       ip->i_imap.im_blkno = bno;
+       error = xfs_imap(mp, tp, ip->i_ino, &ip->i_imap, iget_flags);
+       if (error)
+               return error;
+       ASSERT(bno == 0 || bno == ip->i_imap.im_blkno);
 
        /*
-        * Get pointer's to the on-disk inode and the buffer containing it.
-        * If the inode number refers to a block outside the file system
-        * then xfs_itobp() will return NULL.  In this case we should
-        * return NULL as well.  Set i_blkno to 0 so that xfs_itobp() will
-        * know that this is a new incore inode.
+        * Get pointers to the on-disk inode and the buffer containing it.
         */
-       error = xfs_itobp(mp, tp, ip, &dip, &bp, bno, imap_flags, XFS_BUF_LOCK);
-       if (error) {
-               xfs_idestroy(ip);
+       error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &bp,
+                              XFS_BUF_LOCK, iget_flags);
+       if (error)
                return error;
-       }
+       dip = (xfs_dinode_t *)xfs_buf_offset(bp, ip->i_imap.im_boffset);
 
        /*
         * If we got something that isn't an inode it means someone
         * (nfs or dmi) has a stale handle.
         */
-       if (be16_to_cpu(dip->di_core.di_magic) != XFS_DINODE_MAGIC) {
-               xfs_idestroy(ip);
-               xfs_trans_brelse(tp, bp);
+       if (be16_to_cpu(dip->di_magic) != XFS_DINODE_MAGIC) {
 #ifdef DEBUG
                xfs_fs_cmn_err(CE_ALERT, mp, "xfs_iread: "
-                               "dip->di_core.di_magic (0x%x) != "
+                               "dip->di_magic (0x%x) != "
                                "XFS_DINODE_MAGIC (0x%x)",
-                               be16_to_cpu(dip->di_core.di_magic),
+                               be16_to_cpu(dip->di_magic),
                                XFS_DINODE_MAGIC);
 #endif /* DEBUG */
-               return XFS_ERROR(EINVAL);
+               error = XFS_ERROR(EINVAL);
+               goto out_brelse;
        }
 
        /*
@@ -927,24 +826,22 @@ xfs_iread(
         * specific information.
         * Otherwise, just get the truly permanent information.
         */
-       if (dip->di_core.di_mode) {
-               xfs_dinode_from_disk(&ip->i_d, &dip->di_core);
+       if (dip->di_mode) {
+               xfs_dinode_from_disk(&ip->i_d, dip);
                error = xfs_iformat(ip, dip);
                if (error)  {
-                       xfs_idestroy(ip);
-                       xfs_trans_brelse(tp, bp);
 #ifdef DEBUG
                        xfs_fs_cmn_err(CE_ALERT, mp, "xfs_iread: "
                                        "xfs_iformat() returned error %d",
                                        error);
 #endif /* DEBUG */
-                       return error;
+                       goto out_brelse;
                }
        } else {
-               ip->i_d.di_magic = be16_to_cpu(dip->di_core.di_magic);
-               ip->i_d.di_version = dip->di_core.di_version;
-               ip->i_d.di_gen = be32_to_cpu(dip->di_core.di_gen);
-               ip->i_d.di_flushiter = be16_to_cpu(dip->di_core.di_flushiter);
+               ip->i_d.di_magic = be16_to_cpu(dip->di_magic);
+               ip->i_d.di_version = dip->di_version;
+               ip->i_d.di_gen = be32_to_cpu(dip->di_gen);
+               ip->i_d.di_flushiter = be16_to_cpu(dip->di_flushiter);
                /*
                 * Make sure to pull in the mode here as well in
                 * case the inode is released without being used.
@@ -972,7 +869,7 @@ xfs_iread(
         * the new format. We don't change the version number so that we
         * can distinguish this from a real new format inode.
         */
-       if (ip->i_d.di_version == XFS_DINODE_VERSION_1) {
+       if (ip->i_d.di_version == 1) {
                ip->i_d.di_nlink = ip->i_d.di_onlink;
                ip->i_d.di_onlink = 0;
                ip->i_d.di_projid = 0;
@@ -986,7 +883,7 @@ xfs_iread(
         * around for a while.  This helps to keep recently accessed
         * meta-data in-core longer.
         */
-        XFS_BUF_SET_REF(bp, XFS_INO_REF);
+       XFS_BUF_SET_REF(bp, XFS_INO_REF);
 
        /*
         * Use xfs_trans_brelse() to release the buffer containing the
@@ -1001,9 +898,9 @@ xfs_iread(
         * to worry about the inode being changed just because we released
         * the buffer.
         */
+ out_brelse:
        xfs_trans_brelse(tp, bp);
-       *ipp = ip;
-       return 0;
+       return error;
 }
 
 /*
@@ -1140,8 +1037,8 @@ xfs_ialloc(
         * here rather than here and in the flush/logging code.
         */
        if (xfs_sb_version_hasnlink(&tp->t_mountp->m_sb) &&
-           ip->i_d.di_version == XFS_DINODE_VERSION_1) {
-               ip->i_d.di_version = XFS_DINODE_VERSION_2;
+           ip->i_d.di_version == 1) {
+               ip->i_d.di_version = 2;
                /*
                 * We've already zeroed the old link count, the projid field,
                 * and the pad field.
@@ -1151,7 +1048,7 @@ xfs_ialloc(
        /*
         * Project ids won't be stored on disk if we are using a version 1 inode.
         */
-       if ((prid != 0) && (ip->i_d.di_version == XFS_DINODE_VERSION_1))
+       if ((prid != 0) && (ip->i_d.di_version == 1))
                xfs_bump_ino_vers2(tp, ip);
 
        if (pip && XFS_INHERIT_GID(pip)) {
@@ -1438,8 +1335,8 @@ xfs_itrunc_trace(
  * direct I/O with the truncate operation.  Also, because we hold
  * the IOLOCK in exclusive mode, we prevent new direct I/Os from being
  * started until the truncate completes and drops the lock. Essentially,
- * the vn_iowait() call forms an I/O barrier that provides strict ordering
- * between direct I/Os and the truncate operation.
+ * the xfs_ioend_wait() call forms an I/O barrier that provides strict
+ * ordering between direct I/Os and the truncate operation.
  *
  * The flags parameter can have either the value XFS_ITRUNC_DEFINITE
  * or XFS_ITRUNC_MAYBE.  The XFS_ITRUNC_MAYBE value should be used
@@ -1470,7 +1367,7 @@ xfs_itruncate_start(
 
        /* wait for the completion of any pending DIOs */
        if (new_size == 0 || new_size < ip->i_size)
-               vn_iowait(ip);
+               xfs_ioend_wait(ip);
 
        /*
         * Call toss_pages or flushinval_pages to get rid of pages
@@ -1717,10 +1614,10 @@ xfs_itruncate_finish(
                 * in this file with garbage in them once recovery
                 * runs.
                 */
-               XFS_BMAP_INIT(&free_list, &first_block);
+               xfs_bmap_init(&free_list, &first_block);
                error = xfs_bunmapi(ntp, ip,
                                    first_unmap_block, unmap_len,
-                                   XFS_BMAPI_AFLAG(fork) |
+                                   xfs_bmapi_aflag(fork) |
                                      (sync ? 0 : XFS_BMAPI_ASYNC),
                                    XFS_ITRUNC_MAX_EXTENTS,
                                    &first_block, &free_list,
@@ -1781,8 +1678,14 @@ xfs_itruncate_finish(
                xfs_trans_ijoin(ntp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
                xfs_trans_ihold(ntp, ip);
 
-               if (!error)
-                       error = xfs_trans_reserve(ntp, 0,
+               if (error)
+                       return error;
+               /*
+                * transaction commit worked ok so we can drop the extra ticket
+                * reference that we gained in xfs_trans_dup()
+                */
+               xfs_log_ticket_put(ntp->t_ticket);
+               error = xfs_trans_reserve(ntp, 0,
                                        XFS_ITRUNCATE_LOG_RES(mp), 0,
                                        XFS_TRANS_PERM_LOG_RES,
                                        XFS_ITRUNCATE_LOG_COUNT);
@@ -1836,13 +1739,10 @@ xfs_iunlink(
        xfs_dinode_t    *dip;
        xfs_buf_t       *agibp;
        xfs_buf_t       *ibp;
-       xfs_agnumber_t  agno;
-       xfs_daddr_t     agdaddr;
        xfs_agino_t     agino;
        short           bucket_index;
        int             offset;
        int             error;
-       int             agi_ok;
 
        ASSERT(ip->i_d.di_nlink == 0);
        ASSERT(ip->i_d.di_mode != 0);
@@ -1850,31 +1750,15 @@ xfs_iunlink(
 
        mp = tp->t_mountp;
 
-       agno = XFS_INO_TO_AGNO(mp, ip->i_ino);
-       agdaddr = XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp));
-
        /*
         * Get the agi buffer first.  It ensures lock ordering
         * on the list.
         */
-       error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, agdaddr,
-                                  XFS_FSS_TO_BB(mp, 1), 0, &agibp);
+       error = xfs_read_agi(mp, tp, XFS_INO_TO_AGNO(mp, ip->i_ino), &agibp);
        if (error)
                return error;
-
-       /*
-        * Validate the magic number of the agi block.
-        */
        agi = XFS_BUF_TO_AGI(agibp);
-       agi_ok =
-               be32_to_cpu(agi->agi_magicnum) == XFS_AGI_MAGIC &&
-               XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum));
-       if (unlikely(XFS_TEST_ERROR(!agi_ok, mp, XFS_ERRTAG_IUNLINK,
-                       XFS_RANDOM_IUNLINK))) {
-               XFS_CORRUPTION_ERROR("xfs_iunlink", XFS_ERRLEVEL_LOW, mp, agi);
-               xfs_trans_brelse(tp, agibp);
-               return XFS_ERROR(EFSCORRUPTED);
-       }
+
        /*
         * Get the index into the agi hash table for the
         * list this inode will go on.
@@ -1892,14 +1776,14 @@ xfs_iunlink(
                 * Here we put the head pointer into our next pointer,
                 * and then we fall through to point the head at us.
                 */
-               error = xfs_itobp(mp, tp, ip, &dip, &ibp, 0, 0, XFS_BUF_LOCK);
+               error = xfs_itobp(mp, tp, ip, &dip, &ibp, XFS_BUF_LOCK);
                if (error)
                        return error;
 
                ASSERT(be32_to_cpu(dip->di_next_unlinked) == NULLAGINO);
                /* both on-disk, don't endian flip twice */
                dip->di_next_unlinked = agi->agi_unlinked[bucket_index];
-               offset = ip->i_boffset +
+               offset = ip->i_imap.im_boffset +
                        offsetof(xfs_dinode_t, di_next_unlinked);
                xfs_trans_inode_buf(tp, ibp);
                xfs_trans_log_buf(tp, ibp, offset,
@@ -1934,7 +1818,6 @@ xfs_iunlink_remove(
        xfs_buf_t       *agibp;
        xfs_buf_t       *ibp;
        xfs_agnumber_t  agno;
-       xfs_daddr_t     agdaddr;
        xfs_agino_t     agino;
        xfs_agino_t     next_agino;
        xfs_buf_t       *last_ibp;
@@ -1942,45 +1825,20 @@ xfs_iunlink_remove(
        short           bucket_index;
        int             offset, last_offset = 0;
        int             error;
-       int             agi_ok;
 
-       /*
-        * First pull the on-disk inode from the AGI unlinked list.
-        */
        mp = tp->t_mountp;
-
        agno = XFS_INO_TO_AGNO(mp, ip->i_ino);
-       agdaddr = XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp));
 
        /*
         * Get the agi buffer first.  It ensures lock ordering
         * on the list.
         */
-       error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, agdaddr,
-                                  XFS_FSS_TO_BB(mp, 1), 0, &agibp);
-       if (error) {
-               cmn_err(CE_WARN,
-                       "xfs_iunlink_remove: xfs_trans_read_buf()  returned an error %d on %s.  Returning error.",
-                       error, mp->m_fsname);
+       error = xfs_read_agi(mp, tp, agno, &agibp);
+       if (error)
                return error;
-       }
-       /*
-        * Validate the magic number of the agi block.
-        */
+
        agi = XFS_BUF_TO_AGI(agibp);
-       agi_ok =
-               be32_to_cpu(agi->agi_magicnum) == XFS_AGI_MAGIC &&
-               XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum));
-       if (unlikely(XFS_TEST_ERROR(!agi_ok, mp, XFS_ERRTAG_IUNLINK_REMOVE,
-                       XFS_RANDOM_IUNLINK_REMOVE))) {
-               XFS_CORRUPTION_ERROR("xfs_iunlink_remove", XFS_ERRLEVEL_LOW,
-                                    mp, agi);
-               xfs_trans_brelse(tp, agibp);
-               cmn_err(CE_WARN,
-                       "xfs_iunlink_remove: XFS_TEST_ERROR()  returned an error on %s.  Returning EFSCORRUPTED.",
-                        mp->m_fsname);
-               return XFS_ERROR(EFSCORRUPTED);
-       }
+
        /*
         * Get the index into the agi hash table for the
         * list this inode will go on.
@@ -2000,7 +1858,7 @@ xfs_iunlink_remove(
                 * of dealing with the buffer when there is no need to
                 * change it.
                 */
-               error = xfs_itobp(mp, tp, ip, &dip, &ibp, 0, 0, XFS_BUF_LOCK);
+               error = xfs_itobp(mp, tp, ip, &dip, &ibp, XFS_BUF_LOCK);
                if (error) {
                        cmn_err(CE_WARN,
                                "xfs_iunlink_remove: xfs_itobp()  returned an error %d on %s.  Returning error.",
@@ -2011,7 +1869,7 @@ xfs_iunlink_remove(
                ASSERT(next_agino != 0);
                if (next_agino != NULLAGINO) {
                        dip->di_next_unlinked = cpu_to_be32(NULLAGINO);
-                       offset = ip->i_boffset +
+                       offset = ip->i_imap.im_boffset +
                                offsetof(xfs_dinode_t, di_next_unlinked);
                        xfs_trans_inode_buf(tp, ibp);
                        xfs_trans_log_buf(tp, ibp, offset,
@@ -2062,7 +1920,7 @@ xfs_iunlink_remove(
                 * Now last_ibp points to the buffer previous to us on
                 * the unlinked list.  Pull us from the list.
                 */
-               error = xfs_itobp(mp, tp, ip, &dip, &ibp, 0, 0, XFS_BUF_LOCK);
+               error = xfs_itobp(mp, tp, ip, &dip, &ibp, XFS_BUF_LOCK);
                if (error) {
                        cmn_err(CE_WARN,
                                "xfs_iunlink_remove: xfs_itobp()  returned an error %d on %s.  Returning error.",
@@ -2074,7 +1932,7 @@ xfs_iunlink_remove(
                ASSERT(next_agino != agino);
                if (next_agino != NULLAGINO) {
                        dip->di_next_unlinked = cpu_to_be32(NULLAGINO);
-                       offset = ip->i_boffset +
+                       offset = ip->i_imap.im_boffset +
                                offsetof(xfs_dinode_t, di_next_unlinked);
                        xfs_trans_inode_buf(tp, ibp);
                        xfs_trans_log_buf(tp, ibp, offset,
@@ -2317,7 +2175,7 @@ xfs_ifree(
 
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
 
-       error = xfs_itobp(ip->i_mount, tp, ip, &dip, &ibp, 0, 0, XFS_BUF_LOCK);
+       error = xfs_itobp(ip->i_mount, tp, ip, &dip, &ibp, XFS_BUF_LOCK);
        if (error)
                return error;
 
@@ -2333,7 +2191,7 @@ xfs_ifree(
        * This is a temporary hack that would require a proper fix
        * in the future.
        */
-       dip->di_core.di_mode = 0;
+       dip->di_mode = 0;
 
        if (delete) {
                xfs_ifree_cluster(ip, tp, first_ino);
@@ -2561,64 +2419,6 @@ xfs_idata_realloc(
        ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork));
 }
 
-
-
-
-/*
- * Map inode to disk block and offset.
- *
- * mp -- the mount point structure for the current file system
- * tp -- the current transaction
- * ino -- the inode number of the inode to be located
- * imap -- this structure is filled in with the information necessary
- *      to retrieve the given inode from disk
- * flags -- flags to pass to xfs_dilocate indicating whether or not
- *      lookups in the inode btree were OK or not
- */
-int
-xfs_imap(
-       xfs_mount_t     *mp,
-       xfs_trans_t     *tp,
-       xfs_ino_t       ino,
-       xfs_imap_t      *imap,
-       uint            flags)
-{
-       xfs_fsblock_t   fsbno;
-       int             len;
-       int             off;
-       int             error;
-
-       fsbno = imap->im_blkno ?
-               XFS_DADDR_TO_FSB(mp, imap->im_blkno) : NULLFSBLOCK;
-       error = xfs_dilocate(mp, tp, ino, &fsbno, &len, &off, flags);
-       if (error)
-               return error;
-
-       imap->im_blkno = XFS_FSB_TO_DADDR(mp, fsbno);
-       imap->im_len = XFS_FSB_TO_BB(mp, len);
-       imap->im_agblkno = XFS_FSB_TO_AGBNO(mp, fsbno);
-       imap->im_ioffset = (ushort)off;
-       imap->im_boffset = (ushort)(off << mp->m_sb.sb_inodelog);
-
-       /*
-        * If the inode number maps to a block outside the bounds
-        * of the file system then return NULL rather than calling
-        * read_buf and panicing when we get an error from the
-        * driver.
-        */
-       if ((imap->im_blkno + imap->im_len) >
-           XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)) {
-               xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: "
-                       "(imap->im_blkno (0x%llx) + imap->im_len (0x%llx)) > "
-                       " XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks) (0x%llx)",
-                       (unsigned long long) imap->im_blkno,
-                       (unsigned long long) imap->im_len,
-                       XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks));
-               return EINVAL;
-       }
-       return 0;
-}
-
 void
 xfs_idestroy_fork(
        xfs_inode_t     *ip,
@@ -2663,78 +2463,6 @@ xfs_idestroy_fork(
 }
 
 /*
- * This is called free all the memory associated with an inode.
- * It must free the inode itself and any buffers allocated for
- * if_extents/if_data and if_broot.  It must also free the lock
- * associated with the inode.
- *
- * Note: because we don't initialise everything on reallocation out
- * of the zone, we must ensure we nullify everything correctly before
- * freeing the structure.
- */
-void
-xfs_idestroy(
-       xfs_inode_t     *ip)
-{
-       switch (ip->i_d.di_mode & S_IFMT) {
-       case S_IFREG:
-       case S_IFDIR:
-       case S_IFLNK:
-               xfs_idestroy_fork(ip, XFS_DATA_FORK);
-               break;
-       }
-       if (ip->i_afp)
-               xfs_idestroy_fork(ip, XFS_ATTR_FORK);
-
-#ifdef XFS_INODE_TRACE
-       ktrace_free(ip->i_trace);
-#endif
-#ifdef XFS_BMAP_TRACE
-       ktrace_free(ip->i_xtrace);
-#endif
-#ifdef XFS_BTREE_TRACE
-       ktrace_free(ip->i_btrace);
-#endif
-#ifdef XFS_RW_TRACE
-       ktrace_free(ip->i_rwtrace);
-#endif
-#ifdef XFS_ILOCK_TRACE
-       ktrace_free(ip->i_lock_trace);
-#endif
-#ifdef XFS_DIR2_TRACE
-       ktrace_free(ip->i_dir_trace);
-#endif
-       if (ip->i_itemp) {
-               /*
-                * Only if we are shutting down the fs will we see an
-                * inode still in the AIL. If it is there, we should remove
-                * it to prevent a use-after-free from occurring.
-                */
-               xfs_log_item_t  *lip = &ip->i_itemp->ili_item;
-               struct xfs_ail  *ailp = lip->li_ailp;
-
-               ASSERT(((lip->li_flags & XFS_LI_IN_AIL) == 0) ||
-                                      XFS_FORCED_SHUTDOWN(ip->i_mount));
-               if (lip->li_flags & XFS_LI_IN_AIL) {
-                       spin_lock(&ailp->xa_lock);
-                       if (lip->li_flags & XFS_LI_IN_AIL)
-                               xfs_trans_ail_delete(ailp, lip);
-                       else
-                               spin_unlock(&ailp->xa_lock);
-               }
-               xfs_inode_item_destroy(ip);
-               ip->i_itemp = NULL;
-       }
-       /* asserts to verify all state is correct here */
-       ASSERT(atomic_read(&ip->i_iocount) == 0);
-       ASSERT(atomic_read(&ip->i_pincount) == 0);
-       ASSERT(!spin_is_locked(&ip->i_flags_lock));
-       ASSERT(completion_done(&ip->i_flush));
-       kmem_zone_free(xfs_inode_zone, ip);
-}
-
-
-/*
  * Increment the pin count of the given buffer.
  * This value is protected by ipinlock spinlock in the mount structure.
  */
@@ -2842,7 +2570,7 @@ xfs_iextents_copy(
        for (i = 0; i < nrecs; i++) {
                xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i);
                start_block = xfs_bmbt_get_startblock(ep);
-               if (ISNULLSTARTBLOCK(start_block)) {
+               if (isnullstartblock(start_block)) {
                        /*
                         * It's a delayed allocation extent, so skip it.
                         */
@@ -2947,15 +2675,16 @@ xfs_iflush_fork(
        case XFS_DINODE_FMT_DEV:
                if (iip->ili_format.ilf_fields & XFS_ILOG_DEV) {
                        ASSERT(whichfork == XFS_DATA_FORK);
-                       dip->di_u.di_dev = cpu_to_be32(ip->i_df.if_u2.if_rdev);
+                       xfs_dinode_put_rdev(dip, ip->i_df.if_u2.if_rdev);
                }
                break;
 
        case XFS_DINODE_FMT_UUID:
                if (iip->ili_format.ilf_fields & XFS_ILOG_UUID) {
                        ASSERT(whichfork == XFS_DATA_FORK);
-                       memcpy(&dip->di_u.di_muuid, &ip->i_df.if_u2.if_uuid,
-                               sizeof(uuid_t));
+                       memcpy(XFS_DFORK_DPTR(dip),
+                              &ip->i_df.if_u2.if_uuid,
+                              sizeof(uuid_t));
                }
                break;
 
@@ -3088,7 +2817,6 @@ cluster_corrupt_out:
                        XFS_BUF_CLR_BDSTRAT_FUNC(bp);
                        XFS_BUF_UNDONE(bp);
                        XFS_BUF_STALE(bp);
-                       XFS_BUF_SHUT(bp);
                        XFS_BUF_ERROR(bp,EIO);
                        xfs_biodone(bp);
                } else {
@@ -3230,7 +2958,7 @@ xfs_iflush(
        /*
         * Get the buffer containing the on-disk inode.
         */
-       error = xfs_itobp(mp, NULL, ip, &dip, &bp, 0, 0,
+       error = xfs_itobp(mp, NULL, ip, &dip, &bp,
                                noblock ? XFS_BUF_TRYLOCK : XFS_BUF_LOCK);
        if (error || !bp) {
                xfs_ifunlock(ip);
@@ -3311,7 +3039,7 @@ xfs_iflush_int(
        }
 
        /* set *dip = inode's place in the buffer */
-       dip = (xfs_dinode_t *)xfs_buf_offset(bp, ip->i_boffset);
+       dip = (xfs_dinode_t *)xfs_buf_offset(bp, ip->i_imap.im_boffset);
 
        /*
         * Clear i_update_core before copying out the data.
@@ -3333,11 +3061,11 @@ xfs_iflush_int(
         */
        xfs_synchronize_atime(ip);
 
-       if (XFS_TEST_ERROR(be16_to_cpu(dip->di_core.di_magic) != XFS_DINODE_MAGIC,
+       if (XFS_TEST_ERROR(be16_to_cpu(dip->di_magic) != XFS_DINODE_MAGIC,
                               mp, XFS_ERRTAG_IFLUSH_1, XFS_RANDOM_IFLUSH_1)) {
                xfs_cmn_err(XFS_PTAG_IFLUSH, CE_ALERT, mp,
                    "xfs_iflush: Bad inode %Lu magic number 0x%x, ptr 0x%p",
-                       ip->i_ino, be16_to_cpu(dip->di_core.di_magic), dip);
+                       ip->i_ino, be16_to_cpu(dip->di_magic), dip);
                goto corrupt_out;
        }
        if (XFS_TEST_ERROR(ip->i_d.di_magic != XFS_DINODE_MAGIC,
@@ -3400,7 +3128,7 @@ xfs_iflush_int(
         * because if the inode is dirty at all the core must
         * be.
         */
-       xfs_dinode_to_disk(&dip->di_core, &ip->i_d);
+       xfs_dinode_to_disk(dip, &ip->i_d);
 
        /* Wrap, we never let the log put out DI_MAX_FLUSH */
        if (ip->i_d.di_flushiter == DI_MAX_FLUSH)
@@ -3412,28 +3140,27 @@ xfs_iflush_int(
         * convert back to the old inode format.  If the superblock version
         * has been updated, then make the conversion permanent.
         */
-       ASSERT(ip->i_d.di_version == XFS_DINODE_VERSION_1 ||
-              xfs_sb_version_hasnlink(&mp->m_sb));
-       if (ip->i_d.di_version == XFS_DINODE_VERSION_1) {
+       ASSERT(ip->i_d.di_version == 1 || xfs_sb_version_hasnlink(&mp->m_sb));
+       if (ip->i_d.di_version == 1) {
                if (!xfs_sb_version_hasnlink(&mp->m_sb)) {
                        /*
                         * Convert it back.
                         */
                        ASSERT(ip->i_d.di_nlink <= XFS_MAXLINK_1);
-                       dip->di_core.di_onlink = cpu_to_be16(ip->i_d.di_nlink);
+                       dip->di_onlink = cpu_to_be16(ip->i_d.di_nlink);
                } else {
                        /*
                         * The superblock version has already been bumped,
                         * so just make the conversion to the new inode
                         * format permanent.
                         */
-                       ip->i_d.di_version = XFS_DINODE_VERSION_2;
-                       dip->di_core.di_version =  XFS_DINODE_VERSION_2;
+                       ip->i_d.di_version = 2;
+                       dip->di_version = 2;
                        ip->i_d.di_onlink = 0;
-                       dip->di_core.di_onlink = 0;
+                       dip->di_onlink = 0;
                        memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad));
-                       memset(&(dip->di_core.di_pad[0]), 0,
-                             sizeof(dip->di_core.di_pad));
+                       memset(&(dip->di_pad[0]), 0,
+                             sizeof(dip->di_pad));
                        ASSERT(ip->i_d.di_projid == 0);
                }
        }
@@ -3517,8 +3244,6 @@ corrupt_out:
 
 
 #ifdef XFS_ILOCK_TRACE
-ktrace_t       *xfs_ilock_trace_buf;
-
 void
 xfs_ilock_trace(xfs_inode_t *ip, int lock, unsigned int lockflags, inst_t *ra)
 {