Bug fixes for 6.1-rc4:
- Fix a UAF bug during log recovery. - Fix memory leaks when mount fails. - Detect corrupt bestfree information in a directory block. - Fix incorrect return value type for the dax page fault handlers. - Fix fortify complaints about memcpy of xfs log item objects. - Strengthen inadequate validation of recovered log items. - Fix incorrectly declared flex array in EFI log item structs. - Log corrupt log items for debugging purposes. - Fix infinite loop problems in the refcount code if the refcount btree node block keys are corrupt. - Fix infinite loop problems in the refcount code if the refcount btree records suffer MSB bitflips. - Add more sanity checking to continued defer ops to prevent overflows from one AG to the next or off EOFS. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEUzaAxoMeQq6m2jMV+H93GTRKtOsFAmNhT68ACgkQ+H93GTRK tOs5Bw/+NSyPZ7jYVa3mXYKRsqMU/nqAGnNK4D4uS8gRlJTBolpC8Vs4fpBTQzV8 3JN8F/AUIQJOCxt5a81tlsPSYgEsxuIqion1olh3Z6ln4wN0su3rj0E3h+CTtgV8 xf3axdre4uC2xYhmKiDTD4ezLqylnRmsK1nNLbFzRnnJrYN+FiiJB7BefuJkbEzI HRTAJPo3oxsCDinkkyQhZ8CjD7ZenYuhgc4jFmVSLqNjULkF2kDyHgLCfojq+p3E G6WsuJ9fonMXlt2WV7k3tKektHIll8+ile6+zuPSjOH+WHo4/jWIjvUsg0X+M3DS jemPFNgpS6jSJy3qbPJoDej8XlV0FV4VzsCh2a/YaGa1Outl8V9ZhMyt9tc8LWzF 3Z1KkywsBqzK9m9yDlokmGPq71kCEQ+OMQSSlELEf6q7HHUf6yr3MyA5tXKqzJod DYFYoX70EoPAKk47gFI5EIYrzuTFx7PRugUUSU09e0wmjSswH7RjNur+Ya1eHhYc VUe6gUluuAkTFHhEjk+8mTg1iUlg92YdzL7pKSoeAlQczz1ZwQhE9W0ul1/z07d4 F4DXi6CtmM38e7XsX0CKmZ0ins9QmSDJheCKmE3kdLYY9PpzQpgtlq4kqjUP5eJw XZwB6cUS4pXw2zf4tW1qQ5pe13umfN6/VqymagG4fKWfAwj8s9o= =1IfG -----END PGP SIGNATURE----- Merge tag 'xfs-6.1-fixes-4' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux Pull xfs fixes from Darrick Wong: "Dave and I had thought that this would be a very quiet cycle, but we thought wrong. At first there were the usual trickle of minor bugfixes, but then Zorro pulled -rc1 and noticed complaints about the stronger memcpy checks w.r.t. flex arrays. Analyzing how to fix that revealed a bunch of validation gaps in validating ondisk log items during recovery, and then a customer hit an infinite loop in the refcounting code on a corrupt filesystem. So. This largeish batch of fixes addresses all those problems, I hope. Summary: - Fix a UAF bug during log recovery - Fix memory leaks when mount fails - Detect corrupt bestfree information in a directory block - Fix incorrect return value type for the dax page fault handlers - Fix fortify complaints about memcpy of xfs log item objects - Strengthen inadequate validation of recovered log items - Fix incorrectly declared flex array in EFI log item structs - Log corrupt log items for debugging purposes - Fix infinite loop problems in the refcount code if the refcount btree node block keys are corrupt - Fix infinite loop problems in the refcount code if the refcount btree records suffer MSB bitflips - Add more sanity checking to continued defer ops to prevent overflows from one AG to the next or off EOFS" * tag 'xfs-6.1-fixes-4' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux: (28 commits) xfs: rename XFS_REFC_COW_START to _COWFLAG xfs: fix uninitialized list head in struct xfs_refcount_recovery xfs: fix agblocks check in the cow leftover recovery function xfs: check record domain when accessing refcount records xfs: remove XFS_FIND_RCEXT_SHARED and _COW xfs: refactor domain and refcount checking xfs: report refcount domain in tracepoints xfs: track cow/shared record domains explicitly in xfs_refcount_irec xfs: refactor refcount record usage in xchk_refcountbt_rec xfs: dump corrupt recovered log intent items to dmesg consistently xfs: move _irec structs to xfs_types.h xfs: actually abort log recovery on corrupt intent-done log items xfs: check deferred refcount op continuation parameters xfs: refactor all the EFI/EFD log item sizeof logic xfs: create a predicate to verify per-AG extents xfs: fix memcpy fortify errors in EFI log format copying xfs: make sure aglen never goes negative in xfs_refcount_adjust_extents xfs: fix memcpy fortify errors in RUI log format copying xfs: fix memcpy fortify errors in CUI log format copying xfs: fix memcpy fortify errors in BUI log format copying ...
This commit is contained in:
Коммит
64c3dd0b98
|
@ -133,6 +133,21 @@ xfs_verify_agbno(struct xfs_perag *pag, xfs_agblock_t agbno)
|
|||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xfs_verify_agbext(
|
||||
struct xfs_perag *pag,
|
||||
xfs_agblock_t agbno,
|
||||
xfs_agblock_t len)
|
||||
{
|
||||
if (agbno + len <= agbno)
|
||||
return false;
|
||||
|
||||
if (!xfs_verify_agbno(pag, agbno))
|
||||
return false;
|
||||
|
||||
return xfs_verify_agbno(pag, agbno + len - 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that an AG inode number pointer neither points outside the AG
|
||||
* nor points at static metadata.
|
||||
|
|
|
@ -263,11 +263,7 @@ xfs_alloc_get_rec(
|
|||
goto out_bad_rec;
|
||||
|
||||
/* check for valid extent range, including overflow */
|
||||
if (!xfs_verify_agbno(pag, *bno))
|
||||
goto out_bad_rec;
|
||||
if (*bno > *bno + *len)
|
||||
goto out_bad_rec;
|
||||
if (!xfs_verify_agbno(pag, *bno + *len - 1))
|
||||
if (!xfs_verify_agbext(pag, *bno, *len))
|
||||
goto out_bad_rec;
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -146,6 +146,8 @@ xfs_dir3_leaf_check_int(
|
|||
xfs_dir2_leaf_tail_t *ltp;
|
||||
int stale;
|
||||
int i;
|
||||
bool isleaf1 = (hdr->magic == XFS_DIR2_LEAF1_MAGIC ||
|
||||
hdr->magic == XFS_DIR3_LEAF1_MAGIC);
|
||||
|
||||
ltp = xfs_dir2_leaf_tail_p(geo, leaf);
|
||||
|
||||
|
@ -158,8 +160,7 @@ xfs_dir3_leaf_check_int(
|
|||
return __this_address;
|
||||
|
||||
/* Leaves and bests don't overlap in leaf format. */
|
||||
if ((hdr->magic == XFS_DIR2_LEAF1_MAGIC ||
|
||||
hdr->magic == XFS_DIR3_LEAF1_MAGIC) &&
|
||||
if (isleaf1 &&
|
||||
(char *)&hdr->ents[hdr->count] > (char *)xfs_dir2_leaf_bests_p(ltp))
|
||||
return __this_address;
|
||||
|
||||
|
@ -175,6 +176,10 @@ xfs_dir3_leaf_check_int(
|
|||
}
|
||||
if (hdr->ents[i].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR))
|
||||
stale++;
|
||||
if (isleaf1 && xfs_dir2_dataptr_to_db(geo,
|
||||
be32_to_cpu(hdr->ents[i].address)) >=
|
||||
be32_to_cpu(ltp->bestcount))
|
||||
return __this_address;
|
||||
}
|
||||
if (hdr->stale != stale)
|
||||
return __this_address;
|
||||
|
|
|
@ -1564,20 +1564,6 @@ struct xfs_rmap_rec {
|
|||
#define RMAPBT_UNUSED_OFFSET_BITLEN 7
|
||||
#define RMAPBT_OFFSET_BITLEN 54
|
||||
|
||||
#define XFS_RMAP_ATTR_FORK (1 << 0)
|
||||
#define XFS_RMAP_BMBT_BLOCK (1 << 1)
|
||||
#define XFS_RMAP_UNWRITTEN (1 << 2)
|
||||
#define XFS_RMAP_KEY_FLAGS (XFS_RMAP_ATTR_FORK | \
|
||||
XFS_RMAP_BMBT_BLOCK)
|
||||
#define XFS_RMAP_REC_FLAGS (XFS_RMAP_UNWRITTEN)
|
||||
struct xfs_rmap_irec {
|
||||
xfs_agblock_t rm_startblock; /* extent start block */
|
||||
xfs_extlen_t rm_blockcount; /* extent length */
|
||||
uint64_t rm_owner; /* extent owner */
|
||||
uint64_t rm_offset; /* offset within the owner */
|
||||
unsigned int rm_flags; /* state flags */
|
||||
};
|
||||
|
||||
/*
|
||||
* Key structure
|
||||
*
|
||||
|
@ -1626,7 +1612,7 @@ unsigned int xfs_refc_block(struct xfs_mount *mp);
|
|||
* on the startblock. This speeds up mount time deletion of stale
|
||||
* staging extents because they're all at the right side of the tree.
|
||||
*/
|
||||
#define XFS_REFC_COW_START ((xfs_agblock_t)(1U << 31))
|
||||
#define XFS_REFC_COWFLAG (1U << 31)
|
||||
#define REFCNTBT_COWFLAG_BITLEN 1
|
||||
#define REFCNTBT_AGBLOCK_BITLEN 31
|
||||
|
||||
|
@ -1640,12 +1626,6 @@ struct xfs_refcount_key {
|
|||
__be32 rc_startblock; /* starting block number */
|
||||
};
|
||||
|
||||
struct xfs_refcount_irec {
|
||||
xfs_agblock_t rc_startblock; /* starting block number */
|
||||
xfs_extlen_t rc_blockcount; /* count of free blocks */
|
||||
xfs_nlink_t rc_refcount; /* number of inodes linked here */
|
||||
};
|
||||
|
||||
#define MAXREFCOUNT ((xfs_nlink_t)~0U)
|
||||
#define MAXREFCEXTLEN ((xfs_extlen_t)~0U)
|
||||
|
||||
|
|
|
@ -613,25 +613,49 @@ typedef struct xfs_efi_log_format {
|
|||
uint16_t efi_size; /* size of this item */
|
||||
uint32_t efi_nextents; /* # extents to free */
|
||||
uint64_t efi_id; /* efi identifier */
|
||||
xfs_extent_t efi_extents[1]; /* array of extents to free */
|
||||
xfs_extent_t efi_extents[]; /* array of extents to free */
|
||||
} xfs_efi_log_format_t;
|
||||
|
||||
static inline size_t
|
||||
xfs_efi_log_format_sizeof(
|
||||
unsigned int nr)
|
||||
{
|
||||
return sizeof(struct xfs_efi_log_format) +
|
||||
nr * sizeof(struct xfs_extent);
|
||||
}
|
||||
|
||||
typedef struct xfs_efi_log_format_32 {
|
||||
uint16_t efi_type; /* efi log item type */
|
||||
uint16_t efi_size; /* size of this item */
|
||||
uint32_t efi_nextents; /* # extents to free */
|
||||
uint64_t efi_id; /* efi identifier */
|
||||
xfs_extent_32_t efi_extents[1]; /* array of extents to free */
|
||||
xfs_extent_32_t efi_extents[]; /* array of extents to free */
|
||||
} __attribute__((packed)) xfs_efi_log_format_32_t;
|
||||
|
||||
static inline size_t
|
||||
xfs_efi_log_format32_sizeof(
|
||||
unsigned int nr)
|
||||
{
|
||||
return sizeof(struct xfs_efi_log_format_32) +
|
||||
nr * sizeof(struct xfs_extent_32);
|
||||
}
|
||||
|
||||
typedef struct xfs_efi_log_format_64 {
|
||||
uint16_t efi_type; /* efi log item type */
|
||||
uint16_t efi_size; /* size of this item */
|
||||
uint32_t efi_nextents; /* # extents to free */
|
||||
uint64_t efi_id; /* efi identifier */
|
||||
xfs_extent_64_t efi_extents[1]; /* array of extents to free */
|
||||
xfs_extent_64_t efi_extents[]; /* array of extents to free */
|
||||
} xfs_efi_log_format_64_t;
|
||||
|
||||
static inline size_t
|
||||
xfs_efi_log_format64_sizeof(
|
||||
unsigned int nr)
|
||||
{
|
||||
return sizeof(struct xfs_efi_log_format_64) +
|
||||
nr * sizeof(struct xfs_extent_64);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the structure used to lay out an efd log item in the
|
||||
* log. The efd_extents array is a variable size array whose
|
||||
|
@ -642,25 +666,49 @@ typedef struct xfs_efd_log_format {
|
|||
uint16_t efd_size; /* size of this item */
|
||||
uint32_t efd_nextents; /* # of extents freed */
|
||||
uint64_t efd_efi_id; /* id of corresponding efi */
|
||||
xfs_extent_t efd_extents[1]; /* array of extents freed */
|
||||
xfs_extent_t efd_extents[]; /* array of extents freed */
|
||||
} xfs_efd_log_format_t;
|
||||
|
||||
static inline size_t
|
||||
xfs_efd_log_format_sizeof(
|
||||
unsigned int nr)
|
||||
{
|
||||
return sizeof(struct xfs_efd_log_format) +
|
||||
nr * sizeof(struct xfs_extent);
|
||||
}
|
||||
|
||||
typedef struct xfs_efd_log_format_32 {
|
||||
uint16_t efd_type; /* efd log item type */
|
||||
uint16_t efd_size; /* size of this item */
|
||||
uint32_t efd_nextents; /* # of extents freed */
|
||||
uint64_t efd_efi_id; /* id of corresponding efi */
|
||||
xfs_extent_32_t efd_extents[1]; /* array of extents freed */
|
||||
xfs_extent_32_t efd_extents[]; /* array of extents freed */
|
||||
} __attribute__((packed)) xfs_efd_log_format_32_t;
|
||||
|
||||
static inline size_t
|
||||
xfs_efd_log_format32_sizeof(
|
||||
unsigned int nr)
|
||||
{
|
||||
return sizeof(struct xfs_efd_log_format_32) +
|
||||
nr * sizeof(struct xfs_extent_32);
|
||||
}
|
||||
|
||||
typedef struct xfs_efd_log_format_64 {
|
||||
uint16_t efd_type; /* efd log item type */
|
||||
uint16_t efd_size; /* size of this item */
|
||||
uint32_t efd_nextents; /* # of extents freed */
|
||||
uint64_t efd_efi_id; /* id of corresponding efi */
|
||||
xfs_extent_64_t efd_extents[1]; /* array of extents freed */
|
||||
xfs_extent_64_t efd_extents[]; /* array of extents freed */
|
||||
} xfs_efd_log_format_64_t;
|
||||
|
||||
static inline size_t
|
||||
xfs_efd_log_format64_sizeof(
|
||||
unsigned int nr)
|
||||
{
|
||||
return sizeof(struct xfs_efd_log_format_64) +
|
||||
nr * sizeof(struct xfs_extent_64);
|
||||
}
|
||||
|
||||
/*
|
||||
* RUI/RUD (reverse mapping) log format definitions
|
||||
*/
|
||||
|
|
|
@ -46,13 +46,16 @@ STATIC int __xfs_refcount_cow_free(struct xfs_btree_cur *rcur,
|
|||
int
|
||||
xfs_refcount_lookup_le(
|
||||
struct xfs_btree_cur *cur,
|
||||
enum xfs_refc_domain domain,
|
||||
xfs_agblock_t bno,
|
||||
int *stat)
|
||||
{
|
||||
trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_ag.pag->pag_agno, bno,
|
||||
trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_ag.pag->pag_agno,
|
||||
xfs_refcount_encode_startblock(bno, domain),
|
||||
XFS_LOOKUP_LE);
|
||||
cur->bc_rec.rc.rc_startblock = bno;
|
||||
cur->bc_rec.rc.rc_blockcount = 0;
|
||||
cur->bc_rec.rc.rc_domain = domain;
|
||||
return xfs_btree_lookup(cur, XFS_LOOKUP_LE, stat);
|
||||
}
|
||||
|
||||
|
@ -63,13 +66,16 @@ xfs_refcount_lookup_le(
|
|||
int
|
||||
xfs_refcount_lookup_ge(
|
||||
struct xfs_btree_cur *cur,
|
||||
enum xfs_refc_domain domain,
|
||||
xfs_agblock_t bno,
|
||||
int *stat)
|
||||
{
|
||||
trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_ag.pag->pag_agno, bno,
|
||||
trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_ag.pag->pag_agno,
|
||||
xfs_refcount_encode_startblock(bno, domain),
|
||||
XFS_LOOKUP_GE);
|
||||
cur->bc_rec.rc.rc_startblock = bno;
|
||||
cur->bc_rec.rc.rc_blockcount = 0;
|
||||
cur->bc_rec.rc.rc_domain = domain;
|
||||
return xfs_btree_lookup(cur, XFS_LOOKUP_GE, stat);
|
||||
}
|
||||
|
||||
|
@ -80,13 +86,16 @@ xfs_refcount_lookup_ge(
|
|||
int
|
||||
xfs_refcount_lookup_eq(
|
||||
struct xfs_btree_cur *cur,
|
||||
enum xfs_refc_domain domain,
|
||||
xfs_agblock_t bno,
|
||||
int *stat)
|
||||
{
|
||||
trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_ag.pag->pag_agno, bno,
|
||||
trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_ag.pag->pag_agno,
|
||||
xfs_refcount_encode_startblock(bno, domain),
|
||||
XFS_LOOKUP_LE);
|
||||
cur->bc_rec.rc.rc_startblock = bno;
|
||||
cur->bc_rec.rc.rc_blockcount = 0;
|
||||
cur->bc_rec.rc.rc_domain = domain;
|
||||
return xfs_btree_lookup(cur, XFS_LOOKUP_EQ, stat);
|
||||
}
|
||||
|
||||
|
@ -96,7 +105,17 @@ xfs_refcount_btrec_to_irec(
|
|||
const union xfs_btree_rec *rec,
|
||||
struct xfs_refcount_irec *irec)
|
||||
{
|
||||
irec->rc_startblock = be32_to_cpu(rec->refc.rc_startblock);
|
||||
uint32_t start;
|
||||
|
||||
start = be32_to_cpu(rec->refc.rc_startblock);
|
||||
if (start & XFS_REFC_COWFLAG) {
|
||||
start &= ~XFS_REFC_COWFLAG;
|
||||
irec->rc_domain = XFS_REFC_DOMAIN_COW;
|
||||
} else {
|
||||
irec->rc_domain = XFS_REFC_DOMAIN_SHARED;
|
||||
}
|
||||
|
||||
irec->rc_startblock = start;
|
||||
irec->rc_blockcount = be32_to_cpu(rec->refc.rc_blockcount);
|
||||
irec->rc_refcount = be32_to_cpu(rec->refc.rc_refcount);
|
||||
}
|
||||
|
@ -114,7 +133,6 @@ xfs_refcount_get_rec(
|
|||
struct xfs_perag *pag = cur->bc_ag.pag;
|
||||
union xfs_btree_rec *rec;
|
||||
int error;
|
||||
xfs_agblock_t realstart;
|
||||
|
||||
error = xfs_btree_get_rec(cur, &rec, stat);
|
||||
if (error || !*stat)
|
||||
|
@ -124,22 +142,11 @@ xfs_refcount_get_rec(
|
|||
if (irec->rc_blockcount == 0 || irec->rc_blockcount > MAXREFCEXTLEN)
|
||||
goto out_bad_rec;
|
||||
|
||||
/* handle special COW-staging state */
|
||||
realstart = irec->rc_startblock;
|
||||
if (realstart & XFS_REFC_COW_START) {
|
||||
if (irec->rc_refcount != 1)
|
||||
goto out_bad_rec;
|
||||
realstart &= ~XFS_REFC_COW_START;
|
||||
} else if (irec->rc_refcount < 2) {
|
||||
if (!xfs_refcount_check_domain(irec))
|
||||
goto out_bad_rec;
|
||||
}
|
||||
|
||||
/* check for valid extent range, including overflow */
|
||||
if (!xfs_verify_agbno(pag, realstart))
|
||||
goto out_bad_rec;
|
||||
if (realstart > realstart + irec->rc_blockcount)
|
||||
goto out_bad_rec;
|
||||
if (!xfs_verify_agbno(pag, realstart + irec->rc_blockcount - 1))
|
||||
if (!xfs_verify_agbext(pag, irec->rc_startblock, irec->rc_blockcount))
|
||||
goto out_bad_rec;
|
||||
|
||||
if (irec->rc_refcount == 0 || irec->rc_refcount > MAXREFCOUNT)
|
||||
|
@ -169,12 +176,17 @@ xfs_refcount_update(
|
|||
struct xfs_refcount_irec *irec)
|
||||
{
|
||||
union xfs_btree_rec rec;
|
||||
uint32_t start;
|
||||
int error;
|
||||
|
||||
trace_xfs_refcount_update(cur->bc_mp, cur->bc_ag.pag->pag_agno, irec);
|
||||
rec.refc.rc_startblock = cpu_to_be32(irec->rc_startblock);
|
||||
|
||||
start = xfs_refcount_encode_startblock(irec->rc_startblock,
|
||||
irec->rc_domain);
|
||||
rec.refc.rc_startblock = cpu_to_be32(start);
|
||||
rec.refc.rc_blockcount = cpu_to_be32(irec->rc_blockcount);
|
||||
rec.refc.rc_refcount = cpu_to_be32(irec->rc_refcount);
|
||||
|
||||
error = xfs_btree_update(cur, &rec);
|
||||
if (error)
|
||||
trace_xfs_refcount_update_error(cur->bc_mp,
|
||||
|
@ -196,9 +208,12 @@ xfs_refcount_insert(
|
|||
int error;
|
||||
|
||||
trace_xfs_refcount_insert(cur->bc_mp, cur->bc_ag.pag->pag_agno, irec);
|
||||
|
||||
cur->bc_rec.rc.rc_startblock = irec->rc_startblock;
|
||||
cur->bc_rec.rc.rc_blockcount = irec->rc_blockcount;
|
||||
cur->bc_rec.rc.rc_refcount = irec->rc_refcount;
|
||||
cur->bc_rec.rc.rc_domain = irec->rc_domain;
|
||||
|
||||
error = xfs_btree_insert(cur, i);
|
||||
if (error)
|
||||
goto out_error;
|
||||
|
@ -244,7 +259,8 @@ xfs_refcount_delete(
|
|||
}
|
||||
if (error)
|
||||
goto out_error;
|
||||
error = xfs_refcount_lookup_ge(cur, irec.rc_startblock, &found_rec);
|
||||
error = xfs_refcount_lookup_ge(cur, irec.rc_domain, irec.rc_startblock,
|
||||
&found_rec);
|
||||
out_error:
|
||||
if (error)
|
||||
trace_xfs_refcount_delete_error(cur->bc_mp,
|
||||
|
@ -343,6 +359,7 @@ xfs_refc_next(
|
|||
STATIC int
|
||||
xfs_refcount_split_extent(
|
||||
struct xfs_btree_cur *cur,
|
||||
enum xfs_refc_domain domain,
|
||||
xfs_agblock_t agbno,
|
||||
bool *shape_changed)
|
||||
{
|
||||
|
@ -351,7 +368,7 @@ xfs_refcount_split_extent(
|
|||
int error;
|
||||
|
||||
*shape_changed = false;
|
||||
error = xfs_refcount_lookup_le(cur, agbno, &found_rec);
|
||||
error = xfs_refcount_lookup_le(cur, domain, agbno, &found_rec);
|
||||
if (error)
|
||||
goto out_error;
|
||||
if (!found_rec)
|
||||
|
@ -364,6 +381,8 @@ xfs_refcount_split_extent(
|
|||
error = -EFSCORRUPTED;
|
||||
goto out_error;
|
||||
}
|
||||
if (rcext.rc_domain != domain)
|
||||
return 0;
|
||||
if (rcext.rc_startblock == agbno || xfs_refc_next(&rcext) <= agbno)
|
||||
return 0;
|
||||
|
||||
|
@ -415,6 +434,9 @@ xfs_refcount_merge_center_extents(
|
|||
trace_xfs_refcount_merge_center_extents(cur->bc_mp,
|
||||
cur->bc_ag.pag->pag_agno, left, center, right);
|
||||
|
||||
ASSERT(left->rc_domain == center->rc_domain);
|
||||
ASSERT(right->rc_domain == center->rc_domain);
|
||||
|
||||
/*
|
||||
* Make sure the center and right extents are not in the btree.
|
||||
* If the center extent was synthesized, the first delete call
|
||||
|
@ -423,8 +445,8 @@ xfs_refcount_merge_center_extents(
|
|||
* call removes the center and the second one removes the right
|
||||
* extent.
|
||||
*/
|
||||
error = xfs_refcount_lookup_ge(cur, center->rc_startblock,
|
||||
&found_rec);
|
||||
error = xfs_refcount_lookup_ge(cur, center->rc_domain,
|
||||
center->rc_startblock, &found_rec);
|
||||
if (error)
|
||||
goto out_error;
|
||||
if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) {
|
||||
|
@ -451,8 +473,8 @@ xfs_refcount_merge_center_extents(
|
|||
}
|
||||
|
||||
/* Enlarge the left extent. */
|
||||
error = xfs_refcount_lookup_le(cur, left->rc_startblock,
|
||||
&found_rec);
|
||||
error = xfs_refcount_lookup_le(cur, left->rc_domain,
|
||||
left->rc_startblock, &found_rec);
|
||||
if (error)
|
||||
goto out_error;
|
||||
if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) {
|
||||
|
@ -491,10 +513,12 @@ xfs_refcount_merge_left_extent(
|
|||
trace_xfs_refcount_merge_left_extent(cur->bc_mp,
|
||||
cur->bc_ag.pag->pag_agno, left, cleft);
|
||||
|
||||
ASSERT(left->rc_domain == cleft->rc_domain);
|
||||
|
||||
/* If the extent at agbno (cleft) wasn't synthesized, remove it. */
|
||||
if (cleft->rc_refcount > 1) {
|
||||
error = xfs_refcount_lookup_le(cur, cleft->rc_startblock,
|
||||
&found_rec);
|
||||
error = xfs_refcount_lookup_le(cur, cleft->rc_domain,
|
||||
cleft->rc_startblock, &found_rec);
|
||||
if (error)
|
||||
goto out_error;
|
||||
if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) {
|
||||
|
@ -512,8 +536,8 @@ xfs_refcount_merge_left_extent(
|
|||
}
|
||||
|
||||
/* Enlarge the left extent. */
|
||||
error = xfs_refcount_lookup_le(cur, left->rc_startblock,
|
||||
&found_rec);
|
||||
error = xfs_refcount_lookup_le(cur, left->rc_domain,
|
||||
left->rc_startblock, &found_rec);
|
||||
if (error)
|
||||
goto out_error;
|
||||
if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) {
|
||||
|
@ -552,13 +576,15 @@ xfs_refcount_merge_right_extent(
|
|||
trace_xfs_refcount_merge_right_extent(cur->bc_mp,
|
||||
cur->bc_ag.pag->pag_agno, cright, right);
|
||||
|
||||
ASSERT(right->rc_domain == cright->rc_domain);
|
||||
|
||||
/*
|
||||
* If the extent ending at agbno+aglen (cright) wasn't synthesized,
|
||||
* remove it.
|
||||
*/
|
||||
if (cright->rc_refcount > 1) {
|
||||
error = xfs_refcount_lookup_le(cur, cright->rc_startblock,
|
||||
&found_rec);
|
||||
error = xfs_refcount_lookup_le(cur, cright->rc_domain,
|
||||
cright->rc_startblock, &found_rec);
|
||||
if (error)
|
||||
goto out_error;
|
||||
if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) {
|
||||
|
@ -576,8 +602,8 @@ xfs_refcount_merge_right_extent(
|
|||
}
|
||||
|
||||
/* Enlarge the right extent. */
|
||||
error = xfs_refcount_lookup_le(cur, right->rc_startblock,
|
||||
&found_rec);
|
||||
error = xfs_refcount_lookup_le(cur, right->rc_domain,
|
||||
right->rc_startblock, &found_rec);
|
||||
if (error)
|
||||
goto out_error;
|
||||
if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) {
|
||||
|
@ -600,8 +626,6 @@ out_error:
|
|||
return error;
|
||||
}
|
||||
|
||||
#define XFS_FIND_RCEXT_SHARED 1
|
||||
#define XFS_FIND_RCEXT_COW 2
|
||||
/*
|
||||
* Find the left extent and the one after it (cleft). This function assumes
|
||||
* that we've already split any extent crossing agbno.
|
||||
|
@ -611,16 +635,16 @@ xfs_refcount_find_left_extents(
|
|||
struct xfs_btree_cur *cur,
|
||||
struct xfs_refcount_irec *left,
|
||||
struct xfs_refcount_irec *cleft,
|
||||
enum xfs_refc_domain domain,
|
||||
xfs_agblock_t agbno,
|
||||
xfs_extlen_t aglen,
|
||||
int flags)
|
||||
xfs_extlen_t aglen)
|
||||
{
|
||||
struct xfs_refcount_irec tmp;
|
||||
int error;
|
||||
int found_rec;
|
||||
|
||||
left->rc_startblock = cleft->rc_startblock = NULLAGBLOCK;
|
||||
error = xfs_refcount_lookup_le(cur, agbno - 1, &found_rec);
|
||||
error = xfs_refcount_lookup_le(cur, domain, agbno - 1, &found_rec);
|
||||
if (error)
|
||||
goto out_error;
|
||||
if (!found_rec)
|
||||
|
@ -634,12 +658,10 @@ xfs_refcount_find_left_extents(
|
|||
goto out_error;
|
||||
}
|
||||
|
||||
if (tmp.rc_domain != domain)
|
||||
return 0;
|
||||
if (xfs_refc_next(&tmp) != agbno)
|
||||
return 0;
|
||||
if ((flags & XFS_FIND_RCEXT_SHARED) && tmp.rc_refcount < 2)
|
||||
return 0;
|
||||
if ((flags & XFS_FIND_RCEXT_COW) && tmp.rc_refcount > 1)
|
||||
return 0;
|
||||
/* We have a left extent; retrieve (or invent) the next right one */
|
||||
*left = tmp;
|
||||
|
||||
|
@ -655,6 +677,9 @@ xfs_refcount_find_left_extents(
|
|||
goto out_error;
|
||||
}
|
||||
|
||||
if (tmp.rc_domain != domain)
|
||||
goto not_found;
|
||||
|
||||
/* if tmp starts at the end of our range, just use that */
|
||||
if (tmp.rc_startblock == agbno)
|
||||
*cleft = tmp;
|
||||
|
@ -671,8 +696,10 @@ xfs_refcount_find_left_extents(
|
|||
cleft->rc_blockcount = min(aglen,
|
||||
tmp.rc_startblock - agbno);
|
||||
cleft->rc_refcount = 1;
|
||||
cleft->rc_domain = domain;
|
||||
}
|
||||
} else {
|
||||
not_found:
|
||||
/*
|
||||
* No extents, so pretend that there's one covering the whole
|
||||
* range.
|
||||
|
@ -680,6 +707,7 @@ xfs_refcount_find_left_extents(
|
|||
cleft->rc_startblock = agbno;
|
||||
cleft->rc_blockcount = aglen;
|
||||
cleft->rc_refcount = 1;
|
||||
cleft->rc_domain = domain;
|
||||
}
|
||||
trace_xfs_refcount_find_left_extent(cur->bc_mp, cur->bc_ag.pag->pag_agno,
|
||||
left, cleft, agbno);
|
||||
|
@ -700,16 +728,16 @@ xfs_refcount_find_right_extents(
|
|||
struct xfs_btree_cur *cur,
|
||||
struct xfs_refcount_irec *right,
|
||||
struct xfs_refcount_irec *cright,
|
||||
enum xfs_refc_domain domain,
|
||||
xfs_agblock_t agbno,
|
||||
xfs_extlen_t aglen,
|
||||
int flags)
|
||||
xfs_extlen_t aglen)
|
||||
{
|
||||
struct xfs_refcount_irec tmp;
|
||||
int error;
|
||||
int found_rec;
|
||||
|
||||
right->rc_startblock = cright->rc_startblock = NULLAGBLOCK;
|
||||
error = xfs_refcount_lookup_ge(cur, agbno + aglen, &found_rec);
|
||||
error = xfs_refcount_lookup_ge(cur, domain, agbno + aglen, &found_rec);
|
||||
if (error)
|
||||
goto out_error;
|
||||
if (!found_rec)
|
||||
|
@ -723,12 +751,10 @@ xfs_refcount_find_right_extents(
|
|||
goto out_error;
|
||||
}
|
||||
|
||||
if (tmp.rc_domain != domain)
|
||||
return 0;
|
||||
if (tmp.rc_startblock != agbno + aglen)
|
||||
return 0;
|
||||
if ((flags & XFS_FIND_RCEXT_SHARED) && tmp.rc_refcount < 2)
|
||||
return 0;
|
||||
if ((flags & XFS_FIND_RCEXT_COW) && tmp.rc_refcount > 1)
|
||||
return 0;
|
||||
/* We have a right extent; retrieve (or invent) the next left one */
|
||||
*right = tmp;
|
||||
|
||||
|
@ -744,6 +770,9 @@ xfs_refcount_find_right_extents(
|
|||
goto out_error;
|
||||
}
|
||||
|
||||
if (tmp.rc_domain != domain)
|
||||
goto not_found;
|
||||
|
||||
/* if tmp ends at the end of our range, just use that */
|
||||
if (xfs_refc_next(&tmp) == agbno + aglen)
|
||||
*cright = tmp;
|
||||
|
@ -760,8 +789,10 @@ xfs_refcount_find_right_extents(
|
|||
cright->rc_blockcount = right->rc_startblock -
|
||||
cright->rc_startblock;
|
||||
cright->rc_refcount = 1;
|
||||
cright->rc_domain = domain;
|
||||
}
|
||||
} else {
|
||||
not_found:
|
||||
/*
|
||||
* No extents, so pretend that there's one covering the whole
|
||||
* range.
|
||||
|
@ -769,6 +800,7 @@ xfs_refcount_find_right_extents(
|
|||
cright->rc_startblock = agbno;
|
||||
cright->rc_blockcount = aglen;
|
||||
cright->rc_refcount = 1;
|
||||
cright->rc_domain = domain;
|
||||
}
|
||||
trace_xfs_refcount_find_right_extent(cur->bc_mp, cur->bc_ag.pag->pag_agno,
|
||||
cright, right, agbno + aglen);
|
||||
|
@ -794,10 +826,10 @@ xfs_refc_valid(
|
|||
STATIC int
|
||||
xfs_refcount_merge_extents(
|
||||
struct xfs_btree_cur *cur,
|
||||
enum xfs_refc_domain domain,
|
||||
xfs_agblock_t *agbno,
|
||||
xfs_extlen_t *aglen,
|
||||
enum xfs_refc_adjust_op adjust,
|
||||
int flags,
|
||||
bool *shape_changed)
|
||||
{
|
||||
struct xfs_refcount_irec left = {0}, cleft = {0};
|
||||
|
@ -812,12 +844,12 @@ xfs_refcount_merge_extents(
|
|||
* just below (agbno + aglen) [cright], and just above (agbno + aglen)
|
||||
* [right].
|
||||
*/
|
||||
error = xfs_refcount_find_left_extents(cur, &left, &cleft, *agbno,
|
||||
*aglen, flags);
|
||||
error = xfs_refcount_find_left_extents(cur, &left, &cleft, domain,
|
||||
*agbno, *aglen);
|
||||
if (error)
|
||||
return error;
|
||||
error = xfs_refcount_find_right_extents(cur, &right, &cright, *agbno,
|
||||
*aglen, flags);
|
||||
error = xfs_refcount_find_right_extents(cur, &right, &cright, domain,
|
||||
*agbno, *aglen);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
@ -870,7 +902,7 @@ xfs_refcount_merge_extents(
|
|||
aglen);
|
||||
}
|
||||
|
||||
return error;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -933,7 +965,8 @@ xfs_refcount_adjust_extents(
|
|||
if (*aglen == 0)
|
||||
return 0;
|
||||
|
||||
error = xfs_refcount_lookup_ge(cur, *agbno, &found_rec);
|
||||
error = xfs_refcount_lookup_ge(cur, XFS_REFC_DOMAIN_SHARED, *agbno,
|
||||
&found_rec);
|
||||
if (error)
|
||||
goto out_error;
|
||||
|
||||
|
@ -941,10 +974,11 @@ xfs_refcount_adjust_extents(
|
|||
error = xfs_refcount_get_rec(cur, &ext, &found_rec);
|
||||
if (error)
|
||||
goto out_error;
|
||||
if (!found_rec) {
|
||||
if (!found_rec || ext.rc_domain != XFS_REFC_DOMAIN_SHARED) {
|
||||
ext.rc_startblock = cur->bc_mp->m_sb.sb_agblocks;
|
||||
ext.rc_blockcount = 0;
|
||||
ext.rc_refcount = 0;
|
||||
ext.rc_domain = XFS_REFC_DOMAIN_SHARED;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -957,6 +991,8 @@ xfs_refcount_adjust_extents(
|
|||
tmp.rc_blockcount = min(*aglen,
|
||||
ext.rc_startblock - *agbno);
|
||||
tmp.rc_refcount = 1 + adj;
|
||||
tmp.rc_domain = XFS_REFC_DOMAIN_SHARED;
|
||||
|
||||
trace_xfs_refcount_modify_extent(cur->bc_mp,
|
||||
cur->bc_ag.pag->pag_agno, &tmp);
|
||||
|
||||
|
@ -986,15 +1022,30 @@ xfs_refcount_adjust_extents(
|
|||
(*agbno) += tmp.rc_blockcount;
|
||||
(*aglen) -= tmp.rc_blockcount;
|
||||
|
||||
error = xfs_refcount_lookup_ge(cur, *agbno,
|
||||
/* Stop if there's nothing left to modify */
|
||||
if (*aglen == 0 || !xfs_refcount_still_have_space(cur))
|
||||
break;
|
||||
|
||||
/* Move the cursor to the start of ext. */
|
||||
error = xfs_refcount_lookup_ge(cur,
|
||||
XFS_REFC_DOMAIN_SHARED, *agbno,
|
||||
&found_rec);
|
||||
if (error)
|
||||
goto out_error;
|
||||
}
|
||||
|
||||
/* Stop if there's nothing left to modify */
|
||||
if (*aglen == 0 || !xfs_refcount_still_have_space(cur))
|
||||
break;
|
||||
/*
|
||||
* A previous step trimmed agbno/aglen such that the end of the
|
||||
* range would not be in the middle of the record. If this is
|
||||
* no longer the case, something is seriously wrong with the
|
||||
* btree. Make sure we never feed the synthesized record into
|
||||
* the processing loop below.
|
||||
*/
|
||||
if (XFS_IS_CORRUPT(cur->bc_mp, ext.rc_blockcount == 0) ||
|
||||
XFS_IS_CORRUPT(cur->bc_mp, ext.rc_blockcount > *aglen)) {
|
||||
error = -EFSCORRUPTED;
|
||||
goto out_error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adjust the reference count and either update the tree
|
||||
|
@ -1070,13 +1121,15 @@ xfs_refcount_adjust(
|
|||
/*
|
||||
* Ensure that no rcextents cross the boundary of the adjustment range.
|
||||
*/
|
||||
error = xfs_refcount_split_extent(cur, agbno, &shape_changed);
|
||||
error = xfs_refcount_split_extent(cur, XFS_REFC_DOMAIN_SHARED,
|
||||
agbno, &shape_changed);
|
||||
if (error)
|
||||
goto out_error;
|
||||
if (shape_changed)
|
||||
shape_changes++;
|
||||
|
||||
error = xfs_refcount_split_extent(cur, agbno + aglen, &shape_changed);
|
||||
error = xfs_refcount_split_extent(cur, XFS_REFC_DOMAIN_SHARED,
|
||||
agbno + aglen, &shape_changed);
|
||||
if (error)
|
||||
goto out_error;
|
||||
if (shape_changed)
|
||||
|
@ -1085,8 +1138,8 @@ xfs_refcount_adjust(
|
|||
/*
|
||||
* Try to merge with the left or right extents of the range.
|
||||
*/
|
||||
error = xfs_refcount_merge_extents(cur, new_agbno, new_aglen, adj,
|
||||
XFS_FIND_RCEXT_SHARED, &shape_changed);
|
||||
error = xfs_refcount_merge_extents(cur, XFS_REFC_DOMAIN_SHARED,
|
||||
new_agbno, new_aglen, adj, &shape_changed);
|
||||
if (error)
|
||||
goto out_error;
|
||||
if (shape_changed)
|
||||
|
@ -1124,6 +1177,32 @@ xfs_refcount_finish_one_cleanup(
|
|||
xfs_trans_brelse(tp, agbp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up a continuation a deferred refcount operation by updating the intent.
|
||||
* Checks to make sure we're not going to run off the end of the AG.
|
||||
*/
|
||||
static inline int
|
||||
xfs_refcount_continue_op(
|
||||
struct xfs_btree_cur *cur,
|
||||
xfs_fsblock_t startblock,
|
||||
xfs_agblock_t new_agbno,
|
||||
xfs_extlen_t new_len,
|
||||
xfs_fsblock_t *new_fsbno)
|
||||
{
|
||||
struct xfs_mount *mp = cur->bc_mp;
|
||||
struct xfs_perag *pag = cur->bc_ag.pag;
|
||||
|
||||
if (XFS_IS_CORRUPT(mp, !xfs_verify_agbext(pag, new_agbno, new_len)))
|
||||
return -EFSCORRUPTED;
|
||||
|
||||
*new_fsbno = XFS_AGB_TO_FSB(mp, pag->pag_agno, new_agbno);
|
||||
|
||||
ASSERT(xfs_verify_fsbext(mp, *new_fsbno, new_len));
|
||||
ASSERT(pag->pag_agno == XFS_FSB_TO_AGNO(mp, *new_fsbno));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process one of the deferred refcount operations. We pass back the
|
||||
* btree cursor to maintain our lock on the btree between calls.
|
||||
|
@ -1191,12 +1270,20 @@ xfs_refcount_finish_one(
|
|||
case XFS_REFCOUNT_INCREASE:
|
||||
error = xfs_refcount_adjust(rcur, bno, blockcount, &new_agbno,
|
||||
new_len, XFS_REFCOUNT_ADJUST_INCREASE);
|
||||
*new_fsb = XFS_AGB_TO_FSB(mp, pag->pag_agno, new_agbno);
|
||||
if (error)
|
||||
goto out_drop;
|
||||
if (*new_len > 0)
|
||||
error = xfs_refcount_continue_op(rcur, startblock,
|
||||
new_agbno, *new_len, new_fsb);
|
||||
break;
|
||||
case XFS_REFCOUNT_DECREASE:
|
||||
error = xfs_refcount_adjust(rcur, bno, blockcount, &new_agbno,
|
||||
new_len, XFS_REFCOUNT_ADJUST_DECREASE);
|
||||
*new_fsb = XFS_AGB_TO_FSB(mp, pag->pag_agno, new_agbno);
|
||||
if (error)
|
||||
goto out_drop;
|
||||
if (*new_len > 0)
|
||||
error = xfs_refcount_continue_op(rcur, startblock,
|
||||
new_agbno, *new_len, new_fsb);
|
||||
break;
|
||||
case XFS_REFCOUNT_ALLOC_COW:
|
||||
*new_fsb = startblock + blockcount;
|
||||
|
@ -1307,7 +1394,8 @@ xfs_refcount_find_shared(
|
|||
*flen = 0;
|
||||
|
||||
/* Try to find a refcount extent that crosses the start */
|
||||
error = xfs_refcount_lookup_le(cur, agbno, &have);
|
||||
error = xfs_refcount_lookup_le(cur, XFS_REFC_DOMAIN_SHARED, agbno,
|
||||
&have);
|
||||
if (error)
|
||||
goto out_error;
|
||||
if (!have) {
|
||||
|
@ -1325,6 +1413,8 @@ xfs_refcount_find_shared(
|
|||
error = -EFSCORRUPTED;
|
||||
goto out_error;
|
||||
}
|
||||
if (tmp.rc_domain != XFS_REFC_DOMAIN_SHARED)
|
||||
goto done;
|
||||
|
||||
/* If the extent ends before the start, look at the next one */
|
||||
if (tmp.rc_startblock + tmp.rc_blockcount <= agbno) {
|
||||
|
@ -1340,6 +1430,8 @@ xfs_refcount_find_shared(
|
|||
error = -EFSCORRUPTED;
|
||||
goto out_error;
|
||||
}
|
||||
if (tmp.rc_domain != XFS_REFC_DOMAIN_SHARED)
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* If the extent starts after the range we want, bail out */
|
||||
|
@ -1371,7 +1463,8 @@ xfs_refcount_find_shared(
|
|||
error = -EFSCORRUPTED;
|
||||
goto out_error;
|
||||
}
|
||||
if (tmp.rc_startblock >= agbno + aglen ||
|
||||
if (tmp.rc_domain != XFS_REFC_DOMAIN_SHARED ||
|
||||
tmp.rc_startblock >= agbno + aglen ||
|
||||
tmp.rc_startblock != *fbno + *flen)
|
||||
break;
|
||||
*flen = min(*flen + tmp.rc_blockcount, agbno + aglen - *fbno);
|
||||
|
@ -1455,17 +1548,23 @@ xfs_refcount_adjust_cow_extents(
|
|||
return 0;
|
||||
|
||||
/* Find any overlapping refcount records */
|
||||
error = xfs_refcount_lookup_ge(cur, agbno, &found_rec);
|
||||
error = xfs_refcount_lookup_ge(cur, XFS_REFC_DOMAIN_COW, agbno,
|
||||
&found_rec);
|
||||
if (error)
|
||||
goto out_error;
|
||||
error = xfs_refcount_get_rec(cur, &ext, &found_rec);
|
||||
if (error)
|
||||
goto out_error;
|
||||
if (XFS_IS_CORRUPT(cur->bc_mp, found_rec &&
|
||||
ext.rc_domain != XFS_REFC_DOMAIN_COW)) {
|
||||
error = -EFSCORRUPTED;
|
||||
goto out_error;
|
||||
}
|
||||
if (!found_rec) {
|
||||
ext.rc_startblock = cur->bc_mp->m_sb.sb_agblocks +
|
||||
XFS_REFC_COW_START;
|
||||
ext.rc_startblock = cur->bc_mp->m_sb.sb_agblocks;
|
||||
ext.rc_blockcount = 0;
|
||||
ext.rc_refcount = 0;
|
||||
ext.rc_domain = XFS_REFC_DOMAIN_COW;
|
||||
}
|
||||
|
||||
switch (adj) {
|
||||
|
@ -1480,6 +1579,8 @@ xfs_refcount_adjust_cow_extents(
|
|||
tmp.rc_startblock = agbno;
|
||||
tmp.rc_blockcount = aglen;
|
||||
tmp.rc_refcount = 1;
|
||||
tmp.rc_domain = XFS_REFC_DOMAIN_COW;
|
||||
|
||||
trace_xfs_refcount_modify_extent(cur->bc_mp,
|
||||
cur->bc_ag.pag->pag_agno, &tmp);
|
||||
|
||||
|
@ -1542,24 +1643,24 @@ xfs_refcount_adjust_cow(
|
|||
bool shape_changed;
|
||||
int error;
|
||||
|
||||
agbno += XFS_REFC_COW_START;
|
||||
|
||||
/*
|
||||
* Ensure that no rcextents cross the boundary of the adjustment range.
|
||||
*/
|
||||
error = xfs_refcount_split_extent(cur, agbno, &shape_changed);
|
||||
error = xfs_refcount_split_extent(cur, XFS_REFC_DOMAIN_COW,
|
||||
agbno, &shape_changed);
|
||||
if (error)
|
||||
goto out_error;
|
||||
|
||||
error = xfs_refcount_split_extent(cur, agbno + aglen, &shape_changed);
|
||||
error = xfs_refcount_split_extent(cur, XFS_REFC_DOMAIN_COW,
|
||||
agbno + aglen, &shape_changed);
|
||||
if (error)
|
||||
goto out_error;
|
||||
|
||||
/*
|
||||
* Try to merge with the left or right extents of the range.
|
||||
*/
|
||||
error = xfs_refcount_merge_extents(cur, &agbno, &aglen, adj,
|
||||
XFS_FIND_RCEXT_COW, &shape_changed);
|
||||
error = xfs_refcount_merge_extents(cur, XFS_REFC_DOMAIN_COW, &agbno,
|
||||
&aglen, adj, &shape_changed);
|
||||
if (error)
|
||||
goto out_error;
|
||||
|
||||
|
@ -1666,10 +1767,18 @@ xfs_refcount_recover_extent(
|
|||
be32_to_cpu(rec->refc.rc_refcount) != 1))
|
||||
return -EFSCORRUPTED;
|
||||
|
||||
rr = kmem_alloc(sizeof(struct xfs_refcount_recovery), 0);
|
||||
rr = kmalloc(sizeof(struct xfs_refcount_recovery),
|
||||
GFP_KERNEL | __GFP_NOFAIL);
|
||||
INIT_LIST_HEAD(&rr->rr_list);
|
||||
xfs_refcount_btrec_to_irec(rec, &rr->rr_rrec);
|
||||
list_add_tail(&rr->rr_list, debris);
|
||||
|
||||
if (XFS_IS_CORRUPT(cur->bc_mp,
|
||||
rr->rr_rrec.rc_domain != XFS_REFC_DOMAIN_COW)) {
|
||||
kfree(rr);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
list_add_tail(&rr->rr_list, debris);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1687,10 +1796,11 @@ xfs_refcount_recover_cow_leftovers(
|
|||
union xfs_btree_irec low;
|
||||
union xfs_btree_irec high;
|
||||
xfs_fsblock_t fsb;
|
||||
xfs_agblock_t agbno;
|
||||
int error;
|
||||
|
||||
if (mp->m_sb.sb_agblocks >= XFS_REFC_COW_START)
|
||||
/* reflink filesystems mustn't have AGs larger than 2^31-1 blocks */
|
||||
BUILD_BUG_ON(XFS_MAX_CRC_AG_BLOCKS >= XFS_REFC_COWFLAG);
|
||||
if (mp->m_sb.sb_agblocks > XFS_MAX_CRC_AG_BLOCKS)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
INIT_LIST_HEAD(&debris);
|
||||
|
@ -1717,7 +1827,7 @@ xfs_refcount_recover_cow_leftovers(
|
|||
/* Find all the leftover CoW staging extents. */
|
||||
memset(&low, 0, sizeof(low));
|
||||
memset(&high, 0, sizeof(high));
|
||||
low.rc.rc_startblock = XFS_REFC_COW_START;
|
||||
low.rc.rc_domain = high.rc.rc_domain = XFS_REFC_DOMAIN_COW;
|
||||
high.rc.rc_startblock = -1U;
|
||||
error = xfs_btree_query_range(cur, &low, &high,
|
||||
xfs_refcount_recover_extent, &debris);
|
||||
|
@ -1738,8 +1848,8 @@ xfs_refcount_recover_cow_leftovers(
|
|||
&rr->rr_rrec);
|
||||
|
||||
/* Free the orphan record */
|
||||
agbno = rr->rr_rrec.rc_startblock - XFS_REFC_COW_START;
|
||||
fsb = XFS_AGB_TO_FSB(mp, pag->pag_agno, agbno);
|
||||
fsb = XFS_AGB_TO_FSB(mp, pag->pag_agno,
|
||||
rr->rr_rrec.rc_startblock);
|
||||
xfs_refcount_free_cow_extent(tp, fsb,
|
||||
rr->rr_rrec.rc_blockcount);
|
||||
|
||||
|
@ -1751,7 +1861,7 @@ xfs_refcount_recover_cow_leftovers(
|
|||
goto out_free;
|
||||
|
||||
list_del(&rr->rr_list);
|
||||
kmem_free(rr);
|
||||
kfree(rr);
|
||||
}
|
||||
|
||||
return error;
|
||||
|
@ -1761,7 +1871,7 @@ out_free:
|
|||
/* Free the leftover list */
|
||||
list_for_each_entry_safe(rr, n, &debris, rr_list) {
|
||||
list_del(&rr->rr_list);
|
||||
kmem_free(rr);
|
||||
kfree(rr);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
@ -1770,6 +1880,7 @@ out_free:
|
|||
int
|
||||
xfs_refcount_has_record(
|
||||
struct xfs_btree_cur *cur,
|
||||
enum xfs_refc_domain domain,
|
||||
xfs_agblock_t bno,
|
||||
xfs_extlen_t len,
|
||||
bool *exists)
|
||||
|
@ -1781,6 +1892,7 @@ xfs_refcount_has_record(
|
|||
low.rc.rc_startblock = bno;
|
||||
memset(&high, 0xFF, sizeof(high));
|
||||
high.rc.rc_startblock = bno + len - 1;
|
||||
low.rc.rc_domain = high.rc.rc_domain = domain;
|
||||
|
||||
return xfs_btree_has_record(cur, &low, &high, exists);
|
||||
}
|
||||
|
|
|
@ -14,14 +14,33 @@ struct xfs_bmbt_irec;
|
|||
struct xfs_refcount_irec;
|
||||
|
||||
extern int xfs_refcount_lookup_le(struct xfs_btree_cur *cur,
|
||||
xfs_agblock_t bno, int *stat);
|
||||
enum xfs_refc_domain domain, xfs_agblock_t bno, int *stat);
|
||||
extern int xfs_refcount_lookup_ge(struct xfs_btree_cur *cur,
|
||||
xfs_agblock_t bno, int *stat);
|
||||
enum xfs_refc_domain domain, xfs_agblock_t bno, int *stat);
|
||||
extern int xfs_refcount_lookup_eq(struct xfs_btree_cur *cur,
|
||||
xfs_agblock_t bno, int *stat);
|
||||
enum xfs_refc_domain domain, xfs_agblock_t bno, int *stat);
|
||||
extern int xfs_refcount_get_rec(struct xfs_btree_cur *cur,
|
||||
struct xfs_refcount_irec *irec, int *stat);
|
||||
|
||||
static inline uint32_t
|
||||
xfs_refcount_encode_startblock(
|
||||
xfs_agblock_t startblock,
|
||||
enum xfs_refc_domain domain)
|
||||
{
|
||||
uint32_t start;
|
||||
|
||||
/*
|
||||
* low level btree operations need to handle the generic btree range
|
||||
* query functions (which set rc_domain == -1U), so we check that the
|
||||
* domain is /not/ shared.
|
||||
*/
|
||||
start = startblock & ~XFS_REFC_COWFLAG;
|
||||
if (domain != XFS_REFC_DOMAIN_SHARED)
|
||||
start |= XFS_REFC_COWFLAG;
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
enum xfs_refcount_intent_type {
|
||||
XFS_REFCOUNT_INCREASE = 1,
|
||||
XFS_REFCOUNT_DECREASE,
|
||||
|
@ -36,6 +55,18 @@ struct xfs_refcount_intent {
|
|||
xfs_fsblock_t ri_startblock;
|
||||
};
|
||||
|
||||
/* Check that the refcount is appropriate for the record domain. */
|
||||
static inline bool
|
||||
xfs_refcount_check_domain(
|
||||
const struct xfs_refcount_irec *irec)
|
||||
{
|
||||
if (irec->rc_domain == XFS_REFC_DOMAIN_COW && irec->rc_refcount != 1)
|
||||
return false;
|
||||
if (irec->rc_domain == XFS_REFC_DOMAIN_SHARED && irec->rc_refcount < 2)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void xfs_refcount_increase_extent(struct xfs_trans *tp,
|
||||
struct xfs_bmbt_irec *irec);
|
||||
void xfs_refcount_decrease_extent(struct xfs_trans *tp,
|
||||
|
@ -79,7 +110,8 @@ extern int xfs_refcount_recover_cow_leftovers(struct xfs_mount *mp,
|
|||
#define XFS_REFCOUNT_ITEM_OVERHEAD 32
|
||||
|
||||
extern int xfs_refcount_has_record(struct xfs_btree_cur *cur,
|
||||
xfs_agblock_t bno, xfs_extlen_t len, bool *exists);
|
||||
enum xfs_refc_domain domain, xfs_agblock_t bno,
|
||||
xfs_extlen_t len, bool *exists);
|
||||
union xfs_btree_rec;
|
||||
extern void xfs_refcount_btrec_to_irec(const union xfs_btree_rec *rec,
|
||||
struct xfs_refcount_irec *irec);
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "xfs_btree.h"
|
||||
#include "xfs_btree_staging.h"
|
||||
#include "xfs_refcount_btree.h"
|
||||
#include "xfs_refcount.h"
|
||||
#include "xfs_alloc.h"
|
||||
#include "xfs_error.h"
|
||||
#include "xfs_trace.h"
|
||||
|
@ -160,7 +161,12 @@ xfs_refcountbt_init_rec_from_cur(
|
|||
struct xfs_btree_cur *cur,
|
||||
union xfs_btree_rec *rec)
|
||||
{
|
||||
rec->refc.rc_startblock = cpu_to_be32(cur->bc_rec.rc.rc_startblock);
|
||||
const struct xfs_refcount_irec *irec = &cur->bc_rec.rc;
|
||||
uint32_t start;
|
||||
|
||||
start = xfs_refcount_encode_startblock(irec->rc_startblock,
|
||||
irec->rc_domain);
|
||||
rec->refc.rc_startblock = cpu_to_be32(start);
|
||||
rec->refc.rc_blockcount = cpu_to_be32(cur->bc_rec.rc.rc_blockcount);
|
||||
rec->refc.rc_refcount = cpu_to_be32(cur->bc_rec.rc.rc_refcount);
|
||||
}
|
||||
|
@ -182,10 +188,13 @@ xfs_refcountbt_key_diff(
|
|||
struct xfs_btree_cur *cur,
|
||||
const union xfs_btree_key *key)
|
||||
{
|
||||
struct xfs_refcount_irec *rec = &cur->bc_rec.rc;
|
||||
const struct xfs_refcount_key *kp = &key->refc;
|
||||
const struct xfs_refcount_irec *irec = &cur->bc_rec.rc;
|
||||
uint32_t start;
|
||||
|
||||
return (int64_t)be32_to_cpu(kp->rc_startblock) - rec->rc_startblock;
|
||||
start = xfs_refcount_encode_startblock(irec->rc_startblock,
|
||||
irec->rc_domain);
|
||||
return (int64_t)be32_to_cpu(kp->rc_startblock) - start;
|
||||
}
|
||||
|
||||
STATIC int64_t
|
||||
|
|
|
@ -235,13 +235,8 @@ xfs_rmap_get_rec(
|
|||
goto out_bad_rec;
|
||||
} else {
|
||||
/* check for valid extent range, including overflow */
|
||||
if (!xfs_verify_agbno(pag, irec->rm_startblock))
|
||||
goto out_bad_rec;
|
||||
if (irec->rm_startblock >
|
||||
irec->rm_startblock + irec->rm_blockcount)
|
||||
goto out_bad_rec;
|
||||
if (!xfs_verify_agbno(pag,
|
||||
irec->rm_startblock + irec->rm_blockcount - 1))
|
||||
if (!xfs_verify_agbext(pag, irec->rm_startblock,
|
||||
irec->rm_blockcount))
|
||||
goto out_bad_rec;
|
||||
}
|
||||
|
||||
|
|
|
@ -422,7 +422,7 @@ xfs_calc_itruncate_reservation_minlogsize(
|
|||
|
||||
/*
|
||||
* In renaming a files we can modify:
|
||||
* the four inodes involved: 4 * inode size
|
||||
* the five inodes involved: 5 * inode size
|
||||
* the two directory btrees: 2 * (max depth + v2) * dir block size
|
||||
* the two directory bmap btrees: 2 * max depth * block size
|
||||
* And the bmap_finish transaction can free dir and bmap blocks (two sets
|
||||
|
@ -437,7 +437,7 @@ xfs_calc_rename_reservation(
|
|||
struct xfs_mount *mp)
|
||||
{
|
||||
return XFS_DQUOT_LOGRES(mp) +
|
||||
max((xfs_calc_inode_res(mp, 4) +
|
||||
max((xfs_calc_inode_res(mp, 5) +
|
||||
xfs_calc_buf_res(2 * XFS_DIROP_LOG_COUNT(mp),
|
||||
XFS_FSB_TO_B(mp, 1))),
|
||||
(xfs_calc_buf_res(7, mp->m_sb.sb_sectsize) +
|
||||
|
|
|
@ -166,6 +166,36 @@ typedef struct xfs_bmbt_irec
|
|||
xfs_exntst_t br_state; /* extent state */
|
||||
} xfs_bmbt_irec_t;
|
||||
|
||||
enum xfs_refc_domain {
|
||||
XFS_REFC_DOMAIN_SHARED = 0,
|
||||
XFS_REFC_DOMAIN_COW,
|
||||
};
|
||||
|
||||
#define XFS_REFC_DOMAIN_STRINGS \
|
||||
{ XFS_REFC_DOMAIN_SHARED, "shared" }, \
|
||||
{ XFS_REFC_DOMAIN_COW, "cow" }
|
||||
|
||||
struct xfs_refcount_irec {
|
||||
xfs_agblock_t rc_startblock; /* starting block number */
|
||||
xfs_extlen_t rc_blockcount; /* count of free blocks */
|
||||
xfs_nlink_t rc_refcount; /* number of inodes linked here */
|
||||
enum xfs_refc_domain rc_domain; /* shared or cow staging extent? */
|
||||
};
|
||||
|
||||
#define XFS_RMAP_ATTR_FORK (1 << 0)
|
||||
#define XFS_RMAP_BMBT_BLOCK (1 << 1)
|
||||
#define XFS_RMAP_UNWRITTEN (1 << 2)
|
||||
#define XFS_RMAP_KEY_FLAGS (XFS_RMAP_ATTR_FORK | \
|
||||
XFS_RMAP_BMBT_BLOCK)
|
||||
#define XFS_RMAP_REC_FLAGS (XFS_RMAP_UNWRITTEN)
|
||||
struct xfs_rmap_irec {
|
||||
xfs_agblock_t rm_startblock; /* extent start block */
|
||||
xfs_extlen_t rm_blockcount; /* extent length */
|
||||
uint64_t rm_owner; /* extent owner */
|
||||
uint64_t rm_offset; /* offset within the owner */
|
||||
unsigned int rm_flags; /* state flags */
|
||||
};
|
||||
|
||||
/* per-AG block reservation types */
|
||||
enum xfs_ag_resv_type {
|
||||
XFS_AG_RESV_NONE = 0,
|
||||
|
|
|
@ -100,9 +100,7 @@ xchk_allocbt_rec(
|
|||
bno = be32_to_cpu(rec->alloc.ar_startblock);
|
||||
len = be32_to_cpu(rec->alloc.ar_blockcount);
|
||||
|
||||
if (bno + len <= bno ||
|
||||
!xfs_verify_agbno(pag, bno) ||
|
||||
!xfs_verify_agbno(pag, bno + len - 1))
|
||||
if (!xfs_verify_agbext(pag, bno, len))
|
||||
xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
|
||||
|
||||
xchk_allocbt_xref(bs->sc, bno, len);
|
||||
|
|
|
@ -108,9 +108,8 @@ xchk_iallocbt_chunk(
|
|||
xfs_agblock_t bno;
|
||||
|
||||
bno = XFS_AGINO_TO_AGBNO(mp, agino);
|
||||
if (bno + len <= bno ||
|
||||
!xfs_verify_agbno(pag, bno) ||
|
||||
!xfs_verify_agbno(pag, bno + len - 1))
|
||||
|
||||
if (!xfs_verify_agbext(pag, bno, len))
|
||||
xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
|
||||
|
||||
xchk_iallocbt_chunk_xref(bs->sc, irec, agino, bno, len);
|
||||
|
|
|
@ -269,15 +269,13 @@ done:
|
|||
STATIC void
|
||||
xchk_refcountbt_xref_rmap(
|
||||
struct xfs_scrub *sc,
|
||||
xfs_agblock_t bno,
|
||||
xfs_extlen_t len,
|
||||
xfs_nlink_t refcount)
|
||||
const struct xfs_refcount_irec *irec)
|
||||
{
|
||||
struct xchk_refcnt_check refchk = {
|
||||
.sc = sc,
|
||||
.bno = bno,
|
||||
.len = len,
|
||||
.refcount = refcount,
|
||||
.sc = sc,
|
||||
.bno = irec->rc_startblock,
|
||||
.len = irec->rc_blockcount,
|
||||
.refcount = irec->rc_refcount,
|
||||
.seen = 0,
|
||||
};
|
||||
struct xfs_rmap_irec low;
|
||||
|
@ -291,9 +289,9 @@ xchk_refcountbt_xref_rmap(
|
|||
|
||||
/* Cross-reference with the rmapbt to confirm the refcount. */
|
||||
memset(&low, 0, sizeof(low));
|
||||
low.rm_startblock = bno;
|
||||
low.rm_startblock = irec->rc_startblock;
|
||||
memset(&high, 0xFF, sizeof(high));
|
||||
high.rm_startblock = bno + len - 1;
|
||||
high.rm_startblock = irec->rc_startblock + irec->rc_blockcount - 1;
|
||||
|
||||
INIT_LIST_HEAD(&refchk.fragments);
|
||||
error = xfs_rmap_query_range(sc->sa.rmap_cur, &low, &high,
|
||||
|
@ -302,7 +300,7 @@ xchk_refcountbt_xref_rmap(
|
|||
goto out_free;
|
||||
|
||||
xchk_refcountbt_process_rmap_fragments(&refchk);
|
||||
if (refcount != refchk.seen)
|
||||
if (irec->rc_refcount != refchk.seen)
|
||||
xchk_btree_xref_set_corrupt(sc, sc->sa.rmap_cur, 0);
|
||||
|
||||
out_free:
|
||||
|
@ -315,17 +313,16 @@ out_free:
|
|||
/* Cross-reference with the other btrees. */
|
||||
STATIC void
|
||||
xchk_refcountbt_xref(
|
||||
struct xfs_scrub *sc,
|
||||
xfs_agblock_t agbno,
|
||||
xfs_extlen_t len,
|
||||
xfs_nlink_t refcount)
|
||||
struct xfs_scrub *sc,
|
||||
const struct xfs_refcount_irec *irec)
|
||||
{
|
||||
if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
|
||||
return;
|
||||
|
||||
xchk_xref_is_used_space(sc, agbno, len);
|
||||
xchk_xref_is_not_inode_chunk(sc, agbno, len);
|
||||
xchk_refcountbt_xref_rmap(sc, agbno, len, refcount);
|
||||
xchk_xref_is_used_space(sc, irec->rc_startblock, irec->rc_blockcount);
|
||||
xchk_xref_is_not_inode_chunk(sc, irec->rc_startblock,
|
||||
irec->rc_blockcount);
|
||||
xchk_refcountbt_xref_rmap(sc, irec);
|
||||
}
|
||||
|
||||
/* Scrub a refcountbt record. */
|
||||
|
@ -334,35 +331,27 @@ xchk_refcountbt_rec(
|
|||
struct xchk_btree *bs,
|
||||
const union xfs_btree_rec *rec)
|
||||
{
|
||||
struct xfs_refcount_irec irec;
|
||||
xfs_agblock_t *cow_blocks = bs->private;
|
||||
struct xfs_perag *pag = bs->cur->bc_ag.pag;
|
||||
xfs_agblock_t bno;
|
||||
xfs_extlen_t len;
|
||||
xfs_nlink_t refcount;
|
||||
bool has_cowflag;
|
||||
|
||||
bno = be32_to_cpu(rec->refc.rc_startblock);
|
||||
len = be32_to_cpu(rec->refc.rc_blockcount);
|
||||
refcount = be32_to_cpu(rec->refc.rc_refcount);
|
||||
xfs_refcount_btrec_to_irec(rec, &irec);
|
||||
|
||||
/* Only CoW records can have refcount == 1. */
|
||||
has_cowflag = (bno & XFS_REFC_COW_START);
|
||||
if ((refcount == 1 && !has_cowflag) || (refcount != 1 && has_cowflag))
|
||||
/* Check the domain and refcount are not incompatible. */
|
||||
if (!xfs_refcount_check_domain(&irec))
|
||||
xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
|
||||
if (has_cowflag)
|
||||
(*cow_blocks) += len;
|
||||
|
||||
if (irec.rc_domain == XFS_REFC_DOMAIN_COW)
|
||||
(*cow_blocks) += irec.rc_blockcount;
|
||||
|
||||
/* Check the extent. */
|
||||
bno &= ~XFS_REFC_COW_START;
|
||||
if (bno + len <= bno ||
|
||||
!xfs_verify_agbno(pag, bno) ||
|
||||
!xfs_verify_agbno(pag, bno + len - 1))
|
||||
if (!xfs_verify_agbext(pag, irec.rc_startblock, irec.rc_blockcount))
|
||||
xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
|
||||
|
||||
if (refcount == 0)
|
||||
if (irec.rc_refcount == 0)
|
||||
xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
|
||||
|
||||
xchk_refcountbt_xref(bs->sc, bno, len, refcount);
|
||||
xchk_refcountbt_xref(bs->sc, &irec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -426,7 +415,6 @@ xchk_xref_is_cow_staging(
|
|||
xfs_extlen_t len)
|
||||
{
|
||||
struct xfs_refcount_irec rc;
|
||||
bool has_cowflag;
|
||||
int has_refcount;
|
||||
int error;
|
||||
|
||||
|
@ -434,8 +422,8 @@ xchk_xref_is_cow_staging(
|
|||
return;
|
||||
|
||||
/* Find the CoW staging extent. */
|
||||
error = xfs_refcount_lookup_le(sc->sa.refc_cur,
|
||||
agbno + XFS_REFC_COW_START, &has_refcount);
|
||||
error = xfs_refcount_lookup_le(sc->sa.refc_cur, XFS_REFC_DOMAIN_COW,
|
||||
agbno, &has_refcount);
|
||||
if (!xchk_should_check_xref(sc, &error, &sc->sa.refc_cur))
|
||||
return;
|
||||
if (!has_refcount) {
|
||||
|
@ -451,9 +439,8 @@ xchk_xref_is_cow_staging(
|
|||
return;
|
||||
}
|
||||
|
||||
/* CoW flag must be set, refcount must be 1. */
|
||||
has_cowflag = (rc.rc_startblock & XFS_REFC_COW_START);
|
||||
if (!has_cowflag || rc.rc_refcount != 1)
|
||||
/* CoW lookup returned a shared extent record? */
|
||||
if (rc.rc_domain != XFS_REFC_DOMAIN_COW)
|
||||
xchk_btree_xref_set_corrupt(sc, sc->sa.refc_cur, 0);
|
||||
|
||||
/* Must be at least as long as what was passed in */
|
||||
|
@ -477,7 +464,8 @@ xchk_xref_is_not_shared(
|
|||
if (!sc->sa.refc_cur || xchk_skip_xref(sc->sm))
|
||||
return;
|
||||
|
||||
error = xfs_refcount_has_record(sc->sa.refc_cur, agbno, len, &shared);
|
||||
error = xfs_refcount_has_record(sc->sa.refc_cur, XFS_REFC_DOMAIN_SHARED,
|
||||
agbno, len, &shared);
|
||||
if (!xchk_should_check_xref(sc, &error, &sc->sa.refc_cur))
|
||||
return;
|
||||
if (shared)
|
||||
|
|
|
@ -245,28 +245,6 @@ xfs_attri_init(
|
|||
return attrip;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy an attr format buffer from the given buf, and into the destination attr
|
||||
* format structure.
|
||||
*/
|
||||
STATIC int
|
||||
xfs_attri_copy_format(
|
||||
struct xfs_log_iovec *buf,
|
||||
struct xfs_attri_log_format *dst_attr_fmt)
|
||||
{
|
||||
struct xfs_attri_log_format *src_attr_fmt = buf->i_addr;
|
||||
size_t len;
|
||||
|
||||
len = sizeof(struct xfs_attri_log_format);
|
||||
if (buf->i_len != len) {
|
||||
XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, NULL);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
memcpy((char *)dst_attr_fmt, (char *)src_attr_fmt, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct xfs_attrd_log_item *ATTRD_ITEM(struct xfs_log_item *lip)
|
||||
{
|
||||
return container_of(lip, struct xfs_attrd_log_item, attrd_item);
|
||||
|
@ -731,24 +709,50 @@ xlog_recover_attri_commit_pass2(
|
|||
struct xfs_attri_log_nameval *nv;
|
||||
const void *attr_value = NULL;
|
||||
const void *attr_name;
|
||||
int error;
|
||||
size_t len;
|
||||
|
||||
attri_formatp = item->ri_buf[0].i_addr;
|
||||
attr_name = item->ri_buf[1].i_addr;
|
||||
|
||||
/* Validate xfs_attri_log_format before the large memory allocation */
|
||||
len = sizeof(struct xfs_attri_log_format);
|
||||
if (item->ri_buf[0].i_len != len) {
|
||||
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
|
||||
item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
if (!xfs_attri_validate(mp, attri_formatp)) {
|
||||
XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
|
||||
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
|
||||
item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
/* Validate the attr name */
|
||||
if (item->ri_buf[1].i_len !=
|
||||
xlog_calc_iovec_len(attri_formatp->alfi_name_len)) {
|
||||
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
|
||||
item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
if (!xfs_attr_namecheck(attr_name, attri_formatp->alfi_name_len)) {
|
||||
XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
|
||||
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
|
||||
item->ri_buf[1].i_addr, item->ri_buf[1].i_len);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
if (attri_formatp->alfi_value_len)
|
||||
/* Validate the attr value, if present */
|
||||
if (attri_formatp->alfi_value_len != 0) {
|
||||
if (item->ri_buf[2].i_len != xlog_calc_iovec_len(attri_formatp->alfi_value_len)) {
|
||||
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
|
||||
item->ri_buf[0].i_addr,
|
||||
item->ri_buf[0].i_len);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
attr_value = item->ri_buf[2].i_addr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Memory alloc failure will cause replay to abort. We attach the
|
||||
|
@ -760,9 +764,7 @@ xlog_recover_attri_commit_pass2(
|
|||
attri_formatp->alfi_value_len);
|
||||
|
||||
attrip = xfs_attri_init(mp, nv);
|
||||
error = xfs_attri_copy_format(&item->ri_buf[0], &attrip->attri_format);
|
||||
if (error)
|
||||
goto out;
|
||||
memcpy(&attrip->attri_format, attri_formatp, len);
|
||||
|
||||
/*
|
||||
* The ATTRI has two references. One for the ATTRD and one for ATTRI to
|
||||
|
@ -774,10 +776,6 @@ xlog_recover_attri_commit_pass2(
|
|||
xfs_attri_release(attrip);
|
||||
xfs_attri_log_nameval_put(nv);
|
||||
return 0;
|
||||
out:
|
||||
xfs_attri_item_free(attrip);
|
||||
xfs_attri_log_nameval_put(nv);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -842,7 +840,8 @@ xlog_recover_attrd_commit_pass2(
|
|||
|
||||
attrd_formatp = item->ri_buf[0].i_addr;
|
||||
if (item->ri_buf[0].i_len != sizeof(struct xfs_attrd_log_format)) {
|
||||
XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, NULL);
|
||||
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, log->l_mp,
|
||||
item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
|
|
|
@ -608,28 +608,18 @@ static const struct xfs_item_ops xfs_bui_item_ops = {
|
|||
.iop_relog = xfs_bui_item_relog,
|
||||
};
|
||||
|
||||
/*
|
||||
* Copy an BUI format buffer from the given buf, and into the destination
|
||||
* BUI format structure. The BUI/BUD items were designed not to need any
|
||||
* special alignment handling.
|
||||
*/
|
||||
static int
|
||||
static inline void
|
||||
xfs_bui_copy_format(
|
||||
struct xfs_log_iovec *buf,
|
||||
struct xfs_bui_log_format *dst_bui_fmt)
|
||||
struct xfs_bui_log_format *dst,
|
||||
const struct xfs_bui_log_format *src)
|
||||
{
|
||||
struct xfs_bui_log_format *src_bui_fmt;
|
||||
uint len;
|
||||
unsigned int i;
|
||||
|
||||
src_bui_fmt = buf->i_addr;
|
||||
len = xfs_bui_log_format_sizeof(src_bui_fmt->bui_nextents);
|
||||
memcpy(dst, src, offsetof(struct xfs_bui_log_format, bui_extents));
|
||||
|
||||
if (buf->i_len == len) {
|
||||
memcpy(dst_bui_fmt, src_bui_fmt, len);
|
||||
return 0;
|
||||
}
|
||||
XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, NULL);
|
||||
return -EFSCORRUPTED;
|
||||
for (i = 0; i < src->bui_nextents; i++)
|
||||
memcpy(&dst->bui_extents[i], &src->bui_extents[i],
|
||||
sizeof(struct xfs_map_extent));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -646,23 +636,34 @@ xlog_recover_bui_commit_pass2(
|
|||
struct xlog_recover_item *item,
|
||||
xfs_lsn_t lsn)
|
||||
{
|
||||
int error;
|
||||
struct xfs_mount *mp = log->l_mp;
|
||||
struct xfs_bui_log_item *buip;
|
||||
struct xfs_bui_log_format *bui_formatp;
|
||||
size_t len;
|
||||
|
||||
bui_formatp = item->ri_buf[0].i_addr;
|
||||
|
||||
if (bui_formatp->bui_nextents != XFS_BUI_MAX_FAST_EXTENTS) {
|
||||
XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, log->l_mp);
|
||||
if (item->ri_buf[0].i_len < xfs_bui_log_format_sizeof(0)) {
|
||||
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
|
||||
item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
buip = xfs_bui_init(mp);
|
||||
error = xfs_bui_copy_format(&item->ri_buf[0], &buip->bui_format);
|
||||
if (error) {
|
||||
xfs_bui_item_free(buip);
|
||||
return error;
|
||||
|
||||
if (bui_formatp->bui_nextents != XFS_BUI_MAX_FAST_EXTENTS) {
|
||||
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
|
||||
item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
len = xfs_bui_log_format_sizeof(bui_formatp->bui_nextents);
|
||||
if (item->ri_buf[0].i_len != len) {
|
||||
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
|
||||
item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
buip = xfs_bui_init(mp);
|
||||
xfs_bui_copy_format(&buip->bui_format, bui_formatp);
|
||||
atomic_set(&buip->bui_next_extent, bui_formatp->bui_nextents);
|
||||
/*
|
||||
* Insert the intent into the AIL directly and drop one reference so
|
||||
|
@ -696,7 +697,8 @@ xlog_recover_bud_commit_pass2(
|
|||
|
||||
bud_formatp = item->ri_buf[0].i_addr;
|
||||
if (item->ri_buf[0].i_len != sizeof(struct xfs_bud_log_format)) {
|
||||
XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, log->l_mp);
|
||||
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, log->l_mp,
|
||||
item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
|
|
|
@ -234,13 +234,18 @@ int
|
|||
xfs_errortag_init(
|
||||
struct xfs_mount *mp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mp->m_errortag = kmem_zalloc(sizeof(unsigned int) * XFS_ERRTAG_MAX,
|
||||
KM_MAYFAIL);
|
||||
if (!mp->m_errortag)
|
||||
return -ENOMEM;
|
||||
|
||||
return xfs_sysfs_init(&mp->m_errortag_kobj, &xfs_errortag_ktype,
|
||||
&mp->m_kobj, "errortag");
|
||||
ret = xfs_sysfs_init(&mp->m_errortag_kobj, &xfs_errortag_ktype,
|
||||
&mp->m_kobj, "errortag");
|
||||
if (ret)
|
||||
kmem_free(mp->m_errortag);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -66,27 +66,16 @@ xfs_efi_release(
|
|||
xfs_efi_item_free(efip);
|
||||
}
|
||||
|
||||
/*
|
||||
* This returns the number of iovecs needed to log the given efi item.
|
||||
* We only need 1 iovec for an efi item. It just logs the efi_log_format
|
||||
* structure.
|
||||
*/
|
||||
static inline int
|
||||
xfs_efi_item_sizeof(
|
||||
struct xfs_efi_log_item *efip)
|
||||
{
|
||||
return sizeof(struct xfs_efi_log_format) +
|
||||
(efip->efi_format.efi_nextents - 1) * sizeof(xfs_extent_t);
|
||||
}
|
||||
|
||||
STATIC void
|
||||
xfs_efi_item_size(
|
||||
struct xfs_log_item *lip,
|
||||
int *nvecs,
|
||||
int *nbytes)
|
||||
{
|
||||
struct xfs_efi_log_item *efip = EFI_ITEM(lip);
|
||||
|
||||
*nvecs += 1;
|
||||
*nbytes += xfs_efi_item_sizeof(EFI_ITEM(lip));
|
||||
*nbytes += xfs_efi_log_format_sizeof(efip->efi_format.efi_nextents);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -112,7 +101,7 @@ xfs_efi_item_format(
|
|||
|
||||
xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_EFI_FORMAT,
|
||||
&efip->efi_format,
|
||||
xfs_efi_item_sizeof(efip));
|
||||
xfs_efi_log_format_sizeof(efip->efi_format.efi_nextents));
|
||||
}
|
||||
|
||||
|
||||
|
@ -155,13 +144,11 @@ xfs_efi_init(
|
|||
|
||||
{
|
||||
struct xfs_efi_log_item *efip;
|
||||
uint size;
|
||||
|
||||
ASSERT(nextents > 0);
|
||||
if (nextents > XFS_EFI_MAX_FAST_EXTENTS) {
|
||||
size = (uint)(sizeof(struct xfs_efi_log_item) +
|
||||
((nextents - 1) * sizeof(xfs_extent_t)));
|
||||
efip = kmem_zalloc(size, 0);
|
||||
efip = kzalloc(xfs_efi_log_item_sizeof(nextents),
|
||||
GFP_KERNEL | __GFP_NOFAIL);
|
||||
} else {
|
||||
efip = kmem_cache_zalloc(xfs_efi_cache,
|
||||
GFP_KERNEL | __GFP_NOFAIL);
|
||||
|
@ -188,15 +175,17 @@ xfs_efi_copy_format(xfs_log_iovec_t *buf, xfs_efi_log_format_t *dst_efi_fmt)
|
|||
{
|
||||
xfs_efi_log_format_t *src_efi_fmt = buf->i_addr;
|
||||
uint i;
|
||||
uint len = sizeof(xfs_efi_log_format_t) +
|
||||
(src_efi_fmt->efi_nextents - 1) * sizeof(xfs_extent_t);
|
||||
uint len32 = sizeof(xfs_efi_log_format_32_t) +
|
||||
(src_efi_fmt->efi_nextents - 1) * sizeof(xfs_extent_32_t);
|
||||
uint len64 = sizeof(xfs_efi_log_format_64_t) +
|
||||
(src_efi_fmt->efi_nextents - 1) * sizeof(xfs_extent_64_t);
|
||||
uint len = xfs_efi_log_format_sizeof(src_efi_fmt->efi_nextents);
|
||||
uint len32 = xfs_efi_log_format32_sizeof(src_efi_fmt->efi_nextents);
|
||||
uint len64 = xfs_efi_log_format64_sizeof(src_efi_fmt->efi_nextents);
|
||||
|
||||
if (buf->i_len == len) {
|
||||
memcpy((char *)dst_efi_fmt, (char*)src_efi_fmt, len);
|
||||
memcpy(dst_efi_fmt, src_efi_fmt,
|
||||
offsetof(struct xfs_efi_log_format, efi_extents));
|
||||
for (i = 0; i < src_efi_fmt->efi_nextents; i++)
|
||||
memcpy(&dst_efi_fmt->efi_extents[i],
|
||||
&src_efi_fmt->efi_extents[i],
|
||||
sizeof(struct xfs_extent));
|
||||
return 0;
|
||||
} else if (buf->i_len == len32) {
|
||||
xfs_efi_log_format_32_t *src_efi_fmt_32 = buf->i_addr;
|
||||
|
@ -227,7 +216,8 @@ xfs_efi_copy_format(xfs_log_iovec_t *buf, xfs_efi_log_format_t *dst_efi_fmt)
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, NULL);
|
||||
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, NULL, buf->i_addr,
|
||||
buf->i_len);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
|
@ -246,27 +236,16 @@ xfs_efd_item_free(struct xfs_efd_log_item *efdp)
|
|||
kmem_cache_free(xfs_efd_cache, efdp);
|
||||
}
|
||||
|
||||
/*
|
||||
* This returns the number of iovecs needed to log the given efd item.
|
||||
* We only need 1 iovec for an efd item. It just logs the efd_log_format
|
||||
* structure.
|
||||
*/
|
||||
static inline int
|
||||
xfs_efd_item_sizeof(
|
||||
struct xfs_efd_log_item *efdp)
|
||||
{
|
||||
return sizeof(xfs_efd_log_format_t) +
|
||||
(efdp->efd_format.efd_nextents - 1) * sizeof(xfs_extent_t);
|
||||
}
|
||||
|
||||
STATIC void
|
||||
xfs_efd_item_size(
|
||||
struct xfs_log_item *lip,
|
||||
int *nvecs,
|
||||
int *nbytes)
|
||||
{
|
||||
struct xfs_efd_log_item *efdp = EFD_ITEM(lip);
|
||||
|
||||
*nvecs += 1;
|
||||
*nbytes += xfs_efd_item_sizeof(EFD_ITEM(lip));
|
||||
*nbytes += xfs_efd_log_format_sizeof(efdp->efd_format.efd_nextents);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -291,7 +270,7 @@ xfs_efd_item_format(
|
|||
|
||||
xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_EFD_FORMAT,
|
||||
&efdp->efd_format,
|
||||
xfs_efd_item_sizeof(efdp));
|
||||
xfs_efd_log_format_sizeof(efdp->efd_format.efd_nextents));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -340,9 +319,8 @@ xfs_trans_get_efd(
|
|||
ASSERT(nextents > 0);
|
||||
|
||||
if (nextents > XFS_EFD_MAX_FAST_EXTENTS) {
|
||||
efdp = kmem_zalloc(sizeof(struct xfs_efd_log_item) +
|
||||
(nextents - 1) * sizeof(struct xfs_extent),
|
||||
0);
|
||||
efdp = kzalloc(xfs_efd_log_item_sizeof(nextents),
|
||||
GFP_KERNEL | __GFP_NOFAIL);
|
||||
} else {
|
||||
efdp = kmem_cache_zalloc(xfs_efd_cache,
|
||||
GFP_KERNEL | __GFP_NOFAIL);
|
||||
|
@ -733,6 +711,12 @@ xlog_recover_efi_commit_pass2(
|
|||
|
||||
efi_formatp = item->ri_buf[0].i_addr;
|
||||
|
||||
if (item->ri_buf[0].i_len < xfs_efi_log_format_sizeof(0)) {
|
||||
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
|
||||
item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
efip = xfs_efi_init(mp, efi_formatp->efi_nextents);
|
||||
error = xfs_efi_copy_format(&item->ri_buf[0], &efip->efi_format);
|
||||
if (error) {
|
||||
|
@ -769,12 +753,24 @@ xlog_recover_efd_commit_pass2(
|
|||
xfs_lsn_t lsn)
|
||||
{
|
||||
struct xfs_efd_log_format *efd_formatp;
|
||||
int buflen = item->ri_buf[0].i_len;
|
||||
|
||||
efd_formatp = item->ri_buf[0].i_addr;
|
||||
ASSERT((item->ri_buf[0].i_len == (sizeof(xfs_efd_log_format_32_t) +
|
||||
((efd_formatp->efd_nextents - 1) * sizeof(xfs_extent_32_t)))) ||
|
||||
(item->ri_buf[0].i_len == (sizeof(xfs_efd_log_format_64_t) +
|
||||
((efd_formatp->efd_nextents - 1) * sizeof(xfs_extent_64_t)))));
|
||||
|
||||
if (buflen < sizeof(struct xfs_efd_log_format)) {
|
||||
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, log->l_mp,
|
||||
efd_formatp, buflen);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
if (item->ri_buf[0].i_len != xfs_efd_log_format32_sizeof(
|
||||
efd_formatp->efd_nextents) &&
|
||||
item->ri_buf[0].i_len != xfs_efd_log_format64_sizeof(
|
||||
efd_formatp->efd_nextents)) {
|
||||
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, log->l_mp,
|
||||
efd_formatp, buflen);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
xlog_recover_release_intent(log, XFS_LI_EFI, efd_formatp->efd_efi_id);
|
||||
return 0;
|
||||
|
|
|
@ -52,6 +52,14 @@ struct xfs_efi_log_item {
|
|||
xfs_efi_log_format_t efi_format;
|
||||
};
|
||||
|
||||
static inline size_t
|
||||
xfs_efi_log_item_sizeof(
|
||||
unsigned int nr)
|
||||
{
|
||||
return offsetof(struct xfs_efi_log_item, efi_format) +
|
||||
xfs_efi_log_format_sizeof(nr);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the "extent free done" log item. It is used to log
|
||||
* the fact that some extents earlier mentioned in an efi item
|
||||
|
@ -64,6 +72,14 @@ struct xfs_efd_log_item {
|
|||
xfs_efd_log_format_t efd_format;
|
||||
};
|
||||
|
||||
static inline size_t
|
||||
xfs_efd_log_item_sizeof(
|
||||
unsigned int nr)
|
||||
{
|
||||
return offsetof(struct xfs_efd_log_item, efd_format) +
|
||||
xfs_efd_log_format_sizeof(nr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Max number of extents in fast allocation path.
|
||||
*/
|
||||
|
|
|
@ -1261,7 +1261,7 @@ xfs_file_llseek(
|
|||
}
|
||||
|
||||
#ifdef CONFIG_FS_DAX
|
||||
static int
|
||||
static inline vm_fault_t
|
||||
xfs_dax_fault(
|
||||
struct vm_fault *vmf,
|
||||
enum page_entry_size pe_size,
|
||||
|
@ -1274,14 +1274,15 @@ xfs_dax_fault(
|
|||
&xfs_read_iomap_ops);
|
||||
}
|
||||
#else
|
||||
static int
|
||||
static inline vm_fault_t
|
||||
xfs_dax_fault(
|
||||
struct vm_fault *vmf,
|
||||
enum page_entry_size pe_size,
|
||||
bool write_fault,
|
||||
pfn_t *pfn)
|
||||
{
|
||||
return 0;
|
||||
ASSERT(0);
|
||||
return VM_FAULT_SIGBUS;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -2818,7 +2818,7 @@ retry:
|
|||
* Lock all the participating inodes. Depending upon whether
|
||||
* the target_name exists in the target directory, and
|
||||
* whether the target directory is the same as the source
|
||||
* directory, we can lock from 2 to 4 inodes.
|
||||
* directory, we can lock from 2 to 5 inodes.
|
||||
*/
|
||||
xfs_lock_inodes(inodes, num_inodes, XFS_ILOCK_EXCL);
|
||||
|
||||
|
|
|
@ -2552,6 +2552,8 @@ xlog_recover_process_intents(
|
|||
for (lip = xfs_trans_ail_cursor_first(ailp, &cur, 0);
|
||||
lip != NULL;
|
||||
lip = xfs_trans_ail_cursor_next(ailp, &cur)) {
|
||||
const struct xfs_item_ops *ops;
|
||||
|
||||
if (!xlog_item_is_intent(lip))
|
||||
break;
|
||||
|
||||
|
@ -2567,13 +2569,17 @@ xlog_recover_process_intents(
|
|||
* deferred ops, you /must/ attach them to the capture list in
|
||||
* the recover routine or else those subsequent intents will be
|
||||
* replayed in the wrong order!
|
||||
*
|
||||
* The recovery function can free the log item, so we must not
|
||||
* access lip after it returns.
|
||||
*/
|
||||
spin_unlock(&ailp->ail_lock);
|
||||
error = lip->li_ops->iop_recover(lip, &capture_list);
|
||||
ops = lip->li_ops;
|
||||
error = ops->iop_recover(lip, &capture_list);
|
||||
spin_lock(&ailp->ail_lock);
|
||||
if (error) {
|
||||
trace_xlog_intent_recovery_failed(log->l_mp, error,
|
||||
lip->li_ops->iop_recover);
|
||||
ops->iop_recover);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -118,10 +118,10 @@ xfs_check_ondisk_structs(void)
|
|||
/* log structures */
|
||||
XFS_CHECK_STRUCT_SIZE(struct xfs_buf_log_format, 88);
|
||||
XFS_CHECK_STRUCT_SIZE(struct xfs_dq_logformat, 24);
|
||||
XFS_CHECK_STRUCT_SIZE(struct xfs_efd_log_format_32, 28);
|
||||
XFS_CHECK_STRUCT_SIZE(struct xfs_efd_log_format_64, 32);
|
||||
XFS_CHECK_STRUCT_SIZE(struct xfs_efi_log_format_32, 28);
|
||||
XFS_CHECK_STRUCT_SIZE(struct xfs_efi_log_format_64, 32);
|
||||
XFS_CHECK_STRUCT_SIZE(struct xfs_efd_log_format_32, 16);
|
||||
XFS_CHECK_STRUCT_SIZE(struct xfs_efd_log_format_64, 16);
|
||||
XFS_CHECK_STRUCT_SIZE(struct xfs_efi_log_format_32, 16);
|
||||
XFS_CHECK_STRUCT_SIZE(struct xfs_efi_log_format_64, 16);
|
||||
XFS_CHECK_STRUCT_SIZE(struct xfs_extent_32, 12);
|
||||
XFS_CHECK_STRUCT_SIZE(struct xfs_extent_64, 16);
|
||||
XFS_CHECK_STRUCT_SIZE(struct xfs_log_dinode, 176);
|
||||
|
@ -134,6 +134,21 @@ xfs_check_ondisk_structs(void)
|
|||
XFS_CHECK_STRUCT_SIZE(struct xfs_trans_header, 16);
|
||||
XFS_CHECK_STRUCT_SIZE(struct xfs_attri_log_format, 40);
|
||||
XFS_CHECK_STRUCT_SIZE(struct xfs_attrd_log_format, 16);
|
||||
XFS_CHECK_STRUCT_SIZE(struct xfs_bui_log_format, 16);
|
||||
XFS_CHECK_STRUCT_SIZE(struct xfs_bud_log_format, 16);
|
||||
XFS_CHECK_STRUCT_SIZE(struct xfs_cui_log_format, 16);
|
||||
XFS_CHECK_STRUCT_SIZE(struct xfs_cud_log_format, 16);
|
||||
XFS_CHECK_STRUCT_SIZE(struct xfs_rui_log_format, 16);
|
||||
XFS_CHECK_STRUCT_SIZE(struct xfs_rud_log_format, 16);
|
||||
XFS_CHECK_STRUCT_SIZE(struct xfs_map_extent, 32);
|
||||
XFS_CHECK_STRUCT_SIZE(struct xfs_phys_extent, 16);
|
||||
|
||||
XFS_CHECK_OFFSET(struct xfs_bui_log_format, bui_extents, 16);
|
||||
XFS_CHECK_OFFSET(struct xfs_cui_log_format, cui_extents, 16);
|
||||
XFS_CHECK_OFFSET(struct xfs_rui_log_format, rui_extents, 16);
|
||||
XFS_CHECK_OFFSET(struct xfs_efi_log_format, efi_extents, 16);
|
||||
XFS_CHECK_OFFSET(struct xfs_efi_log_format_32, efi_extents, 16);
|
||||
XFS_CHECK_OFFSET(struct xfs_efi_log_format_64, efi_extents, 16);
|
||||
|
||||
/*
|
||||
* The v5 superblock format extended several v4 header structures with
|
||||
|
|
|
@ -523,7 +523,9 @@ xfs_cui_item_recover(
|
|||
type = refc_type;
|
||||
break;
|
||||
default:
|
||||
XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
|
||||
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
|
||||
&cuip->cui_format,
|
||||
sizeof(cuip->cui_format));
|
||||
error = -EFSCORRUPTED;
|
||||
goto abort_error;
|
||||
}
|
||||
|
@ -536,7 +538,8 @@ xfs_cui_item_recover(
|
|||
&new_fsb, &new_len, &rcur);
|
||||
if (error == -EFSCORRUPTED)
|
||||
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
|
||||
refc, sizeof(*refc));
|
||||
&cuip->cui_format,
|
||||
sizeof(cuip->cui_format));
|
||||
if (error)
|
||||
goto abort_error;
|
||||
|
||||
|
@ -622,28 +625,18 @@ static const struct xfs_item_ops xfs_cui_item_ops = {
|
|||
.iop_relog = xfs_cui_item_relog,
|
||||
};
|
||||
|
||||
/*
|
||||
* Copy an CUI format buffer from the given buf, and into the destination
|
||||
* CUI format structure. The CUI/CUD items were designed not to need any
|
||||
* special alignment handling.
|
||||
*/
|
||||
static int
|
||||
static inline void
|
||||
xfs_cui_copy_format(
|
||||
struct xfs_log_iovec *buf,
|
||||
struct xfs_cui_log_format *dst_cui_fmt)
|
||||
struct xfs_cui_log_format *dst,
|
||||
const struct xfs_cui_log_format *src)
|
||||
{
|
||||
struct xfs_cui_log_format *src_cui_fmt;
|
||||
uint len;
|
||||
unsigned int i;
|
||||
|
||||
src_cui_fmt = buf->i_addr;
|
||||
len = xfs_cui_log_format_sizeof(src_cui_fmt->cui_nextents);
|
||||
memcpy(dst, src, offsetof(struct xfs_cui_log_format, cui_extents));
|
||||
|
||||
if (buf->i_len == len) {
|
||||
memcpy(dst_cui_fmt, src_cui_fmt, len);
|
||||
return 0;
|
||||
}
|
||||
XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, NULL);
|
||||
return -EFSCORRUPTED;
|
||||
for (i = 0; i < src->cui_nextents; i++)
|
||||
memcpy(&dst->cui_extents[i], &src->cui_extents[i],
|
||||
sizeof(struct xfs_phys_extent));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -660,19 +653,28 @@ xlog_recover_cui_commit_pass2(
|
|||
struct xlog_recover_item *item,
|
||||
xfs_lsn_t lsn)
|
||||
{
|
||||
int error;
|
||||
struct xfs_mount *mp = log->l_mp;
|
||||
struct xfs_cui_log_item *cuip;
|
||||
struct xfs_cui_log_format *cui_formatp;
|
||||
size_t len;
|
||||
|
||||
cui_formatp = item->ri_buf[0].i_addr;
|
||||
|
||||
cuip = xfs_cui_init(mp, cui_formatp->cui_nextents);
|
||||
error = xfs_cui_copy_format(&item->ri_buf[0], &cuip->cui_format);
|
||||
if (error) {
|
||||
xfs_cui_item_free(cuip);
|
||||
return error;
|
||||
if (item->ri_buf[0].i_len < xfs_cui_log_format_sizeof(0)) {
|
||||
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
|
||||
item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
len = xfs_cui_log_format_sizeof(cui_formatp->cui_nextents);
|
||||
if (item->ri_buf[0].i_len != len) {
|
||||
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
|
||||
item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
cuip = xfs_cui_init(mp, cui_formatp->cui_nextents);
|
||||
xfs_cui_copy_format(&cuip->cui_format, cui_formatp);
|
||||
atomic_set(&cuip->cui_next_extent, cui_formatp->cui_nextents);
|
||||
/*
|
||||
* Insert the intent into the AIL directly and drop one reference so
|
||||
|
@ -706,7 +708,8 @@ xlog_recover_cud_commit_pass2(
|
|||
|
||||
cud_formatp = item->ri_buf[0].i_addr;
|
||||
if (item->ri_buf[0].i_len != sizeof(struct xfs_cud_log_format)) {
|
||||
XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, log->l_mp);
|
||||
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, log->l_mp,
|
||||
item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
|
|
|
@ -155,31 +155,6 @@ xfs_rui_init(
|
|||
return ruip;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy an RUI format buffer from the given buf, and into the destination
|
||||
* RUI format structure. The RUI/RUD items were designed not to need any
|
||||
* special alignment handling.
|
||||
*/
|
||||
STATIC int
|
||||
xfs_rui_copy_format(
|
||||
struct xfs_log_iovec *buf,
|
||||
struct xfs_rui_log_format *dst_rui_fmt)
|
||||
{
|
||||
struct xfs_rui_log_format *src_rui_fmt;
|
||||
uint len;
|
||||
|
||||
src_rui_fmt = buf->i_addr;
|
||||
len = xfs_rui_log_format_sizeof(src_rui_fmt->rui_nextents);
|
||||
|
||||
if (buf->i_len != len) {
|
||||
XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, NULL);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
memcpy(dst_rui_fmt, src_rui_fmt, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct xfs_rud_log_item *RUD_ITEM(struct xfs_log_item *lip)
|
||||
{
|
||||
return container_of(lip, struct xfs_rud_log_item, rud_item);
|
||||
|
@ -582,7 +557,9 @@ xfs_rui_item_recover(
|
|||
type = XFS_RMAP_FREE;
|
||||
break;
|
||||
default:
|
||||
XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, NULL);
|
||||
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
|
||||
&ruip->rui_format,
|
||||
sizeof(ruip->rui_format));
|
||||
error = -EFSCORRUPTED;
|
||||
goto abort_error;
|
||||
}
|
||||
|
@ -652,6 +629,20 @@ static const struct xfs_item_ops xfs_rui_item_ops = {
|
|||
.iop_relog = xfs_rui_item_relog,
|
||||
};
|
||||
|
||||
static inline void
|
||||
xfs_rui_copy_format(
|
||||
struct xfs_rui_log_format *dst,
|
||||
const struct xfs_rui_log_format *src)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
memcpy(dst, src, offsetof(struct xfs_rui_log_format, rui_extents));
|
||||
|
||||
for (i = 0; i < src->rui_nextents; i++)
|
||||
memcpy(&dst->rui_extents[i], &src->rui_extents[i],
|
||||
sizeof(struct xfs_map_extent));
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine is called to create an in-core extent rmap update
|
||||
* item from the rui format structure which was logged on disk.
|
||||
|
@ -666,19 +657,28 @@ xlog_recover_rui_commit_pass2(
|
|||
struct xlog_recover_item *item,
|
||||
xfs_lsn_t lsn)
|
||||
{
|
||||
int error;
|
||||
struct xfs_mount *mp = log->l_mp;
|
||||
struct xfs_rui_log_item *ruip;
|
||||
struct xfs_rui_log_format *rui_formatp;
|
||||
size_t len;
|
||||
|
||||
rui_formatp = item->ri_buf[0].i_addr;
|
||||
|
||||
ruip = xfs_rui_init(mp, rui_formatp->rui_nextents);
|
||||
error = xfs_rui_copy_format(&item->ri_buf[0], &ruip->rui_format);
|
||||
if (error) {
|
||||
xfs_rui_item_free(ruip);
|
||||
return error;
|
||||
if (item->ri_buf[0].i_len < xfs_rui_log_format_sizeof(0)) {
|
||||
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
|
||||
item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
len = xfs_rui_log_format_sizeof(rui_formatp->rui_nextents);
|
||||
if (item->ri_buf[0].i_len != len) {
|
||||
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
|
||||
item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
ruip = xfs_rui_init(mp, rui_formatp->rui_nextents);
|
||||
xfs_rui_copy_format(&ruip->rui_format, rui_formatp);
|
||||
atomic_set(&ruip->rui_next_extent, rui_formatp->rui_nextents);
|
||||
/*
|
||||
* Insert the intent into the AIL directly and drop one reference so
|
||||
|
@ -711,7 +711,11 @@ xlog_recover_rud_commit_pass2(
|
|||
struct xfs_rud_log_format *rud_formatp;
|
||||
|
||||
rud_formatp = item->ri_buf[0].i_addr;
|
||||
ASSERT(item->ri_buf[0].i_len == sizeof(struct xfs_rud_log_format));
|
||||
if (item->ri_buf[0].i_len != sizeof(struct xfs_rud_log_format)) {
|
||||
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, log->l_mp,
|
||||
rud_formatp, item->ri_buf[0].i_len);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
xlog_recover_release_intent(log, XFS_LI_RUI, rud_formatp->rud_rui_id);
|
||||
return 0;
|
||||
|
|
|
@ -2028,18 +2028,14 @@ xfs_init_caches(void)
|
|||
goto out_destroy_trans_cache;
|
||||
|
||||
xfs_efd_cache = kmem_cache_create("xfs_efd_item",
|
||||
(sizeof(struct xfs_efd_log_item) +
|
||||
(XFS_EFD_MAX_FAST_EXTENTS - 1) *
|
||||
sizeof(struct xfs_extent)),
|
||||
0, 0, NULL);
|
||||
xfs_efd_log_item_sizeof(XFS_EFD_MAX_FAST_EXTENTS),
|
||||
0, 0, NULL);
|
||||
if (!xfs_efd_cache)
|
||||
goto out_destroy_buf_item_cache;
|
||||
|
||||
xfs_efi_cache = kmem_cache_create("xfs_efi_item",
|
||||
(sizeof(struct xfs_efi_log_item) +
|
||||
(XFS_EFI_MAX_FAST_EXTENTS - 1) *
|
||||
sizeof(struct xfs_extent)),
|
||||
0, 0, NULL);
|
||||
xfs_efi_log_item_sizeof(XFS_EFI_MAX_FAST_EXTENTS),
|
||||
0, 0, NULL);
|
||||
if (!xfs_efi_cache)
|
||||
goto out_destroy_efd_cache;
|
||||
|
||||
|
|
|
@ -33,10 +33,15 @@ xfs_sysfs_init(
|
|||
const char *name)
|
||||
{
|
||||
struct kobject *parent;
|
||||
int err;
|
||||
|
||||
parent = parent_kobj ? &parent_kobj->kobject : NULL;
|
||||
init_completion(&kobj->complete);
|
||||
return kobject_init_and_add(&kobj->kobject, ktype, parent, "%s", name);
|
||||
err = kobject_init_and_add(&kobj->kobject, ktype, parent, "%s", name);
|
||||
if (err)
|
||||
kobject_put(&kobj->kobject);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
|
|
@ -799,6 +799,9 @@ TRACE_DEFINE_ENUM(PE_SIZE_PTE);
|
|||
TRACE_DEFINE_ENUM(PE_SIZE_PMD);
|
||||
TRACE_DEFINE_ENUM(PE_SIZE_PUD);
|
||||
|
||||
TRACE_DEFINE_ENUM(XFS_REFC_DOMAIN_SHARED);
|
||||
TRACE_DEFINE_ENUM(XFS_REFC_DOMAIN_COW);
|
||||
|
||||
TRACE_EVENT(xfs_filemap_fault,
|
||||
TP_PROTO(struct xfs_inode *ip, enum page_entry_size pe_size,
|
||||
bool write_fault),
|
||||
|
@ -2925,6 +2928,7 @@ DECLARE_EVENT_CLASS(xfs_refcount_extent_class,
|
|||
TP_STRUCT__entry(
|
||||
__field(dev_t, dev)
|
||||
__field(xfs_agnumber_t, agno)
|
||||
__field(enum xfs_refc_domain, domain)
|
||||
__field(xfs_agblock_t, startblock)
|
||||
__field(xfs_extlen_t, blockcount)
|
||||
__field(xfs_nlink_t, refcount)
|
||||
|
@ -2932,13 +2936,15 @@ DECLARE_EVENT_CLASS(xfs_refcount_extent_class,
|
|||
TP_fast_assign(
|
||||
__entry->dev = mp->m_super->s_dev;
|
||||
__entry->agno = agno;
|
||||
__entry->domain = irec->rc_domain;
|
||||
__entry->startblock = irec->rc_startblock;
|
||||
__entry->blockcount = irec->rc_blockcount;
|
||||
__entry->refcount = irec->rc_refcount;
|
||||
),
|
||||
TP_printk("dev %d:%d agno 0x%x agbno 0x%x fsbcount 0x%x refcount %u",
|
||||
TP_printk("dev %d:%d agno 0x%x dom %s agbno 0x%x fsbcount 0x%x refcount %u",
|
||||
MAJOR(__entry->dev), MINOR(__entry->dev),
|
||||
__entry->agno,
|
||||
__print_symbolic(__entry->domain, XFS_REFC_DOMAIN_STRINGS),
|
||||
__entry->startblock,
|
||||
__entry->blockcount,
|
||||
__entry->refcount)
|
||||
|
@ -2958,6 +2964,7 @@ DECLARE_EVENT_CLASS(xfs_refcount_extent_at_class,
|
|||
TP_STRUCT__entry(
|
||||
__field(dev_t, dev)
|
||||
__field(xfs_agnumber_t, agno)
|
||||
__field(enum xfs_refc_domain, domain)
|
||||
__field(xfs_agblock_t, startblock)
|
||||
__field(xfs_extlen_t, blockcount)
|
||||
__field(xfs_nlink_t, refcount)
|
||||
|
@ -2966,14 +2973,16 @@ DECLARE_EVENT_CLASS(xfs_refcount_extent_at_class,
|
|||
TP_fast_assign(
|
||||
__entry->dev = mp->m_super->s_dev;
|
||||
__entry->agno = agno;
|
||||
__entry->domain = irec->rc_domain;
|
||||
__entry->startblock = irec->rc_startblock;
|
||||
__entry->blockcount = irec->rc_blockcount;
|
||||
__entry->refcount = irec->rc_refcount;
|
||||
__entry->agbno = agbno;
|
||||
),
|
||||
TP_printk("dev %d:%d agno 0x%x agbno 0x%x fsbcount 0x%x refcount %u @ agbno 0x%x",
|
||||
TP_printk("dev %d:%d agno 0x%x dom %s agbno 0x%x fsbcount 0x%x refcount %u @ agbno 0x%x",
|
||||
MAJOR(__entry->dev), MINOR(__entry->dev),
|
||||
__entry->agno,
|
||||
__print_symbolic(__entry->domain, XFS_REFC_DOMAIN_STRINGS),
|
||||
__entry->startblock,
|
||||
__entry->blockcount,
|
||||
__entry->refcount,
|
||||
|
@ -2994,9 +3003,11 @@ DECLARE_EVENT_CLASS(xfs_refcount_double_extent_class,
|
|||
TP_STRUCT__entry(
|
||||
__field(dev_t, dev)
|
||||
__field(xfs_agnumber_t, agno)
|
||||
__field(enum xfs_refc_domain, i1_domain)
|
||||
__field(xfs_agblock_t, i1_startblock)
|
||||
__field(xfs_extlen_t, i1_blockcount)
|
||||
__field(xfs_nlink_t, i1_refcount)
|
||||
__field(enum xfs_refc_domain, i2_domain)
|
||||
__field(xfs_agblock_t, i2_startblock)
|
||||
__field(xfs_extlen_t, i2_blockcount)
|
||||
__field(xfs_nlink_t, i2_refcount)
|
||||
|
@ -3004,20 +3015,24 @@ DECLARE_EVENT_CLASS(xfs_refcount_double_extent_class,
|
|||
TP_fast_assign(
|
||||
__entry->dev = mp->m_super->s_dev;
|
||||
__entry->agno = agno;
|
||||
__entry->i1_domain = i1->rc_domain;
|
||||
__entry->i1_startblock = i1->rc_startblock;
|
||||
__entry->i1_blockcount = i1->rc_blockcount;
|
||||
__entry->i1_refcount = i1->rc_refcount;
|
||||
__entry->i2_domain = i2->rc_domain;
|
||||
__entry->i2_startblock = i2->rc_startblock;
|
||||
__entry->i2_blockcount = i2->rc_blockcount;
|
||||
__entry->i2_refcount = i2->rc_refcount;
|
||||
),
|
||||
TP_printk("dev %d:%d agno 0x%x agbno 0x%x fsbcount 0x%x refcount %u -- "
|
||||
"agbno 0x%x fsbcount 0x%x refcount %u",
|
||||
TP_printk("dev %d:%d agno 0x%x dom %s agbno 0x%x fsbcount 0x%x refcount %u -- "
|
||||
"dom %s agbno 0x%x fsbcount 0x%x refcount %u",
|
||||
MAJOR(__entry->dev), MINOR(__entry->dev),
|
||||
__entry->agno,
|
||||
__print_symbolic(__entry->i1_domain, XFS_REFC_DOMAIN_STRINGS),
|
||||
__entry->i1_startblock,
|
||||
__entry->i1_blockcount,
|
||||
__entry->i1_refcount,
|
||||
__print_symbolic(__entry->i2_domain, XFS_REFC_DOMAIN_STRINGS),
|
||||
__entry->i2_startblock,
|
||||
__entry->i2_blockcount,
|
||||
__entry->i2_refcount)
|
||||
|
@ -3038,9 +3053,11 @@ DECLARE_EVENT_CLASS(xfs_refcount_double_extent_at_class,
|
|||
TP_STRUCT__entry(
|
||||
__field(dev_t, dev)
|
||||
__field(xfs_agnumber_t, agno)
|
||||
__field(enum xfs_refc_domain, i1_domain)
|
||||
__field(xfs_agblock_t, i1_startblock)
|
||||
__field(xfs_extlen_t, i1_blockcount)
|
||||
__field(xfs_nlink_t, i1_refcount)
|
||||
__field(enum xfs_refc_domain, i2_domain)
|
||||
__field(xfs_agblock_t, i2_startblock)
|
||||
__field(xfs_extlen_t, i2_blockcount)
|
||||
__field(xfs_nlink_t, i2_refcount)
|
||||
|
@ -3049,21 +3066,25 @@ DECLARE_EVENT_CLASS(xfs_refcount_double_extent_at_class,
|
|||
TP_fast_assign(
|
||||
__entry->dev = mp->m_super->s_dev;
|
||||
__entry->agno = agno;
|
||||
__entry->i1_domain = i1->rc_domain;
|
||||
__entry->i1_startblock = i1->rc_startblock;
|
||||
__entry->i1_blockcount = i1->rc_blockcount;
|
||||
__entry->i1_refcount = i1->rc_refcount;
|
||||
__entry->i2_domain = i2->rc_domain;
|
||||
__entry->i2_startblock = i2->rc_startblock;
|
||||
__entry->i2_blockcount = i2->rc_blockcount;
|
||||
__entry->i2_refcount = i2->rc_refcount;
|
||||
__entry->agbno = agbno;
|
||||
),
|
||||
TP_printk("dev %d:%d agno 0x%x agbno 0x%x fsbcount 0x%x refcount %u -- "
|
||||
"agbno 0x%x fsbcount 0x%x refcount %u @ agbno 0x%x",
|
||||
TP_printk("dev %d:%d agno 0x%x dom %s agbno 0x%x fsbcount 0x%x refcount %u -- "
|
||||
"dom %s agbno 0x%x fsbcount 0x%x refcount %u @ agbno 0x%x",
|
||||
MAJOR(__entry->dev), MINOR(__entry->dev),
|
||||
__entry->agno,
|
||||
__print_symbolic(__entry->i1_domain, XFS_REFC_DOMAIN_STRINGS),
|
||||
__entry->i1_startblock,
|
||||
__entry->i1_blockcount,
|
||||
__entry->i1_refcount,
|
||||
__print_symbolic(__entry->i2_domain, XFS_REFC_DOMAIN_STRINGS),
|
||||
__entry->i2_startblock,
|
||||
__entry->i2_blockcount,
|
||||
__entry->i2_refcount,
|
||||
|
@ -3086,12 +3107,15 @@ DECLARE_EVENT_CLASS(xfs_refcount_triple_extent_class,
|
|||
TP_STRUCT__entry(
|
||||
__field(dev_t, dev)
|
||||
__field(xfs_agnumber_t, agno)
|
||||
__field(enum xfs_refc_domain, i1_domain)
|
||||
__field(xfs_agblock_t, i1_startblock)
|
||||
__field(xfs_extlen_t, i1_blockcount)
|
||||
__field(xfs_nlink_t, i1_refcount)
|
||||
__field(enum xfs_refc_domain, i2_domain)
|
||||
__field(xfs_agblock_t, i2_startblock)
|
||||
__field(xfs_extlen_t, i2_blockcount)
|
||||
__field(xfs_nlink_t, i2_refcount)
|
||||
__field(enum xfs_refc_domain, i3_domain)
|
||||
__field(xfs_agblock_t, i3_startblock)
|
||||
__field(xfs_extlen_t, i3_blockcount)
|
||||
__field(xfs_nlink_t, i3_refcount)
|
||||
|
@ -3099,27 +3123,33 @@ DECLARE_EVENT_CLASS(xfs_refcount_triple_extent_class,
|
|||
TP_fast_assign(
|
||||
__entry->dev = mp->m_super->s_dev;
|
||||
__entry->agno = agno;
|
||||
__entry->i1_domain = i1->rc_domain;
|
||||
__entry->i1_startblock = i1->rc_startblock;
|
||||
__entry->i1_blockcount = i1->rc_blockcount;
|
||||
__entry->i1_refcount = i1->rc_refcount;
|
||||
__entry->i2_domain = i2->rc_domain;
|
||||
__entry->i2_startblock = i2->rc_startblock;
|
||||
__entry->i2_blockcount = i2->rc_blockcount;
|
||||
__entry->i2_refcount = i2->rc_refcount;
|
||||
__entry->i3_domain = i3->rc_domain;
|
||||
__entry->i3_startblock = i3->rc_startblock;
|
||||
__entry->i3_blockcount = i3->rc_blockcount;
|
||||
__entry->i3_refcount = i3->rc_refcount;
|
||||
),
|
||||
TP_printk("dev %d:%d agno 0x%x agbno 0x%x fsbcount 0x%x refcount %u -- "
|
||||
"agbno 0x%x fsbcount 0x%x refcount %u -- "
|
||||
"agbno 0x%x fsbcount 0x%x refcount %u",
|
||||
TP_printk("dev %d:%d agno 0x%x dom %s agbno 0x%x fsbcount 0x%x refcount %u -- "
|
||||
"dom %s agbno 0x%x fsbcount 0x%x refcount %u -- "
|
||||
"dom %s agbno 0x%x fsbcount 0x%x refcount %u",
|
||||
MAJOR(__entry->dev), MINOR(__entry->dev),
|
||||
__entry->agno,
|
||||
__print_symbolic(__entry->i1_domain, XFS_REFC_DOMAIN_STRINGS),
|
||||
__entry->i1_startblock,
|
||||
__entry->i1_blockcount,
|
||||
__entry->i1_refcount,
|
||||
__print_symbolic(__entry->i2_domain, XFS_REFC_DOMAIN_STRINGS),
|
||||
__entry->i2_startblock,
|
||||
__entry->i2_blockcount,
|
||||
__entry->i2_refcount,
|
||||
__print_symbolic(__entry->i3_domain, XFS_REFC_DOMAIN_STRINGS),
|
||||
__entry->i3_startblock,
|
||||
__entry->i3_blockcount,
|
||||
__entry->i3_refcount)
|
||||
|
|
|
@ -730,11 +730,10 @@ void
|
|||
xfs_ail_push_all_sync(
|
||||
struct xfs_ail *ailp)
|
||||
{
|
||||
struct xfs_log_item *lip;
|
||||
DEFINE_WAIT(wait);
|
||||
|
||||
spin_lock(&ailp->ail_lock);
|
||||
while ((lip = xfs_ail_max(ailp)) != NULL) {
|
||||
while (xfs_ail_max(ailp) != NULL) {
|
||||
prepare_to_wait(&ailp->ail_empty, &wait, TASK_UNINTERRUPTIBLE);
|
||||
wake_up_process(ailp->ail_task);
|
||||
spin_unlock(&ailp->ail_lock);
|
||||
|
|
Загрузка…
Ссылка в новой задаче