]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blobdiff - libxfs/util.c
xfsprogs: make static things static
[thirdparty/xfsprogs-dev.git] / libxfs / util.c
index 6464a1b19b172e2a547772722dfd744a36c71499..993218615d008b745a1efb616b0e1876dab6e6ae 100644 (file)
@@ -1,25 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Copyright (c) 2000-2005 Silicon Graphics, Inc.
  * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write the Free Software Foundation,
- * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#include <xfs.h>
-#include <time.h>
-#include <stdio.h>
-#include <stdarg.h>
+#include "libxfs_priv.h"
+#include "libxfs_io.h"
+#include "init.h"
+#include "xfs_fs.h"
+#include "xfs_shared.h"
+#include "xfs_format.h"
+#include "xfs_log_format.h"
+#include "xfs_trans_resv.h"
+#include "xfs_mount.h"
+#include "xfs_defer.h"
+#include "xfs_inode_buf.h"
+#include "xfs_inode_fork.h"
+#include "xfs_inode.h"
+#include "xfs_trans.h"
+#include "xfs_bmap.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_trans_space.h"
+#include "xfs_ialloc.h"
+#include "xfs_alloc.h"
+#include "xfs_bit.h"
+#include "xfs_da_format.h"
+#include "xfs_da_btree.h"
+#include "xfs_dir2_priv.h"
 
 /*
  * Calculate the worst case log unit reservation for a given superblock
@@ -146,18 +153,72 @@ libxfs_trans_ichgtime(
        gettimeofday(&stv, (struct timezone *)0);
        tv.tv_sec = stv.tv_sec;
        tv.tv_nsec = stv.tv_usec * 1000;
-       if (flags & XFS_ICHGTIME_MOD) {
-               ip->i_d.di_mtime.t_sec = (__int32_t)tv.tv_sec;
-               ip->i_d.di_mtime.t_nsec = (__int32_t)tv.tv_nsec;
-       }
-       if (flags & XFS_ICHGTIME_CHG) {
-               ip->i_d.di_ctime.t_sec = (__int32_t)tv.tv_sec;
-               ip->i_d.di_ctime.t_nsec = (__int32_t)tv.tv_nsec;
-       }
+       if (flags & XFS_ICHGTIME_MOD)
+               VFS_I(ip)->i_mtime = tv;
+       if (flags & XFS_ICHGTIME_CHG)
+               VFS_I(ip)->i_ctime = tv;
        if (flags & XFS_ICHGTIME_CREATE) {
-               ip->i_d.di_crtime.t_sec = (__int32_t)tv.tv_sec;
-               ip->i_d.di_crtime.t_nsec = (__int32_t)tv.tv_nsec;
+               ip->i_d.di_crtime.t_sec = (int32_t)tv.tv_sec;
+               ip->i_d.di_crtime.t_nsec = (int32_t)tv.tv_nsec;
+       }
+}
+
+STATIC uint16_t
+xfs_flags2diflags(
+       struct xfs_inode        *ip,
+       unsigned int            xflags)
+{
+       /* can't set PREALLOC this way, just preserve it */
+       uint16_t                di_flags =
+               (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC);
+
+       if (xflags & FS_XFLAG_IMMUTABLE)
+               di_flags |= XFS_DIFLAG_IMMUTABLE;
+       if (xflags & FS_XFLAG_APPEND)
+               di_flags |= XFS_DIFLAG_APPEND;
+       if (xflags & FS_XFLAG_SYNC)
+               di_flags |= XFS_DIFLAG_SYNC;
+       if (xflags & FS_XFLAG_NOATIME)
+               di_flags |= XFS_DIFLAG_NOATIME;
+       if (xflags & FS_XFLAG_NODUMP)
+               di_flags |= XFS_DIFLAG_NODUMP;
+       if (xflags & FS_XFLAG_NODEFRAG)
+               di_flags |= XFS_DIFLAG_NODEFRAG;
+       if (xflags & FS_XFLAG_FILESTREAM)
+               di_flags |= XFS_DIFLAG_FILESTREAM;
+       if (S_ISDIR(VFS_I(ip)->i_mode)) {
+               if (xflags & FS_XFLAG_RTINHERIT)
+                       di_flags |= XFS_DIFLAG_RTINHERIT;
+               if (xflags & FS_XFLAG_NOSYMLINKS)
+                       di_flags |= XFS_DIFLAG_NOSYMLINKS;
+               if (xflags & FS_XFLAG_EXTSZINHERIT)
+                       di_flags |= XFS_DIFLAG_EXTSZINHERIT;
+               if (xflags & FS_XFLAG_PROJINHERIT)
+                       di_flags |= XFS_DIFLAG_PROJINHERIT;
+       } else if (S_ISREG(VFS_I(ip)->i_mode)) {
+               if (xflags & FS_XFLAG_REALTIME)
+                       di_flags |= XFS_DIFLAG_REALTIME;
+               if (xflags & FS_XFLAG_EXTSIZE)
+                       di_flags |= XFS_DIFLAG_EXTSIZE;
        }
+
+       return di_flags;
+}
+
+STATIC uint64_t
+xfs_flags2diflags2(
+       struct xfs_inode        *ip,
+       unsigned int            xflags)
+{
+       uint64_t                di_flags2 =
+               (ip->i_d.di_flags2 & XFS_DIFLAG2_REFLINK);
+
+       if (xflags & FS_XFLAG_DAX)
+               di_flags2 |= XFS_DIFLAG2_DAX;
+       if (xflags & FS_XFLAG_COWEXTSIZE)
+               di_flags2 |= XFS_DIFLAG2_COWEXTSIZE;
+
+       return di_flags2;
 }
 
 /*
@@ -169,7 +230,7 @@ libxfs_trans_ichgtime(
  * This was once shared with the kernel, but has diverged to the point
  * where it's no longer worth the hassle of maintaining common code.
  */
-int
+static int
 libxfs_ialloc(
        xfs_trans_t     *tp,
        xfs_inode_t     *pip,
@@ -178,7 +239,6 @@ libxfs_ialloc(
        xfs_dev_t       rdev,
        struct cred     *cr,
        struct fsxattr  *fsx,
-       int             okalloc,
        xfs_buf_t       **ialloc_context,
        xfs_inode_t     **ipp)
 {
@@ -191,7 +251,7 @@ libxfs_ialloc(
         * Call the space management code to pick
         * the on-disk inode to be allocated.
         */
-       error = xfs_dialloc(tp, pip ? pip->i_ino : 0, mode, okalloc,
+       error = xfs_dialloc(tp, pip ? pip->i_ino : 0, mode,
                            ialloc_context, &ino);
        if (error != 0)
                return error;
@@ -206,24 +266,20 @@ libxfs_ialloc(
                return error;
        ASSERT(ip != NULL);
 
-       ip->i_d.di_mode = (__uint16_t)mode;
-       ip->i_d.di_onlink = 0;
-       ip->i_d.di_nlink = nlink;
-       ASSERT(ip->i_d.di_nlink == nlink);
+       VFS_I(ip)->i_mode = mode;
+       set_nlink(VFS_I(ip), nlink);
        ip->i_d.di_uid = cr->cr_uid;
        ip->i_d.di_gid = cr->cr_gid;
        xfs_set_projid(&ip->i_d, pip ? 0 : fsx->fsx_projid);
-       memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad));
        xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG | XFS_ICHGTIME_MOD);
 
        /*
-        * If the superblock version is up to where we support new format
-        * inodes and this is currently an old format inode, then change
-        * the inode version number now.  This way we only do the conversion
-        * here rather than here and in the flush/logging code.
+        * We only support filesystems that understand v2 format inodes. So if
+        * this is currently an old format inode, then change the inode version
+        * number now.  This way we only do the conversion 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 == 1) {
+       if (ip->i_d.di_version == 1) {
                ip->i_d.di_version = 2;
                /*
                 * old link count, projid_lo/hi field, pad field
@@ -231,32 +287,29 @@ libxfs_ialloc(
                 */
        }
 
-       if (pip && (pip->i_d.di_mode & S_ISGID)) {
+       if (pip && (VFS_I(pip)->i_mode & S_ISGID)) {
                ip->i_d.di_gid = pip->i_d.di_gid;
-               if ((pip->i_d.di_mode & S_ISGID) && (mode & S_IFMT) == S_IFDIR)
-                       ip->i_d.di_mode |= S_ISGID;
+               if ((VFS_I(pip)->i_mode & S_ISGID) && (mode & S_IFMT) == S_IFDIR)
+                       VFS_I(ip)->i_mode |= S_ISGID;
        }
 
        ip->i_d.di_size = 0;
        ip->i_d.di_nextents = 0;
        ASSERT(ip->i_d.di_nblocks == 0);
-       /*
-        * di_gen will have been taken care of in xfs_iread.
-        */
        ip->i_d.di_extsize = pip ? 0 : fsx->fsx_extsize;
        ip->i_d.di_dmevmask = 0;
        ip->i_d.di_dmstate = 0;
-       ip->i_d.di_flags = pip ? 0 : fsx->fsx_xflags;
+       ip->i_d.di_flags = pip ? 0 : xfs_flags2diflags(ip, fsx->fsx_xflags);
 
        if (ip->i_d.di_version == 3) {
                ASSERT(ip->i_d.di_ino == ino);
-               ASSERT(uuid_equal(&ip->i_d.di_uuid, &mp->m_sb.sb_uuid));
-               ip->i_d.di_crc = 0;
-               ip->i_d.di_changecount = 1;
-               ip->i_d.di_lsn = 0;
-               ip->i_d.di_flags2 = 0;
-               memset(&(ip->i_d.di_pad2[0]), 0, sizeof(ip->i_d.di_pad2));
-               ip->i_d.di_crtime = ip->i_d.di_mtime;
+               ASSERT(uuid_equal(&ip->i_d.di_uuid, &mp->m_sb.sb_meta_uuid));
+               VFS_I(ip)->i_version = 1;
+               ip->i_d.di_flags2 = pip ? 0 : xfs_flags2diflags2(ip,
+                               fsx->fsx_xflags);
+               ip->i_d.di_crtime.t_sec = (int32_t)VFS_I(ip)->i_mtime.tv_sec;
+               ip->i_d.di_crtime.t_nsec = (int32_t)VFS_I(ip)->i_mtime.tv_nsec;
+               ip->i_d.di_cowextsize = pip ? 0 : fsx->fsx_cowextsize;
        }
 
        flags = XFS_ILOG_CORE;
@@ -269,8 +322,8 @@ libxfs_ialloc(
        case S_IFCHR:
        case S_IFBLK:
                ip->i_d.di_format = XFS_DINODE_FMT_DEV;
-               ip->i_df.if_u2.if_rdev = rdev;
                flags |= XFS_ILOG_DEV;
+               VFS_I(ip)->i_rdev = rdev;
                break;
        case S_IFREG:
        case S_IFDIR:
@@ -301,8 +354,8 @@ libxfs_ialloc(
        case S_IFLNK:
                ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS;
                ip->i_df.if_flags = XFS_IFEXTENTS;
-               ip->i_df.if_bytes = ip->i_df.if_real_bytes = 0;
-               ip->i_df.if_u1.if_extents = NULL;
+               ip->i_df.if_bytes = 0;
+               ip->i_df.if_u1.if_root = NULL;
                break;
        default:
                ASSERT(0);
@@ -311,6 +364,14 @@ libxfs_ialloc(
        ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS;
        ip->i_d.di_anextents = 0;
 
+       /*
+        * set up the inode ops structure that the libxfs code relies on
+        */
+       if (XFS_ISDIR(ip))
+               ip->d_ops = ip->i_mount->m_dir_inode_ops;
+       else
+               ip->d_ops = ip->i_mount->m_nondir_inode_ops;
+
        /*
         * Log the new values stuffed into the inode.
         */
@@ -319,14 +380,15 @@ libxfs_ialloc(
        return 0;
 }
 
-void
+static void
 libxfs_iprint(
        xfs_inode_t             *ip)
 {
-       xfs_icdinode_t          *dip;
-       xfs_bmbt_rec_host_t     *ep;
-       xfs_extnum_t            i;
-       xfs_extnum_t            nextents;
+       struct xfs_icdinode     *dip;
+       xfs_extnum_t            i = 0;
+       struct xfs_ifork        *ifp;           /* inode fork pointer */
+       struct xfs_iext_cursor  icur;
+       xfs_bmbt_irec_t         rec;
 
        printf("Inode %lx\n", (unsigned long)ip);
        printf("    i_ino %llx\n", (unsigned long long)ip->i_ino);
@@ -335,21 +397,18 @@ libxfs_iprint(
                printf("EXTENTS ");
        printf("\n");
        printf("    i_df.if_bytes %d\n", ip->i_df.if_bytes);
-       printf("    i_df.if_u1.if_extents/if_data %lx\n",
-               (unsigned long)ip->i_df.if_u1.if_extents);
+       printf("    i_df.if_u1.if_root/if_data %lx\n",
+               (unsigned long)ip->i_df.if_u1.if_root);
        if (ip->i_df.if_flags & XFS_IFEXTENTS) {
-               nextents = ip->i_df.if_bytes / (uint)sizeof(*ep);
-               for (ep = ip->i_df.if_u1.if_extents, i = 0; i < nextents; 
-                                                               i++, ep++) {
-                       xfs_bmbt_irec_t rec;
-
-                       xfs_bmbt_get_all(ep, &rec);
+               ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
+               for_each_xfs_iext(ifp, &icur, &rec) {
                        printf("\t%d: startoff %llu, startblock 0x%llx,"
                                " blockcount %llu, state %d\n",
                                i, (unsigned long long)rec.br_startoff,
                                (unsigned long long)rec.br_startblock,
                                (unsigned long long)rec.br_blockcount,
                                (int)rec.br_state);
+                       i++;
                }
        }
        printf("    i_df.if_broot %lx\n", (unsigned long)ip->i_df.if_broot);
@@ -357,8 +416,7 @@ libxfs_iprint(
 
        dip = &ip->i_d;
        printf("\nOn disk portion\n");
-       printf("    di_magic %x\n", dip->di_magic);
-       printf("    di_mode %o\n", dip->di_mode);
+       printf("    di_mode %o\n", VFS_I(ip)->i_mode);
        printf("    di_version %x\n", (uint)dip->di_version);
        switch (ip->i_d.di_format) {
        case XFS_DINODE_FMT_LOCAL:
@@ -374,12 +432,12 @@ libxfs_iprint(
                printf("    Other inode\n");
                break;
        }
-       printf("   di_nlink %x\n", dip->di_nlink);
+       printf("   di_nlink %x\n", VFS_I(ip)->i_nlink);
        printf("   di_uid %d\n", dip->di_uid);
        printf("   di_gid %d\n", dip->di_gid);
        printf("   di_nextents %d\n", dip->di_nextents);
        printf("   di_size %llu\n", (unsigned long long)dip->di_size);
-       printf("   di_gen %x\n", dip->di_gen);
+       printf("   di_gen %x\n", VFS_I(ip)->i_generation);
        printf("   di_extsize %d\n", dip->di_extsize);
        printf("   di_flags %x\n", dip->di_flags);
        printf("   di_nblocks %llu\n", (unsigned long long)dip->di_nblocks);
@@ -396,22 +454,22 @@ libxfs_iflush_int(xfs_inode_t *ip, xfs_buf_t *bp)
        xfs_dinode_t            *dip;
        xfs_mount_t             *mp;
 
-       ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL);
+       ASSERT(bp-b_log_item != NULL);
        ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE ||
                ip->i_d.di_nextents > ip->i_df.if_ext_max);
+       ASSERT(ip->i_d.di_version > 1);
 
        iip = ip->i_itemp;
        mp = ip->i_mount;
 
        /* set *dip = inode's place in the buffer */
-       dip = (xfs_dinode_t *)xfs_buf_offset(bp, ip->i_imap.im_boffset);
+       dip = xfs_buf_offset(bp, ip->i_imap.im_boffset);
 
        ASSERT(ip->i_d.di_magic == XFS_DINODE_MAGIC);
-       if ((ip->i_d.di_mode & S_IFMT) == S_IFREG) {
+       if (XFS_ISREG(ip)) {
                ASSERT( (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS) ||
                        (ip->i_d.di_format == XFS_DINODE_FMT_BTREE) );
-       }
-       else if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) {
+       } else if (XFS_ISDIR(ip)) {
                ASSERT( (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS) ||
                        (ip->i_d.di_format == XFS_DINODE_FMT_BTREE)   ||
                        (ip->i_d.di_format == XFS_DINODE_FMT_LOCAL) );
@@ -421,7 +479,11 @@ libxfs_iflush_int(xfs_inode_t *ip, xfs_buf_t *bp)
 
        /* bump the change count on v3 inodes */
        if (ip->i_d.di_version == 3)
-               ip->i_d.di_changecount++;
+               VFS_I(ip)->i_version++;
+
+       /* Check the inline fork data before we write out. */
+       if (!libxfs_inode_verify_forks(ip, &xfs_default_ifork_ops))
+               return -EFSCORRUPTED;
 
        /*
         * Copy the dirty parts of the inode into the on-disk
@@ -429,46 +491,11 @@ libxfs_iflush_int(xfs_inode_t *ip, xfs_buf_t *bp)
         * because if the inode is dirty at all the core must
         * be.
         */
-       xfs_dinode_to_disk(dip, &ip->i_d);
+       xfs_inode_to_disk(ip, dip, iip->ili_item.li_lsn);
 
-       /*
-        * If this is really an old format inode and the superblock version
-        * has not been updated to support only new format inodes, then
-        * 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 == 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_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 = 2;
-                       dip->di_version =  2;
-                       ip->i_d.di_onlink = 0;
-                       dip->di_onlink = 0;
-                       memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad));
-                       memset(&(dip->di_pad[0]), 0, sizeof(dip->di_pad));
-                       ASSERT(xfs_get_projid(&ip->i_d) == 0);
-               }
-       }
-
-       xfs_iflush_fork(ip, dip, iip, XFS_DATA_FORK, bp);
-       if (XFS_IFORK_Q(ip)) 
-               xfs_iflush_fork(ip, dip, iip, XFS_ATTR_FORK, bp);
-
-       /* update the lsn in the on disk inode if required */
-       if (ip->i_d.di_version == 3)
-               dip->di_lsn = cpu_to_be64(iip->ili_item.li_lsn);
+       xfs_iflush_fork(ip, dip, iip, XFS_DATA_FORK);
+       if (XFS_IFORK_Q(ip))
+               xfs_iflush_fork(ip, dip, iip, XFS_ATTR_FORK);
 
        /* generate the checksum. */
        xfs_dinode_calc_crc(mp, dip);
@@ -476,62 +503,27 @@ libxfs_iflush_int(xfs_inode_t *ip, xfs_buf_t *bp)
        return 0;
 }
 
-/*
- * Utility routine common used to apply a delta to a field in the
- * in-core superblock.
- * Switch on the field indicated and apply the delta to that field.
- * Fields are not allowed to dip below zero, so if the delta would
- * do this do not apply it and return EINVAL.
- *
- * Originally derived from xfs_mod_incore_sb_unlocked().
- */
 int
 libxfs_mod_incore_sb(
-       xfs_mount_t     *mp,
-       xfs_sb_field_t  field,
+       struct xfs_mount *mp,
+       int             field,
        int64_t         delta,
        int             rsvd)
 {
        long long       lcounter;       /* long counter for 64 bit fields */
 
        switch (field) {
-       case XFS_SBS_FDBLOCKS:
+       case XFS_TRANS_SB_FDBLOCKS:
                lcounter = (long long)mp->m_sb.sb_fdblocks;
                lcounter += delta;
                if (lcounter < 0)
-                       return XFS_ERROR(ENOSPC);
+                       return -ENOSPC;
                mp->m_sb.sb_fdblocks = lcounter;
                return 0;
        default:
                ASSERT(0);
-               return XFS_ERROR(EINVAL);
-       }
-}
-
-int
-libxfs_bmap_finish(
-       xfs_trans_t     **tp,
-       xfs_bmap_free_t *flist,
-       int             *committed)
-{
-       xfs_bmap_free_item_t    *free;  /* free extent list item */
-       xfs_bmap_free_item_t    *next;  /* next item on free list */
-       int                     error;
-
-       if (flist->xbf_count == 0) {
-               *committed = 0;
-               return 0;
-       }
-
-       for (free = flist->xbf_first; free != NULL; free = next) {
-               next = free->xbfi_next;
-               if ((error = xfs_free_extent(*tp, free->xbfi_startblock,
-                               free->xbfi_blockcount)))
-                       return error;
-               xfs_bmap_del_free(flist, NULL, free);
+               return -EINVAL;
        }
-       *committed = 0;
-       return 0;
 }
 
 /*
@@ -551,8 +543,6 @@ libxfs_alloc_file_space(
        xfs_filblks_t   datablocks;
        xfs_filblks_t   allocated_fsb;
        xfs_filblks_t   allocatesize_fsb;
-       xfs_fsblock_t   firstfsb;
-       xfs_bmap_free_t free_list;
        xfs_bmbt_irec_t *imapp;
        xfs_bmbt_irec_t imaps[1];
        int             reccount;
@@ -560,11 +550,10 @@ libxfs_alloc_file_space(
        xfs_fileoff_t   startoffset_fsb;
        xfs_trans_t     *tp;
        int             xfs_bmapi_flags;
-       int             committed;
        int             error;
 
        if (len <= 0)
-               return EINVAL;
+               return -EINVAL;
 
        count = len;
        error = 0;
@@ -579,43 +568,34 @@ libxfs_alloc_file_space(
        while (allocatesize_fsb && !error) {
                datablocks = allocatesize_fsb;
 
-               tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT);
                resblks = (uint)XFS_DIOSTRAT_SPACE_RES(mp, datablocks);
-               error = xfs_trans_reserve(tp, &M_RES(mp)->tr_write,
-                                         resblks, 0);
+               error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, resblks,
+                                       0, 0, &tp);
                /*
                 * Check for running out of space
                 */
                if (error) {
-                       /*
-                        * Free the transaction structure.
-                        */
-                       ASSERT(error == ENOSPC);
-                       xfs_trans_cancel(tp, 0);
+                       ASSERT(error == -ENOSPC);
                        break;
                }
                xfs_trans_ijoin(tp, ip, 0);
 
-               xfs_bmap_init(&free_list, &firstfsb);
                error = xfs_bmapi_write(tp, ip, startoffset_fsb, allocatesize_fsb,
-                               xfs_bmapi_flags, &firstfsb, 0, imapp,
-                               &reccount, &free_list);
+                               xfs_bmapi_flags, 0, imapp, &reccount);
 
                if (error)
                        goto error0;
 
-               /* complete the transaction */
-               error = xfs_bmap_finish(&tp, &free_list, &committed);
-               if (error)
-                       goto error0;
-
-               error = xfs_trans_commit(tp, 0);
+               /*
+                * Complete the transaction
+                */
+               error = xfs_trans_commit(tp);
                if (error)
                        break;
 
                allocated_fsb = imapp->br_blockcount;
                if (reccount == 0)
-                       return ENOSPC;
+                       return -ENOSPC;
 
                startoffset_fsb += allocated_fsb;
                allocatesize_fsb -= allocated_fsb;
@@ -623,23 +603,10 @@ libxfs_alloc_file_space(
        return error;
 
 error0:        /* Cancel bmap, cancel trans */
-       xfs_bmap_cancel(&free_list);
-       xfs_trans_cancel(tp, 0);
+       xfs_trans_cancel(tp);
        return error;
 }
 
-unsigned int
-libxfs_log2_roundup(unsigned int i)
-{
-       unsigned int    rval;
-
-       for (rval = 0; rval < NBBY * sizeof(i); rval++) {
-               if ((1 << rval) >= i)
-                       break;
-       }
-       return rval;
-}
-
 /*
  * Wrapper around call to libxfs_ialloc. Takes care of committing and
  * allocating a new transaction as needed.
@@ -660,48 +627,38 @@ libxfs_inode_alloc(
 {
        xfs_buf_t       *ialloc_context;
        xfs_inode_t     *ip;
-       xfs_trans_t     *ntp;
        int             error;
 
        ialloc_context = (xfs_buf_t *)0;
        error = libxfs_ialloc(*tp, pip, mode, nlink, rdev, cr, fsx,
-                          1, &ialloc_context, &ip);
+                          &ialloc_context, &ip);
        if (error) {
                *ipp = NULL;
                return error;
        }
        if (!ialloc_context && !ip) {
                *ipp = NULL;
-               return XFS_ERROR(ENOSPC);
+               return -ENOSPC;
        }
 
        if (ialloc_context) {
-               struct xfs_trans_res    tres;
 
                xfs_trans_bhold(*tp, ialloc_context);
-               tres.tr_logres = (*tp)->t_log_res;
-               tres.tr_logcount = (*tp)->t_log_count;
-
-               ntp = xfs_trans_dup(*tp);
-               xfs_trans_commit(*tp, 0);
-               *tp = ntp;
-               tres.tr_logflags = XFS_TRANS_PERM_LOG_RES;
-               error = xfs_trans_reserve(*tp, &tres, 0, 0);
+
+               error = xfs_trans_roll(tp);
                if (error) {
-                       fprintf(stderr, _("%s: cannot reserve space: %s\n"),
+                       fprintf(stderr, _("%s: cannot duplicate transaction: %s\n"),
                                progname, strerror(error));
                        exit(1);
                }
                xfs_trans_bjoin(*tp, ialloc_context);
                error = libxfs_ialloc(*tp, pip, mode, nlink, rdev, cr,
-                                  fsx, 1, &ialloc_context, &ip);
+                                  fsx, &ialloc_context, &ip);
                if (!ip)
-                       error = ENOSPC;
+                       error = -ENOSPC;
                if (error)
                        return error;
        }
-       if (!ip)
-               error = ENOSPC;
 
        *ipp = ip;
        return error;
@@ -719,8 +676,9 @@ libxfs_fs_repair_cmn_err(int level, xfs_mount_t *mp, char *fmt, ...)
        vfprintf(stderr, fmt, ap);
        fprintf(stderr, "  This is a bug.\n");
        fprintf(stderr, "%s version %s\n", progname, VERSION);
-       fprintf(stderr, "Please capture the filesystem metadata with "
-                       "xfs_metadump and\nreport it to xfs@oss.sgi.com.\n");
+       fprintf(stderr,
+               "Please capture the filesystem metadata with xfs_metadump and\n"
+               "report it to linux-xfs@vger.kernel.org\n");
        va_end(ap);
 }
 
@@ -752,9 +710,131 @@ cmn_err(int level, char *fmt, ...)
  */
 void
 xfs_verifier_error(
-       struct xfs_buf          *bp)
+       struct xfs_buf          *bp,
+       int                     error,
+       xfs_failaddr_t          failaddr)
+{
+       xfs_buf_ioerror(bp, error);
+
+       xfs_alert(NULL, "Metadata %s detected at %p, %s block 0x%llx/0x%x",
+                 bp->b_error == -EFSBADCRC ? "CRC error" : "corruption",
+                 failaddr ? failaddr : __return_address,
+                 bp->b_ops->name, bp->b_bn, BBTOB(bp->b_length));
+}
+
+/*
+ * Warnings for inode corruption problems.  Don't bother with the stack
+ * trace unless the error level is turned up high.
+ */
+void
+xfs_inode_verifier_error(
+       struct xfs_inode        *ip,
+       int                     error,
+       const char              *name,
+       void                    *buf,
+       size_t                  bufsz,
+       xfs_failaddr_t          failaddr)
 {
-       xfs_alert(NULL, "Metadata %s detected at block 0x%llx/0x%x",
-                 bp->b_error == EFSBADCRC ? "CRC error" : "corruption",
-                 bp->b_bn, BBTOB(bp->b_length));
+       xfs_alert(NULL, "Metadata %s detected at %p, inode 0x%llx %s",
+                 error == -EFSBADCRC ? "CRC error" : "corruption",
+                 failaddr ? failaddr : __return_address,
+                 ip->i_ino, name);
 }
+
+/*
+ * This is called from I/O verifiers on v5 superblock filesystems. In the
+ * kernel, it validates the metadata LSN parameter against the current LSN of
+ * the active log. We don't have an active log in userspace so this kind of
+ * validation is not required. Therefore, this function always returns true in
+ * userspace.
+ *
+ * xfs_repair piggybacks off this mechanism to help track the largest metadata
+ * LSN in use on a filesystem. Keep a record of the largest LSN seen such that
+ * repair can validate it against the state of the log.
+ */
+xfs_lsn_t      libxfs_max_lsn = 0;
+static pthread_mutex_t libxfs_max_lsn_lock = PTHREAD_MUTEX_INITIALIZER;
+
+bool
+xfs_log_check_lsn(
+       struct xfs_mount        *mp,
+       xfs_lsn_t               lsn)
+{
+       int                     cycle = CYCLE_LSN(lsn);
+       int                     block = BLOCK_LSN(lsn);
+       int                     max_cycle;
+       int                     max_block;
+
+       if (lsn == NULLCOMMITLSN)
+               return true;
+
+       pthread_mutex_lock(&libxfs_max_lsn_lock);
+
+       max_cycle = CYCLE_LSN(libxfs_max_lsn);
+       max_block = BLOCK_LSN(libxfs_max_lsn);
+
+       if ((cycle > max_cycle) ||
+           (cycle == max_cycle && block > max_block))
+               libxfs_max_lsn = lsn;
+
+       pthread_mutex_unlock(&libxfs_max_lsn_lock);
+
+       return true;
+}
+
+static struct xfs_buftarg *
+xfs_find_bdev_for_inode(
+       struct xfs_inode        *ip)
+{
+       struct xfs_mount        *mp = ip->i_mount;
+
+       if (XFS_IS_REALTIME_INODE(ip))
+               return mp->m_rtdev_targp;
+       return mp->m_ddev_targp;
+}
+
+static xfs_daddr_t
+xfs_fsb_to_db(struct xfs_inode *ip, xfs_fsblock_t fsb)
+{
+       if (XFS_IS_REALTIME_INODE(ip))
+                return XFS_FSB_TO_BB(ip->i_mount, fsb);
+       return XFS_FSB_TO_DADDR(ip->i_mount, (fsb));
+}
+
+int
+libxfs_zero_extent(
+       struct xfs_inode *ip,
+       xfs_fsblock_t   start_fsb,
+       xfs_off_t       count_fsb)
+{
+       xfs_daddr_t     sector = xfs_fsb_to_db(ip, start_fsb);
+       ssize_t         size = XFS_FSB_TO_BB(ip->i_mount, count_fsb);
+
+       return libxfs_device_zero(xfs_find_bdev_for_inode(ip), sector, size);
+}
+
+unsigned int
+hweight8(unsigned int w)
+{
+       unsigned int res = w - ((w >> 1) & 0x55);
+       res = (res & 0x33) + ((res >> 2) & 0x33);
+       return (res + (res >> 4)) & 0x0F;
+}
+
+unsigned int
+hweight32(unsigned int w)
+{
+       unsigned int res = w - ((w >> 1) & 0x55555555);
+       res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
+       res = (res + (res >> 4)) & 0x0F0F0F0F;
+       res = res + (res >> 8);
+       return (res + (res >> 16)) & 0x000000FF;
+}
+
+unsigned int
+hweight64(__u64 w)
+{
+       return hweight32((unsigned int)w) +
+              hweight32((unsigned int)(w >> 32));
+}
+