Changes since last update:
- Fix a stale kernel memory exposure when logging inodes. - Fix some build problems with CONFIG_XFS_RT=n - Don't change inode mode if the acl write fails, leaving the file totally inaccessible. - Fix a dangling pointer problem when removing an attr fork under memory pressure. - Don't crash while trying to invalidate a null buffer associated with a corrupt metadata pointer. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCgAGBQJZ3lPiAAoJEPh/dxk0SrTrfuMP/Axy7VSX71tE/eXPOmzxCVZD w4/usqO+OsQj+q8o+rwwuX9hz0VGF8kWZJOdgGdXpYT7pWqPmcf88wbThheTetLF fjevusqva0Ds+U4AE7DCNWSKQQRhu2jDgnhQXTv1hdYhWIF59qGwioIijbEvb72I 0QW+/uV9yXmODjWL6KfRh9zRT9N4npMtszukScONwJr9t0/5ub8H03H/ktv8T9oi C3ljEWwyMk5lEYH8p6tpta8EbY0mrIZgo+kj33PU5s9rHvcrTGtyPNqidREUm1fL X3+STMytcDQFAcZdBBXHN0nFMwa8ADTrVvKmEgaR8OsXmOmrlcPn7HfVVlWrY31w X3awJ0b0+IXUrsbbQOPeqgTo5hIkMDkMOga5AP/rqpx1yCCOrlMHaRPXB2NxNcVw dyTj6IpKybhsQ4GkcqmFcgnxPPaogNpYlp6SXV5Dm+8zEJdIQNUuci/EGsNz7UcV msxNlJJkxczXOew6JzCyw45wTnJCxduX7Y1xrOTLaDfa9pkWO2zQBXukCJNIqVIq 35Q4P4JVYtmwQr8XkkX9tiqU0gBWTCTG9KjmTCMm5MYkutEYM0uTNR5Jvyiobl7L Nn+RydssVw7ssnNfgsLhzQHPElUivRdYoYFSBa2DQp6ViILrefqQegd5INAjK63W 7vnHVZyJMHPM0YFoiX8w =6Yvh -----END PGP SIGNATURE----- Merge tag 'xfs-4.14-fixes-5' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux Pull xfs fixes from Darrick Wong: - Fix a stale kernel memory exposure when logging inodes. - Fix some build problems with CONFIG_XFS_RT=n - Don't change inode mode if the acl write fails, leaving the file totally inaccessible. - Fix a dangling pointer problem when removing an attr fork under memory pressure. - Don't crash while trying to invalidate a null buffer associated with a corrupt metadata pointer. * tag 'xfs-4.14-fixes-5' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux: xfs: handle error if xfs_btree_get_bufs fails xfs: reinit btree pointer on attr tree inactivation walk xfs: Fix bool initialization/comparison xfs: don't change inode mode if ACL update fails xfs: move more RT specific code under CONFIG_XFS_RT xfs: Don't log uninitialised fields in inode structures
This commit is contained in:
commit
8ff0b97cf2
@ -1584,6 +1584,10 @@ xfs_alloc_ag_vextent_small(
|
||||
|
||||
bp = xfs_btree_get_bufs(args->mp, args->tp,
|
||||
args->agno, fbno, 0);
|
||||
if (!bp) {
|
||||
error = -EFSCORRUPTED;
|
||||
goto error0;
|
||||
}
|
||||
xfs_trans_binval(args->tp, bp);
|
||||
}
|
||||
args->len = 1;
|
||||
@ -2141,6 +2145,10 @@ xfs_alloc_fix_freelist(
|
||||
if (error)
|
||||
goto out_agbp_relse;
|
||||
bp = xfs_btree_get_bufs(mp, tp, args->agno, bno, 0);
|
||||
if (!bp) {
|
||||
error = -EFSCORRUPTED;
|
||||
goto out_agbp_relse;
|
||||
}
|
||||
xfs_trans_binval(tp, bp);
|
||||
}
|
||||
|
||||
|
@ -1477,14 +1477,14 @@ xfs_bmap_isaeof(
|
||||
int is_empty;
|
||||
int error;
|
||||
|
||||
bma->aeof = 0;
|
||||
bma->aeof = false;
|
||||
error = xfs_bmap_last_extent(NULL, bma->ip, whichfork, &rec,
|
||||
&is_empty);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (is_empty) {
|
||||
bma->aeof = 1;
|
||||
bma->aeof = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1962,7 +1962,7 @@ xfs_difree_inobt(
|
||||
if (!(mp->m_flags & XFS_MOUNT_IKEEP) &&
|
||||
rec.ir_free == XFS_INOBT_ALL_FREE &&
|
||||
mp->m_sb.sb_inopblock <= XFS_INODES_PER_CHUNK) {
|
||||
xic->deleted = 1;
|
||||
xic->deleted = true;
|
||||
xic->first_ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino);
|
||||
xic->alloc = xfs_inobt_irec_to_allocmask(&rec);
|
||||
|
||||
@ -1989,7 +1989,7 @@ xfs_difree_inobt(
|
||||
|
||||
xfs_difree_inode_chunk(mp, agno, &rec, dfops);
|
||||
} else {
|
||||
xic->deleted = 0;
|
||||
xic->deleted = false;
|
||||
|
||||
error = xfs_inobt_update(cur, &rec);
|
||||
if (error) {
|
||||
|
@ -270,6 +270,7 @@ typedef struct xfs_inode_log_format {
|
||||
uint32_t ilf_fields; /* flags for fields logged */
|
||||
uint16_t ilf_asize; /* size of attr d/ext/root */
|
||||
uint16_t ilf_dsize; /* size of data/ext/root */
|
||||
uint32_t ilf_pad; /* pad for 64 bit boundary */
|
||||
uint64_t ilf_ino; /* inode number */
|
||||
union {
|
||||
uint32_t ilfu_rdev; /* rdev value for dev inode*/
|
||||
@ -280,7 +281,12 @@ typedef struct xfs_inode_log_format {
|
||||
int32_t ilf_boffset; /* off of inode in buffer */
|
||||
} xfs_inode_log_format_t;
|
||||
|
||||
typedef struct xfs_inode_log_format_32 {
|
||||
/*
|
||||
* Old 32 bit systems will log in this format without the 64 bit
|
||||
* alignment padding. Recovery will detect this and convert it to the
|
||||
* correct format.
|
||||
*/
|
||||
struct xfs_inode_log_format_32 {
|
||||
uint16_t ilf_type; /* inode log item type */
|
||||
uint16_t ilf_size; /* size of this item */
|
||||
uint32_t ilf_fields; /* flags for fields logged */
|
||||
@ -294,24 +300,7 @@ typedef struct xfs_inode_log_format_32 {
|
||||
int64_t ilf_blkno; /* blkno of inode buffer */
|
||||
int32_t ilf_len; /* len of inode buffer */
|
||||
int32_t ilf_boffset; /* off of inode in buffer */
|
||||
} __attribute__((packed)) xfs_inode_log_format_32_t;
|
||||
|
||||
typedef struct xfs_inode_log_format_64 {
|
||||
uint16_t ilf_type; /* inode log item type */
|
||||
uint16_t ilf_size; /* size of this item */
|
||||
uint32_t ilf_fields; /* flags for fields logged */
|
||||
uint16_t ilf_asize; /* size of attr d/ext/root */
|
||||
uint16_t ilf_dsize; /* size of data/ext/root */
|
||||
uint32_t ilf_pad; /* pad for 64 bit boundary */
|
||||
uint64_t ilf_ino; /* inode number */
|
||||
union {
|
||||
uint32_t ilfu_rdev; /* rdev value for dev inode*/
|
||||
uuid_t ilfu_uuid; /* mount point value */
|
||||
} ilf_u;
|
||||
int64_t ilf_blkno; /* blkno of inode buffer */
|
||||
int32_t ilf_len; /* len of inode buffer */
|
||||
int32_t ilf_boffset; /* off of inode in buffer */
|
||||
} xfs_inode_log_format_64_t;
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
/*
|
||||
|
@ -247,6 +247,8 @@ xfs_set_mode(struct inode *inode, umode_t mode)
|
||||
int
|
||||
xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
|
||||
{
|
||||
umode_t mode;
|
||||
bool set_mode = false;
|
||||
int error = 0;
|
||||
|
||||
if (!acl)
|
||||
@ -257,16 +259,24 @@ xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
|
||||
return error;
|
||||
|
||||
if (type == ACL_TYPE_ACCESS) {
|
||||
umode_t mode;
|
||||
|
||||
error = posix_acl_update_mode(inode, &mode, &acl);
|
||||
if (error)
|
||||
return error;
|
||||
error = xfs_set_mode(inode, mode);
|
||||
if (error)
|
||||
return error;
|
||||
set_mode = true;
|
||||
}
|
||||
|
||||
set_acl:
|
||||
return __xfs_set_acl(inode, acl, type);
|
||||
error = __xfs_set_acl(inode, acl, type);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/*
|
||||
* We set the mode after successfully updating the ACL xattr because the
|
||||
* xattr update can fail at ENOSPC and we don't want to change the mode
|
||||
* if the ACL update hasn't been applied.
|
||||
*/
|
||||
if (set_mode)
|
||||
error = xfs_set_mode(inode, mode);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
@ -302,6 +302,8 @@ xfs_attr3_node_inactive(
|
||||
&bp, XFS_ATTR_FORK);
|
||||
if (error)
|
||||
return error;
|
||||
node = bp->b_addr;
|
||||
btree = dp->d_ops->node_tree_p(node);
|
||||
child_fsb = be32_to_cpu(btree[i + 1].before);
|
||||
xfs_trans_brelse(*trans, bp);
|
||||
}
|
||||
|
@ -84,6 +84,7 @@ xfs_zero_extent(
|
||||
GFP_NOFS, 0);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_XFS_RT
|
||||
int
|
||||
xfs_bmap_rtalloc(
|
||||
struct xfs_bmalloca *ap) /* bmap alloc argument struct */
|
||||
@ -190,6 +191,7 @@ xfs_bmap_rtalloc(
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_XFS_RT */
|
||||
|
||||
/*
|
||||
* Check if the endoff is outside the last extent. If so the caller will grow
|
||||
|
@ -28,7 +28,20 @@ struct xfs_mount;
|
||||
struct xfs_trans;
|
||||
struct xfs_bmalloca;
|
||||
|
||||
#ifdef CONFIG_XFS_RT
|
||||
int xfs_bmap_rtalloc(struct xfs_bmalloca *ap);
|
||||
#else /* !CONFIG_XFS_RT */
|
||||
/*
|
||||
* Attempts to allocate RT extents when RT is disable indicates corruption and
|
||||
* should trigger a shutdown.
|
||||
*/
|
||||
static inline int
|
||||
xfs_bmap_rtalloc(struct xfs_bmalloca *ap)
|
||||
{
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
#endif /* CONFIG_XFS_RT */
|
||||
|
||||
int xfs_bmap_eof(struct xfs_inode *ip, xfs_fileoff_t endoff,
|
||||
int whichfork, int *eof);
|
||||
int xfs_bmap_punch_delalloc_range(struct xfs_inode *ip,
|
||||
|
@ -764,7 +764,7 @@ xfs_file_fallocate(
|
||||
enum xfs_prealloc_flags flags = 0;
|
||||
uint iolock = XFS_IOLOCK_EXCL;
|
||||
loff_t new_size = 0;
|
||||
bool do_file_insert = 0;
|
||||
bool do_file_insert = false;
|
||||
|
||||
if (!S_ISREG(inode->i_mode))
|
||||
return -EINVAL;
|
||||
@ -825,7 +825,7 @@ xfs_file_fallocate(
|
||||
error = -EINVAL;
|
||||
goto out_unlock;
|
||||
}
|
||||
do_file_insert = 1;
|
||||
do_file_insert = true;
|
||||
} else {
|
||||
flags |= XFS_PREALLOC_SET;
|
||||
|
||||
|
@ -521,6 +521,7 @@ __xfs_getfsmap_rtdev(
|
||||
return query_fn(tp, info);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_XFS_RT
|
||||
/* Actually query the realtime bitmap. */
|
||||
STATIC int
|
||||
xfs_getfsmap_rtdev_rtbitmap_query(
|
||||
@ -561,6 +562,7 @@ xfs_getfsmap_rtdev_rtbitmap(
|
||||
return __xfs_getfsmap_rtdev(tp, keys, xfs_getfsmap_rtdev_rtbitmap_query,
|
||||
info);
|
||||
}
|
||||
#endif /* CONFIG_XFS_RT */
|
||||
|
||||
/* Execute a getfsmap query against the regular data device. */
|
||||
STATIC int
|
||||
@ -795,7 +797,15 @@ xfs_getfsmap_check_keys(
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* There are only two devices if we didn't configure RT devices at build time.
|
||||
*/
|
||||
#ifdef CONFIG_XFS_RT
|
||||
#define XFS_GETFSMAP_DEVS 3
|
||||
#else
|
||||
#define XFS_GETFSMAP_DEVS 2
|
||||
#endif /* CONFIG_XFS_RT */
|
||||
|
||||
/*
|
||||
* Get filesystem's extents as described in head, and format for
|
||||
* output. Calls formatter to fill the user's buffer until all
|
||||
@ -853,10 +863,12 @@ xfs_getfsmap(
|
||||
handlers[1].dev = new_encode_dev(mp->m_logdev_targp->bt_dev);
|
||||
handlers[1].fn = xfs_getfsmap_logdev;
|
||||
}
|
||||
#ifdef CONFIG_XFS_RT
|
||||
if (mp->m_rtdev_targp) {
|
||||
handlers[2].dev = new_encode_dev(mp->m_rtdev_targp->bt_dev);
|
||||
handlers[2].fn = xfs_getfsmap_rtdev_rtbitmap;
|
||||
}
|
||||
#endif /* CONFIG_XFS_RT */
|
||||
|
||||
xfs_sort(handlers, XFS_GETFSMAP_DEVS, sizeof(struct xfs_getfsmap_dev),
|
||||
xfs_getfsmap_dev_compare);
|
||||
|
@ -364,6 +364,9 @@ xfs_inode_to_log_dinode(
|
||||
to->di_dmstate = from->di_dmstate;
|
||||
to->di_flags = from->di_flags;
|
||||
|
||||
/* log a dummy value to ensure log structure is fully initialised */
|
||||
to->di_next_unlinked = NULLAGINO;
|
||||
|
||||
if (from->di_version == 3) {
|
||||
to->di_changecount = inode->i_version;
|
||||
to->di_crtime.t_sec = from->di_crtime.t_sec;
|
||||
@ -404,6 +407,11 @@ xfs_inode_item_format_core(
|
||||
* the second with the on-disk inode structure, and a possible third and/or
|
||||
* fourth with the inode data/extents/b-tree root and inode attributes
|
||||
* data/extents/b-tree root.
|
||||
*
|
||||
* Note: Always use the 64 bit inode log format structure so we don't
|
||||
* leave an uninitialised hole in the format item on 64 bit systems. Log
|
||||
* recovery on 32 bit systems handles this just fine, so there's no reason
|
||||
* for not using an initialising the properly padded structure all the time.
|
||||
*/
|
||||
STATIC void
|
||||
xfs_inode_item_format(
|
||||
@ -412,8 +420,8 @@ xfs_inode_item_format(
|
||||
{
|
||||
struct xfs_inode_log_item *iip = INODE_ITEM(lip);
|
||||
struct xfs_inode *ip = iip->ili_inode;
|
||||
struct xfs_inode_log_format *ilf;
|
||||
struct xfs_log_iovec *vecp = NULL;
|
||||
struct xfs_inode_log_format *ilf;
|
||||
|
||||
ASSERT(ip->i_d.di_version > 1);
|
||||
|
||||
@ -425,7 +433,17 @@ xfs_inode_item_format(
|
||||
ilf->ilf_boffset = ip->i_imap.im_boffset;
|
||||
ilf->ilf_fields = XFS_ILOG_CORE;
|
||||
ilf->ilf_size = 2; /* format + core */
|
||||
xlog_finish_iovec(lv, vecp, sizeof(struct xfs_inode_log_format));
|
||||
|
||||
/*
|
||||
* make sure we don't leak uninitialised data into the log in the case
|
||||
* when we don't log every field in the inode.
|
||||
*/
|
||||
ilf->ilf_dsize = 0;
|
||||
ilf->ilf_asize = 0;
|
||||
ilf->ilf_pad = 0;
|
||||
uuid_copy(&ilf->ilf_u.ilfu_uuid, &uuid_null);
|
||||
|
||||
xlog_finish_iovec(lv, vecp, sizeof(*ilf));
|
||||
|
||||
xfs_inode_item_format_core(ip, lv, &vecp);
|
||||
xfs_inode_item_format_data_fork(iip, ilf, lv, &vecp);
|
||||
@ -855,44 +873,29 @@ xfs_istale_done(
|
||||
}
|
||||
|
||||
/*
|
||||
* convert an xfs_inode_log_format struct from either 32 or 64 bit versions
|
||||
* (which can have different field alignments) to the native version
|
||||
* convert an xfs_inode_log_format struct from the old 32 bit version
|
||||
* (which can have different field alignments) to the native 64 bit version
|
||||
*/
|
||||
int
|
||||
xfs_inode_item_format_convert(
|
||||
xfs_log_iovec_t *buf,
|
||||
xfs_inode_log_format_t *in_f)
|
||||
struct xfs_log_iovec *buf,
|
||||
struct xfs_inode_log_format *in_f)
|
||||
{
|
||||
if (buf->i_len == sizeof(xfs_inode_log_format_32_t)) {
|
||||
xfs_inode_log_format_32_t *in_f32 = buf->i_addr;
|
||||
struct xfs_inode_log_format_32 *in_f32 = buf->i_addr;
|
||||
|
||||
in_f->ilf_type = in_f32->ilf_type;
|
||||
in_f->ilf_size = in_f32->ilf_size;
|
||||
in_f->ilf_fields = in_f32->ilf_fields;
|
||||
in_f->ilf_asize = in_f32->ilf_asize;
|
||||
in_f->ilf_dsize = in_f32->ilf_dsize;
|
||||
in_f->ilf_ino = in_f32->ilf_ino;
|
||||
/* copy biggest field of ilf_u */
|
||||
uuid_copy(&in_f->ilf_u.ilfu_uuid, &in_f32->ilf_u.ilfu_uuid);
|
||||
in_f->ilf_blkno = in_f32->ilf_blkno;
|
||||
in_f->ilf_len = in_f32->ilf_len;
|
||||
in_f->ilf_boffset = in_f32->ilf_boffset;
|
||||
return 0;
|
||||
} else if (buf->i_len == sizeof(xfs_inode_log_format_64_t)){
|
||||
xfs_inode_log_format_64_t *in_f64 = buf->i_addr;
|
||||
if (buf->i_len != sizeof(*in_f32))
|
||||
return -EFSCORRUPTED;
|
||||
|
||||
in_f->ilf_type = in_f64->ilf_type;
|
||||
in_f->ilf_size = in_f64->ilf_size;
|
||||
in_f->ilf_fields = in_f64->ilf_fields;
|
||||
in_f->ilf_asize = in_f64->ilf_asize;
|
||||
in_f->ilf_dsize = in_f64->ilf_dsize;
|
||||
in_f->ilf_ino = in_f64->ilf_ino;
|
||||
/* copy biggest field of ilf_u */
|
||||
uuid_copy(&in_f->ilf_u.ilfu_uuid, &in_f64->ilf_u.ilfu_uuid);
|
||||
in_f->ilf_blkno = in_f64->ilf_blkno;
|
||||
in_f->ilf_len = in_f64->ilf_len;
|
||||
in_f->ilf_boffset = in_f64->ilf_boffset;
|
||||
return 0;
|
||||
}
|
||||
return -EFSCORRUPTED;
|
||||
in_f->ilf_type = in_f32->ilf_type;
|
||||
in_f->ilf_size = in_f32->ilf_size;
|
||||
in_f->ilf_fields = in_f32->ilf_fields;
|
||||
in_f->ilf_asize = in_f32->ilf_asize;
|
||||
in_f->ilf_dsize = in_f32->ilf_dsize;
|
||||
in_f->ilf_ino = in_f32->ilf_ino;
|
||||
/* copy biggest field of ilf_u */
|
||||
uuid_copy(&in_f->ilf_u.ilfu_uuid, &in_f32->ilf_u.ilfu_uuid);
|
||||
in_f->ilf_blkno = in_f32->ilf_blkno;
|
||||
in_f->ilf_len = in_f32->ilf_len;
|
||||
in_f->ilf_boffset = in_f32->ilf_boffset;
|
||||
return 0;
|
||||
}
|
||||
|
@ -2515,7 +2515,7 @@ next_lv:
|
||||
if (lv)
|
||||
vecp = lv->lv_iovecp;
|
||||
}
|
||||
if (record_cnt == 0 && ordered == false) {
|
||||
if (record_cnt == 0 && !ordered) {
|
||||
if (!lv)
|
||||
return 0;
|
||||
break;
|
||||
|
@ -704,7 +704,7 @@ xfs_mountfs(
|
||||
xfs_set_maxicount(mp);
|
||||
|
||||
/* enable fail_at_unmount as default */
|
||||
mp->m_fail_unmount = 1;
|
||||
mp->m_fail_unmount = true;
|
||||
|
||||
error = xfs_sysfs_init(&mp->m_kobj, &xfs_mp_ktype, NULL, mp->m_fsname);
|
||||
if (error)
|
||||
|
@ -134,7 +134,7 @@ xfs_check_ondisk_structs(void)
|
||||
XFS_CHECK_STRUCT_SIZE(struct xfs_icreate_log, 28);
|
||||
XFS_CHECK_STRUCT_SIZE(struct xfs_ictimestamp, 8);
|
||||
XFS_CHECK_STRUCT_SIZE(struct xfs_inode_log_format_32, 52);
|
||||
XFS_CHECK_STRUCT_SIZE(struct xfs_inode_log_format_64, 56);
|
||||
XFS_CHECK_STRUCT_SIZE(struct xfs_inode_log_format, 56);
|
||||
XFS_CHECK_STRUCT_SIZE(struct xfs_qoff_logformat, 20);
|
||||
XFS_CHECK_STRUCT_SIZE(struct xfs_trans_header, 16);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user