+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2000-2005 Silicon Graphics, Inc.
* All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include <libxfs.h>
+#include "libxfs.h"
#include "avl.h"
#include "globals.h"
#include "agheader.h"
#include "attr_repair.h"
#include "bmap.h"
#include "threads.h"
+#include "slab.h"
+#include "rmap.h"
/*
* gettext lookups for translations of strings use mutexes internally to
return(1);
}
-static int
+static void
clear_dinode_core(struct xfs_mount *mp, xfs_dinode_t *dinoc, xfs_ino_t ino_num)
{
- int dirty = 0;
- int i;
-
-#define __dirty_no_modify_ret(dirty) \
- ({ (dirty) = 1; if (no_modify) return 1; })
-
- if (be16_to_cpu(dinoc->di_magic) != XFS_DINODE_MAGIC) {
- __dirty_no_modify_ret(dirty);
- dinoc->di_magic = cpu_to_be16(XFS_DINODE_MAGIC);
- }
-
- if (!XFS_DINODE_GOOD_VERSION(dinoc->di_version)) {
- __dirty_no_modify_ret(dirty);
- if (xfs_sb_version_hascrc(&mp->m_sb))
- dinoc->di_version = 3;
- else
- dinoc->di_version = 2;
- }
-
- if (be16_to_cpu(dinoc->di_mode) != 0) {
- __dirty_no_modify_ret(dirty);
- dinoc->di_mode = 0;
- }
-
- if (be16_to_cpu(dinoc->di_flags) != 0) {
- __dirty_no_modify_ret(dirty);
- dinoc->di_flags = 0;
- }
-
- if (be32_to_cpu(dinoc->di_dmevmask) != 0) {
- __dirty_no_modify_ret(dirty);
- dinoc->di_dmevmask = 0;
- }
-
- if (dinoc->di_forkoff != 0) {
- __dirty_no_modify_ret(dirty);
- dinoc->di_forkoff = 0;
- }
-
- if (dinoc->di_format != XFS_DINODE_FMT_EXTENTS) {
- __dirty_no_modify_ret(dirty);
- dinoc->di_format = XFS_DINODE_FMT_EXTENTS;
- }
-
- if (dinoc->di_aformat != XFS_DINODE_FMT_EXTENTS) {
- __dirty_no_modify_ret(dirty);
- dinoc->di_aformat = XFS_DINODE_FMT_EXTENTS;
- }
-
- if (be64_to_cpu(dinoc->di_size) != 0) {
- __dirty_no_modify_ret(dirty);
- dinoc->di_size = 0;
- }
-
- if (be64_to_cpu(dinoc->di_nblocks) != 0) {
- __dirty_no_modify_ret(dirty);
- dinoc->di_nblocks = 0;
- }
-
- if (be16_to_cpu(dinoc->di_onlink) != 0) {
- __dirty_no_modify_ret(dirty);
- dinoc->di_onlink = 0;
- }
-
- if (be32_to_cpu(dinoc->di_nextents) != 0) {
- __dirty_no_modify_ret(dirty);
- dinoc->di_nextents = 0;
- }
-
- if (be16_to_cpu(dinoc->di_anextents) != 0) {
- __dirty_no_modify_ret(dirty);
- dinoc->di_anextents = 0;
- }
-
- if (dinoc->di_version > 1 &&
- be32_to_cpu(dinoc->di_nlink) != 0) {
- __dirty_no_modify_ret(dirty);
- dinoc->di_nlink = 0;
- }
-
+ memset(dinoc, 0, sizeof(*dinoc));
+ dinoc->di_magic = cpu_to_be16(XFS_DINODE_MAGIC);
+ if (xfs_sb_version_hascrc(&mp->m_sb))
+ dinoc->di_version = 3;
+ else
+ dinoc->di_version = 2;
+ dinoc->di_gen = cpu_to_be32(random());
+ dinoc->di_format = XFS_DINODE_FMT_EXTENTS;
+ dinoc->di_aformat = XFS_DINODE_FMT_EXTENTS;
/* we are done for version 1/2 inodes */
if (dinoc->di_version < 3)
- return dirty;
-
- if (be64_to_cpu(dinoc->di_ino) != ino_num) {
- __dirty_no_modify_ret(dirty);
- dinoc->di_ino = cpu_to_be64(ino_num);
- }
-
- if (platform_uuid_compare(&dinoc->di_uuid, &mp->m_sb.sb_uuid)) {
- __dirty_no_modify_ret(dirty);
- platform_uuid_copy(&dinoc->di_uuid, &mp->m_sb.sb_uuid);
- }
-
- for (i = 0; i < sizeof(dinoc->di_pad2)/sizeof(dinoc->di_pad2[0]); i++) {
- if (dinoc->di_pad2[i] != 0) {
- __dirty_no_modify_ret(dirty);
- memset(dinoc->di_pad2, 0, sizeof(dinoc->di_pad2));
- break;
- }
- }
-
- if (be64_to_cpu(dinoc->di_flags2) != 0) {
- __dirty_no_modify_ret(dirty);
- dinoc->di_flags2 = 0;
- }
-
- if (be64_to_cpu(dinoc->di_lsn) != 0) {
- __dirty_no_modify_ret(dirty);
- dinoc->di_lsn = 0;
- }
-
- if (be64_to_cpu(dinoc->di_changecount) != 0) {
- __dirty_no_modify_ret(dirty);
- dinoc->di_changecount = 0;
- }
-
- return dirty;
+ return;
+ dinoc->di_ino = cpu_to_be64(ino_num);
+ platform_uuid_copy(&dinoc->di_uuid, &mp->m_sb.sb_meta_uuid);
+ return;
}
-static int
+static void
clear_dinode_unlinked(xfs_mount_t *mp, xfs_dinode_t *dino)
{
- if (be32_to_cpu(dino->di_next_unlinked) != NULLAGINO) {
- if (!no_modify)
- dino->di_next_unlinked = cpu_to_be32(NULLAGINO);
- return(1);
- }
-
- return(0);
+ dino->di_next_unlinked = cpu_to_be32(NULLAGINO);
}
/*
* this clears the unlinked list too so it should not be called
* until after the agi unlinked lists are walked in phase 3.
- * returns > zero if the inode has been altered while being cleared
*/
-static int
+static void
clear_dinode(xfs_mount_t *mp, xfs_dinode_t *dino, xfs_ino_t ino_num)
{
- int dirty;
-
- dirty = clear_dinode_core(mp, dino, ino_num);
- dirty += clear_dinode_unlinked(mp, dino);
+ clear_dinode_core(mp, dino, ino_num);
+ clear_dinode_unlinked(mp, dino);
/* and clear the forks */
-
- if (dirty && !no_modify)
- memset(XFS_DFORK_DPTR(dino), 0,
- XFS_LITINO(mp, dino->di_version));
-
- return(dirty);
+ memset(XFS_DFORK_DPTR(dino), 0, XFS_LITINO(mp, dino->di_version));
+ return;
}
xfs_agnumber_t agno,
xfs_agblock_t agbno)
{
- if (agno < (sbp->sb_agcount - 1))
+ if (agno < (sbp->sb_agcount - 1))
return (agbno >= sbp->sb_agblocks);
- if (agno == (sbp->sb_agcount - 1))
+ if (agno == (sbp->sb_agcount - 1))
return (agbno >= (sbp->sb_dblocks -
- ((xfs_drfsbno_t)(sbp->sb_agcount - 1) *
+ ((xfs_rfsblock_t)(sbp->sb_agcount - 1) *
sbp->sb_agblocks)));
return 1;
}
*/
int
verify_dfsbno(xfs_mount_t *mp,
- xfs_dfsbno_t fsbno)
+ xfs_fsblock_t fsbno)
{
xfs_agnumber_t agno;
xfs_agblock_t agbno;
static __inline int
verify_dfsbno_range(xfs_mount_t *mp,
- xfs_dfsbno_t fsbno,
- xfs_dfilblks_t count)
+ xfs_fsblock_t fsbno,
+ xfs_filblks_t count)
{
xfs_agnumber_t agno;
xfs_agblock_t agbno;
xfs_mount_t *mp,
xfs_bmbt_irec_t *irec,
xfs_ino_t ino,
- xfs_drfsbno_t *tot,
+ xfs_rfsblock_t *tot,
int check_dups)
{
- xfs_dfsbno_t b;
- xfs_drtbno_t ext;
+ xfs_fsblock_t b;
+ xfs_rtblock_t ext;
int state;
int pwe; /* partially-written extent */
return 1;
}
- /*
- * verify that the blocks listed in the record
- * are multiples of an extent
- */
- if (xfs_sb_version_hasextflgbit(&mp->m_sb) == 0 &&
- (irec->br_startblock % mp->m_sb.sb_rextsize != 0 ||
- irec->br_blockcount % mp->m_sb.sb_rextsize != 0)) {
- do_warn(
-_("malformed rt inode extent [%" PRIu64 " %" PRIu64 "] (fs rtext size = %u)\n"),
- irec->br_startblock,
- irec->br_blockcount,
- mp->m_sb.sb_rextsize);
- return 1;
- }
-
/*
* set the appropriate number of extents
* this iterates block by block, this can be optimised using extents
*/
for (b = irec->br_startblock; b < irec->br_startblock +
irec->br_blockcount; b += mp->m_sb.sb_rextsize) {
- ext = (xfs_drtbno_t) b / mp->m_sb.sb_rextsize;
- pwe = xfs_sb_version_hasextflgbit(&mp->m_sb) &&
- irec->br_state == XFS_EXT_UNWRITTEN &&
+ ext = (xfs_rtblock_t) b / mp->m_sb.sb_rextsize;
+ pwe = irec->br_state == XFS_EXT_UNWRITTEN &&
(b % mp->m_sb.sb_rextsize != 0);
if (check_dups == 1) {
case XR_E_INUSE:
if (pwe)
break;
+ /* fall through */
case XR_E_MULT:
set_rtbmap(ext, XR_E_MULT);
do_warn(
int *numrecs,
int type,
xfs_ino_t ino,
- xfs_drfsbno_t *tot,
+ xfs_rfsblock_t *tot,
blkmap_t **blkmapp,
- xfs_dfiloff_t *first_key,
- xfs_dfiloff_t *last_key,
+ xfs_fileoff_t *first_key,
+ xfs_fileoff_t *last_key,
int check_dups,
int whichfork)
{
xfs_bmbt_irec_t irec;
- xfs_dfilblks_t cp = 0; /* prev count */
- xfs_dfsbno_t sp = 0; /* prev start */
- xfs_dfiloff_t op = 0; /* prev offset */
- xfs_dfsbno_t b;
+ xfs_filblks_t cp = 0; /* prev count */
+ xfs_fsblock_t sp = 0; /* prev start */
+ xfs_fileoff_t op = 0; /* prev offset */
+ xfs_fsblock_t b;
char *ftype;
char *forkname = get_forkname(whichfork);
int i;
* checking each entry without setting the
* block bitmap
*/
- if (search_dup_extent(agno, agbno, ebno)) {
+ if (!(type == XR_INO_DATA &&
+ xfs_sb_version_hasreflink(&mp->m_sb)) &&
+ search_dup_extent(agno, agbno, ebno)) {
do_warn(
_("%s fork in ino %" PRIu64 " claims dup extent, "
"off - %" PRIu64 ", start - %" PRIu64 ", cnt %" PRIu64 "\n"),
case XR_E_FREE1:
do_warn(
_("%s fork in ino %" PRIu64 " claims free block %" PRIu64 "\n"),
- forkname, ino, (__uint64_t) b);
+ forkname, ino, (uint64_t) b);
/* fall through ... */
+ case XR_E_INUSE1: /* seen by rmap */
case XR_E_UNKNOWN:
- set_bmap_ext(agno, agbno, blen, XR_E_INUSE);
break;
case XR_E_BAD_STATE:
do_error(_("bad state in block map %" PRIu64 "\n"), b);
+ case XR_E_FS_MAP1:
+ case XR_E_INO1:
+ case XR_E_INUSE_FS1:
+ do_warn(_("rmap claims metadata use!\n"));
+ /* fall through */
case XR_E_FS_MAP:
case XR_E_INO:
case XR_E_INUSE_FS:
+ case XR_E_REFC:
do_warn(
_("%s fork in inode %" PRIu64 " claims metadata block %" PRIu64 "\n"),
forkname, ino, b);
case XR_E_INUSE:
case XR_E_MULT:
- set_bmap_ext(agno, agbno, blen, XR_E_MULT);
+ if (type == XR_INO_DATA &&
+ xfs_sb_version_hasreflink(&mp->m_sb))
+ break;
do_warn(
_("%s fork in %s inode %" PRIu64 " claims used block %" PRIu64 "\n"),
forkname, ftype, ino, b);
goto done;
+ case XR_E_COW:
+ do_warn(
+_("%s fork in %s inode %" PRIu64 " claims CoW block %" PRIu64 "\n"),
+ forkname, ftype, ino, b);
+ goto done;
+
default:
do_error(
_("illegal state %d in block map %" PRIu64 "\n"),
state, b);
+ goto done;
+ }
+ }
+
+ /*
+ * Update the internal extent map only after we've checked
+ * every block in this extent. The first time we reject this
+ * data fork we'll try to rebuild the bmbt from rmap data.
+ * After a successful rebuild we'll try this scan again.
+ * (If the rebuild fails we won't come back here.)
+ */
+ agbno = XFS_FSB_TO_AGBNO(mp, irec.br_startblock);
+ ebno = agbno + irec.br_blockcount;
+ for (; agbno < ebno; agbno += blen) {
+ state = get_bmap_ext(agno, agbno, ebno, &blen);
+ switch (state) {
+ case XR_E_FREE:
+ case XR_E_FREE1:
+ case XR_E_INUSE1:
+ case XR_E_UNKNOWN:
+ set_bmap_ext(agno, agbno, blen, XR_E_INUSE);
+ break;
+ case XR_E_INUSE:
+ case XR_E_MULT:
+ set_bmap_ext(agno, agbno, blen, XR_E_MULT);
+ break;
+ default:
+ break;
}
}
+ if (collect_rmaps) { /* && !check_dups */
+ error = rmap_add_rec(mp, ino, whichfork, &irec);
+ if (error)
+ do_error(
+_("couldn't add reverse mapping\n")
+ );
+ }
*tot += irec.br_blockcount;
}
error = 0;
int *numrecs,
int type,
xfs_ino_t ino,
- xfs_drfsbno_t *tot,
+ xfs_rfsblock_t *tot,
blkmap_t **blkmapp,
- xfs_dfiloff_t *first_key,
- xfs_dfiloff_t *last_key,
+ xfs_fileoff_t *first_key,
+ xfs_fileoff_t *last_key,
int whichfork)
{
return process_bmbt_reclist_int(mp, rp, numrecs, type, ino, tot,
int *numrecs,
int type,
xfs_ino_t ino,
- xfs_drfsbno_t *tot,
+ xfs_rfsblock_t *tot,
int whichfork)
{
- xfs_dfiloff_t first_key = 0;
- xfs_dfiloff_t last_key = 0;
+ xfs_fileoff_t first_key = 0;
+ xfs_fileoff_t last_key = 0;
return process_bmbt_reclist_int(mp, rp, numrecs, type, ino, tot,
NULL, &first_key, &last_key, 1, whichfork);
}
/*
- * these two are meant for routines that read and work with inodes
- * one at a time where the inodes may be in any order (like walking
- * the unlinked lists to look for inodes). the caller is responsible
- * for writing/releasing the buffer.
+ * Grab the buffer backing an inode. This is meant for routines that
+ * work with inodes one at a time in any order (like walking the
+ * unlinked lists to look for inodes). The caller is responsible for
+ * writing/releasing the buffer.
*/
-xfs_buf_t *
-get_agino_buf(xfs_mount_t *mp,
- xfs_agnumber_t agno,
- xfs_agino_t agino,
- xfs_dinode_t **dipp)
+struct xfs_buf *
+get_agino_buf(
+ struct xfs_mount *mp,
+ xfs_agnumber_t agno,
+ xfs_agino_t agino,
+ struct xfs_dinode **dipp)
{
- ino_tree_node_t *irec;
- xfs_buf_t *bp;
- int size;
+ struct xfs_buf *bp;
+ int cluster_size;
+ int ino_per_cluster;
+ xfs_agino_t cluster_agino;
+ xfs_daddr_t cluster_daddr;
+ xfs_daddr_t cluster_blks;
- if ((irec = find_inode_rec(mp, agno, agino)) == NULL)
- return(NULL);
+ /*
+ * Inode buffers have been read into memory in inode_cluster_size
+ * chunks (or one FSB). To find the correct buffer for an inode,
+ * we must find the buffer for its cluster, add the appropriate
+ * offset, and return that.
+ */
+ cluster_size = max(mp->m_inode_cluster_size, mp->m_sb.sb_blocksize);
+ ino_per_cluster = cluster_size / mp->m_sb.sb_inodesize;
+ cluster_agino = agino & ~(ino_per_cluster - 1);
+ cluster_blks = XFS_FSB_TO_DADDR(mp, max(1,
+ mp->m_inode_cluster_size >> mp->m_sb.sb_blocklog));
+ cluster_daddr = XFS_AGB_TO_DADDR(mp, agno,
+ XFS_AGINO_TO_AGBNO(mp, cluster_agino));
- size = XFS_FSB_TO_BB(mp, MAX(1, XFS_INODES_PER_CHUNK/inodes_per_block));
- bp = libxfs_readbuf(mp->m_dev, XFS_AGB_TO_DADDR(mp, agno,
- XFS_AGINO_TO_AGBNO(mp, irec->ino_startnum)), size, 0,
- &xfs_inode_buf_ops);
+#ifdef XR_INODE_TRACE
+ printf("cluster_size %d ipc %d clusagino %d daddr %lld sectors %lld\n",
+ cluster_size, ino_per_cluster, cluster_agino, cluster_daddr,
+ cluster_blks);
+#endif
+
+ bp = libxfs_readbuf(mp->m_dev, cluster_daddr, cluster_blks,
+ 0, &xfs_inode_buf_ops);
if (!bp) {
do_warn(_("cannot read inode (%u/%u), disk block %" PRIu64 "\n"),
- agno, irec->ino_startnum,
- XFS_AGB_TO_DADDR(mp, agno,
- XFS_AGINO_TO_AGBNO(mp, irec->ino_startnum)));
- return(NULL);
+ agno, cluster_agino, cluster_daddr);
+ return NULL;
}
- *dipp = xfs_make_iptr(mp, bp, agino -
- XFS_OFFBNO_TO_AGINO(mp, XFS_AGINO_TO_AGBNO(mp,
- irec->ino_startnum),
- 0));
-
- return(bp);
+ *dipp = xfs_make_iptr(mp, bp, agino - cluster_agino);
+ ASSERT(!xfs_sb_version_hascrc(&mp->m_sb) ||
+ XFS_AGINO_TO_INO(mp, agno, agino) ==
+ be64_to_cpu((*dipp)->di_ino));
+ return bp;
}
/*
xfs_dinode_t *dip,
int type,
int *dirty,
- xfs_drfsbno_t *tot,
- __uint64_t *nex,
+ xfs_rfsblock_t *tot,
+ uint64_t *nex,
blkmap_t **blkmapp,
int whichfork,
int check_dups)
{
xfs_bmdr_block_t *dib;
- xfs_dfiloff_t last_key;
- xfs_dfiloff_t first_key = 0;
+ xfs_fileoff_t last_key;
+ xfs_fileoff_t first_key = 0;
xfs_ino_t lino;
xfs_bmbt_ptr_t *pp;
xfs_bmbt_key_t *pkey;
int level;
int numrecs;
bmap_cursor_t cursor;
- __uint64_t magic;
+ uint64_t magic;
dib = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork);
lino = XFS_AGINO_TO_INO(mp, agno, ino);
init_bm_cursor(&cursor, level + 1);
pp = XFS_BMDR_PTR_ADDR(dib, 1,
- xfs_bmdr_maxrecs(XFS_DFORK_SIZE(dip, mp, whichfork), 0));
+ libxfs_bmdr_maxrecs(XFS_DFORK_SIZE(dip, mp, whichfork), 0));
pkey = XFS_BMDR_KEY_ADDR(dib, 1);
- last_key = NULLDFILOFF;
+ last_key = NULLFILEOFF;
for (i = 0; i < numrecs; i++) {
/*
* btree, we'd do it right here. For now, if there's a
* problem, we'll bail out and presumably clear the inode.
*/
- if (!verify_dfsbno(mp, be64_to_cpu(pp[i]))) {
- do_warn(_("bad bmap btree ptr 0x%llx in ino %" PRIu64 "\n"),
- (unsigned long long) be64_to_cpu(pp[i]), lino);
+ if (!verify_dfsbno(mp, get_unaligned_be64(&pp[i]))) {
+ do_warn(
+_("bad bmap btree ptr 0x%" PRIx64 " in ino %" PRIu64 "\n"),
+ get_unaligned_be64(&pp[i]), lino);
return(1);
}
- if (scan_lbtree(be64_to_cpu(pp[i]), level, scan_bmapbt, type,
- whichfork, lino, tot, nex, blkmapp, &cursor,
- 1, check_dups, magic, &xfs_bmbt_buf_ops))
+ if (scan_lbtree(get_unaligned_be64(&pp[i]), level, scan_bmapbt,
+ type, whichfork, lino, tot, nex, blkmapp,
+ &cursor, 1, check_dups, magic,
+ &xfs_bmbt_buf_ops))
return(1);
/*
* fix key (offset) mismatches between the keys in root
* blocks but the parent hasn't been updated
*/
if (!check_dups && cursor.level[level-1].first_key !=
- be64_to_cpu(pkey[i].br_startoff)) {
+ get_unaligned_be64(&pkey[i].br_startoff)) {
if (!no_modify) {
do_warn(
- _("correcting key in bmbt root (was %llu, now %" PRIu64") in inode "
- "%" PRIu64" %s fork\n"),
- (unsigned long long)
- be64_to_cpu(pkey[i].br_startoff),
- cursor.level[level-1].first_key,
- XFS_AGINO_TO_INO(mp, agno, ino),
- forkname);
+_("correcting key in bmbt root (was %" PRIu64 ", now %" PRIu64") in inode "
+ "%" PRIu64" %s fork\n"),
+ get_unaligned_be64(&pkey[i].br_startoff),
+ cursor.level[level-1].first_key,
+ XFS_AGINO_TO_INO(mp, agno, ino),
+ forkname);
*dirty = 1;
- pkey[i].br_startoff = cpu_to_be64(
- cursor.level[level-1].first_key);
+ put_unaligned_be64(
+ cursor.level[level-1].first_key,
+ &pkey[i].br_startoff);
} else {
do_warn(
- _("bad key in bmbt root (is %llu, would reset to %" PRIu64 ") in inode "
- "%" PRIu64 " %s fork\n"),
- (unsigned long long)
- be64_to_cpu(pkey[i].br_startoff),
- cursor.level[level-1].first_key,
- XFS_AGINO_TO_INO(mp, agno, ino),
- forkname);
+_("bad key in bmbt root (is %" PRIu64 ", would reset to %" PRIu64 ") in inode "
+ "%" PRIu64 " %s fork\n"),
+ get_unaligned_be64(&pkey[i].br_startoff),
+ cursor.level[level-1].first_key,
+ XFS_AGINO_TO_INO(mp, agno, ino),
+ forkname);
}
}
/*
* inode if the ordering doesn't hold
*/
if (check_dups == 0) {
- if (last_key != NULLDFILOFF && last_key >=
+ if (last_key != NULLFILEOFF && last_key >=
cursor.level[level-1].first_key) {
do_warn(
_("out of order bmbt root key %" PRIu64 " in inode %" PRIu64 " %s fork\n"),
* is NULL.
*/
if (check_dups == 0 &&
- cursor.level[0].right_fsbno != NULLDFSBNO) {
+ cursor.level[0].right_fsbno != NULLFSBLOCK) {
do_warn(
- _("bad fwd (right) sibling pointer (saw %" PRIu64 " should be NULLDFSBNO)\n"),
+ _("bad fwd (right) sibling pointer (saw %" PRIu64 " should be NULLFSBLOCK)\n"),
cursor.level[0].right_fsbno);
do_warn(
_("\tin inode %" PRIu64 " (%s fork) bmap btree block %" PRIu64 "\n"),
xfs_dinode_t *dip,
int type,
int *dirty,
- xfs_drfsbno_t *tot,
- __uint64_t *nex,
+ xfs_rfsblock_t *tot,
+ uint64_t *nex,
blkmap_t **blkmapp,
int whichfork,
int check_dups)
{
xfs_ino_t lino;
xfs_bmbt_rec_t *rp;
- xfs_dfiloff_t first_key;
- xfs_dfiloff_t last_key;
+ xfs_fileoff_t first_key;
+ xfs_fileoff_t last_key;
int32_t numrecs;
int ret;
static int
process_symlink_extlist(xfs_mount_t *mp, xfs_ino_t lino, xfs_dinode_t *dino)
{
- xfs_dfiloff_t expected_offset;
+ xfs_fileoff_t expected_offset;
xfs_bmbt_rec_t *rp;
xfs_bmbt_irec_t irec;
int numrecs;
int max_blocks;
if (be64_to_cpu(dino->di_size) <= XFS_DFORK_DSIZE(dino, mp)) {
- if (dino->di_format == XFS_DINODE_FMT_LOCAL)
+ if (dino->di_format == XFS_DINODE_FMT_LOCAL)
return 0;
do_warn(
_("mismatch between format (%d) and size (%" PRId64 ") in symlink ino %" PRIu64 "\n"),
dino->di_format,
- (__int64_t)be64_to_cpu(dino->di_size), lino);
+ (int64_t)be64_to_cpu(dino->di_size), lino);
return 1;
}
if (dino->di_format == XFS_DINODE_FMT_LOCAL) {
do_warn(
_("mismatch between format (%d) and size (%" PRId64 ") in symlink inode %" PRIu64 "\n"),
dino->di_format,
- (__int64_t)be64_to_cpu(dino->di_size), lino);
+ (int64_t)be64_to_cpu(dino->di_size), lino);
return 1;
}
{
int i;
- ASSERT(length < MAXPATHLEN);
+ ASSERT(length < XFS_SYMLINK_MAXLEN);
for (i = 0; i < length; i++, name++) {
if (*name == '\0')
return(0);
}
+/*
+ * This does /not/ do quotacheck, it validates the basic quota
+ * inode metadata, checksums, etc.
+ */
+#define uuid_equal(s,d) (platform_uuid_compare((s),(d)) == 0)
+static int
+process_quota_inode(
+ struct xfs_mount *mp,
+ xfs_ino_t lino,
+ struct xfs_dinode *dino,
+ uint ino_type,
+ struct blkmap *blkmap)
+{
+ xfs_fsblock_t fsbno;
+ struct xfs_buf *bp;
+ xfs_filblks_t dqchunklen;
+ uint dqperchunk;
+ int quota_type;
+ char *quota_string;
+ xfs_dqid_t dqid;
+ xfs_fileoff_t qbno;
+ int i;
+ int t = 0;
+
+ switch (ino_type) {
+ case XR_INO_UQUOTA:
+ quota_type = XFS_DQ_USER;
+ quota_string = _("User quota");
+ break;
+ case XR_INO_GQUOTA:
+ quota_type = XFS_DQ_GROUP;
+ quota_string = _("Group quota");
+ break;
+ case XR_INO_PQUOTA:
+ quota_type = XFS_DQ_PROJ;
+ quota_string = _("Project quota");
+ break;
+ default:
+ ASSERT(0);
+ }
+
+ dqchunklen = XFS_FSB_TO_BB(mp, XFS_DQUOT_CLUSTER_SIZE_FSB);
+ dqperchunk = libxfs_calc_dquots_per_chunk(dqchunklen);
+ dqid = 0;
+ qbno = NULLFILEOFF;
+
+ while ((qbno = blkmap_next_off(blkmap, qbno, &t)) != NULLFILEOFF) {
+ xfs_dqblk_t *dqb;
+ int writebuf = 0;
+
+ fsbno = blkmap_get(blkmap, qbno);
+ dqid = (xfs_dqid_t)qbno * dqperchunk;
+
+ bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno),
+ dqchunklen, 0, &xfs_dquot_buf_ops);
+ if (!bp) {
+ do_warn(
+_("cannot read inode %" PRIu64 ", file block %" PRIu64 ", disk block %" PRIu64 "\n"),
+ lino, qbno, fsbno);
+ return 1;
+ }
+
+ dqb = bp->b_addr;
+ for (i = 0; i < dqperchunk; i++, dqid++, dqb++) {
+ int bad_dqb = 0;
+
+ /* We only print the first problem we find */
+ if (xfs_sb_version_hascrc(&mp->m_sb)) {
+ if (!libxfs_verify_cksum((char *)dqb,
+ sizeof(*dqb),
+ XFS_DQUOT_CRC_OFF)) {
+ do_warn(_("%s: bad CRC for id %u. "),
+ quota_string, dqid);
+ bad_dqb = 1;
+ goto bad;
+ }
+
+ if (!uuid_equal(&dqb->dd_uuid,
+ &mp->m_sb.sb_meta_uuid)) {
+ do_warn(_("%s: bad UUID for id %u. "),
+ quota_string, dqid);
+ bad_dqb = 1;
+ goto bad;
+ }
+ }
+ if (libxfs_dquot_verify(mp, &dqb->dd_diskdq, dqid,
+ quota_type) != NULL) {
+ do_warn(_("%s: Corrupt quota for id %u. "),
+ quota_string, dqid);
+ bad_dqb = 1;
+ }
+
+bad:
+ if (bad_dqb) {
+ if (no_modify)
+ do_warn(_("Would correct.\n"));
+ else {
+ do_warn(_("Corrected.\n"));
+ libxfs_dqblk_repair(mp, dqb,
+ dqid, quota_type);
+ writebuf = 1;
+ }
+ }
+ }
+
+ if (writebuf && !no_modify)
+ libxfs_writebuf(bp, 0);
+ else
+ libxfs_putbuf(bp);
+ }
+ return 0;
+}
+
static int
process_symlink_remote(
struct xfs_mount *mp,
struct blkmap *blkmap,
char *dst)
{
- xfs_dfsbno_t fsbno;
+ xfs_fsblock_t fsbno;
struct xfs_buf *bp;
char *src;
int pathlen;
int badcrc = 0;
fsbno = blkmap_get(blkmap, i);
- if (fsbno == NULLDFSBNO) {
+ if (fsbno == NULLFSBLOCK) {
do_warn(
_("cannot read inode %" PRIu64 ", file block %d, NULL disk block\n"),
lino, i);
lino, i, fsbno);
return 1;
}
- if (bp->b_error == EFSBADCRC) {
+ if (bp->b_error == -EFSCORRUPTED) {
+ do_warn(
+_("Corrupt symlink remote block %" PRIu64 ", inode %" PRIu64 ".\n"),
+ fsbno, lino);
+ libxfs_putbuf(bp);
+ return 1;
+ }
+ if (bp->b_error == -EFSBADCRC) {
do_warn(
_("Bad symlink buffer CRC, block %" PRIu64 ", inode %" PRIu64 ".\n"
"Correcting CRC, but symlink may be bad.\n"), fsbno, lino);
}
byte_cnt = XFS_SYMLINK_BUF_SPACE(mp, byte_cnt);
- byte_cnt = MIN(pathlen, byte_cnt);
+ byte_cnt = min(pathlen, byte_cnt);
src = bp->b_addr;
if (xfs_sb_version_hascrc(&mp->m_sb)) {
blkmap_t *blkmap)
{
char *symlink;
- char data[MAXPATHLEN];
+ char data[XFS_SYMLINK_MAXLEN];
/*
* check size against kernel symlink limits. we know
* the inode is structurally ok so we don't have to check
* for that
*/
- if (be64_to_cpu(dino->di_size) >= MAXPATHLEN) {
+ if (be64_to_cpu(dino->di_size) >= XFS_SYMLINK_MAXLEN) {
do_warn(_("symlink in inode %" PRIu64 " too long (%llu chars)\n"),
lino, (unsigned long long) be64_to_cpu(dino->di_size));
return(1);
}
+ if (be64_to_cpu(dino->di_size) == 0) {
+ do_warn(_("zero size symlink in inode %" PRIu64 "\n"), lino);
+ return 1;
+ }
+
/*
* have to check symlink component by component.
* get symlink contents into data area
* local symlink, just copy the symlink out of the
* inode into the data area
*/
- memmove(symlink, XFS_DFORK_DPTR(dino),
+ memmove(symlink, XFS_DFORK_DPTR(dino),
be64_to_cpu(dino->di_size));
} else {
int error;
case XR_INO_CHRDEV:
do_warn(
_("size of character device inode %" PRIu64 " != 0 (%" PRId64 " bytes)\n"), lino,
- (__int64_t)be64_to_cpu(dino->di_size));
+ (int64_t)be64_to_cpu(dino->di_size));
break;
case XR_INO_BLKDEV:
do_warn(
_("size of block device inode %" PRIu64 " != 0 (%" PRId64 " bytes)\n"), lino,
- (__int64_t)be64_to_cpu(dino->di_size));
+ (int64_t)be64_to_cpu(dino->di_size));
break;
case XR_INO_SOCK:
do_warn(
_("size of socket inode %" PRIu64 " != 0 (%" PRId64 " bytes)\n"), lino,
- (__int64_t)be64_to_cpu(dino->di_size));
+ (int64_t)be64_to_cpu(dino->di_size));
break;
case XR_INO_FIFO:
do_warn(
_("size of fifo inode %" PRIu64 " != 0 (%" PRId64 " bytes)\n"), lino,
- (__int64_t)be64_to_cpu(dino->di_size));
+ (int64_t)be64_to_cpu(dino->di_size));
+ break;
+ case XR_INO_UQUOTA:
+ case XR_INO_GQUOTA:
+ case XR_INO_PQUOTA:
+ do_warn(
+_("size of quota inode %" PRIu64 " != 0 (%" PRId64 " bytes)\n"), lino,
+ (int64_t)be64_to_cpu(dino->di_size));
break;
default:
do_warn(_("Internal error - process_misc_ino_types, "
}
static int
-process_misc_ino_types_blocks(xfs_drfsbno_t totblocks, xfs_ino_t lino, int type)
+process_misc_ino_types_blocks(xfs_rfsblock_t totblocks, xfs_ino_t lino, int type)
{
/*
* you can not enforce all misc types have zero data fork blocks
int *dirty)
{
if (lino == mp->m_sb.sb_rootino) {
- if (*type != XR_INO_DIR) {
+ if (*type != XR_INO_DIR) {
do_warn(_("root inode %" PRIu64 " has bad type 0x%x\n"),
lino, dinode_fmt(dinoc));
*type = XR_INO_DIR;
return 0;
}
if (lino == mp->m_sb.sb_uquotino) {
- if (*type != XR_INO_DATA) {
+ if (*type != XR_INO_UQUOTA) {
do_warn(_("user quota inode %" PRIu64 " has bad type 0x%x\n"),
lino, dinode_fmt(dinoc));
mp->m_sb.sb_uquotino = NULLFSINO;
return 0;
}
if (lino == mp->m_sb.sb_gquotino) {
- if (*type != XR_INO_DATA) {
+ if (*type != XR_INO_GQUOTA) {
do_warn(_("group quota inode %" PRIu64 " has bad type 0x%x\n"),
lino, dinode_fmt(dinoc));
mp->m_sb.sb_gquotino = NULLFSINO;
return 0;
}
if (lino == mp->m_sb.sb_pquotino) {
- if (*type != XR_INO_DATA) {
+ if (*type != XR_INO_PQUOTA) {
do_warn(_("project quota inode %" PRIu64 " has bad type 0x%x\n"),
lino, dinode_fmt(dinoc));
mp->m_sb.sb_pquotino = NULLFSINO;
return 1;
break;
+ case XR_INO_UQUOTA:
+ case XR_INO_GQUOTA:
+ case XR_INO_PQUOTA:
+ /* Quota inodes have same restrictions as above types */
+ if (process_misc_ino_types(mp, dino, lino, type))
+ return 1;
+ break;
+
case XR_INO_RTDATA:
/*
* if we have no realtime blocks, any inode claiming
break;
case XR_INO_RTBITMAP:
- if (size != (__int64_t)mp->m_sb.sb_rbmblocks *
+ if (size != (int64_t)mp->m_sb.sb_rbmblocks *
mp->m_sb.sb_blocksize) {
do_warn(
_("realtime bitmap inode %" PRIu64 " has bad size %" PRId64 " (should be %" PRIu64 ")\n"),
lino, size,
- (__int64_t) mp->m_sb.sb_rbmblocks *
+ (int64_t) mp->m_sb.sb_rbmblocks *
mp->m_sb.sb_blocksize);
return 1;
}
static int
process_inode_blocks_and_extents(
xfs_dinode_t *dino,
- xfs_drfsbno_t nblocks,
- __uint64_t nextents,
- __uint64_t anextents,
+ xfs_rfsblock_t nblocks,
+ uint64_t nextents,
+ uint64_t anextents,
xfs_ino_t lino,
int *dirty)
{
xfs_dinode_t *dino,
int type,
int *dirty,
- xfs_drfsbno_t *totblocks,
- __uint64_t *nextents,
+ xfs_rfsblock_t *totblocks,
+ uint64_t *nextents,
blkmap_t **dblkmap,
int check_dups)
{
if (err) {
do_warn(_("bad data fork in inode %" PRIu64 "\n"), lino);
if (!no_modify) {
- *dirty += clear_dinode(mp, dino, lino);
- ASSERT(*dirty > 0);
+ clear_dinode(mp, dino, lino);
+ *dirty += 1;
}
return 1;
}
*/
switch (dino->di_format) {
case XFS_DINODE_FMT_LOCAL:
- err = process_lclinode(mp, agno, ino, dino,
+ err = process_lclinode(mp, agno, ino, dino,
XFS_DATA_FORK);
break;
case XFS_DINODE_FMT_EXTENTS:
xfs_dinode_t *dino,
int type,
int *dirty,
- xfs_drfsbno_t *atotblocks,
- __uint64_t *anextents,
+ xfs_rfsblock_t *atotblocks,
+ uint64_t *anextents,
int check_dups,
int extra_attr_check,
int *retval)
do_warn(_("bad attribute fork in inode %" PRIu64), lino);
if (!no_modify) {
- if (delete_attr_ok) {
- do_warn(_(", clearing attr fork\n"));
- *dirty += clear_dinode_attr(mp, dino, lino);
- dino->di_aformat = XFS_DINODE_FMT_LOCAL;
- } else {
- do_warn("\n");
- *dirty += clear_dinode(mp, dino, lino);
- }
+ do_warn(_(", clearing attr fork\n"));
+ *dirty += clear_dinode_attr(mp, dino, lino);
+ dino->di_aformat = XFS_DINODE_FMT_LOCAL;
ASSERT(*dirty > 0);
} else {
do_warn(_(", would clear attr fork\n"));
blkmap_free(ablkmap);
*retval = 1;
- return delete_attr_ok ? 0 : 1;
+ return 0;
}
if (check_dups) {
switch (dino->di_aformat) {
case XFS_DINODE_FMT_LOCAL:
- err = process_lclinode(mp, agno, ino, dino,
+ err = process_lclinode(mp, agno, ino, dino,
XFS_ATTR_FORK);
break;
case XFS_DINODE_FMT_EXTENTS:
return dirty;
}
+/* Check nanoseconds of a timestamp don't exceed 1 second. */
+static void
+check_nsec(
+ const char *name,
+ xfs_ino_t lino,
+ struct xfs_timestamp *t,
+ int *dirty)
+{
+ if (be32_to_cpu(t->t_nsec) < 1000000000)
+ return;
+
+ do_warn(
+_("Bad %s nsec %u on inode %" PRIu64 ", "), name, be32_to_cpu(t->t_nsec), lino);
+ if (no_modify) {
+ do_warn(_("would reset to zero\n"));
+ } else {
+ do_warn(_("resetting to zero\n"));
+ t->t_nsec = 0;
+ *dirty = 1;
+ }
+}
+
/*
* returns 0 if the inode is ok, 1 if the inode is corrupt
* check_dups can be set to 1 *only* when called by the
int *isa_dir, /* out == 1 if inode is a directory */
xfs_ino_t *parent) /* out -- parent if ino is a dir */
{
- xfs_drfsbno_t totblocks = 0;
- xfs_drfsbno_t atotblocks = 0;
+ xfs_rfsblock_t totblocks = 0;
+ xfs_rfsblock_t atotblocks = 0;
int di_mode;
int type;
int retval = 0;
- __uint64_t nextents;
- __uint64_t anextents;
+ uint64_t nextents;
+ uint64_t anextents;
xfs_ino_t lino;
const int is_free = 0;
const int is_used = 1;
* rewritten, and the CRC is updated automagically.
*/
if (xfs_sb_version_hascrc(&mp->m_sb) &&
- !xfs_verify_cksum((char *)dino, mp->m_sb.sb_inodesize,
+ !libxfs_verify_cksum((char *)dino, mp->m_sb.sb_inodesize,
XFS_DINODE_CRC_OFF)) {
retval = 1;
if (!uncertain)
}
}
- if (!XFS_DINODE_GOOD_VERSION(dino->di_version) ||
- (xfs_sb_version_hascrc(&mp->m_sb) && dino->di_version < 3) ) {
+ if (!libxfs_dinode_good_version(mp, dino->di_version)) {
retval = 1;
if (!uncertain)
do_warn(_("bad version number 0x%x on inode %" PRIu64 "%c"),
if (!uncertain)
do_warn(
_("inode identifier %llu mismatch on inode %" PRIu64 "\n"),
- be64_to_cpu(dino->di_ino), lino);
+ (unsigned long long)be64_to_cpu(dino->di_ino),
+ lino);
if (verify_mode)
return 1;
goto clear_bad_out;
}
- if (platform_uuid_compare(&dino->di_uuid, &mp->m_sb.sb_uuid)) {
+ if (platform_uuid_compare(&dino->di_uuid,
+ &mp->m_sb.sb_meta_uuid)) {
if (!uncertain)
do_warn(
_("UUID mismatch on inode %" PRIu64 "\n"), lino);
if (!uncertain)
do_warn(
_("bad (negative) size %" PRId64 " on inode %" PRIu64 "\n"),
- (__int64_t)be64_to_cpu(dino->di_size),
+ (int64_t)be64_to_cpu(dino->di_size),
lino);
if (verify_mode)
return 1;
}
/*
- * if not in verify mode, check to sii if the inode and imap
+ * if not in verify mode, check to see if the inode and imap
* agree that the inode is free
*/
if (!verify_mode && di_mode == 0) {
*/
if (was_free) {
/*
- * easy case, inode free -- inode and map agree, clear
+ * easy case, inode free -- inode and map agree, check
* it just in case to ensure that format, etc. are
* set correctly
*/
- if (!no_modify)
- *dirty += clear_dinode(mp, dino, lino);
+ if (libxfs_dinode_verify(mp, lino, dino) != NULL) {
+ do_warn(
+ _("free inode %" PRIu64 " contains errors, "), lino);
+ if (!no_modify) {
+ clear_dinode(mp, dino, lino);
+ do_warn(_("corrected\n"));
+ *dirty += 1;
+ } else {
+ do_warn(_("would correct\n"));
+ }
+ }
*used = is_free;
return 0;
}
_("imap claims a free inode %" PRIu64 " is in use, "), lino);
if (!no_modify) {
do_warn(_("correcting imap and clearing inode\n"));
- *dirty += clear_dinode(mp, dino, lino);
+ clear_dinode(mp, dino, lino);
+ *dirty += 1;
retval = 1;
} else
do_warn(_("would correct imap and clear inode\n"));
XFS_DIFLAG_NOSYMLINKS);
}
}
- if (flags & (XFS_DIFLAG_REALTIME | XFS_XFLAG_EXTSIZE)) {
+ if (flags & (XFS_DIFLAG_REALTIME | FS_XFLAG_EXTSIZE)) {
/* must be a file */
if (di_mode && !S_ISREG(di_mode)) {
if (!uncertain) {
lino);
}
flags &= ~(XFS_DIFLAG_REALTIME |
- XFS_XFLAG_EXTSIZE);
+ FS_XFLAG_EXTSIZE);
}
}
if (!verify_mode && flags != be16_to_cpu(dino->di_flags)) {
}
}
+ /*
+ * check that we only have valid flags2 set, and those that are set make
+ * sense.
+ */
+ if (dino->di_version >= 3) {
+ uint16_t flags = be16_to_cpu(dino->di_flags);
+ uint64_t flags2 = be64_to_cpu(dino->di_flags2);
+
+ if (flags2 & ~XFS_DIFLAG2_ANY) {
+ if (!uncertain) {
+ do_warn(
+ _("Bad flags2 set in inode %" PRIu64 "\n"),
+ lino);
+ }
+ flags2 &= XFS_DIFLAG2_ANY;
+ }
+
+ if (flags2 & XFS_DIFLAG2_DAX) {
+ /* must be a file or dir */
+ if (di_mode && !(S_ISREG(di_mode) || S_ISDIR(di_mode))) {
+ if (!uncertain) {
+ do_warn(
+ _("DAX flag set on special inode %" PRIu64 "\n"),
+ lino);
+ }
+ flags2 &= ~XFS_DIFLAG2_DAX;
+ }
+ }
+
+ if ((flags2 & XFS_DIFLAG2_REFLINK) &&
+ !xfs_sb_version_hasreflink(&mp->m_sb)) {
+ if (!uncertain) {
+ do_warn(
+ _("inode %" PRIu64 " is marked reflinked but file system does not support reflink\n"),
+ lino);
+ }
+ goto clear_bad_out;
+ }
+
+ if (flags2 & XFS_DIFLAG2_REFLINK) {
+ /* must be a file */
+ if (di_mode && !S_ISREG(di_mode)) {
+ if (!uncertain) {
+ do_warn(
+ _("reflink flag set on non-file inode %" PRIu64 "\n"),
+ lino);
+ }
+ goto clear_bad_out;
+ }
+ }
+
+ if ((flags2 & XFS_DIFLAG2_REFLINK) &&
+ (flags & (XFS_DIFLAG_REALTIME | XFS_DIFLAG_RTINHERIT))) {
+ if (!uncertain) {
+ do_warn(
+ _("Cannot have a reflinked realtime inode %" PRIu64 "\n"),
+ lino);
+ }
+ goto clear_bad_out;
+ }
+
+ if ((flags2 & XFS_DIFLAG2_COWEXTSIZE) &&
+ !xfs_sb_version_hasreflink(&mp->m_sb)) {
+ if (!uncertain) {
+ do_warn(
+ _("inode %" PRIu64 " has CoW extent size hint but file system does not support reflink\n"),
+ lino);
+ }
+ flags2 &= ~XFS_DIFLAG2_COWEXTSIZE;
+ }
+
+ if (flags2 & XFS_DIFLAG2_COWEXTSIZE) {
+ /* must be a directory or file */
+ if (di_mode && !S_ISDIR(di_mode) && !S_ISREG(di_mode)) {
+ if (!uncertain) {
+ do_warn(
+ _("CoW extent size flag set on non-file, non-directory inode %" PRIu64 "\n" ),
+ lino);
+ }
+ flags2 &= ~XFS_DIFLAG2_COWEXTSIZE;
+ }
+ }
+
+ if ((flags2 & XFS_DIFLAG2_COWEXTSIZE) &&
+ (flags & (XFS_DIFLAG_REALTIME | XFS_DIFLAG_RTINHERIT))) {
+ if (!uncertain) {
+ do_warn(
+ _("Cannot have CoW extent size hint on a realtime inode %" PRIu64 "\n"),
+ lino);
+ }
+ flags2 &= ~XFS_DIFLAG2_COWEXTSIZE;
+ }
+
+ if (!verify_mode && flags2 != be64_to_cpu(dino->di_flags2)) {
+ if (!no_modify) {
+ do_warn(_("fixing bad flags2.\n"));
+ dino->di_flags2 = cpu_to_be64(flags2);
+ *dirty = 1;
+ } else
+ do_warn(_("would fix bad flags2.\n"));
+ }
+ }
+
if (verify_mode)
return retval;
* we're going to find. check_dups is set to 1 only during
* phase 4. Ugly.
*/
- if (check_dups && !no_modify)
- *dirty += clear_dinode_unlinked(mp, dino);
+ if (check_dups && be32_to_cpu(dino->di_next_unlinked) != NULLAGINO) {
+ if (no_modify) {
+ do_warn(
+ _("Would clear next_unlinked in inode %" PRIu64 "\n"), lino);
+ } else {
+ clear_dinode_unlinked(mp, dino);
+ do_warn(
+ _("Cleared next_unlinked in inode %" PRIu64 "\n"), lino);
+ *dirty += 1;
+ }
+ }
/* set type and map type info */
type = XR_INO_RTBITMAP;
else if (lino == mp->m_sb.sb_rsumino)
type = XR_INO_RTSUM;
+ else if (lino == mp->m_sb.sb_uquotino)
+ type = XR_INO_UQUOTA;
+ else if (lino == mp->m_sb.sb_gquotino)
+ type = XR_INO_GQUOTA;
+ else if (lino == mp->m_sb.sb_pquotino)
+ type = XR_INO_PQUOTA;
else
type = XR_INO_DATA;
break;
* only regular files with REALTIME or EXTSIZE flags set can have
* extsize set, or directories with EXTSZINHERIT.
*/
- if (be32_to_cpu(dino->di_extsize) != 0) {
- if ((type == XR_INO_RTDATA) ||
- (type == XR_INO_DIR && (be16_to_cpu(dino->di_flags) &
- XFS_DIFLAG_EXTSZINHERIT)) ||
- (type == XR_INO_DATA && (be16_to_cpu(dino->di_flags) &
- XFS_DIFLAG_EXTSIZE))) {
- /* s'okay */ ;
- } else {
- do_warn(
-_("bad non-zero extent size %u for non-realtime/extsize inode %" PRIu64 ", "),
- be32_to_cpu(dino->di_extsize), lino);
- if (!no_modify) {
- do_warn(_("resetting to zero\n"));
- dino->di_extsize = 0;
- *dirty = 1;
- } else
- do_warn(_("would reset to zero\n"));
- }
+ if (libxfs_inode_validate_extsize(mp,
+ be32_to_cpu(dino->di_extsize),
+ be16_to_cpu(dino->di_mode),
+ be16_to_cpu(dino->di_flags)) != NULL) {
+ do_warn(
+_("Bad extent size %u on inode %" PRIu64 ", "),
+ be32_to_cpu(dino->di_extsize), lino);
+ if (!no_modify) {
+ do_warn(_("resetting to zero\n"));
+ dino->di_extsize = 0;
+ dino->di_flags &= ~cpu_to_be16(XFS_DIFLAG_EXTSIZE |
+ XFS_DIFLAG_EXTSZINHERIT);
+ *dirty = 1;
+ } else
+ do_warn(_("would reset to zero\n"));
}
+ /*
+ * Only (regular files and directories) with COWEXTSIZE flags
+ * set can have extsize set.
+ */
+ if (dino->di_version >= 3 &&
+ libxfs_inode_validate_cowextsize(mp,
+ be32_to_cpu(dino->di_cowextsize),
+ be16_to_cpu(dino->di_mode),
+ be16_to_cpu(dino->di_flags),
+ be64_to_cpu(dino->di_flags2)) != NULL) {
+ do_warn(
+_("Bad CoW extent size %u on inode %" PRIu64 ", "),
+ be32_to_cpu(dino->di_cowextsize), lino);
+ if (!no_modify) {
+ do_warn(_("resetting to zero\n"));
+ dino->di_flags2 &= ~cpu_to_be64(XFS_DIFLAG2_COWEXTSIZE);
+ dino->di_cowextsize = 0;
+ *dirty = 1;
+ } else
+ do_warn(_("would reset to zero\n"));
+ }
+
+ /* nsec fields cannot be larger than 1 billion */
+ check_nsec("atime", lino, &dino->di_atime, dirty);
+ check_nsec("mtime", lino, &dino->di_mtime, dirty);
+ check_nsec("ctime", lino, &dino->di_ctime, dirty);
+ if (dino->di_version >= 3)
+ check_nsec("crtime", lino, &dino->di_crtime, dirty);
+
/*
* general size/consistency checks:
*/
if (process_check_inode_forkoff(mp, dino, lino) != 0)
goto clear_bad_out;
+ /*
+ * record the state of the reflink flag
+ */
+ if (collect_rmaps)
+ record_inode_reflink_flag(mp, dino, agno, ino, lino);
+
/*
* check data fork -- if it's bad, clear the inode
*/
goto clear_bad_out;
}
break;
+ case XR_INO_UQUOTA:
+ case XR_INO_GQUOTA:
+ case XR_INO_PQUOTA:
+ if (process_quota_inode(mp, lino, dino, type, dblkmap) != 0) {
+ do_warn(
+ _("problem with quota inode %" PRIu64 "\n"), lino);
+ goto clear_bad_out;
+ }
+ break;
default:
break;
}
clear_bad_out:
if (!no_modify) {
- *dirty += clear_dinode(mp, dino, lino);
- ASSERT(*dirty > 0);
+ clear_dinode(mp, dino, lino);
+ *dirty += 1;
}
bad_out:
*used = is_free;