]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
Merge tag 'y2038-for-4.21' of ssh://gitolite.kernel.org:/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 28 Dec 2018 20:45:04 +0000 (12:45 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 28 Dec 2018 20:45:04 +0000 (12:45 -0800)
Pull y2038 updates from Arnd Bergmann:
 "More syscalls and cleanups

  This concludes the main part of the system call rework for 64-bit
  time_t, which has spread over most of year 2018, the last six system
  calls being

    - ppoll
    - pselect6
    - io_pgetevents
    - recvmmsg
    - futex
    - rt_sigtimedwait

  As before, nothing changes for 64-bit architectures, while 32-bit
  architectures gain another entry point that differs only in the layout
  of the timespec structure. Hopefully in the next release we can wire
  up all 22 of those system calls on all 32-bit architectures, which
  gives us a baseline version for glibc to start using them.

  This does not include the clock_adjtime, getrusage/waitid, and
  getitimer/setitimer system calls. I still plan to have new versions of
  those as well, but they are not required for correct operation of the
  C library since they can be emulated using the old 32-bit time_t based
  system calls.

  Aside from the system calls, there are also a few cleanups here,
  removing old kernel internal interfaces that have become unused after
  all references got removed. The arch/sh cleanups are part of this,
  there were posted several times over the past year without a reaction
  from the maintainers, while the corresponding changes made it into all
  other architectures"

* tag 'y2038-for-4.21' of ssh://gitolite.kernel.org:/pub/scm/linux/kernel/git/arnd/playground:
  timekeeping: remove obsolete time accessors
  vfs: replace current_kernel_time64 with ktime equivalent
  timekeeping: remove timespec_add/timespec_del
  timekeeping: remove unused {read,update}_persistent_clock
  sh: remove board_time_init() callback
  sh: remove unused rtc_sh_get/set_time infrastructure
  sh: sh03: rtc: push down rtc class ops into driver
  sh: dreamcast: rtc: push down rtc class ops into driver
  y2038: signal: Add compat_sys_rt_sigtimedwait_time64
  y2038: signal: Add sys_rt_sigtimedwait_time32
  y2038: socket: Add compat_sys_recvmmsg_time64
  y2038: futex: Add support for __kernel_timespec
  y2038: futex: Move compat implementation into futex.c
  io_pgetevents: use __kernel_timespec
  pselect6: use __kernel_timespec
  ppoll: use __kernel_timespec
  signal: Add restore_user_sigmask()
  signal: Add set_user_sigmask()

35 files changed:
Documentation/sh/new-machine.txt
arch/sh/boards/mach-dreamcast/Makefile
arch/sh/boards/mach-dreamcast/rtc.c
arch/sh/boards/mach-dreamcast/setup.c
arch/sh/boards/mach-sh03/Makefile
arch/sh/boards/mach-sh03/rtc.c
arch/sh/boards/mach-sh03/setup.c
arch/sh/boards/of-generic.c
arch/sh/configs/dreamcast_defconfig
arch/sh/configs/sh03_defconfig
arch/sh/include/asm/rtc.h
arch/sh/include/mach-dreamcast/mach/sysasic.h
arch/sh/kernel/time.c
fs/aio.c
fs/eventpoll.c
fs/inode.c
fs/select.c
include/linux/compat.h
include/linux/futex.h
include/linux/signal.h
include/linux/socket.h
include/linux/syscalls.h
include/linux/time32.h
include/linux/timekeeping.h
include/linux/timekeeping32.h
kernel/Makefile
kernel/futex.c
kernel/futex_compat.c [deleted file]
kernel/signal.c
kernel/sys_ni.c
kernel/time/ntp.c
kernel/time/time.c
kernel/time/timekeeping.c
net/compat.c
net/socket.c

index f0354164cb0e4cea15670373b4b3db0e6cf80e42..e0961a66130b0965abb211d34ca20159b47640d1 100644 (file)
@@ -116,7 +116,6 @@ might look something like:
  * arch/sh/boards/vapor/setup.c - Setup code for imaginary board
  */
 #include <linux/init.h>
-#include <asm/rtc.h> /* for board_time_init() */
 
 const char *get_system_type(void)
 {
@@ -132,13 +131,6 @@ int __init platform_setup(void)
         * this board.
         */
 
-       /* 
-        * Presume all FooTech boards have the same broken timer,
-        * and also presume that we've defined foo_timer_init to
-        * do something useful.
-        */
-       board_time_init = foo_timer_init;
-
        /* Start-up imaginary PCI ... */
 
        /* And whatever else ... */
index 7b97546c7e5f4d58bda8f080e0910290a05a5112..62b024bc2a3ef59a8e1654387a7de853c394c506 100644 (file)
@@ -2,5 +2,5 @@
 # Makefile for the Sega Dreamcast specific parts of the kernel
 #
 
-obj-y   := setup.o irq.o rtc.o
-
+obj-y   := setup.o irq.o
+obj-$(CONFIG_RTC_DRV_GENERIC) += rtc.o
index 061d65714fcc2782ab0dae15daec9e33223d43c3..0eb12c45fa597174d48bace5151b4b9fe5bfa9ce 100644 (file)
@@ -11,8 +11,9 @@
  */
 
 #include <linux/time.h>
-#include <asm/rtc.h>
-#include <asm/io.h>
+#include <linux/rtc.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
 
 /* The AICA RTC has an Epoch of 1/1/1950, so we must subtract 20 years (in
    seconds) to get the standard Unix Epoch when getting the time, and add
 
 /**
  * aica_rtc_gettimeofday - Get the time from the AICA RTC
- * @ts: pointer to resulting timespec
+ * @dev: the RTC device (ignored)
+ * @tm: pointer to resulting RTC time structure
  *
  * Grabs the current RTC seconds counter and adjusts it to the Unix Epoch.
  */
-static void aica_rtc_gettimeofday(struct timespec *ts)
+static int aica_rtc_gettimeofday(struct device *dev, struct rtc_time *tm)
 {
        unsigned long val1, val2;
+       time64_t t;
 
        do {
                val1 = ((__raw_readl(AICA_RTC_SECS_H) & 0xffff) << 16) |
@@ -42,22 +45,26 @@ static void aica_rtc_gettimeofday(struct timespec *ts)
                        (__raw_readl(AICA_RTC_SECS_L) & 0xffff);
        } while (val1 != val2);
 
-       ts->tv_sec = val1 - TWENTY_YEARS;
+       /* normalize to 1970..2106 time range */
+       t = (u32)(val1 - TWENTY_YEARS);
 
-       /* Can't get nanoseconds with just a seconds counter. */
-       ts->tv_nsec = 0;
+       rtc_time64_to_tm(t, tm);
+
+       return 0;
 }
 
 /**
  * aica_rtc_settimeofday - Set the AICA RTC to the current time
- * @secs: contains the time_t to set
+ * @dev: the RTC device (ignored)
+ * @tm: pointer to new RTC time structure
  *
  * Adjusts the given @tv to the AICA Epoch and sets the RTC seconds counter.
  */
-static int aica_rtc_settimeofday(const time_t secs)
+static int aica_rtc_settimeofday(struct device *dev, struct rtc_time *tm)
 {
        unsigned long val1, val2;
-       unsigned long adj = secs + TWENTY_YEARS;
+       time64_t secs = rtc_tm_to_time64(tm);
+       u32 adj = secs + TWENTY_YEARS;
 
        do {
                __raw_writel((adj & 0xffff0000) >> 16, AICA_RTC_SECS_H);
@@ -73,9 +80,19 @@ static int aica_rtc_settimeofday(const time_t secs)
        return 0;
 }
 
-void aica_time_init(void)
+static const struct rtc_class_ops rtc_generic_ops = {
+       .read_time = aica_rtc_gettimeofday,
+       .set_time = aica_rtc_settimeofday,
+};
+
+static int __init aica_time_init(void)
 {
-       rtc_sh_get_time = aica_rtc_gettimeofday;
-       rtc_sh_set_time = aica_rtc_settimeofday;
-}
+       struct platform_device *pdev;
+
+       pdev = platform_device_register_data(NULL, "rtc-generic", -1,
+                                            &rtc_generic_ops,
+                                            sizeof(rtc_generic_ops));
 
+       return PTR_ERR_OR_ZERO(pdev);
+}
+arch_initcall(aica_time_init);
index ad1a4db72e0406308484ce7bebe6ad514433696b..672c2ad8f8d57866e04c946c3727fd9746ba6af4 100644 (file)
@@ -30,7 +30,6 @@
 
 static void __init dreamcast_setup(char **cmdline_p)
 {
-       board_time_init = aica_time_init;
 }
 
 static struct sh_machine_vector mv_dreamcast __initmv = {
index 400306a796ec5427f9554b5a78074d1f10302495..47007a3a2fc8add20654fe975ca9bbb42777f364 100644 (file)
@@ -2,4 +2,5 @@
 # Makefile for the Interface (CTP/PCI-SH03) specific parts of the kernel
 #
 
-obj-y   := setup.o rtc.o
+obj-y   := setup.o
+obj-$(CONFIG_RTC_DRV_GENERIC) += rtc.o
index dc3d50e3b7a2acc517e06cc291de9af36a243db4..8b23ed7c201c6ebca21e15f2682b2030d3104474 100644 (file)
@@ -13,8 +13,9 @@
 #include <linux/bcd.h>
 #include <linux/rtc.h>
 #include <linux/spinlock.h>
-#include <asm/io.h>
-#include <asm/rtc.h>
+#include <linux/io.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
 
 #define RTC_BASE       0xb0000000
 #define RTC_SEC1       (RTC_BASE + 0)
@@ -38,7 +39,7 @@
 
 static DEFINE_SPINLOCK(sh03_rtc_lock);
 
-unsigned long get_cmos_time(void)
+static int sh03_rtc_gettimeofday(struct device *dev, struct rtc_time *tm)
 {
        unsigned int year, mon, day, hour, min, sec;
 
@@ -75,17 +76,18 @@ unsigned long get_cmos_time(void)
        }
 
        spin_unlock(&sh03_rtc_lock);
-       return mktime(year, mon, day, hour, min, sec);
-}
 
-void sh03_rtc_gettimeofday(struct timespec *tv)
-{
+       tm->tm_sec  = sec;
+       tm->tm_min  = min;
+       tm->tm_hour = hour;
+       tm->tm_mday = day;
+       tm->tm_mon  = mon;
+       tm->tm_year = year - 1900;
 
-       tv->tv_sec = get_cmos_time();
-       tv->tv_nsec = 0;
+       return 0;
 }
 
-static int set_rtc_mmss(unsigned long nowtime)
+static int set_rtc_mmss(struct rtc_time *tm)
 {
        int retval = 0;
        int real_seconds, real_minutes, cmos_minutes;
@@ -97,8 +99,8 @@ static int set_rtc_mmss(unsigned long nowtime)
                if (!(__raw_readb(RTC_CTL) & RTC_BUSY))
                        break;
        cmos_minutes = (__raw_readb(RTC_MIN1) & 0xf) + (__raw_readb(RTC_MIN10) & 0xf) * 10;
-       real_seconds = nowtime % 60;
-       real_minutes = nowtime / 60;
+       real_seconds = tm->tm_sec;
+       real_minutes = tm->tm_min;
        if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
                real_minutes += 30;             /* correct for half hour time zone */
        real_minutes %= 60;
@@ -112,22 +114,31 @@ static int set_rtc_mmss(unsigned long nowtime)
                printk_once(KERN_NOTICE
                       "set_rtc_mmss: can't update from %d to %d\n",
                       cmos_minutes, real_minutes);
-               retval = -1;
+               retval = -EINVAL;
        }
        spin_unlock(&sh03_rtc_lock);
 
        return retval;
 }
 
-int sh03_rtc_settimeofday(const time_t secs)
+int sh03_rtc_settimeofday(struct device *dev, struct rtc_time *tm)
 {
-       unsigned long nowtime = secs;
-
-       return set_rtc_mmss(nowtime);
+       return set_rtc_mmss(tm);
 }
 
-void sh03_time_init(void)
+static const struct rtc_class_ops rtc_generic_ops = {
+       .read_time = sh03_rtc_gettimeofday,
+       .set_time = sh03_rtc_settimeofday,
+};
+
+static int __init sh03_time_init(void)
 {
-       rtc_sh_get_time = sh03_rtc_gettimeofday;
-       rtc_sh_set_time = sh03_rtc_settimeofday;
+       struct platform_device *pdev;
+
+       pdev = platform_device_register_data(NULL, "rtc-generic", -1,
+                                            &rtc_generic_ops,
+                                            sizeof(rtc_generic_ops));
+
+       return PTR_ERR_OR_ZERO(pdev);
 }
+arch_initcall(sh03_time_init);
index 85e7059a77e9fbf844d96a7b44e9247ab35c1148..3901b6031ad565fc999967e1b53029b6e9eb01ab 100644 (file)
@@ -22,14 +22,6 @@ static void __init init_sh03_IRQ(void)
        plat_irq_setup_pins(IRQ_MODE_IRQ);
 }
 
-/* arch/sh/boards/sh03/rtc.c */
-void sh03_time_init(void);
-
-static void __init sh03_setup(char **cmdline_p)
-{
-       board_time_init = sh03_time_init;
-}
-
 static struct resource cf_ide_resources[] = {
        [0] = {
                .start  = 0x1f0,
@@ -101,6 +93,5 @@ device_initcall(sh03_devices_setup);
 
 static struct sh_machine_vector mv_sh03 __initmv = {
        .mv_name                = "Interface (CTP/PCI-SH03)",
-       .mv_setup               = sh03_setup,
        .mv_init_irq            = init_sh03_IRQ,
 };
index cde370cad4ae3c0b447929a63e6d197c0a38f562..6e9786548ac652f107600a2e4755ed78d341d898 100644 (file)
@@ -117,18 +117,10 @@ static void __init sh_of_mem_reserve(void)
        early_init_fdt_scan_reserved_mem();
 }
 
-static void __init sh_of_time_init(void)
-{
-       pr_info("SH generic board support: scanning for clocksource devices\n");
-       timer_probe();
-}
-
 static void __init sh_of_setup(char **cmdline_p)
 {
        struct device_node *root;
 
-       board_time_init = sh_of_time_init;
-
        sh_mv.mv_name = "Unknown SH model";
        root = of_find_node_by_path("/");
        if (root) {
index 3f08dc54480b8f9be93e4d24e645a05e0fac3930..1d27666c029f7efaaf42907799104f50611f5809 100644 (file)
@@ -70,3 +70,5 @@ CONFIG_PROC_KCORE=y
 CONFIG_TMPFS=y
 CONFIG_HUGETLBFS=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_GENERIC=y
index 2156223405a160df5031ba0dcff300118a979262..489ffdfb1517840e3630eaffa460229943d9c2fb 100644 (file)
@@ -130,3 +130,5 @@ CONFIG_CRYPTO_SHA1=y
 CONFIG_CRYPTO_DEFLATE=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRC_CCITT=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_GENERIC=y
index c63555ee12555817193f3a74f2711b1d56a5b639..69dbae2949b0dd679d8fe7a47050c4962b7aaf24 100644 (file)
@@ -3,9 +3,6 @@
 #define _ASM_RTC_H
 
 void time_init(void);
-extern void (*board_time_init)(void);
-extern void (*rtc_sh_get_time)(struct timespec *);
-extern int (*rtc_sh_set_time)(const time_t);
 
 #define RTC_CAP_4_DIGIT_YEAR   (1 << 0)
 
index 58f710e1ebc2af30dc235cd4c17370798f986e23..59effd1ed3e138de548efb2ce38a56a60b691ffb 100644 (file)
@@ -42,7 +42,6 @@
 /* arch/sh/boards/mach-dreamcast/irq.c */
 extern int systemasic_irq_demux(int);
 extern void systemasic_irq_init(void);
-extern void aica_time_init(void);
 
 #endif /* __ASM_SH_DREAMCAST_SYSASIC_H */
 
index fcd5e41977d176709c3c8d14d89e32e31b4791c8..8a1c6c8ab4ec9698b7f079c418e33f1775bc2791 100644 (file)
 #include <asm/clock.h>
 #include <asm/rtc.h>
 
-/* Dummy RTC ops */
-static void null_rtc_get_time(struct timespec *tv)
-{
-       tv->tv_sec = mktime(2000, 1, 1, 0, 0, 0);
-       tv->tv_nsec = 0;
-}
-
-static int null_rtc_set_time(const time_t secs)
-{
-       return 0;
-}
-
-void (*rtc_sh_get_time)(struct timespec *) = null_rtc_get_time;
-int (*rtc_sh_set_time)(const time_t) = null_rtc_set_time;
-
-void read_persistent_clock(struct timespec *ts)
-{
-       rtc_sh_get_time(ts);
-}
-
-#ifdef CONFIG_GENERIC_CMOS_UPDATE
-int update_persistent_clock(struct timespec now)
-{
-       return rtc_sh_set_time(now.tv_sec);
-}
-#endif
-
-static int rtc_generic_get_time(struct device *dev, struct rtc_time *tm)
-{
-       struct timespec tv;
-
-       rtc_sh_get_time(&tv);
-       rtc_time_to_tm(tv.tv_sec, tm);
-       return 0;
-}
-
-static int rtc_generic_set_time(struct device *dev, struct rtc_time *tm)
-{
-       unsigned long secs;
-
-       rtc_tm_to_time(tm, &secs);
-       if ((rtc_sh_set_time == null_rtc_set_time) ||
-           (rtc_sh_set_time(secs) < 0))
-               return -EOPNOTSUPP;
-
-       return 0;
-}
-
-static const struct rtc_class_ops rtc_generic_ops = {
-       .read_time = rtc_generic_get_time,
-       .set_time = rtc_generic_set_time,
-};
-
-static int __init rtc_generic_init(void)
-{
-       struct platform_device *pdev;
-
-       if (rtc_sh_get_time == null_rtc_get_time)
-               return -ENODEV;
-
-       pdev = platform_device_register_data(NULL, "rtc-generic", -1,
-                                            &rtc_generic_ops,
-                                            sizeof(rtc_generic_ops));
-
-
-       return PTR_ERR_OR_ZERO(pdev);
-}
-device_initcall(rtc_generic_init);
-
-void (*board_time_init)(void);
-
 static void __init sh_late_time_init(void)
 {
        /*
@@ -110,8 +39,7 @@ static void __init sh_late_time_init(void)
 
 void __init time_init(void)
 {
-       if (board_time_init)
-               board_time_init();
+       timer_probe();
 
        clk_init();
 
index aac9659381d2564542eecaa71932aeea7f6720e2..76f72509f8c5edbeeadd0cd1aad5602fccc73da0 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -2065,11 +2065,13 @@ static long do_io_getevents(aio_context_t ctx_id,
  *     specifies an infinite timeout. Note that the timeout pointed to by
  *     timeout is relative.  Will fail with -ENOSYS if not implemented.
  */
+#if !defined(CONFIG_64BIT_TIME) || defined(CONFIG_64BIT)
+
 SYSCALL_DEFINE5(io_getevents, aio_context_t, ctx_id,
                long, min_nr,
                long, nr,
                struct io_event __user *, events,
-               struct timespec __user *, timeout)
+               struct __kernel_timespec __user *, timeout)
 {
        struct timespec64       ts;
        int                     ret;
@@ -2083,6 +2085,8 @@ SYSCALL_DEFINE5(io_getevents, aio_context_t, ctx_id,
        return ret;
 }
 
+#endif
+
 struct __aio_sigset {
        const sigset_t __user   *sigmask;
        size_t          sigsetsize;
@@ -2093,7 +2097,7 @@ SYSCALL_DEFINE6(io_pgetevents,
                long, min_nr,
                long, nr,
                struct io_event __user *, events,
-               struct timespec __user *, timeout,
+               struct __kernel_timespec __user *, timeout,
                const struct __aio_sigset __user *, usig)
 {
        struct __aio_sigset     ksig = { NULL, };
@@ -2107,33 +2111,56 @@ SYSCALL_DEFINE6(io_pgetevents,
        if (usig && copy_from_user(&ksig, usig, sizeof(ksig)))
                return -EFAULT;
 
-       if (ksig.sigmask) {
-               if (ksig.sigsetsize != sizeof(sigset_t))
-                       return -EINVAL;
-               if (copy_from_user(&ksigmask, ksig.sigmask, sizeof(ksigmask)))
-                       return -EFAULT;
-               sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP));
-               sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
-       }
+       ret = set_user_sigmask(ksig.sigmask, &ksigmask, &sigsaved, ksig.sigsetsize);
+       if (ret)
+               return ret;
 
        ret = do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &ts : NULL);
-       if (signal_pending(current)) {
-               if (ksig.sigmask) {
-                       current->saved_sigmask = sigsaved;
-                       set_restore_sigmask();
-               }
+       restore_user_sigmask(ksig.sigmask, &sigsaved);
+       if (signal_pending(current) && !ret)
+               ret = -ERESTARTNOHAND;
 
-               if (!ret)
-                       ret = -ERESTARTNOHAND;
-       } else {
-               if (ksig.sigmask)
-                       sigprocmask(SIG_SETMASK, &sigsaved, NULL);
-       }
+       return ret;
+}
+
+#if defined(CONFIG_COMPAT_32BIT_TIME) && !defined(CONFIG_64BIT)
+
+SYSCALL_DEFINE6(io_pgetevents_time32,
+               aio_context_t, ctx_id,
+               long, min_nr,
+               long, nr,
+               struct io_event __user *, events,
+               struct old_timespec32 __user *, timeout,
+               const struct __aio_sigset __user *, usig)
+{
+       struct __aio_sigset     ksig = { NULL, };
+       sigset_t                ksigmask, sigsaved;
+       struct timespec64       ts;
+       int ret;
+
+       if (timeout && unlikely(get_old_timespec32(&ts, timeout)))
+               return -EFAULT;
+
+       if (usig && copy_from_user(&ksig, usig, sizeof(ksig)))
+               return -EFAULT;
+
+
+       ret = set_user_sigmask(ksig.sigmask, &ksigmask, &sigsaved, ksig.sigsetsize);
+       if (ret)
+               return ret;
+
+       ret = do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &ts : NULL);
+       restore_user_sigmask(ksig.sigmask, &sigsaved);
+       if (signal_pending(current) && !ret)
+               ret = -ERESTARTNOHAND;
 
        return ret;
 }
 
-#ifdef CONFIG_COMPAT
+#endif
+
+#if defined(CONFIG_COMPAT_32BIT_TIME)
+
 COMPAT_SYSCALL_DEFINE5(io_getevents, compat_aio_context_t, ctx_id,
                       compat_long_t, min_nr,
                       compat_long_t, nr,
@@ -2152,12 +2179,17 @@ COMPAT_SYSCALL_DEFINE5(io_getevents, compat_aio_context_t, ctx_id,
        return ret;
 }
 
+#endif
+
+#ifdef CONFIG_COMPAT
 
 struct __compat_aio_sigset {
        compat_sigset_t __user  *sigmask;
        compat_size_t           sigsetsize;
 };
 
+#if defined(CONFIG_COMPAT_32BIT_TIME)
+
 COMPAT_SYSCALL_DEFINE6(io_pgetevents,
                compat_aio_context_t, ctx_id,
                compat_long_t, min_nr,
@@ -2177,27 +2209,47 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents,
        if (usig && copy_from_user(&ksig, usig, sizeof(ksig)))
                return -EFAULT;
 
-       if (ksig.sigmask) {
-               if (ksig.sigsetsize != sizeof(compat_sigset_t))
-                       return -EINVAL;
-               if (get_compat_sigset(&ksigmask, ksig.sigmask))
-                       return -EFAULT;
-               sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP));
-               sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
-       }
+       ret = set_compat_user_sigmask(ksig.sigmask, &ksigmask, &sigsaved, ksig.sigsetsize);
+       if (ret)
+               return ret;
 
        ret = do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &t : NULL);
-       if (signal_pending(current)) {
-               if (ksig.sigmask) {
-                       current->saved_sigmask = sigsaved;
-                       set_restore_sigmask();
-               }
-               if (!ret)
-                       ret = -ERESTARTNOHAND;
-       } else {
-               if (ksig.sigmask)
-                       sigprocmask(SIG_SETMASK, &sigsaved, NULL);
-       }
+       restore_user_sigmask(ksig.sigmask, &sigsaved);
+       if (signal_pending(current) && !ret)
+               ret = -ERESTARTNOHAND;
+
+       return ret;
+}
+
+#endif
+
+COMPAT_SYSCALL_DEFINE6(io_pgetevents_time64,
+               compat_aio_context_t, ctx_id,
+               compat_long_t, min_nr,
+               compat_long_t, nr,
+               struct io_event __user *, events,
+               struct __kernel_timespec __user *, timeout,
+               const struct __compat_aio_sigset __user *, usig)
+{
+       struct __compat_aio_sigset ksig = { NULL, };
+       sigset_t ksigmask, sigsaved;
+       struct timespec64 t;
+       int ret;
+
+       if (timeout && get_timespec64(&t, timeout))
+               return -EFAULT;
+
+       if (usig && copy_from_user(&ksig, usig, sizeof(ksig)))
+               return -EFAULT;
+
+       ret = set_compat_user_sigmask(ksig.sigmask, &ksigmask, &sigsaved, ksig.sigsetsize);
+       if (ret)
+               return ret;
+
+       ret = do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &t : NULL);
+       restore_user_sigmask(ksig.sigmask, &sigsaved);
+       if (signal_pending(current) && !ret)
+               ret = -ERESTARTNOHAND;
 
        return ret;
 }
index 42bbe6824b4bffc1fb5388c993abf102fcd8ea2b..8a5a1010886bad1f5c2918565807b5b3aaa988e1 100644 (file)
@@ -2223,31 +2223,13 @@ SYSCALL_DEFINE6(epoll_pwait, int, epfd, struct epoll_event __user *, events,
         * If the caller wants a certain signal mask to be set during the wait,
         * we apply it here.
         */
-       if (sigmask) {
-               if (sigsetsize != sizeof(sigset_t))
-                       return -EINVAL;
-               if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask)))
-                       return -EFAULT;
-               sigsaved = current->blocked;
-               set_current_blocked(&ksigmask);
-       }
+       error = set_user_sigmask(sigmask, &ksigmask, &sigsaved, sigsetsize);
+       if (error)
+               return error;
 
        error = do_epoll_wait(epfd, events, maxevents, timeout);
 
-       /*
-        * If we changed the signal mask, we need to restore the original one.
-        * In case we've got a signal while waiting, we do not restore the
-        * signal mask yet, and we allow do_signal() to deliver the signal on
-        * the way back to userspace, before the signal mask is restored.
-        */
-       if (sigmask) {
-               if (error == -EINTR) {
-                       memcpy(&current->saved_sigmask, &sigsaved,
-                              sizeof(sigsaved));
-                       set_restore_sigmask();
-               } else
-                       set_current_blocked(&sigsaved);
-       }
+       restore_user_sigmask(sigmask, &sigsaved);
 
        return error;
 }
@@ -2266,31 +2248,13 @@ COMPAT_SYSCALL_DEFINE6(epoll_pwait, int, epfd,
         * If the caller wants a certain signal mask to be set during the wait,
         * we apply it here.
         */
-       if (sigmask) {
-               if (sigsetsize != sizeof(compat_sigset_t))
-                       return -EINVAL;
-               if (get_compat_sigset(&ksigmask, sigmask))
-                       return -EFAULT;
-               sigsaved = current->blocked;
-               set_current_blocked(&ksigmask);
-       }
+       err = set_compat_user_sigmask(sigmask, &ksigmask, &sigsaved, sigsetsize);
+       if (err)
+               return err;
 
        err = do_epoll_wait(epfd, events, maxevents, timeout);
 
-       /*
-        * If we changed the signal mask, we need to restore the original one.
-        * In case we've got a signal while waiting, we do not restore the
-        * signal mask yet, and we allow do_signal() to deliver the signal on
-        * the way back to userspace, before the signal mask is restored.
-        */
-       if (sigmask) {
-               if (err == -EINTR) {
-                       memcpy(&current->saved_sigmask, &sigsaved,
-                              sizeof(sigsaved));
-                       set_restore_sigmask();
-               } else
-                       set_current_blocked(&sigsaved);
-       }
+       restore_user_sigmask(sigmask, &sigsaved);
 
        return err;
 }
index 35d2108d567c25d0de1376a84e8a2a4333859ddf..0cd47fe0dbe51db41233db2cace81b1f64503b32 100644 (file)
@@ -2149,7 +2149,9 @@ EXPORT_SYMBOL(timespec64_trunc);
  */
 struct timespec64 current_time(struct inode *inode)
 {
-       struct timespec64 now = current_kernel_time64();
+       struct timespec64 now;
+
+       ktime_get_coarse_real_ts64(&now);
 
        if (unlikely(!inode->i_sb)) {
                WARN(1, "current_time() called with uninitialized super_block in the inode");
index 22b3bf89f051e9c60bd96ce4ce24024f6b5e84d6..4c8652390c944b47ce9286aa1db409baf9cc75eb 100644 (file)
@@ -287,12 +287,18 @@ int poll_select_set_timeout(struct timespec64 *to, time64_t sec, long nsec)
        return 0;
 }
 
+enum poll_time_type {
+       PT_TIMEVAL = 0,
+       PT_OLD_TIMEVAL = 1,
+       PT_TIMESPEC = 2,
+       PT_OLD_TIMESPEC = 3,
+};
+
 static int poll_select_copy_remaining(struct timespec64 *end_time,
                                      void __user *p,
-                                     int timeval, int ret)
+                                     enum poll_time_type pt_type, int ret)
 {
        struct timespec64 rts;
-       struct timeval rtv;
 
        if (!p)
                return ret;
@@ -310,18 +316,40 @@ static int poll_select_copy_remaining(struct timespec64 *end_time,
                rts.tv_sec = rts.tv_nsec = 0;
 
 
-       if (timeval) {
-               if (sizeof(rtv) > sizeof(rtv.tv_sec) + sizeof(rtv.tv_usec))
-                       memset(&rtv, 0, sizeof(rtv));
-               rtv.tv_sec = rts.tv_sec;
-               rtv.tv_usec = rts.tv_nsec / NSEC_PER_USEC;
+       switch (pt_type) {
+       case PT_TIMEVAL:
+               {
+                       struct timeval rtv;
 
-               if (!copy_to_user(p, &rtv, sizeof(rtv)))
+                       if (sizeof(rtv) > sizeof(rtv.tv_sec) + sizeof(rtv.tv_usec))
+                               memset(&rtv, 0, sizeof(rtv));
+                       rtv.tv_sec = rts.tv_sec;
+                       rtv.tv_usec = rts.tv_nsec / NSEC_PER_USEC;
+                       if (!copy_to_user(p, &rtv, sizeof(rtv)))
+                               return ret;
+               }
+               break;
+       case PT_OLD_TIMEVAL:
+               {
+                       struct old_timeval32 rtv;
+
+                       rtv.tv_sec = rts.tv_sec;
+                       rtv.tv_usec = rts.tv_nsec / NSEC_PER_USEC;
+                       if (!copy_to_user(p, &rtv, sizeof(rtv)))
+                               return ret;
+               }
+               break;
+       case PT_TIMESPEC:
+               if (!put_timespec64(&rts, p))
                        return ret;
-
-       } else if (!put_timespec64(&rts, p))
-               return ret;
-
+               break;
+       case PT_OLD_TIMESPEC:
+               if (!put_old_timespec32(&rts, p))
+                       return ret;
+               break;
+       default:
+               BUG();
+       }
        /*
         * If an application puts its timeval in read-only memory, we
         * don't want the Linux-specific update to the timeval to
@@ -689,7 +717,7 @@ static int kern_select(int n, fd_set __user *inp, fd_set __user *outp,
        }
 
        ret = core_sys_select(n, inp, outp, exp, to);
-       ret = poll_select_copy_remaining(&end_time, tvp, 1, ret);
+       ret = poll_select_copy_remaining(&end_time, tvp, PT_TIMEVAL, ret);
 
        return ret;
 }
@@ -701,49 +729,41 @@ SYSCALL_DEFINE5(select, int, n, fd_set __user *, inp, fd_set __user *, outp,
 }
 
 static long do_pselect(int n, fd_set __user *inp, fd_set __user *outp,
-                      fd_set __user *exp, struct timespec __user *tsp,
-                      const sigset_t __user *sigmask, size_t sigsetsize)
+                      fd_set __user *exp, void __user *tsp,
+                      const sigset_t __user *sigmask, size_t sigsetsize,
+                      enum poll_time_type type)
 {
        sigset_t ksigmask, sigsaved;
        struct timespec64 ts, end_time, *to = NULL;
        int ret;
 
        if (tsp) {
-               if (get_timespec64(&ts, tsp))
-                       return -EFAULT;
+               switch (type) {
+               case PT_TIMESPEC:
+                       if (get_timespec64(&ts, tsp))
+                               return -EFAULT;
+                       break;
+               case PT_OLD_TIMESPEC:
+                       if (get_old_timespec32(&ts, tsp))
+                               return -EFAULT;
+                       break;
+               default:
+                       BUG();
+               }
 
                to = &end_time;
                if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec))
                        return -EINVAL;
        }
 
-       if (sigmask) {
-               /* XXX: Don't preclude handling different sized sigset_t's.  */
-               if (sigsetsize != sizeof(sigset_t))
-                       return -EINVAL;
-               if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask)))
-                       return -EFAULT;
-
-               sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP));
-               sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
-       }
+       ret = set_user_sigmask(sigmask, &ksigmask, &sigsaved, sigsetsize);
+       if (ret)
+               return ret;
 
        ret = core_sys_select(n, inp, outp, exp, to);
-       ret = poll_select_copy_remaining(&end_time, tsp, 0, ret);
+       ret = poll_select_copy_remaining(&end_time, tsp, type, ret);
 
-       if (ret == -ERESTARTNOHAND) {
-               /*
-                * Don't restore the signal mask yet. Let do_signal() deliver
-                * the signal on the way back to userspace, before the signal
-                * mask is restored.
-                */
-               if (sigmask) {
-                       memcpy(&current->saved_sigmask, &sigsaved,
-                                       sizeof(sigsaved));
-                       set_restore_sigmask();
-               }
-       } else if (sigmask)
-               sigprocmask(SIG_SETMASK, &sigsaved, NULL);
+       restore_user_sigmask(sigmask, &sigsaved);
 
        return ret;
 }
@@ -755,7 +775,7 @@ static long do_pselect(int n, fd_set __user *inp, fd_set __user *outp,
  * the sigset size.
  */
 SYSCALL_DEFINE6(pselect6, int, n, fd_set __user *, inp, fd_set __user *, outp,
-               fd_set __user *, exp, struct timespec __user *, tsp,
+               fd_set __user *, exp, struct __kernel_timespec __user *, tsp,
                void __user *, sig)
 {
        size_t sigsetsize = 0;
@@ -769,9 +789,31 @@ SYSCALL_DEFINE6(pselect6, int, n, fd_set __user *, inp, fd_set __user *, outp,
                        return -EFAULT;
        }
 
-       return do_pselect(n, inp, outp, exp, tsp, up, sigsetsize);
+       return do_pselect(n, inp, outp, exp, tsp, up, sigsetsize, PT_TIMESPEC);
 }
 
+#if defined(CONFIG_COMPAT_32BIT_TIME) && !defined(CONFIG_64BIT)
+
+SYSCALL_DEFINE6(pselect6_time32, int, n, fd_set __user *, inp, fd_set __user *, outp,
+               fd_set __user *, exp, struct old_timespec32 __user *, tsp,
+               void __user *, sig)
+{
+       size_t sigsetsize = 0;
+       sigset_t __user *up = NULL;
+
+       if (sig) {
+               if (!access_ok(VERIFY_READ, sig, sizeof(void *)+sizeof(size_t))
+                   || __get_user(up, (sigset_t __user * __user *)sig)
+                   || __get_user(sigsetsize,
+                               (size_t __user *)(sig+sizeof(void *))))
+                       return -EFAULT;
+       }
+
+       return do_pselect(n, inp, outp, exp, tsp, up, sigsetsize, PT_OLD_TIMESPEC);
+}
+
+#endif
+
 #ifdef __ARCH_WANT_SYS_OLD_SELECT
 struct sel_arg_struct {
        unsigned long n;
@@ -1045,7 +1087,7 @@ SYSCALL_DEFINE3(poll, struct pollfd __user *, ufds, unsigned int, nfds,
 }
 
 SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds, unsigned int, nfds,
-               struct timespec __user *, tsp, const sigset_t __user *, sigmask,
+               struct __kernel_timespec __user *, tsp, const sigset_t __user *, sigmask,
                size_t, sigsetsize)
 {
        sigset_t ksigmask, sigsaved;
@@ -1061,89 +1103,62 @@ SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds, unsigned int, nfds,
                        return -EINVAL;
        }
 
-       if (sigmask) {
-               /* XXX: Don't preclude handling different sized sigset_t's.  */
-               if (sigsetsize != sizeof(sigset_t))
-                       return -EINVAL;
-               if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask)))
-                       return -EFAULT;
-
-               sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP));
-               sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
-       }
+       ret = set_user_sigmask(sigmask, &ksigmask, &sigsaved, sigsetsize);
+       if (ret)
+               return ret;
 
        ret = do_sys_poll(ufds, nfds, to);
 
+       restore_user_sigmask(sigmask, &sigsaved);
+
        /* We can restart this syscall, usually */
-       if (ret == -EINTR) {
-               /*
-                * Don't restore the signal mask yet. Let do_signal() deliver
-                * the signal on the way back to userspace, before the signal
-                * mask is restored.
-                */
-               if (sigmask) {
-                       memcpy(&current->saved_sigmask, &sigsaved,
-                                       sizeof(sigsaved));
-                       set_restore_sigmask();
-               }
+       if (ret == -EINTR)
                ret = -ERESTARTNOHAND;
-       } else if (sigmask)
-               sigprocmask(SIG_SETMASK, &sigsaved, NULL);
 
-       ret = poll_select_copy_remaining(&end_time, tsp, 0, ret);
+       ret = poll_select_copy_remaining(&end_time, tsp, PT_TIMESPEC, ret);
 
        return ret;
 }
 
-#ifdef CONFIG_COMPAT
-#define __COMPAT_NFDBITS       (8 * sizeof(compat_ulong_t))
+#if defined(CONFIG_COMPAT_32BIT_TIME) && !defined(CONFIG_64BIT)
 
-static
-int compat_poll_select_copy_remaining(struct timespec64 *end_time, void __user *p,
-                                     int timeval, int ret)
+SYSCALL_DEFINE5(ppoll_time32, struct pollfd __user *, ufds, unsigned int, nfds,
+               struct old_timespec32 __user *, tsp, const sigset_t __user *, sigmask,
+               size_t, sigsetsize)
 {
-       struct timespec64 ts;
+       sigset_t ksigmask, sigsaved;
+       struct timespec64 ts, end_time, *to = NULL;
+       int ret;
 
-       if (!p)
-               return ret;
+       if (tsp) {
+               if (get_old_timespec32(&ts, tsp))
+                       return -EFAULT;
 
-       if (current->personality & STICKY_TIMEOUTS)
-               goto sticky;
+               to = &end_time;
+               if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec))
+                       return -EINVAL;
+       }
 
-       /* No update for zero timeout */
-       if (!end_time->tv_sec && !end_time->tv_nsec)
+       ret = set_user_sigmask(sigmask, &ksigmask, &sigsaved, sigsetsize);
+       if (ret)
                return ret;
 
-       ktime_get_ts64(&ts);
-       ts = timespec64_sub(*end_time, ts);
-       if (ts.tv_sec < 0)
-               ts.tv_sec = ts.tv_nsec = 0;
+       ret = do_sys_poll(ufds, nfds, to);
 
-       if (timeval) {
-               struct old_timeval32 rtv;
+       restore_user_sigmask(sigmask, &sigsaved);
 
-               rtv.tv_sec = ts.tv_sec;
-               rtv.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
+       /* We can restart this syscall, usually */
+       if (ret == -EINTR)
+               ret = -ERESTARTNOHAND;
 
-               if (!copy_to_user(p, &rtv, sizeof(rtv)))
-                       return ret;
-       } else {
-               if (!put_old_timespec32(&ts, p))
-                       return ret;
-       }
-       /*
-        * If an application puts its timeval in read-only memory, we
-        * don't want the Linux-specific update to the timeval to
-        * cause a fault after the select has completed
-        * successfully. However, because we're not updating the
-        * timeval, we can't restart the system call.
-        */
+       ret = poll_select_copy_remaining(&end_time, tsp, PT_OLD_TIMESPEC, ret);
 
-sticky:
-       if (ret == -ERESTARTNOHAND)
-               ret = -EINTR;
        return ret;
 }
+#endif
+
+#ifdef CONFIG_COMPAT
+#define __COMPAT_NFDBITS       (8 * sizeof(compat_ulong_t))
 
 /*
  * Ooo, nasty.  We need here to frob 32-bit unsigned longs to
@@ -1275,7 +1290,7 @@ static int do_compat_select(int n, compat_ulong_t __user *inp,
        }
 
        ret = compat_core_sys_select(n, inp, outp, exp, to);
-       ret = compat_poll_select_copy_remaining(&end_time, tvp, 1, ret);
+       ret = poll_select_copy_remaining(&end_time, tvp, PT_OLD_TIMEVAL, ret);
 
        return ret;
 }
@@ -1307,52 +1322,66 @@ COMPAT_SYSCALL_DEFINE1(old_select, struct compat_sel_arg_struct __user *, arg)
 
 static long do_compat_pselect(int n, compat_ulong_t __user *inp,
        compat_ulong_t __user *outp, compat_ulong_t __user *exp,
-       struct old_timespec32 __user *tsp, compat_sigset_t __user *sigmask,
-       compat_size_t sigsetsize)
+       void __user *tsp, compat_sigset_t __user *sigmask,
+       compat_size_t sigsetsize, enum poll_time_type type)
 {
        sigset_t ksigmask, sigsaved;
        struct timespec64 ts, end_time, *to = NULL;
        int ret;
 
        if (tsp) {
-               if (get_old_timespec32(&ts, tsp))
-                       return -EFAULT;
+               switch (type) {
+               case PT_OLD_TIMESPEC:
+                       if (get_old_timespec32(&ts, tsp))
+                               return -EFAULT;
+                       break;
+               case PT_TIMESPEC:
+                       if (get_timespec64(&ts, tsp))
+                               return -EFAULT;
+                       break;
+               default:
+                       BUG();
+               }
 
                to = &end_time;
                if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec))
                        return -EINVAL;
        }
 
-       if (sigmask) {
-               if (sigsetsize != sizeof(compat_sigset_t))
-                       return -EINVAL;
-               if (get_compat_sigset(&ksigmask, sigmask))
-                       return -EFAULT;
-
-               sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP));
-               sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
-       }
+       ret = set_compat_user_sigmask(sigmask, &ksigmask, &sigsaved, sigsetsize);
+       if (ret)
+               return ret;
 
        ret = compat_core_sys_select(n, inp, outp, exp, to);
-       ret = compat_poll_select_copy_remaining(&end_time, tsp, 0, ret);
+       ret = poll_select_copy_remaining(&end_time, tsp, type, ret);
 
-       if (ret == -ERESTARTNOHAND) {
-               /*
-                * Don't restore the signal mask yet. Let do_signal() deliver
-                * the signal on the way back to userspace, before the signal
-                * mask is restored.
-                */
-               if (sigmask) {
-                       memcpy(&current->saved_sigmask, &sigsaved,
-                                       sizeof(sigsaved));
-                       set_restore_sigmask();
-               }
-       } else if (sigmask)
-               sigprocmask(SIG_SETMASK, &sigsaved, NULL);
+       restore_user_sigmask(sigmask, &sigsaved);
 
        return ret;
 }
 
+COMPAT_SYSCALL_DEFINE6(pselect6_time64, int, n, compat_ulong_t __user *, inp,
+       compat_ulong_t __user *, outp, compat_ulong_t __user *, exp,
+       struct __kernel_timespec __user *, tsp, void __user *, sig)
+{
+       compat_size_t sigsetsize = 0;
+       compat_uptr_t up = 0;
+
+       if (sig) {
+               if (!access_ok(VERIFY_READ, sig,
+                               sizeof(compat_uptr_t)+sizeof(compat_size_t)) ||
+                               __get_user(up, (compat_uptr_t __user *)sig) ||
+                               __get_user(sigsetsize,
+                               (compat_size_t __user *)(sig+sizeof(up))))
+                       return -EFAULT;
+       }
+
+       return do_compat_pselect(n, inp, outp, exp, tsp, compat_ptr(up),
+                                sigsetsize, PT_TIMESPEC);
+}
+
+#if defined(CONFIG_COMPAT_32BIT_TIME)
+
 COMPAT_SYSCALL_DEFINE6(pselect6, int, n, compat_ulong_t __user *, inp,
        compat_ulong_t __user *, outp, compat_ulong_t __user *, exp,
        struct old_timespec32 __user *, tsp, void __user *, sig)
@@ -1368,10 +1397,14 @@ COMPAT_SYSCALL_DEFINE6(pselect6, int, n, compat_ulong_t __user *, inp,
                                (compat_size_t __user *)(sig+sizeof(up))))
                        return -EFAULT;
        }
+
        return do_compat_pselect(n, inp, outp, exp, tsp, compat_ptr(up),
-                                sigsetsize);
+                                sigsetsize, PT_OLD_TIMESPEC);
 }
 
+#endif
+
+#if defined(CONFIG_COMPAT_32BIT_TIME)
 COMPAT_SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds,
        unsigned int,  nfds, struct old_timespec32 __user *, tsp,
        const compat_sigset_t __user *, sigmask, compat_size_t, sigsetsize)
@@ -1389,36 +1422,57 @@ COMPAT_SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds,
                        return -EINVAL;
        }
 
-       if (sigmask) {
-               if (sigsetsize != sizeof(compat_sigset_t))
-                       return -EINVAL;
-               if (get_compat_sigset(&ksigmask, sigmask))
+       ret = set_compat_user_sigmask(sigmask, &ksigmask, &sigsaved, sigsetsize);
+       if (ret)
+               return ret;
+
+       ret = do_sys_poll(ufds, nfds, to);
+
+       restore_user_sigmask(sigmask, &sigsaved);
+
+       /* We can restart this syscall, usually */
+       if (ret == -EINTR)
+               ret = -ERESTARTNOHAND;
+
+       ret = poll_select_copy_remaining(&end_time, tsp, PT_OLD_TIMESPEC, ret);
+
+       return ret;
+}
+#endif
+
+/* New compat syscall for 64 bit time_t*/
+COMPAT_SYSCALL_DEFINE5(ppoll_time64, struct pollfd __user *, ufds,
+       unsigned int,  nfds, struct __kernel_timespec __user *, tsp,
+       const compat_sigset_t __user *, sigmask, compat_size_t, sigsetsize)
+{
+       sigset_t ksigmask, sigsaved;
+       struct timespec64 ts, end_time, *to = NULL;
+       int ret;
+
+       if (tsp) {
+               if (get_timespec64(&ts, tsp))
                        return -EFAULT;
 
-               sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP));
-               sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
+               to = &end_time;
+               if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec))
+                       return -EINVAL;
        }
 
+       ret = set_compat_user_sigmask(sigmask, &ksigmask, &sigsaved, sigsetsize);
+       if (ret)
+               return ret;
+
        ret = do_sys_poll(ufds, nfds, to);
 
+       restore_user_sigmask(sigmask, &sigsaved);
+
        /* We can restart this syscall, usually */
-       if (ret == -EINTR) {
-               /*
-                * Don't restore the signal mask yet. Let do_signal() deliver
-                * the signal on the way back to userspace, before the signal
-                * mask is restored.
-                */
-               if (sigmask) {
-                       memcpy(&current->saved_sigmask, &sigsaved,
-                               sizeof(sigsaved));
-                       set_restore_sigmask();
-               }
+       if (ret == -EINTR)
                ret = -ERESTARTNOHAND;
-       } else if (sigmask)
-               sigprocmask(SIG_SETMASK, &sigsaved, NULL);
 
-       ret = compat_poll_select_copy_remaining(&end_time, tsp, 0, ret);
+       ret = poll_select_copy_remaining(&end_time, tsp, PT_TIMESPEC, ret);
 
        return ret;
 }
+
 #endif
index 88720b443cd646f588fa183d60a0f5c549fc030e..056be0d037225865618b077a163d65c20c08ed0a 100644 (file)
@@ -169,6 +169,10 @@ typedef struct {
        compat_sigset_word      sig[_COMPAT_NSIG_WORDS];
 } compat_sigset_t;
 
+int set_compat_user_sigmask(const compat_sigset_t __user *usigmask,
+                           sigset_t *set, sigset_t *oldset,
+                           size_t sigsetsize);
+
 struct compat_sigaction {
 #ifndef __ARCH_HAS_IRIX_SIGACTION
        compat_uptr_t                   sa_handler;
@@ -558,6 +562,12 @@ asmlinkage long compat_sys_io_pgetevents(compat_aio_context_t ctx_id,
                                        struct io_event __user *events,
                                        struct old_timespec32 __user *timeout,
                                        const struct __compat_aio_sigset __user *usig);
+asmlinkage long compat_sys_io_pgetevents_time64(compat_aio_context_t ctx_id,
+                                       compat_long_t min_nr,
+                                       compat_long_t nr,
+                                       struct io_event __user *events,
+                                       struct __kernel_timespec __user *timeout,
+                                       const struct __compat_aio_sigset __user *usig);
 
 /* fs/cookies.c */
 asmlinkage long compat_sys_lookup_dcookie(u32, u32, char __user *, compat_size_t);
@@ -643,11 +653,21 @@ asmlinkage long compat_sys_pselect6(int n, compat_ulong_t __user *inp,
                                    compat_ulong_t __user *exp,
                                    struct old_timespec32 __user *tsp,
                                    void __user *sig);
+asmlinkage long compat_sys_pselect6_time64(int n, compat_ulong_t __user *inp,
+                                   compat_ulong_t __user *outp,
+                                   compat_ulong_t __user *exp,
+                                   struct __kernel_timespec __user *tsp,
+                                   void __user *sig);
 asmlinkage long compat_sys_ppoll(struct pollfd __user *ufds,
                                 unsigned int nfds,
                                 struct old_timespec32 __user *tsp,
                                 const compat_sigset_t __user *sigmask,
                                 compat_size_t sigsetsize);
+asmlinkage long compat_sys_ppoll_time64(struct pollfd __user *ufds,
+                                unsigned int nfds,
+                                struct __kernel_timespec __user *tsp,
+                                const compat_sigset_t __user *sigmask,
+                                compat_size_t sigsetsize);
 
 /* fs/signalfd.c */
 asmlinkage long compat_sys_signalfd4(int ufd,
@@ -768,6 +788,9 @@ asmlinkage long compat_sys_rt_sigpending(compat_sigset_t __user *uset,
 asmlinkage long compat_sys_rt_sigtimedwait(compat_sigset_t __user *uthese,
                struct compat_siginfo __user *uinfo,
                struct old_timespec32 __user *uts, compat_size_t sigsetsize);
+asmlinkage long compat_sys_rt_sigtimedwait_time64(compat_sigset_t __user *uthese,
+               struct compat_siginfo __user *uinfo,
+               struct __kernel_timespec __user *uts, compat_size_t sigsetsize);
 asmlinkage long compat_sys_rt_sigqueueinfo(compat_pid_t pid, int sig,
                                struct compat_siginfo __user *uinfo);
 /* No generic prototype for rt_sigreturn */
@@ -873,6 +896,9 @@ asmlinkage long compat_sys_move_pages(pid_t pid, compat_ulong_t nr_pages,
 asmlinkage long compat_sys_rt_tgsigqueueinfo(compat_pid_t tgid,
                                        compat_pid_t pid, int sig,
                                        struct compat_siginfo __user *uinfo);
+asmlinkage long compat_sys_recvmmsg_time64(int fd, struct compat_mmsghdr __user *mmsg,
+                                   unsigned vlen, unsigned int flags,
+                                   struct __kernel_timespec __user *timeout);
 asmlinkage long compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg,
                                    unsigned vlen, unsigned int flags,
                                    struct old_timespec32 __user *timeout);
index 821ae502d3d89b8c5bc69d45b8f02120ebe41887..ccaef0097785b84545d95ef8543406ee3ff01231 100644 (file)
@@ -9,9 +9,6 @@ struct inode;
 struct mm_struct;
 struct task_struct;
 
-extern int
-handle_futex_death(u32 __user *uaddr, struct task_struct *curr, int pi);
-
 /*
  * Futexes are matched on equal values of this key.
  * The key type depends on whether it's a shared or private mapping.
@@ -55,11 +52,6 @@ extern void exit_robust_list(struct task_struct *curr);
 
 long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
              u32 __user *uaddr2, u32 val2, u32 val3);
-#ifdef CONFIG_HAVE_FUTEX_CMPXCHG
-#define futex_cmpxchg_enabled 1
-#else
-extern int futex_cmpxchg_enabled;
-#endif
 #else
 static inline void exit_robust_list(struct task_struct *curr)
 {
index f428e86f480075fe0c2a8a71938616fdd6ee8dcc..cc7e2c1cd44465926c3626a014dbd051319c2a64 100644 (file)
@@ -273,6 +273,10 @@ extern int group_send_sig_info(int sig, struct kernel_siginfo *info,
                               struct task_struct *p, enum pid_type type);
 extern int __group_send_sig_info(int, struct kernel_siginfo *, struct task_struct *);
 extern int sigprocmask(int, sigset_t *, sigset_t *);
+extern int set_user_sigmask(const sigset_t __user *usigmask, sigset_t *set,
+       sigset_t *oldset, size_t sigsetsize);
+extern void restore_user_sigmask(const void __user *usigmask,
+                                sigset_t *sigsaved);
 extern void set_current_blocked(sigset_t *);
 extern void __set_current_blocked(const sigset_t *);
 extern int show_unhandled_signals;
index 84c48a3c0227c2a5383146363c34d773aa3b2dd7..ab2041a00e014c87f2bf9b88d93ee65b09464805 100644 (file)
@@ -349,7 +349,8 @@ struct ucred {
 extern int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr_storage *kaddr);
 extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data);
 
-struct timespec64;
+struct __kernel_timespec;
+struct old_timespec32;
 
 /* The __sys_...msg variants allow MSG_CMSG_COMPAT iff
  * forbid_cmsg_compat==false
@@ -358,8 +359,10 @@ extern long __sys_recvmsg(int fd, struct user_msghdr __user *msg,
                          unsigned int flags, bool forbid_cmsg_compat);
 extern long __sys_sendmsg(int fd, struct user_msghdr __user *msg,
                          unsigned int flags, bool forbid_cmsg_compat);
-extern int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
-                         unsigned int flags, struct timespec64 *timeout);
+extern int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg,
+                         unsigned int vlen, unsigned int flags,
+                         struct __kernel_timespec __user *timeout,
+                         struct old_timespec32 __user *timeout32);
 extern int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg,
                          unsigned int vlen, unsigned int flags,
                          bool forbid_cmsg_compat);
index 2ac3d13a915bfc3954b08c3fac23e8d3351f4827..251979d2e70919ca7bc80e7204617e70201213ef 100644 (file)
@@ -296,12 +296,18 @@ asmlinkage long sys_io_getevents(aio_context_t ctx_id,
                                long min_nr,
                                long nr,
                                struct io_event __user *events,
-                               struct timespec __user *timeout);
+                               struct __kernel_timespec __user *timeout);
 asmlinkage long sys_io_pgetevents(aio_context_t ctx_id,
                                long min_nr,
                                long nr,
                                struct io_event __user *events,
-                               struct timespec __user *timeout,
+                               struct __kernel_timespec __user *timeout,
+                               const struct __aio_sigset *sig);
+asmlinkage long sys_io_pgetevents_time32(aio_context_t ctx_id,
+                               long min_nr,
+                               long nr,
+                               struct io_event __user *events,
+                               struct old_timespec32 __user *timeout,
                                const struct __aio_sigset *sig);
 
 /* fs/xattr.c */
@@ -466,10 +472,16 @@ asmlinkage long sys_sendfile64(int out_fd, int in_fd,
 
 /* fs/select.c */
 asmlinkage long sys_pselect6(int, fd_set __user *, fd_set __user *,
-                            fd_set __user *, struct timespec __user *,
+                            fd_set __user *, struct __kernel_timespec __user *,
+                            void __user *);
+asmlinkage long sys_pselect6_time32(int, fd_set __user *, fd_set __user *,
+                            fd_set __user *, struct old_timespec32 __user *,
                             void __user *);
 asmlinkage long sys_ppoll(struct pollfd __user *, unsigned int,
-                         struct timespec __user *, const sigset_t __user *,
+                         struct __kernel_timespec __user *, const sigset_t __user *,
+                         size_t);
+asmlinkage long sys_ppoll_time32(struct pollfd __user *, unsigned int,
+                         struct old_timespec32 __user *, const sigset_t __user *,
                          size_t);
 
 /* fs/signalfd.c */
@@ -541,7 +553,7 @@ asmlinkage long sys_unshare(unsigned long unshare_flags);
 
 /* kernel/futex.c */
 asmlinkage long sys_futex(u32 __user *uaddr, int op, u32 val,
-                       struct timespec __user *utime, u32 __user *uaddr2,
+                       struct __kernel_timespec __user *utime, u32 __user *uaddr2,
                        u32 val3);
 asmlinkage long sys_get_robust_list(int pid,
                                    struct robust_list_head __user * __user *head_ptr,
@@ -637,6 +649,10 @@ asmlinkage long sys_rt_sigtimedwait(const sigset_t __user *uthese,
                                siginfo_t __user *uinfo,
                                const struct __kernel_timespec __user *uts,
                                size_t sigsetsize);
+asmlinkage long sys_rt_sigtimedwait_time32(const sigset_t __user *uthese,
+                               siginfo_t __user *uinfo,
+                               const struct old_timespec32 __user *uts,
+                               size_t sigsetsize);
 asmlinkage long sys_rt_sigqueueinfo(pid_t pid, int sig, siginfo_t __user *uinfo);
 
 /* kernel/sys.c */
@@ -831,6 +847,9 @@ asmlinkage long sys_accept4(int, struct sockaddr __user *, int __user *, int);
 asmlinkage long sys_recvmmsg(int fd, struct mmsghdr __user *msg,
                             unsigned int vlen, unsigned flags,
                             struct __kernel_timespec __user *timeout);
+asmlinkage long sys_recvmmsg_time32(int fd, struct mmsghdr __user *msg,
+                            unsigned int vlen, unsigned flags,
+                            struct old_timespec32 __user *timeout);
 
 asmlinkage long sys_wait4(pid_t pid, int __user *stat_addr,
                                int options, struct rusage __user *ru);
index 61904a6c098f2305bcb512241b68fe2ed7b6b271..118b9977080c3761ca015f66fb28c5d2720436fc 100644 (file)
@@ -96,31 +96,6 @@ static inline int timespec_compare(const struct timespec *lhs, const struct time
        return lhs->tv_nsec - rhs->tv_nsec;
 }
 
-extern void set_normalized_timespec(struct timespec *ts, time_t sec, s64 nsec);
-
-static inline struct timespec timespec_add(struct timespec lhs,
-                                               struct timespec rhs)
-{
-       struct timespec ts_delta;
-
-       set_normalized_timespec(&ts_delta, lhs.tv_sec + rhs.tv_sec,
-                               lhs.tv_nsec + rhs.tv_nsec);
-       return ts_delta;
-}
-
-/*
- * sub = lhs - rhs, in normalized form
- */
-static inline struct timespec timespec_sub(struct timespec lhs,
-                                               struct timespec rhs)
-{
-       struct timespec ts_delta;
-
-       set_normalized_timespec(&ts_delta, lhs.tv_sec - rhs.tv_sec,
-                               lhs.tv_nsec - rhs.tv_nsec);
-       return ts_delta;
-}
-
 /*
  * Returns true if the timespec is norm, false if denorm:
  */
index 29975e93fcb8e4f51692826c9f535787dc49ed46..a8ab0f143ac45df8009693e476d62d2be38d247e 100644 (file)
@@ -262,18 +262,4 @@ void read_persistent_wall_and_boot_offset(struct timespec64 *wall_clock,
                                          struct timespec64 *boot_offset);
 extern int update_persistent_clock64(struct timespec64 now);
 
-/*
- * deprecated aliases, don't use in new code
- */
-#define getnstimeofday64(ts)           ktime_get_real_ts64(ts)
-
-static inline struct timespec64 current_kernel_time64(void)
-{
-       struct timespec64 ts;
-
-       ktime_get_coarse_real_ts64(&ts);
-
-       return ts;
-}
-
 #endif
index a502616f7e1c517e057682a45b80dad433c36a29..cc59cc9e0e841dc8980882837afb03a5ae10a51e 100644 (file)
@@ -6,15 +6,6 @@
  * over time so we can remove the file here.
  */
 
-static inline void do_gettimeofday(struct timeval *tv)
-{
-       struct timespec64 now;
-
-       ktime_get_real_ts64(&now);
-       tv->tv_sec = now.tv_sec;
-       tv->tv_usec = now.tv_nsec/1000;
-}
-
 static inline unsigned long get_seconds(void)
 {
        return ktime_get_real_seconds();
@@ -52,10 +43,4 @@ static inline void getboottime(struct timespec *ts)
        *ts = timespec64_to_timespec(ts64);
 }
 
-/*
- * Persistent clock related interfaces
- */
-extern void read_persistent_clock(struct timespec *ts);
-extern int update_persistent_clock(struct timespec now);
-
 #endif
index 9dc7f519129d8e505b1e58ac63d628681ef8d861..cde93d54c5711806764a6935994cb1fc9ca4b7fb 100644 (file)
@@ -49,9 +49,6 @@ obj-$(CONFIG_PROFILING) += profile.o
 obj-$(CONFIG_STACKTRACE) += stacktrace.o
 obj-y += time/
 obj-$(CONFIG_FUTEX) += futex.o
-ifeq ($(CONFIG_COMPAT),y)
-obj-$(CONFIG_FUTEX) += futex_compat.o
-endif
 obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
 obj-$(CONFIG_SMP) += smp.o
 ifneq ($(CONFIG_SMP),y)
index 5cc8083a4c890976c93d5ff5bc45357349f13f25..054105854e0e38fbab1fbaee8fc743729526de2c 100644 (file)
@@ -44,6 +44,7 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
+#include <linux/compat.h>
 #include <linux/slab.h>
 #include <linux/poll.h>
 #include <linux/fs.h>
  * double_lock_hb() and double_unlock_hb(), respectively.
  */
 
-#ifndef CONFIG_HAVE_FUTEX_CMPXCHG
-int __read_mostly futex_cmpxchg_enabled;
+#ifdef CONFIG_HAVE_FUTEX_CMPXCHG
+#define futex_cmpxchg_enabled 1
+#else
+static int  __read_mostly futex_cmpxchg_enabled;
 #endif
 
 /*
@@ -3417,7 +3420,7 @@ err_unlock:
  * Process a futex-list entry, check whether it's owned by the
  * dying task, and do notification if so:
  */
-int handle_futex_death(u32 __user *uaddr, struct task_struct *curr, int pi)
+static int handle_futex_death(u32 __user *uaddr, struct task_struct *curr, int pi)
 {
        u32 uval, uninitialized_var(nval), mval;
 
@@ -3612,10 +3615,10 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
 
 
 SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
-               struct timespec __user *, utime, u32 __user *, uaddr2,
+               struct __kernel_timespec __user *, utime, u32 __user *, uaddr2,
                u32, val3)
 {
-       struct timespec ts;
+       struct timespec64 ts;
        ktime_t t, *tp = NULL;
        u32 val2 = 0;
        int cmd = op & FUTEX_CMD_MASK;
@@ -3625,12 +3628,12 @@ SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
                      cmd == FUTEX_WAIT_REQUEUE_PI)) {
                if (unlikely(should_fail_futex(!(op & FUTEX_PRIVATE_FLAG))))
                        return -EFAULT;
-               if (copy_from_user(&ts, utime, sizeof(ts)) != 0)
+               if (get_timespec64(&ts, utime))
                        return -EFAULT;
-               if (!timespec_valid(&ts))
+               if (!timespec64_valid(&ts))
                        return -EINVAL;
 
-               t = timespec_to_ktime(ts);
+               t = timespec64_to_ktime(ts);
                if (cmd == FUTEX_WAIT)
                        t = ktime_add_safe(ktime_get(), t);
                tp = &t;
@@ -3646,6 +3649,194 @@ SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
        return do_futex(uaddr, op, val, tp, uaddr2, val2, val3);
 }
 
+#ifdef CONFIG_COMPAT
+/*
+ * Fetch a robust-list pointer. Bit 0 signals PI futexes:
+ */
+static inline int
+compat_fetch_robust_entry(compat_uptr_t *uentry, struct robust_list __user **entry,
+                  compat_uptr_t __user *head, unsigned int *pi)
+{
+       if (get_user(*uentry, head))
+               return -EFAULT;
+
+       *entry = compat_ptr((*uentry) & ~1);
+       *pi = (unsigned int)(*uentry) & 1;
+
+       return 0;
+}
+
+static void __user *futex_uaddr(struct robust_list __user *entry,
+                               compat_long_t futex_offset)
+{
+       compat_uptr_t base = ptr_to_compat(entry);
+       void __user *uaddr = compat_ptr(base + futex_offset);
+
+       return uaddr;
+}
+
+/*
+ * Walk curr->robust_list (very carefully, it's a userspace list!)
+ * and mark any locks found there dead, and notify any waiters.
+ *
+ * We silently return on any sign of list-walking problem.
+ */
+void compat_exit_robust_list(struct task_struct *curr)
+{
+       struct compat_robust_list_head __user *head = curr->compat_robust_list;
+       struct robust_list __user *entry, *next_entry, *pending;
+       unsigned int limit = ROBUST_LIST_LIMIT, pi, pip;
+       unsigned int uninitialized_var(next_pi);
+       compat_uptr_t uentry, next_uentry, upending;
+       compat_long_t futex_offset;
+       int rc;
+
+       if (!futex_cmpxchg_enabled)
+               return;
+
+       /*
+        * Fetch the list head (which was registered earlier, via
+        * sys_set_robust_list()):
+        */
+       if (compat_fetch_robust_entry(&uentry, &entry, &head->list.next, &pi))
+               return;
+       /*
+        * Fetch the relative futex offset:
+        */
+       if (get_user(futex_offset, &head->futex_offset))
+               return;
+       /*
+        * Fetch any possibly pending lock-add first, and handle it
+        * if it exists:
+        */
+       if (compat_fetch_robust_entry(&upending, &pending,
+                              &head->list_op_pending, &pip))
+               return;
+
+       next_entry = NULL;      /* avoid warning with gcc */
+       while (entry != (struct robust_list __user *) &head->list) {
+               /*
+                * Fetch the next entry in the list before calling
+                * handle_futex_death:
+                */
+               rc = compat_fetch_robust_entry(&next_uentry, &next_entry,
+                       (compat_uptr_t __user *)&entry->next, &next_pi);
+               /*
+                * A pending lock might already be on the list, so
+                * dont process it twice:
+                */
+               if (entry != pending) {
+                       void __user *uaddr = futex_uaddr(entry, futex_offset);
+
+                       if (handle_futex_death(uaddr, curr, pi))
+                               return;
+               }
+               if (rc)
+                       return;
+               uentry = next_uentry;
+               entry = next_entry;
+               pi = next_pi;
+               /*
+                * Avoid excessively long or circular lists:
+                */
+               if (!--limit)
+                       break;
+
+               cond_resched();
+       }
+       if (pending) {
+               void __user *uaddr = futex_uaddr(pending, futex_offset);
+
+               handle_futex_death(uaddr, curr, pip);
+       }
+}
+
+COMPAT_SYSCALL_DEFINE2(set_robust_list,
+               struct compat_robust_list_head __user *, head,
+               compat_size_t, len)
+{
+       if (!futex_cmpxchg_enabled)
+               return -ENOSYS;
+
+       if (unlikely(len != sizeof(*head)))
+               return -EINVAL;
+
+       current->compat_robust_list = head;
+
+       return 0;
+}
+
+COMPAT_SYSCALL_DEFINE3(get_robust_list, int, pid,
+                       compat_uptr_t __user *, head_ptr,
+                       compat_size_t __user *, len_ptr)
+{
+       struct compat_robust_list_head __user *head;
+       unsigned long ret;
+       struct task_struct *p;
+
+       if (!futex_cmpxchg_enabled)
+               return -ENOSYS;
+
+       rcu_read_lock();
+
+       ret = -ESRCH;
+       if (!pid)
+               p = current;
+       else {
+               p = find_task_by_vpid(pid);
+               if (!p)
+                       goto err_unlock;
+       }
+
+       ret = -EPERM;
+       if (!ptrace_may_access(p, PTRACE_MODE_READ_REALCREDS))
+               goto err_unlock;
+
+       head = p->compat_robust_list;
+       rcu_read_unlock();
+
+       if (put_user(sizeof(*head), len_ptr))
+               return -EFAULT;
+       return put_user(ptr_to_compat(head), head_ptr);
+
+err_unlock:
+       rcu_read_unlock();
+
+       return ret;
+}
+#endif /* CONFIG_COMPAT */
+
+#ifdef CONFIG_COMPAT_32BIT_TIME
+COMPAT_SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
+               struct old_timespec32 __user *, utime, u32 __user *, uaddr2,
+               u32, val3)
+{
+       struct timespec64 ts;
+       ktime_t t, *tp = NULL;
+       int val2 = 0;
+       int cmd = op & FUTEX_CMD_MASK;
+
+       if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||
+                     cmd == FUTEX_WAIT_BITSET ||
+                     cmd == FUTEX_WAIT_REQUEUE_PI)) {
+               if (get_old_timespec32(&ts, utime))
+                       return -EFAULT;
+               if (!timespec64_valid(&ts))
+                       return -EINVAL;
+
+               t = timespec64_to_ktime(ts);
+               if (cmd == FUTEX_WAIT)
+                       t = ktime_add_safe(ktime_get(), t);
+               tp = &t;
+       }
+       if (cmd == FUTEX_REQUEUE || cmd == FUTEX_CMP_REQUEUE ||
+           cmd == FUTEX_CMP_REQUEUE_PI || cmd == FUTEX_WAKE_OP)
+               val2 = (int) (unsigned long) utime;
+
+       return do_futex(uaddr, op, val, tp, uaddr2, val2, val3);
+}
+#endif /* CONFIG_COMPAT_32BIT_TIME */
+
 static void __init futex_detect_cmpxchg(void)
 {
 #ifndef CONFIG_HAVE_FUTEX_CMPXCHG
diff --git a/kernel/futex_compat.c b/kernel/futex_compat.c
deleted file mode 100644 (file)
index 410a77a..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * linux/kernel/futex_compat.c
- *
- * Futex compatibililty routines.
- *
- * Copyright 2006, Red Hat, Inc., Ingo Molnar
- */
-
-#include <linux/linkage.h>
-#include <linux/compat.h>
-#include <linux/nsproxy.h>
-#include <linux/futex.h>
-#include <linux/ptrace.h>
-#include <linux/syscalls.h>
-
-#include <linux/uaccess.h>
-
-
-/*
- * Fetch a robust-list pointer. Bit 0 signals PI futexes:
- */
-static inline int
-fetch_robust_entry(compat_uptr_t *uentry, struct robust_list __user **entry,
-                  compat_uptr_t __user *head, unsigned int *pi)
-{
-       if (get_user(*uentry, head))
-               return -EFAULT;
-
-       *entry = compat_ptr((*uentry) & ~1);
-       *pi = (unsigned int)(*uentry) & 1;
-
-       return 0;
-}
-
-static void __user *futex_uaddr(struct robust_list __user *entry,
-                               compat_long_t futex_offset)
-{
-       compat_uptr_t base = ptr_to_compat(entry);
-       void __user *uaddr = compat_ptr(base + futex_offset);
-
-       return uaddr;
-}
-
-/*
- * Walk curr->robust_list (very carefully, it's a userspace list!)
- * and mark any locks found there dead, and notify any waiters.
- *
- * We silently return on any sign of list-walking problem.
- */
-void compat_exit_robust_list(struct task_struct *curr)
-{
-       struct compat_robust_list_head __user *head = curr->compat_robust_list;
-       struct robust_list __user *entry, *next_entry, *pending;
-       unsigned int limit = ROBUST_LIST_LIMIT, pi, pip;
-       unsigned int uninitialized_var(next_pi);
-       compat_uptr_t uentry, next_uentry, upending;
-       compat_long_t futex_offset;
-       int rc;
-
-       if (!futex_cmpxchg_enabled)
-               return;
-
-       /*
-        * Fetch the list head (which was registered earlier, via
-        * sys_set_robust_list()):
-        */
-       if (fetch_robust_entry(&uentry, &entry, &head->list.next, &pi))
-               return;
-       /*
-        * Fetch the relative futex offset:
-        */
-       if (get_user(futex_offset, &head->futex_offset))
-               return;
-       /*
-        * Fetch any possibly pending lock-add first, and handle it
-        * if it exists:
-        */
-       if (fetch_robust_entry(&upending, &pending,
-                              &head->list_op_pending, &pip))
-               return;
-
-       next_entry = NULL;      /* avoid warning with gcc */
-       while (entry != (struct robust_list __user *) &head->list) {
-               /*
-                * Fetch the next entry in the list before calling
-                * handle_futex_death:
-                */
-               rc = fetch_robust_entry(&next_uentry, &next_entry,
-                       (compat_uptr_t __user *)&entry->next, &next_pi);
-               /*
-                * A pending lock might already be on the list, so
-                * dont process it twice:
-                */
-               if (entry != pending) {
-                       void __user *uaddr = futex_uaddr(entry, futex_offset);
-
-                       if (handle_futex_death(uaddr, curr, pi))
-                               return;
-               }
-               if (rc)
-                       return;
-               uentry = next_uentry;
-               entry = next_entry;
-               pi = next_pi;
-               /*
-                * Avoid excessively long or circular lists:
-                */
-               if (!--limit)
-                       break;
-
-               cond_resched();
-       }
-       if (pending) {
-               void __user *uaddr = futex_uaddr(pending, futex_offset);
-
-               handle_futex_death(uaddr, curr, pip);
-       }
-}
-
-COMPAT_SYSCALL_DEFINE2(set_robust_list,
-               struct compat_robust_list_head __user *, head,
-               compat_size_t, len)
-{
-       if (!futex_cmpxchg_enabled)
-               return -ENOSYS;
-
-       if (unlikely(len != sizeof(*head)))
-               return -EINVAL;
-
-       current->compat_robust_list = head;
-
-       return 0;
-}
-
-COMPAT_SYSCALL_DEFINE3(get_robust_list, int, pid,
-                       compat_uptr_t __user *, head_ptr,
-                       compat_size_t __user *, len_ptr)
-{
-       struct compat_robust_list_head __user *head;
-       unsigned long ret;
-       struct task_struct *p;
-
-       if (!futex_cmpxchg_enabled)
-               return -ENOSYS;
-
-       rcu_read_lock();
-
-       ret = -ESRCH;
-       if (!pid)
-               p = current;
-       else {
-               p = find_task_by_vpid(pid);
-               if (!p)
-                       goto err_unlock;
-       }
-
-       ret = -EPERM;
-       if (!ptrace_may_access(p, PTRACE_MODE_READ_REALCREDS))
-               goto err_unlock;
-
-       head = p->compat_robust_list;
-       rcu_read_unlock();
-
-       if (put_user(sizeof(*head), len_ptr))
-               return -EFAULT;
-       return put_user(ptr_to_compat(head), head_ptr);
-
-err_unlock:
-       rcu_read_unlock();
-
-       return ret;
-}
-
-COMPAT_SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
-               struct old_timespec32 __user *, utime, u32 __user *, uaddr2,
-               u32, val3)
-{
-       struct timespec ts;
-       ktime_t t, *tp = NULL;
-       int val2 = 0;
-       int cmd = op & FUTEX_CMD_MASK;
-
-       if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||
-                     cmd == FUTEX_WAIT_BITSET ||
-                     cmd == FUTEX_WAIT_REQUEUE_PI)) {
-               if (compat_get_timespec(&ts, utime))
-                       return -EFAULT;
-               if (!timespec_valid(&ts))
-                       return -EINVAL;
-
-               t = timespec_to_ktime(ts);
-               if (cmd == FUTEX_WAIT)
-                       t = ktime_add_safe(ktime_get(), t);
-               tp = &t;
-       }
-       if (cmd == FUTEX_REQUEUE || cmd == FUTEX_CMP_REQUEUE ||
-           cmd == FUTEX_CMP_REQUEUE_PI || cmd == FUTEX_WAKE_OP)
-               val2 = (int) (unsigned long) utime;
-
-       return do_futex(uaddr, op, val, tp, uaddr2, val2, val3);
-}
index 9a32bc2088c90c709cc2acc336f0ac3d68342931..53e07d97ffe018f391fa7976573dc0e0c93c40cb 100644 (file)
@@ -2735,6 +2735,84 @@ int sigprocmask(int how, sigset_t *set, sigset_t *oldset)
 }
 EXPORT_SYMBOL(sigprocmask);
 
+/*
+ * The api helps set app-provided sigmasks.
+ *
+ * This is useful for syscalls such as ppoll, pselect, io_pgetevents and
+ * epoll_pwait where a new sigmask is passed from userland for the syscalls.
+ */
+int set_user_sigmask(const sigset_t __user *usigmask, sigset_t *set,
+                    sigset_t *oldset, size_t sigsetsize)
+{
+       if (!usigmask)
+               return 0;
+
+       if (sigsetsize != sizeof(sigset_t))
+               return -EINVAL;
+       if (copy_from_user(set, usigmask, sizeof(sigset_t)))
+               return -EFAULT;
+
+       *oldset = current->blocked;
+       set_current_blocked(set);
+
+       return 0;
+}
+EXPORT_SYMBOL(set_user_sigmask);
+
+#ifdef CONFIG_COMPAT
+int set_compat_user_sigmask(const compat_sigset_t __user *usigmask,
+                           sigset_t *set, sigset_t *oldset,
+                           size_t sigsetsize)
+{
+       if (!usigmask)
+               return 0;
+
+       if (sigsetsize != sizeof(compat_sigset_t))
+               return -EINVAL;
+       if (get_compat_sigset(set, usigmask))
+               return -EFAULT;
+
+       *oldset = current->blocked;
+       set_current_blocked(set);
+
+       return 0;
+}
+EXPORT_SYMBOL(set_compat_user_sigmask);
+#endif
+
+/*
+ * restore_user_sigmask:
+ * usigmask: sigmask passed in from userland.
+ * sigsaved: saved sigmask when the syscall started and changed the sigmask to
+ *           usigmask.
+ *
+ * This is useful for syscalls such as ppoll, pselect, io_pgetevents and
+ * epoll_pwait where a new sigmask is passed in from userland for the syscalls.
+ */
+void restore_user_sigmask(const void __user *usigmask, sigset_t *sigsaved)
+{
+
+       if (!usigmask)
+               return;
+       /*
+        * When signals are pending, do not restore them here.
+        * Restoring sigmask here can lead to delivering signals that the above
+        * syscalls are intended to block because of the sigmask passed in.
+        */
+       if (signal_pending(current)) {
+               current->saved_sigmask = *sigsaved;
+               set_restore_sigmask();
+               return;
+       }
+
+       /*
+        * This is needed because the fast syscall return path does not restore
+        * saved_sigmask when signals are not pending.
+        */
+       set_current_blocked(sigsaved);
+}
+EXPORT_SYMBOL(restore_user_sigmask);
+
 /**
  *  sys_rt_sigprocmask - change the list of currently blocked signals
  *  @how: whether to add, remove, or set signals
@@ -3254,7 +3332,71 @@ SYSCALL_DEFINE4(rt_sigtimedwait, const sigset_t __user *, uthese,
        return ret;
 }
 
+#ifdef CONFIG_COMPAT_32BIT_TIME
+SYSCALL_DEFINE4(rt_sigtimedwait_time32, const sigset_t __user *, uthese,
+               siginfo_t __user *, uinfo,
+               const struct old_timespec32 __user *, uts,
+               size_t, sigsetsize)
+{
+       sigset_t these;
+       struct timespec64 ts;
+       kernel_siginfo_t info;
+       int ret;
+
+       if (sigsetsize != sizeof(sigset_t))
+               return -EINVAL;
+
+       if (copy_from_user(&these, uthese, sizeof(these)))
+               return -EFAULT;
+
+       if (uts) {
+               if (get_old_timespec32(&ts, uts))
+                       return -EFAULT;
+       }
+
+       ret = do_sigtimedwait(&these, &info, uts ? &ts : NULL);
+
+       if (ret > 0 && uinfo) {
+               if (copy_siginfo_to_user(uinfo, &info))
+                       ret = -EFAULT;
+       }
+
+       return ret;
+}
+#endif
+
 #ifdef CONFIG_COMPAT
+COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait_time64, compat_sigset_t __user *, uthese,
+               struct compat_siginfo __user *, uinfo,
+               struct __kernel_timespec __user *, uts, compat_size_t, sigsetsize)
+{
+       sigset_t s;
+       struct timespec64 t;
+       kernel_siginfo_t info;
+       long ret;
+
+       if (sigsetsize != sizeof(sigset_t))
+               return -EINVAL;
+
+       if (get_compat_sigset(&s, uthese))
+               return -EFAULT;
+
+       if (uts) {
+               if (get_timespec64(&t, uts))
+                       return -EFAULT;
+       }
+
+       ret = do_sigtimedwait(&s, &info, uts ? &t : NULL);
+
+       if (ret > 0 && uinfo) {
+               if (copy_siginfo_to_user32(uinfo, &info))
+                       ret = -EFAULT;
+       }
+
+       return ret;
+}
+
+#ifdef CONFIG_COMPAT_32BIT_TIME
 COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait, compat_sigset_t __user *, uthese,
                struct compat_siginfo __user *, uinfo,
                struct old_timespec32 __user *, uts, compat_size_t, sigsetsize)
@@ -3285,6 +3427,7 @@ COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait, compat_sigset_t __user *, uthese,
        return ret;
 }
 #endif
+#endif
 
 /**
  *  sys_kill - send a signal to a process
index df556175be506902ae501f9bd2b0ddd01483c34c..ab9d0e3c6d5072b624a37279b28eb6c440ebfb48 100644 (file)
@@ -284,7 +284,9 @@ COND_SYSCALL_COMPAT(move_pages);
 COND_SYSCALL(perf_event_open);
 COND_SYSCALL(accept4);
 COND_SYSCALL(recvmmsg);
+COND_SYSCALL(recvmmsg_time32);
 COND_SYSCALL_COMPAT(recvmmsg);
+COND_SYSCALL_COMPAT(recvmmsg_time64);
 
 /*
  * Architecture specific syscalls: see further below
index bc3a3c37ec9ce11b8e649c01f3d3ed5bb01badc3..36a2bef001253c558a7894002f56dfeb5d6d1ace 100644 (file)
@@ -554,17 +554,9 @@ static void sync_rtc_clock(void)
 }
 
 #ifdef CONFIG_GENERIC_CMOS_UPDATE
-int __weak update_persistent_clock(struct timespec now)
-{
-       return -ENODEV;
-}
-
 int __weak update_persistent_clock64(struct timespec64 now64)
 {
-       struct timespec now;
-
-       now = timespec64_to_timespec(now64);
-       return update_persistent_clock(now);
+       return -ENODEV;
 }
 #endif
 
index 5aa0a156e3311ce708f82d54baf59d6edff38189..2edb5088a70b60feaa107eb8725d460d3724bac8 100644 (file)
@@ -383,42 +383,6 @@ time64_t mktime64(const unsigned int year0, const unsigned int mon0,
 }
 EXPORT_SYMBOL(mktime64);
 
-/**
- * set_normalized_timespec - set timespec sec and nsec parts and normalize
- *
- * @ts:                pointer to timespec variable to be set
- * @sec:       seconds to set
- * @nsec:      nanoseconds to set
- *
- * Set seconds and nanoseconds field of a timespec variable and
- * normalize to the timespec storage format
- *
- * Note: The tv_nsec part is always in the range of
- *     0 <= tv_nsec < NSEC_PER_SEC
- * For negative values only the tv_sec field is negative !
- */
-void set_normalized_timespec(struct timespec *ts, time_t sec, s64 nsec)
-{
-       while (nsec >= NSEC_PER_SEC) {
-               /*
-                * The following asm() prevents the compiler from
-                * optimising this loop into a modulo operation. See
-                * also __iter_div_u64_rem() in include/linux/time.h
-                */
-               asm("" : "+rm"(nsec));
-               nsec -= NSEC_PER_SEC;
-               ++sec;
-       }
-       while (nsec < 0) {
-               asm("" : "+rm"(nsec));
-               nsec += NSEC_PER_SEC;
-               --sec;
-       }
-       ts->tv_sec = sec;
-       ts->tv_nsec = nsec;
-}
-EXPORT_SYMBOL(set_normalized_timespec);
-
 /**
  * ns_to_timespec - Convert nanoseconds to timespec
  * @nsec:       the nanoseconds value to be converted
index c801e25875a3e75d10171459aa04221abde724bd..ac5dbf2cd4a21db91f2e9adc5c8fed5636f7650a 100644 (file)
@@ -1464,7 +1464,7 @@ u64 timekeeping_max_deferment(void)
 }
 
 /**
- * read_persistent_clock -  Return time from the persistent clock.
+ * read_persistent_clock64 -  Return time from the persistent clock.
  *
  * Weak dummy function for arches that do not yet support it.
  * Reads the time from the battery backed persistent clock.
@@ -1472,20 +1472,12 @@ u64 timekeeping_max_deferment(void)
  *
  *  XXX - Do be sure to remove it once all arches implement it.
  */
-void __weak read_persistent_clock(struct timespec *ts)
+void __weak read_persistent_clock64(struct timespec64 *ts)
 {
        ts->tv_sec = 0;
        ts->tv_nsec = 0;
 }
 
-void __weak read_persistent_clock64(struct timespec64 *ts64)
-{
-       struct timespec ts;
-
-       read_persistent_clock(&ts);
-       *ts64 = timespec_to_timespec64(ts);
-}
-
 /**
  * read_persistent_wall_and_boot_offset - Read persistent clock, and also offset
  *                                        from the boot.
index 47a614b370cd3e4b7039875e3389477415701408..f7084780a8f81d073f4796e8732f61ab917afa05 100644 (file)
@@ -810,34 +810,23 @@ COMPAT_SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, buf, compat_size_t, len
        return __compat_sys_recvfrom(fd, buf, len, flags, addr, addrlen);
 }
 
-static int __compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg,
-                                unsigned int vlen, unsigned int flags,
-                                struct old_timespec32 __user *timeout)
+COMPAT_SYSCALL_DEFINE5(recvmmsg_time64, int, fd, struct compat_mmsghdr __user *, mmsg,
+                      unsigned int, vlen, unsigned int, flags,
+                      struct __kernel_timespec __user *, timeout)
 {
-       int datagrams;
-       struct timespec64 ktspec;
-
-       if (timeout == NULL)
-               return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
-                                     flags | MSG_CMSG_COMPAT, NULL);
-
-       if (compat_get_timespec64(&ktspec, timeout))
-               return -EFAULT;
-
-       datagrams = __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
-                                  flags | MSG_CMSG_COMPAT, &ktspec);
-       if (datagrams > 0 && compat_put_timespec64(&ktspec, timeout))
-               datagrams = -EFAULT;
-
-       return datagrams;
+       return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
+                             flags | MSG_CMSG_COMPAT, timeout, NULL);
 }
 
+#ifdef CONFIG_COMPAT_32BIT_TIME
 COMPAT_SYSCALL_DEFINE5(recvmmsg, int, fd, struct compat_mmsghdr __user *, mmsg,
                       unsigned int, vlen, unsigned int, flags,
                       struct old_timespec32 __user *, timeout)
 {
-       return __compat_sys_recvmmsg(fd, mmsg, vlen, flags, timeout);
+       return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
+                             flags | MSG_CMSG_COMPAT, NULL, timeout);
 }
+#endif
 
 COMPAT_SYSCALL_DEFINE2(socketcall, int, call, u32 __user *, args)
 {
@@ -925,8 +914,9 @@ COMPAT_SYSCALL_DEFINE2(socketcall, int, call, u32 __user *, args)
                ret = __compat_sys_recvmsg(a0, compat_ptr(a1), a[2]);
                break;
        case SYS_RECVMMSG:
-               ret = __compat_sys_recvmmsg(a0, compat_ptr(a1), a[2], a[3],
-                                           compat_ptr(a[4]));
+               ret = __sys_recvmmsg(a0, compat_ptr(a1), a[2],
+                                    a[3] | MSG_CMSG_COMPAT, NULL,
+                                    compat_ptr(a[4]));
                break;
        case SYS_ACCEPT4:
                ret = __sys_accept4(a0, compat_ptr(a1), compat_ptr(a[2]), a[3]);
index 334fcc617ef2737acd0a84f7921e28a88771756f..e89884e2197babb827b34a345ad8d8625c7071ce 100644 (file)
@@ -2341,8 +2341,9 @@ SYSCALL_DEFINE3(recvmsg, int, fd, struct user_msghdr __user *, msg,
  *     Linux recvmmsg interface
  */
 
-int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
-                  unsigned int flags, struct timespec64 *timeout)
+static int do_recvmmsg(int fd, struct mmsghdr __user *mmsg,
+                         unsigned int vlen, unsigned int flags,
+                         struct timespec64 *timeout)
 {
        int fput_needed, err, datagrams;
        struct socket *sock;
@@ -2451,25 +2452,32 @@ out_put:
        return datagrams;
 }
 
-static int do_sys_recvmmsg(int fd, struct mmsghdr __user *mmsg,
-                          unsigned int vlen, unsigned int flags,
-                          struct __kernel_timespec __user *timeout)
+int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg,
+                  unsigned int vlen, unsigned int flags,
+                  struct __kernel_timespec __user *timeout,
+                  struct old_timespec32 __user *timeout32)
 {
        int datagrams;
        struct timespec64 timeout_sys;
 
-       if (flags & MSG_CMSG_COMPAT)
-               return -EINVAL;
-
-       if (!timeout)
-               return __sys_recvmmsg(fd, mmsg, vlen, flags, NULL);
+       if (timeout && get_timespec64(&timeout_sys, timeout))
+               return -EFAULT;
 
-       if (get_timespec64(&timeout_sys, timeout))
+       if (timeout32 && get_old_timespec32(&timeout_sys, timeout32))
                return -EFAULT;
 
-       datagrams = __sys_recvmmsg(fd, mmsg, vlen, flags, &timeout_sys);
+       if (!timeout && !timeout32)
+               return do_recvmmsg(fd, mmsg, vlen, flags, NULL);
+
+       datagrams = do_recvmmsg(fd, mmsg, vlen, flags, &timeout_sys);
 
-       if (datagrams > 0 && put_timespec64(&timeout_sys, timeout))
+       if (datagrams <= 0)
+               return datagrams;
+
+       if (timeout && put_timespec64(&timeout_sys, timeout))
+               datagrams = -EFAULT;
+
+       if (timeout32 && put_old_timespec32(&timeout_sys, timeout32))
                datagrams = -EFAULT;
 
        return datagrams;
@@ -2479,8 +2487,23 @@ SYSCALL_DEFINE5(recvmmsg, int, fd, struct mmsghdr __user *, mmsg,
                unsigned int, vlen, unsigned int, flags,
                struct __kernel_timespec __user *, timeout)
 {
-       return do_sys_recvmmsg(fd, mmsg, vlen, flags, timeout);
+       if (flags & MSG_CMSG_COMPAT)
+               return -EINVAL;
+
+       return __sys_recvmmsg(fd, mmsg, vlen, flags, timeout, NULL);
+}
+
+#ifdef CONFIG_COMPAT_32BIT_TIME
+SYSCALL_DEFINE5(recvmmsg_time32, int, fd, struct mmsghdr __user *, mmsg,
+               unsigned int, vlen, unsigned int, flags,
+               struct old_timespec32 __user *, timeout)
+{
+       if (flags & MSG_CMSG_COMPAT)
+               return -EINVAL;
+
+       return __sys_recvmmsg(fd, mmsg, vlen, flags, NULL, timeout);
 }
+#endif
 
 #ifdef __ARCH_WANT_SYS_SOCKETCALL
 /* Argument list sizes for sys_socketcall */
@@ -2600,8 +2623,15 @@ SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args)
                                    a[2], true);
                break;
        case SYS_RECVMMSG:
-               err = do_sys_recvmmsg(a0, (struct mmsghdr __user *)a1, a[2],
-                                     a[3], (struct __kernel_timespec __user *)a[4]);
+               if (IS_ENABLED(CONFIG_64BIT) || !IS_ENABLED(CONFIG_64BIT_TIME))
+                       err = __sys_recvmmsg(a0, (struct mmsghdr __user *)a1,
+                                            a[2], a[3],
+                                            (struct __kernel_timespec __user *)a[4],
+                                            NULL);
+               else
+                       err = __sys_recvmmsg(a0, (struct mmsghdr __user *)a1,
+                                            a[2], a[3], NULL,
+                                            (struct old_timespec32 __user *)a[4]);
                break;
        case SYS_ACCEPT4:
                err = __sys_accept4(a0, (struct sockaddr __user *)a1,