Skip to content

Commit

Permalink
Merge branch 'xfs-4.10-misc-fixes-3' into for-next
Browse files Browse the repository at this point in the history
  • Loading branch information
dchinner committed Dec 7, 2016
2 parents 5f1c6d2 + 6031e73 commit a444d72
Show file tree
Hide file tree
Showing 28 changed files with 306 additions and 301 deletions.
10 changes: 7 additions & 3 deletions fs/xfs/libxfs/xfs_alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -2455,12 +2455,15 @@ xfs_agf_verify(
be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp)))
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)
return false;

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;

/*
Expand All @@ -2477,7 +2480,8 @@ xfs_agf_verify(
return false;

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 true;;
Expand Down
4 changes: 4 additions & 0 deletions fs/xfs/libxfs/xfs_alloc_btree.c
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,10 @@ xfs_allocbt_init_cursor(
cur->bc_btnum = btnum;
cur->bc_blocklog = mp->m_sb.sb_blocklog;
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) {
cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]);
Expand Down
2 changes: 1 addition & 1 deletion fs/xfs/libxfs/xfs_attr_leaf.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ int xfs_attr3_leaf_add(struct xfs_buf *leaf_buffer,
struct xfs_da_args *args);
int xfs_attr3_leaf_remove(struct xfs_buf *leaf_buffer,
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);

/*
Expand Down
14 changes: 10 additions & 4 deletions fs/xfs/libxfs/xfs_bmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,7 @@ void
xfs_bmap_trace_exlist(
xfs_inode_t *ip, /* incore inode pointer */
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)
{
xfs_extnum_t idx; /* extent record index */
Expand All @@ -527,11 +527,13 @@ xfs_bmap_trace_exlist(

if (whichfork == XFS_ATTR_FORK)
state |= BMAP_ATTRFORK;
else if (whichfork == XFS_COW_FORK)
state |= BMAP_COWFORK;

ifp = XFS_IFORK_PTR(ip, whichfork);
ASSERT(cnt == xfs_iext_count(ifp));
for (idx = 0; idx < cnt; idx++)
trace_xfs_extlist(ip, idx, whichfork, caller_ip);
trace_xfs_extlist(ip, idx, state, caller_ip);
}

/*
Expand Down Expand Up @@ -1151,14 +1153,17 @@ xfs_bmap_add_attrfork(
goto trans_cancel;
if (XFS_IFORK_Q(ip))
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) {
/*
* For inodes coming from pre-6.2 filesystems.
*/
ASSERT(ip->i_d.di_aformat == 0);
ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS;
}
ASSERT(ip->i_d.di_anextents == 0);

xfs_trans_ijoin(tp, ip, 0);
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
Expand Down Expand Up @@ -1375,8 +1380,9 @@ xfs_bmap_read_extents(
return error;
block = XFS_BUF_TO_BLOCK(bp);
}
if (i != XFS_IFORK_NEXTENTS(ip, whichfork))
return -EFSCORRUPTED;
ASSERT(i == xfs_iext_count(ifp));
ASSERT(i == XFS_IFORK_NEXTENTS(ip, whichfork));
XFS_BMAP_TRACE_EXLIST(ip, i, whichfork);
return 0;
error0:
Expand Down
1 change: 1 addition & 0 deletions fs/xfs/libxfs/xfs_bmap_btree.c
Original file line number Diff line number Diff line change
Expand Up @@ -803,6 +803,7 @@ xfs_bmbt_init_cursor(
cur->bc_nlevels = be16_to_cpu(ifp->if_broot->bb_level) + 1;
cur->bc_btnum = XFS_BTNUM_BMAP;
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_flags = XFS_BTREE_LONG_PTRS | XFS_BTREE_ROOT_IN_INODE;
Expand Down
20 changes: 20 additions & 0 deletions fs/xfs/libxfs/xfs_btree.c
Original file line number Diff line number Diff line change
Expand Up @@ -1769,8 +1769,28 @@ xfs_btree_lookup_get_block(
if (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);
return 0;

out_bad:
*blkp = NULL;
xfs_trans_brelse(cur->bc_tp, bp);
return -EFSCORRUPTED;
}

/*
Expand Down
43 changes: 4 additions & 39 deletions fs/xfs/libxfs/xfs_btree.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,46 +96,10 @@ union xfs_btree_rec {
/*
* 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) \
do { \
struct xfs_mount *__mp = cur->bc_mp; \
switch (cur->bc_btnum) { \
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)
XFS_STATS_INC_OFF((cur)->bc_mp, (cur)->bc_statoff + __XBTS_ ## stat)
#define XFS_BTREE_STATS_ADD(cur, stat, val) \
XFS_STATS_ADD_OFF((cur)->bc_mp, (cur)->bc_statoff + __XBTS_ ## stat, val)

#define XFS_BTREE_MAXLEVELS 9 /* max of all btrees */

Expand Down Expand Up @@ -253,6 +217,7 @@ typedef struct xfs_btree_cur
__uint8_t bc_nlevels; /* number of levels in the tree */
__uint8_t bc_blocklog; /* log2(blocksize) of btree blocks */
xfs_btnum_t bc_btnum; /* identifies which btree type */
int bc_statoff; /* offset of btre stats array */
union {
struct { /* needed for BNO, CNT, INO */
struct xfs_buf *agbp; /* agf/agi buffer pointer */
Expand Down
26 changes: 22 additions & 4 deletions fs/xfs/libxfs/xfs_cksum.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
/*
* 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
* 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
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 crc;
Expand All @@ -25,6 +26,20 @@ xfs_start_cksum(char *buffer, size_t length, unsigned long cksum_offset)
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.
*
Expand All @@ -40,11 +55,14 @@ xfs_end_cksum(__uint32_t crc)

/*
* 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
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);
}
Expand All @@ -55,7 +73,7 @@ xfs_update_cksum(char *buffer, size_t length, unsigned long cksum_offset)
static inline int
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);
}
Expand Down
2 changes: 1 addition & 1 deletion fs/xfs/libxfs/xfs_dir2_data.c
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ xfs_dir3_data_read(

err = xfs_da_read_buf(tp, dp, bno, mapped_bno, bpp,
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);
return err;
}
Expand Down
13 changes: 10 additions & 3 deletions fs/xfs/libxfs/xfs_ialloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -2451,8 +2451,6 @@ xfs_ialloc_log_agi(
ASSERT(agi->agi_magicnum == cpu_to_be32(XFS_AGI_MAGIC));
#endif

xfs_trans_buf_set_type(tp, bp, XFS_BLFT_AGI_BUF);

/*
* Compute byte offsets for the first and last fields in the first
* region and log the agi buffer. This only logs up through
Expand Down Expand Up @@ -2513,8 +2511,15 @@ xfs_agi_verify(
if (!XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum)))
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;

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,
* so we can't use it for any useful checking. growfs ensures we can't
Expand Down Expand Up @@ -2593,6 +2598,8 @@ xfs_read_agi(
XFS_FSS_TO_BB(mp, 1), 0, bpp, &xfs_agi_buf_ops);
if (error)
return error;
if (tp)
xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_AGI_BUF);

xfs_buf_set_ref(*bpp, XFS_AGI_REF);
return 0;
Expand Down
2 changes: 2 additions & 0 deletions fs/xfs/libxfs/xfs_ialloc_btree.c
Original file line number Diff line number Diff line change
Expand Up @@ -365,9 +365,11 @@ xfs_inobt_init_cursor(
if (btnum == XFS_BTNUM_INO) {
cur->bc_nlevels = be32_to_cpu(agi->agi_level);
cur->bc_ops = &xfs_inobt_ops;
cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_ibt_2);
} else {
cur->bc_nlevels = be32_to_cpu(agi->agi_free_level);
cur->bc_ops = &xfs_finobt_ops;
cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_fibt_2);
}

cur->bc_blocklog = mp->m_sb.sb_blocklog;
Expand Down
10 changes: 9 additions & 1 deletion fs/xfs/libxfs/xfs_inode_buf.c
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,14 @@ xfs_dinode_verify(
if (dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC))
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 */
if (dip->di_version < 3)
return true;
Expand Down Expand Up @@ -436,7 +444,7 @@ xfs_dinode_calc_crc(
return;

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);
dip->di_crc = xfs_end_cksum(crc);
}
Expand Down
1 change: 1 addition & 0 deletions fs/xfs/libxfs/xfs_refcount_btree.c
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ xfs_refcountbt_init_cursor(
cur->bc_btnum = XFS_BTNUM_REFC;
cur->bc_blocklog = mp->m_sb.sb_blocklog;
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);

Expand Down
1 change: 1 addition & 0 deletions fs/xfs/libxfs/xfs_rmap_btree.c
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,7 @@ xfs_rmapbt_init_cursor(
cur->bc_blocklog = mp->m_sb.sb_blocklog;
cur->bc_ops = &xfs_rmapbt_ops;
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.agno = agno;
Expand Down
4 changes: 2 additions & 2 deletions fs/xfs/xfs_attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@ typedef struct attrlist_cursor_kern {
*========================================================================*/


/* Return 0 on success, or -errno; other state communicated via *context */
typedef int (*put_listent_func_t)(struct xfs_attr_list_context *, int,
/* void; state communicated via *context */
typedef void (*put_listent_func_t)(struct xfs_attr_list_context *, int,
unsigned char *, int, int);

typedef struct xfs_attr_list_context {
Expand Down
Loading

0 comments on commit a444d72

Please sign in to comment.