mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-05 19:31:57 -04:00
Merge remote-tracking branch 'sm8350/lineage-20' into lineage-23.0
* sm8350/lineage-20: BACKPORT: epoll: fix compat syscall wire up of epoll_pwait2 BACKPORT: epoll: wire up syscall epoll_pwait2 UPSTREAM: epoll: add syscall epoll_pwait2 UPSTREAM: epoll: convert internal api to timespec64 UPSTREAM: close_range(): fix the logics in descriptor table trimming UPSTREAM: fs: fix fd table size alignment properly UPSTREAM: fs: fd tables have to be multiples of BITS_PER_LONG UPSTREAM: file: simplify logic in __close_range() UPSTREAM: file: fix close_range() for unshare+cloexec UPSTREAM: close_range: unshare all fds for CLOSE_RANGE_UNSHARE | CLOSE_RANGE_CLOEXEC UPSTREAM: fs, close_range: add flag CLOSE_RANGE_CLOEXEC BACKPORT: arch: wire-up close_range() UPSTREAM: close_range: add CLOSE_RANGE_UNSHARE UPSTREAM: open: add close_range() Change-Id: Ifa546e0fe29af81ccbb2a5baa32a3b9cb42965fa
This commit is contained in:
commit
0bf05d890a
28 changed files with 362 additions and 87 deletions
|
|
@ -475,8 +475,9 @@
|
|||
543 common fspick sys_fspick
|
||||
544 common pidfd_open sys_pidfd_open
|
||||
# 545 reserved for clone3
|
||||
# 546 reserved for close_range
|
||||
546 common close_range sys_close_range
|
||||
# 547 reserved for openat2
|
||||
# 548 reserved for pidfd_getfd
|
||||
# 549 reserved for faccessat2
|
||||
550 common process_madvise sys_process_madvise
|
||||
551 common epoll_pwait2 sys_epoll_pwait2
|
||||
|
|
|
|||
|
|
@ -449,8 +449,9 @@
|
|||
433 common fspick sys_fspick
|
||||
434 common pidfd_open sys_pidfd_open
|
||||
435 common clone3 sys_clone3
|
||||
# 436 reserved for close_range
|
||||
436 common close_range sys_close_range
|
||||
# 437 reserved for openat2
|
||||
# 438 reserved for pidfd_getfd
|
||||
# 439 reserved for faccessat2
|
||||
440 common process_madvise sys_process_madvise
|
||||
441 common epoll_pwait2 sys_epoll_pwait2
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@
|
|||
#define __ARM_NR_compat_set_tls (__ARM_NR_COMPAT_BASE + 5)
|
||||
#define __ARM_NR_COMPAT_END (__ARM_NR_COMPAT_BASE + 0x800)
|
||||
|
||||
#define __NR_compat_syscalls 441
|
||||
#define __NR_compat_syscalls 442
|
||||
#endif
|
||||
|
||||
#define __ARCH_WANT_SYS_CLONE
|
||||
|
|
|
|||
|
|
@ -879,8 +879,12 @@ __SYSCALL(__NR_fspick, sys_fspick)
|
|||
__SYSCALL(__NR_pidfd_open, sys_pidfd_open)
|
||||
#define __NR_clone3 435
|
||||
__SYSCALL(__NR_clone3, sys_clone3)
|
||||
#define __NR_close_range 436
|
||||
__SYSCALL(__NR_close_range, sys_close_range)
|
||||
#define __NR_process_madvise 440
|
||||
__SYSCALL(__NR_process_madvise, sys_process_madvise)
|
||||
#define __NR_epoll_pwait2 441
|
||||
__SYSCALL(__NR_epoll_pwait2, compat_sys_epoll_pwait2)
|
||||
|
||||
/*
|
||||
* Please add new compat syscalls above this comment and update
|
||||
|
|
|
|||
|
|
@ -356,8 +356,9 @@
|
|||
433 common fspick sys_fspick
|
||||
434 common pidfd_open sys_pidfd_open
|
||||
# 435 reserved for clone3
|
||||
# 436 reserved for close_range
|
||||
436 common close_range sys_close_range
|
||||
# 437 reserved for openat2
|
||||
# 438 reserved for pidfd_getfd
|
||||
# 439 reserved for faccessat2
|
||||
440 common process_madvise sys_process_madvise
|
||||
441 common epoll_pwait2 sys_epoll_pwait2
|
||||
|
|
|
|||
|
|
@ -435,8 +435,9 @@
|
|||
433 common fspick sys_fspick
|
||||
434 common pidfd_open sys_pidfd_open
|
||||
# 435 reserved for clone3
|
||||
# 436 reserved for close_range
|
||||
436 common close_range sys_close_range
|
||||
# 437 reserved for openat2
|
||||
# 438 reserved for pidfd_getfd
|
||||
# 439 reserved for faccessat2
|
||||
440 common process_madvise sys_process_madvise
|
||||
441 common epoll_pwait2 sys_epoll_pwait2
|
||||
|
|
|
|||
|
|
@ -441,8 +441,9 @@
|
|||
433 common fspick sys_fspick
|
||||
434 common pidfd_open sys_pidfd_open
|
||||
435 common clone3 sys_clone3
|
||||
# 436 reserved for close_range
|
||||
436 common close_range sys_close_range
|
||||
# 437 reserved for openat2
|
||||
# 438 reserved for pidfd_getfd
|
||||
# 439 reserved for faccessat2
|
||||
440 common process_madvise sys_process_madvise
|
||||
441 common epoll_pwait2 sys_epoll_pwait2
|
||||
|
|
|
|||
|
|
@ -374,8 +374,9 @@
|
|||
433 n32 fspick sys_fspick
|
||||
434 n32 pidfd_open sys_pidfd_open
|
||||
435 n32 clone3 __sys_clone3
|
||||
# 436 reserved for close_range
|
||||
436 n32 close_range sys_close_range
|
||||
# 437 reserved for openat2
|
||||
# 438 reserved for pidfd_getfd
|
||||
# 439 reserved for faccessat2
|
||||
440 n32 process_madvise sys_process_madvise
|
||||
441 n32 epoll_pwait2 compat_sys_epoll_pwait2
|
||||
|
|
|
|||
|
|
@ -350,8 +350,9 @@
|
|||
433 n64 fspick sys_fspick
|
||||
434 n64 pidfd_open sys_pidfd_open
|
||||
435 n64 clone3 __sys_clone3
|
||||
# 436 reserved for close_range
|
||||
436 n64 close_range sys_close_range
|
||||
# 437 reserved for openat2
|
||||
# 438 reserved for pidfd_getfd
|
||||
# 439 reserved for faccessat2
|
||||
440 n64 process_madvise sys_process_madvise
|
||||
441 n64 epoll_pwait2 sys_epoll_pwait2
|
||||
|
|
|
|||
|
|
@ -423,3 +423,5 @@
|
|||
433 o32 fspick sys_fspick
|
||||
434 o32 pidfd_open sys_pidfd_open
|
||||
435 o32 clone3 __sys_clone3
|
||||
436 o32 close_range sys_close_range
|
||||
441 o32 epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2
|
||||
|
|
|
|||
|
|
@ -433,8 +433,9 @@
|
|||
433 common fspick sys_fspick
|
||||
434 common pidfd_open sys_pidfd_open
|
||||
435 common clone3 sys_clone3_wrapper
|
||||
# 436 reserved for close_range
|
||||
436 common close_range sys_close_range
|
||||
# 437 reserved for openat2
|
||||
# 438 reserved for pidfd_getfd
|
||||
# 439 reserved for faccessat2
|
||||
440 common process_madvise sys_process_madvise
|
||||
441 common epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2
|
||||
|
|
|
|||
|
|
@ -517,8 +517,9 @@
|
|||
433 common fspick sys_fspick
|
||||
434 common pidfd_open sys_pidfd_open
|
||||
435 nospu clone3 ppc_clone3
|
||||
# 436 reserved for close_range
|
||||
436 common close_range sys_close_range
|
||||
# 437 reserved for openat2
|
||||
# 438 reserved for pidfd_getfd
|
||||
# 439 reserved for faccessat2
|
||||
440 common process_madvise sys_process_madvise
|
||||
441 common epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2
|
||||
|
|
|
|||
|
|
@ -438,8 +438,9 @@
|
|||
433 common fspick sys_fspick sys_fspick
|
||||
434 common pidfd_open sys_pidfd_open sys_pidfd_open
|
||||
435 common clone3 sys_clone3 sys_clone3
|
||||
# 436 reserved for close_range
|
||||
436 common close_range sys_close_range sys_close_range
|
||||
# 437 reserved for openat2
|
||||
# 438 reserved for pidfd_getfd
|
||||
# 439 reserved for faccessat2
|
||||
440 common process_madvise sys_process_madvise sys_process_madvise
|
||||
441 common epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2
|
||||
|
|
|
|||
|
|
@ -438,8 +438,9 @@
|
|||
433 common fspick sys_fspick
|
||||
434 common pidfd_open sys_pidfd_open
|
||||
# 435 reserved for clone3
|
||||
# 436 reserved for close_range
|
||||
436 common close_range sys_close_range
|
||||
# 437 reserved for openat2
|
||||
# 438 reserved for pidfd_getfd
|
||||
# 439 reserved for faccessat2
|
||||
440 common process_madvise sys_process_madvise
|
||||
441 common epoll_pwait2 sys_epoll_pwait2
|
||||
|
|
|
|||
|
|
@ -481,8 +481,9 @@
|
|||
433 common fspick sys_fspick
|
||||
434 common pidfd_open sys_pidfd_open
|
||||
# 435 reserved for clone3
|
||||
# 436 reserved for close_range
|
||||
436 common close_range sys_close_range
|
||||
# 437 reserved for openat2
|
||||
# 438 reserved for pidfd_getfd
|
||||
# 439 reserved for faccessat2
|
||||
440 common process_madvise sys_process_madvise
|
||||
441 common epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2
|
||||
|
|
|
|||
|
|
@ -440,8 +440,9 @@
|
|||
433 i386 fspick sys_fspick __ia32_sys_fspick
|
||||
434 i386 pidfd_open sys_pidfd_open __ia32_sys_pidfd_open
|
||||
435 i386 clone3 sys_clone3 __ia32_sys_clone3
|
||||
# 436 reserved for close_range
|
||||
436 i386 close_range sys_close_range
|
||||
# 437 reserved for openat2
|
||||
# 438 reserved for pidfd_getfd
|
||||
# 439 reserved for faccessat2
|
||||
440 i386 process_madvise sys_process_madvise
|
||||
441 i386 epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2
|
||||
|
|
|
|||
|
|
@ -357,11 +357,12 @@
|
|||
433 common fspick __x64_sys_fspick
|
||||
434 common pidfd_open __x64_sys_pidfd_open
|
||||
435 common clone3 __x64_sys_clone3/ptregs
|
||||
# 436 reserved for close_range
|
||||
436 common close_range sys_close_range
|
||||
# 437 reserved for openat2
|
||||
# 438 reserved for pidfd_getfd
|
||||
# 439 reserved for faccessat2
|
||||
440 common process_madvise sys_process_madvise
|
||||
441 common epoll_pwait2 sys_epoll_pwait2
|
||||
|
||||
#
|
||||
# x32-specific system call numbers start at 512 to avoid cache impact
|
||||
|
|
|
|||
|
|
@ -406,8 +406,9 @@
|
|||
433 common fspick sys_fspick
|
||||
434 common pidfd_open sys_pidfd_open
|
||||
435 common clone3 sys_clone3
|
||||
# 436 reserved for close_range
|
||||
436 common close_range sys_close_range
|
||||
# 437 reserved for openat2
|
||||
# 438 reserved for pidfd_getfd
|
||||
# 439 reserved for faccessat2
|
||||
440 common process_madvise sys_process_madvise
|
||||
441 common epoll_pwait2 sys_epoll_pwait2
|
||||
|
|
|
|||
130
fs/eventpoll.c
130
fs/eventpoll.c
|
|
@ -1803,15 +1803,25 @@ static int ep_send_events(struct eventpoll *ep,
|
|||
return esed.res;
|
||||
}
|
||||
|
||||
static inline struct timespec64 ep_set_mstimeout(long ms)
|
||||
static struct timespec64 *ep_timeout_to_timespec(struct timespec64 *to, long ms)
|
||||
{
|
||||
struct timespec64 now, ts = {
|
||||
.tv_sec = ms / MSEC_PER_SEC,
|
||||
.tv_nsec = NSEC_PER_MSEC * (ms % MSEC_PER_SEC),
|
||||
};
|
||||
struct timespec64 now;
|
||||
|
||||
if (ms < 0)
|
||||
return NULL;
|
||||
|
||||
if (!ms) {
|
||||
to->tv_sec = 0;
|
||||
to->tv_nsec = 0;
|
||||
return to;
|
||||
}
|
||||
|
||||
to->tv_sec = ms / MSEC_PER_SEC;
|
||||
to->tv_nsec = NSEC_PER_MSEC * (ms % MSEC_PER_SEC);
|
||||
|
||||
ktime_get_ts64(&now);
|
||||
return timespec64_add_safe(now, ts);
|
||||
*to = timespec64_add_safe(now, *to);
|
||||
return to;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1842,8 +1852,8 @@ static int ep_autoremove_wake_function(struct wait_queue_entry *wq_entry,
|
|||
* stored.
|
||||
* @maxevents: Size (in terms of number of events) of the caller event buffer.
|
||||
* @timeout: Maximum timeout for the ready events fetch operation, in
|
||||
* milliseconds. If the @timeout is zero, the function will not block,
|
||||
* while if the @timeout is less than zero, the function will block
|
||||
* timespec. If the timeout is zero, the function will not block,
|
||||
* while if the @timeout ptr is NULL, the function will block
|
||||
* until at least one event has been retrieved (or an error
|
||||
* occurred).
|
||||
*
|
||||
|
|
@ -1851,7 +1861,7 @@ static int ep_autoremove_wake_function(struct wait_queue_entry *wq_entry,
|
|||
* error code, in case of error.
|
||||
*/
|
||||
static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
|
||||
int maxevents, long timeout)
|
||||
int maxevents, struct timespec64 *timeout)
|
||||
{
|
||||
int res = 0, eavail, timed_out = 0;
|
||||
u64 slack = 0;
|
||||
|
|
@ -1860,13 +1870,11 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
|
|||
|
||||
lockdep_assert_irqs_enabled();
|
||||
|
||||
if (timeout > 0) {
|
||||
struct timespec64 end_time = ep_set_mstimeout(timeout);
|
||||
|
||||
slack = select_estimate_accuracy(&end_time);
|
||||
if (timeout && (timeout->tv_sec | timeout->tv_nsec)) {
|
||||
slack = select_estimate_accuracy(timeout);
|
||||
to = &expires;
|
||||
*to = timespec64_to_ktime(end_time);
|
||||
} else if (timeout == 0) {
|
||||
*to = timespec64_to_ktime(*timeout);
|
||||
} else if (timeout) {
|
||||
/*
|
||||
* Avoid the unnecessary trip to the wait queue loop, if the
|
||||
* caller specified a non blocking operation. We still need
|
||||
|
|
@ -2305,7 +2313,7 @@ error_return:
|
|||
* part of the user space epoll_wait(2).
|
||||
*/
|
||||
static int do_epoll_wait(int epfd, struct epoll_event __user *events,
|
||||
int maxevents, int timeout)
|
||||
int maxevents, struct timespec64 *to)
|
||||
{
|
||||
int error;
|
||||
struct fd f;
|
||||
|
|
@ -2339,7 +2347,7 @@ static int do_epoll_wait(int epfd, struct epoll_event __user *events,
|
|||
ep = f.file->private_data;
|
||||
|
||||
/* Time to fish for events ... */
|
||||
error = ep_poll(ep, events, maxevents, timeout);
|
||||
error = ep_poll(ep, events, maxevents, to);
|
||||
|
||||
error_fput:
|
||||
fdput(f);
|
||||
|
|
@ -2349,16 +2357,19 @@ error_fput:
|
|||
SYSCALL_DEFINE4(epoll_wait, int, epfd, struct epoll_event __user *, events,
|
||||
int, maxevents, int, timeout)
|
||||
{
|
||||
return do_epoll_wait(epfd, events, maxevents, timeout);
|
||||
struct timespec64 to;
|
||||
|
||||
return do_epoll_wait(epfd, events, maxevents,
|
||||
ep_timeout_to_timespec(&to, timeout));
|
||||
}
|
||||
|
||||
/*
|
||||
* Implement the event wait interface for the eventpoll file. It is the kernel
|
||||
* part of the user space epoll_pwait(2).
|
||||
*/
|
||||
SYSCALL_DEFINE6(epoll_pwait, int, epfd, struct epoll_event __user *, events,
|
||||
int, maxevents, int, timeout, const sigset_t __user *, sigmask,
|
||||
size_t, sigsetsize)
|
||||
static int do_epoll_pwait(int epfd, struct epoll_event __user *events,
|
||||
int maxevents, struct timespec64 *to,
|
||||
const sigset_t __user *sigmask, size_t sigsetsize)
|
||||
{
|
||||
int error;
|
||||
|
||||
|
|
@ -2370,18 +2381,47 @@ SYSCALL_DEFINE6(epoll_pwait, int, epfd, struct epoll_event __user *, events,
|
|||
if (error)
|
||||
return error;
|
||||
|
||||
error = do_epoll_wait(epfd, events, maxevents, timeout);
|
||||
error = do_epoll_wait(epfd, events, maxevents, to);
|
||||
|
||||
restore_saved_sigmask_unless(error == -EINTR);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE6(epoll_pwait, int, epfd, struct epoll_event __user *, events,
|
||||
int, maxevents, int, timeout, const sigset_t __user *, sigmask,
|
||||
size_t, sigsetsize)
|
||||
{
|
||||
struct timespec64 to;
|
||||
|
||||
return do_epoll_pwait(epfd, events, maxevents,
|
||||
ep_timeout_to_timespec(&to, timeout),
|
||||
sigmask, sigsetsize);
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE6(epoll_pwait2, int, epfd, struct epoll_event __user *, events,
|
||||
int, maxevents, const struct __kernel_timespec __user *, timeout,
|
||||
const sigset_t __user *, sigmask, size_t, sigsetsize)
|
||||
{
|
||||
struct timespec64 ts, *to = NULL;
|
||||
|
||||
if (timeout) {
|
||||
if (get_timespec64(&ts, timeout))
|
||||
return -EFAULT;
|
||||
to = &ts;
|
||||
if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return do_epoll_pwait(epfd, events, maxevents, to,
|
||||
sigmask, sigsetsize);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
COMPAT_SYSCALL_DEFINE6(epoll_pwait, int, epfd,
|
||||
struct epoll_event __user *, events,
|
||||
int, maxevents, int, timeout,
|
||||
const compat_sigset_t __user *, sigmask,
|
||||
compat_size_t, sigsetsize)
|
||||
static int do_compat_epoll_pwait(int epfd, struct epoll_event __user *events,
|
||||
int maxevents, struct timespec64 *timeout,
|
||||
const compat_sigset_t __user *sigmask,
|
||||
compat_size_t sigsetsize)
|
||||
{
|
||||
long err;
|
||||
|
||||
|
|
@ -2394,10 +2434,46 @@ COMPAT_SYSCALL_DEFINE6(epoll_pwait, int, epfd,
|
|||
return err;
|
||||
|
||||
err = do_epoll_wait(epfd, events, maxevents, timeout);
|
||||
|
||||
restore_saved_sigmask_unless(err == -EINTR);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
COMPAT_SYSCALL_DEFINE6(epoll_pwait, int, epfd,
|
||||
struct epoll_event __user *, events,
|
||||
int, maxevents, int, timeout,
|
||||
const compat_sigset_t __user *, sigmask,
|
||||
compat_size_t, sigsetsize)
|
||||
{
|
||||
struct timespec64 to;
|
||||
|
||||
return do_compat_epoll_pwait(epfd, events, maxevents,
|
||||
ep_timeout_to_timespec(&to, timeout),
|
||||
sigmask, sigsetsize);
|
||||
}
|
||||
|
||||
COMPAT_SYSCALL_DEFINE6(epoll_pwait2, int, epfd,
|
||||
struct epoll_event __user *, events,
|
||||
int, maxevents,
|
||||
const struct __kernel_timespec __user *, timeout,
|
||||
const compat_sigset_t __user *, sigmask,
|
||||
compat_size_t, sigsetsize)
|
||||
{
|
||||
struct timespec64 ts, *to = NULL;
|
||||
|
||||
if (timeout) {
|
||||
if (get_timespec64(&ts, timeout))
|
||||
return -EFAULT;
|
||||
to = &ts;
|
||||
if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return do_compat_epoll_pwait(epfd, events, maxevents, to,
|
||||
sigmask, sigsetsize);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int __init eventpoll_init(void)
|
||||
|
|
|
|||
185
fs/file.c
185
fs/file.c
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/syscalls.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/sched/signal.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
@ -18,6 +19,7 @@
|
|||
#include <linux/bitops.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/close_range.h>
|
||||
|
||||
unsigned int sysctl_nr_open __read_mostly = 1024*1024;
|
||||
unsigned int sysctl_nr_open_min = BITS_PER_LONG;
|
||||
|
|
@ -84,6 +86,14 @@ static void copy_fdtable(struct fdtable *nfdt, struct fdtable *ofdt)
|
|||
* 'unsigned long' in some places, but simply because that is how the Linux
|
||||
* kernel bitmaps are defined to work: they are not "bits in an array of bytes",
|
||||
* they are very much "bits in an array of unsigned long".
|
||||
*
|
||||
* The ALIGN(nr, BITS_PER_LONG) here is for clarity: since we just multiplied
|
||||
* by that "1024/sizeof(ptr)" before, we already know there are sufficient
|
||||
* clear low bits. Clang seems to realize that, gcc ends up being confused.
|
||||
*
|
||||
* On a 128-bit machine, the ALIGN() would actually matter. In the meantime,
|
||||
* let's consider it documentation (and maybe a test-case for gcc to improve
|
||||
* its code generation ;)
|
||||
*/
|
||||
static struct fdtable *alloc_fdtable(unsigned int slots_wanted)
|
||||
{
|
||||
|
|
@ -272,36 +282,45 @@ static inline void __clear_open_fd(unsigned int fd, struct fdtable *fdt)
|
|||
__clear_bit(fd / BITS_PER_LONG, fdt->full_fds_bits);
|
||||
}
|
||||
|
||||
static unsigned int count_open_files(struct fdtable *fdt)
|
||||
/*
|
||||
* Note that a sane fdtable size always has to be a multiple of
|
||||
* BITS_PER_LONG, since we have bitmaps that are sized by this.
|
||||
*
|
||||
* punch_hole is optional - when close_range() is asked to unshare
|
||||
* and close, we don't need to copy descriptors in that range, so
|
||||
* a smaller cloned descriptor table might suffice if the last
|
||||
* currently opened descriptor falls into that range.
|
||||
*/
|
||||
static unsigned int sane_fdtable_size(struct fdtable *fdt, struct fd_range *punch_hole)
|
||||
{
|
||||
unsigned int size = fdt->max_fds;
|
||||
unsigned int i;
|
||||
unsigned int last = find_last_bit(fdt->open_fds, fdt->max_fds);
|
||||
|
||||
/* Find the last open fd */
|
||||
for (i = size / BITS_PER_LONG; i > 0; ) {
|
||||
if (fdt->open_fds[--i])
|
||||
break;
|
||||
if (last == fdt->max_fds)
|
||||
return NR_OPEN_DEFAULT;
|
||||
if (punch_hole && punch_hole->to >= last && punch_hole->from <= last) {
|
||||
last = find_last_bit(fdt->open_fds, punch_hole->from);
|
||||
if (last == punch_hole->from)
|
||||
return NR_OPEN_DEFAULT;
|
||||
}
|
||||
i = (i + 1) * BITS_PER_LONG;
|
||||
return i;
|
||||
return ALIGN(last + 1, BITS_PER_LONG);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a new files structure and copy contents from the
|
||||
* passed in files structure.
|
||||
* errorp will be valid only when the returned files_struct is NULL.
|
||||
* Allocate a new descriptor table and copy contents from the passed in
|
||||
* instance. Returns a pointer to cloned table on success, ERR_PTR()
|
||||
* on failure. For 'punch_hole' see sane_fdtable_size().
|
||||
*/
|
||||
struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
|
||||
struct files_struct *dup_fd(struct files_struct *oldf, struct fd_range *punch_hole)
|
||||
{
|
||||
struct files_struct *newf;
|
||||
struct file **old_fds, **new_fds;
|
||||
unsigned int open_files, i;
|
||||
struct fdtable *old_fdt, *new_fdt;
|
||||
int error;
|
||||
|
||||
*errorp = -ENOMEM;
|
||||
newf = kmem_cache_alloc(files_cachep, GFP_KERNEL);
|
||||
if (!newf)
|
||||
goto out;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
atomic_set(&newf->count, 1);
|
||||
|
||||
|
|
@ -318,7 +337,7 @@ struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
|
|||
|
||||
spin_lock(&oldf->file_lock);
|
||||
old_fdt = files_fdtable(oldf);
|
||||
open_files = count_open_files(old_fdt);
|
||||
open_files = sane_fdtable_size(old_fdt, punch_hole);
|
||||
|
||||
/*
|
||||
* Check whether we need to allocate a larger fd array and fd set.
|
||||
|
|
@ -331,7 +350,7 @@ struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
|
|||
|
||||
new_fdt = alloc_fdtable(open_files);
|
||||
if (IS_ERR(new_fdt)) {
|
||||
*errorp = PTR_ERR(new_fdt);
|
||||
error = PTR_ERR(new_fdt);
|
||||
goto out_release;
|
||||
}
|
||||
|
||||
|
|
@ -342,7 +361,7 @@ struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
|
|||
*/
|
||||
spin_lock(&oldf->file_lock);
|
||||
old_fdt = files_fdtable(oldf);
|
||||
open_files = count_open_files(old_fdt);
|
||||
open_files = sane_fdtable_size(old_fdt, punch_hole);
|
||||
}
|
||||
|
||||
copy_fd_bitmaps(new_fdt, old_fdt, open_files / BITS_PER_LONG);
|
||||
|
|
@ -376,8 +395,7 @@ struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
|
|||
|
||||
out_release:
|
||||
kmem_cache_free(files_cachep, newf);
|
||||
out:
|
||||
return NULL;
|
||||
return ERR_PTR(error);
|
||||
}
|
||||
|
||||
static struct fdtable *close_files(struct files_struct * files)
|
||||
|
|
@ -630,12 +648,9 @@ void fd_install(unsigned int fd, struct file *file)
|
|||
|
||||
EXPORT_SYMBOL(fd_install);
|
||||
|
||||
/*
|
||||
* The same warnings as for __alloc_fd()/__fd_install() apply here...
|
||||
*/
|
||||
int __close_fd(struct files_struct *files, unsigned fd)
|
||||
static struct file *pick_file(struct files_struct *files, unsigned fd)
|
||||
{
|
||||
struct file *file;
|
||||
struct file *file = NULL;
|
||||
struct fdtable *fdt;
|
||||
|
||||
spin_lock(&files->file_lock);
|
||||
|
|
@ -647,15 +662,129 @@ int __close_fd(struct files_struct *files, unsigned fd)
|
|||
goto out_unlock;
|
||||
rcu_assign_pointer(fdt->fd[fd], NULL);
|
||||
__put_unused_fd(files, fd);
|
||||
spin_unlock(&files->file_lock);
|
||||
return filp_close(file, files);
|
||||
|
||||
out_unlock:
|
||||
spin_unlock(&files->file_lock);
|
||||
return -EBADF;
|
||||
return file;
|
||||
}
|
||||
|
||||
/*
|
||||
* The same warnings as for __alloc_fd()/__fd_install() apply here...
|
||||
*/
|
||||
int __close_fd(struct files_struct *files, unsigned fd)
|
||||
{
|
||||
struct file *file;
|
||||
|
||||
file = pick_file(files, fd);
|
||||
if (!file)
|
||||
return -EBADF;
|
||||
|
||||
return filp_close(file, files);
|
||||
}
|
||||
EXPORT_SYMBOL(__close_fd); /* for ksys_close() */
|
||||
|
||||
/**
|
||||
* last_fd - return last valid index into fd table
|
||||
* @cur_fds: files struct
|
||||
*
|
||||
* Context: Either rcu read lock or files_lock must be held.
|
||||
*
|
||||
* Returns: Last valid index into fdtable.
|
||||
*/
|
||||
static inline unsigned last_fd(struct fdtable *fdt)
|
||||
{
|
||||
return fdt->max_fds - 1;
|
||||
}
|
||||
|
||||
static inline void __range_cloexec(struct files_struct *cur_fds,
|
||||
unsigned int fd, unsigned int max_fd)
|
||||
{
|
||||
struct fdtable *fdt;
|
||||
|
||||
/* make sure we're using the correct maximum value */
|
||||
spin_lock(&cur_fds->file_lock);
|
||||
fdt = files_fdtable(cur_fds);
|
||||
max_fd = min(last_fd(fdt), max_fd);
|
||||
if (fd <= max_fd)
|
||||
bitmap_set(fdt->close_on_exec, fd, max_fd - fd + 1);
|
||||
spin_unlock(&cur_fds->file_lock);
|
||||
}
|
||||
|
||||
static inline void __range_close(struct files_struct *cur_fds, unsigned int fd,
|
||||
unsigned int max_fd)
|
||||
{
|
||||
while (fd <= max_fd) {
|
||||
struct file *file;
|
||||
|
||||
file = pick_file(cur_fds, fd++);
|
||||
if (!file)
|
||||
continue;
|
||||
|
||||
filp_close(file, cur_fds);
|
||||
cond_resched();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* __close_range() - Close all file descriptors in a given range.
|
||||
*
|
||||
* @fd: starting file descriptor to close
|
||||
* @max_fd: last file descriptor to close
|
||||
*
|
||||
* This closes a range of file descriptors. All file descriptors
|
||||
* from @fd up to and including @max_fd are closed.
|
||||
*/
|
||||
int __close_range(unsigned fd, unsigned max_fd, unsigned int flags)
|
||||
{
|
||||
struct task_struct *me = current;
|
||||
struct files_struct *cur_fds = me->files, *fds = NULL;
|
||||
|
||||
if (flags & ~(CLOSE_RANGE_UNSHARE | CLOSE_RANGE_CLOEXEC))
|
||||
return -EINVAL;
|
||||
|
||||
if (fd > max_fd)
|
||||
return -EINVAL;
|
||||
|
||||
if ((flags & CLOSE_RANGE_UNSHARE) && atomic_read(&cur_fds->count) > 1) {
|
||||
struct fd_range range = {fd, max_fd}, *punch_hole = ⦥
|
||||
|
||||
/*
|
||||
* If the caller requested all fds to be made cloexec we always
|
||||
* copy all of the file descriptors since they still want to
|
||||
* use them.
|
||||
*/
|
||||
if (flags & CLOSE_RANGE_CLOEXEC)
|
||||
punch_hole = NULL;
|
||||
|
||||
fds = dup_fd(cur_fds, punch_hole);
|
||||
if (IS_ERR(fds))
|
||||
return PTR_ERR(fds);
|
||||
/*
|
||||
* We used to share our file descriptor table, and have now
|
||||
* created a private one, make sure we're using it below.
|
||||
*/
|
||||
swap(cur_fds, fds);
|
||||
}
|
||||
|
||||
if (flags & CLOSE_RANGE_CLOEXEC)
|
||||
__range_cloexec(cur_fds, fd, max_fd);
|
||||
else
|
||||
__range_close(cur_fds, fd, max_fd);
|
||||
|
||||
if (fds) {
|
||||
/*
|
||||
* We're done closing the files we were supposed to. Time to install
|
||||
* the new file descriptor table and drop the old one.
|
||||
*/
|
||||
task_lock(me);
|
||||
me->files = cur_fds;
|
||||
task_unlock(me);
|
||||
put_files_struct(fds);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* variant of __close_fd that gets a ref on the file for later fput
|
||||
*/
|
||||
|
|
|
|||
17
fs/open.c
17
fs/open.c
|
|
@ -1211,6 +1211,23 @@ SYSCALL_DEFINE1(close, unsigned int, fd)
|
|||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* close_range() - Close all file descriptors in a given range.
|
||||
*
|
||||
* @fd: starting file descriptor to close
|
||||
* @max_fd: last file descriptor to close
|
||||
* @flags: reserved for future extensions
|
||||
*
|
||||
* This closes a range of file descriptors. All file descriptors
|
||||
* from @fd up to and including @max_fd are closed.
|
||||
* Currently, errors to close a given file descriptor are ignored.
|
||||
*/
|
||||
SYSCALL_DEFINE3(close_range, unsigned int, fd, unsigned int, max_fd,
|
||||
unsigned int, flags)
|
||||
{
|
||||
return __close_range(fd, max_fd, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine simulates a hangup on the tty, to arrange that users
|
||||
* are given clean terminals at login time.
|
||||
|
|
|
|||
|
|
@ -539,6 +539,12 @@ asmlinkage long compat_sys_epoll_pwait(int epfd,
|
|||
int maxevents, int timeout,
|
||||
const compat_sigset_t __user *sigmask,
|
||||
compat_size_t sigsetsize);
|
||||
asmlinkage long compat_sys_epoll_pwait2(int epfd,
|
||||
struct epoll_event __user *events,
|
||||
int maxevents,
|
||||
const struct __kernel_timespec __user *timeout,
|
||||
const compat_sigset_t __user *sigmask,
|
||||
compat_size_t sigsetsize);
|
||||
|
||||
/* fs/fcntl.c */
|
||||
asmlinkage long compat_sys_fcntl(unsigned int fd, unsigned int cmd,
|
||||
|
|
|
|||
|
|
@ -109,7 +109,10 @@ struct files_struct *get_files_struct(struct task_struct *);
|
|||
void put_files_struct(struct files_struct *fs);
|
||||
void reset_files_struct(struct files_struct *);
|
||||
int unshare_files(struct files_struct **);
|
||||
struct files_struct *dup_fd(struct files_struct *, int *) __latent_entropy;
|
||||
struct fd_range {
|
||||
unsigned int from, to;
|
||||
};
|
||||
struct files_struct *dup_fd(struct files_struct *, struct fd_range *) __latent_entropy;
|
||||
void do_close_on_exec(struct files_struct *);
|
||||
int iterate_fd(struct files_struct *, unsigned,
|
||||
int (*)(const void *, struct file *, unsigned),
|
||||
|
|
@ -121,6 +124,7 @@ extern void __fd_install(struct files_struct *files,
|
|||
unsigned int fd, struct file *file);
|
||||
extern int __close_fd(struct files_struct *files,
|
||||
unsigned int fd);
|
||||
extern int __close_range(unsigned int fd, unsigned int max_fd, unsigned int flags);
|
||||
extern int __close_fd_get_file(unsigned int fd, struct file **res);
|
||||
|
||||
extern struct kmem_cache *files_cachep;
|
||||
|
|
|
|||
|
|
@ -364,6 +364,11 @@ asmlinkage long sys_epoll_pwait(int epfd, struct epoll_event __user *events,
|
|||
int maxevents, int timeout,
|
||||
const sigset_t __user *sigmask,
|
||||
size_t sigsetsize);
|
||||
asmlinkage long sys_epoll_pwait2(int epfd, struct epoll_event __user *events,
|
||||
int maxevents,
|
||||
const struct __kernel_timespec __user *timeout,
|
||||
const sigset_t __user *sigmask,
|
||||
size_t sigsetsize);
|
||||
|
||||
/* fs/fcntl.c */
|
||||
asmlinkage long sys_dup(unsigned int fildes);
|
||||
|
|
@ -441,6 +446,8 @@ asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group);
|
|||
asmlinkage long sys_openat(int dfd, const char __user *filename, int flags,
|
||||
umode_t mode);
|
||||
asmlinkage long sys_close(unsigned int fd);
|
||||
asmlinkage long sys_close_range(unsigned int fd, unsigned int max_fd,
|
||||
unsigned int flags);
|
||||
asmlinkage long sys_vhangup(void);
|
||||
|
||||
/* fs/pipe.c */
|
||||
|
|
|
|||
|
|
@ -850,11 +850,15 @@ __SYSCALL(__NR_pidfd_open, sys_pidfd_open)
|
|||
#define __NR_clone3 435
|
||||
__SYSCALL(__NR_clone3, sys_clone3)
|
||||
#endif
|
||||
#define __NR_close_range 436
|
||||
__SYSCALL(__NR_close_range, sys_close_range)
|
||||
#define __NR_process_madvise 440
|
||||
__SYSCALL(__NR_process_madvise, sys_process_madvise)
|
||||
#define __NR_epoll_pwait2 441
|
||||
__SC_COMP(__NR_epoll_pwait2, sys_epoll_pwait2, compat_sys_epoll_pwait2)
|
||||
|
||||
#undef __NR_syscalls
|
||||
#define __NR_syscalls 441
|
||||
#define __NR_syscalls 442
|
||||
|
||||
/*
|
||||
* 32 bit systems traditionally used different
|
||||
|
|
|
|||
12
include/uapi/linux/close_range.h
Normal file
12
include/uapi/linux/close_range.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
#ifndef _UAPI_LINUX_CLOSE_RANGE_H
|
||||
#define _UAPI_LINUX_CLOSE_RANGE_H
|
||||
|
||||
/* Unshare the file descriptor table before closing file descriptors. */
|
||||
#define CLOSE_RANGE_UNSHARE (1U << 1)
|
||||
|
||||
/* Set the FD_CLOEXEC bit instead of closing the file descriptor. */
|
||||
#define CLOSE_RANGE_CLOEXEC (1U << 2)
|
||||
|
||||
#endif /* _UAPI_LINUX_CLOSE_RANGE_H */
|
||||
|
||||
|
|
@ -1477,28 +1477,25 @@ static int copy_fs(unsigned long clone_flags, struct task_struct *tsk)
|
|||
static int copy_files(unsigned long clone_flags, struct task_struct *tsk)
|
||||
{
|
||||
struct files_struct *oldf, *newf;
|
||||
int error = 0;
|
||||
|
||||
/*
|
||||
* A background process may not have any files ...
|
||||
*/
|
||||
oldf = current->files;
|
||||
if (!oldf)
|
||||
goto out;
|
||||
return 0;
|
||||
|
||||
if (clone_flags & CLONE_FILES) {
|
||||
atomic_inc(&oldf->count);
|
||||
goto out;
|
||||
return 0;
|
||||
}
|
||||
|
||||
newf = dup_fd(oldf, &error);
|
||||
if (!newf)
|
||||
goto out;
|
||||
newf = dup_fd(oldf, NULL);
|
||||
if (IS_ERR(newf))
|
||||
return PTR_ERR(newf);
|
||||
|
||||
tsk->files = newf;
|
||||
error = 0;
|
||||
out:
|
||||
return error;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int copy_io(unsigned long clone_flags, struct task_struct *tsk)
|
||||
|
|
@ -2923,13 +2920,13 @@ static int unshare_fs(unsigned long unshare_flags, struct fs_struct **new_fsp)
|
|||
static int unshare_fd(unsigned long unshare_flags, struct files_struct **new_fdp)
|
||||
{
|
||||
struct files_struct *fd = current->files;
|
||||
int error = 0;
|
||||
|
||||
if ((unshare_flags & CLONE_FILES) &&
|
||||
(fd && atomic_read(&fd->count) > 1)) {
|
||||
*new_fdp = dup_fd(fd, &error);
|
||||
if (!*new_fdp)
|
||||
return error;
|
||||
fd = dup_fd(fd, NULL);
|
||||
if (IS_ERR(fd))
|
||||
return PTR_ERR(fd);
|
||||
*new_fdp = fd;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -68,6 +68,8 @@ COND_SYSCALL(epoll_create1);
|
|||
COND_SYSCALL(epoll_ctl);
|
||||
COND_SYSCALL(epoll_pwait);
|
||||
COND_SYSCALL_COMPAT(epoll_pwait);
|
||||
COND_SYSCALL(epoll_pwait2);
|
||||
COND_SYSCALL_COMPAT(epoll_pwait2);
|
||||
|
||||
/* fs/fcntl.c */
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue