DBM_LOG, DBM_MISSING, DBM_QUOTA, DBM_RTBITMAP,
DBM_RTDATA, DBM_RTFREE, DBM_RTSUM, DBM_SB,
DBM_SYMLINK, DBM_BTFINO, DBM_BTRMAP, DBM_BTREFC,
- DBM_RLDATA,
+ DBM_RLDATA, DBM_COWDATA,
DBM_NDBM
} dbm_t;
rp = XFS_REFCOUNT_REC_ADDR(block, 1);
lastblock = 0;
for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) {
- set_dbmap(seqno, be32_to_cpu(rp[i].rc_startblock),
- be32_to_cpu(rp[i].rc_blockcount), DBM_RLDATA,
- seqno, bno);
+ if (be32_to_cpu(rp[i].rc_refcount) == 1) {
+ dbprintf(_(
+ "leftover CoW extent (%u/%u) len %u\n"),
+ seqno,
+ be32_to_cpu(rp[i].rc_startblock),
+ be32_to_cpu(rp[i].rc_blockcount));
+ set_dbmap(seqno,
+ be32_to_cpu(rp[i].rc_startblock),
+ be32_to_cpu(rp[i].rc_blockcount),
+ DBM_COWDATA, seqno, bno);
+ } else {
+ set_dbmap(seqno,
+ be32_to_cpu(rp[i].rc_startblock),
+ be32_to_cpu(rp[i].rc_blockcount),
+ DBM_RLDATA, seqno, bno);
+ }
if (be32_to_cpu(rp[i].rc_startblock) < lastblock) {
dbprintf(_(
"out-of-order refcnt btree record %d (%u %u) block %u/%u\n"),
#define XR_E_INO1 10 /* used by inodes (marked by rmap btree) */
#define XR_E_FS_MAP1 11 /* used by fs space/inode maps (rmap btree) */
#define XR_E_REFC 12 /* used by fs ag reference count btree */
-#define XR_E_BAD_STATE 13
+#define XR_E_COW 13 /* leftover cow extent */
+#define XR_E_BAD_STATE 14
/* separate state bit, OR'ed into high (4th) bit of ex_state field */
case XFS_RMAP_OWN_REFC:
set_bmap_ext(agno, b, blen, XR_E_REFC);
break;
+ case XFS_RMAP_OWN_COW:
+ set_bmap_ext(agno, b, blen, XR_E_COW);
+ break;
case XFS_RMAP_OWN_NULL:
/* still unknown */
break;
rp = XFS_REFCOUNT_REC_ADDR(block, 1);
for (i = 0; i < numrecs; i++) {
- xfs_agblock_t b, end;
+ xfs_agblock_t b, agb, end;
xfs_extlen_t len;
xfs_nlink_t nr;
- b = be32_to_cpu(rp[i].rc_startblock);
+ b = agb = be32_to_cpu(rp[i].rc_startblock);
len = be32_to_cpu(rp[i].rc_blockcount);
nr = be32_to_cpu(rp[i].rc_refcount);
- end = b + len;
+ if (b >= XFS_REFC_COW_START && nr != 1)
+ do_warn(
+_("leftover CoW extent has incorrect refcount in record %u of %s btree block %u/%u\n"),
+ i, name, agno, bno);
+ if (nr == 1) {
+ if (agb < XFS_REFC_COW_START)
+ do_warn(
+_("leftover CoW extent has invalid startblock in record %u of %s btree block %u/%u\n"),
+ i, name, agno, bno);
+ agb -= XFS_REFC_COW_START;
+ }
+ end = agb + len;
- if (!verify_agbno(mp, agno, b)) {
+ if (!verify_agbno(mp, agno, agb)) {
do_warn(
_("invalid start block %u in record %u of %s btree block %u/%u\n"),
b, i, name, agno, bno);
continue;
}
- if (nr < 2 || nr > MAXREFCOUNT) {
+ if (nr == 1) {
+ xfs_agblock_t c;
+ xfs_extlen_t cnr;
+
+ for (c = agb; c < end; c += cnr) {
+ state = get_bmap_ext(agno, c, end, &cnr);
+ switch (state) {
+ case XR_E_UNKNOWN:
+ case XR_E_COW:
+ do_warn(
+_("leftover CoW extent (%u/%u) len %u\n"),
+ agno, c, cnr);
+ set_bmap_ext(agno, c, cnr, XR_E_FREE);
+ break;
+ default:
+ do_warn(
+_("extent (%u/%u) len %u claimed, state is %d\n"),
+ agno, c, cnr, state);
+ break;
+ }
+ }
+ } else if (nr < 2 || nr > MAXREFCOUNT) {
do_warn(
_("invalid reference count %u in record %u of %s btree block %u/%u\n"),
nr, i, name, agno, bno);