diff mbox series

[RFC,3/5] xfs: [variant C] avoid i386-misaligned xfs_bstat

Message ID 20191112120910.1977003-4-arnd@arndb.de (mailing list archive)
State New, archived
Headers show
Series xfs: y2038 conversion | expand

Commit Message

Arnd Bergmann Nov. 12, 2019, 12:09 p.m. UTC
The change to the ioctl commands requires updating the header file. If
we do that, the alignment problem on i386 could be solved for the new
format by explictly aligning all 64-bit members to time_t. This complicates
the header file definition, but saves the code to deal with a third format.

The native ioctl simply deals with both the time32 and the time64 version,
and the latter is the same across all 64-bit architectures and all 32-bit
user space with 32-bit time_t including i386 and x32.

If we decide to do this, this change should be folded into "xfs: [variant B]
add time64 version of xfs_bstat".

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 fs/xfs/libxfs/xfs_fs.h |  20 +++++--
 fs/xfs/xfs_ioctl32.c   | 120 +----------------------------------------
 2 files changed, 18 insertions(+), 122 deletions(-)
diff mbox series

Patch

diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
index 9310576a45e5..e95807d223ad 100644
--- a/fs/xfs/libxfs/xfs_fs.h
+++ b/fs/xfs/libxfs/xfs_fs.h
@@ -319,6 +319,17 @@  typedef struct xfs_growfs_rt {
 	__u32		extsize;	/* new realtime extent size, fsblocks */
 } xfs_growfs_rt_t;
 
+/*
+ * on i386, u64 has 32-bit alignment, which makes the traditional xfs_bstat
+ * different from other architectures. Aligning all 64-bit members to
+ * sizeof(time_t) means that the new version with 64-bit time_t is padded
+ * the same as on all other architectures.
+ */
+#ifdef __i386__
+#define __TIME_ALIGN __attribute__((aligned(sizeof(time_t))))
+#else
+#define __TIME_ALIGN
+#endif
 
 /*
  * Structures returned from ioctl XFS_IOC_FSBULKSTAT & XFS_IOC_FSBULKSTAT_SINGLE
@@ -328,24 +339,24 @@  typedef struct xfs_bstime {
 	__s64		tv_sec;		/* seconds		*/
 	__s32		tv_nsec;	/* and nanoseconds	*/
 #else
-	time_t		tv_sec;		/* seconds		*/
+	time_t		tv_sec __TIME_ALIGN; /* seconds		*/
 	__s32		tv_nsec;	/* and nanoseconds	*/
 #endif
 } xfs_bstime_t;
 
 struct xfs_bstat {
-	__u64		bs_ino;		/* inode number			*/
+	__u64		bs_ino __TIME_ALIGN; /* inode number		*/
 	__u16		bs_mode;	/* type and mode		*/
 	__u16		bs_nlink;	/* number of links		*/
 	__u32		bs_uid;		/* user id			*/
 	__u32		bs_gid;		/* group id			*/
 	__u32		bs_rdev;	/* device value			*/
 	__s32		bs_blksize;	/* block size			*/
-	__s64		bs_size;	/* file size			*/
+	__s64		bs_size __TIME_ALIGN;	/* file size		*/
 	xfs_bstime_t	bs_atime;	/* access time			*/
 	xfs_bstime_t	bs_mtime;	/* modify time			*/
 	xfs_bstime_t	bs_ctime;	/* inode change time		*/
-	int64_t		bs_blocks;	/* number of blocks		*/
+	int64_t		bs_blocks __TIME_ALIGN;	/* number of blocks	*/
 	__u32		bs_xflags;	/* extended flags		*/
 	__s32		bs_extsize;	/* extent size			*/
 	__s32		bs_extents;	/* number of extents		*/
@@ -362,6 +373,7 @@  struct xfs_bstat {
 	__u16		bs_dmstate;	/* DMIG state info		*/
 	__u16		bs_aextents;	/* attribute number of extents	*/
 };
+#undef __TIME_ALIGN
 
 /* New bulkstat structure that reports v5 features and fixes padding issues */
 struct xfs_bulkstat {
diff --git a/fs/xfs/xfs_ioctl32.c b/fs/xfs/xfs_ioctl32.c
index 2ea7d3e12b4b..8059cdc2d5ca 100644
--- a/fs/xfs/xfs_ioctl32.c
+++ b/fs/xfs/xfs_ioctl32.c
@@ -98,101 +98,6 @@  xfs_fsinumbers_fmt_compat(
 	return xfs_ibulk_advance(breq, sizeof(struct compat_xfs_inogrp));
 }
 
-/* struct xfs_bstat has differing alignment on intel */
-STATIC int
-xfs_ioctl32_bstime_copyin(
-	xfs_bstime_t		*bstime,
-	compat_xfs_bstime_t	__user *bstime32)
-{
-	if (get_user(bstime->tv_sec,	&bstime32->tv_sec)	||
-	    get_user(bstime->tv_nsec,	&bstime32->tv_nsec))
-		return -EFAULT;
-	return 0;
-}
-
-STATIC int
-xfs_ioctl32_bstat_copyin(
-	struct xfs_bstat		*bstat,
-	struct compat_xfs_bstat	__user	*bstat32)
-{
-	if (get_user(bstat->bs_ino,	&bstat32->bs_ino)	||
-	    get_user(bstat->bs_mode,	&bstat32->bs_mode)	||
-	    get_user(bstat->bs_nlink,	&bstat32->bs_nlink)	||
-	    get_user(bstat->bs_uid,	&bstat32->bs_uid)	||
-	    get_user(bstat->bs_gid,	&bstat32->bs_gid)	||
-	    get_user(bstat->bs_rdev,	&bstat32->bs_rdev)	||
-	    get_user(bstat->bs_blksize,	&bstat32->bs_blksize)	||
-	    get_user(bstat->bs_size,	&bstat32->bs_size)	||
-	    xfs_ioctl32_bstime_copyin(&bstat->bs_atime, &bstat32->bs_atime) ||
-	    xfs_ioctl32_bstime_copyin(&bstat->bs_mtime, &bstat32->bs_mtime) ||
-	    xfs_ioctl32_bstime_copyin(&bstat->bs_ctime, &bstat32->bs_ctime) ||
-	    get_user(bstat->bs_blocks,	&bstat32->bs_size)	||
-	    get_user(bstat->bs_xflags,	&bstat32->bs_size)	||
-	    get_user(bstat->bs_extsize,	&bstat32->bs_extsize)	||
-	    get_user(bstat->bs_extents,	&bstat32->bs_extents)	||
-	    get_user(bstat->bs_gen,	&bstat32->bs_gen)	||
-	    get_user(bstat->bs_projid_lo, &bstat32->bs_projid_lo) ||
-	    get_user(bstat->bs_projid_hi, &bstat32->bs_projid_hi) ||
-	    get_user(bstat->bs_forkoff,	&bstat32->bs_forkoff)	||
-	    get_user(bstat->bs_dmevmask, &bstat32->bs_dmevmask)	||
-	    get_user(bstat->bs_dmstate,	&bstat32->bs_dmstate)	||
-	    get_user(bstat->bs_aextents, &bstat32->bs_aextents))
-		return -EFAULT;
-	return 0;
-}
-
-/* XFS_IOC_FSBULKSTAT and friends */
-
-STATIC int
-xfs_bstime_store_compat(
-	compat_xfs_bstime_t	__user *p32,
-	const xfs_bstime_t	*p)
-{
-	if (put_user(p->tv_sec, &p32->tv_sec) ||
-	    put_user(p->tv_nsec, &p32->tv_nsec))
-		return -EFAULT;
-	return 0;
-}
-
-/* Return 0 on success or positive error (to xfs_bulkstat()) */
-STATIC int
-xfs_fsbulkstat_one_fmt_compat(
-	struct xfs_ibulk		*breq,
-	const struct xfs_bulkstat	*bstat)
-{
-	struct compat_xfs_bstat	__user	*p32 = breq->ubuffer;
-	struct xfs_bstat		bs1;
-	struct xfs_bstat		*buffer = &bs1;
-
-	xfs_bulkstat_to_bstat(breq->mp, &bs1, bstat);
-
-	if (put_user(buffer->bs_ino,	  &p32->bs_ino)		||
-	    put_user(buffer->bs_mode,	  &p32->bs_mode)	||
-	    put_user(buffer->bs_nlink,	  &p32->bs_nlink)	||
-	    put_user(buffer->bs_uid,	  &p32->bs_uid)		||
-	    put_user(buffer->bs_gid,	  &p32->bs_gid)		||
-	    put_user(buffer->bs_rdev,	  &p32->bs_rdev)	||
-	    put_user(buffer->bs_blksize,  &p32->bs_blksize)	||
-	    put_user(buffer->bs_size,	  &p32->bs_size)	||
-	    xfs_bstime_store_compat(&p32->bs_atime, &buffer->bs_atime) ||
-	    xfs_bstime_store_compat(&p32->bs_mtime, &buffer->bs_mtime) ||
-	    xfs_bstime_store_compat(&p32->bs_ctime, &buffer->bs_ctime) ||
-	    put_user(buffer->bs_blocks,	  &p32->bs_blocks)	||
-	    put_user(buffer->bs_xflags,	  &p32->bs_xflags)	||
-	    put_user(buffer->bs_extsize,  &p32->bs_extsize)	||
-	    put_user(buffer->bs_extents,  &p32->bs_extents)	||
-	    put_user(buffer->bs_gen,	  &p32->bs_gen)		||
-	    put_user(buffer->bs_projid,	  &p32->bs_projid)	||
-	    put_user(buffer->bs_projid_hi,	&p32->bs_projid_hi)	||
-	    put_user(buffer->bs_forkoff,  &p32->bs_forkoff)	||
-	    put_user(buffer->bs_dmevmask, &p32->bs_dmevmask)	||
-	    put_user(buffer->bs_dmstate,  &p32->bs_dmstate)	||
-	    put_user(buffer->bs_aextents, &p32->bs_aextents))
-		return -EFAULT;
-
-	return xfs_ibulk_advance(breq, sizeof(struct compat_xfs_bstat));
-}
-
 #else
 #define xfs_fsinumbers_fmt_compat xfs_fsinumbers_fmt
 #endif	/* BROKEN_X86_ALIGNMENT */
@@ -221,11 +126,6 @@  xfs_compat_ioc_fsbulkstat(
 	 */
 	inumbers_fmt_pf		inumbers_func = xfs_fsinumbers_fmt_compat;
 	bulkstat_one_fmt_pf	bs_one_func_old = xfs_fsbulkstat_time32_one_fmt;
-	bulkstat_one_fmt_pf	bs_one_func_new = xfs_fsbulkstat_one_fmt;
-
-#ifdef BROKEN_X86_ALIGNMENT
-	bs_one_func_new = xfs_fsbulkstat_one_fmt_compat;
-#endif
 
 #ifdef CONFIG_X86_X32
 	if (in_x32_syscall()) {
@@ -305,12 +205,12 @@  xfs_compat_ioc_fsbulkstat(
 	case XFS_IOC_FSBULKSTAT_SINGLE_NEW32:
 		breq.startino = lastino;
 		breq.icount = 1;
-		error = xfs_bulkstat_one(&breq, bs_one_func_new);
+		error = xfs_bulkstat_one(&breq, xfs_fsbulkstat_one_fmt);
 		lastino = breq.startino;
 		break;
 	case XFS_IOC_FSBULKSTAT_NEW32:
 		breq.startino = lastino ? lastino + 1 : 0;
-		error = xfs_bulkstat(&breq, bs_one_func_new);
+		error = xfs_bulkstat(&breq, xfs_fsbulkstat_one_fmt);
 		lastino = breq.startino - 1;
 		break;
 	default:
@@ -610,22 +510,6 @@  xfs_file_compat_ioctl(
 		mnt_drop_write_file(filp);
 		return error;
 	}
-	case XFS_IOC_SWAPEXT_32: {
-		struct xfs_swapext	  sxp;
-		struct compat_xfs_swapext __user *sxu = arg;
-
-		/* Bulk copy in up to the sx_stat field, then copy bstat */
-		if (copy_from_user(&sxp, sxu,
-				   offsetof(struct xfs_swapext, sx_stat)) ||
-		    xfs_ioctl32_bstat_copyin(&sxp.sx_stat, &sxu->sx_stat))
-			return -EFAULT;
-		error = mnt_want_write_file(filp);
-		if (error)
-			return error;
-		error = xfs_ioc_swapext(&sxp);
-		mnt_drop_write_file(filp);
-		return error;
-	}
 #endif
 	/* long changes size, but xfs only copiese out 32 bits */
 	case XFS_IOC_GETXFLAGS_32: