Merge branch 'xfs-4.10-misc-fixes-3' into for-next

This commit is contained in:
Dave Chinner 2016-12-07 17:42:30 +11:00
commit a444d72e60
28 changed files with 306 additions and 301 deletions

View File

@ -2455,12 +2455,15 @@ xfs_agf_verify(
be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp))) be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp)))
return false; return false;
if (be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]) > XFS_BTREE_MAXLEVELS || if (be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]) < 1 ||
be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]) < 1 ||
be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]) > XFS_BTREE_MAXLEVELS ||
be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]) > XFS_BTREE_MAXLEVELS) be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]) > XFS_BTREE_MAXLEVELS)
return false; return false;
if (xfs_sb_version_hasrmapbt(&mp->m_sb) && if (xfs_sb_version_hasrmapbt(&mp->m_sb) &&
be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]) > XFS_BTREE_MAXLEVELS) (be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]) < 1 ||
be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]) > XFS_BTREE_MAXLEVELS))
return false; return false;
/* /*
@ -2477,7 +2480,8 @@ xfs_agf_verify(
return false; return false;
if (xfs_sb_version_hasreflink(&mp->m_sb) && if (xfs_sb_version_hasreflink(&mp->m_sb) &&
be32_to_cpu(agf->agf_refcount_level) > XFS_BTREE_MAXLEVELS) (be32_to_cpu(agf->agf_refcount_level) < 1 ||
be32_to_cpu(agf->agf_refcount_level) > XFS_BTREE_MAXLEVELS))
return false; return false;
return true;; return true;;

View File

@ -428,6 +428,10 @@ xfs_allocbt_init_cursor(
cur->bc_btnum = btnum; cur->bc_btnum = btnum;
cur->bc_blocklog = mp->m_sb.sb_blocklog; cur->bc_blocklog = mp->m_sb.sb_blocklog;
cur->bc_ops = &xfs_allocbt_ops; cur->bc_ops = &xfs_allocbt_ops;
if (btnum == XFS_BTNUM_BNO)
cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_abtb_2);
else
cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_abtc_2);
if (btnum == XFS_BTNUM_CNT) { if (btnum == XFS_BTNUM_CNT) {
cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]); cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]);

View File

@ -77,7 +77,7 @@ int xfs_attr3_leaf_add(struct xfs_buf *leaf_buffer,
struct xfs_da_args *args); struct xfs_da_args *args);
int xfs_attr3_leaf_remove(struct xfs_buf *leaf_buffer, int xfs_attr3_leaf_remove(struct xfs_buf *leaf_buffer,
struct xfs_da_args *args); struct xfs_da_args *args);
int xfs_attr3_leaf_list_int(struct xfs_buf *bp, void xfs_attr3_leaf_list_int(struct xfs_buf *bp,
struct xfs_attr_list_context *context); struct xfs_attr_list_context *context);
/* /*

View File

@ -518,7 +518,7 @@ void
xfs_bmap_trace_exlist( xfs_bmap_trace_exlist(
xfs_inode_t *ip, /* incore inode pointer */ xfs_inode_t *ip, /* incore inode pointer */
xfs_extnum_t cnt, /* count of entries in the list */ xfs_extnum_t cnt, /* count of entries in the list */
int whichfork, /* data or attr fork */ int whichfork, /* data or attr or cow fork */
unsigned long caller_ip) unsigned long caller_ip)
{ {
xfs_extnum_t idx; /* extent record index */ xfs_extnum_t idx; /* extent record index */
@ -527,11 +527,13 @@ xfs_bmap_trace_exlist(
if (whichfork == XFS_ATTR_FORK) if (whichfork == XFS_ATTR_FORK)
state |= BMAP_ATTRFORK; state |= BMAP_ATTRFORK;
else if (whichfork == XFS_COW_FORK)
state |= BMAP_COWFORK;
ifp = XFS_IFORK_PTR(ip, whichfork); ifp = XFS_IFORK_PTR(ip, whichfork);
ASSERT(cnt == xfs_iext_count(ifp)); ASSERT(cnt == xfs_iext_count(ifp));
for (idx = 0; idx < cnt; idx++) for (idx = 0; idx < cnt; idx++)
trace_xfs_extlist(ip, idx, whichfork, caller_ip); trace_xfs_extlist(ip, idx, state, caller_ip);
} }
/* /*
@ -1151,6 +1153,10 @@ xfs_bmap_add_attrfork(
goto trans_cancel; goto trans_cancel;
if (XFS_IFORK_Q(ip)) if (XFS_IFORK_Q(ip))
goto trans_cancel; goto trans_cancel;
if (ip->i_d.di_anextents != 0) {
error = -EFSCORRUPTED;
goto trans_cancel;
}
if (ip->i_d.di_aformat != XFS_DINODE_FMT_EXTENTS) { if (ip->i_d.di_aformat != XFS_DINODE_FMT_EXTENTS) {
/* /*
* For inodes coming from pre-6.2 filesystems. * For inodes coming from pre-6.2 filesystems.
@ -1158,7 +1164,6 @@ xfs_bmap_add_attrfork(
ASSERT(ip->i_d.di_aformat == 0); ASSERT(ip->i_d.di_aformat == 0);
ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS; ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS;
} }
ASSERT(ip->i_d.di_anextents == 0);
xfs_trans_ijoin(tp, ip, 0); xfs_trans_ijoin(tp, ip, 0);
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
@ -1375,8 +1380,9 @@ xfs_bmap_read_extents(
return error; return error;
block = XFS_BUF_TO_BLOCK(bp); block = XFS_BUF_TO_BLOCK(bp);
} }
if (i != XFS_IFORK_NEXTENTS(ip, whichfork))
return -EFSCORRUPTED;
ASSERT(i == xfs_iext_count(ifp)); ASSERT(i == xfs_iext_count(ifp));
ASSERT(i == XFS_IFORK_NEXTENTS(ip, whichfork));
XFS_BMAP_TRACE_EXLIST(ip, i, whichfork); XFS_BMAP_TRACE_EXLIST(ip, i, whichfork);
return 0; return 0;
error0: error0:

View File

@ -803,6 +803,7 @@ xfs_bmbt_init_cursor(
cur->bc_nlevels = be16_to_cpu(ifp->if_broot->bb_level) + 1; cur->bc_nlevels = be16_to_cpu(ifp->if_broot->bb_level) + 1;
cur->bc_btnum = XFS_BTNUM_BMAP; cur->bc_btnum = XFS_BTNUM_BMAP;
cur->bc_blocklog = mp->m_sb.sb_blocklog; cur->bc_blocklog = mp->m_sb.sb_blocklog;
cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_bmbt_2);
cur->bc_ops = &xfs_bmbt_ops; cur->bc_ops = &xfs_bmbt_ops;
cur->bc_flags = XFS_BTREE_LONG_PTRS | XFS_BTREE_ROOT_IN_INODE; cur->bc_flags = XFS_BTREE_LONG_PTRS | XFS_BTREE_ROOT_IN_INODE;

View File

@ -1769,8 +1769,28 @@ xfs_btree_lookup_get_block(
if (error) if (error)
return error; return error;
/* Check the inode owner since the verifiers don't. */
if (xfs_sb_version_hascrc(&cur->bc_mp->m_sb) &&
(cur->bc_flags & XFS_BTREE_LONG_PTRS) &&
be64_to_cpu((*blkp)->bb_u.l.bb_owner) !=
cur->bc_private.b.ip->i_ino)
goto out_bad;
/* Did we get the level we were looking for? */
if (be16_to_cpu((*blkp)->bb_level) != level)
goto out_bad;
/* Check that internal nodes have at least one record. */
if (level != 0 && be16_to_cpu((*blkp)->bb_numrecs) == 0)
goto out_bad;
xfs_btree_setbuf(cur, level, bp); xfs_btree_setbuf(cur, level, bp);
return 0; return 0;
out_bad:
*blkp = NULL;
xfs_trans_brelse(cur->bc_tp, bp);
return -EFSCORRUPTED;
} }
/* /*

View File

@ -96,46 +96,10 @@ union xfs_btree_rec {
/* /*
* Generic stats interface * Generic stats interface
*/ */
#define __XFS_BTREE_STATS_INC(mp, type, stat) \
XFS_STATS_INC(mp, xs_ ## type ## _2_ ## stat)
#define XFS_BTREE_STATS_INC(cur, stat) \ #define XFS_BTREE_STATS_INC(cur, stat) \
do { \ XFS_STATS_INC_OFF((cur)->bc_mp, (cur)->bc_statoff + __XBTS_ ## stat)
struct xfs_mount *__mp = cur->bc_mp; \ #define XFS_BTREE_STATS_ADD(cur, stat, val) \
switch (cur->bc_btnum) { \ XFS_STATS_ADD_OFF((cur)->bc_mp, (cur)->bc_statoff + __XBTS_ ## stat, val)
case XFS_BTNUM_BNO: __XFS_BTREE_STATS_INC(__mp, abtb, stat); break; \
case XFS_BTNUM_CNT: __XFS_BTREE_STATS_INC(__mp, abtc, stat); break; \
case XFS_BTNUM_BMAP: __XFS_BTREE_STATS_INC(__mp, bmbt, stat); break; \
case XFS_BTNUM_INO: __XFS_BTREE_STATS_INC(__mp, ibt, stat); break; \
case XFS_BTNUM_FINO: __XFS_BTREE_STATS_INC(__mp, fibt, stat); break; \
case XFS_BTNUM_RMAP: __XFS_BTREE_STATS_INC(__mp, rmap, stat); break; \
case XFS_BTNUM_REFC: __XFS_BTREE_STATS_INC(__mp, refcbt, stat); break; \
case XFS_BTNUM_MAX: ASSERT(0); /* fucking gcc */ ; break; \
} \
} while (0)
#define __XFS_BTREE_STATS_ADD(mp, type, stat, val) \
XFS_STATS_ADD(mp, xs_ ## type ## _2_ ## stat, val)
#define XFS_BTREE_STATS_ADD(cur, stat, val) \
do { \
struct xfs_mount *__mp = cur->bc_mp; \
switch (cur->bc_btnum) { \
case XFS_BTNUM_BNO: \
__XFS_BTREE_STATS_ADD(__mp, abtb, stat, val); break; \
case XFS_BTNUM_CNT: \
__XFS_BTREE_STATS_ADD(__mp, abtc, stat, val); break; \
case XFS_BTNUM_BMAP: \
__XFS_BTREE_STATS_ADD(__mp, bmbt, stat, val); break; \
case XFS_BTNUM_INO: \
__XFS_BTREE_STATS_ADD(__mp, ibt, stat, val); break; \
case XFS_BTNUM_FINO: \
__XFS_BTREE_STATS_ADD(__mp, fibt, stat, val); break; \
case XFS_BTNUM_RMAP: \
__XFS_BTREE_STATS_ADD(__mp, rmap, stat, val); break; \
case XFS_BTNUM_REFC: \
__XFS_BTREE_STATS_ADD(__mp, refcbt, stat, val); break; \
case XFS_BTNUM_MAX: ASSERT(0); /* fucking gcc */ ; break; \
} \
} while (0)
#define XFS_BTREE_MAXLEVELS 9 /* max of all btrees */ #define XFS_BTREE_MAXLEVELS 9 /* max of all btrees */
@ -253,6 +217,7 @@ typedef struct xfs_btree_cur
__uint8_t bc_nlevels; /* number of levels in the tree */ __uint8_t bc_nlevels; /* number of levels in the tree */
__uint8_t bc_blocklog; /* log2(blocksize) of btree blocks */ __uint8_t bc_blocklog; /* log2(blocksize) of btree blocks */
xfs_btnum_t bc_btnum; /* identifies which btree type */ xfs_btnum_t bc_btnum; /* identifies which btree type */
int bc_statoff; /* offset of btre stats array */
union { union {
struct { /* needed for BNO, CNT, INO */ struct { /* needed for BNO, CNT, INO */
struct xfs_buf *agbp; /* agf/agi buffer pointer */ struct xfs_buf *agbp; /* agf/agi buffer pointer */

View File

@ -6,10 +6,11 @@
/* /*
* Calculate the intermediate checksum for a buffer that has the CRC field * Calculate the intermediate checksum for a buffer that has the CRC field
* inside it. The offset of the 32bit crc fields is passed as the * inside it. The offset of the 32bit crc fields is passed as the
* cksum_offset parameter. * cksum_offset parameter. We do not modify the buffer during verification,
* hence we have to split the CRC calculation across the cksum_offset.
*/ */
static inline __uint32_t static inline __uint32_t
xfs_start_cksum(char *buffer, size_t length, unsigned long cksum_offset) xfs_start_cksum_safe(char *buffer, size_t length, unsigned long cksum_offset)
{ {
__uint32_t zero = 0; __uint32_t zero = 0;
__uint32_t crc; __uint32_t crc;
@ -25,6 +26,20 @@ xfs_start_cksum(char *buffer, size_t length, unsigned long cksum_offset)
length - (cksum_offset + sizeof(__be32))); length - (cksum_offset + sizeof(__be32)));
} }
/*
* Fast CRC method where the buffer is modified. Callers must have exclusive
* access to the buffer while the calculation takes place.
*/
static inline __uint32_t
xfs_start_cksum_update(char *buffer, size_t length, unsigned long cksum_offset)
{
/* zero the CRC field */
*(__le32 *)(buffer + cksum_offset) = 0;
/* single pass CRC calculation for the entire buffer */
return crc32c(XFS_CRC_SEED, buffer, length);
}
/* /*
* Convert the intermediate checksum to the final ondisk format. * Convert the intermediate checksum to the final ondisk format.
* *
@ -40,11 +55,14 @@ xfs_end_cksum(__uint32_t crc)
/* /*
* Helper to generate the checksum for a buffer. * Helper to generate the checksum for a buffer.
*
* This modifies the buffer temporarily - callers must have exclusive
* access to the buffer while the calculation takes place.
*/ */
static inline void static inline void
xfs_update_cksum(char *buffer, size_t length, unsigned long cksum_offset) xfs_update_cksum(char *buffer, size_t length, unsigned long cksum_offset)
{ {
__uint32_t crc = xfs_start_cksum(buffer, length, cksum_offset); __uint32_t crc = xfs_start_cksum_update(buffer, length, cksum_offset);
*(__le32 *)(buffer + cksum_offset) = xfs_end_cksum(crc); *(__le32 *)(buffer + cksum_offset) = xfs_end_cksum(crc);
} }
@ -55,7 +73,7 @@ xfs_update_cksum(char *buffer, size_t length, unsigned long cksum_offset)
static inline int static inline int
xfs_verify_cksum(char *buffer, size_t length, unsigned long cksum_offset) xfs_verify_cksum(char *buffer, size_t length, unsigned long cksum_offset)
{ {
__uint32_t crc = xfs_start_cksum(buffer, length, cksum_offset); __uint32_t crc = xfs_start_cksum_safe(buffer, length, cksum_offset);
return *(__le32 *)(buffer + cksum_offset) == xfs_end_cksum(crc); return *(__le32 *)(buffer + cksum_offset) == xfs_end_cksum(crc);
} }

View File

@ -329,7 +329,7 @@ xfs_dir3_data_read(
err = xfs_da_read_buf(tp, dp, bno, mapped_bno, bpp, err = xfs_da_read_buf(tp, dp, bno, mapped_bno, bpp,
XFS_DATA_FORK, &xfs_dir3_data_buf_ops); XFS_DATA_FORK, &xfs_dir3_data_buf_ops);
if (!err && tp) if (!err && tp && *bpp)
xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_DATA_BUF); xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_DATA_BUF);
return err; return err;
} }

View File

@ -2451,8 +2451,6 @@ xfs_ialloc_log_agi(
ASSERT(agi->agi_magicnum == cpu_to_be32(XFS_AGI_MAGIC)); ASSERT(agi->agi_magicnum == cpu_to_be32(XFS_AGI_MAGIC));
#endif #endif
xfs_trans_buf_set_type(tp, bp, XFS_BLFT_AGI_BUF);
/* /*
* Compute byte offsets for the first and last fields in the first * Compute byte offsets for the first and last fields in the first
* region and log the agi buffer. This only logs up through * region and log the agi buffer. This only logs up through
@ -2513,8 +2511,15 @@ xfs_agi_verify(
if (!XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum))) if (!XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum)))
return false; return false;
if (be32_to_cpu(agi->agi_level) > XFS_BTREE_MAXLEVELS) if (be32_to_cpu(agi->agi_level) < 1 ||
be32_to_cpu(agi->agi_level) > XFS_BTREE_MAXLEVELS)
return false; return false;
if (xfs_sb_version_hasfinobt(&mp->m_sb) &&
(be32_to_cpu(agi->agi_free_level) < 1 ||
be32_to_cpu(agi->agi_free_level) > XFS_BTREE_MAXLEVELS))
return false;
/* /*
* during growfs operations, the perag is not fully initialised, * during growfs operations, the perag is not fully initialised,
* so we can't use it for any useful checking. growfs ensures we can't * so we can't use it for any useful checking. growfs ensures we can't
@ -2593,6 +2598,8 @@ xfs_read_agi(
XFS_FSS_TO_BB(mp, 1), 0, bpp, &xfs_agi_buf_ops); XFS_FSS_TO_BB(mp, 1), 0, bpp, &xfs_agi_buf_ops);
if (error) if (error)
return error; return error;
if (tp)
xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_AGI_BUF);
xfs_buf_set_ref(*bpp, XFS_AGI_REF); xfs_buf_set_ref(*bpp, XFS_AGI_REF);
return 0; return 0;

View File

@ -365,9 +365,11 @@ xfs_inobt_init_cursor(
if (btnum == XFS_BTNUM_INO) { if (btnum == XFS_BTNUM_INO) {
cur->bc_nlevels = be32_to_cpu(agi->agi_level); cur->bc_nlevels = be32_to_cpu(agi->agi_level);
cur->bc_ops = &xfs_inobt_ops; cur->bc_ops = &xfs_inobt_ops;
cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_ibt_2);
} else { } else {
cur->bc_nlevels = be32_to_cpu(agi->agi_free_level); cur->bc_nlevels = be32_to_cpu(agi->agi_free_level);
cur->bc_ops = &xfs_finobt_ops; cur->bc_ops = &xfs_finobt_ops;
cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_fibt_2);
} }
cur->bc_blocklog = mp->m_sb.sb_blocklog; cur->bc_blocklog = mp->m_sb.sb_blocklog;

View File

@ -392,6 +392,14 @@ xfs_dinode_verify(
if (dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC)) if (dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC))
return false; return false;
/* don't allow invalid i_size */
if (be64_to_cpu(dip->di_size) & (1ULL << 63))
return false;
/* No zero-length symlinks. */
if (S_ISLNK(be16_to_cpu(dip->di_mode)) && dip->di_size == 0)
return false;
/* only version 3 or greater inodes are extensively verified here */ /* only version 3 or greater inodes are extensively verified here */
if (dip->di_version < 3) if (dip->di_version < 3)
return true; return true;
@ -436,7 +444,7 @@ xfs_dinode_calc_crc(
return; return;
ASSERT(xfs_sb_version_hascrc(&mp->m_sb)); ASSERT(xfs_sb_version_hascrc(&mp->m_sb));
crc = xfs_start_cksum((char *)dip, mp->m_sb.sb_inodesize, crc = xfs_start_cksum_update((char *)dip, mp->m_sb.sb_inodesize,
XFS_DINODE_CRC_OFF); XFS_DINODE_CRC_OFF);
dip->di_crc = xfs_end_cksum(crc); dip->di_crc = xfs_end_cksum(crc);
} }

View File

@ -354,6 +354,7 @@ xfs_refcountbt_init_cursor(
cur->bc_btnum = XFS_BTNUM_REFC; cur->bc_btnum = XFS_BTNUM_REFC;
cur->bc_blocklog = mp->m_sb.sb_blocklog; cur->bc_blocklog = mp->m_sb.sb_blocklog;
cur->bc_ops = &xfs_refcountbt_ops; cur->bc_ops = &xfs_refcountbt_ops;
cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_refcbt_2);
cur->bc_nlevels = be32_to_cpu(agf->agf_refcount_level); cur->bc_nlevels = be32_to_cpu(agf->agf_refcount_level);

View File

@ -484,6 +484,7 @@ xfs_rmapbt_init_cursor(
cur->bc_blocklog = mp->m_sb.sb_blocklog; cur->bc_blocklog = mp->m_sb.sb_blocklog;
cur->bc_ops = &xfs_rmapbt_ops; cur->bc_ops = &xfs_rmapbt_ops;
cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]); cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]);
cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_rmap_2);
cur->bc_private.a.agbp = agbp; cur->bc_private.a.agbp = agbp;
cur->bc_private.a.agno = agno; cur->bc_private.a.agno = agno;

View File

@ -112,8 +112,8 @@ typedef struct attrlist_cursor_kern {
*========================================================================*/ *========================================================================*/
/* Return 0 on success, or -errno; other state communicated via *context */ /* void; state communicated via *context */
typedef int (*put_listent_func_t)(struct xfs_attr_list_context *, int, typedef void (*put_listent_func_t)(struct xfs_attr_list_context *, int,
unsigned char *, int, int); unsigned char *, int, int);
typedef struct xfs_attr_list_context { typedef struct xfs_attr_list_context {

View File

@ -74,7 +74,6 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
xfs_attr_sf_entry_t *sfe; xfs_attr_sf_entry_t *sfe;
xfs_inode_t *dp; xfs_inode_t *dp;
int sbsize, nsbuf, count, i; int sbsize, nsbuf, count, i;
int error;
ASSERT(context != NULL); ASSERT(context != NULL);
dp = context->dp; dp = context->dp;
@ -102,13 +101,11 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
(XFS_ISRESET_CURSOR(cursor) && (XFS_ISRESET_CURSOR(cursor) &&
(dp->i_afp->if_bytes + sf->hdr.count * 16) < context->bufsize)) { (dp->i_afp->if_bytes + sf->hdr.count * 16) < context->bufsize)) {
for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) { for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
error = context->put_listent(context, context->put_listent(context,
sfe->flags, sfe->flags,
sfe->nameval, sfe->nameval,
(int)sfe->namelen, (int)sfe->namelen,
(int)sfe->valuelen); (int)sfe->valuelen);
if (error)
return error;
/* /*
* Either search callback finished early or * Either search callback finished early or
* didn't fit it all in the buffer after all. * didn't fit it all in the buffer after all.
@ -193,15 +190,11 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
cursor->hashval = sbp->hash; cursor->hashval = sbp->hash;
cursor->offset = 0; cursor->offset = 0;
} }
error = context->put_listent(context, context->put_listent(context,
sbp->flags, sbp->flags,
sbp->name, sbp->name,
sbp->namelen, sbp->namelen,
sbp->valuelen); sbp->valuelen);
if (error) {
kmem_free(sbuf);
return error;
}
if (context->seen_enough) if (context->seen_enough)
break; break;
cursor->offset++; cursor->offset++;
@ -335,11 +328,7 @@ xfs_attr_node_list(xfs_attr_list_context_t *context)
*/ */
for (;;) { for (;;) {
leaf = bp->b_addr; leaf = bp->b_addr;
error = xfs_attr3_leaf_list_int(bp, context); xfs_attr3_leaf_list_int(bp, context);
if (error) {
xfs_trans_brelse(NULL, bp);
return error;
}
xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf); xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);
if (context->seen_enough || leafhdr.forw == 0) if (context->seen_enough || leafhdr.forw == 0)
break; break;
@ -356,7 +345,7 @@ xfs_attr_node_list(xfs_attr_list_context_t *context)
/* /*
* Copy out attribute list entries for attr_list(), for leaf attribute lists. * Copy out attribute list entries for attr_list(), for leaf attribute lists.
*/ */
int void
xfs_attr3_leaf_list_int( xfs_attr3_leaf_list_int(
struct xfs_buf *bp, struct xfs_buf *bp,
struct xfs_attr_list_context *context) struct xfs_attr_list_context *context)
@ -366,7 +355,6 @@ xfs_attr3_leaf_list_int(
struct xfs_attr3_icleaf_hdr ichdr; struct xfs_attr3_icleaf_hdr ichdr;
struct xfs_attr_leaf_entry *entries; struct xfs_attr_leaf_entry *entries;
struct xfs_attr_leaf_entry *entry; struct xfs_attr_leaf_entry *entry;
int retval;
int i; int i;
struct xfs_mount *mp = context->dp->i_mount; struct xfs_mount *mp = context->dp->i_mount;
@ -399,7 +387,7 @@ xfs_attr3_leaf_list_int(
} }
if (i == ichdr.count) { if (i == ichdr.count) {
trace_xfs_attr_list_notfound(context); trace_xfs_attr_list_notfound(context);
return 0; return;
} }
} else { } else {
entry = &entries[0]; entry = &entries[0];
@ -410,7 +398,6 @@ xfs_attr3_leaf_list_int(
/* /*
* We have found our place, start copying out the new attributes. * We have found our place, start copying out the new attributes.
*/ */
retval = 0;
for (; i < ichdr.count; entry++, i++) { for (; i < ichdr.count; entry++, i++) {
char *name; char *name;
int namelen, valuelen; int namelen, valuelen;
@ -439,16 +426,14 @@ xfs_attr3_leaf_list_int(
valuelen = be32_to_cpu(name_rmt->valuelen); valuelen = be32_to_cpu(name_rmt->valuelen);
} }
retval = context->put_listent(context, entry->flags, context->put_listent(context, entry->flags,
name, namelen, valuelen); name, namelen, valuelen);
if (retval)
break;
if (context->seen_enough) if (context->seen_enough)
break; break;
cursor->offset++; cursor->offset++;
} }
trace_xfs_attr_list_leaf_end(context); trace_xfs_attr_list_leaf_end(context);
return retval; return;
} }
/* /*
@ -467,9 +452,9 @@ xfs_attr_leaf_list(xfs_attr_list_context_t *context)
if (error) if (error)
return error; return error;
error = xfs_attr3_leaf_list_int(bp, context); xfs_attr3_leaf_list_int(bp, context);
xfs_trans_brelse(NULL, bp); xfs_trans_brelse(NULL, bp);
return error; return 0;
} }
int int
@ -513,7 +498,7 @@ xfs_attr_list_int(
* Take care to check values and protect against them changing later, * Take care to check values and protect against them changing later,
* we may be reading them directly out of a user buffer. * we may be reading them directly out of a user buffer.
*/ */
STATIC int STATIC void
xfs_attr_put_listent( xfs_attr_put_listent(
xfs_attr_list_context_t *context, xfs_attr_list_context_t *context,
int flags, int flags,
@ -536,10 +521,10 @@ xfs_attr_put_listent(
*/ */
if (((context->flags & ATTR_SECURE) == 0) != if (((context->flags & ATTR_SECURE) == 0) !=
((flags & XFS_ATTR_SECURE) == 0)) ((flags & XFS_ATTR_SECURE) == 0))
return 0; return;
if (((context->flags & ATTR_ROOT) == 0) != if (((context->flags & ATTR_ROOT) == 0) !=
((flags & XFS_ATTR_ROOT) == 0)) ((flags & XFS_ATTR_ROOT) == 0))
return 0; return;
arraytop = sizeof(*alist) + arraytop = sizeof(*alist) +
context->count * sizeof(alist->al_offset[0]); context->count * sizeof(alist->al_offset[0]);
@ -548,7 +533,7 @@ xfs_attr_put_listent(
trace_xfs_attr_list_full(context); trace_xfs_attr_list_full(context);
alist->al_more = 1; alist->al_more = 1;
context->seen_enough = 1; context->seen_enough = 1;
return 0; return;
} }
aep = (attrlist_ent_t *)&context->alist[context->firstu]; aep = (attrlist_ent_t *)&context->alist[context->firstu];
@ -558,7 +543,7 @@ xfs_attr_put_listent(
alist->al_offset[context->count++] = context->firstu; alist->al_offset[context->count++] = context->firstu;
alist->al_count = context->count; alist->al_count = context->count;
trace_xfs_attr_list_add(context); trace_xfs_attr_list_add(context);
return 0; return;
} }
/* /*

View File

@ -219,7 +219,6 @@ _xfs_buf_alloc(
init_completion(&bp->b_iowait); init_completion(&bp->b_iowait);
INIT_LIST_HEAD(&bp->b_lru); INIT_LIST_HEAD(&bp->b_lru);
INIT_LIST_HEAD(&bp->b_list); INIT_LIST_HEAD(&bp->b_list);
RB_CLEAR_NODE(&bp->b_rbnode);
sema_init(&bp->b_sema, 0); /* held, no waiters */ sema_init(&bp->b_sema, 0); /* held, no waiters */
spin_lock_init(&bp->b_lock); spin_lock_init(&bp->b_lock);
XB_SET_OWNER(bp); XB_SET_OWNER(bp);
@ -473,6 +472,62 @@ _xfs_buf_map_pages(
/* /*
* Finding and Reading Buffers * Finding and Reading Buffers
*/ */
static int
_xfs_buf_obj_cmp(
struct rhashtable_compare_arg *arg,
const void *obj)
{
const struct xfs_buf_map *map = arg->key;
const struct xfs_buf *bp = obj;
/*
* The key hashing in the lookup path depends on the key being the
* first element of the compare_arg, make sure to assert this.
*/
BUILD_BUG_ON(offsetof(struct xfs_buf_map, bm_bn) != 0);
if (bp->b_bn != map->bm_bn)
return 1;
if (unlikely(bp->b_length != map->bm_len)) {
/*
* found a block number match. If the range doesn't
* match, the only way this is allowed is if the buffer
* in the cache is stale and the transaction that made
* it stale has not yet committed. i.e. we are
* reallocating a busy extent. Skip this buffer and
* continue searching for an exact match.
*/
ASSERT(bp->b_flags & XBF_STALE);
return 1;
}
return 0;
}
static const struct rhashtable_params xfs_buf_hash_params = {
.min_size = 32, /* empty AGs have minimal footprint */
.nelem_hint = 16,
.key_len = sizeof(xfs_daddr_t),
.key_offset = offsetof(struct xfs_buf, b_bn),
.head_offset = offsetof(struct xfs_buf, b_rhash_head),
.automatic_shrinking = true,
.obj_cmpfn = _xfs_buf_obj_cmp,
};
int
xfs_buf_hash_init(
struct xfs_perag *pag)
{
spin_lock_init(&pag->pag_buf_lock);
return rhashtable_init(&pag->pag_buf_hash, &xfs_buf_hash_params);
}
void
xfs_buf_hash_destroy(
struct xfs_perag *pag)
{
rhashtable_destroy(&pag->pag_buf_hash);
}
/* /*
* Look up, and creates if absent, a lockable buffer for * Look up, and creates if absent, a lockable buffer for
@ -488,27 +543,24 @@ _xfs_buf_find(
xfs_buf_t *new_bp) xfs_buf_t *new_bp)
{ {
struct xfs_perag *pag; struct xfs_perag *pag;
struct rb_node **rbp;
struct rb_node *parent;
xfs_buf_t *bp; xfs_buf_t *bp;
xfs_daddr_t blkno = map[0].bm_bn; struct xfs_buf_map cmap = { .bm_bn = map[0].bm_bn };
xfs_daddr_t eofs; xfs_daddr_t eofs;
int numblks = 0;
int i; int i;
for (i = 0; i < nmaps; i++) for (i = 0; i < nmaps; i++)
numblks += map[i].bm_len; cmap.bm_len += map[i].bm_len;
/* Check for IOs smaller than the sector size / not sector aligned */ /* Check for IOs smaller than the sector size / not sector aligned */
ASSERT(!(BBTOB(numblks) < btp->bt_meta_sectorsize)); ASSERT(!(BBTOB(cmap.bm_len) < btp->bt_meta_sectorsize));
ASSERT(!(BBTOB(blkno) & (xfs_off_t)btp->bt_meta_sectormask)); ASSERT(!(BBTOB(cmap.bm_bn) & (xfs_off_t)btp->bt_meta_sectormask));
/* /*
* Corrupted block numbers can get through to here, unfortunately, so we * Corrupted block numbers can get through to here, unfortunately, so we
* have to check that the buffer falls within the filesystem bounds. * have to check that the buffer falls within the filesystem bounds.
*/ */
eofs = XFS_FSB_TO_BB(btp->bt_mount, btp->bt_mount->m_sb.sb_dblocks); eofs = XFS_FSB_TO_BB(btp->bt_mount, btp->bt_mount->m_sb.sb_dblocks);
if (blkno < 0 || blkno >= eofs) { if (cmap.bm_bn < 0 || cmap.bm_bn >= eofs) {
/* /*
* XXX (dgc): we should really be returning -EFSCORRUPTED here, * XXX (dgc): we should really be returning -EFSCORRUPTED here,
* but none of the higher level infrastructure supports * but none of the higher level infrastructure supports
@ -516,53 +568,29 @@ _xfs_buf_find(
*/ */
xfs_alert(btp->bt_mount, xfs_alert(btp->bt_mount,
"%s: Block out of range: block 0x%llx, EOFS 0x%llx ", "%s: Block out of range: block 0x%llx, EOFS 0x%llx ",
__func__, blkno, eofs); __func__, cmap.bm_bn, eofs);
WARN_ON(1); WARN_ON(1);
return NULL; return NULL;
} }
/* get tree root */
pag = xfs_perag_get(btp->bt_mount, pag = xfs_perag_get(btp->bt_mount,
xfs_daddr_to_agno(btp->bt_mount, blkno)); xfs_daddr_to_agno(btp->bt_mount, cmap.bm_bn));
/* walk tree */
spin_lock(&pag->pag_buf_lock); spin_lock(&pag->pag_buf_lock);
rbp = &pag->pag_buf_tree.rb_node; bp = rhashtable_lookup_fast(&pag->pag_buf_hash, &cmap,
parent = NULL; xfs_buf_hash_params);
bp = NULL; if (bp) {
while (*rbp) { atomic_inc(&bp->b_hold);
parent = *rbp; goto found;
bp = rb_entry(parent, struct xfs_buf, b_rbnode);
if (blkno < bp->b_bn)
rbp = &(*rbp)->rb_left;
else if (blkno > bp->b_bn)
rbp = &(*rbp)->rb_right;
else {
/*
* found a block number match. If the range doesn't
* match, the only way this is allowed is if the buffer
* in the cache is stale and the transaction that made
* it stale has not yet committed. i.e. we are
* reallocating a busy extent. Skip this buffer and
* continue searching to the right for an exact match.
*/
if (bp->b_length != numblks) {
ASSERT(bp->b_flags & XBF_STALE);
rbp = &(*rbp)->rb_right;
continue;
}
atomic_inc(&bp->b_hold);
goto found;
}
} }
/* No match found */ /* No match found */
if (new_bp) { if (new_bp) {
rb_link_node(&new_bp->b_rbnode, parent, rbp);
rb_insert_color(&new_bp->b_rbnode, &pag->pag_buf_tree);
/* the buffer keeps the perag reference until it is freed */ /* the buffer keeps the perag reference until it is freed */
new_bp->b_pag = pag; new_bp->b_pag = pag;
rhashtable_insert_fast(&pag->pag_buf_hash,
&new_bp->b_rhash_head,
xfs_buf_hash_params);
spin_unlock(&pag->pag_buf_lock); spin_unlock(&pag->pag_buf_lock);
} else { } else {
XFS_STATS_INC(btp->bt_mount, xb_miss_locked); XFS_STATS_INC(btp->bt_mount, xb_miss_locked);
@ -930,7 +958,6 @@ xfs_buf_rele(
if (!pag) { if (!pag) {
ASSERT(list_empty(&bp->b_lru)); ASSERT(list_empty(&bp->b_lru));
ASSERT(RB_EMPTY_NODE(&bp->b_rbnode));
if (atomic_dec_and_test(&bp->b_hold)) { if (atomic_dec_and_test(&bp->b_hold)) {
xfs_buf_ioacct_dec(bp); xfs_buf_ioacct_dec(bp);
xfs_buf_free(bp); xfs_buf_free(bp);
@ -938,8 +965,6 @@ xfs_buf_rele(
return; return;
} }
ASSERT(!RB_EMPTY_NODE(&bp->b_rbnode));
ASSERT(atomic_read(&bp->b_hold) > 0); ASSERT(atomic_read(&bp->b_hold) > 0);
release = atomic_dec_and_lock(&bp->b_hold, &pag->pag_buf_lock); release = atomic_dec_and_lock(&bp->b_hold, &pag->pag_buf_lock);
@ -983,7 +1008,8 @@ xfs_buf_rele(
} }
ASSERT(!(bp->b_flags & _XBF_DELWRI_Q)); ASSERT(!(bp->b_flags & _XBF_DELWRI_Q));
rb_erase(&bp->b_rbnode, &pag->pag_buf_tree); rhashtable_remove_fast(&pag->pag_buf_hash, &bp->b_rhash_head,
xfs_buf_hash_params);
spin_unlock(&pag->pag_buf_lock); spin_unlock(&pag->pag_buf_lock);
xfs_perag_put(pag); xfs_perag_put(pag);
freebuf = true; freebuf = true;

View File

@ -151,7 +151,7 @@ typedef struct xfs_buf {
* which is the only bit that is touched if we hit the semaphore * which is the only bit that is touched if we hit the semaphore
* fast-path on locking. * fast-path on locking.
*/ */
struct rb_node b_rbnode; /* rbtree node */ struct rhash_head b_rhash_head; /* pag buffer hash node */
xfs_daddr_t b_bn; /* block number of buffer */ xfs_daddr_t b_bn; /* block number of buffer */
int b_length; /* size of buffer in BBs */ int b_length; /* size of buffer in BBs */
atomic_t b_hold; /* reference count */ atomic_t b_hold; /* reference count */

View File

@ -883,7 +883,6 @@ xfs_file_clone_range(
len, false); len, false);
} }
#define XFS_MAX_DEDUPE_LEN (16 * 1024 * 1024)
STATIC ssize_t STATIC ssize_t
xfs_file_dedupe_range( xfs_file_dedupe_range(
struct file *src_file, struct file *src_file,
@ -894,14 +893,6 @@ xfs_file_dedupe_range(
{ {
int error; int error;
/*
* Limit the total length we will dedupe for each operation.
* This is intended to bound the total time spent in this
* ioctl to something sane.
*/
if (len > XFS_MAX_DEDUPE_LEN)
len = XFS_MAX_DEDUPE_LEN;
error = xfs_reflink_remap_range(src_file, loff, dst_file, dst_loff, error = xfs_reflink_remap_range(src_file, loff, dst_file, dst_loff,
len, true); len, true);
if (error) if (error)

View File

@ -2032,7 +2032,6 @@ xfs_iunlink(
agi->agi_unlinked[bucket_index] = cpu_to_be32(agino); agi->agi_unlinked[bucket_index] = cpu_to_be32(agino);
offset = offsetof(xfs_agi_t, agi_unlinked) + offset = offsetof(xfs_agi_t, agi_unlinked) +
(sizeof(xfs_agino_t) * bucket_index); (sizeof(xfs_agino_t) * bucket_index);
xfs_trans_buf_set_type(tp, agibp, XFS_BLFT_AGI_BUF);
xfs_trans_log_buf(tp, agibp, offset, xfs_trans_log_buf(tp, agibp, offset,
(offset + sizeof(xfs_agino_t) - 1)); (offset + sizeof(xfs_agino_t) - 1));
return 0; return 0;
@ -2124,7 +2123,6 @@ xfs_iunlink_remove(
agi->agi_unlinked[bucket_index] = cpu_to_be32(next_agino); agi->agi_unlinked[bucket_index] = cpu_to_be32(next_agino);
offset = offsetof(xfs_agi_t, agi_unlinked) + offset = offsetof(xfs_agi_t, agi_unlinked) +
(sizeof(xfs_agino_t) * bucket_index); (sizeof(xfs_agino_t) * bucket_index);
xfs_trans_buf_set_type(tp, agibp, XFS_BLFT_AGI_BUF);
xfs_trans_log_buf(tp, agibp, offset, xfs_trans_log_buf(tp, agibp, offset,
(offset + sizeof(xfs_agino_t) - 1)); (offset + sizeof(xfs_agino_t) - 1));
} else { } else {

View File

@ -78,6 +78,7 @@ typedef __u32 xfs_nlink_t;
#include <linux/freezer.h> #include <linux/freezer.h>
#include <linux/list_sort.h> #include <linux/list_sort.h>
#include <linux/ratelimit.h> #include <linux/ratelimit.h>
#include <linux/rhashtable.h>
#include <asm/page.h> #include <asm/page.h>
#include <asm/div64.h> #include <asm/div64.h>

View File

@ -1668,7 +1668,7 @@ xlog_cksum(
__uint32_t crc; __uint32_t crc;
/* first generate the crc for the record header ... */ /* first generate the crc for the record header ... */
crc = xfs_start_cksum((char *)rhead, crc = xfs_start_cksum_update((char *)rhead,
sizeof(struct xlog_rec_header), sizeof(struct xlog_rec_header),
offsetof(struct xlog_rec_header, h_crc)); offsetof(struct xlog_rec_header, h_crc));

View File

@ -5113,19 +5113,21 @@ xlog_recover_process(
struct list_head *buffer_list) struct list_head *buffer_list)
{ {
int error; int error;
__le32 old_crc = rhead->h_crc;
__le32 crc; __le32 crc;
crc = xlog_cksum(log, rhead, dp, be32_to_cpu(rhead->h_len)); crc = xlog_cksum(log, rhead, dp, be32_to_cpu(rhead->h_len));
/* /*
* Nothing else to do if this is a CRC verification pass. Just return * Nothing else to do if this is a CRC verification pass. Just return
* if this a record with a non-zero crc. Unfortunately, mkfs always * if this a record with a non-zero crc. Unfortunately, mkfs always
* sets h_crc to 0 so we must consider this valid even on v5 supers. * sets old_crc to 0 so we must consider this valid even on v5 supers.
* Otherwise, return EFSBADCRC on failure so the callers up the stack * Otherwise, return EFSBADCRC on failure so the callers up the stack
* know precisely what failed. * know precisely what failed.
*/ */
if (pass == XLOG_RECOVER_CRCPASS) { if (pass == XLOG_RECOVER_CRCPASS) {
if (rhead->h_crc && crc != rhead->h_crc) if (old_crc && crc != old_crc)
return -EFSBADCRC; return -EFSBADCRC;
return 0; return 0;
} }
@ -5136,11 +5138,11 @@ xlog_recover_process(
* zero CRC check prevents warnings from being emitted when upgrading * zero CRC check prevents warnings from being emitted when upgrading
* the kernel from one that does not add CRCs by default. * the kernel from one that does not add CRCs by default.
*/ */
if (crc != rhead->h_crc) { if (crc != old_crc) {
if (rhead->h_crc || xfs_sb_version_hascrc(&log->l_mp->m_sb)) { if (old_crc || xfs_sb_version_hascrc(&log->l_mp->m_sb)) {
xfs_alert(log->l_mp, xfs_alert(log->l_mp,
"log record CRC mismatch: found 0x%x, expected 0x%x.", "log record CRC mismatch: found 0x%x, expected 0x%x.",
le32_to_cpu(rhead->h_crc), le32_to_cpu(old_crc),
le32_to_cpu(crc)); le32_to_cpu(crc));
xfs_hex_dump(dp, 32); xfs_hex_dump(dp, 32);
} }

View File

@ -157,6 +157,7 @@ xfs_free_perag(
spin_unlock(&mp->m_perag_lock); spin_unlock(&mp->m_perag_lock);
ASSERT(pag); ASSERT(pag);
ASSERT(atomic_read(&pag->pag_ref) == 0); ASSERT(atomic_read(&pag->pag_ref) == 0);
xfs_buf_hash_destroy(pag);
call_rcu(&pag->rcu_head, __xfs_free_perag); call_rcu(&pag->rcu_head, __xfs_free_perag);
} }
} }
@ -212,8 +213,8 @@ xfs_initialize_perag(
spin_lock_init(&pag->pag_ici_lock); spin_lock_init(&pag->pag_ici_lock);
mutex_init(&pag->pag_ici_reclaim_lock); mutex_init(&pag->pag_ici_reclaim_lock);
INIT_RADIX_TREE(&pag->pag_ici_root, GFP_ATOMIC); INIT_RADIX_TREE(&pag->pag_ici_root, GFP_ATOMIC);
spin_lock_init(&pag->pag_buf_lock); if (xfs_buf_hash_init(pag))
pag->pag_buf_tree = RB_ROOT; goto out_unwind;
if (radix_tree_preload(GFP_NOFS)) if (radix_tree_preload(GFP_NOFS))
goto out_unwind; goto out_unwind;
@ -239,9 +240,11 @@ xfs_initialize_perag(
return 0; return 0;
out_unwind: out_unwind:
xfs_buf_hash_destroy(pag);
kmem_free(pag); kmem_free(pag);
for (; index > first_initialised; index--) { for (; index > first_initialised; index--) {
pag = radix_tree_delete(&mp->m_perag_tree, index); pag = radix_tree_delete(&mp->m_perag_tree, index);
xfs_buf_hash_destroy(pag);
kmem_free(pag); kmem_free(pag);
} }
return error; return error;

View File

@ -393,8 +393,8 @@ typedef struct xfs_perag {
unsigned long pag_ici_reclaim_cursor; /* reclaim restart point */ unsigned long pag_ici_reclaim_cursor; /* reclaim restart point */
/* buffer cache index */ /* buffer cache index */
spinlock_t pag_buf_lock; /* lock for pag_buf_tree */ spinlock_t pag_buf_lock; /* lock for pag_buf_hash */
struct rb_root pag_buf_tree; /* ordered tree of active buffers */ struct rhashtable pag_buf_hash;
/* for rcu-safe freeing */ /* for rcu-safe freeing */
struct rcu_head rcu_head; struct rcu_head rcu_head;
@ -424,6 +424,9 @@ xfs_perag_resv(
} }
} }
int xfs_buf_hash_init(xfs_perag_t *pag);
void xfs_buf_hash_destroy(xfs_perag_t *pag);
extern void xfs_uuid_table_free(void); extern void xfs_uuid_table_free(void);
extern int xfs_log_sbcount(xfs_mount_t *); extern int xfs_log_sbcount(xfs_mount_t *);
extern __uint64_t xfs_default_resblks(xfs_mount_t *mp); extern __uint64_t xfs_default_resblks(xfs_mount_t *mp);

View File

@ -80,9 +80,9 @@ int xfs_stats_format(struct xfsstats __percpu *stats, char *buf)
} }
/* extra precision counters */ /* extra precision counters */
for_each_possible_cpu(i) { for_each_possible_cpu(i) {
xs_xstrat_bytes += per_cpu_ptr(stats, i)->xs_xstrat_bytes; xs_xstrat_bytes += per_cpu_ptr(stats, i)->s.xs_xstrat_bytes;
xs_write_bytes += per_cpu_ptr(stats, i)->xs_write_bytes; xs_write_bytes += per_cpu_ptr(stats, i)->s.xs_write_bytes;
xs_read_bytes += per_cpu_ptr(stats, i)->xs_read_bytes; xs_read_bytes += per_cpu_ptr(stats, i)->s.xs_read_bytes;
} }
len += snprintf(buf + len, PATH_MAX-len, "xpc %Lu %Lu %Lu\n", len += snprintf(buf + len, PATH_MAX-len, "xpc %Lu %Lu %Lu\n",
@ -106,9 +106,9 @@ void xfs_stats_clearall(struct xfsstats __percpu *stats)
for_each_possible_cpu(c) { for_each_possible_cpu(c) {
preempt_disable(); preempt_disable();
/* save vn_active, it's a universal truth! */ /* save vn_active, it's a universal truth! */
vn_active = per_cpu_ptr(stats, c)->vn_active; vn_active = per_cpu_ptr(stats, c)->s.vn_active;
memset(per_cpu_ptr(stats, c), 0, sizeof(*stats)); memset(per_cpu_ptr(stats, c), 0, sizeof(*stats));
per_cpu_ptr(stats, c)->vn_active = vn_active; per_cpu_ptr(stats, c)->s.vn_active = vn_active;
preempt_enable(); preempt_enable();
} }
} }

View File

@ -21,10 +21,38 @@
#include <linux/percpu.h> #include <linux/percpu.h>
/*
* The btree stats arrays have fixed offsets for the different stats. We
* store the base index in the btree cursor via XFS_STATS_CALC_INDEX() and
* that allows us to use fixed offsets into the stats array for each btree
* stat. These index offsets are defined in the order they will be emitted
* in the stats files, so it is possible to add new btree stat types by
* appending to the enum list below.
*/
enum {
__XBTS_lookup = 0,
__XBTS_compare = 1,
__XBTS_insrec = 2,
__XBTS_delrec = 3,
__XBTS_newroot = 4,
__XBTS_killroot = 5,
__XBTS_increment = 6,
__XBTS_decrement = 7,
__XBTS_lshift = 8,
__XBTS_rshift = 9,
__XBTS_split = 10,
__XBTS_join = 11,
__XBTS_alloc = 12,
__XBTS_free = 13,
__XBTS_moves = 14,
__XBTS_MAX = 15,
};
/* /*
* XFS global statistics * XFS global statistics
*/ */
struct xfsstats { struct __xfsstats {
# define XFSSTAT_END_EXTENT_ALLOC 4 # define XFSSTAT_END_EXTENT_ALLOC 4
__uint32_t xs_allocx; __uint32_t xs_allocx;
__uint32_t xs_allocb; __uint32_t xs_allocb;
@ -117,118 +145,20 @@ struct xfsstats {
__uint32_t xb_page_found; __uint32_t xb_page_found;
__uint32_t xb_get_read; __uint32_t xb_get_read;
/* Version 2 btree counters */ /* Version 2 btree counters */
#define XFSSTAT_END_ABTB_V2 (XFSSTAT_END_BUF+15) #define XFSSTAT_END_ABTB_V2 (XFSSTAT_END_BUF + __XBTS_MAX)
__uint32_t xs_abtb_2_lookup; __uint32_t xs_abtb_2[__XBTS_MAX];
__uint32_t xs_abtb_2_compare; #define XFSSTAT_END_ABTC_V2 (XFSSTAT_END_ABTB_V2 + __XBTS_MAX)
__uint32_t xs_abtb_2_insrec; __uint32_t xs_abtc_2[__XBTS_MAX];
__uint32_t xs_abtb_2_delrec; #define XFSSTAT_END_BMBT_V2 (XFSSTAT_END_ABTC_V2 + __XBTS_MAX)
__uint32_t xs_abtb_2_newroot; __uint32_t xs_bmbt_2[__XBTS_MAX];
__uint32_t xs_abtb_2_killroot; #define XFSSTAT_END_IBT_V2 (XFSSTAT_END_BMBT_V2 + __XBTS_MAX)
__uint32_t xs_abtb_2_increment; __uint32_t xs_ibt_2[__XBTS_MAX];
__uint32_t xs_abtb_2_decrement; #define XFSSTAT_END_FIBT_V2 (XFSSTAT_END_IBT_V2 + __XBTS_MAX)
__uint32_t xs_abtb_2_lshift; __uint32_t xs_fibt_2[__XBTS_MAX];
__uint32_t xs_abtb_2_rshift; #define XFSSTAT_END_RMAP_V2 (XFSSTAT_END_FIBT_V2 + __XBTS_MAX)
__uint32_t xs_abtb_2_split; __uint32_t xs_rmap_2[__XBTS_MAX];
__uint32_t xs_abtb_2_join; #define XFSSTAT_END_REFCOUNT (XFSSTAT_END_RMAP_V2 + __XBTS_MAX)
__uint32_t xs_abtb_2_alloc; __uint32_t xs_refcbt_2[__XBTS_MAX];
__uint32_t xs_abtb_2_free;
__uint32_t xs_abtb_2_moves;
#define XFSSTAT_END_ABTC_V2 (XFSSTAT_END_ABTB_V2+15)
__uint32_t xs_abtc_2_lookup;
__uint32_t xs_abtc_2_compare;
__uint32_t xs_abtc_2_insrec;
__uint32_t xs_abtc_2_delrec;
__uint32_t xs_abtc_2_newroot;
__uint32_t xs_abtc_2_killroot;
__uint32_t xs_abtc_2_increment;
__uint32_t xs_abtc_2_decrement;
__uint32_t xs_abtc_2_lshift;
__uint32_t xs_abtc_2_rshift;
__uint32_t xs_abtc_2_split;
__uint32_t xs_abtc_2_join;
__uint32_t xs_abtc_2_alloc;
__uint32_t xs_abtc_2_free;
__uint32_t xs_abtc_2_moves;
#define XFSSTAT_END_BMBT_V2 (XFSSTAT_END_ABTC_V2+15)
__uint32_t xs_bmbt_2_lookup;
__uint32_t xs_bmbt_2_compare;
__uint32_t xs_bmbt_2_insrec;
__uint32_t xs_bmbt_2_delrec;
__uint32_t xs_bmbt_2_newroot;
__uint32_t xs_bmbt_2_killroot;
__uint32_t xs_bmbt_2_increment;
__uint32_t xs_bmbt_2_decrement;
__uint32_t xs_bmbt_2_lshift;
__uint32_t xs_bmbt_2_rshift;
__uint32_t xs_bmbt_2_split;
__uint32_t xs_bmbt_2_join;
__uint32_t xs_bmbt_2_alloc;
__uint32_t xs_bmbt_2_free;
__uint32_t xs_bmbt_2_moves;
#define XFSSTAT_END_IBT_V2 (XFSSTAT_END_BMBT_V2+15)
__uint32_t xs_ibt_2_lookup;
__uint32_t xs_ibt_2_compare;
__uint32_t xs_ibt_2_insrec;
__uint32_t xs_ibt_2_delrec;
__uint32_t xs_ibt_2_newroot;
__uint32_t xs_ibt_2_killroot;
__uint32_t xs_ibt_2_increment;
__uint32_t xs_ibt_2_decrement;
__uint32_t xs_ibt_2_lshift;
__uint32_t xs_ibt_2_rshift;
__uint32_t xs_ibt_2_split;
__uint32_t xs_ibt_2_join;
__uint32_t xs_ibt_2_alloc;
__uint32_t xs_ibt_2_free;
__uint32_t xs_ibt_2_moves;
#define XFSSTAT_END_FIBT_V2 (XFSSTAT_END_IBT_V2+15)
__uint32_t xs_fibt_2_lookup;
__uint32_t xs_fibt_2_compare;
__uint32_t xs_fibt_2_insrec;
__uint32_t xs_fibt_2_delrec;
__uint32_t xs_fibt_2_newroot;
__uint32_t xs_fibt_2_killroot;
__uint32_t xs_fibt_2_increment;
__uint32_t xs_fibt_2_decrement;
__uint32_t xs_fibt_2_lshift;
__uint32_t xs_fibt_2_rshift;
__uint32_t xs_fibt_2_split;
__uint32_t xs_fibt_2_join;
__uint32_t xs_fibt_2_alloc;
__uint32_t xs_fibt_2_free;
__uint32_t xs_fibt_2_moves;
#define XFSSTAT_END_RMAP_V2 (XFSSTAT_END_FIBT_V2+15)
__uint32_t xs_rmap_2_lookup;
__uint32_t xs_rmap_2_compare;
__uint32_t xs_rmap_2_insrec;
__uint32_t xs_rmap_2_delrec;
__uint32_t xs_rmap_2_newroot;
__uint32_t xs_rmap_2_killroot;
__uint32_t xs_rmap_2_increment;
__uint32_t xs_rmap_2_decrement;
__uint32_t xs_rmap_2_lshift;
__uint32_t xs_rmap_2_rshift;
__uint32_t xs_rmap_2_split;
__uint32_t xs_rmap_2_join;
__uint32_t xs_rmap_2_alloc;
__uint32_t xs_rmap_2_free;
__uint32_t xs_rmap_2_moves;
#define XFSSTAT_END_REFCOUNT (XFSSTAT_END_RMAP_V2 + 15)
__uint32_t xs_refcbt_2_lookup;
__uint32_t xs_refcbt_2_compare;
__uint32_t xs_refcbt_2_insrec;
__uint32_t xs_refcbt_2_delrec;
__uint32_t xs_refcbt_2_newroot;
__uint32_t xs_refcbt_2_killroot;
__uint32_t xs_refcbt_2_increment;
__uint32_t xs_refcbt_2_decrement;
__uint32_t xs_refcbt_2_lshift;
__uint32_t xs_refcbt_2_rshift;
__uint32_t xs_refcbt_2_split;
__uint32_t xs_refcbt_2_join;
__uint32_t xs_refcbt_2_alloc;
__uint32_t xs_refcbt_2_free;
__uint32_t xs_refcbt_2_moves;
#define XFSSTAT_END_XQMSTAT (XFSSTAT_END_REFCOUNT + 6) #define XFSSTAT_END_XQMSTAT (XFSSTAT_END_REFCOUNT + 6)
__uint32_t xs_qm_dqreclaims; __uint32_t xs_qm_dqreclaims;
__uint32_t xs_qm_dqreclaim_misses; __uint32_t xs_qm_dqreclaim_misses;
@ -245,26 +175,58 @@ struct xfsstats {
__uint64_t xs_read_bytes; __uint64_t xs_read_bytes;
}; };
struct xfsstats {
union {
struct __xfsstats s;
uint32_t a[XFSSTAT_END_XQMSTAT];
};
};
/*
* simple wrapper for getting the array index of s struct member offset
*/
#define XFS_STATS_CALC_INDEX(member) \
(offsetof(struct __xfsstats, member) / (int)sizeof(__uint32_t))
int xfs_stats_format(struct xfsstats __percpu *stats, char *buf); int xfs_stats_format(struct xfsstats __percpu *stats, char *buf);
void xfs_stats_clearall(struct xfsstats __percpu *stats); void xfs_stats_clearall(struct xfsstats __percpu *stats);
extern struct xstats xfsstats; extern struct xstats xfsstats;
#define XFS_STATS_INC(mp, v) \ #define XFS_STATS_INC(mp, v) \
do { \ do { \
per_cpu_ptr(xfsstats.xs_stats, current_cpu())->v++; \ per_cpu_ptr(xfsstats.xs_stats, current_cpu())->s.v++; \
per_cpu_ptr(mp->m_stats.xs_stats, current_cpu())->v++; \ per_cpu_ptr(mp->m_stats.xs_stats, current_cpu())->s.v++; \
} while (0) } while (0)
#define XFS_STATS_DEC(mp, v) \ #define XFS_STATS_DEC(mp, v) \
do { \ do { \
per_cpu_ptr(xfsstats.xs_stats, current_cpu())->v--; \ per_cpu_ptr(xfsstats.xs_stats, current_cpu())->s.v--; \
per_cpu_ptr(mp->m_stats.xs_stats, current_cpu())->v--; \ per_cpu_ptr(mp->m_stats.xs_stats, current_cpu())->s.v--; \
} while (0) } while (0)
#define XFS_STATS_ADD(mp, v, inc) \ #define XFS_STATS_ADD(mp, v, inc) \
do { \ do { \
per_cpu_ptr(xfsstats.xs_stats, current_cpu())->v += (inc); \ per_cpu_ptr(xfsstats.xs_stats, current_cpu())->s.v += (inc); \
per_cpu_ptr(mp->m_stats.xs_stats, current_cpu())->v += (inc); \ per_cpu_ptr(mp->m_stats.xs_stats, current_cpu())->s.v += (inc); \
} while (0)
#define XFS_STATS_INC_OFF(mp, off) \
do { \
per_cpu_ptr(xfsstats.xs_stats, current_cpu())->a[off]++; \
per_cpu_ptr(mp->m_stats.xs_stats, current_cpu())->a[off]++; \
} while (0)
#define XFS_STATS_DEC_OFF(mp, off) \
do { \
per_cpu_ptr(xfsstats.xs_stats, current_cpu())->a[off]; \
per_cpu_ptr(mp->m_stats.xs_stats, current_cpu())->a[off]; \
} while (0)
#define XFS_STATS_ADD_OFF(mp, off, inc) \
do { \
per_cpu_ptr(xfsstats.xs_stats, current_cpu())->a[off] += (inc); \
per_cpu_ptr(mp->m_stats.xs_stats, current_cpu())->a[off] += (inc); \
} while (0) } while (0)
#if defined(CONFIG_PROC_FS) #if defined(CONFIG_PROC_FS)

View File

@ -130,7 +130,7 @@ const struct xattr_handler *xfs_xattr_handlers[] = {
NULL NULL
}; };
static int static void
__xfs_xattr_put_listent( __xfs_xattr_put_listent(
struct xfs_attr_list_context *context, struct xfs_attr_list_context *context,
char *prefix, char *prefix,
@ -148,7 +148,7 @@ __xfs_xattr_put_listent(
if (arraytop > context->firstu) { if (arraytop > context->firstu) {
context->count = -1; /* insufficient space */ context->count = -1; /* insufficient space */
context->seen_enough = 1; context->seen_enough = 1;
return 0; return;
} }
offset = (char *)context->alist + context->count; offset = (char *)context->alist + context->count;
strncpy(offset, prefix, prefix_len); strncpy(offset, prefix, prefix_len);
@ -159,10 +159,10 @@ __xfs_xattr_put_listent(
compute_size: compute_size:
context->count += prefix_len + namelen + 1; context->count += prefix_len + namelen + 1;
return 0; return;
} }
static int static void
xfs_xattr_put_listent( xfs_xattr_put_listent(
struct xfs_attr_list_context *context, struct xfs_attr_list_context *context,
int flags, int flags,
@ -180,23 +180,19 @@ xfs_xattr_put_listent(
if (namelen == SGI_ACL_FILE_SIZE && if (namelen == SGI_ACL_FILE_SIZE &&
strncmp(name, SGI_ACL_FILE, strncmp(name, SGI_ACL_FILE,
SGI_ACL_FILE_SIZE) == 0) { SGI_ACL_FILE_SIZE) == 0) {
int ret = __xfs_xattr_put_listent( __xfs_xattr_put_listent(
context, XATTR_SYSTEM_PREFIX, context, XATTR_SYSTEM_PREFIX,
XATTR_SYSTEM_PREFIX_LEN, XATTR_SYSTEM_PREFIX_LEN,
XATTR_POSIX_ACL_ACCESS, XATTR_POSIX_ACL_ACCESS,
strlen(XATTR_POSIX_ACL_ACCESS)); strlen(XATTR_POSIX_ACL_ACCESS));
if (ret)
return ret;
} else if (namelen == SGI_ACL_DEFAULT_SIZE && } else if (namelen == SGI_ACL_DEFAULT_SIZE &&
strncmp(name, SGI_ACL_DEFAULT, strncmp(name, SGI_ACL_DEFAULT,
SGI_ACL_DEFAULT_SIZE) == 0) { SGI_ACL_DEFAULT_SIZE) == 0) {
int ret = __xfs_xattr_put_listent( __xfs_xattr_put_listent(
context, XATTR_SYSTEM_PREFIX, context, XATTR_SYSTEM_PREFIX,
XATTR_SYSTEM_PREFIX_LEN, XATTR_SYSTEM_PREFIX_LEN,
XATTR_POSIX_ACL_DEFAULT, XATTR_POSIX_ACL_DEFAULT,
strlen(XATTR_POSIX_ACL_DEFAULT)); strlen(XATTR_POSIX_ACL_DEFAULT));
if (ret)
return ret;
} }
#endif #endif
@ -205,7 +201,7 @@ xfs_xattr_put_listent(
* see them. * see them.
*/ */
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return 0; return;
prefix = XATTR_TRUSTED_PREFIX; prefix = XATTR_TRUSTED_PREFIX;
prefix_len = XATTR_TRUSTED_PREFIX_LEN; prefix_len = XATTR_TRUSTED_PREFIX_LEN;
@ -217,8 +213,9 @@ xfs_xattr_put_listent(
prefix_len = XATTR_USER_PREFIX_LEN; prefix_len = XATTR_USER_PREFIX_LEN;
} }
return __xfs_xattr_put_listent(context, prefix, prefix_len, name, __xfs_xattr_put_listent(context, prefix, prefix_len, name,
namelen); namelen);
return;
} }
ssize_t ssize_t