Commit 64c3dd0b authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents 5d8401be 4eb559dd
...@@ -133,6 +133,21 @@ xfs_verify_agbno(struct xfs_perag *pag, xfs_agblock_t agbno) ...@@ -133,6 +133,21 @@ xfs_verify_agbno(struct xfs_perag *pag, xfs_agblock_t agbno)
return true; 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 * Verify that an AG inode number pointer neither points outside the AG
* nor points at static metadata. * nor points at static metadata.
......
...@@ -263,11 +263,7 @@ xfs_alloc_get_rec( ...@@ -263,11 +263,7 @@ xfs_alloc_get_rec(
goto out_bad_rec; goto out_bad_rec;
/* check for valid extent range, including overflow */ /* check for valid extent range, including overflow */
if (!xfs_verify_agbno(pag, *bno)) if (!xfs_verify_agbext(pag, *bno, *len))
goto out_bad_rec;
if (*bno > *bno + *len)
goto out_bad_rec;
if (!xfs_verify_agbno(pag, *bno + *len - 1))
goto out_bad_rec; goto out_bad_rec;
return 0; return 0;
......
...@@ -146,6 +146,8 @@ xfs_dir3_leaf_check_int( ...@@ -146,6 +146,8 @@ xfs_dir3_leaf_check_int(
xfs_dir2_leaf_tail_t *ltp; xfs_dir2_leaf_tail_t *ltp;
int stale; int stale;
int i; int i;
bool isleaf1 = (hdr->magic == XFS_DIR2_LEAF1_MAGIC ||
hdr->magic == XFS_DIR3_LEAF1_MAGIC);
ltp = xfs_dir2_leaf_tail_p(geo, leaf); ltp = xfs_dir2_leaf_tail_p(geo, leaf);
...@@ -158,8 +160,7 @@ xfs_dir3_leaf_check_int( ...@@ -158,8 +160,7 @@ xfs_dir3_leaf_check_int(
return __this_address; return __this_address;
/* Leaves and bests don't overlap in leaf format. */ /* Leaves and bests don't overlap in leaf format. */
if ((hdr->magic == XFS_DIR2_LEAF1_MAGIC || if (isleaf1 &&
hdr->magic == XFS_DIR3_LEAF1_MAGIC) &&
(char *)&hdr->ents[hdr->count] > (char *)xfs_dir2_leaf_bests_p(ltp)) (char *)&hdr->ents[hdr->count] > (char *)xfs_dir2_leaf_bests_p(ltp))
return __this_address; return __this_address;
...@@ -175,6 +176,10 @@ xfs_dir3_leaf_check_int( ...@@ -175,6 +176,10 @@ xfs_dir3_leaf_check_int(
} }
if (hdr->ents[i].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) if (hdr->ents[i].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR))
stale++; 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) if (hdr->stale != stale)
return __this_address; return __this_address;
......
...@@ -1564,20 +1564,6 @@ struct xfs_rmap_rec { ...@@ -1564,20 +1564,6 @@ struct xfs_rmap_rec {
#define RMAPBT_UNUSED_OFFSET_BITLEN 7 #define RMAPBT_UNUSED_OFFSET_BITLEN 7
#define RMAPBT_OFFSET_BITLEN 54 #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 * Key structure
* *
...@@ -1626,7 +1612,7 @@ unsigned int xfs_refc_block(struct xfs_mount *mp); ...@@ -1626,7 +1612,7 @@ unsigned int xfs_refc_block(struct xfs_mount *mp);
* on the startblock. This speeds up mount time deletion of stale * on the startblock. This speeds up mount time deletion of stale
* staging extents because they're all at the right side of the tree. * 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_COWFLAG_BITLEN 1
#define REFCNTBT_AGBLOCK_BITLEN 31 #define REFCNTBT_AGBLOCK_BITLEN 31
...@@ -1640,12 +1626,6 @@ struct xfs_refcount_key { ...@@ -1640,12 +1626,6 @@ struct xfs_refcount_key {
__be32 rc_startblock; /* starting block number */ __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 MAXREFCOUNT ((xfs_nlink_t)~0U)
#define MAXREFCEXTLEN ((xfs_extlen_t)~0U) #define MAXREFCEXTLEN ((xfs_extlen_t)~0U)
......
...@@ -613,25 +613,49 @@ typedef struct xfs_efi_log_format { ...@@ -613,25 +613,49 @@ typedef struct xfs_efi_log_format {
uint16_t efi_size; /* size of this item */ uint16_t efi_size; /* size of this item */
uint32_t efi_nextents; /* # extents to free */ uint32_t efi_nextents; /* # extents to free */
uint64_t efi_id; /* efi identifier */ 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; } 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 { typedef struct xfs_efi_log_format_32 {
uint16_t efi_type; /* efi log item type */ uint16_t efi_type; /* efi log item type */
uint16_t efi_size; /* size of this item */ uint16_t efi_size; /* size of this item */
uint32_t efi_nextents; /* # extents to free */ uint32_t efi_nextents; /* # extents to free */
uint64_t efi_id; /* efi identifier */ 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; } __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 { typedef struct xfs_efi_log_format_64 {
uint16_t efi_type; /* efi log item type */ uint16_t efi_type; /* efi log item type */
uint16_t efi_size; /* size of this item */ uint16_t efi_size; /* size of this item */
uint32_t efi_nextents; /* # extents to free */ uint32_t efi_nextents; /* # extents to free */
uint64_t efi_id; /* efi identifier */ 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; } 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 * 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 * log. The efd_extents array is a variable size array whose
...@@ -642,25 +666,49 @@ typedef struct xfs_efd_log_format { ...@@ -642,25 +666,49 @@ typedef struct xfs_efd_log_format {
uint16_t efd_size; /* size of this item */ uint16_t efd_size; /* size of this item */
uint32_t efd_nextents; /* # of extents freed */ uint32_t efd_nextents; /* # of extents freed */
uint64_t efd_efi_id; /* id of corresponding efi */ 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; } 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 { typedef struct xfs_efd_log_format_32 {
uint16_t efd_type; /* efd log item type */ uint16_t efd_type; /* efd log item type */
uint16_t efd_size; /* size of this item */ uint16_t efd_size; /* size of this item */
uint32_t efd_nextents; /* # of extents freed */ uint32_t efd_nextents; /* # of extents freed */
uint64_t efd_efi_id; /* id of corresponding efi */ 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; } __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 { typedef struct xfs_efd_log_format_64 {
uint16_t efd_type; /* efd log item type */ uint16_t efd_type; /* efd log item type */
uint16_t efd_size; /* size of this item */ uint16_t efd_size; /* size of this item */
uint32_t efd_nextents; /* # of extents freed */ uint32_t efd_nextents; /* # of extents freed */
uint64_t efd_efi_id; /* id of corresponding efi */ 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; } 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 * RUI/RUD (reverse mapping) log format definitions
*/ */
......
This diff is collapsed.
...@@ -14,14 +14,33 @@ struct xfs_bmbt_irec; ...@@ -14,14 +14,33 @@ struct xfs_bmbt_irec;
struct xfs_refcount_irec; struct xfs_refcount_irec;
extern int xfs_refcount_lookup_le(struct xfs_btree_cur *cur, 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, 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, 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, extern int xfs_refcount_get_rec(struct xfs_btree_cur *cur,
struct xfs_refcount_irec *irec, int *stat); 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 { enum xfs_refcount_intent_type {
XFS_REFCOUNT_INCREASE = 1, XFS_REFCOUNT_INCREASE = 1,
XFS_REFCOUNT_DECREASE, XFS_REFCOUNT_DECREASE,
...@@ -36,6 +55,18 @@ struct xfs_refcount_intent { ...@@ -36,6 +55,18 @@ struct xfs_refcount_intent {
xfs_fsblock_t ri_startblock; 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, void xfs_refcount_increase_extent(struct xfs_trans *tp,
struct xfs_bmbt_irec *irec); struct xfs_bmbt_irec *irec);
void xfs_refcount_decrease_extent(struct xfs_trans *tp, void xfs_refcount_decrease_extent(struct xfs_trans *tp,
...@@ -79,7 +110,8 @@ extern int xfs_refcount_recover_cow_leftovers(struct xfs_mount *mp, ...@@ -79,7 +110,8 @@ extern int xfs_refcount_recover_cow_leftovers(struct xfs_mount *mp,
#define XFS_REFCOUNT_ITEM_OVERHEAD 32 #define XFS_REFCOUNT_ITEM_OVERHEAD 32
extern int xfs_refcount_has_record(struct xfs_btree_cur *cur, 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; union xfs_btree_rec;
extern void xfs_refcount_btrec_to_irec(const union xfs_btree_rec *rec, extern void xfs_refcount_btrec_to_irec(const union xfs_btree_rec *rec,
struct xfs_refcount_irec *irec); struct xfs_refcount_irec *irec);
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "xfs_btree.h" #include "xfs_btree.h"
#include "xfs_btree_staging.h" #include "xfs_btree_staging.h"
#include "xfs_refcount_btree.h" #include "xfs_refcount_btree.h"
#include "xfs_refcount.h"
#include "xfs_alloc.h" #include "xfs_alloc.h"
#include "xfs_error.h" #include "xfs_error.h"
#include "xfs_trace.h" #include "xfs_trace.h"
...@@ -160,7 +161,12 @@ xfs_refcountbt_init_rec_from_cur( ...@@ -160,7 +161,12 @@ xfs_refcountbt_init_rec_from_cur(
struct xfs_btree_cur *cur, struct xfs_btree_cur *cur,
union xfs_btree_rec *rec) 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_blockcount = cpu_to_be32(cur->bc_rec.rc.rc_blockcount);
rec->refc.rc_refcount = cpu_to_be32(cur->bc_rec.rc.rc_refcount); rec->refc.rc_refcount = cpu_to_be32(cur->bc_rec.rc.rc_refcount);
} }
...@@ -182,10 +188,13 @@ xfs_refcountbt_key_diff( ...@@ -182,10 +188,13 @@ xfs_refcountbt_key_diff(
struct xfs_btree_cur *cur, struct xfs_btree_cur *cur,
const union xfs_btree_key *key) 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_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 STATIC int64_t
......
...@@ -235,13 +235,8 @@ xfs_rmap_get_rec( ...@@ -235,13 +235,8 @@ xfs_rmap_get_rec(
goto out_bad_rec; goto out_bad_rec;
} else { } else {
/* check for valid extent range, including overflow */ /* check for valid extent range, including overflow */
if (!xfs_verify_agbno(pag, irec->rm_startblock)) if (!xfs_verify_agbext(pag, irec->rm_startblock,
goto out_bad_rec; irec->rm_blockcount))
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))
goto out_bad_rec; goto out_bad_rec;
} }
......
...@@ -422,7 +422,7 @@ xfs_calc_itruncate_reservation_minlogsize( ...@@ -422,7 +422,7 @@ xfs_calc_itruncate_reservation_minlogsize(
/* /*
* In renaming a files we can modify: * 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 btrees: 2 * (max depth + v2) * dir block size
* the two directory bmap btrees: 2 * max depth * 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 * And the bmap_finish transaction can free dir and bmap blocks (two sets
...@@ -437,7 +437,7 @@ xfs_calc_rename_reservation( ...@@ -437,7 +437,7 @@ xfs_calc_rename_reservation(
struct xfs_mount *mp) struct xfs_mount *mp)
{ {
return XFS_DQUOT_LOGRES(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_calc_buf_res(2 * XFS_DIROP_LOG_COUNT(mp),
XFS_FSB_TO_B(mp, 1))), XFS_FSB_TO_B(mp, 1))),
(xfs_calc_buf_res(7, mp->m_sb.sb_sectsize) + (xfs_calc_buf_res(7, mp->m_sb.sb_sectsize) +
......
...@@ -166,6 +166,36 @@ typedef struct xfs_bmbt_irec ...@@ -166,6 +166,36 @@ typedef struct xfs_bmbt_irec
xfs_exntst_t br_state; /* extent state */ xfs_exntst_t br_state; /* extent state */
} xfs_bmbt_irec_t; } 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 */ /* per-AG block reservation types */
enum xfs_ag_resv_type { enum xfs_ag_resv_type {
XFS_AG_RESV_NONE = 0, XFS_AG_RESV_NONE = 0,
......
...@@ -100,9 +100,7 @@ xchk_allocbt_rec( ...@@ -100,9 +100,7 @@ xchk_allocbt_rec(
bno = be32_to_cpu(rec->alloc.ar_startblock); bno = be32_to_cpu(rec->alloc.ar_startblock);
len = be32_to_cpu(rec->alloc.ar_blockcount); len = be32_to_cpu(rec->alloc.ar_blockcount);
if (bno + len <= bno || if (!xfs_verify_agbext(pag, bno, len))
!xfs_verify_agbno(pag, bno) ||
!xfs_verify_agbno(pag, bno + len - 1))
xchk_btree_set_corrupt(bs->sc, bs->cur, 0); xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
xchk_allocbt_xref(bs->sc, bno, len); xchk_allocbt_xref(bs->sc, bno, len);
......
...@@ -108,9 +108,8 @@ xchk_iallocbt_chunk( ...@@ -108,9 +108,8 @@ xchk_iallocbt_chunk(
xfs_agblock_t bno; xfs_agblock_t bno;
bno = XFS_AGINO_TO_AGBNO(mp, agino); bno = XFS_AGINO_TO_AGBNO(mp, agino);
if (bno + len <= bno ||
!xfs_verify_agbno(pag, bno) || if (!xfs_verify_agbext(pag, bno, len))
!xfs_verify_agbno(pag, bno + len - 1))
xchk_btree_set_corrupt(bs->sc, bs->cur, 0); xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
xchk_iallocbt_chunk_xref(bs->sc, irec, agino, bno, len); xchk_iallocbt_chunk_xref(bs->sc, irec, agino, bno, len);
......
...@@ -269,15 +269,13 @@ xchk_refcountbt_process_rmap_fragments( ...@@ -269,15 +269,13 @@ xchk_refcountbt_process_rmap_fragments(
STATIC void STATIC void
xchk_refcountbt_xref_rmap( xchk_refcountbt_xref_rmap(
struct xfs_scrub *sc, struct xfs_scrub *sc,
xfs_agblock_t bno, const struct xfs_refcount_irec *irec)
xfs_extlen_t len,
xfs_nlink_t refcount)
{ {
struct xchk_refcnt_check refchk = { struct xchk_refcnt_check refchk = {
.sc = sc, .sc = sc,
.bno = bno, .bno = irec->rc_startblock,
.len = len, .len = irec->rc_blockcount,
.refcount = refcount, .refcount = irec->rc_refcount,
.seen = 0, .seen = 0,
}; };
struct xfs_rmap_irec low; struct xfs_rmap_irec low;
...@@ -291,9 +289,9 @@ xchk_refcountbt_xref_rmap( ...@@ -291,9 +289,9 @@ xchk_refcountbt_xref_rmap(
/* Cross-reference with the rmapbt to confirm the refcount. */ /* Cross-reference with the rmapbt to confirm the refcount. */
memset(&low, 0, sizeof(low)); memset(&low, 0, sizeof(low));
low.rm_startblock = bno; low.rm_startblock = irec->rc_startblock;
memset(&high, 0xFF, sizeof(high)); 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); INIT_LIST_HEAD(&refchk.fragments);
error = xfs_rmap_query_range(sc->sa.rmap_cur, &low, &high, error = xfs_rmap_query_range(sc->sa.rmap_cur, &low, &high,
...@@ -302,7 +300,7 @@ xchk_refcountbt_xref_rmap( ...@@ -302,7 +300,7 @@ xchk_refcountbt_xref_rmap(
goto out_free; goto out_free;
xchk_refcountbt_process_rmap_fragments(&refchk); 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); xchk_btree_xref_set_corrupt(sc, sc->sa.rmap_cur, 0);
out_free: out_free:
...@@ -315,17 +313,16 @@ xchk_refcountbt_xref_rmap( ...@@ -315,17 +313,16 @@ xchk_refcountbt_xref_rmap(
/* Cross-reference with the other btrees. */ /* Cross-reference with the other btrees. */
STATIC void STATIC void
xchk_refcountbt_xref( xchk_refcountbt_xref(
struct xfs_scrub *sc, struct xfs_scrub *sc,
xfs_agblock_t agbno, const struct xfs_refcount_irec *irec)
xfs_extlen_t len,
xfs_nlink_t refcount)
{ {
if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
return; return;
xchk_xref_is_used_space(sc, agbno, len); xchk_xref_is_used_space(sc, irec->rc_startblock, irec->rc_blockcount);
xchk_xref_is_not_inode_chunk(sc, agbno, len); xchk_xref_is_not_inode_chunk(sc, irec->rc_startblock,
xchk_refcountbt_xref_rmap(sc, agbno, len, refcount); irec->rc_blockcount);
xchk_refcountbt_xref_rmap(sc, irec);
} }
/* Scrub a refcountbt record. */ /* Scrub a refcountbt record. */
...@@ -334,35 +331,27 @@ xchk_refcountbt_rec( ...@@ -334,35 +331,27 @@ xchk_refcountbt_rec(
struct xchk_btree *bs, struct xchk_btree *bs,
const union xfs_btree_rec *rec) const union xfs_btree_rec *rec)
{ {
struct xfs_refcount_irec irec;
xfs_agblock_t *cow_blocks = bs->private; xfs_agblock_t *cow_blocks = bs->private;
struct xfs_perag *pag = bs->cur->bc_ag.pag; 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); xfs_refcount_btrec_to_irec(rec, &irec);
len = be32_to_cpu(rec->refc.rc_blockcount);
refcount = be32_to_cpu(rec->refc.rc_refcount);
/* Only CoW records can have refcount == 1. */ /* Check the domain and refcount are not incompatible. */
has_cowflag = (bno & XFS_REFC_COW_START); if (!xfs_refcount_check_domain(&irec))
if ((refcount == 1 && !has_cowflag) || (refcount != 1 && has_cowflag))
xchk_btree_set_corrupt(bs->sc, bs->cur, 0); 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. */ /* Check the extent. */
bno &= ~XFS_REFC_COW_START; if (!xfs_verify_agbext(pag, irec.rc_startblock, irec.rc_blockcount))
if (bno + len <= bno ||
!xfs_verify_agbno(pag, bno) ||
!xfs_verify_agbno(pag, bno + len - 1))
xchk_btree_set_corrupt(bs->sc, bs->cur, 0); 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_btree_set_corrupt(bs->sc, bs->cur, 0);
xchk_refcountbt_xref(bs->sc, bno, len, refcount); xchk_refcountbt_xref(bs->sc, &irec);
return 0; return 0;
} }
...@@ -426,7 +415,6 @@ xchk_xref_is_cow_staging( ...@@ -426,7 +415,6 @@ xchk_xref_is_cow_staging(
xfs_extlen_t len) xfs_extlen_t len)
{ {
struct xfs_refcount_irec rc; struct xfs_refcount_irec rc;
bool has_cowflag;
int has_refcount; int has_refcount;
int error; int error;
...@@ -434,8 +422,8 @@ xchk_xref_is_cow_staging( ...@@ -434,8 +422,8 @@ xchk_xref_is_cow_staging(
return; return;
/* Find the CoW staging extent. */ /* Find the CoW staging extent. */
error = xfs_refcount_lookup_le(sc->sa.refc_cur, error = xfs_refcount_lookup_le(sc->sa.refc_cur, XFS_REFC_DOMAIN_COW,
agbno + XFS_REFC_COW_START, &has_refcount); agbno, &has_refcount);
if (!xchk_should_check_xref(sc, &error, &sc->sa.refc_cur)) if (!xchk_should_check_xref(sc, &error, &sc->sa.refc_cur))
return; return;
if (!has_refcount) { if (!has_refcount) {
...@@ -451,9 +439,8 @@ xchk_xref_is_cow_staging( ...@@ -451,9 +439,8 @@ xchk_xref_is_cow_staging(
return; return;
} }
/* CoW flag must be set, refcount must be 1. */ /* CoW lookup returned a shared extent record? */
has_cowflag = (rc.rc_startblock & XFS_REFC_COW_START); if (rc.rc_domain != XFS_REFC_DOMAIN_COW)
if (!has_cowflag || rc.rc_refcount != 1)
xchk_btree_xref_set_corrupt(sc, sc->sa.refc_cur, 0); xchk_btree_xref_set_corrupt(sc, sc->sa.refc_cur, 0);
/* Must be at least as long as what was passed in */ /* Must be at least as long as what was passed in */
...@@ -477,7 +464,8 @@ xchk_xref_is_not_shared( ...@@ -477,7 +464,8 @@ xchk_xref_is_not_shared(
if (!sc->sa.refc_cur || xchk_skip_xref(sc->sm)) if (!sc->sa.refc_cur || xchk_skip_xref(sc->sm))
return; 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)) if (!xchk_should_check_xref(sc, &error, &sc->sa.refc_cur))
return; return;
if (shared) if (shared)
......
...@@ -245,28 +245,6 @@ xfs_attri_init( ...@@ -245,28 +245,6 @@ xfs_attri_init(
return attrip; 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) 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); return container_of(lip, struct xfs_attrd_log_item, attrd_item);
...@@ -731,24 +709,50 @@ xlog_recover_attri_commit_pass2( ...@@ -731,24 +709,50 @@ xlog_recover_attri_commit_pass2(
struct xfs_attri_log_nameval *nv; struct xfs_attri_log_nameval *nv;
const void *attr_value = NULL; const void *attr_value = NULL;
const void *attr_name; const void *attr_name;
int error; size_t len;
attri_formatp = item->ri_buf[0].i_addr; attri_formatp = item->ri_buf[0].i_addr;
attr_name = item->ri_buf[1].i_addr; attr_name = item->ri_buf[1].i_addr;
/* Validate xfs_attri_log_format before the large memory allocation */ /* 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)) { 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; return -EFSCORRUPTED;
} }
if (!xfs_attr_namecheck(attr_name, attri_formatp->alfi_name_len)) { 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; 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; attr_value = item->ri_buf[2].i_addr;
}
/* /*
* Memory alloc failure will cause replay to abort. We attach the * Memory alloc failure will cause replay to abort. We attach the
...@@ -760,9 +764,7 @@ xlog_recover_attri_commit_pass2( ...@@ -760,9 +764,7 @@ xlog_recover_attri_commit_pass2(
attri_formatp->alfi_value_len); attri_formatp->alfi_value_len);
attrip = xfs_attri_init(mp, nv); attrip = xfs_attri_init(mp, nv);
error = xfs_attri_copy_format(&item->ri_buf[0], &attrip->attri_format); memcpy(&attrip->attri_format, attri_formatp, len);
if (error)
goto out;
/* /*
* The ATTRI has two references. One for the ATTRD and one for ATTRI to * The ATTRI has two references. One for the ATTRD and one for ATTRI to
...@@ -774,10 +776,6 @@ xlog_recover_attri_commit_pass2( ...@@ -774,10 +776,6 @@ xlog_recover_attri_commit_pass2(
xfs_attri_release(attrip); xfs_attri_release(attrip);
xfs_attri_log_nameval_put(nv); xfs_attri_log_nameval_put(nv);
return 0; 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( ...@@ -842,7 +840,8 @@ xlog_recover_attrd_commit_pass2(
attrd_formatp = item->ri_buf[0].i_addr; attrd_formatp = item->ri_buf[0].i_addr;
if (item->ri_buf[0].i_len != sizeof(struct xfs_attrd_log_format)) { 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; return -EFSCORRUPTED;
} }
......
...@@ -608,28 +608,18 @@ static const struct xfs_item_ops xfs_bui_item_ops = { ...@@ -608,28 +608,18 @@ static const struct xfs_item_ops xfs_bui_item_ops = {
.iop_relog = xfs_bui_item_relog, .iop_relog = xfs_bui_item_relog,
}; };
/* static inline void
* 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
xfs_bui_copy_format( xfs_bui_copy_format(
struct xfs_log_iovec *buf, struct xfs_bui_log_format *dst,
struct xfs_bui_log_format *dst_bui_fmt) const struct xfs_bui_log_format *src)
{ {
struct xfs_bui_log_format *src_bui_fmt; unsigned int i;
uint len;
src_bui_fmt = buf->i_addr; memcpy(dst, src, offsetof(struct xfs_bui_log_format, bui_extents));
len = xfs_bui_log_format_sizeof(src_bui_fmt->bui_nextents);
if (buf->i_len == len) { for (i = 0; i < src->bui_nextents; i++)
memcpy(dst_bui_fmt, src_bui_fmt, len); memcpy(&dst->bui_extents[i], &src->bui_extents[i],
return 0; sizeof(struct xfs_map_extent));
}
XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, NULL);
return -EFSCORRUPTED;
} }
/* /*
...@@ -646,23 +636,34 @@ xlog_recover_bui_commit_pass2( ...@@ -646,23 +636,34 @@ xlog_recover_bui_commit_pass2(
struct xlog_recover_item *item, struct xlog_recover_item *item,
xfs_lsn_t lsn) xfs_lsn_t lsn)
{ {
int error;
struct xfs_mount *mp = log->l_mp; struct xfs_mount *mp = log->l_mp;
struct xfs_bui_log_item *buip; struct xfs_bui_log_item *buip;
struct xfs_bui_log_format *bui_formatp; struct xfs_bui_log_format *bui_formatp;
size_t len;
bui_formatp = item->ri_buf[0].i_addr; bui_formatp = item->ri_buf[0].i_addr;
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;
}
if (bui_formatp->bui_nextents != XFS_BUI_MAX_FAST_EXTENTS) { if (bui_formatp->bui_nextents != XFS_BUI_MAX_FAST_EXTENTS) {
XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, log->l_mp); XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
return -EFSCORRUPTED; return -EFSCORRUPTED;
} }
buip = xfs_bui_init(mp);
error = xfs_bui_copy_format(&item->ri_buf[0], &buip->bui_format); len = xfs_bui_log_format_sizeof(bui_formatp->bui_nextents);
if (error) { if (item->ri_buf[0].i_len != len) {
xfs_bui_item_free(buip); XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
return error; 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); atomic_set(&buip->bui_next_extent, bui_formatp->bui_nextents);
/* /*
* Insert the intent into the AIL directly and drop one reference so * Insert the intent into the AIL directly and drop one reference so
...@@ -696,7 +697,8 @@ xlog_recover_bud_commit_pass2( ...@@ -696,7 +697,8 @@ xlog_recover_bud_commit_pass2(
bud_formatp = item->ri_buf[0].i_addr; bud_formatp = item->ri_buf[0].i_addr;
if (item->ri_buf[0].i_len != sizeof(struct xfs_bud_log_format)) { 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; return -EFSCORRUPTED;
} }
......
...@@ -234,13 +234,18 @@ int ...@@ -234,13 +234,18 @@ int
xfs_errortag_init( xfs_errortag_init(
struct xfs_mount *mp) struct xfs_mount *mp)
{ {
int ret;
mp->m_errortag = kmem_zalloc(sizeof(unsigned int) * XFS_ERRTAG_MAX, mp->m_errortag = kmem_zalloc(sizeof(unsigned int) * XFS_ERRTAG_MAX,
KM_MAYFAIL); KM_MAYFAIL);
if (!mp->m_errortag) if (!mp->m_errortag)
return -ENOMEM; return -ENOMEM;
return xfs_sysfs_init(&mp->m_errortag_kobj, &xfs_errortag_ktype, ret = xfs_sysfs_init(&mp->m_errortag_kobj, &xfs_errortag_ktype,
&mp->m_kobj, "errortag"); &mp->m_kobj, "errortag");
if (ret)
kmem_free(mp->m_errortag);
return ret;
} }
void void
......
...@@ -66,27 +66,16 @@ xfs_efi_release( ...@@ -66,27 +66,16 @@ xfs_efi_release(
xfs_efi_item_free(efip); 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 STATIC void
xfs_efi_item_size( xfs_efi_item_size(
struct xfs_log_item *lip, struct xfs_log_item *lip,
int *nvecs, int *nvecs,
int *nbytes) int *nbytes)
{ {
struct xfs_efi_log_item *efip = EFI_ITEM(lip);
*nvecs += 1; *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( ...@@ -112,7 +101,7 @@ xfs_efi_item_format(
xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_EFI_FORMAT, xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_EFI_FORMAT,
&efip->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( ...@@ -155,13 +144,11 @@ xfs_efi_init(
{ {
struct xfs_efi_log_item *efip; struct xfs_efi_log_item *efip;
uint size;
ASSERT(nextents > 0); ASSERT(nextents > 0);
if (nextents > XFS_EFI_MAX_FAST_EXTENTS) { if (nextents > XFS_EFI_MAX_FAST_EXTENTS) {
size = (uint)(sizeof(struct xfs_efi_log_item) + efip = kzalloc(xfs_efi_log_item_sizeof(nextents),
((nextents - 1) * sizeof(xfs_extent_t))); GFP_KERNEL | __GFP_NOFAIL);
efip = kmem_zalloc(size, 0);
} else { } else {
efip = kmem_cache_zalloc(xfs_efi_cache, efip = kmem_cache_zalloc(xfs_efi_cache,
GFP_KERNEL | __GFP_NOFAIL); 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) ...@@ -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; xfs_efi_log_format_t *src_efi_fmt = buf->i_addr;
uint i; uint i;
uint len = sizeof(xfs_efi_log_format_t) + uint len = xfs_efi_log_format_sizeof(src_efi_fmt->efi_nextents);
(src_efi_fmt->efi_nextents - 1) * sizeof(xfs_extent_t); uint len32 = xfs_efi_log_format32_sizeof(src_efi_fmt->efi_nextents);
uint len32 = sizeof(xfs_efi_log_format_32_t) + uint len64 = xfs_efi_log_format64_sizeof(src_efi_fmt->efi_nextents);
(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);
if (buf->i_len == len) { 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; return 0;
} else if (buf->i_len == len32) { } else if (buf->i_len == len32) {
xfs_efi_log_format_32_t *src_efi_fmt_32 = buf->i_addr; 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) ...@@ -227,7 +216,8 @@ xfs_efi_copy_format(xfs_log_iovec_t *buf, xfs_efi_log_format_t *dst_efi_fmt)
} }
return 0; 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; return -EFSCORRUPTED;
} }
...@@ -246,27 +236,16 @@ xfs_efd_item_free(struct xfs_efd_log_item *efdp) ...@@ -246,27 +236,16 @@ xfs_efd_item_free(struct xfs_efd_log_item *efdp)
kmem_cache_free(xfs_efd_cache, 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 STATIC void
xfs_efd_item_size( xfs_efd_item_size(
struct xfs_log_item *lip, struct xfs_log_item *lip,
int *nvecs, int *nvecs,
int *nbytes) int *nbytes)
{ {
struct xfs_efd_log_item *efdp = EFD_ITEM(lip);
*nvecs += 1; *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( ...@@ -291,7 +270,7 @@ xfs_efd_item_format(
xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_EFD_FORMAT, xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_EFD_FORMAT,
&efdp->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( ...@@ -340,9 +319,8 @@ xfs_trans_get_efd(
ASSERT(nextents > 0); ASSERT(nextents > 0);
if (nextents > XFS_EFD_MAX_FAST_EXTENTS) { if (nextents > XFS_EFD_MAX_FAST_EXTENTS) {
efdp = kmem_zalloc(sizeof(struct xfs_efd_log_item) + efdp = kzalloc(xfs_efd_log_item_sizeof(nextents),
(nextents - 1) * sizeof(struct xfs_extent), GFP_KERNEL | __GFP_NOFAIL);
0);
} else { } else {
efdp = kmem_cache_zalloc(xfs_efd_cache, efdp = kmem_cache_zalloc(xfs_efd_cache,
GFP_KERNEL | __GFP_NOFAIL); GFP_KERNEL | __GFP_NOFAIL);
...@@ -733,6 +711,12 @@ xlog_recover_efi_commit_pass2( ...@@ -733,6 +711,12 @@ xlog_recover_efi_commit_pass2(
efi_formatp = item->ri_buf[0].i_addr; 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); efip = xfs_efi_init(mp, efi_formatp->efi_nextents);
error = xfs_efi_copy_format(&item->ri_buf[0], &efip->efi_format); error = xfs_efi_copy_format(&item->ri_buf[0], &efip->efi_format);
if (error) { if (error) {
...@@ -769,12 +753,24 @@ xlog_recover_efd_commit_pass2( ...@@ -769,12 +753,24 @@ xlog_recover_efd_commit_pass2(
xfs_lsn_t lsn) xfs_lsn_t lsn)
{ {
struct xfs_efd_log_format *efd_formatp; struct xfs_efd_log_format *efd_formatp;
int buflen = item->ri_buf[0].i_len;
efd_formatp = item->ri_buf[0].i_addr; 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)))) || if (buflen < sizeof(struct xfs_efd_log_format)) {
(item->ri_buf[0].i_len == (sizeof(xfs_efd_log_format_64_t) + XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, log->l_mp,
((efd_formatp->efd_nextents - 1) * sizeof(xfs_extent_64_t))))); 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); xlog_recover_release_intent(log, XFS_LI_EFI, efd_formatp->efd_efi_id);
return 0; return 0;
......
...@@ -52,6 +52,14 @@ struct xfs_efi_log_item { ...@@ -52,6 +52,14 @@ struct xfs_efi_log_item {
xfs_efi_log_format_t efi_format; 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 * This is the "extent free done" log item. It is used to log
* the fact that some extents earlier mentioned in an efi item * the fact that some extents earlier mentioned in an efi item
...@@ -64,6 +72,14 @@ struct xfs_efd_log_item { ...@@ -64,6 +72,14 @@ struct xfs_efd_log_item {
xfs_efd_log_format_t efd_format; 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. * Max number of extents in fast allocation path.
*/ */
......
...@@ -1261,7 +1261,7 @@ xfs_file_llseek( ...@@ -1261,7 +1261,7 @@ xfs_file_llseek(
} }
#ifdef CONFIG_FS_DAX #ifdef CONFIG_FS_DAX
static int static inline vm_fault_t
xfs_dax_fault( xfs_dax_fault(
struct vm_fault *vmf, struct vm_fault *vmf,
enum page_entry_size pe_size, enum page_entry_size pe_size,
...@@ -1274,14 +1274,15 @@ xfs_dax_fault( ...@@ -1274,14 +1274,15 @@ xfs_dax_fault(
&xfs_read_iomap_ops); &xfs_read_iomap_ops);
} }
#else #else
static int static inline vm_fault_t
xfs_dax_fault( xfs_dax_fault(
struct vm_fault *vmf, struct vm_fault *vmf,
enum page_entry_size pe_size, enum page_entry_size pe_size,
bool write_fault, bool write_fault,
pfn_t *pfn) pfn_t *pfn)
{ {
return 0; ASSERT(0);
return VM_FAULT_SIGBUS;
} }
#endif #endif
......
...@@ -2818,7 +2818,7 @@ xfs_rename( ...@@ -2818,7 +2818,7 @@ xfs_rename(
* Lock all the participating inodes. Depending upon whether * Lock all the participating inodes. Depending upon whether
* the target_name exists in the target directory, and * the target_name exists in the target directory, and
* whether the target directory is the same as the source * 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); xfs_lock_inodes(inodes, num_inodes, XFS_ILOCK_EXCL);
......
...@@ -2552,6 +2552,8 @@ xlog_recover_process_intents( ...@@ -2552,6 +2552,8 @@ xlog_recover_process_intents(
for (lip = xfs_trans_ail_cursor_first(ailp, &cur, 0); for (lip = xfs_trans_ail_cursor_first(ailp, &cur, 0);
lip != NULL; lip != NULL;
lip = xfs_trans_ail_cursor_next(ailp, &cur)) { lip = xfs_trans_ail_cursor_next(ailp, &cur)) {
const struct xfs_item_ops *ops;
if (!xlog_item_is_intent(lip)) if (!xlog_item_is_intent(lip))
break; break;
...@@ -2567,13 +2569,17 @@ xlog_recover_process_intents( ...@@ -2567,13 +2569,17 @@ xlog_recover_process_intents(
* deferred ops, you /must/ attach them to the capture list in * deferred ops, you /must/ attach them to the capture list in
* the recover routine or else those subsequent intents will be * the recover routine or else those subsequent intents will be
* replayed in the wrong order! * 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); 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); spin_lock(&ailp->ail_lock);
if (error) { if (error) {
trace_xlog_intent_recovery_failed(log->l_mp, error, trace_xlog_intent_recovery_failed(log->l_mp, error,
lip->li_ops->iop_recover); ops->iop_recover);
break; break;
} }
} }
......
...@@ -118,10 +118,10 @@ xfs_check_ondisk_structs(void) ...@@ -118,10 +118,10 @@ xfs_check_ondisk_structs(void)
/* log structures */ /* log structures */
XFS_CHECK_STRUCT_SIZE(struct xfs_buf_log_format, 88); 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_dq_logformat, 24);
XFS_CHECK_STRUCT_SIZE(struct xfs_efd_log_format_32, 28); XFS_CHECK_STRUCT_SIZE(struct xfs_efd_log_format_32, 16);
XFS_CHECK_STRUCT_SIZE(struct xfs_efd_log_format_64, 32); XFS_CHECK_STRUCT_SIZE(struct xfs_efd_log_format_64, 16);
XFS_CHECK_STRUCT_SIZE(struct xfs_efi_log_format_32, 28); XFS_CHECK_STRUCT_SIZE(struct xfs_efi_log_format_32, 16);
XFS_CHECK_STRUCT_SIZE(struct xfs_efi_log_format_64, 32); 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_32, 12);
XFS_CHECK_STRUCT_SIZE(struct xfs_extent_64, 16); XFS_CHECK_STRUCT_SIZE(struct xfs_extent_64, 16);
XFS_CHECK_STRUCT_SIZE(struct xfs_log_dinode, 176); XFS_CHECK_STRUCT_SIZE(struct xfs_log_dinode, 176);
...@@ -134,6 +134,21 @@ xfs_check_ondisk_structs(void) ...@@ -134,6 +134,21 @@ xfs_check_ondisk_structs(void)
XFS_CHECK_STRUCT_SIZE(struct xfs_trans_header, 16); 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_attri_log_format, 40);
XFS_CHECK_STRUCT_SIZE(struct xfs_attrd_log_format, 16); 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 * The v5 superblock format extended several v4 header structures with
......
...@@ -523,7 +523,9 @@ xfs_cui_item_recover( ...@@ -523,7 +523,9 @@ xfs_cui_item_recover(
type = refc_type; type = refc_type;
break; break;
default: 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; error = -EFSCORRUPTED;
goto abort_error; goto abort_error;
} }
...@@ -536,7 +538,8 @@ xfs_cui_item_recover( ...@@ -536,7 +538,8 @@ xfs_cui_item_recover(
&new_fsb, &new_len, &rcur); &new_fsb, &new_len, &rcur);
if (error == -EFSCORRUPTED) if (error == -EFSCORRUPTED)
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
refc, sizeof(*refc)); &cuip->cui_format,
sizeof(cuip->cui_format));
if (error) if (error)
goto abort_error; goto abort_error;
...@@ -622,28 +625,18 @@ static const struct xfs_item_ops xfs_cui_item_ops = { ...@@ -622,28 +625,18 @@ static const struct xfs_item_ops xfs_cui_item_ops = {
.iop_relog = xfs_cui_item_relog, .iop_relog = xfs_cui_item_relog,
}; };
/* static inline void
* 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
xfs_cui_copy_format( xfs_cui_copy_format(
struct xfs_log_iovec *buf, struct xfs_cui_log_format *dst,
struct xfs_cui_log_format *dst_cui_fmt) const struct xfs_cui_log_format *src)
{ {
struct xfs_cui_log_format *src_cui_fmt; unsigned int i;
uint len;
src_cui_fmt = buf->i_addr; memcpy(dst, src, offsetof(struct xfs_cui_log_format, cui_extents));
len = xfs_cui_log_format_sizeof(src_cui_fmt->cui_nextents);
if (buf->i_len == len) { for (i = 0; i < src->cui_nextents; i++)
memcpy(dst_cui_fmt, src_cui_fmt, len); memcpy(&dst->cui_extents[i], &src->cui_extents[i],
return 0; sizeof(struct xfs_phys_extent));
}
XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, NULL);
return -EFSCORRUPTED;
} }
/* /*
...@@ -660,19 +653,28 @@ xlog_recover_cui_commit_pass2( ...@@ -660,19 +653,28 @@ xlog_recover_cui_commit_pass2(
struct xlog_recover_item *item, struct xlog_recover_item *item,
xfs_lsn_t lsn) xfs_lsn_t lsn)
{ {
int error;
struct xfs_mount *mp = log->l_mp; struct xfs_mount *mp = log->l_mp;
struct xfs_cui_log_item *cuip; struct xfs_cui_log_item *cuip;
struct xfs_cui_log_format *cui_formatp; struct xfs_cui_log_format *cui_formatp;
size_t len;
cui_formatp = item->ri_buf[0].i_addr; cui_formatp = item->ri_buf[0].i_addr;
cuip = xfs_cui_init(mp, cui_formatp->cui_nextents); if (item->ri_buf[0].i_len < xfs_cui_log_format_sizeof(0)) {
error = xfs_cui_copy_format(&item->ri_buf[0], &cuip->cui_format); XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
if (error) { item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
xfs_cui_item_free(cuip); return -EFSCORRUPTED;
return error;
} }
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); atomic_set(&cuip->cui_next_extent, cui_formatp->cui_nextents);
/* /*
* Insert the intent into the AIL directly and drop one reference so * Insert the intent into the AIL directly and drop one reference so
...@@ -706,7 +708,8 @@ xlog_recover_cud_commit_pass2( ...@@ -706,7 +708,8 @@ xlog_recover_cud_commit_pass2(
cud_formatp = item->ri_buf[0].i_addr; cud_formatp = item->ri_buf[0].i_addr;
if (item->ri_buf[0].i_len != sizeof(struct xfs_cud_log_format)) { 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; return -EFSCORRUPTED;
} }
......
...@@ -155,31 +155,6 @@ xfs_rui_init( ...@@ -155,31 +155,6 @@ xfs_rui_init(
return ruip; 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) 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); return container_of(lip, struct xfs_rud_log_item, rud_item);
...@@ -582,7 +557,9 @@ xfs_rui_item_recover( ...@@ -582,7 +557,9 @@ xfs_rui_item_recover(
type = XFS_RMAP_FREE; type = XFS_RMAP_FREE;
break; break;
default: 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; error = -EFSCORRUPTED;
goto abort_error; goto abort_error;
} }
...@@ -652,6 +629,20 @@ static const struct xfs_item_ops xfs_rui_item_ops = { ...@@ -652,6 +629,20 @@ static const struct xfs_item_ops xfs_rui_item_ops = {
.iop_relog = xfs_rui_item_relog, .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 * This routine is called to create an in-core extent rmap update
* item from the rui format structure which was logged on disk. * item from the rui format structure which was logged on disk.
...@@ -666,19 +657,28 @@ xlog_recover_rui_commit_pass2( ...@@ -666,19 +657,28 @@ xlog_recover_rui_commit_pass2(
struct xlog_recover_item *item, struct xlog_recover_item *item,
xfs_lsn_t lsn) xfs_lsn_t lsn)
{ {
int error;
struct xfs_mount *mp = log->l_mp; struct xfs_mount *mp = log->l_mp;
struct xfs_rui_log_item *ruip; struct xfs_rui_log_item *ruip;
struct xfs_rui_log_format *rui_formatp; struct xfs_rui_log_format *rui_formatp;
size_t len;
rui_formatp = item->ri_buf[0].i_addr; rui_formatp = item->ri_buf[0].i_addr;
ruip = xfs_rui_init(mp, rui_formatp->rui_nextents); if (item->ri_buf[0].i_len < xfs_rui_log_format_sizeof(0)) {
error = xfs_rui_copy_format(&item->ri_buf[0], &ruip->rui_format); XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
if (error) { item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
xfs_rui_item_free(ruip); return -EFSCORRUPTED;
return error; }
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); atomic_set(&ruip->rui_next_extent, rui_formatp->rui_nextents);
/* /*
* Insert the intent into the AIL directly and drop one reference so * Insert the intent into the AIL directly and drop one reference so
...@@ -711,7 +711,11 @@ xlog_recover_rud_commit_pass2( ...@@ -711,7 +711,11 @@ xlog_recover_rud_commit_pass2(
struct xfs_rud_log_format *rud_formatp; struct xfs_rud_log_format *rud_formatp;
rud_formatp = item->ri_buf[0].i_addr; 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); xlog_recover_release_intent(log, XFS_LI_RUI, rud_formatp->rud_rui_id);
return 0; return 0;
......
...@@ -2028,18 +2028,14 @@ xfs_init_caches(void) ...@@ -2028,18 +2028,14 @@ xfs_init_caches(void)
goto out_destroy_trans_cache; goto out_destroy_trans_cache;
xfs_efd_cache = kmem_cache_create("xfs_efd_item", xfs_efd_cache = kmem_cache_create("xfs_efd_item",
(sizeof(struct xfs_efd_log_item) + xfs_efd_log_item_sizeof(XFS_EFD_MAX_FAST_EXTENTS),
(XFS_EFD_MAX_FAST_EXTENTS - 1) * 0, 0, NULL);
sizeof(struct xfs_extent)),
0, 0, NULL);
if (!xfs_efd_cache) if (!xfs_efd_cache)
goto out_destroy_buf_item_cache; goto out_destroy_buf_item_cache;
xfs_efi_cache = kmem_cache_create("xfs_efi_item", xfs_efi_cache = kmem_cache_create("xfs_efi_item",
(sizeof(struct xfs_efi_log_item) + xfs_efi_log_item_sizeof(XFS_EFI_MAX_FAST_EXTENTS),
(XFS_EFI_MAX_FAST_EXTENTS - 1) * 0, 0, NULL);
sizeof(struct xfs_extent)),
0, 0, NULL);
if (!xfs_efi_cache) if (!xfs_efi_cache)
goto out_destroy_efd_cache; goto out_destroy_efd_cache;
......
...@@ -33,10 +33,15 @@ xfs_sysfs_init( ...@@ -33,10 +33,15 @@ xfs_sysfs_init(
const char *name) const char *name)
{ {
struct kobject *parent; struct kobject *parent;
int err;
parent = parent_kobj ? &parent_kobj->kobject : NULL; parent = parent_kobj ? &parent_kobj->kobject : NULL;
init_completion(&kobj->complete); 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 static inline void
......
...@@ -799,6 +799,9 @@ TRACE_DEFINE_ENUM(PE_SIZE_PTE); ...@@ -799,6 +799,9 @@ TRACE_DEFINE_ENUM(PE_SIZE_PTE);
TRACE_DEFINE_ENUM(PE_SIZE_PMD); TRACE_DEFINE_ENUM(PE_SIZE_PMD);
TRACE_DEFINE_ENUM(PE_SIZE_PUD); 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, TRACE_EVENT(xfs_filemap_fault,
TP_PROTO(struct xfs_inode *ip, enum page_entry_size pe_size, TP_PROTO(struct xfs_inode *ip, enum page_entry_size pe_size,
bool write_fault), bool write_fault),
...@@ -2925,6 +2928,7 @@ DECLARE_EVENT_CLASS(xfs_refcount_extent_class, ...@@ -2925,6 +2928,7 @@ DECLARE_EVENT_CLASS(xfs_refcount_extent_class,
TP_STRUCT__entry( TP_STRUCT__entry(
__field(dev_t, dev) __field(dev_t, dev)
__field(xfs_agnumber_t, agno) __field(xfs_agnumber_t, agno)
__field(enum xfs_refc_domain, domain)
__field(xfs_agblock_t, startblock) __field(xfs_agblock_t, startblock)
__field(xfs_extlen_t, blockcount) __field(xfs_extlen_t, blockcount)
__field(xfs_nlink_t, refcount) __field(xfs_nlink_t, refcount)
...@@ -2932,13 +2936,15 @@ DECLARE_EVENT_CLASS(xfs_refcount_extent_class, ...@@ -2932,13 +2936,15 @@ DECLARE_EVENT_CLASS(xfs_refcount_extent_class,
TP_fast_assign( TP_fast_assign(
__entry->dev = mp->m_super->s_dev; __entry->dev = mp->m_super->s_dev;
__entry->agno = agno; __entry->agno = agno;
__entry->domain = irec->rc_domain;
__entry->startblock = irec->rc_startblock; __entry->startblock = irec->rc_startblock;
__entry->blockcount = irec->rc_blockcount; __entry->blockcount = irec->rc_blockcount;
__entry->refcount = irec->rc_refcount; __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), MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->agno, __entry->agno,
__print_symbolic(__entry->domain, XFS_REFC_DOMAIN_STRINGS),
__entry->startblock, __entry->startblock,
__entry->blockcount, __entry->blockcount,
__entry->refcount) __entry->refcount)
...@@ -2958,6 +2964,7 @@ DECLARE_EVENT_CLASS(xfs_refcount_extent_at_class, ...@@ -2958,6 +2964,7 @@ DECLARE_EVENT_CLASS(xfs_refcount_extent_at_class,
TP_STRUCT__entry( TP_STRUCT__entry(
__field(dev_t, dev) __field(dev_t, dev)
__field(xfs_agnumber_t, agno) __field(xfs_agnumber_t, agno)
__field(enum xfs_refc_domain, domain)
__field(xfs_agblock_t, startblock) __field(xfs_agblock_t, startblock)
__field(xfs_extlen_t, blockcount) __field(xfs_extlen_t, blockcount)
__field(xfs_nlink_t, refcount) __field(xfs_nlink_t, refcount)
...@@ -2966,14 +2973,16 @@ DECLARE_EVENT_CLASS(xfs_refcount_extent_at_class, ...@@ -2966,14 +2973,16 @@ DECLARE_EVENT_CLASS(xfs_refcount_extent_at_class,
TP_fast_assign( TP_fast_assign(
__entry->dev = mp->m_super->s_dev; __entry->dev = mp->m_super->s_dev;
__entry->agno = agno; __entry->agno = agno;
__entry->domain = irec->rc_domain;
__entry->startblock = irec->rc_startblock; __entry->startblock = irec->rc_startblock;
__entry->blockcount = irec->rc_blockcount; __entry->blockcount = irec->rc_blockcount;
__entry->refcount = irec->rc_refcount; __entry->refcount = irec->rc_refcount;
__entry->agbno = agbno; __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), MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->agno, __entry->agno,
__print_symbolic(__entry->domain, XFS_REFC_DOMAIN_STRINGS),
__entry->startblock, __entry->startblock,
__entry->blockcount, __entry->blockcount,
__entry->refcount, __entry->refcount,
...@@ -2994,9 +3003,11 @@ DECLARE_EVENT_CLASS(xfs_refcount_double_extent_class, ...@@ -2994,9 +3003,11 @@ DECLARE_EVENT_CLASS(xfs_refcount_double_extent_class,
TP_STRUCT__entry( TP_STRUCT__entry(
__field(dev_t, dev) __field(dev_t, dev)
__field(xfs_agnumber_t, agno) __field(xfs_agnumber_t, agno)
__field(enum xfs_refc_domain, i1_domain)
__field(xfs_agblock_t, i1_startblock) __field(xfs_agblock_t, i1_startblock)
__field(xfs_extlen_t, i1_blockcount) __field(xfs_extlen_t, i1_blockcount)
__field(xfs_nlink_t, i1_refcount) __field(xfs_nlink_t, i1_refcount)
__field(enum xfs_refc_domain, i2_domain)
__field(xfs_agblock_t, i2_startblock) __field(xfs_agblock_t, i2_startblock)
__field(xfs_extlen_t, i2_blockcount) __field(xfs_extlen_t, i2_blockcount)
__field(xfs_nlink_t, i2_refcount) __field(xfs_nlink_t, i2_refcount)
...@@ -3004,20 +3015,24 @@ DECLARE_EVENT_CLASS(xfs_refcount_double_extent_class, ...@@ -3004,20 +3015,24 @@ DECLARE_EVENT_CLASS(xfs_refcount_double_extent_class,
TP_fast_assign( TP_fast_assign(
__entry->dev = mp->m_super->s_dev; __entry->dev = mp->m_super->s_dev;
__entry->agno = agno; __entry->agno = agno;
__entry->i1_domain = i1->rc_domain;
__entry->i1_startblock = i1->rc_startblock; __entry->i1_startblock = i1->rc_startblock;
__entry->i1_blockcount = i1->rc_blockcount; __entry->i1_blockcount = i1->rc_blockcount;
__entry->i1_refcount = i1->rc_refcount; __entry->i1_refcount = i1->rc_refcount;
__entry->i2_domain = i2->rc_domain;
__entry->i2_startblock = i2->rc_startblock; __entry->i2_startblock = i2->rc_startblock;
__entry->i2_blockcount = i2->rc_blockcount; __entry->i2_blockcount = i2->rc_blockcount;
__entry->i2_refcount = i2->rc_refcount; __entry->i2_refcount = i2->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 -- "
"agbno 0x%x fsbcount 0x%x refcount %u", "dom %s agbno 0x%x fsbcount 0x%x refcount %u",
MAJOR(__entry->dev), MINOR(__entry->dev), MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->agno, __entry->agno,
__print_symbolic(__entry->i1_domain, XFS_REFC_DOMAIN_STRINGS),
__entry->i1_startblock, __entry->i1_startblock,
__entry->i1_blockcount, __entry->i1_blockcount,
__entry->i1_refcount, __entry->i1_refcount,
__print_symbolic(__entry->i2_domain, XFS_REFC_DOMAIN_STRINGS),
__entry->i2_startblock, __entry->i2_startblock,
__entry->i2_blockcount, __entry->i2_blockcount,
__entry->i2_refcount) __entry->i2_refcount)
...@@ -3038,9 +3053,11 @@ DECLARE_EVENT_CLASS(xfs_refcount_double_extent_at_class, ...@@ -3038,9 +3053,11 @@ DECLARE_EVENT_CLASS(xfs_refcount_double_extent_at_class,
TP_STRUCT__entry( TP_STRUCT__entry(
__field(dev_t, dev) __field(dev_t, dev)
__field(xfs_agnumber_t, agno) __field(xfs_agnumber_t, agno)
__field(enum xfs_refc_domain, i1_domain)
__field(xfs_agblock_t, i1_startblock) __field(xfs_agblock_t, i1_startblock)
__field(xfs_extlen_t, i1_blockcount) __field(xfs_extlen_t, i1_blockcount)
__field(xfs_nlink_t, i1_refcount) __field(xfs_nlink_t, i1_refcount)
__field(enum xfs_refc_domain, i2_domain)
__field(xfs_agblock_t, i2_startblock) __field(xfs_agblock_t, i2_startblock)
__field(xfs_extlen_t, i2_blockcount) __field(xfs_extlen_t, i2_blockcount)
__field(xfs_nlink_t, i2_refcount) __field(xfs_nlink_t, i2_refcount)
...@@ -3049,21 +3066,25 @@ DECLARE_EVENT_CLASS(xfs_refcount_double_extent_at_class, ...@@ -3049,21 +3066,25 @@ DECLARE_EVENT_CLASS(xfs_refcount_double_extent_at_class,
TP_fast_assign( TP_fast_assign(
__entry->dev = mp->m_super->s_dev; __entry->dev = mp->m_super->s_dev;
__entry->agno = agno; __entry->agno = agno;
__entry->i1_domain = i1->rc_domain;
__entry->i1_startblock = i1->rc_startblock; __entry->i1_startblock = i1->rc_startblock;
__entry->i1_blockcount = i1->rc_blockcount; __entry->i1_blockcount = i1->rc_blockcount;
__entry->i1_refcount = i1->rc_refcount; __entry->i1_refcount = i1->rc_refcount;
__entry->i2_domain = i2->rc_domain;
__entry->i2_startblock = i2->rc_startblock; __entry->i2_startblock = i2->rc_startblock;
__entry->i2_blockcount = i2->rc_blockcount; __entry->i2_blockcount = i2->rc_blockcount;
__entry->i2_refcount = i2->rc_refcount; __entry->i2_refcount = i2->rc_refcount;
__entry->agbno = agbno; __entry->agbno = agbno;
), ),
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 -- "
"agbno 0x%x fsbcount 0x%x refcount %u @ agbno 0x%x", "dom %s agbno 0x%x fsbcount 0x%x refcount %u @ agbno 0x%x",
MAJOR(__entry->dev), MINOR(__entry->dev), MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->agno, __entry->agno,
__print_symbolic(__entry->i1_domain, XFS_REFC_DOMAIN_STRINGS),
__entry->i1_startblock, __entry->i1_startblock,
__entry->i1_blockcount, __entry->i1_blockcount,
__entry->i1_refcount, __entry->i1_refcount,
__print_symbolic(__entry->i2_domain, XFS_REFC_DOMAIN_STRINGS),
__entry->i2_startblock, __entry->i2_startblock,
__entry->i2_blockcount, __entry->i2_blockcount,
__entry->i2_refcount, __entry->i2_refcount,
...@@ -3086,12 +3107,15 @@ DECLARE_EVENT_CLASS(xfs_refcount_triple_extent_class, ...@@ -3086,12 +3107,15 @@ DECLARE_EVENT_CLASS(xfs_refcount_triple_extent_class,
TP_STRUCT__entry( TP_STRUCT__entry(
__field(dev_t, dev) __field(dev_t, dev)
__field(xfs_agnumber_t, agno) __field(xfs_agnumber_t, agno)
__field(enum xfs_refc_domain, i1_domain)
__field(xfs_agblock_t, i1_startblock) __field(xfs_agblock_t, i1_startblock)
__field(xfs_extlen_t, i1_blockcount) __field(xfs_extlen_t, i1_blockcount)
__field(xfs_nlink_t, i1_refcount) __field(xfs_nlink_t, i1_refcount)
__field(enum xfs_refc_domain, i2_domain)
__field(xfs_agblock_t, i2_startblock) __field(xfs_agblock_t, i2_startblock)
__field(xfs_extlen_t, i2_blockcount) __field(xfs_extlen_t, i2_blockcount)
__field(xfs_nlink_t, i2_refcount) __field(xfs_nlink_t, i2_refcount)
__field(enum xfs_refc_domain, i3_domain)
__field(xfs_agblock_t, i3_startblock) __field(xfs_agblock_t, i3_startblock)
__field(xfs_extlen_t, i3_blockcount) __field(xfs_extlen_t, i3_blockcount)
__field(xfs_nlink_t, i3_refcount) __field(xfs_nlink_t, i3_refcount)
...@@ -3099,27 +3123,33 @@ DECLARE_EVENT_CLASS(xfs_refcount_triple_extent_class, ...@@ -3099,27 +3123,33 @@ DECLARE_EVENT_CLASS(xfs_refcount_triple_extent_class,
TP_fast_assign( TP_fast_assign(
__entry->dev = mp->m_super->s_dev; __entry->dev = mp->m_super->s_dev;
__entry->agno = agno; __entry->agno = agno;
__entry->i1_domain = i1->rc_domain;
__entry->i1_startblock = i1->rc_startblock; __entry->i1_startblock = i1->rc_startblock;
__entry->i1_blockcount = i1->rc_blockcount; __entry->i1_blockcount = i1->rc_blockcount;
__entry->i1_refcount = i1->rc_refcount; __entry->i1_refcount = i1->rc_refcount;
__entry->i2_domain = i2->rc_domain;
__entry->i2_startblock = i2->rc_startblock; __entry->i2_startblock = i2->rc_startblock;
__entry->i2_blockcount = i2->rc_blockcount; __entry->i2_blockcount = i2->rc_blockcount;
__entry->i2_refcount = i2->rc_refcount; __entry->i2_refcount = i2->rc_refcount;
__entry->i3_domain = i3->rc_domain;
__entry->i3_startblock = i3->rc_startblock; __entry->i3_startblock = i3->rc_startblock;
__entry->i3_blockcount = i3->rc_blockcount; __entry->i3_blockcount = i3->rc_blockcount;
__entry->i3_refcount = i3->rc_refcount; __entry->i3_refcount = i3->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 -- "
"agbno 0x%x fsbcount 0x%x refcount %u -- " "dom %s agbno 0x%x fsbcount 0x%x refcount %u -- "
"agbno 0x%x fsbcount 0x%x refcount %u", "dom %s agbno 0x%x fsbcount 0x%x refcount %u",
MAJOR(__entry->dev), MINOR(__entry->dev), MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->agno, __entry->agno,
__print_symbolic(__entry->i1_domain, XFS_REFC_DOMAIN_STRINGS),
__entry->i1_startblock, __entry->i1_startblock,
__entry->i1_blockcount, __entry->i1_blockcount,
__entry->i1_refcount, __entry->i1_refcount,
__print_symbolic(__entry->i2_domain, XFS_REFC_DOMAIN_STRINGS),
__entry->i2_startblock, __entry->i2_startblock,
__entry->i2_blockcount, __entry->i2_blockcount,
__entry->i2_refcount, __entry->i2_refcount,
__print_symbolic(__entry->i3_domain, XFS_REFC_DOMAIN_STRINGS),
__entry->i3_startblock, __entry->i3_startblock,
__entry->i3_blockcount, __entry->i3_blockcount,
__entry->i3_refcount) __entry->i3_refcount)
......
...@@ -730,11 +730,10 @@ void ...@@ -730,11 +730,10 @@ void
xfs_ail_push_all_sync( xfs_ail_push_all_sync(
struct xfs_ail *ailp) struct xfs_ail *ailp)
{ {
struct xfs_log_item *lip;
DEFINE_WAIT(wait); DEFINE_WAIT(wait);
spin_lock(&ailp->ail_lock); 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); prepare_to_wait(&ailp->ail_empty, &wait, TASK_UNINTERRUPTIBLE);
wake_up_process(ailp->ail_task); wake_up_process(ailp->ail_task);
spin_unlock(&ailp->ail_lock); spin_unlock(&ailp->ail_lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment