Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 18981
b: refs/heads/master
c: 9f72949
h: refs/heads/master
i:
  18979: eb02421
v: v3
  • Loading branch information
David Woodhouse authored and Linus Torvalds committed Jan 19, 2006
1 parent caef1df commit 7dbd104
Show file tree
Hide file tree
Showing 4 changed files with 520 additions and 96 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 36a7878a224c18aa4a5e098dc93d19cf5601462b
refs/heads/master: 9f72949f679df06021c9e43886c9191494fdb007
260 changes: 223 additions & 37 deletions trunk/fs/compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@
#include <asm/mmu_context.h>
#include <asm/ioctls.h>

extern void sigset_from_compat(sigset_t *set, compat_sigset_t *compat);

/*
* Not all architectures have sys_utime, so implement this in terms
* of sys_utimes.
Expand Down Expand Up @@ -1657,36 +1659,14 @@ static void select_bits_free(void *bits, int size)
#define MAX_SELECT_SECONDS \
((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)

asmlinkage long
compat_sys_select(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp,
compat_ulong_t __user *exp, struct compat_timeval __user *tvp)
int compat_core_sys_select(int n, compat_ulong_t __user *inp,
compat_ulong_t __user *outp, compat_ulong_t __user *exp, s64 *timeout)
{
fd_set_bits fds;
char *bits;
long timeout;
int size, max_fdset, ret = -EINVAL;
struct fdtable *fdt;

timeout = MAX_SCHEDULE_TIMEOUT;
if (tvp) {
time_t sec, usec;

if (!access_ok(VERIFY_READ, tvp, sizeof(*tvp))
|| __get_user(sec, &tvp->tv_sec)
|| __get_user(usec, &tvp->tv_usec)) {
ret = -EFAULT;
goto out_nofds;
}

if (sec < 0 || usec < 0)
goto out_nofds;

if ((unsigned long) sec < MAX_SELECT_SECONDS) {
timeout = ROUND_UP(usec, 1000000/HZ);
timeout += sec * (unsigned long) HZ;
}
}

if (n < 0)
goto out_nofds;

Expand Down Expand Up @@ -1723,19 +1703,7 @@ compat_sys_select(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp
zero_fd_set(n, fds.res_out);
zero_fd_set(n, fds.res_ex);

ret = do_select(n, &fds, &timeout);

if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
time_t sec = 0, usec = 0;
if (timeout) {
sec = timeout / HZ;
usec = timeout % HZ;
usec *= (1000000/HZ);
}
if (put_user(sec, &tvp->tv_sec) ||
put_user(usec, &tvp->tv_usec))
ret = -EFAULT;
}
ret = do_select(n, &fds, timeout);

if (ret < 0)
goto out;
Expand All @@ -1756,6 +1724,224 @@ compat_sys_select(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp
return ret;
}

asmlinkage long compat_sys_select(int n, compat_ulong_t __user *inp,
compat_ulong_t __user *outp, compat_ulong_t __user *exp,
struct compat_timeval __user *tvp)
{
s64 timeout = -1;
struct compat_timeval tv;
int ret;

if (tvp) {
if (copy_from_user(&tv, tvp, sizeof(tv)))
return -EFAULT;

if (tv.tv_sec < 0 || tv.tv_usec < 0)
return -EINVAL;

/* Cast to u64 to make GCC stop complaining */
if ((u64)tv.tv_sec >= (u64)MAX_INT64_SECONDS)
timeout = -1; /* infinite */
else {
timeout = ROUND_UP(tv.tv_sec, 1000000/HZ);
timeout += tv.tv_sec * HZ;
}
}

ret = compat_core_sys_select(n, inp, outp, exp, &timeout);

if (tvp) {
if (current->personality & STICKY_TIMEOUTS)
goto sticky;
tv.tv_usec = jiffies_to_usecs(do_div((*(u64*)&timeout), HZ));
tv.tv_sec = timeout;
if (copy_to_user(tvp, &tv, sizeof(tv))) {
sticky:
/*
* 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.
*/
if (ret == -ERESTARTNOHAND)
ret = -EINTR;
}
}

return ret;
}

#ifdef TIF_RESTORE_SIGMASK
asmlinkage long compat_sys_pselect7(int n, compat_ulong_t __user *inp,
compat_ulong_t __user *outp, compat_ulong_t __user *exp,
struct compat_timespec __user *tsp, compat_sigset_t __user *sigmask,
compat_size_t sigsetsize)
{
compat_sigset_t ss32;
sigset_t ksigmask, sigsaved;
long timeout = MAX_SCHEDULE_TIMEOUT;
struct compat_timespec ts;
int ret;

if (tsp) {
if (copy_from_user(&ts, tsp, sizeof(ts)))
return -EFAULT;

if (ts.tv_sec < 0 || ts.tv_nsec < 0)
return -EINVAL;
}

if (sigmask) {
if (sigsetsize != sizeof(compat_sigset_t))
return -EINVAL;
if (copy_from_user(&ss32, sigmask, sizeof(ss32)))
return -EFAULT;
sigset_from_compat(&ksigmask, &ss32);

sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP));
sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
}

do {
if (tsp) {
if ((unsigned long)ts.tv_sec < MAX_SELECT_SECONDS) {
timeout = ROUND_UP(ts.tv_nsec, 1000000000/HZ);
timeout += ts.tv_sec * (unsigned long)HZ;
ts.tv_sec = 0;
ts.tv_nsec = 0;
} else {
ts.tv_sec -= MAX_SELECT_SECONDS;
timeout = MAX_SELECT_SECONDS * HZ;
}
}

ret = compat_core_sys_select(n, inp, outp, exp, &timeout);

} while (!ret && !timeout && tsp && (ts.tv_sec || ts.tv_nsec));

if (tsp && !(current->personality & STICKY_TIMEOUTS)) {
ts.tv_sec += timeout / HZ;
ts.tv_nsec += (timeout % HZ) * (1000000000/HZ);
if (ts.tv_nsec >= 1000000000) {
ts.tv_sec++;
ts.tv_nsec -= 1000000000;
}
(void)copy_to_user(tsp, &ts, sizeof(ts));
}

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_thread_flag(TIF_RESTORE_SIGMASK);
}
} else if (sigmask)
sigprocmask(SIG_SETMASK, &sigsaved, NULL);

return ret;
}

asmlinkage long compat_sys_pselect6(int n, compat_ulong_t __user *inp,
compat_ulong_t __user *outp, compat_ulong_t __user *exp,
struct compat_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 compat_sys_pselect7(n, inp, outp, exp, tsp, compat_ptr(up),
sigsetsize);
}

asmlinkage long compat_sys_ppoll(struct pollfd __user *ufds,
unsigned int nfds, struct compat_timespec __user *tsp,
const compat_sigset_t __user *sigmask, compat_size_t sigsetsize)
{
compat_sigset_t ss32;
sigset_t ksigmask, sigsaved;
struct compat_timespec ts;
s64 timeout = -1;
int ret;

if (tsp) {
if (copy_from_user(&ts, tsp, sizeof(ts)))
return -EFAULT;

/* We assume that ts.tv_sec is always lower than
the number of seconds that can be expressed in
an s64. Otherwise the compiler bitches at us */
timeout = ROUND_UP(ts.tv_sec, 1000000000/HZ);
timeout += ts.tv_sec * HZ;
}

if (sigmask) {
if (sigsetsize |= sizeof(compat_sigset_t))
return -EINVAL;
if (copy_from_user(&ss32, sigmask, sizeof(ss32)))
return -EFAULT;
sigset_from_compat(&ksigmask, &ss32);

sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP));
sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
}

ret = do_sys_poll(ufds, nfds, &timeout);

/* 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_thread_flag(TIF_RESTORE_SIGMASK);
}
ret = -ERESTARTNOHAND;
} else if (sigmask)
sigprocmask(SIG_SETMASK, &sigsaved, NULL);

if (tsp && timeout >= 0) {
if (current->personality & STICKY_TIMEOUTS)
goto sticky;
/* Yes, we know it's actually an s64, but it's also positive. */
ts.tv_nsec = jiffies_to_usecs(do_div((*(u64*)&timeout), HZ)) * 1000;
ts.tv_sec = timeout;
if (copy_to_user(tsp, &ts, sizeof(ts))) {
sticky:
/*
* 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.
*/
if (ret == -ERESTARTNOHAND && timeout >= 0)
ret = -EINTR;
}
}

return ret;
}
#endif /* TIF_RESTORE_SIGMASK */

#if defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE)
/* Stuff for NFS server syscalls... */
struct compat_nfsctl_svc {
Expand Down
Loading

0 comments on commit 7dbd104

Please sign in to comment.