Message ID | 157859551417.164065.16772455171549647070.stgit@magnolia (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | xfs: fix buf log item memory corruption on non-amd64 | expand |
On Thu, Jan 09, 2020 at 10:45:14AM -0800, Darrick J. Wong wrote: > From: Darrick J. Wong <darrick.wong@oracle.com> > > Increase XFS_BLF_DATAMAP_SIZE by 1 to fill in the implied padding at the > end of struct xfs_buf_log_format. This makes the size consistent so > that we can check it in xfs_ondisk.h, and will be needed once we start > logging attribute values. Isn't this an incompatible change in the on-disk format for 32-bit systems?
On Fri, Jan 10, 2020 at 03:59:38AM -0800, Christoph Hellwig wrote: > On Thu, Jan 09, 2020 at 10:45:14AM -0800, Darrick J. Wong wrote: > > From: Darrick J. Wong <darrick.wong@oracle.com> > > > > Increase XFS_BLF_DATAMAP_SIZE by 1 to fill in the implied padding at the > > end of struct xfs_buf_log_format. This makes the size consistent so > > that we can check it in xfs_ondisk.h, and will be needed once we start > > logging attribute values. > > Isn't this an incompatible change in the on-disk format for 32-bit > systems? AFAICT it isn't, because log recovery reads the on-disk log op head to figure out the length of the log iovec, allocates that much memory for the log buf, reads in the contents, and then casts i_addr to xfs_buf_log_format. On the log writing side, the logging code takes the buffer item and writes out whatever's in the incore structure, assuming that the incore structure is actually large enough to cover data_map[map_size - 1]. (Someone else might want to check that to make sure I haven't gone mad from looking at the log code... :P) --D
diff --git a/fs/xfs/libxfs/xfs_log_format.h b/fs/xfs/libxfs/xfs_log_format.h index 8ef31d71a9c7..9bac0d2e56dc 100644 --- a/fs/xfs/libxfs/xfs_log_format.h +++ b/fs/xfs/libxfs/xfs_log_format.h @@ -462,11 +462,20 @@ static inline uint xfs_log_dinode_size(int version) #define XFS_BLF_GDQUOT_BUF (1<<4) /* - * This is the structure used to lay out a buf log item in the - * log. The data map describes which 128 byte chunks of the buffer - * have been logged. - */ -#define XFS_BLF_DATAMAP_SIZE ((XFS_MAX_BLOCKSIZE / XFS_BLF_CHUNK) / NBWORD) + * This is the structure used to lay out a buf log item in the log. The data + * map describes which 128 byte chunks of the buffer have been logged. + * + * The placement of blf_map_size causes blf_data_map to start at an odd + * multiple of sizeof(unsigned int) offset within the struct. Because the data + * bitmap size will always be an even number, the end of the data_map (and + * therefore the structure) will also be at an odd multiple of sizeof(unsigned + * int). Some 64-bit compilers will insert padding at the end of the struct to + * ensure 64-bit alignment of blf_blkno, but 32-bit ones will not. Therefore, + * XFS_BLF_DATAMAP_SIZE must be an odd number to make the padding explicit and + * keep the structure size consistent between 32-bit and 64-bit platforms. + */ +#define __XFS_BLF_DATAMAP_SIZE ((XFS_MAX_BLOCKSIZE / XFS_BLF_CHUNK) / NBWORD) +#define XFS_BLF_DATAMAP_SIZE (__XFS_BLF_DATAMAP_SIZE + 1) typedef struct xfs_buf_log_format { unsigned short blf_type; /* buf log item type indicator */ diff --git a/fs/xfs/xfs_ondisk.h b/fs/xfs/xfs_ondisk.h index b6701b4f59a9..5f04d8a5ab2a 100644 --- a/fs/xfs/xfs_ondisk.h +++ b/fs/xfs/xfs_ondisk.h @@ -111,6 +111,7 @@ xfs_check_ondisk_structs(void) XFS_CHECK_STRUCT_SIZE(xfs_dir2_sf_hdr_t, 10); /* log structures */ + XFS_CHECK_STRUCT_SIZE(struct xfs_buf_log_format, 88); XFS_CHECK_STRUCT_SIZE(struct xfs_dq_logformat, 24); XFS_CHECK_STRUCT_SIZE(struct xfs_efd_log_format_32, 28); XFS_CHECK_STRUCT_SIZE(struct xfs_efd_log_format_64, 32);