]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blobdiff - libxfs/xfs_dir2_block.c
xfs: convert to SPDX license tags
[thirdparty/xfsprogs-dev.git] / libxfs / xfs_dir2_block.c
index cf1fc4b56b671cd5ff499588ba39723a8ea9699c..d1ffdb391aaf7417b1cf3a0e414f6edf7613d021 100644 (file)
+// SPDX-License-Identifier: GPL-2.0
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 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.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.         Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA  94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
+ * Copyright (c) 2013 Red Hat, Inc.
+ * All Rights Reserved.
  */
+#include "libxfs_priv.h"
+#include "xfs_fs.h"
+#include "xfs_format.h"
+#include "xfs_log_format.h"
+#include "xfs_trans_resv.h"
+#include "xfs_mount.h"
+#include "xfs_da_format.h"
+#include "xfs_da_btree.h"
+#include "xfs_inode.h"
+#include "xfs_trans.h"
+#include "xfs_bmap.h"
+#include "xfs_dir2.h"
+#include "xfs_dir2_priv.h"
+#include "xfs_trace.h"
+#include "xfs_cksum.h"
 
 /*
- * xfs_dir2_block.c
- * XFS V2 directory implementation, single-block form.
- * See xfs_dir2_block.h for the format.
+ * Local function prototypes.
  */
+static void xfs_dir2_block_log_leaf(xfs_trans_t *tp, struct xfs_buf *bp,
+                                   int first, int last);
+static void xfs_dir2_block_log_tail(xfs_trans_t *tp, struct xfs_buf *bp);
+static int xfs_dir2_block_lookup_int(xfs_da_args_t *args, struct xfs_buf **bpp,
+                                    int *entno);
+static int xfs_dir2_block_sort(const void *a, const void *b);
 
-#include <xfs.h>
+static xfs_dahash_t xfs_dir_hash_dot, xfs_dir_hash_dotdot;
+
+/*
+ * One-time startup routine called from xfs_init().
+ */
+void
+xfs_dir_startup(void)
+{
+       xfs_dir_hash_dot = xfs_da_hashname((unsigned char *)".", 1);
+       xfs_dir_hash_dotdot = xfs_da_hashname((unsigned char *)"..", 2);
+}
+
+static xfs_failaddr_t
+xfs_dir3_block_verify(
+       struct xfs_buf          *bp)
+{
+       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr;
+
+       if (xfs_sb_version_hascrc(&mp->m_sb)) {
+               if (hdr3->magic != cpu_to_be32(XFS_DIR3_BLOCK_MAGIC))
+                       return __this_address;
+               if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid))
+                       return __this_address;
+               if (be64_to_cpu(hdr3->blkno) != bp->b_bn)
+                       return __this_address;
+               if (!xfs_log_check_lsn(mp, be64_to_cpu(hdr3->lsn)))
+                       return __this_address;
+       } else {
+               if (hdr3->magic != cpu_to_be32(XFS_DIR2_BLOCK_MAGIC))
+                       return __this_address;
+       }
+       return __xfs_dir3_data_check(NULL, bp);
+}
+
+static void
+xfs_dir3_block_read_verify(
+       struct xfs_buf  *bp)
+{
+       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       xfs_failaddr_t          fa;
+
+       if (xfs_sb_version_hascrc(&mp->m_sb) &&
+            !xfs_buf_verify_cksum(bp, XFS_DIR3_DATA_CRC_OFF))
+               xfs_verifier_error(bp, -EFSBADCRC, __this_address);
+       else {
+               fa = xfs_dir3_block_verify(bp);
+               if (fa)
+                       xfs_verifier_error(bp, -EFSCORRUPTED, fa);
+       }
+}
+
+static void
+xfs_dir3_block_write_verify(
+       struct xfs_buf  *bp)
+{
+       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_buf_log_item *bip = bp->b_log_item;
+       struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr;
+       xfs_failaddr_t          fa;
+
+       fa = xfs_dir3_block_verify(bp);
+       if (fa) {
+               xfs_verifier_error(bp, -EFSCORRUPTED, fa);
+               return;
+       }
+
+       if (!xfs_sb_version_hascrc(&mp->m_sb))
+               return;
+
+       if (bip)
+               hdr3->lsn = cpu_to_be64(bip->bli_item.li_lsn);
+
+       xfs_buf_update_cksum(bp, XFS_DIR3_DATA_CRC_OFF);
+}
+
+const struct xfs_buf_ops xfs_dir3_block_buf_ops = {
+       .name = "xfs_dir3_block",
+       .verify_read = xfs_dir3_block_read_verify,
+       .verify_write = xfs_dir3_block_write_verify,
+       .verify_struct = xfs_dir3_block_verify,
+};
+
+int
+xfs_dir3_block_read(
+       struct xfs_trans        *tp,
+       struct xfs_inode        *dp,
+       struct xfs_buf          **bpp)
+{
+       struct xfs_mount        *mp = dp->i_mount;
+       int                     err;
+
+       err = xfs_da_read_buf(tp, dp, mp->m_dir_geo->datablk, -1, bpp,
+                               XFS_DATA_FORK, &xfs_dir3_block_buf_ops);
+       if (!err && tp && *bpp)
+               xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_BLOCK_BUF);
+       return err;
+}
+
+static void
+xfs_dir3_block_init(
+       struct xfs_mount        *mp,
+       struct xfs_trans        *tp,
+       struct xfs_buf          *bp,
+       struct xfs_inode        *dp)
+{
+       struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr;
+
+       bp->b_ops = &xfs_dir3_block_buf_ops;
+       xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DIR_BLOCK_BUF);
+
+       if (xfs_sb_version_hascrc(&mp->m_sb)) {
+               memset(hdr3, 0, sizeof(*hdr3));
+               hdr3->magic = cpu_to_be32(XFS_DIR3_BLOCK_MAGIC);
+               hdr3->blkno = cpu_to_be64(bp->b_bn);
+               hdr3->owner = cpu_to_be64(dp->i_ino);
+               uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid);
+               return;
+
+       }
+       hdr3->magic = cpu_to_be32(XFS_DIR2_BLOCK_MAGIC);
+}
+
+static void
+xfs_dir2_block_need_space(
+       struct xfs_inode                *dp,
+       struct xfs_dir2_data_hdr        *hdr,
+       struct xfs_dir2_block_tail      *btp,
+       struct xfs_dir2_leaf_entry      *blp,
+       __be16                          **tagpp,
+       struct xfs_dir2_data_unused     **dupp,
+       struct xfs_dir2_data_unused     **enddupp,
+       int                             *compact,
+       int                             len)
+{
+       struct xfs_dir2_data_free       *bf;
+       __be16                          *tagp = NULL;
+       struct xfs_dir2_data_unused     *dup = NULL;
+       struct xfs_dir2_data_unused     *enddup = NULL;
+
+       *compact = 0;
+       bf = dp->d_ops->data_bestfree_p(hdr);
+
+       /*
+        * If there are stale entries we'll use one for the leaf.
+        */
+       if (btp->stale) {
+               if (be16_to_cpu(bf[0].length) >= len) {
+                       /*
+                        * The biggest entry enough to avoid compaction.
+                        */
+                       dup = (xfs_dir2_data_unused_t *)
+                             ((char *)hdr + be16_to_cpu(bf[0].offset));
+                       goto out;
+               }
+
+               /*
+                * Will need to compact to make this work.
+                * Tag just before the first leaf entry.
+                */
+               *compact = 1;
+               tagp = (__be16 *)blp - 1;
+
+               /* Data object just before the first leaf entry.  */
+               dup = (xfs_dir2_data_unused_t *)((char *)hdr + be16_to_cpu(*tagp));
+
+               /*
+                * If it's not free then the data will go where the
+                * leaf data starts now, if it works at all.
+                */
+               if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
+                       if (be16_to_cpu(dup->length) + (be32_to_cpu(btp->stale) - 1) *
+                           (uint)sizeof(*blp) < len)
+                               dup = NULL;
+               } else if ((be32_to_cpu(btp->stale) - 1) * (uint)sizeof(*blp) < len)
+                       dup = NULL;
+               else
+                       dup = (xfs_dir2_data_unused_t *)blp;
+               goto out;
+       }
+
+       /*
+        * no stale entries, so just use free space.
+        * Tag just before the first leaf entry.
+        */
+       tagp = (__be16 *)blp - 1;
+
+       /* Data object just before the first leaf entry.  */
+       enddup = (xfs_dir2_data_unused_t *)((char *)hdr + be16_to_cpu(*tagp));
+
+       /*
+        * If it's not free then can't do this add without cleaning up:
+        * the space before the first leaf entry needs to be free so it
+        * can be expanded to hold the pointer to the new entry.
+        */
+       if (be16_to_cpu(enddup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
+               /*
+                * Check out the biggest freespace and see if it's the same one.
+                */
+               dup = (xfs_dir2_data_unused_t *)
+                     ((char *)hdr + be16_to_cpu(bf[0].offset));
+               if (dup != enddup) {
+                       /*
+                        * Not the same free entry, just check its length.
+                        */
+                       if (be16_to_cpu(dup->length) < len)
+                               dup = NULL;
+                       goto out;
+               }
+
+               /*
+                * It is the biggest freespace, can it hold the leaf too?
+                */
+               if (be16_to_cpu(dup->length) < len + (uint)sizeof(*blp)) {
+                       /*
+                        * Yes, use the second-largest entry instead if it works.
+                        */
+                       if (be16_to_cpu(bf[1].length) >= len)
+                               dup = (xfs_dir2_data_unused_t *)
+                                     ((char *)hdr + be16_to_cpu(bf[1].offset));
+                       else
+                               dup = NULL;
+               }
+       }
+out:
+       *tagpp = tagp;
+       *dupp = dup;
+       *enddupp = enddup;
+}
+
+/*
+ * compact the leaf entries.
+ * Leave the highest-numbered stale entry stale.
+ * XXX should be the one closest to mid but mid is not yet computed.
+ */
+static void
+xfs_dir2_block_compact(
+       struct xfs_da_args              *args,
+       struct xfs_buf                  *bp,
+       struct xfs_dir2_data_hdr        *hdr,
+       struct xfs_dir2_block_tail      *btp,
+       struct xfs_dir2_leaf_entry      *blp,
+       int                             *needlog,
+       int                             *lfloghigh,
+       int                             *lfloglow)
+{
+       int                     fromidx;        /* source leaf index */
+       int                     toidx;          /* target leaf index */
+       int                     needscan = 0;
+       int                     highstale;      /* high stale index */
+
+       fromidx = toidx = be32_to_cpu(btp->count) - 1;
+       highstale = *lfloghigh = -1;
+       for (; fromidx >= 0; fromidx--) {
+               if (blp[fromidx].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) {
+                       if (highstale == -1)
+                               highstale = toidx;
+                       else {
+                               if (*lfloghigh == -1)
+                                       *lfloghigh = toidx;
+                               continue;
+                       }
+               }
+               if (fromidx < toidx)
+                       blp[toidx] = blp[fromidx];
+               toidx--;
+       }
+       *lfloglow = toidx + 1 - (be32_to_cpu(btp->stale) - 1);
+       *lfloghigh -= be32_to_cpu(btp->stale) - 1;
+       be32_add_cpu(&btp->count, -(be32_to_cpu(btp->stale) - 1));
+       xfs_dir2_data_make_free(args, bp,
+               (xfs_dir2_data_aoff_t)((char *)blp - (char *)hdr),
+               (xfs_dir2_data_aoff_t)((be32_to_cpu(btp->stale) - 1) * sizeof(*blp)),
+               needlog, &needscan);
+       btp->stale = cpu_to_be32(1);
+       /*
+        * If we now need to rebuild the bestfree map, do so.
+        * This needs to happen before the next call to use_free.
+        */
+       if (needscan)
+               xfs_dir2_data_freescan(args->dp, hdr, needlog);
+}
 
 /*
  * Add an entry to a block directory.
@@ -45,10 +320,9 @@ int                                         /* error */
 xfs_dir2_block_addname(
        xfs_da_args_t           *args)          /* directory op arguments */
 {
-       xfs_dir2_data_free_t    *bf;            /* bestfree table in block */
-       xfs_dir2_block_t        *block;         /* directory block structure */
+       xfs_dir2_data_hdr_t     *hdr;           /* block header */
        xfs_dir2_leaf_entry_t   *blp;           /* block leaf entries */
-       xfs_dabuf_t             *bp;            /* buffer for block */
+       struct xfs_buf          *bp;            /* buffer for block */
        xfs_dir2_block_tail_t   *btp;           /* block tail */
        int                     compact;        /* need to compact leaf ents */
        xfs_dir2_data_entry_t   *dep;           /* block data entry */
@@ -65,251 +339,125 @@ xfs_dir2_block_addname(
        int                     low;            /* low index for binary srch */
        int                     lowstale;       /* low stale index */
        int                     mid=0;          /* midpoint for binary srch */
-       xfs_mount_t             *mp;            /* filesystem mount point */
        int                     needlog;        /* need to log header */
        int                     needscan;       /* need to rescan freespace */
-       xfs_dir2_data_off_t     *tagp;          /* pointer to tag value */
+       __be16                  *tagp;          /* pointer to tag value */
        xfs_trans_t             *tp;            /* transaction structure */
 
-       xfs_dir2_trace_args("block_addname", args);
+       trace_xfs_dir2_block_addname(args);
+
        dp = args->dp;
        tp = args->trans;
-       mp = dp->i_mount;
-       /*
-        * Read the (one and only) directory block into dabuf bp.
-        */
-       if ((error =
-           xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, &bp, XFS_DATA_FORK))) {
+
+       /* Read the (one and only) directory block into bp. */
+       error = xfs_dir3_block_read(tp, dp, &bp);
+       if (error)
                return error;
-       }
-       ASSERT(bp != NULL);
-       block = bp->data;
-       /*
-        * Check the magic number, corrupted if wrong.
-        */
-       if (INT_GET(block->hdr.magic, ARCH_CONVERT) != XFS_DIR2_BLOCK_MAGIC) {
-               xfs_da_brelse(tp, bp);
-               return XFS_ERROR(EFSCORRUPTED);
-       }
-       len = XFS_DIR2_DATA_ENTSIZE(args->namelen);
+
+       len = dp->d_ops->data_entsize(args->namelen);
+
        /*
         * Set up pointers to parts of the block.
         */
-       bf = block->hdr.bestfree;
-       btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
-       blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT);
-       /*
-        * No stale entries?  Need space for entry and new leaf.
-        */
-       if (INT_ISZERO(btp->stale, ARCH_CONVERT)) {
-               /*
-                * Tag just before the first leaf entry.
-                */
-               tagp = (xfs_dir2_data_off_t *)blp - 1;
-               /*
-                * Data object just before the first leaf entry.
-                */
-               enddup = (xfs_dir2_data_unused_t *)((char *)block + INT_GET(*tagp, ARCH_CONVERT));
-               /*
-                * If it's not free then can't do this add without cleaning up:
-                * the space before the first leaf entry needs to be free so it
-                * can be expanded to hold the pointer to the new entry.
-                */
-               if (INT_GET(enddup->freetag, ARCH_CONVERT) != XFS_DIR2_DATA_FREE_TAG)
-                       dup = enddup = NULL;
-               /*
-                * Check out the biggest freespace and see if it's the same one.
-                */
-               else {
-                       dup = (xfs_dir2_data_unused_t *)
-                             ((char *)block + INT_GET(bf[0].offset, ARCH_CONVERT));
-                       if (dup == enddup) {
-                               /*
-                                * It is the biggest freespace, is it too small
-                                * to hold the new leaf too?
-                                */
-                               if (INT_GET(dup->length, ARCH_CONVERT) < len + (uint)sizeof(*blp)) {
-                                       /*
-                                        * Yes, we use the second-largest
-                                        * entry instead if it works.
-                                        */
-                                       if (INT_GET(bf[1].length, ARCH_CONVERT) >= len)
-                                               dup = (xfs_dir2_data_unused_t *)
-                                                     ((char *)block +
-                                                      INT_GET(bf[1].offset, ARCH_CONVERT));
-                                       else
-                                               dup = NULL;
-                               }
-                       } else {
-                               /*
-                                * Not the same free entry,
-                                * just check its length.
-                                */
-                               if (INT_GET(dup->length, ARCH_CONVERT) < len) {
-                                       dup = NULL;
-                               }
-                       }
-               }
-               compact = 0;
-       }
+       hdr = bp->b_addr;
+       btp = xfs_dir2_block_tail_p(args->geo, hdr);
+       blp = xfs_dir2_block_leaf_p(btp);
+
        /*
-        * If there are stale entries we'll use one for the leaf.
-        * Is the biggest entry enough to avoid compaction?
+        * Find out if we can reuse stale entries or whether we need extra
+        * space for entry and new leaf.
         */
-       else if (INT_GET(bf[0].length, ARCH_CONVERT) >= len) {
-               dup = (xfs_dir2_data_unused_t *)
-                     ((char *)block + INT_GET(bf[0].offset, ARCH_CONVERT));
-               compact = 0;
-       }
+       xfs_dir2_block_need_space(dp, hdr, btp, blp, &tagp, &dup,
+                                 &enddup, &compact, len);
+
        /*
-        * Will need to compact to make this work.
+        * Done everything we need for a space check now.
         */
-       else {
-               /*
-                * Tag just before the first leaf entry.
-                */
-               tagp = (xfs_dir2_data_off_t *)blp - 1;
-               /*
-                * Data object just before the first leaf entry.
-                */
-               dup = (xfs_dir2_data_unused_t *)((char *)block + INT_GET(*tagp, ARCH_CONVERT));
-               /*
-                * If it's not free then the data will go where the
-                * leaf data starts now, if it works at all.
-                */
-               if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) {
-                       if (INT_GET(dup->length, ARCH_CONVERT) + (INT_GET(btp->stale, ARCH_CONVERT) - 1) *
-                           (uint)sizeof(*blp) < len)
-                               dup = NULL;
-               } else if ((INT_GET(btp->stale, ARCH_CONVERT) - 1) * (uint)sizeof(*blp) < len)
-                       dup = NULL;
-               else
-                       dup = (xfs_dir2_data_unused_t *)blp;
-               compact = 1;
+       if (args->op_flags & XFS_DA_OP_JUSTCHECK) {
+               xfs_trans_brelse(tp, bp);
+               if (!dup)
+                       return -ENOSPC;
+               return 0;
        }
-       /*
-        * If this isn't a real add, we're done with the buffer.
-        */
-       if (args->justcheck)
-               xfs_da_brelse(tp, bp);
+
        /*
         * If we don't have space for the new entry & leaf ...
         */
        if (!dup) {
-               /*
-                * Not trying to actually do anything, or don't have
-                * a space reservation: return no-space.
-                */
-               if (args->justcheck || args->total == 0)
-                       return XFS_ERROR(ENOSPC);
+               /* Don't have a space reservation: return no-space.  */
+               if (args->total == 0)
+                       return -ENOSPC;
                /*
                 * Convert to the next larger format.
                 * Then add the new entry in that format.
                 */
                error = xfs_dir2_block_to_leaf(args, bp);
-               xfs_da_buf_done(bp);
                if (error)
                        return error;
                return xfs_dir2_leaf_addname(args);
        }
-       /*
-        * Just checking, and it would work, so say so.
-        */
-       if (args->justcheck)
-               return 0;
+
        needlog = needscan = 0;
+
        /*
         * If need to compact the leaf entries, do it now.
-        * Leave the highest-numbered stale entry stale.
-        * XXX should be the one closest to mid but mid is not yet computed.
         */
        if (compact) {
-               int     fromidx;                /* source leaf index */
-               int     toidx;                  /* target leaf index */
-
-               for (fromidx = toidx = INT_GET(btp->count, ARCH_CONVERT) - 1,
-                       highstale = lfloghigh = -1;
-                    fromidx >= 0;
-                    fromidx--) {
-                       if (INT_GET(blp[fromidx].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) {
-                               if (highstale == -1)
-                                       highstale = toidx;
-                               else {
-                                       if (lfloghigh == -1)
-                                               lfloghigh = toidx;
-                                       continue;
-                               }
-                       }
-                       if (fromidx < toidx)
-                               blp[toidx] = blp[fromidx];
-                       toidx--;
-               }
-               lfloglow = toidx + 1 - (INT_GET(btp->stale, ARCH_CONVERT) - 1);
-               lfloghigh -= INT_GET(btp->stale, ARCH_CONVERT) - 1;
-               INT_MOD(btp->count, ARCH_CONVERT, -(INT_GET(btp->stale, ARCH_CONVERT) - 1));
-               xfs_dir2_data_make_free(tp, bp,
-                       (xfs_dir2_data_aoff_t)((char *)blp - (char *)block),
-                       (xfs_dir2_data_aoff_t)((INT_GET(btp->stale, ARCH_CONVERT) - 1) * sizeof(*blp)),
-                       &needlog, &needscan);
-               blp += INT_GET(btp->stale, ARCH_CONVERT) - 1;
-               INT_SET(btp->stale, ARCH_CONVERT, 1);
+               xfs_dir2_block_compact(args, bp, hdr, btp, blp, &needlog,
+                                     &lfloghigh, &lfloglow);
+               /* recalculate blp post-compaction */
+               blp = xfs_dir2_block_leaf_p(btp);
+       } else if (btp->stale) {
                /*
-                * If we now need to rebuild the bestfree map, do so.
-                * This needs to happen before the next call to use_free.
+                * Set leaf logging boundaries to impossible state.
+                * For the no-stale case they're set explicitly.
                 */
-               if (needscan) {
-                       xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block,
-                               &needlog, NULL);
-                       needscan = 0;
-               }
-       }
-       /*
-        * Set leaf logging boundaries to impossible state.
-        * For the no-stale case they're set explicitly.
-        */
-       else if (INT_GET(btp->stale, ARCH_CONVERT)) {
-               lfloglow = INT_GET(btp->count, ARCH_CONVERT);
+               lfloglow = be32_to_cpu(btp->count);
                lfloghigh = -1;
        }
+
        /*
         * Find the slot that's first lower than our hash value, -1 if none.
         */
-       for (low = 0, high = INT_GET(btp->count, ARCH_CONVERT) - 1; low <= high; ) {
+       for (low = 0, high = be32_to_cpu(btp->count) - 1; low <= high; ) {
                mid = (low + high) >> 1;
-               if ((hash = INT_GET(blp[mid].hashval, ARCH_CONVERT)) == args->hashval)
+               if ((hash = be32_to_cpu(blp[mid].hashval)) == args->hashval)
                        break;
                if (hash < args->hashval)
                        low = mid + 1;
                else
                        high = mid - 1;
        }
-       while (mid >= 0 && INT_GET(blp[mid].hashval, ARCH_CONVERT) >= args->hashval) {
+       while (mid >= 0 && be32_to_cpu(blp[mid].hashval) >= args->hashval) {
                mid--;
        }
        /*
         * No stale entries, will use enddup space to hold new leaf.
         */
-       if (INT_ISZERO(btp->stale, ARCH_CONVERT)) {
+       if (!btp->stale) {
+               xfs_dir2_data_aoff_t    aoff;
+
                /*
                 * Mark the space needed for the new leaf entry, now in use.
                 */
-               xfs_dir2_data_use_free(tp, bp, enddup,
-                       (xfs_dir2_data_aoff_t)
-                       ((char *)enddup - (char *)block + INT_GET(enddup->length, ARCH_CONVERT) -
-                        sizeof(*blp)),
-                       (xfs_dir2_data_aoff_t)sizeof(*blp),
-                       &needlog, &needscan);
+               aoff = (xfs_dir2_data_aoff_t)((char *)enddup - (char *)hdr +
+                               be16_to_cpu(enddup->length) - sizeof(*blp));
+               error = xfs_dir2_data_use_free(args, bp, enddup, aoff,
+                               (xfs_dir2_data_aoff_t)sizeof(*blp), &needlog,
+                               &needscan);
+               if (error)
+                       return error;
+
                /*
                 * Update the tail (entry count).
                 */
-               INT_MOD(btp->count, ARCH_CONVERT, +1);
+               be32_add_cpu(&btp->count, 1);
                /*
                 * If we now need to rebuild the bestfree map, do so.
                 * This needs to happen before the next call to use_free.
                 */
                if (needscan) {
-                       xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block,
-                               &needlog, NULL);
+                       xfs_dir2_data_freescan(dp, hdr, &needlog);
                        needscan = 0;
                }
                /*
@@ -330,12 +478,14 @@ xfs_dir2_block_addname(
        else {
                for (lowstale = mid;
                     lowstale >= 0 &&
-                       INT_GET(blp[lowstale].address, ARCH_CONVERT) != XFS_DIR2_NULL_DATAPTR;
+                       blp[lowstale].address !=
+                       cpu_to_be32(XFS_DIR2_NULL_DATAPTR);
                     lowstale--)
                        continue;
                for (highstale = mid + 1;
-                    highstale < INT_GET(btp->count, ARCH_CONVERT) &&
-                       INT_GET(blp[highstale].address, ARCH_CONVERT) != XFS_DIR2_NULL_DATAPTR &&
+                    highstale < be32_to_cpu(btp->count) &&
+                       blp[highstale].address !=
+                       cpu_to_be32(XFS_DIR2_NULL_DATAPTR) &&
                        (lowstale < 0 || mid - lowstale > highstale - mid);
                     highstale++)
                        continue;
@@ -343,7 +493,7 @@ xfs_dir2_block_addname(
                 * Move entries toward the low-numbered stale entry.
                 */
                if (lowstale >= 0 &&
-                   (highstale == INT_GET(btp->count, ARCH_CONVERT) ||
+                   (highstale == be32_to_cpu(btp->count) ||
                     mid - lowstale <= highstale - mid)) {
                        if (mid - lowstale)
                                memmove(&blp[lowstale], &blp[lowstale + 1],
@@ -355,7 +505,7 @@ xfs_dir2_block_addname(
                 * Move entries toward the high-numbered stale entry.
                 */
                else {
-                       ASSERT(highstale < INT_GET(btp->count, ARCH_CONVERT));
+                       ASSERT(highstale < be32_to_cpu(btp->count));
                        mid++;
                        if (highstale - mid)
                                memmove(&blp[mid + 1], &blp[mid],
@@ -363,7 +513,7 @@ xfs_dir2_block_addname(
                        lfloglow = MIN(mid, lfloglow);
                        lfloghigh = MAX(highstale, lfloghigh);
                }
-               INT_MOD(btp->stale, ARCH_CONVERT, -1);
+               be32_add_cpu(&btp->stale, -1);
        }
        /*
         * Point to the new data entry.
@@ -372,78 +522,74 @@ xfs_dir2_block_addname(
        /*
         * Fill in the leaf entry.
         */
-       INT_SET(blp[mid].hashval, ARCH_CONVERT, args->hashval);
-       INT_SET(blp[mid].address, ARCH_CONVERT, XFS_DIR2_BYTE_TO_DATAPTR(mp, (char *)dep - (char *)block));
+       blp[mid].hashval = cpu_to_be32(args->hashval);
+       blp[mid].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(
+                               (char *)dep - (char *)hdr));
        xfs_dir2_block_log_leaf(tp, bp, lfloglow, lfloghigh);
        /*
         * Mark space for the data entry used.
         */
-       xfs_dir2_data_use_free(tp, bp, dup,
-               (xfs_dir2_data_aoff_t)((char *)dup - (char *)block),
-               (xfs_dir2_data_aoff_t)len, &needlog, &needscan);
+       error = xfs_dir2_data_use_free(args, bp, dup,
+                       (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr),
+                       (xfs_dir2_data_aoff_t)len, &needlog, &needscan);
+       if (error)
+               return error;
        /*
         * Create the new data entry.
         */
-       INT_SET(dep->inumber, ARCH_CONVERT, args->inumber);
+       dep->inumber = cpu_to_be64(args->inumber);
        dep->namelen = args->namelen;
        memcpy(dep->name, args->name, args->namelen);
-       tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
-       INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)block));
+       dp->d_ops->data_put_ftype(dep, args->filetype);
+       tagp = dp->d_ops->data_entry_tag_p(dep);
+       *tagp = cpu_to_be16((char *)dep - (char *)hdr);
        /*
         * Clean up the bestfree array and log the header, tail, and entry.
         */
        if (needscan)
-               xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog,
-                       NULL);
+               xfs_dir2_data_freescan(dp, hdr, &needlog);
        if (needlog)
-               xfs_dir2_data_log_header(tp, bp);
+               xfs_dir2_data_log_header(args, bp);
        xfs_dir2_block_log_tail(tp, bp);
-       xfs_dir2_data_log_entry(tp, bp, dep);
-       xfs_dir2_data_check(dp, bp);
-       xfs_da_buf_done(bp);
+       xfs_dir2_data_log_entry(args, bp, dep);
+       xfs_dir3_data_check(dp, bp);
        return 0;
 }
 
 /*
  * Log leaf entries from the block.
  */
-STATIC void
+static void
 xfs_dir2_block_log_leaf(
        xfs_trans_t             *tp,            /* transaction structure */
-       xfs_dabuf_t             *bp,            /* block buffer */
+       struct xfs_buf          *bp,            /* block buffer */
        int                     first,          /* index of first logged leaf */
        int                     last)           /* index of last logged leaf */
 {
-       xfs_dir2_block_t        *block;         /* directory block structure */
-       xfs_dir2_leaf_entry_t   *blp;           /* block leaf entries */
-       xfs_dir2_block_tail_t   *btp;           /* block tail */
-       xfs_mount_t             *mp;            /* filesystem mount point */
+       xfs_dir2_data_hdr_t     *hdr = bp->b_addr;
+       xfs_dir2_leaf_entry_t   *blp;
+       xfs_dir2_block_tail_t   *btp;
 
-       mp = tp->t_mountp;
-       block = bp->data;
-       btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
-       blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT);
-       xfs_da_log_buf(tp, bp, (uint)((char *)&blp[first] - (char *)block),
-               (uint)((char *)&blp[last + 1] - (char *)block - 1));
+       btp = xfs_dir2_block_tail_p(tp->t_mountp->m_dir_geo, hdr);
+       blp = xfs_dir2_block_leaf_p(btp);
+       xfs_trans_log_buf(tp, bp, (uint)((char *)&blp[first] - (char *)hdr),
+               (uint)((char *)&blp[last + 1] - (char *)hdr - 1));
 }
 
 /*
  * Log the block tail.
  */
-STATIC void
+static void
 xfs_dir2_block_log_tail(
        xfs_trans_t             *tp,            /* transaction structure */
-       xfs_dabuf_t             *bp)            /* block buffer */
+       struct xfs_buf          *bp)            /* block buffer */
 {
-       xfs_dir2_block_t        *block;         /* directory block structure */
-       xfs_dir2_block_tail_t   *btp;           /* block tail */
-       xfs_mount_t             *mp;            /* filesystem mount point */
+       xfs_dir2_data_hdr_t     *hdr = bp->b_addr;
+       xfs_dir2_block_tail_t   *btp;
 
-       mp = tp->t_mountp;
-       block = bp->data;
-       btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
-       xfs_da_log_buf(tp, bp, (uint)((char *)btp - (char *)block),
-               (uint)((char *)(btp + 1) - (char *)block - 1));
+       btp = xfs_dir2_block_tail_p(tp->t_mountp->m_dir_geo, hdr);
+       xfs_trans_log_buf(tp, bp, (uint)((char *)btp - (char *)hdr),
+               (uint)((char *)(btp + 1) - (char *)hdr - 1));
 }
 
 /*
@@ -454,17 +600,17 @@ int                                               /* error */
 xfs_dir2_block_lookup(
        xfs_da_args_t           *args)          /* dir lookup arguments */
 {
-       xfs_dir2_block_t        *block;         /* block structure */
+       xfs_dir2_data_hdr_t     *hdr;           /* block header */
        xfs_dir2_leaf_entry_t   *blp;           /* block leaf entries */
-       xfs_dabuf_t             *bp;            /* block buffer */
+       struct xfs_buf          *bp;            /* block buffer */
        xfs_dir2_block_tail_t   *btp;           /* block tail */
        xfs_dir2_data_entry_t   *dep;           /* block data entry */
        xfs_inode_t             *dp;            /* incore inode */
        int                     ent;            /* entry index */
        int                     error;          /* error return value */
-       xfs_mount_t             *mp;            /* filesystem mount point */
 
-       xfs_dir2_trace_args("block_lookup", args);
+       trace_xfs_dir2_block_lookup(args);
+
        /*
         * Get the buffer, look up the entry.
         * If not found (ENOENT) then return, have no buffer.
@@ -472,37 +618,39 @@ xfs_dir2_block_lookup(
        if ((error = xfs_dir2_block_lookup_int(args, &bp, &ent)))
                return error;
        dp = args->dp;
-       mp = dp->i_mount;
-       block = bp->data;
-       xfs_dir2_data_check(dp, bp);
-       btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
-       blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT);
+       hdr = bp->b_addr;
+       xfs_dir3_data_check(dp, bp);
+       btp = xfs_dir2_block_tail_p(args->geo, hdr);
+       blp = xfs_dir2_block_leaf_p(btp);
        /*
         * Get the offset from the leaf entry, to point to the data.
         */
-       dep = (xfs_dir2_data_entry_t *)
-             ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, INT_GET(blp[ent].address, ARCH_CONVERT)));
+       dep = (xfs_dir2_data_entry_t *)((char *)hdr +
+                       xfs_dir2_dataptr_to_off(args->geo,
+                                               be32_to_cpu(blp[ent].address)));
        /*
-        * Fill in inode number, release the block.
+        * Fill in inode number, CI name if appropriate, release the block.
         */
-       args->inumber = INT_GET(dep->inumber, ARCH_CONVERT);
-       xfs_da_brelse(args->trans, bp);
-       return XFS_ERROR(EEXIST);
+       args->inumber = be64_to_cpu(dep->inumber);
+       args->filetype = dp->d_ops->data_get_ftype(dep);
+       error = xfs_dir_cilookup_result(args, dep->name, dep->namelen);
+       xfs_trans_brelse(args->trans, bp);
+       return error;
 }
 
 /*
  * Internal block lookup routine.
  */
-STATIC int                                     /* error */
+static int                                     /* error */
 xfs_dir2_block_lookup_int(
        xfs_da_args_t           *args,          /* dir lookup arguments */
-       xfs_dabuf_t             **bpp,          /* returned block buffer */
+       struct xfs_buf          **bpp,          /* returned block buffer */
        int                     *entno)         /* returned entry number */
 {
        xfs_dir2_dataptr_t      addr;           /* data entry address */
-       xfs_dir2_block_t        *block;         /* block structure */
+       xfs_dir2_data_hdr_t     *hdr;           /* block header */
        xfs_dir2_leaf_entry_t   *blp;           /* block leaf entries */
-       xfs_dabuf_t             *bp;            /* block buffer */
+       struct xfs_buf          *bp;            /* block buffer */
        xfs_dir2_block_tail_t   *btp;           /* block tail */
        xfs_dir2_data_entry_t   *dep;           /* block data entry */
        xfs_inode_t             *dp;            /* incore inode */
@@ -513,45 +661,43 @@ xfs_dir2_block_lookup_int(
        int                     mid;            /* binary search current idx */
        xfs_mount_t             *mp;            /* filesystem mount point */
        xfs_trans_t             *tp;            /* transaction pointer */
+       enum xfs_dacmp          cmp;            /* comparison result */
 
        dp = args->dp;
        tp = args->trans;
        mp = dp->i_mount;
-       /*
-        * Read the buffer, return error if we can't get it.
-        */
-       if ((error =
-           xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, &bp, XFS_DATA_FORK))) {
+
+       error = xfs_dir3_block_read(tp, dp, &bp);
+       if (error)
                return error;
-       }
-       ASSERT(bp != NULL);
-       block = bp->data;
-       xfs_dir2_data_check(dp, bp);
-       btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
-       blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT);
+
+       hdr = bp->b_addr;
+       xfs_dir3_data_check(dp, bp);
+       btp = xfs_dir2_block_tail_p(args->geo, hdr);
+       blp = xfs_dir2_block_leaf_p(btp);
        /*
         * Loop doing a binary search for our hash value.
         * Find our entry, ENOENT if it's not there.
         */
-       for (low = 0, high = INT_GET(btp->count, ARCH_CONVERT) - 1; ; ) {
+       for (low = 0, high = be32_to_cpu(btp->count) - 1; ; ) {
                ASSERT(low <= high);
                mid = (low + high) >> 1;
-               if ((hash = INT_GET(blp[mid].hashval, ARCH_CONVERT)) == args->hashval)
+               if ((hash = be32_to_cpu(blp[mid].hashval)) == args->hashval)
                        break;
                if (hash < args->hashval)
                        low = mid + 1;
                else
                        high = mid - 1;
                if (low > high) {
-                       ASSERT(args->oknoent);
-                       xfs_da_brelse(tp, bp);
-                       return XFS_ERROR(ENOENT);
+                       ASSERT(args->op_flags & XFS_DA_OP_OKNOENT);
+                       xfs_trans_brelse(tp, bp);
+                       return -ENOENT;
                }
        }
        /*
         * Back up to the first one with the right hash value.
         */
-       while (mid > 0 && INT_GET(blp[mid - 1].hashval, ARCH_CONVERT) == args->hashval) {
+       while (mid > 0 && be32_to_cpu(blp[mid - 1].hashval) == args->hashval) {
                mid--;
        }
        /*
@@ -559,30 +705,41 @@ xfs_dir2_block_lookup_int(
         * right hash value looking for our name.
         */
        do {
-               if ((addr = INT_GET(blp[mid].address, ARCH_CONVERT)) == XFS_DIR2_NULL_DATAPTR)
+               if ((addr = be32_to_cpu(blp[mid].address)) == XFS_DIR2_NULL_DATAPTR)
                        continue;
                /*
                 * Get pointer to the entry from the leaf.
                 */
                dep = (xfs_dir2_data_entry_t *)
-                       ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, addr));
+                       ((char *)hdr + xfs_dir2_dataptr_to_off(args->geo, addr));
                /*
-                * Compare, if it's right give back buffer & entry number.
+                * Compare name and if it's an exact match, return the index
+                * and buffer. If it's the first case-insensitive match, store
+                * the index and buffer and continue looking for an exact match.
                 */
-               if (dep->namelen == args->namelen &&
-                   dep->name[0] == args->name[0] &&
-                   memcmp(dep->name, args->name, args->namelen) == 0) {
+               cmp = mp->m_dirnameops->compname(args, dep->name, dep->namelen);
+               if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) {
+                       args->cmpresult = cmp;
                        *bpp = bp;
                        *entno = mid;
-                       return 0;
+                       if (cmp == XFS_CMP_EXACT)
+                               return 0;
                }
-       } while (++mid < INT_GET(btp->count, ARCH_CONVERT) && INT_GET(blp[mid].hashval, ARCH_CONVERT) == hash);
+       } while (++mid < be32_to_cpu(btp->count) &&
+                       be32_to_cpu(blp[mid].hashval) == hash);
+
+       ASSERT(args->op_flags & XFS_DA_OP_OKNOENT);
+       /*
+        * Here, we can only be doing a lookup (not a rename or replace).
+        * If a case-insensitive match was found earlier, return success.
+        */
+       if (args->cmpresult == XFS_CMP_CASE)
+               return 0;
        /*
         * No match, release the buffer and return ENOENT.
         */
-       ASSERT(args->oknoent);
-       xfs_da_brelse(tp, bp);
-       return XFS_ERROR(ENOENT);
+       xfs_trans_brelse(tp, bp);
+       return -ENOENT;
 }
 
 /*
@@ -593,22 +750,22 @@ int                                               /* error */
 xfs_dir2_block_removename(
        xfs_da_args_t           *args)          /* directory operation args */
 {
-       xfs_dir2_block_t        *block;         /* block structure */
+       xfs_dir2_data_hdr_t     *hdr;           /* block header */
        xfs_dir2_leaf_entry_t   *blp;           /* block leaf pointer */
-       xfs_dabuf_t             *bp;            /* block buffer */
+       struct xfs_buf          *bp;            /* block buffer */
        xfs_dir2_block_tail_t   *btp;           /* block tail */
        xfs_dir2_data_entry_t   *dep;           /* block data entry */
        xfs_inode_t             *dp;            /* incore inode */
        int                     ent;            /* block leaf entry index */
        int                     error;          /* error return value */
-       xfs_mount_t             *mp;            /* filesystem mount point */
        int                     needlog;        /* need to log block header */
        int                     needscan;       /* need to fixup bestfree */
        xfs_dir2_sf_hdr_t       sfh;            /* shortform header */
        int                     size;           /* shortform size */
        xfs_trans_t             *tp;            /* transaction pointer */
 
-       xfs_dir2_trace_args("block_removename", args);
+       trace_xfs_dir2_block_removename(args);
+
        /*
         * Look up the entry in the block.  Gets the buffer and entry index.
         * It will always be there, the vnodeops level does a lookup first.
@@ -618,49 +775,47 @@ xfs_dir2_block_removename(
        }
        dp = args->dp;
        tp = args->trans;
-       mp = dp->i_mount;
-       block = bp->data;
-       btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
-       blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT);
+       hdr = bp->b_addr;
+       btp = xfs_dir2_block_tail_p(args->geo, hdr);
+       blp = xfs_dir2_block_leaf_p(btp);
        /*
         * Point to the data entry using the leaf entry.
         */
-       dep = (xfs_dir2_data_entry_t *)
-             ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, INT_GET(blp[ent].address, ARCH_CONVERT)));
+       dep = (xfs_dir2_data_entry_t *)((char *)hdr +
+                       xfs_dir2_dataptr_to_off(args->geo,
+                                               be32_to_cpu(blp[ent].address)));
        /*
         * Mark the data entry's space free.
         */
        needlog = needscan = 0;
-       xfs_dir2_data_make_free(tp, bp,
-               (xfs_dir2_data_aoff_t)((char *)dep - (char *)block),
-               XFS_DIR2_DATA_ENTSIZE(dep->namelen), &needlog, &needscan);
+       xfs_dir2_data_make_free(args, bp,
+               (xfs_dir2_data_aoff_t)((char *)dep - (char *)hdr),
+               dp->d_ops->data_entsize(dep->namelen), &needlog, &needscan);
        /*
         * Fix up the block tail.
         */
-       INT_MOD(btp->stale, ARCH_CONVERT, +1);
+       be32_add_cpu(&btp->stale, 1);
        xfs_dir2_block_log_tail(tp, bp);
        /*
         * Remove the leaf entry by marking it stale.
         */
-       INT_SET(blp[ent].address, ARCH_CONVERT, XFS_DIR2_NULL_DATAPTR);
+       blp[ent].address = cpu_to_be32(XFS_DIR2_NULL_DATAPTR);
        xfs_dir2_block_log_leaf(tp, bp, ent, ent);
        /*
         * Fix up bestfree, log the header if necessary.
         */
        if (needscan)
-               xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog,
-                       NULL);
+               xfs_dir2_data_freescan(dp, hdr, &needlog);
        if (needlog)
-               xfs_dir2_data_log_header(tp, bp);
-       xfs_dir2_data_check(dp, bp);
+               xfs_dir2_data_log_header(args, bp);
+       xfs_dir3_data_check(dp, bp);
        /*
         * See if the size as a shortform is good enough.
         */
-       if ((size = xfs_dir2_block_sfsize(dp, block, &sfh)) >
-           XFS_IFORK_DSIZE(dp)) {
-               xfs_da_buf_done(bp);
+       size = xfs_dir2_block_sfsize(dp, hdr, &sfh);
+       if (size > XFS_IFORK_DSIZE(dp))
                return 0;
-       }
+
        /*
         * If it works, do the conversion.
         */
@@ -675,17 +830,17 @@ int                                               /* error */
 xfs_dir2_block_replace(
        xfs_da_args_t           *args)          /* directory operation args */
 {
-       xfs_dir2_block_t        *block;         /* block structure */
+       xfs_dir2_data_hdr_t     *hdr;           /* block header */
        xfs_dir2_leaf_entry_t   *blp;           /* block leaf entries */
-       xfs_dabuf_t             *bp;            /* block buffer */
+       struct xfs_buf          *bp;            /* block buffer */
        xfs_dir2_block_tail_t   *btp;           /* block tail */
        xfs_dir2_data_entry_t   *dep;           /* block data entry */
        xfs_inode_t             *dp;            /* incore inode */
        int                     ent;            /* leaf entry index */
        int                     error;          /* error return value */
-       xfs_mount_t             *mp;            /* filesystem mount point */
 
-       xfs_dir2_trace_args("block_replace", args);
+       trace_xfs_dir2_block_replace(args);
+
        /*
         * Lookup the entry in the directory.  Get buffer and entry index.
         * This will always succeed since the caller has already done a lookup.
@@ -694,23 +849,23 @@ xfs_dir2_block_replace(
                return error;
        }
        dp = args->dp;
-       mp = dp->i_mount;
-       block = bp->data;
-       btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
-       blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT);
+       hdr = bp->b_addr;
+       btp = xfs_dir2_block_tail_p(args->geo, hdr);
+       blp = xfs_dir2_block_leaf_p(btp);
        /*
         * Point to the data entry we need to change.
         */
-       dep = (xfs_dir2_data_entry_t *)
-             ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, INT_GET(blp[ent].address, ARCH_CONVERT)));
-       ASSERT(INT_GET(dep->inumber, ARCH_CONVERT) != args->inumber);
+       dep = (xfs_dir2_data_entry_t *)((char *)hdr +
+                       xfs_dir2_dataptr_to_off(args->geo,
+                                               be32_to_cpu(blp[ent].address)));
+       ASSERT(be64_to_cpu(dep->inumber) != args->inumber);
        /*
         * Change the inode number to the new value.
         */
-       INT_SET(dep->inumber, ARCH_CONVERT, args->inumber);
-       xfs_dir2_data_log_entry(args->trans, bp, dep);
-       xfs_dir2_data_check(dp, bp);
-       xfs_da_buf_done(bp);
+       dep->inumber = cpu_to_be64(args->inumber);
+       dp->d_ops->data_put_ftype(dep, args->filetype);
+       xfs_dir2_data_log_entry(args, bp, dep);
+       xfs_dir3_data_check(dp, bp);
        return 0;
 }
 
@@ -727,8 +882,8 @@ xfs_dir2_block_sort(
 
        la = a;
        lb = b;
-       return INT_GET(la->hashval, ARCH_CONVERT) < INT_GET(lb->hashval, ARCH_CONVERT) ? -1 :
-               (INT_GET(la->hashval, ARCH_CONVERT) > INT_GET(lb->hashval, ARCH_CONVERT) ? 1 : 0);
+       return be32_to_cpu(la->hashval) < be32_to_cpu(lb->hashval) ? -1 :
+               (be32_to_cpu(la->hashval) > be32_to_cpu(lb->hashval) ? 1 : 0);
 }
 
 /*
@@ -737,11 +892,11 @@ xfs_dir2_block_sort(
 int                                            /* error */
 xfs_dir2_leaf_to_block(
        xfs_da_args_t           *args,          /* operation arguments */
-       xfs_dabuf_t             *lbp,           /* leaf buffer */
-       xfs_dabuf_t             *dbp)           /* data buffer */
+       struct xfs_buf          *lbp,           /* leaf buffer */
+       struct xfs_buf          *dbp)           /* data buffer */
 {
-       xfs_dir2_data_off_t     *bestsp;        /* leaf bests table */
-       xfs_dir2_block_t        *block;         /* block structure */
+       __be16                  *bestsp;        /* leaf bests table */
+       xfs_dir2_data_hdr_t     *hdr;           /* block header */
        xfs_dir2_block_tail_t   *btp;           /* block tail */
        xfs_inode_t             *dp;            /* incore directory inode */
        xfs_dir2_data_unused_t  *dup;           /* unused data entry */
@@ -755,123 +910,127 @@ xfs_dir2_leaf_to_block(
        int                     needscan;       /* need to scan for bestfree */
        xfs_dir2_sf_hdr_t       sfh;            /* shortform header */
        int                     size;           /* bytes used */
-       xfs_dir2_data_off_t     *tagp;          /* end of entry (tag) */
+       __be16                  *tagp;          /* end of entry (tag) */
        int                     to;             /* block/leaf to index */
        xfs_trans_t             *tp;            /* transaction pointer */
+       struct xfs_dir2_leaf_entry *ents;
+       struct xfs_dir3_icleaf_hdr leafhdr;
+
+       trace_xfs_dir2_leaf_to_block(args);
 
-       xfs_dir2_trace_args_bb("leaf_to_block", args, lbp, dbp);
        dp = args->dp;
        tp = args->trans;
        mp = dp->i_mount;
-       leaf = lbp->data;
-       ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC);
-       ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);
+       leaf = lbp->b_addr;
+       dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf);
+       ents = dp->d_ops->leaf_ents_p(leaf);
+       ltp = xfs_dir2_leaf_tail_p(args->geo, leaf);
+
+       ASSERT(leafhdr.magic == XFS_DIR2_LEAF1_MAGIC ||
+              leafhdr.magic == XFS_DIR3_LEAF1_MAGIC);
        /*
         * If there are data blocks other than the first one, take this
         * opportunity to remove trailing empty data blocks that may have
         * been left behind during no-space-reservation operations.
         * These will show up in the leaf bests table.
         */
-       while (dp->i_d.di_size > mp->m_dirblksize) {
-               bestsp = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT);
-               if (INT_GET(bestsp[INT_GET(ltp->bestcount, ARCH_CONVERT) - 1], ARCH_CONVERT) ==
-                   mp->m_dirblksize - (uint)sizeof(block->hdr)) {
+       while (dp->i_d.di_size > args->geo->blksize) {
+               int hdrsz;
+
+               hdrsz = dp->d_ops->data_entry_offset;
+               bestsp = xfs_dir2_leaf_bests_p(ltp);
+               if (be16_to_cpu(bestsp[be32_to_cpu(ltp->bestcount) - 1]) ==
+                                           args->geo->blksize - hdrsz) {
                        if ((error =
                            xfs_dir2_leaf_trim_data(args, lbp,
-                                   (xfs_dir2_db_t)(INT_GET(ltp->bestcount, ARCH_CONVERT) - 1))))
-                               goto out;
-               } else {
-                       error = 0;
-                       goto out;
-               }
+                                   (xfs_dir2_db_t)(be32_to_cpu(ltp->bestcount) - 1))))
+                               return error;
+               } else
+                       return 0;
        }
        /*
         * Read the data block if we don't already have it, give up if it fails.
         */
-       if (dbp == NULL &&
-           (error = xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, &dbp,
-                   XFS_DATA_FORK))) {
-               goto out;
+       if (!dbp) {
+               error = xfs_dir3_data_read(tp, dp, args->geo->datablk, -1, &dbp);
+               if (error)
+                       return error;
        }
-       block = dbp->data;
-       ASSERT(INT_GET(block->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC);
+       hdr = dbp->b_addr;
+       ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
+              hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC));
+
        /*
         * Size of the "leaf" area in the block.
         */
-       size = (uint)sizeof(block->tail) +
-              (uint)sizeof(*lep) * (INT_GET(leaf->hdr.count, ARCH_CONVERT) - INT_GET(leaf->hdr.stale, ARCH_CONVERT));
+       size = (uint)sizeof(xfs_dir2_block_tail_t) +
+              (uint)sizeof(*lep) * (leafhdr.count - leafhdr.stale);
        /*
         * Look at the last data entry.
         */
-       tagp = (xfs_dir2_data_off_t *)((char *)block + mp->m_dirblksize) - 1;
-       dup = (xfs_dir2_data_unused_t *)((char *)block + INT_GET(*tagp, ARCH_CONVERT));
+       tagp = (__be16 *)((char *)hdr + args->geo->blksize) - 1;
+       dup = (xfs_dir2_data_unused_t *)((char *)hdr + be16_to_cpu(*tagp));
        /*
         * If it's not free or is too short we can't do it.
         */
-       if (INT_GET(dup->freetag, ARCH_CONVERT) != XFS_DIR2_DATA_FREE_TAG || INT_GET(dup->length, ARCH_CONVERT) < size) {
-               error = 0;
-               goto out;
-       }
+       if (be16_to_cpu(dup->freetag) != XFS_DIR2_DATA_FREE_TAG ||
+           be16_to_cpu(dup->length) < size)
+               return 0;
+
        /*
         * Start converting it to block form.
         */
-       INT_SET(block->hdr.magic, ARCH_CONVERT, XFS_DIR2_BLOCK_MAGIC);
+       xfs_dir3_block_init(mp, tp, dbp, dp);
+
        needlog = 1;
        needscan = 0;
        /*
         * Use up the space at the end of the block (blp/btp).
         */
-       xfs_dir2_data_use_free(tp, dbp, dup, mp->m_dirblksize - size, size,
-               &needlog, &needscan);
+       error = xfs_dir2_data_use_free(args, dbp, dup,
+                       args->geo->blksize - size, size, &needlog, &needscan);
+       if (error)
+               return error;
        /*
         * Initialize the block tail.
         */
-       btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
-       INT_SET(btp->count, ARCH_CONVERT, INT_GET(leaf->hdr.count, ARCH_CONVERT) - INT_GET(leaf->hdr.stale, ARCH_CONVERT));
-       INT_ZERO(btp->stale, ARCH_CONVERT);
+       btp = xfs_dir2_block_tail_p(args->geo, hdr);
+       btp->count = cpu_to_be32(leafhdr.count - leafhdr.stale);
+       btp->stale = 0;
        xfs_dir2_block_log_tail(tp, dbp);
        /*
         * Initialize the block leaf area.  We compact out stale entries.
         */
-       lep = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT);
-       for (from = to = 0; from < INT_GET(leaf->hdr.count, ARCH_CONVERT); from++) {
-               if (INT_GET(leaf->ents[from].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR)
+       lep = xfs_dir2_block_leaf_p(btp);
+       for (from = to = 0; from < leafhdr.count; from++) {
+               if (ents[from].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR))
                        continue;
-               lep[to++] = leaf->ents[from];
+               lep[to++] = ents[from];
        }
-       ASSERT(to == INT_GET(btp->count, ARCH_CONVERT));
-       xfs_dir2_block_log_leaf(tp, dbp, 0, INT_GET(btp->count, ARCH_CONVERT) - 1);
+       ASSERT(to == be32_to_cpu(btp->count));
+       xfs_dir2_block_log_leaf(tp, dbp, 0, be32_to_cpu(btp->count) - 1);
        /*
         * Scan the bestfree if we need it and log the data block header.
         */
        if (needscan)
-               xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog,
-                       NULL);
+               xfs_dir2_data_freescan(dp, hdr, &needlog);
        if (needlog)
-               xfs_dir2_data_log_header(tp, dbp);
+               xfs_dir2_data_log_header(args, dbp);
        /*
         * Pitch the old leaf block.
         */
-       error = xfs_da_shrink_inode(args, mp->m_dirleafblk, lbp);
-       lbp = NULL;
-       if (error) {
-               goto out;
-       }
+       error = xfs_da_shrink_inode(args, args->geo->leafblk, lbp);
+       if (error)
+               return error;
+
        /*
         * Now see if the resulting block can be shrunken to shortform.
         */
-       if ((size = xfs_dir2_block_sfsize(dp, block, &sfh)) >
-           XFS_IFORK_DSIZE(dp)) {
-               error = 0;
-               goto out;
-       }
+       size = xfs_dir2_block_sfsize(dp, hdr, &sfh);
+       if (size > XFS_IFORK_DSIZE(dp))
+               return 0;
+
        return xfs_dir2_block_to_sf(args, dbp, size, &sfh);
-out:
-       if (lbp)
-               xfs_da_buf_done(lbp);
-       if (dbp)
-               xfs_da_buf_done(dbp);
-       return error;
 }
 
 /*
@@ -882,12 +1041,10 @@ xfs_dir2_sf_to_block(
        xfs_da_args_t           *args)          /* operation arguments */
 {
        xfs_dir2_db_t           blkno;          /* dir-relative block # (0) */
-       xfs_dir2_block_t        *block;         /* block structure */
+       xfs_dir2_data_hdr_t     *hdr;           /* block header */
        xfs_dir2_leaf_entry_t   *blp;           /* block leaf entries */
-       xfs_dabuf_t             *bp;            /* block buffer */
+       struct xfs_buf          *bp;            /* block buffer */
        xfs_dir2_block_tail_t   *btp;           /* block tail pointer */
-       char                    *buf;           /* sf buffer */
-       int                     buf_len;
        xfs_dir2_data_entry_t   *dep;           /* data entry pointer */
        xfs_inode_t             *dp;            /* incore directory inode */
        int                     dummy;          /* trash */
@@ -901,122 +1058,130 @@ xfs_dir2_sf_to_block(
        int                     newoffset;      /* offset from current entry */
        int                     offset;         /* target block offset */
        xfs_dir2_sf_entry_t     *sfep;          /* sf entry pointer */
-       xfs_dir2_sf_t           *sfp;           /* shortform structure */
-       xfs_dir2_data_off_t     *tagp;          /* end of data entry */
+       xfs_dir2_sf_hdr_t       *oldsfp;        /* old shortform header  */
+       xfs_dir2_sf_hdr_t       *sfp;           /* shortform header  */
+       __be16                  *tagp;          /* end of data entry */
        xfs_trans_t             *tp;            /* transaction pointer */
+       struct xfs_name         name;
+       struct xfs_ifork        *ifp;
+
+       trace_xfs_dir2_sf_to_block(args);
 
-       xfs_dir2_trace_args("sf_to_block", args);
        dp = args->dp;
        tp = args->trans;
        mp = dp->i_mount;
-       ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
+       ifp = XFS_IFORK_PTR(dp, XFS_DATA_FORK);
+       ASSERT(ifp->if_flags & XFS_IFINLINE);
        /*
         * Bomb out if the shortform directory is way too short.
         */
        if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {
                ASSERT(XFS_FORCED_SHUTDOWN(mp));
-               return XFS_ERROR(EIO);
+               return -EIO;
        }
-       ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
-       ASSERT(dp->i_df.if_u1.if_data != NULL);
-       sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
-       ASSERT(dp->i_d.di_size >= XFS_DIR2_SF_HDR_SIZE(sfp->hdr.i8count));
+
+       oldsfp = (xfs_dir2_sf_hdr_t *)ifp->if_u1.if_data;
+
+       ASSERT(ifp->if_bytes == dp->i_d.di_size);
+       ASSERT(ifp->if_u1.if_data != NULL);
+       ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(oldsfp->i8count));
+       ASSERT(dp->i_d.di_nextents == 0);
+
        /*
-        * Copy the directory into the stack buffer.
+        * Copy the directory into a temporary buffer.
         * Then pitch the incore inode data so we can make extents.
         */
+       sfp = kmem_alloc(ifp->if_bytes, KM_SLEEP);
+       memcpy(sfp, oldsfp, ifp->if_bytes);
 
-       buf_len = dp->i_df.if_bytes;
-       buf = kmem_alloc(dp->i_df.if_bytes, KM_SLEEP);
-
-       memcpy(buf, sfp, dp->i_df.if_bytes);
-       xfs_idata_realloc(dp, -dp->i_df.if_bytes, XFS_DATA_FORK);
+       xfs_idata_realloc(dp, -ifp->if_bytes, XFS_DATA_FORK);
+       xfs_bmap_local_to_extents_empty(dp, XFS_DATA_FORK);
        dp->i_d.di_size = 0;
-       xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
-       /*
-        * Reset pointer - old sfp is gone.
-        */
-       sfp = (xfs_dir2_sf_t *)buf;
+
        /*
         * Add block 0 to the inode.
         */
        error = xfs_dir2_grow_inode(args, XFS_DIR2_DATA_SPACE, &blkno);
-       if (error) {
-               kmem_free(buf, buf_len);
-               return error;
-       }
+       if (error)
+               goto out_free;
        /*
-        * Initialize the data block.
+        * Initialize the data block, then convert it to block format.
         */
-       error = xfs_dir2_data_init(args, blkno, &bp);
-       if (error) {
-               kmem_free(buf, buf_len);
-               return error;
-       }
-       block = bp->data;
-       INT_SET(block->hdr.magic, ARCH_CONVERT, XFS_DIR2_BLOCK_MAGIC);
+       error = xfs_dir3_data_init(args, blkno, &bp);
+       if (error)
+               goto out_free;
+       xfs_dir3_block_init(mp, tp, bp, dp);
+       hdr = bp->b_addr;
+
        /*
         * Compute size of block "tail" area.
         */
        i = (uint)sizeof(*btp) +
-           (INT_GET(sfp->hdr.count, ARCH_CONVERT) + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t);
+           (sfp->count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t);
        /*
         * The whole thing is initialized to free by the init routine.
         * Say we're using the leaf and tail area.
         */
-       dup = (xfs_dir2_data_unused_t *)block->u;
+       dup = dp->d_ops->data_unused_p(hdr);
        needlog = needscan = 0;
-       xfs_dir2_data_use_free(tp, bp, dup, mp->m_dirblksize - i, i, &needlog,
-               &needscan);
+       error = xfs_dir2_data_use_free(args, bp, dup, args->geo->blksize - i,
+                       i, &needlog, &needscan);
+       if (error)
+               goto out_free;
        ASSERT(needscan == 0);
        /*
         * Fill in the tail.
         */
-       btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
-       INT_SET(btp->count, ARCH_CONVERT, INT_GET(sfp->hdr.count, ARCH_CONVERT) + 2);   /* ., .. */
-       INT_ZERO(btp->stale, ARCH_CONVERT);
-       blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT);
-       endoffset = (uint)((char *)blp - (char *)block);
+       btp = xfs_dir2_block_tail_p(args->geo, hdr);
+       btp->count = cpu_to_be32(sfp->count + 2);       /* ., .. */
+       btp->stale = 0;
+       blp = xfs_dir2_block_leaf_p(btp);
+       endoffset = (uint)((char *)blp - (char *)hdr);
        /*
         * Remove the freespace, we'll manage it.
         */
-       xfs_dir2_data_use_free(tp, bp, dup,
-               (xfs_dir2_data_aoff_t)((char *)dup - (char *)block),
-               INT_GET(dup->length, ARCH_CONVERT), &needlog, &needscan);
+       error = xfs_dir2_data_use_free(args, bp, dup,
+                       (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr),
+                       be16_to_cpu(dup->length), &needlog, &needscan);
+       if (error)
+               goto out_free;
        /*
         * Create entry for .
         */
-       dep = (xfs_dir2_data_entry_t *)
-             ((char *)block + XFS_DIR2_DATA_DOT_OFFSET);
-       INT_SET(dep->inumber, ARCH_CONVERT, dp->i_ino);
+       dep = dp->d_ops->data_dot_entry_p(hdr);
+       dep->inumber = cpu_to_be64(dp->i_ino);
        dep->namelen = 1;
        dep->name[0] = '.';
-       tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
-       INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)block));
-       xfs_dir2_data_log_entry(tp, bp, dep);
-       INT_SET(blp[0].hashval, ARCH_CONVERT, xfs_dir_hash_dot);
-       INT_SET(blp[0].address, ARCH_CONVERT, XFS_DIR2_BYTE_TO_DATAPTR(mp, (char *)dep - (char *)block));
+       dp->d_ops->data_put_ftype(dep, XFS_DIR3_FT_DIR);
+       tagp = dp->d_ops->data_entry_tag_p(dep);
+       *tagp = cpu_to_be16((char *)dep - (char *)hdr);
+       xfs_dir2_data_log_entry(args, bp, dep);
+       blp[0].hashval = cpu_to_be32(xfs_dir_hash_dot);
+       blp[0].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(
+                               (char *)dep - (char *)hdr));
        /*
         * Create entry for ..
         */
-       dep = (xfs_dir2_data_entry_t *)
-               ((char *)block + XFS_DIR2_DATA_DOTDOT_OFFSET);
-       INT_SET(dep->inumber, ARCH_CONVERT, XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, &sfp->hdr.parent, ARCH_CONVERT));
+       dep = dp->d_ops->data_dotdot_entry_p(hdr);
+       dep->inumber = cpu_to_be64(dp->d_ops->sf_get_parent_ino(sfp));
        dep->namelen = 2;
        dep->name[0] = dep->name[1] = '.';
-       tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
-       INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)block));
-       xfs_dir2_data_log_entry(tp, bp, dep);
-       INT_SET(blp[1].hashval, ARCH_CONVERT, xfs_dir_hash_dotdot);
-       INT_SET(blp[1].address, ARCH_CONVERT, XFS_DIR2_BYTE_TO_DATAPTR(mp, (char *)dep - (char *)block));
-       offset = XFS_DIR2_DATA_FIRST_OFFSET;
+       dp->d_ops->data_put_ftype(dep, XFS_DIR3_FT_DIR);
+       tagp = dp->d_ops->data_entry_tag_p(dep);
+       *tagp = cpu_to_be16((char *)dep - (char *)hdr);
+       xfs_dir2_data_log_entry(args, bp, dep);
+       blp[1].hashval = cpu_to_be32(xfs_dir_hash_dotdot);
+       blp[1].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(
+                               (char *)dep - (char *)hdr));
+       offset = dp->d_ops->data_first_offset;
        /*
         * Loop over existing entries, stuff them in.
         */
-       if ((i = 0) == INT_GET(sfp->hdr.count, ARCH_CONVERT))
+       i = 0;
+       if (!sfp->count)
                sfep = NULL;
        else
-               sfep = XFS_DIR2_SF_FIRSTENTRY(sfp);
+               sfep = xfs_dir2_sf_firstentry(sfp);
        /*
         * Need to preserve the existing offset values in the sf directory.
         * Insert holes (unused entries) where necessary.
@@ -1028,58 +1193,62 @@ xfs_dir2_sf_to_block(
                if (sfep == NULL)
                        newoffset = endoffset;
                else
-                       newoffset = XFS_DIR2_SF_GET_OFFSET_ARCH(sfep, ARCH_CONVERT);
+                       newoffset = xfs_dir2_sf_get_offset(sfep);
                /*
                 * There should be a hole here, make one.
                 */
                if (offset < newoffset) {
-                       dup = (xfs_dir2_data_unused_t *)
-                             ((char *)block + offset);
-                       INT_SET(dup->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG);
-                       INT_SET(dup->length, ARCH_CONVERT, newoffset - offset);
-                       INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT), ARCH_CONVERT,
-                               (xfs_dir2_data_off_t)
-                               ((char *)dup - (char *)block));
-                       xfs_dir2_data_log_unused(tp, bp, dup);
-                       (void)xfs_dir2_data_freeinsert((xfs_dir2_data_t *)block,
-                               dup, &dummy);
-                       offset += INT_GET(dup->length, ARCH_CONVERT);
+                       dup = (xfs_dir2_data_unused_t *)((char *)hdr + offset);
+                       dup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
+                       dup->length = cpu_to_be16(newoffset - offset);
+                       *xfs_dir2_data_unused_tag_p(dup) = cpu_to_be16(
+                               ((char *)dup - (char *)hdr));
+                       xfs_dir2_data_log_unused(args, bp, dup);
+                       xfs_dir2_data_freeinsert(hdr,
+                                                dp->d_ops->data_bestfree_p(hdr),
+                                                dup, &dummy);
+                       offset += be16_to_cpu(dup->length);
                        continue;
                }
                /*
                 * Copy a real entry.
                 */
-               dep = (xfs_dir2_data_entry_t *)((char *)block + newoffset);
-               INT_SET(dep->inumber, ARCH_CONVERT, XFS_DIR2_SF_GET_INUMBER_ARCH(sfp,
-                               XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT));
+               dep = (xfs_dir2_data_entry_t *)((char *)hdr + newoffset);
+               dep->inumber = cpu_to_be64(dp->d_ops->sf_get_ino(sfp, sfep));
                dep->namelen = sfep->namelen;
+               dp->d_ops->data_put_ftype(dep, dp->d_ops->sf_get_ftype(sfep));
                memcpy(dep->name, sfep->name, dep->namelen);
-               tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
-               INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)block));
-               xfs_dir2_data_log_entry(tp, bp, dep);
-               INT_SET(blp[2 + i].hashval, ARCH_CONVERT, xfs_da_hashname((char *)sfep->name, sfep->namelen));
-               INT_SET(blp[2 + i].address, ARCH_CONVERT, XFS_DIR2_BYTE_TO_DATAPTR(mp,
-                                                (char *)dep - (char *)block));
-               offset = (int)((char *)(tagp + 1) - (char *)block);
-               if (++i == INT_GET(sfp->hdr.count, ARCH_CONVERT))
+               tagp = dp->d_ops->data_entry_tag_p(dep);
+               *tagp = cpu_to_be16((char *)dep - (char *)hdr);
+               xfs_dir2_data_log_entry(args, bp, dep);
+               name.name = sfep->name;
+               name.len = sfep->namelen;
+               blp[2 + i].hashval = cpu_to_be32(mp->m_dirnameops->
+                                                       hashname(&name));
+               blp[2 + i].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(
+                                                (char *)dep - (char *)hdr));
+               offset = (int)((char *)(tagp + 1) - (char *)hdr);
+               if (++i == sfp->count)
                        sfep = NULL;
                else
-                       sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep);
+                       sfep = dp->d_ops->sf_nextentry(sfp, sfep);
        }
        /* Done with the temporary buffer */
-       kmem_free(buf, buf_len);
+       kmem_free(sfp);
        /*
         * Sort the leaf entries by hash value.
         */
-       qsort(blp, INT_GET(btp->count, ARCH_CONVERT), sizeof(*blp), xfs_dir2_block_sort);
+       xfs_sort(blp, be32_to_cpu(btp->count), sizeof(*blp), xfs_dir2_block_sort);
        /*
         * Log the leaf entry area and tail.
         * Already logged the header in data_init, ignore needlog.
         */
        ASSERT(needscan == 0);
-       xfs_dir2_block_log_leaf(tp, bp, 0, INT_GET(btp->count, ARCH_CONVERT) - 1);
+       xfs_dir2_block_log_leaf(tp, bp, 0, be32_to_cpu(btp->count) - 1);
        xfs_dir2_block_log_tail(tp, bp);
-       xfs_dir2_data_check(dp, bp);
-       xfs_da_buf_done(bp);
+       xfs_dir3_data_check(dp, bp);
        return 0;
+out_free:
+       kmem_free(sfp);
+       return error;
 }