@@ -324,8 +324,13 @@ typedef struct xfs_growfs_rt {
* Structures returned from ioctl XFS_IOC_FSBULKSTAT & XFS_IOC_FSBULKSTAT_SINGLE
*/
typedef struct xfs_bstime {
- __kernel_long_t tv_sec; /* seconds */
+#ifdef __KERNEL__
+ __s64 tv_sec; /* seconds */
__s32 tv_nsec; /* and nanoseconds */
+#else
+ time_t tv_sec; /* seconds */
+ __s32 tv_nsec; /* and nanoseconds */
+#endif
} xfs_bstime_t;
struct xfs_bstat {
@@ -775,8 +780,8 @@ struct xfs_scrub_metadata {
* ioctl commands that replace IRIX syssgi()'s
*/
#define XFS_IOC_FSGEOMETRY_V1 _IOR ('X', 100, struct xfs_fsop_geom_v1)
-#define XFS_IOC_FSBULKSTAT _IOWR('X', 101, struct xfs_fsop_bulkreq)
-#define XFS_IOC_FSBULKSTAT_SINGLE _IOWR('X', 102, struct xfs_fsop_bulkreq)
+#define XFS_IOC_FSBULKSTAT_OLD _IOWR('X', 101, struct xfs_fsop_bulkreq)
+#define XFS_IOC_FSBULKSTAT_SINGLE_OLD _IOWR('X', 102, struct xfs_fsop_bulkreq)
#define XFS_IOC_FSINUMBERS _IOWR('X', 103, struct xfs_fsop_bulkreq)
#define XFS_IOC_PATH_TO_FSHANDLE _IOWR('X', 104, struct xfs_fsop_handlereq)
#define XFS_IOC_PATH_TO_HANDLE _IOWR('X', 105, struct xfs_fsop_handlereq)
@@ -805,6 +810,14 @@ struct xfs_scrub_metadata {
#define XFS_IOC_FSGEOMETRY _IOR ('X', 126, struct xfs_fsop_geom)
#define XFS_IOC_BULKSTAT _IOR ('X', 127, struct xfs_bulkstat_req)
#define XFS_IOC_INUMBERS _IOR ('X', 128, struct xfs_inumbers_req)
+#define XFS_IOC_FSBULKSTAT_NEW _IOWR('X', 129, struct xfs_fsop_bulkreq)
+#define XFS_IOC_FSBULKSTAT_SINGLE_NEW _IOWR('X', 130, struct xfs_fsop_bulkreq)
+
+#define XFS_IOC_FSBULKSTAT ((sizeof(time_t) == sizeof(__kernel_long_t)) ? \
+ XFS_IOC_FSBULKSTAT_OLD : XFS_IOC_FSBULKSTAT_NEW)
+#define XFS_IOC_FSBULKSTAT_SINGLE ((sizeof(time_t) == sizeof(__kernel_long_t)) ? \
+ XFS_IOC_FSBULKSTAT_OLD : XFS_IOC_FSBULKSTAT_NEW)
+
/* XFS_IOC_GETFSUUID ---------- deprecated 140 */
@@ -24,6 +24,7 @@
#include "xfs_export.h"
#include "xfs_trace.h"
#include "xfs_icache.h"
+#include "xfs_ioctl.h"
#include "xfs_trans.h"
#include "xfs_acl.h"
#include "xfs_btree.h"
@@ -713,7 +714,96 @@ xfs_ioc_space(
return error;
}
+/*
+ * Structures returned from ioctl XFS_IOC_FSBULKSTAT_TIME32 & XFS_IOC_FSBULKSTAT_SINGLE_TIME32
+ */
+struct xfs_bstime32 {
+ __s32 tv_sec; /* seconds */
+ __s32 tv_nsec; /* and nanoseconds */
+};
+
+struct xfs_bstat_time32 {
+ __u64 bs_ino; /* 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 */
+ struct xfs_bstime32 bs_atime; /* access time */
+ struct xfs_bstime32 bs_mtime; /* modify time */
+ struct xfs_bstime32 bs_ctime; /* inode change time */
+ int64_t bs_blocks; /* number of blocks */
+ __u32 bs_xflags; /* extended flags */
+ __s32 bs_extsize; /* extent size */
+ __s32 bs_extents; /* number of extents */
+ __u32 bs_gen; /* generation count */
+ __u16 bs_projid_lo; /* lower part of project id */
+ __u16 bs_forkoff; /* inode fork offset in bytes */
+ __u16 bs_projid_hi; /* higher part of project id */
+ uint16_t bs_sick; /* sick inode metadata */
+ uint16_t bs_checked; /* checked inode metadata */
+ unsigned char bs_pad[2]; /* pad space, unused */
+ __u32 bs_cowextsize; /* cow extent size */
+ __u32 bs_dmevmask; /* DMIG event mask */
+ __u16 bs_dmstate; /* DMIG state info */
+ __u16 bs_aextents; /* attribute number of extents */
+} __compat_packed; /* packing for x86-64 compat mode */
+
+/* Convert bulkstat (v5) to bstat (v1) with 32-bit time_t. */
+void
+xfs_bulkstat_to_bstat_time32(
+ struct xfs_mount *mp,
+ struct xfs_bstat_time32 *bs1,
+ const struct xfs_bulkstat *bstat)
+{
+ /* memset is needed here because of padding holes in the structure. */
+ memset(bs1, 0, sizeof(struct xfs_bstat));
+ bs1->bs_ino = bstat->bs_ino;
+ bs1->bs_mode = bstat->bs_mode;
+ bs1->bs_nlink = bstat->bs_nlink;
+ bs1->bs_uid = bstat->bs_uid;
+ bs1->bs_gid = bstat->bs_gid;
+ bs1->bs_rdev = bstat->bs_rdev;
+ bs1->bs_blksize = bstat->bs_blksize;
+ bs1->bs_size = bstat->bs_size;
+ bs1->bs_atime.tv_sec = bstat->bs_atime;
+ bs1->bs_mtime.tv_sec = bstat->bs_mtime;
+ bs1->bs_ctime.tv_sec = bstat->bs_ctime;
+ bs1->bs_atime.tv_nsec = bstat->bs_atime_nsec;
+ bs1->bs_mtime.tv_nsec = bstat->bs_mtime_nsec;
+ bs1->bs_ctime.tv_nsec = bstat->bs_ctime_nsec;
+ bs1->bs_blocks = bstat->bs_blocks;
+ bs1->bs_xflags = bstat->bs_xflags;
+ bs1->bs_extsize = XFS_FSB_TO_B(mp, bstat->bs_extsize_blks);
+ bs1->bs_extents = bstat->bs_extents;
+ bs1->bs_gen = bstat->bs_gen;
+ bs1->bs_projid_lo = bstat->bs_projectid & 0xFFFF;
+ bs1->bs_forkoff = bstat->bs_forkoff;
+ bs1->bs_projid_hi = bstat->bs_projectid >> 16;
+ bs1->bs_sick = bstat->bs_sick;
+ bs1->bs_checked = bstat->bs_checked;
+ bs1->bs_cowextsize = XFS_FSB_TO_B(mp, bstat->bs_cowextsize_blks);
+ bs1->bs_dmevmask = 0;
+ bs1->bs_dmstate = 0;
+ bs1->bs_aextents = bstat->bs_aextents;
+}
+
/* Return 0 on success or positive error */
+int
+xfs_fsbulkstat_time32_one_fmt(
+ struct xfs_ibulk *breq,
+ const struct xfs_bulkstat *bstat)
+{
+ struct xfs_bstat_time32 bs1;
+
+ xfs_bulkstat_to_bstat_time32(breq->mp, &bs1, bstat);
+ if (copy_to_user(breq->ubuffer, &bs1, sizeof(bs1)))
+ return -EFAULT;
+ return xfs_ibulk_advance(breq, sizeof(struct xfs_bstat_time32));
+}
+
int
xfs_fsbulkstat_one_fmt(
struct xfs_ibulk *breq,
@@ -789,18 +879,40 @@ xfs_ioc_fsbulkstat(
* is a special case because it has traditionally meant "first inode
* in filesystem".
*/
- if (cmd == XFS_IOC_FSINUMBERS) {
+ switch (cmd) {
+ case XFS_IOC_FSINUMBERS:
breq.startino = lastino ? lastino + 1 : 0;
error = xfs_inumbers(&breq, xfs_fsinumbers_fmt);
lastino = breq.startino - 1;
- } else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE) {
+ break;
+ case XFS_IOC_FSBULKSTAT_SINGLE_OLD:
+ if (!IS_ENABLED(CONFIG_64BIT)) {
+ breq.startino = lastino;
+ breq.icount = 1;
+ error = xfs_bulkstat_one(&breq, xfs_fsbulkstat_time32_one_fmt);
+ break;
+ }
+ /* Fallthrough */
+ case XFS_IOC_FSBULKSTAT_SINGLE_NEW:
breq.startino = lastino;
breq.icount = 1;
error = xfs_bulkstat_one(&breq, xfs_fsbulkstat_one_fmt);
- } else { /* XFS_IOC_FSBULKSTAT */
+ break;
+ case XFS_IOC_FSBULKSTAT_OLD:
+ if (!IS_ENABLED(CONFIG_64BIT)) {
+ breq.startino = lastino ? lastino + 1 : 0;
+ error = xfs_bulkstat(&breq, xfs_fsbulkstat_time32_one_fmt);
+ lastino = breq.startino - 1;
+ break;
+ }
+ /* Fallthrough */
+ case XFS_IOC_FSBULKSTAT_NEW:
breq.startino = lastino ? lastino + 1 : 0;
error = xfs_bulkstat(&breq, xfs_fsbulkstat_one_fmt);
lastino = breq.startino - 1;
+ break;
+ default:
+ error = -EINVAL;
}
if (error)
@@ -2093,6 +2205,74 @@ xfs_ioc_setlabel(
return error;
}
+static int get_xfs_bstime32(struct xfs_bstime *bstime,
+ struct xfs_bstime32 __user *bstime32)
+{
+ struct xfs_bstime32 t;
+
+ if (copy_from_user(&t, bstime32, sizeof(t)))
+ return -EFAULT;
+
+ *bstime = (struct xfs_bstime){
+ .tv_sec = t.tv_sec,
+ .tv_nsec = t.tv_nsec,
+ };
+
+ return 0;
+}
+
+static int get_xfs_bstat_time32(struct xfs_bstat *bstat,
+ struct xfs_bstat_time32 __user *bstat32)
+{
+ if (copy_from_user(bstat, bstat32,
+ offsetof(struct xfs_bstat, bs_atime)))
+ return -EFAULT;
+
+ if (get_xfs_bstime32(&bstat->bs_atime, &bstat32->bs_atime) ||
+ get_xfs_bstime32(&bstat->bs_mtime, &bstat32->bs_mtime) ||
+ get_xfs_bstime32(&bstat->bs_ctime, &bstat32->bs_ctime))
+ return -EFAULT;
+
+ if (copy_from_user(&bstat->bs_blocks, &bstat32->bs_blocks,
+ sizeof(struct xfs_bstat) -
+ offsetof(struct xfs_bstat, bs_blocks)))
+ return -EFAULT;
+
+ return 0;
+}
+
+/*
+ * Structure passed to XFS_IOC_SWAPEXT_TIME32
+ */
+struct xfs_swapext_time32
+{
+ int64_t sx_version; /* version */
+ int64_t sx_fdtarget; /* fd of target file */
+ int64_t sx_fdtmp; /* fd of tmp file */
+ xfs_off_t sx_offset; /* offset into file */
+ xfs_off_t sx_length; /* leng from offset */
+ char sx_pad[16]; /* pad space, unused */
+ struct xfs_bstat_time32 sx_stat;/* stat of target b4 copy */
+};
+#define XFS_IOC_SWAPEXT_TIME32 _IOWR('X', 109, struct xfs_swapext_time32)
+
+static int get_xfs_swapext(struct xfs_swapext *sxp, unsigned int cmd, void __user *arg)
+{
+ struct xfs_swapext_time32 *sxp32 = arg;
+ int ret;
+
+ if (cmd == XFS_IOC_SWAPEXT) {
+ ret = copy_from_user(sxp, arg, sizeof(struct xfs_swapext));
+ return ret ? -EFAULT : 0;
+ }
+
+ ret = copy_from_user(sxp, arg, offsetof(struct xfs_swapext, sx_stat));
+ if (ret)
+ return -EFAULT;
+
+ return get_xfs_bstat_time32(&sxp->sx_stat, &sxp32->sx_stat);
+}
+
/*
* Note: some of the ioctl's return positive numbers as a
* byte count indicating success, such as readlink_by_handle.
@@ -2149,8 +2329,10 @@ xfs_file_ioctl(
return 0;
}
- case XFS_IOC_FSBULKSTAT_SINGLE:
- case XFS_IOC_FSBULKSTAT:
+ case XFS_IOC_FSBULKSTAT_SINGLE_OLD:
+ case XFS_IOC_FSBULKSTAT_OLD:
+ case XFS_IOC_FSBULKSTAT_SINGLE_NEW:
+ case XFS_IOC_FSBULKSTAT_NEW:
case XFS_IOC_FSINUMBERS:
return xfs_ioc_fsbulkstat(mp, cmd, arg);
@@ -2242,10 +2424,11 @@ xfs_file_ioctl(
case XFS_IOC_ATTRMULTI_BY_HANDLE:
return xfs_attrmulti_by_handle(filp, arg);
+ case XFS_IOC_SWAPEXT_TIME32:
case XFS_IOC_SWAPEXT: {
struct xfs_swapext sxp;
- if (copy_from_user(&sxp, arg, sizeof(xfs_swapext_t)))
+ if (get_xfs_swapext(&sxp, cmd, arg))
return -EFAULT;
error = mnt_want_write_file(filp);
if (error)
@@ -83,6 +83,18 @@ struct xfs_inogrp;
int xfs_fsbulkstat_one_fmt(struct xfs_ibulk *breq,
const struct xfs_bulkstat *bstat);
+int xfs_fsbulkstat_time32_one_fmt(struct xfs_ibulk *breq,
+ const struct xfs_bulkstat *bstat);
int xfs_fsinumbers_fmt(struct xfs_ibulk *breq, const struct xfs_inumbers *igrp);
+/*
+ * On intel, even if sizes match, alignment and/or padding may differ.
+ */
+#if defined(CONFIG_IA64) || defined(CONFIG_X86_64)
+#define BROKEN_X86_ALIGNMENT
+#define __compat_packed __attribute__((packed))
+#else
+#define __compat_packed
+#endif
+
#endif
@@ -98,28 +98,18 @@ xfs_fsinumbers_fmt_compat(
return xfs_ibulk_advance(breq, sizeof(struct compat_xfs_inogrp));
}
-#else
-#define xfs_fsinumbers_fmt_compat xfs_fsinumbers_fmt
-#endif /* BROKEN_X86_ALIGNMENT */
-
+/* struct xfs_bstat has differing alignment on intel */
STATIC int
xfs_ioctl32_bstime_copyin(
xfs_bstime_t *bstime,
compat_xfs_bstime_t __user *bstime32)
{
- compat_time_t sec32; /* tv_sec differs on 64 vs. 32 */
-
- if (get_user(sec32, &bstime32->tv_sec) ||
+ if (get_user(bstime->tv_sec, &bstime32->tv_sec) ||
get_user(bstime->tv_nsec, &bstime32->tv_nsec))
return -EFAULT;
- bstime->tv_sec = sec32;
return 0;
}
-/*
- * struct xfs_bstat has differing alignment on intel, & bstime_t sizes
- * everywhere
- */
STATIC int
xfs_ioctl32_bstat_copyin(
struct xfs_bstat *bstat,
@@ -158,10 +148,7 @@ xfs_bstime_store_compat(
compat_xfs_bstime_t __user *p32,
const xfs_bstime_t *p)
{
- __s32 sec32;
-
- sec32 = p->tv_sec;
- if (put_user(sec32, &p32->tv_sec) ||
+ if (put_user(p->tv_sec, &p32->tv_sec) ||
put_user(p->tv_nsec, &p32->tv_nsec))
return -EFAULT;
return 0;
@@ -206,6 +193,10 @@ xfs_fsbulkstat_one_fmt_compat(
return xfs_ibulk_advance(breq, sizeof(struct compat_xfs_bstat));
}
+#else
+#define xfs_fsinumbers_fmt_compat xfs_fsinumbers_fmt
+#endif /* BROKEN_X86_ALIGNMENT */
+
/* copied from xfs_ioctl.c */
STATIC int
xfs_compat_ioc_fsbulkstat(
@@ -229,7 +220,12 @@ xfs_compat_ioc_fsbulkstat(
* functions and structure size are the correct ones to use ...
*/
inumbers_fmt_pf inumbers_func = xfs_fsinumbers_fmt_compat;
- bulkstat_one_fmt_pf bs_one_func = xfs_fsbulkstat_one_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()) {
@@ -242,7 +238,7 @@ xfs_compat_ioc_fsbulkstat(
* x32 userspace expects.
*/
inumbers_func = xfs_fsinumbers_fmt;
- bs_one_func = xfs_fsbulkstat_one_fmt;
+ bs_one_func_old = xfs_fsbulkstat_one_fmt;
}
#endif
@@ -289,21 +285,37 @@ xfs_compat_ioc_fsbulkstat(
* is a special case because it has traditionally meant "first inode
* in filesystem".
*/
- if (cmd == XFS_IOC_FSINUMBERS_32) {
+ switch (cmd) {
+ case XFS_IOC_FSINUMBERS_32:
breq.startino = lastino ? lastino + 1 : 0;
error = xfs_inumbers(&breq, inumbers_func);
lastino = breq.startino - 1;
- } else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE_32) {
+ break;
+ case XFS_IOC_FSBULKSTAT_SINGLE_OLD32:
breq.startino = lastino;
breq.icount = 1;
- error = xfs_bulkstat_one(&breq, bs_one_func);
+ error = xfs_bulkstat_one(&breq, bs_one_func_old);
lastino = breq.startino;
- } else if (cmd == XFS_IOC_FSBULKSTAT_32) {
+ break;
+ case XFS_IOC_FSBULKSTAT_OLD32:
breq.startino = lastino ? lastino + 1 : 0;
- error = xfs_bulkstat(&breq, bs_one_func);
+ error = xfs_bulkstat(&breq, bs_one_func_old);
lastino = breq.startino - 1;
- } else {
+ break;
+ case XFS_IOC_FSBULKSTAT_SINGLE_NEW32:
+ breq.startino = lastino;
+ breq.icount = 1;
+ error = xfs_bulkstat_one(&breq, bs_one_func_new);
+ lastino = breq.startino;
+ break;
+ case XFS_IOC_FSBULKSTAT_NEW32:
+ breq.startino = lastino ? lastino + 1 : 0;
+ error = xfs_bulkstat(&breq, bs_one_func_new);
+ lastino = breq.startino - 1;
+ break;
+ default:
error = -EINVAL;
+ break;
}
if (error)
return error;
@@ -548,7 +560,9 @@ xfs_file_compat_ioctl(
struct xfs_inode *ip = XFS_I(inode);
struct xfs_mount *mp = ip->i_mount;
void __user *arg = compat_ptr(p);
+#if defined(BROKEN_X86_ALIGNMENT)
int error;
+#endif
trace_xfs_file_compat_ioctl(ip);
@@ -596,13 +610,6 @@ xfs_file_compat_ioctl(
mnt_drop_write_file(filp);
return error;
}
-#endif
- /* long changes size, but xfs only copiese out 32 bits */
- case XFS_IOC_GETXFLAGS_32:
- case XFS_IOC_SETXFLAGS_32:
- case XFS_IOC_GETVERSION_32:
- cmd = _NATIVE_IOC(cmd, long);
- return xfs_file_ioctl(filp, cmd, p);
case XFS_IOC_SWAPEXT_32: {
struct xfs_swapext sxp;
struct compat_xfs_swapext __user *sxu = arg;
@@ -619,8 +626,17 @@ xfs_file_compat_ioctl(
mnt_drop_write_file(filp);
return error;
}
- case XFS_IOC_FSBULKSTAT_32:
- case XFS_IOC_FSBULKSTAT_SINGLE_32:
+#endif
+ /* long changes size, but xfs only copiese out 32 bits */
+ case XFS_IOC_GETXFLAGS_32:
+ case XFS_IOC_SETXFLAGS_32:
+ case XFS_IOC_GETVERSION_32:
+ cmd = _NATIVE_IOC(cmd, long);
+ return xfs_file_ioctl(filp, cmd, p);
+ case XFS_IOC_FSBULKSTAT_OLD32:
+ case XFS_IOC_FSBULKSTAT_SINGLE_OLD32:
+ case XFS_IOC_FSBULKSTAT_NEW32:
+ case XFS_IOC_FSBULKSTAT_SINGLE_NEW32:
case XFS_IOC_FSINUMBERS_32:
return xfs_compat_ioc_fsbulkstat(mp, cmd, arg);
case XFS_IOC_FD_TO_HANDLE_32:
@@ -21,20 +21,11 @@
#define XFS_IOC_SETXFLAGS_32 FS_IOC32_SETFLAGS
#define XFS_IOC_GETVERSION_32 FS_IOC32_GETVERSION
-/*
- * On intel, even if sizes match, alignment and/or padding may differ.
- */
-#if defined(CONFIG_IA64) || defined(CONFIG_X86_64)
-#define BROKEN_X86_ALIGNMENT
-#define __compat_packed __attribute__((packed))
-#else
-#define __compat_packed
-#endif
-
+#ifdef BROKEN_X86_ALIGNMENT
typedef struct compat_xfs_bstime {
- compat_time_t tv_sec; /* seconds */
+ __s64 tv_sec; /* seconds */
__s32 tv_nsec; /* and nanoseconds */
-} compat_xfs_bstime_t;
+} __compat_packed compat_xfs_bstime_t;
struct compat_xfs_bstat {
__u64 bs_ino; /* inode number */
@@ -62,6 +53,7 @@ struct compat_xfs_bstat {
__u16 bs_dmstate; /* DMIG state info */
__u16 bs_aextents; /* attribute number of extents */
} __compat_packed;
+#endif
struct compat_xfs_fsop_bulkreq {
compat_uptr_t lastip; /* last inode # pointer */
@@ -70,10 +62,14 @@ struct compat_xfs_fsop_bulkreq {
compat_uptr_t ocount; /* output count pointer */
};
-#define XFS_IOC_FSBULKSTAT_32 \
+#define XFS_IOC_FSBULKSTAT_OLD32 \
_IOWR('X', 101, struct compat_xfs_fsop_bulkreq)
-#define XFS_IOC_FSBULKSTAT_SINGLE_32 \
+#define XFS_IOC_FSBULKSTAT_SINGLE_OLD32 \
_IOWR('X', 102, struct compat_xfs_fsop_bulkreq)
+#define XFS_IOC_FSBULKSTAT_NEW32 \
+ _IOWR('X', 129, struct compat_xfs_fsop_bulkreq)
+#define XFS_IOC_FSBULKSTAT_SINGLE_NEW32 \
+ _IOWR('X', 130, struct compat_xfs_fsop_bulkreq)
#define XFS_IOC_FSINUMBERS_32 \
_IOWR('X', 103, struct compat_xfs_fsop_bulkreq)
@@ -98,6 +94,7 @@ typedef struct compat_xfs_fsop_handlereq {
#define XFS_IOC_READLINK_BY_HANDLE_32 \
_IOWR('X', 108, struct compat_xfs_fsop_handlereq)
+#ifdef BROKEN_X86_ALIGNMENT
/* The bstat field in the swapext struct needs translation */
typedef struct compat_xfs_swapext {
int64_t sx_version; /* version */
@@ -110,6 +107,7 @@ typedef struct compat_xfs_swapext {
} __compat_packed compat_xfs_swapext_t;
#define XFS_IOC_SWAPEXT_32 _IOWR('X', 109, struct compat_xfs_swapext)
+#endif
typedef struct compat_xfs_fsop_attrlist_handlereq {
struct compat_xfs_fsop_handlereq hreq; /* handle interface structure */
The ioctl definitions for XFS_IOC_SWAPEXT, XFS_IOC_FSBULKSTAT and XFS_IOC_FSBULKSTAT_SINGLE are part of libxfs and based on time_t. The definition for time_t differs between current kernels and coming 32-bit libc variants that define it as 64-bit. For most ioctls, that means the kernel has to be able to handle two different command codes based on the different structure sizes. The same solution is be applied for XFS_IOC_SWAPEXT, but it would does work for XFS_IOC_FSBULKSTAT and XFS_IOC_FSBULKSTAT_SINGLE because the structure with the time_t is passed through an indirect pointer, and the command number itself is based on struct xfs_fsop_bulkreq, which does not differ based on time_t. The best workaround I could come up with is to change the header file to define new command numbers with the same structure and have users pick one or the other at compile-time based on the time_t definition in the C library, like: #define XFS_IOC_FSBULKSTAT_OLD _IOWR('X', 101, struct xfs_fsop_bulkreq) #define XFS_IOC_FSBULKSTAT_NEW _IOWR('X', 129, struct xfs_fsop_bulkreq) #define XFS_IOC_FSBULKSTAT ((sizeof(time_t) == sizeof(__kernel_long_t)) ? \ XFS_IOC_FSBULKSTAT_OLD : XFS_IOC_FSBULKSTAT_NEW) The native xfs_ioctl now handles both the time32 and the time64 version of the xfs_bstat data structure, and this gets called indirectly by the compat code implementing the xfs_fsop_bulkreq commands. For x86, we still need another implementation to deal with the broken alignment, so the existing code is left in ioctl32 but changed to now handle the misaligned time64 structure. Based on the requirement to change the header file, a much simpler fix would be to change the time_t reference to 'long' and always keep passing the shorter timestamp as on 32-bit applications using the old ioctl, forcing code changes to use the v5 API to access post-y2038 timestamps, and still requiring the updated header when building with a new C library. Signed-off-by: Arnd Bergmann <arnd@arndb.de> --- Note: I have not tested this patch beyond compiling it, for now this is for discussion, to decide which approach makes more sense. --- fs/xfs/libxfs/xfs_fs.h | 19 +++- fs/xfs/xfs_ioctl.c | 195 +++++++++++++++++++++++++++++++++++++++-- fs/xfs/xfs_ioctl.h | 12 +++ fs/xfs/xfs_ioctl32.c | 82 ++++++++++------- fs/xfs/xfs_ioctl32.h | 26 +++--- 5 files changed, 278 insertions(+), 56 deletions(-)