]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blobdiff - repair/attr_repair.c
libxfs: refactor manage_zones()
[thirdparty/xfsprogs-dev.git] / repair / attr_repair.c
index 3fd25286e473bb186cccf731e615ccb105b57138..5ad81c091ea4d3317d1288ee07166ea6e700a52b 100644 (file)
+// SPDX-License-Identifier: GPL-2.0
 /*
- * Copyright (c) 2000 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-2002,2004-2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
  */
 
-#include <libxfs.h>
-#include <errno.h>
-
+#include "libxfs.h"
 #include "globals.h"
 #include "err_protos.h"
 #include "attr_repair.h"
-#include "dir.h"
 #include "dinode.h"
 #include "bmap.h"
+#include "protos.h"
+#include "dir2.h"
+#include "da_util.h"
+
+static int xfs_acl_valid(struct xfs_mount *mp, struct xfs_acl *daclp);
+static int xfs_mac_valid(xfs_mac_label_t *lp);
 
-static int acl_valid(struct acl *aclp);
-static int mac_valid(mac_t lp);
+/*
+ * da node check/verify functions that the attribute tree relies on are first in
+ * the file before the actual attribute code. This used to be shared with the
+ * dir v1 code, but that format is no longer supported yb the userspace
+ * utilities and hence is now specific to the attribute tree implementation.
+ */
 
+typedef unsigned char  da_freemap_t;
 
 /*
- * For attribute repair, there are 3 formats to worry about. First, is 
+ * Allocate a freespace map for directory or attr leaf blocks (1 bit per byte)
+ * 1 == used, 0 == free.
+ */
+static da_freemap_t *
+alloc_da_freemap(struct xfs_mount *mp)
+{
+       return calloc(1, mp->m_sb.sb_blocksize / NBBY);
+}
+
+/*
+ * Set the he range [start, stop) in the directory freemap.
+ *
+ * Returns 1 if there is a conflict or 0 if everything's good.
+ *
+ * Within a char, the lowest bit of the char represents the byte with
+ * the smallest address
+ */
+static int
+set_da_freemap(xfs_mount_t *mp, da_freemap_t *map, int start, int stop)
+{
+       const da_freemap_t mask = 0x1;
+       int i;
+
+       if (start > stop)  {
+               /*
+                * allow == relation since [x, x) claims 1 byte
+                */
+               do_warn(_("bad range claimed [%d, %d) in da block\n"),
+                       start, stop);
+               return(1);
+       }
+
+       if (stop > mp->m_sb.sb_blocksize)  {
+               do_warn(
+       _("byte range end [%d %d) in da block larger than blocksize %d\n"),
+                       start, stop, mp->m_sb.sb_blocksize);
+               return(1);
+       }
+
+       for (i = start; i < stop; i ++)  {
+               if (map[i / NBBY] & (mask << i % NBBY))  {
+                       do_warn(_("multiply claimed byte %d in da block\n"), i);
+                       return(1);
+               }
+               map[i / NBBY] |= (mask << i % NBBY);
+       }
+
+       return(0);
+}
+
+/*
+ * For attribute repair, there are 3 formats to worry about. First, is
  * shortform attributes which reside in the inode. Second is the leaf
  * form, and lastly the btree. Much of this models after the directory
- * structure so code resembles the directory repair cases. 
+ * structure so code resembles the directory repair cases.
  * For shortform case, if an attribute looks corrupt, it is removed.
- * If that leaves the shortform down to 0 attributes, it's okay and 
+ * If that leaves the shortform down to 0 attributes, it's okay and
  * will appear to just have a null attribute fork. Some checks are done
  * for validity of the value field based on what the security needs are.
- * Calls will be made out to mac_valid or acl_valid libc libraries if
- * the security attributes exist. They will be cleared if invalid. No
- * other values will be checked. The DMF folks do not have current
+ * Calls will be made to xfs_mac_valid or xfs_acl_valid routines if the
+ * security attributes exist. They will be cleared if invalid.
+ * No other values will be checked. The DMF folks do not have current
  * requirements, but may in the future.
  *
  * For leaf block attributes, it requires more processing. One sticky
- * point is that the attributes can be local (within the leaf) or 
+ * point is that the attributes can be local (within the leaf) or
  * remote (outside the leaf in other blocks). Thinking of local only
- * if you get a bad attribute, and want to delete just one, its a-okay
+ * if you get a bad attribute, and want to delete just one, it's a-okay
  * if it remains large enough to still be a leaf block attribute. Otherwise,
  * it may have to be converted to shortform. How to convert this and when
  * is an issue. This call is happening in Phase3. Phase5 will capture empty
- * blocks, but Phase6 allows you to use the simulation library which knows
+ * blocks, but Phase6 allows you to use the libxfs library which knows
  * how to handle attributes in the kernel for converting formats. What we
  * could do is mark an attribute to be cleared now, but in phase6 somehow
  * have it cleared for real and then the format changed to shortform if
@@ -74,7 +107,7 @@ static int mac_valid(mac_t lp);
  * attribute in the leaf block will make the entire attribute fork be
  * cleared. The simplest way to do that is to ignore the leaf format, and
  * call clear_dinode_attr to just make a shortform attribute fork with
- * zero entries. 
+ * zero entries.
  *
  * Another issue with handling repair on leaf attributes is the remote
  * blocks. To make sure that they look good and are not used multiple times
@@ -89,47 +122,66 @@ static int mac_valid(mac_t lp);
  * fork being emptied and put in shortform format.
  */
 
+static int
+attr_namecheck(
+       uint8_t *name,
+       int     length)
+{
+       return namecheck((char *)name, length, false);
+}
+
 /*
  * This routine just checks what security needs are for attribute values
  * only called when root flag is set, otherwise these names could exist in
  * in user attribute land without a conflict.
  * If value is non-zero, then a remote attribute is being passed in
  */
-
-int
-valuecheck(char *namevalue, char *value, int namelen, int valuelen)
+static int
+valuecheck(
+       struct xfs_mount *mp,
+       char            *namevalue,
+       char            *value,
+       int             namelen,
+       int             valuelen)
 {
-       /* for proper alignment issues, get the structs and bcopy the values */
-       mac_label macl;
-       struct acl thisacl;
+       /* for proper alignment issues, get the structs and memmove the values */
+       xfs_mac_label_t macl;
        void *valuep;
        int clearit = 0;
 
-       if ((strncmp(namevalue, SGI_ACL_FILE, SGI_ACL_FILE_SIZE) == 0) || 
-                       (strncmp(namevalue, SGI_ACL_DEFAULT, 
-                               SGI_ACL_DEFAULT_SIZE) == 0)) {
-               if (value == NULL) {    
-                       bzero(&thisacl, sizeof(struct acl));
-                       bcopy(namevalue+namelen, &thisacl, valuelen);
-                       valuep = &thisacl;
+       if ((namelen == SGI_ACL_FILE_SIZE &&
+            strncmp(namevalue, SGI_ACL_FILE, SGI_ACL_FILE_SIZE) == 0) ||
+           (namelen == SGI_ACL_DEFAULT_SIZE &&
+            strncmp(namevalue, SGI_ACL_DEFAULT, SGI_ACL_DEFAULT_SIZE) == 0)) {
+               if (value == NULL) {
+                       valuep = malloc(valuelen);
+                       if (!valuep)
+                               do_error(_("No memory for ACL check!\n"));
+                       memcpy(valuep, namevalue + namelen, valuelen);
                } else
                        valuep = value;
 
-               if (acl_valid((struct acl *) valuep) != 0) { /* 0 means valid */
+               if (xfs_acl_valid(mp, valuep) != 0) {
                        clearit = 1;
-                       do_warn("entry contains illegal value in attribute named SGI_ACL_FILE or SGI_ACL_DEFAULT\n");
+                       do_warn(
+       _("entry contains illegal value in attribute named SGI_ACL_FILE "
+         "or SGI_ACL_DEFAULT\n"));
                }
+
+               if (valuep != value)
+                       free(valuep);
+
        } else if (strncmp(namevalue, SGI_MAC_FILE, SGI_MAC_FILE_SIZE) == 0) {
                if (value == NULL) {
-                       bzero(&macl, sizeof(mac_label));
-                       bcopy(namevalue+namelen, &macl, valuelen);
+                       memset(&macl, 0, sizeof(xfs_mac_label_t));
+                       memmove(&macl, namevalue+namelen, valuelen);
                        valuep = &macl;
-               } else 
+               } else
                        valuep = value;
 
-               if (mac_valid((mac_label *) valuep) != 1) { /* 1 means valid */
+               if (xfs_mac_valid((xfs_mac_label_t *)valuep) != 1) { /* 1 is valid */
                         /*
-                        *if sysconf says MAC enabled, 
+                        * if sysconf says MAC enabled,
                         *      temp = mac_from_text("msenhigh/mintlow", NULL)
                         *      copy it to value, update valuelen, totsize
                         *      This causes pushing up or down of all following
@@ -137,12 +189,14 @@ valuecheck(char *namevalue, char *value, int namelen, int valuelen)
                         * else clearit = 1;
                         */
                        clearit = 1;
-                       do_warn("entry contains illegal value in attribute named SGI_MAC_LABEL\n");
+                       do_warn(
+       _("entry contains illegal value in attribute named SGI_MAC_LABEL\n"));
                }
        } else if (strncmp(namevalue, SGI_CAP_FILE, SGI_CAP_FILE_SIZE) == 0) {
-               if ( valuelen != sizeof(cap_set_t)) {
+               if ( valuelen != sizeof(xfs_cap_set_t)) {
                        clearit = 1;
-                       do_warn("entry contains illegal value in attribute named SGI_CAP_FILE\n");
+                       do_warn(
+       _("entry contains illegal value in attribute named SGI_CAP_FILE\n"));
                }
        }
 
@@ -157,61 +211,68 @@ valuecheck(char *namevalue, char *value, int namelen, int valuelen)
  * if you cannot modify the structures. repair is set to 1, if anything
  * was fixed.
  */
-int
+static int
 process_shortform_attr(
+       struct xfs_mount *mp,
        xfs_ino_t       ino,
        xfs_dinode_t    *dip,
-       int             *repair)        
+       int             *repair)
 {
        xfs_attr_shortform_t    *asf;
        xfs_attr_sf_entry_t     *currententry, *nextentry, *tempentry;
        int                     i, junkit;
        int                     currentsize, remainingspace;
-       
+
        *repair = 0;
 
-       asf = (xfs_attr_shortform_t *) XFS_DFORK_APTR_ARCH(dip, ARCH_CONVERT);
+       asf = (xfs_attr_shortform_t *) XFS_DFORK_APTR(dip);
 
        /* Assumption: hdr.totsize is less than a leaf block and was checked
-        * by lclinode for valid sizes. Check the count though. 
+        * by lclinode for valid sizes. Check the count though.
        */
-       if (INT_GET(asf->hdr.count, ARCH_CONVERT) == 0) 
+       if (asf->hdr.count == 0)
                /* then the total size should just be the header length */
-               if (INT_GET(asf->hdr.totsize, ARCH_CONVERT) != sizeof(xfs_attr_sf_hdr_t)) {
+               if (be16_to_cpu(asf->hdr.totsize) != sizeof(xfs_attr_sf_hdr_t)) {
                        /* whoops there's a discrepancy. Clear the hdr */
                        if (!no_modify) {
-                               do_warn("there are no attributes in the fork for inode %llu \n", ino);
-                               INT_SET(asf->hdr.totsize, ARCH_CONVERT,
-                                               sizeof(xfs_attr_sf_hdr_t));
+                               do_warn(
+       _("there are no attributes in the fork for inode %" PRIu64 "\n"),
+                                       ino);
+                               asf->hdr.totsize =
+                                       cpu_to_be16(sizeof(xfs_attr_sf_hdr_t));
                                *repair = 1;
-                               return(1);      
+                               return(1);
                        } else {
-                               do_warn("would junk the attribute fork since the count is 0 for inode %llu\n",ino);
+                               do_warn(
+       _("would junk the attribute fork since count is 0 for inode %" PRIu64 "\n"),
+                                       ino);
                                return(1);
                        }
-                }
-               
-       currentsize = sizeof(xfs_attr_sf_hdr_t); 
-       remainingspace = INT_GET(asf->hdr.totsize, ARCH_CONVERT) - currentsize;
+               }
+
+       currentsize = sizeof(xfs_attr_sf_hdr_t);
+       remainingspace = be16_to_cpu(asf->hdr.totsize) - currentsize;
        nextentry = &asf->list[0];
-       for (i = 0; i < INT_GET(asf->hdr.count, ARCH_CONVERT); i++)  {
+       for (i = 0; i < asf->hdr.count; i++)  {
                currententry = nextentry;
                junkit = 0;
 
                /* don't go off the end if the hdr.count was off */
-               if ((currentsize + (sizeof(xfs_attr_sf_entry_t) - 1)) > 
-                               INT_GET(asf->hdr.totsize, ARCH_CONVERT))
+               if ((currentsize + (sizeof(xfs_attr_sf_entry_t) - 1)) >
+                                               be16_to_cpu(asf->hdr.totsize))
                        break; /* get out and reset count and totSize */
 
                /* if the namelen is 0, can't get to the rest of the entries */
-               if (INT_GET(currententry->namelen, ARCH_CONVERT) == 0) {
-                       do_warn("zero length name entry in attribute fork, ");
+               if (currententry->namelen == 0) {
+                       do_warn(_("zero length name entry in attribute fork,"));
                        if (!no_modify) {
-                               do_warn("truncating attributes for inode %llu to %d \n", ino, i);
+                               do_warn(
+       _(" truncating attributes for inode %" PRIu64 " to %d\n"), ino, i);
                                *repair = 1;
-                               break;  /* and then update hdr fields */
+                               break;  /* and then update hdr fields */
                        } else {
-                               do_warn("would truncate attributes for inode %llu to %d \n", ino, i);
+                               do_warn(
+       _(" would truncate attributes for inode %" PRIu64 " to %d\n"), ino, i);
                                break;
                        }
                } else {
@@ -219,90 +280,105 @@ process_shortform_attr(
                         * rough check to make sure we haven't gone outside of
                         * totsize.
                         */
-                       if ((remainingspace < INT_GET(currententry->namelen, ARCH_CONVERT)) ||
-                               ((remainingspace - INT_GET(currententry->namelen, ARCH_CONVERT))
-                                         < INT_GET(currententry->valuelen, ARCH_CONVERT))) {
-                               do_warn("name or value attribute lengths are too large, \n");
+                       if (remainingspace < currententry->namelen ||
+                                       ((remainingspace - currententry->
+                                       namelen) < currententry->valuelen)) {
+                               do_warn(
+       _("name or value attribute lengths are too large,\n"));
                                if (!no_modify) {
-                                       do_warn(" truncating attributes for inode %llu to %d \n", ino, i);
-                                       *repair = 1; 
+                                       do_warn(
+       _(" truncating attributes for inode %" PRIu64 " to %d\n"),
+                                               ino, i);
+                                       *repair = 1;
                                        break; /* and then update hdr fields */
                                } else {
-                                       do_warn(" would truncate attributes for inode %llu to %d \n", ino, i);  
+                                       do_warn(
+       _(" would truncate attributes for inode %" PRIu64 " to %d\n"),
+                                               ino, i);
                                        break;
-                               }       
+                               }
                        }
                }
-       
-               /* namecheck checks for / and null terminated for file names. 
-                * attributes names currently follow the same rules.
-               */
-               if (namecheck((char *)&currententry->nameval[0], 
-                               INT_GET(currententry->namelen, ARCH_CONVERT)))  {
-                       do_warn("entry contains illegal character in shortform attribute name\n");
+
+               /* namecheck checks for null chars in attr names. */
+               if (attr_namecheck(currententry->nameval,
+                                               currententry->namelen)) {
+                       do_warn(
+       _("entry contains illegal character in shortform attribute name\n"));
                        junkit = 1;
                }
 
-               if (INT_GET(currententry->flags, ARCH_CONVERT) & XFS_ATTR_INCOMPLETE) {
-                       do_warn("entry has INCOMPLETE flag on in shortform attribute\n");
+               if (currententry->flags & XFS_ATTR_INCOMPLETE) {
+                       do_warn(
+       _("entry has INCOMPLETE flag on in shortform attribute\n"));
                        junkit = 1;
                }
 
                /* Only check values for root security attributes */
-               if (INT_GET(currententry->flags, ARCH_CONVERT) & XFS_ATTR_ROOT) 
-                      junkit = valuecheck((char *)&currententry->nameval[0], NULL, 
-                               INT_GET(currententry->namelen, ARCH_CONVERT), INT_GET(currententry->valuelen, ARCH_CONVERT));
+               if (currententry->flags & XFS_ATTR_ROOT)
+                      junkit |= valuecheck(mp,
+                                       (char *)&currententry->nameval[0],
+                                       NULL, currententry->namelen,
+                                       currententry->valuelen);
 
-               remainingspace = remainingspace - 
-                               XFS_ATTR_SF_ENTSIZE(currententry);
+               remainingspace = remainingspace -
+                                       XFS_ATTR_SF_ENTSIZE(currententry);
 
                if (junkit) {
                        if (!no_modify) {
                                /* get rid of only this entry */
-                               do_warn("removing attribute entry %d for inode %llu \n", i, ino);
+                               do_warn(
+       _("removing attribute entry %d for inode %" PRIu64 "\n"),
+                                       i, ino);
                                tempentry = (xfs_attr_sf_entry_t *)
-                                       ((__psint_t) currententry +
+                                       ((intptr_t) currententry +
                                         XFS_ATTR_SF_ENTSIZE(currententry));
                                memmove(currententry,tempentry,remainingspace);
-                               INT_MOD(asf->hdr.count, ARCH_CONVERT, -1);
+                               asf->hdr.count -= 1;
                                i--; /* no worries, it will wrap back to 0 */
                                *repair = 1;
                                continue; /* go back up now */
-                       } else { 
-                               do_warn("would remove attribute entry %d for inode %llu \n", i, ino);
-                        }
-                }
+                       } else {
+                               do_warn(
+       _("would remove attribute entry %d for inode %" PRIu64 "\n"),
+                                       i, ino);
+                       }
+               }
 
                /* Let's get ready for the next entry... */
-               nextentry = (xfs_attr_sf_entry_t *)
-                        ((__psint_t) nextentry +
-                        XFS_ATTR_SF_ENTSIZE(currententry));
+               nextentry = (xfs_attr_sf_entry_t *)((intptr_t) nextentry +
+                                       XFS_ATTR_SF_ENTSIZE(currententry));
                currentsize = currentsize + XFS_ATTR_SF_ENTSIZE(currententry);
-       
-               } /* end the loop */
 
-       
-       if (INT_GET(asf->hdr.count, ARCH_CONVERT) != i)  {
+       } /* end the loop */
+
+       if (asf->hdr.count != i)  {
                if (no_modify)  {
-                       do_warn("would have corrected attribute entry count in inode %llu from %d to %d\n",
-                               ino, INT_GET(asf->hdr.count, ARCH_CONVERT), i);
+                       do_warn(
+       _("would have corrected attribute entry count in inode %" PRIu64 " from %d to %d\n"),
+                               ino, asf->hdr.count, i);
                } else  {
-                       do_warn("corrected attribute entry count in inode %llu, was %d, now %d\n",
-                               ino, INT_GET(asf->hdr.count, ARCH_CONVERT), i);
-                       INT_SET(asf->hdr.count, ARCH_CONVERT, i);
+                       do_warn(
+       _("corrected attribute entry count in inode %" PRIu64 ", was %d, now %d\n"),
+                               ino, asf->hdr.count, i);
+                       asf->hdr.count = i;
                        *repair = 1;
                }
        }
-       
+
        /* ASSUMPTION: currentsize <= totsize */
-       if (INT_GET(asf->hdr.totsize, ARCH_CONVERT) != currentsize)  {
+       if (be16_to_cpu(asf->hdr.totsize) != currentsize)  {
                if (no_modify)  {
-                       do_warn("would have corrected attribute totsize in inode %llu from %d to %d\n",
-                               ino, INT_GET(asf->hdr.totsize, ARCH_CONVERT), currentsize);
+                       do_warn(
+       _("would have corrected attribute totsize in inode %" PRIu64 " from %d to %d\n"),
+                               ino, be16_to_cpu(asf->hdr.totsize),
+                               currentsize);
                } else  {
-                       do_warn("corrected attribute entry totsize in inode %llu, was %d, now %d\n",
-                               ino, INT_GET(asf->hdr.totsize, ARCH_CONVERT), currentsize);
-                       INT_SET(asf->hdr.totsize, ARCH_CONVERT, currentsize);
+                       do_warn(
+       _("corrected attribute entry totsize in inode %" PRIu64 ", was %d, now %d\n"),
+                               ino, be16_to_cpu(asf->hdr.totsize),
+                               currentsize);
+                       asf->hdr.totsize = cpu_to_be16(currentsize);
                        *repair = 1;
                }
        }
@@ -319,31 +395,46 @@ static int
 rmtval_get(xfs_mount_t *mp, xfs_ino_t ino, blkmap_t *blkmap,
                xfs_dablk_t blocknum, int valuelen, char* value)
 {
-       xfs_dfsbno_t    bno;
+       xfs_fsblock_t   bno;
        xfs_buf_t       *bp;
        int             clearit = 0, i = 0, length = 0, amountdone = 0;
-       
+       int             hdrsize = 0;
+
+       if (xfs_sb_version_hascrc(&mp->m_sb))
+               hdrsize = sizeof(struct xfs_attr3_rmt_hdr);
+
        /* ASSUMPTION: valuelen is a valid number, so use it for looping */
-       /* Note that valuelen is not a multiple of blocksize */  
+       /* Note that valuelen is not a multiple of blocksize */
        while (amountdone < valuelen) {
                bno = blkmap_get(blkmap, blocknum + i);
-               if (bno == NULLDFSBNO) {
-                       do_warn("remote block for attributes of inode %llu"
-                               " is missing\n", ino);
+               if (bno == NULLFSBLOCK) {
+                       do_warn(
+       _("remote block for attributes of inode %" PRIu64 " is missing\n"), ino);
                        clearit = 1;
                        break;
                }
                bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, bno),
-                               XFS_FSB_TO_BB(mp, 1), 0);
+                                   XFS_FSB_TO_BB(mp, 1), 0,
+                                   &xfs_attr3_rmt_buf_ops);
                if (!bp) {
-                       do_warn("can't read remote block for attributes"
-                               " of inode %llu\n", ino);
+                       do_warn(
+       _("can't read remote block for attributes of inode %" PRIu64 "\n"), ino);
+                       clearit = 1;
+                       break;
+               }
+
+               if (bp->b_error == -EFSBADCRC || bp->b_error == -EFSCORRUPTED) {
+                       do_warn(
+       _("Corrupt remote block for attributes of inode %" PRIu64 "\n"), ino);
+                       libxfs_putbuf(bp);
                        clearit = 1;
                        break;
                }
-               ASSERT(mp->m_sb.sb_blocksize == XFS_BUF_COUNT(bp));
-               length = MIN(XFS_BUF_COUNT(bp), valuelen - amountdone);
-               bcopy(XFS_BUF_PTR(bp), value, length); 
+
+               ASSERT(mp->m_sb.sb_blocksize == bp->b_bcount);
+
+               length = min(bp->b_bcount - hdrsize, valuelen - amountdone);
+               memmove(value, bp->b_addr + hdrsize, length);
                amountdone += length;
                value += length;
                i++;
@@ -352,21 +443,127 @@ rmtval_get(xfs_mount_t *mp, xfs_ino_t ino, blkmap_t *blkmap,
        return (clearit);
 }
 
-/*
- * freespace map for directory and attribute leaf blocks (1 bit per byte)
- * 1 == used, 0 == free
- */
-static da_freemap_t attr_freemap[DA_BMAP_SIZE];
-
 /* The block is read in. The magic number and forward / backward
  * links are checked by the caller process_leaf_attr.
  * If any problems occur the routine returns with non-zero. In
  * this case the next step is to clear the attribute fork, by
  * changing it to shortform and zeroing it out. Forkoff need not
- * be changed. 
+ * be changed.
  */
 
-int
+static int
+process_leaf_attr_local(
+       struct xfs_mount        *mp,
+       xfs_attr_leafblock_t    *leaf,
+       int                     i,
+       xfs_attr_leaf_entry_t   *entry,
+       xfs_dahash_t            last_hashval,
+       xfs_dablk_t             da_bno,
+       xfs_ino_t               ino)
+{
+       xfs_attr_leaf_name_local_t *local;
+
+       local = xfs_attr3_leaf_name_local(leaf, i);
+       if (local->namelen == 0 || attr_namecheck(local->nameval,
+                                                       local->namelen)) {
+               do_warn(
+       _("attribute entry %d in attr block %u, inode %" PRIu64 " has bad name (namelen = %d)\n"),
+                       i, da_bno, ino, local->namelen);
+               return -1;
+       }
+
+       /* Check on the hash value. Checking order of values
+        * is not necessary, since one wrong clears the whole
+        * fork. If the ordering's wrong, it's caught here or
+        * the kernel code has a bug with transaction logging
+        * or attributes itself. Being paranoid, let's check
+        * ordering anyway in case both the name value and the
+        * hashvalue were wrong but matched. Unlikely, however.
+        */
+       if (be32_to_cpu(entry->hashval) != libxfs_da_hashname(
+                               &local->nameval[0], local->namelen) ||
+                               be32_to_cpu(entry->hashval) < last_hashval) {
+               do_warn(
+       _("bad hashvalue for attribute entry %d in attr block %u, inode %" PRIu64 "\n"),
+                       i, da_bno, ino);
+               return -1;
+       }
+
+       /* Only check values for root security attributes */
+       if (entry->flags & XFS_ATTR_ROOT) {
+               if (valuecheck(mp, (char *)&local->nameval[0], NULL,
+                               local->namelen, be16_to_cpu(local->valuelen))) {
+                       do_warn(
+       _("bad security value for attribute entry %d in attr block %u, inode %" PRIu64 "\n"),
+                               i, da_bno, ino);
+                       return -1;
+               }
+       }
+       return xfs_attr_leaf_entsize_local(local->namelen,
+                                               be16_to_cpu(local->valuelen));
+}
+
+static int
+process_leaf_attr_remote(
+       xfs_attr_leafblock_t    *leaf,
+       int                     i,
+       xfs_attr_leaf_entry_t   *entry,
+       xfs_dahash_t            last_hashval,
+       xfs_dablk_t             da_bno,
+       xfs_ino_t               ino,
+       xfs_mount_t             *mp,
+       blkmap_t                *blkmap)
+{
+       xfs_attr_leaf_name_remote_t *remotep;
+       char*                   value;
+
+       remotep = xfs_attr3_leaf_name_remote(leaf, i);
+
+       if (remotep->namelen == 0 || attr_namecheck(remotep->name,
+                                               remotep->namelen) ||
+                       be32_to_cpu(entry->hashval) !=
+                               libxfs_da_hashname((unsigned char *)&remotep->name[0],
+                                               remotep->namelen) ||
+                       be32_to_cpu(entry->hashval) < last_hashval ||
+                       be32_to_cpu(remotep->valueblk) == 0) {
+               do_warn(
+       _("inconsistent remote attribute entry %d in attr block %u, ino %" PRIu64 "\n"), i, da_bno, ino);
+               return -1;
+       }
+
+       value = malloc(be32_to_cpu(remotep->valuelen));
+       if (value == NULL) {
+               do_warn(
+       _("cannot malloc enough for remotevalue attribute for inode %" PRIu64 "\n"),
+                       ino);
+               do_warn(_("SKIPPING this remote attribute\n"));
+               goto out;
+       }
+       if (rmtval_get(mp, ino, blkmap, be32_to_cpu(remotep->valueblk),
+                               be32_to_cpu(remotep->valuelen), value)) {
+               do_warn(
+       _("remote attribute get failed for entry %d, inode %" PRIu64 "\n"),
+                       i, ino);
+               goto bad_free_out;
+       }
+       if ((entry->flags & XFS_ATTR_ROOT) &&
+           valuecheck(mp, (char *)&remotep->name[0], value, remotep->namelen,
+                               be32_to_cpu(remotep->valuelen))) {
+               do_warn(
+       _("remote attribute value check failed for entry %d, inode %" PRIu64 "\n"),
+                       i, ino);
+               goto bad_free_out;
+       }
+       free(value);
+out:
+       return xfs_attr_leaf_entsize_remote(remotep->namelen);
+
+bad_free_out:
+       free(value);
+       return -1;
+}
+
+static int
 process_leaf_attr_block(
        xfs_mount_t     *mp,
        xfs_attr_leafblock_t *leaf,
@@ -375,169 +572,89 @@ process_leaf_attr_block(
        blkmap_t        *blkmap,
        xfs_dahash_t    last_hashval,
        xfs_dahash_t    *current_hashval,
-       int             *repair)        
+       int             *repair)
 {
        xfs_attr_leaf_entry_t *entry;
-       xfs_attr_leaf_name_local_t *local;
-       xfs_attr_leaf_name_remote_t *remotep;
        int  i, start, stop, clearit, usedbs, firstb, thissize;
+       da_freemap_t *attr_freemap;
+       struct xfs_attr3_icleaf_hdr leafhdr;
 
+       xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);
        clearit = usedbs = 0;
-       *repair = 0;
-       firstb = mp->m_sb.sb_blocksize; 
-       stop = sizeof(xfs_attr_leaf_hdr_t);
+       firstb = mp->m_sb.sb_blocksize;
+       stop = xfs_attr3_leaf_hdr_size(leaf);
 
        /* does the count look sorta valid? */
-       if (INT_GET(leaf->hdr.count, ARCH_CONVERT)
-                               * sizeof(xfs_attr_leaf_entry_t)
-                               + sizeof(xfs_attr_leaf_hdr_t)
-                                                       > XFS_LBSIZE(mp)) {
-               do_warn("bad attribute count %d in attr block %u, inode %llu\n",
-                       (int) INT_GET(leaf->hdr.count, ARCH_CONVERT),
-                                               da_bno, ino);
-               return (1);
+       if (!leafhdr.count ||
+           leafhdr.count * sizeof(xfs_attr_leaf_entry_t) + stop >
+                                               mp->m_sb.sb_blocksize) {
+               do_warn(
+       _("bad attribute count %d in attr block %u, inode %" PRIu64 "\n"),
+                       leafhdr.count, da_bno, ino);
+               return 1;
        }
-       init_da_freemap(attr_freemap);
+
+       attr_freemap = alloc_da_freemap(mp);
        (void) set_da_freemap(mp, attr_freemap, 0, stop);
-       
+
        /* go thru each entry checking for problems */
-       for (i = 0, entry = &leaf->entries[0]; 
-                       i < INT_GET(leaf->hdr.count, ARCH_CONVERT);
-                                               i++, entry++) {
-       
+       for (i = 0, entry = xfs_attr3_leaf_entryp(leaf);
+                       i < leafhdr.count; i++, entry++) {
+
                /* check if index is within some boundary. */
-               if (INT_GET(entry->nameidx, ARCH_CONVERT) > XFS_LBSIZE(mp)) {
-                       do_warn("bad attribute nameidx %d in attr block %u, inode %llu\n",
-                               (int)INT_GET(entry->nameidx, ARCH_CONVERT),
-                               da_bno,ino);
+               if (be16_to_cpu(entry->nameidx) > mp->m_sb.sb_blocksize) {
+                       do_warn(
+       _("bad attribute nameidx %d in attr block %u, inode %" PRIu64 "\n"),
+                               be16_to_cpu(entry->nameidx), da_bno, ino);
                        clearit = 1;
                        break;
-                       }
+               }
 
-               if (INT_GET(entry->flags, ARCH_CONVERT) & XFS_ATTR_INCOMPLETE) {
+               if (entry->flags & XFS_ATTR_INCOMPLETE) {
                        /* we are inconsistent state. get rid of us */
-                       do_warn("attribute entry #%d in attr block %u, inode %llu is INCOMPLETE\n",
+                       do_warn(
+       _("attribute entry #%d in attr block %u, inode %" PRIu64 " is INCOMPLETE\n"),
                                i, da_bno, ino);
                        clearit = 1;
                        break;
-                       }
+               }
 
                /* mark the entry used */
-               start = (__psint_t)&leaf->entries[i] - (__psint_t)leaf;
+               start = (intptr_t)entry - (intptr_t)leaf;
                stop = start + sizeof(xfs_attr_leaf_entry_t);
                if (set_da_freemap(mp, attr_freemap, start, stop))  {
-                       do_warn("attribute entry %d in attr block %u, inode %llu claims already used space\n",
-                               i,da_bno,ino);
+                       do_warn(
+       _("attribute entry %d in attr block %u, inode %" PRIu64 " claims already used space\n"),
+                               i, da_bno, ino);
                        clearit = 1;
                        break;  /* got an overlap */
-                       }
-
-               if (INT_GET(entry->flags, ARCH_CONVERT) & XFS_ATTR_LOCAL) {
-
-                       local = XFS_ATTR_LEAF_NAME_LOCAL(leaf, i);      
-                       if ((INT_GET(local->namelen, ARCH_CONVERT) == 0) || 
-                                       (namecheck((char *)&local->nameval[0], 
-                                               INT_GET(local->namelen, ARCH_CONVERT)))) {
-                               do_warn("attribute entry %d in attr block %u, inode %llu has bad name (namelen = %d)\n",
-                                       i, da_bno, ino, (int) INT_GET(local->namelen, ARCH_CONVERT));
-
-                               clearit = 1;
-                               break;
-                               };
-
-                       /* Check on the hash value. Checking ordering of hash values
-                        * is not necessary, since one wrong one clears the whole
-                        * fork. If the ordering's wrong, it's caught here or 
-                        * the kernel code has a bug with transaction logging
-                        * or attributes itself. For paranoia reasons, let's check
-                        * ordering anyway in case both the name value and the 
-                        * hashvalue were wrong but matched. Unlikely, however.
-                       */
-                       if (INT_GET(entry->hashval, ARCH_CONVERT) != 
-                               libxfs_da_hashname((char *)&local->nameval[0],
-                                       INT_GET(local->namelen, ARCH_CONVERT)) ||
-                               (INT_GET(entry->hashval, ARCH_CONVERT)
-                                                       < last_hashval)) {
-                               do_warn("bad hashvalue for attribute entry %d in attr block %u, inode %llu\n",
-                                       i, da_bno, ino);
-                               clearit = 1;
-                               break;
-                       }
-
-                       /* Only check values for root security attributes */
-                       if (INT_GET(entry->flags, ARCH_CONVERT) & XFS_ATTR_ROOT) 
-                               if (valuecheck((char *)&local->nameval[0], NULL,
-                                           INT_GET(local->namelen, ARCH_CONVERT), INT_GET(local->valuelen, ARCH_CONVERT))) {
-                                       do_warn("bad security value for attribute entry %d in attr block %u, inode %llu\n",
-                                               i,da_bno,ino);
-                                       clearit = 1;
-                                       break;
-                               };
-                       thissize = XFS_ATTR_LEAF_ENTSIZE_LOCAL(
-                                       INT_GET(local->namelen, ARCH_CONVERT), INT_GET(local->valuelen, ARCH_CONVERT));
+               }
 
-               } else {
-                       /* do the remote case */
-                       remotep = XFS_ATTR_LEAF_NAME_REMOTE(leaf, i);
-                       thissize = XFS_ATTR_LEAF_ENTSIZE_REMOTE(
-                                       INT_GET(remotep->namelen, ARCH_CONVERT)); 
-
-                       if ((INT_GET(remotep->namelen, ARCH_CONVERT) == 0) || 
-                                  (namecheck((char *)&remotep->name[0],
-                                       INT_GET(remotep->namelen, ARCH_CONVERT))) ||
-                                  (INT_GET(entry->hashval, ARCH_CONVERT)
-                                               != libxfs_da_hashname(
-                                       (char *)&remotep->name[0],
-                                        INT_GET(remotep->namelen, ARCH_CONVERT))) ||
-                                  (INT_GET(entry->hashval, ARCH_CONVERT)
-                                               < last_hashval) ||
-                                  (INT_GET(remotep->valueblk, ARCH_CONVERT) == 0)) {
-                               do_warn("inconsistent remote attribute entry %d in attr block %u, ino %llu\n",
-                                       i, da_bno, ino);
-                               clearit = 1;
-                               break;
-                       };
-
-                       if (INT_GET(entry->flags, ARCH_CONVERT) & XFS_ATTR_ROOT) {
-                               char*   value;
-                               if ((value = malloc(INT_GET(remotep->valuelen, ARCH_CONVERT)))==NULL){
-                                       do_warn("cannot malloc enough for remotevalue attribute for inode %llu\n",ino);
-                                       do_warn("SKIPPING this remote attribute\n");
-                                       continue;
-                               }
-                               if (rmtval_get(mp, ino, blkmap,
-                                               INT_GET(remotep->valueblk, ARCH_CONVERT),
-                                               INT_GET(remotep->valuelen, ARCH_CONVERT), value)) {
-                                       do_warn("remote attribute get failed for entry %d, inode %llu\n", i,ino);
-                                       clearit = 1;
-                                       free(value);
-                                       break;
-                               }
-                               if (valuecheck((char *)&remotep->name[0], value,
-                                           INT_GET(remotep->namelen, ARCH_CONVERT), INT_GET(remotep->valuelen, ARCH_CONVERT))){
-                                       do_warn("remote attribute value check  failed for entry %d, inode %llu\n", i, ino);
-                                       clearit = 1;
-                                       free(value);
-                                       break;
-                               }
-                               free(value);
-                       }
+               if (entry->flags & XFS_ATTR_LOCAL)
+                       thissize = process_leaf_attr_local(mp, leaf, i, entry,
+                                               last_hashval, da_bno, ino);
+               else
+                       thissize = process_leaf_attr_remote(leaf, i, entry,
+                                               last_hashval, da_bno, ino,
+                                               mp, blkmap);
+               if (thissize < 0) {
+                       clearit = 1;
+                       break;
                }
 
-               *current_hashval = last_hashval 
-                                = INT_GET(entry->hashval, ARCH_CONVERT);
+               *current_hashval = last_hashval = be32_to_cpu(entry->hashval);
 
-               if (set_da_freemap(mp, attr_freemap, INT_GET(entry->nameidx, ARCH_CONVERT),
-                               INT_GET(entry->nameidx, ARCH_CONVERT) + thissize))  {
-                       do_warn("attribute entry %d in attr block %u, inode %llu claims used space\n",
+               if (set_da_freemap(mp, attr_freemap, be16_to_cpu(entry->nameidx),
+                               be16_to_cpu(entry->nameidx) + thissize)) {
+                       do_warn(
+       _("attribute entry %d in attr block %u, inode %" PRIu64 " claims used space\n"),
                                i, da_bno, ino);
                        clearit = 1;
                        break;  /* got an overlap */
-               }                       
+               }
                usedbs += thissize;
-               if (INT_GET(entry->nameidx, ARCH_CONVERT) < firstb) 
-                       firstb = INT_GET(entry->nameidx, ARCH_CONVERT);
+               if (be16_to_cpu(entry->nameidx) < firstb)
+                       firstb = be16_to_cpu(entry->nameidx);
 
        } /* end the loop */
 
@@ -546,40 +663,44 @@ process_leaf_attr_block(
 
                /* if the holes flag is set, don't reset first_used unless it's
                 * pointing to used bytes.  we're being conservative here
-                * since the block will get compacted anyhow by the kernel. 
+                * since the block will get compacted anyhow by the kernel.
                 */
 
-               if (  (INT_GET(leaf->hdr.holes, ARCH_CONVERT) == 0
-                   && firstb != INT_GET(leaf->hdr.firstused, ARCH_CONVERT))
-                   || INT_GET(leaf->hdr.firstused, ARCH_CONVERT) > firstb)  {
+               if ((leafhdr.holes == 0 &&
+                               firstb != leafhdr.firstused) ||
+                               leafhdr.firstused > firstb)  {
                        if (!no_modify)  {
-                               do_warn("- resetting first used heap value from %d to %d in block %u of attribute fork of inode %llu\n",
-                                       (int)INT_GET(leaf->hdr.firstused,
-                                               ARCH_CONVERT), firstb,
-                                               da_bno, ino);
-                               INT_SET(leaf->hdr.firstused,
-                                               ARCH_CONVERT, firstb);
+                               do_warn(
+       _("- resetting first used heap value from %d to %d in "
+         "block %u of attribute fork of inode %" PRIu64 "\n"),
+                                       leafhdr.firstused,
+                                       firstb, da_bno, ino);
+                               leafhdr.firstused = firstb;
                                *repair = 1;
                        } else  {
-                               do_warn("- would reset first used value from %d to %d in block %u of attribute fork of inode %llu\n",
-                                       (int)INT_GET(leaf->hdr.firstused,
-                                               ARCH_CONVERT), firstb,
-                                               da_bno, ino);
+                               do_warn(
+       _("- would reset first used value from %d to %d in "
+         "block %u of attribute fork of inode %" PRIu64 "\n"),
+                                       leafhdr.firstused,
+                                       firstb, da_bno, ino);
                        }
                }
 
-               if (usedbs != INT_GET(leaf->hdr.usedbytes, ARCH_CONVERT))  {
+               if (usedbs != leafhdr.usedbytes)  {
                        if (!no_modify)  {
-                               do_warn("- resetting usedbytes cnt from %d to %d in block %u of attribute fork of inode %llu\n",
-                                       (int)INT_GET(leaf->hdr.usedbytes,
-                                         ARCH_CONVERT), usedbs, da_bno, ino);
-                               INT_SET(leaf->hdr.usedbytes,
-                                               ARCH_CONVERT, usedbs);
+                               do_warn(
+       _("- resetting usedbytes cnt from %d to %d in "
+         "block %u of attribute fork of inode %" PRIu64 "\n"),
+                                       leafhdr.usedbytes,
+                                       usedbs, da_bno, ino);
+                               leafhdr.usedbytes = usedbs;
                                *repair = 1;
                        } else  {
-                               do_warn("- would reset usedbytes cnt from %d to %d in block %u of attribute fork of %llu\n",
-                                       (int)INT_GET(leaf->hdr.usedbytes,
-                                           ARCH_CONVERT), usedbs,da_bno,ino);
+                               do_warn(
+       _("- would reset usedbytes cnt from %d to %d in "
+         "block %u of attribute fork of %" PRIu64 "\n"),
+                                       leafhdr.usedbytes,
+                                       usedbs, da_bno, ino);
                        }
                }
 
@@ -587,9 +708,20 @@ process_leaf_attr_block(
                * checking for holes and compacting if appropiate. I don't think
                * attributes need all that, so let's just leave the holes. If
                * we discover later that this is a good place to do compaction
-               * we can add it then. 
+               * we can add it then.
                */
        }
+       /*
+        * If we're just going to zap the block, don't pretend like we
+        * repaired it, because repairing the block stops the clear
+        * operation.
+        */
+       if (clearit)
+               *repair = 0;
+       if (*repair)
+               xfs_attr3_leaf_hdr_to_disk(mp->m_attr_geo, leaf, &leafhdr);
+
+       free(attr_freemap);
        return (clearit);  /* and repair */
 }
 
@@ -597,7 +729,7 @@ process_leaf_attr_block(
 /*
  * returns 0 if the attribute fork is ok, 1 if it has to be junked.
  */
-int
+static int
 process_leaf_attr_level(xfs_mount_t    *mp,
                        da_bt_cursor_t  *da_cursor)
 {
@@ -605,53 +737,63 @@ process_leaf_attr_level(xfs_mount_t       *mp,
        xfs_attr_leafblock_t    *leaf;
        xfs_buf_t               *bp;
        xfs_ino_t               ino;
-       xfs_dfsbno_t            dev_bno;
+       xfs_fsblock_t           dev_bno;
        xfs_dablk_t             da_bno;
        xfs_dablk_t             prev_bno;
        xfs_dahash_t            current_hashval = 0;
        xfs_dahash_t            greatest_hashval;
+       struct xfs_attr3_icleaf_hdr leafhdr;
 
        da_bno = da_cursor->level[0].bno;
        ino = da_cursor->ino;
+       /*
+        * 0 is the root block and no block
+        * pointer can point to the root block of the btree
+        */
+       if (da_bno == 0) {
+               do_warn(
+       _("btree cycle detected in attribute fork for inode %" PRIu64 "\n"),
+                       ino);
+               goto error_out;
+       }
+
        prev_bno = 0;
 
        do {
                repair = 0;
                dev_bno = blkmap_get(da_cursor->blkmap, da_bno);
-               /*
-                * 0 is the root block and no block
-                * pointer can point to the root block of the btree
-                */
-               ASSERT(da_bno != 0);
-
-               if (dev_bno == NULLDFSBNO) {
-                       do_warn("can't map block %u for attribute fork "
-                               "for inode %llu\n", da_bno, ino);
-                       goto error_out; 
+               if (dev_bno == NULLFSBLOCK) {
+                       do_warn(
+       _("can't map block %u for attribute fork for inode %" PRIu64 "\n"),
+                               da_bno, ino);
+                       goto error_out;
                }
 
                bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, dev_bno),
-                                       XFS_FSB_TO_BB(mp, 1), 0);
+                                   XFS_FSB_TO_BB(mp, 1), 0,
+                                   &xfs_attr3_leaf_buf_ops);
                if (!bp) {
-                       do_warn("can't read file block %u (fsbno %llu) for"
-                               " attribute fork of inode %llu\n",
+                       do_warn(
+       _("can't read file block %u (fsbno %" PRIu64 ") for attribute fork of inode %" PRIu64 "\n"),
                                da_bno, dev_bno, ino);
                        goto error_out;
                }
 
-               leaf = (xfs_attr_leafblock_t *)XFS_BUF_PTR(bp);
+               leaf = bp->b_addr;
+               xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);
 
                /* check magic number for leaf directory btree block */
-               if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
-                                               != XFS_ATTR_LEAF_MAGIC) {
-                       do_warn("bad attribute leaf magic %#x for inode %llu\n",
-                                leaf->hdr.info.magic, ino);
+               if (!(leafhdr.magic == XFS_ATTR_LEAF_MAGIC ||
+                     leafhdr.magic == XFS_ATTR3_LEAF_MAGIC)) {
+                       do_warn(
+       _("bad attribute leaf magic %#x for inode %" PRIu64 "\n"),
+                                leafhdr.magic, ino);
                        libxfs_putbuf(bp);
                        goto error_out;
                }
 
                /*
-                * for each block, process the block, verify it's path,
+                * for each block, process the block, verify its path,
                 * then get next block.  update cursor values along the way
                 */
                if (process_leaf_attr_block(mp, leaf, da_bno, ino,
@@ -670,40 +812,47 @@ process_leaf_attr_level(xfs_mount_t       *mp,
                da_cursor->level[0].hashval = greatest_hashval;
                da_cursor->level[0].bp = bp;
                da_cursor->level[0].bno = da_bno;
-               da_cursor->level[0].index
-                               = INT_GET(leaf->hdr.count, ARCH_CONVERT);
-               da_cursor->level[0].dirty = repair; 
+               da_cursor->level[0].index = leafhdr.count;
+               da_cursor->level[0].dirty = repair;
 
-               if (INT_GET(leaf->hdr.info.back, ARCH_CONVERT) != prev_bno)  {
-                       do_warn("bad sibling back pointer for block %u in "
-                               "attribute fork for inode %llu\n", da_bno, ino);
+               if (leafhdr.back != prev_bno)  {
+                       do_warn(
+       _("bad sibling back pointer for block %u in attribute fork for inode %" PRIu64 "\n"),
+                               da_bno, ino);
                        libxfs_putbuf(bp);
                        goto error_out;
                }
 
                prev_bno = da_bno;
-               da_bno = INT_GET(leaf->hdr.info.forw, ARCH_CONVERT);
+               da_bno = leafhdr.forw;
 
-               if (da_bno != 0 && verify_da_path(mp, da_cursor, 0))  {
-                       libxfs_putbuf(bp);
-                       goto error_out;
+               if (da_bno != 0) {
+                       if (verify_da_path(mp, da_cursor, 0, XFS_ATTR_FORK)) {
+                               libxfs_putbuf(bp);
+                               goto error_out;
+                       }
                }
 
                current_hashval = greatest_hashval;
+                /*
+                * If block looks ok but CRC didn't match, make sure to
+                * recompute it.
+                */
+               if (!no_modify && bp->b_error == -EFSBADCRC)
+                       repair++;
 
-               if (repair && !no_modify) {
+               if (repair && !no_modify)
                        libxfs_writebuf(bp, 0);
-               }
-               else {
+               else
                        libxfs_putbuf(bp);
-               }
        } while (da_bno != 0);
 
-       if (verify_final_da_path(mp, da_cursor, 0))  {
+       if (verify_final_da_path(mp, da_cursor, 0, XFS_ATTR_FORK))  {
                /*
                 * verify the final path up (right-hand-side) if still ok
                 */
-               do_warn("bad hash path in attribute fork for inode %llu\n",
+               do_warn(
+       _("bad hash path in attribute fork for inode %" PRIu64 "\n"),
                        da_cursor->ino);
                goto error_out;
        }
@@ -725,11 +874,11 @@ error_out:
  * has more than just a block) btree.
  *
  * Note that if we run into any problems, we will trash the attribute fork.
- * 
+ *
  * returns 0 if things are ok, 1 if bad
- * Note this code has been based off process_node_dir. 
+ * Note this code has been based off process_node_dir.
  */
-int
+static int
 process_node_attr(
        xfs_mount_t     *mp,
        xfs_ino_t       ino,
@@ -746,9 +895,8 @@ process_node_attr(
         * the way.  Then walk the leaf blocks left-to-right, calling
         * a parent-verification routine each time we traverse a block.
         */
-       bzero(&da_cursor, sizeof(da_bt_cursor_t));
+       memset(&da_cursor, 0, sizeof(da_bt_cursor_t));
        da_cursor.active = 0;
-       da_cursor.type = 0;
        da_cursor.ino = ino;
        da_cursor.dip = dip;
        da_cursor.greatest_bno = 0;
@@ -758,7 +906,7 @@ process_node_attr(
         * now process interior node. don't have any buffers held in this path.
         */
        error = traverse_int_dablock(mp, &da_cursor, &bno, XFS_ATTR_FORK);
-       if (error == 0) 
+       if (error == 0)
                return(1);  /* 0 means unsuccessful */
 
        /*
@@ -766,10 +914,50 @@ process_node_attr(
         * the leaf dir level routine checks the interior paths
         * up to the root including the final right-most path.
         */
-       
+
        return (process_leaf_attr_level(mp, &da_cursor));
 }
 
+/* check v5 metadata */
+static int
+__check_attr_header(
+       struct xfs_mount        *mp,
+       struct xfs_buf          *bp,
+       xfs_ino_t               ino)
+{
+       struct xfs_da3_blkinfo  *info = bp->b_addr;
+
+       if (info->hdr.magic != cpu_to_be16(XFS_ATTR3_LEAF_MAGIC) &&
+           info->hdr.magic != cpu_to_be16(XFS_DA3_NODE_MAGIC))
+               return 0;
+
+       /* verify owner */
+       if (be64_to_cpu(info->owner) != ino) {
+               do_warn(
+_("expected owner inode %" PRIu64 ", got %llu, attr block %" PRIu64 "\n"),
+                       ino, (unsigned long long)be64_to_cpu(info->owner),
+                       bp->b_bn);
+               return 1;
+       }
+       /* verify block number */
+       if (be64_to_cpu(info->blkno) != bp->b_bn) {
+               do_warn(
+_("expected block %" PRIu64 ", got %llu, inode %" PRIu64 "attr block\n"),
+                       bp->b_bn, (unsigned long long)be64_to_cpu(info->blkno),
+                       ino);
+               return 1;
+       }
+       /* verify uuid */
+       if (platform_uuid_compare(&info->uuid, &mp->m_sb.sb_meta_uuid) != 0) {
+               do_warn(
+_("wrong FS UUID, inode %" PRIu64 " attr block %" PRIu64 "\n"),
+                       ino, bp->b_bn);
+               return 1;
+       }
+
+       return 0;
+}
+
 /*
  * Start processing for a leaf or fuller btree.
  * A leaf directory is one where the attribute fork is too big for
@@ -779,8 +967,7 @@ process_node_attr(
  * returns 0 if things are ok, 1 if bad (attributes needs to be junked)
  * repair is set, if anything was changed, but attributes can live thru it
  */
-
-int
+static int
 process_longform_attr(
        xfs_mount_t     *mp,
        xfs_ino_t       ino,
@@ -789,58 +976,71 @@ process_longform_attr(
        int             *repair)        /* out - 1 if something was fixed */
 {
        xfs_attr_leafblock_t    *leaf;
-       xfs_dfsbno_t    bno;
+       xfs_fsblock_t   bno;
        xfs_buf_t       *bp;
        xfs_dahash_t    next_hashval;
        int             repairlinks = 0;
+       struct xfs_attr3_icleaf_hdr leafhdr;
+       int             error;
 
        *repair = 0;
 
        bno = blkmap_get(blkmap, 0);
 
-       if ( bno == NULLDFSBNO ) {
-               if (INT_GET(dip->di_core.di_anextents, ARCH_CONVERT) == 0  &&
-                   dip->di_core.di_aformat == XFS_DINODE_FMT_EXTENTS )
-                       /* it's okay the kernel can handle this state */
-                       return(0);
-               else    {
-                       do_warn("block 0 of inode %llu attribute fork"
-                               " is missing\n", ino);
-                       return(1);
-               }
+       if ( bno == NULLFSBLOCK ) {
+               if (dip->di_aformat == XFS_DINODE_FMT_EXTENTS &&
+                               be16_to_cpu(dip->di_anextents) == 0)
+                       return(0); /* the kernel can handle this state */
+               do_warn(
+       _("block 0 of inode %" PRIu64 " attribute fork is missing\n"),
+                       ino);
+               return(1);
        }
        /* FIX FOR bug 653709 -- EKN */
        if (mp->m_sb.sb_agcount < XFS_FSB_TO_AGNO(mp, bno)) {
-               do_warn("agno of attribute fork of inode %llu out of "
-                       "regular partition\n", ino);
+               do_warn(
+       _("agno of attribute fork of inode %" PRIu64 " out of regular partition\n"), ino);
                return(1);
        }
 
        bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, bno),
-                               XFS_FSB_TO_BB(mp, 1), 0);
+                               XFS_FSB_TO_BB(mp, 1), 0, &xfs_da3_node_buf_ops);
        if (!bp) {
-               do_warn("can't read block 0 of inode %llu attribute fork\n",
+               do_warn(
+       _("can't read block 0 of inode %" PRIu64 " attribute fork\n"),
                        ino);
                return(1);
        }
+       if (bp->b_error == -EFSBADCRC)
+               (*repair)++;
+
+       /* is this block sane? */
+       if (__check_attr_header(mp, bp, ino)) {
+               *repair = 0;
+               libxfs_putbuf(bp);
+               return 1;
+       }
 
        /* verify leaf block */
-       leaf = (xfs_attr_leafblock_t *)XFS_BUF_PTR(bp);
+       leaf = bp->b_addr;
+       xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);
 
        /* check sibling pointers in leaf block or root block 0 before
        * we have to release the btree block
        */
-       if (   INT_GET(leaf->hdr.info.forw, ARCH_CONVERT) != 0
-           || INT_GET(leaf->hdr.info.back, ARCH_CONVERT) != 0)  {
+       if (leafhdr.forw != 0 || leafhdr.back != 0)  {
                if (!no_modify)  {
-                       do_warn("clearing forw/back pointers in block 0 "
-                               "for attributes in inode %llu\n", ino);
+                       do_warn(
+       _("clearing forw/back pointers in block 0 for attributes in inode %" PRIu64 "\n"),
+                               ino);
                        repairlinks = 1;
-                       INT_SET(leaf->hdr.info.forw, ARCH_CONVERT, 0);
-                       INT_SET(leaf->hdr.info.back, ARCH_CONVERT, 0);
+                       leafhdr.forw = 0;
+                       leafhdr.back = 0;
+                       xfs_attr3_leaf_hdr_to_disk(mp->m_attr_geo,
+                                                  leaf, &leafhdr);
                } else  {
-                       do_warn("would clear forw/back pointers in block 0 "
-                               "for attributes in inode %llu\n", ino);
+                       do_warn(
+       _("would clear forw/back pointers in block 0 for attributes in inode %" PRIu64 "\n"), ino);
                }
        }
 
@@ -849,33 +1049,41 @@ process_longform_attr(
         * it's possible to have a node or leaf attribute in either an
         * extent format or btree format attribute fork.
         */
-       switch (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)) {
+       switch (leafhdr.magic) {
        case XFS_ATTR_LEAF_MAGIC:       /* leaf-form attribute */
+       case XFS_ATTR3_LEAF_MAGIC:
                if (process_leaf_attr_block(mp, leaf, 0, ino, blkmap,
                                0, &next_hashval, repair)) {
+                       *repair = 0;
                        /* the block is bad.  lose the attribute fork. */
                        libxfs_putbuf(bp);
-                       return(1); 
+                       return(1);
                }
-               *repair = *repair || repairlinks; 
+               *repair = *repair || repairlinks;
                break;
 
        case XFS_DA_NODE_MAGIC:         /* btree-form attribute */
+       case XFS_DA3_NODE_MAGIC:
                /* must do this now, to release block 0 before the traversal */
-               if (repairlinks) {
+               if ((*repair || repairlinks) && !no_modify) {
                        *repair = 1;
                        libxfs_writebuf(bp, 0);
-               } else 
-                       libxfs_putbuf(bp);      
-               return (process_node_attr(mp, ino, dip, blkmap)); /* + repair */
+               } else
+                       libxfs_putbuf(bp);
+               error = process_node_attr(mp, ino, dip, blkmap); /* + repair */
+               if (error)
+                       *repair = 0;
+               return error;
        default:
-               do_warn("bad attribute leaf magic # %#x for dir ino %llu\n", 
-                       INT_GET(leaf->hdr.info.magic, ARCH_CONVERT), ino);
+               do_warn(
+       _("bad attribute leaf magic # %#x for dir ino %" PRIu64 "\n"),
+                       be16_to_cpu(leaf->hdr.info.magic), ino);
                libxfs_putbuf(bp);
+               *repair = 0;
                return(1);
        }
 
-       if (*repair && !no_modify) 
+       if (*repair && !no_modify)
                libxfs_writebuf(bp, 0);
        else
                libxfs_putbuf(bp);
@@ -884,9 +1092,52 @@ process_longform_attr(
 }
 
 
+static int
+xfs_acl_from_disk(
+       struct xfs_mount        *mp,
+       struct xfs_icacl        **aclp,
+       struct xfs_acl          *dacl)
+{
+       struct xfs_icacl        *acl;
+       struct xfs_icacl_entry  *ace;
+       struct xfs_acl_entry    *dace;
+       int                     count;
+       int                     i;
+
+       count = be32_to_cpu(dacl->acl_cnt);
+       if (count > XFS_ACL_MAX_ENTRIES(mp)) {
+               do_warn(_("Too many ACL entries, count %d\n"), count);
+               *aclp = NULL;
+               return EINVAL;
+       }
+
+
+       acl = malloc(sizeof(struct xfs_icacl) +
+                    count * sizeof(struct xfs_icacl_entry));
+       if (!acl) {
+               do_warn(_("cannot malloc enough for ACL attribute\n"));
+               do_warn(_("SKIPPING this ACL\n"));
+               *aclp = NULL;
+               return ENOMEM;
+       }
+
+       acl->acl_cnt = count;
+       for (i = 0; i < count; i++) {
+               ace = &acl->acl_entry[i];
+               dace = &dacl->acl_entry[i];
+
+               ace->ae_tag = be32_to_cpu(dace->ae_tag);
+               ace->ae_id = be32_to_cpu(dace->ae_id);
+               ace->ae_perm = be16_to_cpu(dace->ae_perm);
+       }
+
+       *aclp = acl;
+       return 0;
+}
+
 /*
  * returns 1 if attributes got cleared
- * and 0 if things are ok. 
+ * and 0 if things are ok.
  */
 int
 process_attributes(
@@ -896,54 +1147,62 @@ process_attributes(
        blkmap_t        *blkmap,
        int             *repair)  /* returned if we did repair */
 {
-       int err;
-       xfs_dinode_core_t *dinoc;
-       /* REFERENCED */
+       int             err;
+       __u8            aformat = dip->di_aformat;
+#ifdef DEBUG
        xfs_attr_shortform_t *asf;
 
-       dinoc = &dip->di_core;
-       asf = (xfs_attr_shortform_t *) XFS_DFORK_APTR_ARCH(dip, ARCH_CONVERT);
+       asf = (xfs_attr_shortform_t *) XFS_DFORK_APTR(dip);
+#endif
 
-       if (dinoc->di_aformat == XFS_DINODE_FMT_LOCAL) {
-               ASSERT(INT_GET(asf->hdr.totsize, ARCH_CONVERT) <= XFS_DFORK_ASIZE_ARCH(dip, mp, ARCH_CONVERT));
-               err = process_shortform_attr(ino, dip, repair);
-       } else if (dinoc->di_aformat == XFS_DINODE_FMT_EXTENTS ||
-                  dinoc->di_aformat == XFS_DINODE_FMT_BTREE)  {
+       if (aformat == XFS_DINODE_FMT_LOCAL) {
+               ASSERT(be16_to_cpu(asf->hdr.totsize) <=
+                       XFS_DFORK_ASIZE(dip, mp));
+               err = process_shortform_attr(mp, ino, dip, repair);
+       } else if (aformat == XFS_DINODE_FMT_EXTENTS ||
+                                       aformat == XFS_DINODE_FMT_BTREE)  {
                        err = process_longform_attr(mp, ino, dip, blkmap,
                                repair);
                        /* if err, convert this to shortform and clear it */
                        /* if repair and no error, it's taken care of */
        } else  {
-               do_warn("illegal attribute format %d, ino %llu\n",
-                       dinoc->di_aformat, ino);
-               err = 1; 
+               do_warn(_("illegal attribute format %d, ino %" PRIu64 "\n"),
+                       aformat, ino);
+               err = 1;
        }
        return (err);  /* and repair */
 }
 
-/* 
+/*
  * Validate an ACL
  */
 static int
-acl_valid (struct acl *aclp)
+xfs_acl_valid(
+       struct xfs_mount *mp,
+       struct xfs_acl  *daclp)
 {
-       struct acl_entry *entry, *e;
+       struct xfs_icacl        *aclp = NULL;
+       struct xfs_icacl_entry  *entry, *e;
        int user = 0, group = 0, other = 0, mask = 0, mask_required = 0;
        int i, j;
 
-       if (aclp == NULL)
+       if (daclp == NULL)
                goto acl_invalid;
 
-       if (aclp->acl_cnt > ACL_MAX_ENTRIES)
+       switch (xfs_acl_from_disk(mp, &aclp, daclp)) {
+       case ENOMEM:
+               return 0;
+       case EINVAL:
                goto acl_invalid;
+       default:
+               break;
+       }
 
-       for (i = 0; i < aclp->acl_cnt; i++)
-       {
-
+       for (i = 0; i < aclp->acl_cnt; i++) {
                entry = &aclp->acl_entry[i];
-
-               switch (entry->ae_tag)
-               {
+               if (entry->ae_perm & ~(ACL_READ|ACL_WRITE|ACL_EXECUTE))
+                       goto acl_invalid;
+               switch (entry->ae_tag) {
                        case ACL_USER_OBJ:
                                if (user++)
                                        goto acl_invalid;
@@ -952,16 +1211,16 @@ acl_valid (struct acl *aclp)
                                if (group++)
                                        goto acl_invalid;
                                break;
-                       case ACL_OTHER_OBJ:
+                       case ACL_OTHER:
                                if (other++)
                                        goto acl_invalid;
                                break;
                        case ACL_USER:
                        case ACL_GROUP:
-                               for (j = i + 1; j < aclp->acl_cnt; j++)
-                               {
+                               for (j = i + 1; j < aclp->acl_cnt; j++) {
                                        e = &aclp->acl_entry[j];
-                                       if (e->ae_id == entry->ae_id && e->ae_tag == entry->ae_tag)
+                                       if (e->ae_id == entry->ae_id &&
+                                           e->ae_tag == entry->ae_tag)
                                                goto acl_invalid;
                                }
                                mask_required++;
@@ -976,9 +1235,10 @@ acl_valid (struct acl *aclp)
        }
        if (!user || !group || !other || (mask_required && !mask))
                goto acl_invalid;
-       else
-               return 0;
+       free(aclp);
+       return 0;
 acl_invalid:
+       free(aclp);
        errno = EINVAL;
        return (-1);
 }
@@ -990,21 +1250,20 @@ acl_invalid:
 static int
 __check_setvalue(const unsigned short *list, unsigned short count)
 {
-        unsigned short i;
+       unsigned short i;
 
-        for (i = 1; i < count ; i++)
-                if (list[i] <= list[i-1])
-                        return -1;
-        return 0;
+       for (i = 1; i < count ; i++)
+               if (list[i] <= list[i-1])
+                       return -1;
+       return 0;
 }
 
-
 /*
- * mac_valid(lp)
- * check the validity of a mac label
+ * xfs_mac_valid(lp)
+ * Check the validity of a MAC label.
  */
 static int
-mac_valid(mac_t lp)
+xfs_mac_valid(xfs_mac_label_t *lp)
 {
        if (lp == NULL)
                return (0);
@@ -1013,31 +1272,31 @@ mac_valid(mac_t lp)
         * if the total category set and division set is greater than 250
         * report error
         */
-       if ((lp->ml_catcount + lp->ml_divcount) > MAC_MAX_SETS)
+       if ((lp->ml_catcount + lp->ml_divcount) > XFS_MAC_MAX_SETS)
                return(0);
 
        /*
         * check whether the msentype value is valid, and do they have
-        * appropriate level, category association.
-         */
+        * appropriate level, category association.
+        */
        switch (lp->ml_msen_type) {
-               case MSEN_ADMIN_LABEL:
-               case MSEN_EQUAL_LABEL:
-               case MSEN_HIGH_LABEL:
-               case MSEN_MLD_HIGH_LABEL:
-               case MSEN_LOW_LABEL:
-               case MSEN_MLD_LOW_LABEL:
+               case XFS_MSEN_ADMIN_LABEL:
+               case XFS_MSEN_EQUAL_LABEL:
+               case XFS_MSEN_HIGH_LABEL:
+               case XFS_MSEN_MLD_HIGH_LABEL:
+               case XFS_MSEN_LOW_LABEL:
+               case XFS_MSEN_MLD_LOW_LABEL:
                        if (lp->ml_level != 0 || lp->ml_catcount > 0 )
                                return (0);
                        break;
-               case MSEN_TCSEC_LABEL:
-               case MSEN_MLD_LABEL:
+               case XFS_MSEN_TCSEC_LABEL:
+               case XFS_MSEN_MLD_LABEL:
                        if (lp->ml_catcount > 0 &&
                            __check_setvalue(lp->ml_list,
                                             lp->ml_catcount) == -1)
                                return (0);
                        break;
-               case MSEN_UNKNOWN_LABEL:
+               case XFS_MSEN_UNKNOWN_LABEL:
                default:
                        return (0);
        }
@@ -1047,15 +1306,15 @@ mac_valid(mac_t lp)
         * appropriate grade, division association.
         */
        switch (lp->ml_mint_type) {
-               case MINT_BIBA_LABEL:
+               case XFS_MINT_BIBA_LABEL:
                        if (lp->ml_divcount > 0 &&
                            __check_setvalue(lp->ml_list + lp->ml_catcount,
                                             lp->ml_divcount) == -1)
                                return(0);
                        break;
-               case MINT_EQUAL_LABEL:
-               case MINT_HIGH_LABEL:
-               case MINT_LOW_LABEL:
+               case XFS_MINT_EQUAL_LABEL:
+               case XFS_MINT_HIGH_LABEL:
+               case XFS_MINT_LOW_LABEL:
                        if (lp->ml_grade != 0 || lp->ml_divcount > 0 )
                                return(0);
                        break;