diff options
| author | Anton Altaparmakov <aia21@cantab.net> | 2006-01-19 11:39:33 -0500 |
|---|---|---|
| committer | Anton Altaparmakov <aia21@cantab.net> | 2006-01-19 11:39:33 -0500 |
| commit | 944d79559d154c12becde0dab327016cf438f46c (patch) | |
| tree | 50c101806f4d3b6585222dda060559eb4f3e005a /fs/compat.c | |
| parent | d087e4bdd24ebe3ae3d0b265b6573ec901af4b4b (diff) | |
| parent | 0f36b018b2e314d45af86449f1a97facb1fbe300 (diff) | |
Merge branch 'master' of /usr/src/ntfs-2.6/
Diffstat (limited to 'fs/compat.c')
| -rw-r--r-- | fs/compat.c | 336 |
1 files changed, 286 insertions, 50 deletions
diff --git a/fs/compat.c b/fs/compat.c index 818634120b69..18b21b4c9e3a 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
| @@ -53,6 +53,8 @@ | |||
| 53 | #include <asm/mmu_context.h> | 53 | #include <asm/mmu_context.h> |
| 54 | #include <asm/ioctls.h> | 54 | #include <asm/ioctls.h> |
| 55 | 55 | ||
| 56 | extern void sigset_from_compat(sigset_t *set, compat_sigset_t *compat); | ||
| 57 | |||
| 56 | /* | 58 | /* |
| 57 | * Not all architectures have sys_utime, so implement this in terms | 59 | * Not all architectures have sys_utime, so implement this in terms |
| 58 | * of sys_utimes. | 60 | * of sys_utimes. |
| @@ -68,10 +70,10 @@ asmlinkage long compat_sys_utime(char __user *filename, struct compat_utimbuf __ | |||
| 68 | tv[0].tv_usec = 0; | 70 | tv[0].tv_usec = 0; |
| 69 | tv[1].tv_usec = 0; | 71 | tv[1].tv_usec = 0; |
| 70 | } | 72 | } |
| 71 | return do_utimes(filename, t ? tv : NULL); | 73 | return do_utimes(AT_FDCWD, filename, t ? tv : NULL); |
| 72 | } | 74 | } |
| 73 | 75 | ||
| 74 | asmlinkage long compat_sys_utimes(char __user *filename, struct compat_timeval __user *t) | 76 | asmlinkage long compat_sys_futimesat(int dfd, char __user *filename, struct compat_timeval __user *t) |
| 75 | { | 77 | { |
| 76 | struct timeval tv[2]; | 78 | struct timeval tv[2]; |
| 77 | 79 | ||
| @@ -82,14 +84,19 @@ asmlinkage long compat_sys_utimes(char __user *filename, struct compat_timeval _ | |||
| 82 | get_user(tv[1].tv_usec, &t[1].tv_usec)) | 84 | get_user(tv[1].tv_usec, &t[1].tv_usec)) |
| 83 | return -EFAULT; | 85 | return -EFAULT; |
| 84 | } | 86 | } |
| 85 | return do_utimes(filename, t ? tv : NULL); | 87 | return do_utimes(dfd, filename, t ? tv : NULL); |
| 88 | } | ||
| 89 | |||
| 90 | asmlinkage long compat_sys_utimes(char __user *filename, struct compat_timeval __user *t) | ||
| 91 | { | ||
| 92 | return compat_sys_futimesat(AT_FDCWD, filename, t); | ||
| 86 | } | 93 | } |
| 87 | 94 | ||
| 88 | asmlinkage long compat_sys_newstat(char __user * filename, | 95 | asmlinkage long compat_sys_newstat(char __user * filename, |
| 89 | struct compat_stat __user *statbuf) | 96 | struct compat_stat __user *statbuf) |
| 90 | { | 97 | { |
| 91 | struct kstat stat; | 98 | struct kstat stat; |
| 92 | int error = vfs_stat(filename, &stat); | 99 | int error = vfs_stat_fd(AT_FDCWD, filename, &stat); |
| 93 | 100 | ||
| 94 | if (!error) | 101 | if (!error) |
| 95 | error = cp_compat_stat(&stat, statbuf); | 102 | error = cp_compat_stat(&stat, statbuf); |
| @@ -100,10 +107,31 @@ asmlinkage long compat_sys_newlstat(char __user * filename, | |||
| 100 | struct compat_stat __user *statbuf) | 107 | struct compat_stat __user *statbuf) |
| 101 | { | 108 | { |
| 102 | struct kstat stat; | 109 | struct kstat stat; |
| 103 | int error = vfs_lstat(filename, &stat); | 110 | int error = vfs_lstat_fd(AT_FDCWD, filename, &stat); |
| 111 | |||
| 112 | if (!error) | ||
| 113 | error = cp_compat_stat(&stat, statbuf); | ||
| 114 | return error; | ||
| 115 | } | ||
| 116 | |||
| 117 | asmlinkage long compat_sys_newfstatat(int dfd, char __user *filename, | ||
| 118 | struct compat_stat __user *statbuf, int flag) | ||
| 119 | { | ||
| 120 | struct kstat stat; | ||
| 121 | int error = -EINVAL; | ||
| 122 | |||
| 123 | if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0) | ||
| 124 | goto out; | ||
| 125 | |||
| 126 | if (flag & AT_SYMLINK_NOFOLLOW) | ||
| 127 | error = vfs_lstat_fd(dfd, filename, &stat); | ||
| 128 | else | ||
| 129 | error = vfs_stat_fd(dfd, filename, &stat); | ||
| 104 | 130 | ||
| 105 | if (!error) | 131 | if (!error) |
| 106 | error = cp_compat_stat(&stat, statbuf); | 132 | error = cp_compat_stat(&stat, statbuf); |
| 133 | |||
| 134 | out: | ||
| 107 | return error; | 135 | return error; |
| 108 | } | 136 | } |
| 109 | 137 | ||
| @@ -494,9 +522,21 @@ asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd, | |||
| 494 | ret = sys_fcntl(fd, cmd, (unsigned long)&f); | 522 | ret = sys_fcntl(fd, cmd, (unsigned long)&f); |
| 495 | set_fs(old_fs); | 523 | set_fs(old_fs); |
| 496 | if (cmd == F_GETLK && ret == 0) { | 524 | if (cmd == F_GETLK && ret == 0) { |
| 497 | if ((f.l_start >= COMPAT_OFF_T_MAX) || | 525 | /* GETLK was successfule and we need to return the data... |
| 498 | ((f.l_start + f.l_len) > COMPAT_OFF_T_MAX)) | 526 | * but it needs to fit in the compat structure. |
| 527 | * l_start shouldn't be too big, unless the original | ||
| 528 | * start + end is greater than COMPAT_OFF_T_MAX, in which | ||
| 529 | * case the app was asking for trouble, so we return | ||
| 530 | * -EOVERFLOW in that case. | ||
| 531 | * l_len could be too big, in which case we just truncate it, | ||
| 532 | * and only allow the app to see that part of the conflicting | ||
| 533 | * lock that might make sense to it anyway | ||
| 534 | */ | ||
| 535 | |||
| 536 | if (f.l_start > COMPAT_OFF_T_MAX) | ||
| 499 | ret = -EOVERFLOW; | 537 | ret = -EOVERFLOW; |
| 538 | if (f.l_len > COMPAT_OFF_T_MAX) | ||
| 539 | f.l_len = COMPAT_OFF_T_MAX; | ||
| 500 | if (ret == 0) | 540 | if (ret == 0) |
| 501 | ret = put_compat_flock(&f, compat_ptr(arg)); | 541 | ret = put_compat_flock(&f, compat_ptr(arg)); |
| 502 | } | 542 | } |
| @@ -515,9 +555,11 @@ asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd, | |||
| 515 | (unsigned long)&f); | 555 | (unsigned long)&f); |
| 516 | set_fs(old_fs); | 556 | set_fs(old_fs); |
| 517 | if (cmd == F_GETLK64 && ret == 0) { | 557 | if (cmd == F_GETLK64 && ret == 0) { |
| 518 | if ((f.l_start >= COMPAT_LOFF_T_MAX) || | 558 | /* need to return lock information - see above for commentary */ |
| 519 | ((f.l_start + f.l_len) > COMPAT_LOFF_T_MAX)) | 559 | if (f.l_start > COMPAT_LOFF_T_MAX) |
| 520 | ret = -EOVERFLOW; | 560 | ret = -EOVERFLOW; |
| 561 | if (f.l_len > COMPAT_LOFF_T_MAX) | ||
| 562 | f.l_len = COMPAT_LOFF_T_MAX; | ||
| 521 | if (ret == 0) | 563 | if (ret == 0) |
| 522 | ret = put_compat_flock64(&f, compat_ptr(arg)); | 564 | ret = put_compat_flock64(&f, compat_ptr(arg)); |
| 523 | } | 565 | } |
| @@ -1170,7 +1212,7 @@ static ssize_t compat_do_readv_writev(int type, struct file *file, | |||
| 1170 | } | 1212 | } |
| 1171 | 1213 | ||
| 1172 | ret = rw_verify_area(type, file, pos, tot_len); | 1214 | ret = rw_verify_area(type, file, pos, tot_len); |
| 1173 | if (ret) | 1215 | if (ret < 0) |
| 1174 | goto out; | 1216 | goto out; |
| 1175 | 1217 | ||
| 1176 | fnv = NULL; | 1218 | fnv = NULL; |
| @@ -1276,7 +1318,17 @@ out: | |||
| 1276 | asmlinkage long | 1318 | asmlinkage long |
| 1277 | compat_sys_open(const char __user *filename, int flags, int mode) | 1319 | compat_sys_open(const char __user *filename, int flags, int mode) |
| 1278 | { | 1320 | { |
| 1279 | return do_sys_open(filename, flags, mode); | 1321 | return do_sys_open(AT_FDCWD, filename, flags, mode); |
| 1322 | } | ||
| 1323 | |||
| 1324 | /* | ||
| 1325 | * Exactly like fs/open.c:sys_openat(), except that it doesn't set the | ||
| 1326 | * O_LARGEFILE flag. | ||
| 1327 | */ | ||
| 1328 | asmlinkage long | ||
| 1329 | compat_sys_openat(int dfd, const char __user *filename, int flags, int mode) | ||
| 1330 | { | ||
| 1331 | return do_sys_open(dfd, filename, flags, mode); | ||
| 1280 | } | 1332 | } |
| 1281 | 1333 | ||
| 1282 | /* | 1334 | /* |
| @@ -1523,7 +1575,7 @@ out_ret: | |||
| 1523 | * Ooo, nasty. We need here to frob 32-bit unsigned longs to | 1575 | * Ooo, nasty. We need here to frob 32-bit unsigned longs to |
| 1524 | * 64-bit unsigned longs. | 1576 | * 64-bit unsigned longs. |
| 1525 | */ | 1577 | */ |
| 1526 | static inline | 1578 | static |
| 1527 | int compat_get_fd_set(unsigned long nr, compat_ulong_t __user *ufdset, | 1579 | int compat_get_fd_set(unsigned long nr, compat_ulong_t __user *ufdset, |
| 1528 | unsigned long *fdset) | 1580 | unsigned long *fdset) |
| 1529 | { | 1581 | { |
| @@ -1556,7 +1608,7 @@ int compat_get_fd_set(unsigned long nr, compat_ulong_t __user *ufdset, | |||
| 1556 | return 0; | 1608 | return 0; |
| 1557 | } | 1609 | } |
| 1558 | 1610 | ||
| 1559 | static inline | 1611 | static |
| 1560 | void compat_set_fd_set(unsigned long nr, compat_ulong_t __user *ufdset, | 1612 | void compat_set_fd_set(unsigned long nr, compat_ulong_t __user *ufdset, |
| 1561 | unsigned long *fdset) | 1613 | unsigned long *fdset) |
| 1562 | { | 1614 | { |
| @@ -1607,36 +1659,14 @@ static void select_bits_free(void *bits, int size) | |||
| 1607 | #define MAX_SELECT_SECONDS \ | 1659 | #define MAX_SELECT_SECONDS \ |
| 1608 | ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1) | 1660 | ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1) |
| 1609 | 1661 | ||
| 1610 | asmlinkage long | 1662 | int compat_core_sys_select(int n, compat_ulong_t __user *inp, |
| 1611 | compat_sys_select(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp, | 1663 | compat_ulong_t __user *outp, compat_ulong_t __user *exp, s64 *timeout) |
| 1612 | compat_ulong_t __user *exp, struct compat_timeval __user *tvp) | ||
| 1613 | { | 1664 | { |
| 1614 | fd_set_bits fds; | 1665 | fd_set_bits fds; |
| 1615 | char *bits; | 1666 | char *bits; |
| 1616 | long timeout; | ||
| 1617 | int size, max_fdset, ret = -EINVAL; | 1667 | int size, max_fdset, ret = -EINVAL; |
| 1618 | struct fdtable *fdt; | 1668 | struct fdtable *fdt; |
| 1619 | 1669 | ||
| 1620 | timeout = MAX_SCHEDULE_TIMEOUT; | ||
| 1621 | if (tvp) { | ||
| 1622 | time_t sec, usec; | ||
| 1623 | |||
| 1624 | if (!access_ok(VERIFY_READ, tvp, sizeof(*tvp)) | ||
| 1625 | || __get_user(sec, &tvp->tv_sec) | ||
| 1626 | || __get_user(usec, &tvp->tv_usec)) { | ||
| 1627 | ret = -EFAULT; | ||
| 1628 | goto out_nofds; | ||
| 1629 | } | ||
| 1630 | |||
| 1631 | if (sec < 0 || usec < 0) | ||
| 1632 | goto out_nofds; | ||
| 1633 | |||
| 1634 | if ((unsigned long) sec < MAX_SELECT_SECONDS) { | ||
| 1635 | timeout = ROUND_UP(usec, 1000000/HZ); | ||
| 1636 | timeout += sec * (unsigned long) HZ; | ||
| 1637 | } | ||
| 1638 | } | ||
| 1639 | |||
| 1640 | if (n < 0) | 1670 | if (n < 0) |
| 1641 | goto out_nofds; | 1671 | goto out_nofds; |
| 1642 | 1672 | ||
| @@ -1673,19 +1703,7 @@ compat_sys_select(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp | |||
| 1673 | zero_fd_set(n, fds.res_out); | 1703 | zero_fd_set(n, fds.res_out); |
| 1674 | zero_fd_set(n, fds.res_ex); | 1704 | zero_fd_set(n, fds.res_ex); |
| 1675 | 1705 | ||
| 1676 | ret = do_select(n, &fds, &timeout); | 1706 | ret = do_select(n, &fds, timeout); |
| 1677 | |||
| 1678 | if (tvp && !(current->personality & STICKY_TIMEOUTS)) { | ||
| 1679 | time_t sec = 0, usec = 0; | ||
| 1680 | if (timeout) { | ||
| 1681 | sec = timeout / HZ; | ||
| 1682 | usec = timeout % HZ; | ||
| 1683 | usec *= (1000000/HZ); | ||
| 1684 | } | ||
| 1685 | if (put_user(sec, &tvp->tv_sec) || | ||
| 1686 | put_user(usec, &tvp->tv_usec)) | ||
| 1687 | ret = -EFAULT; | ||
| 1688 | } | ||
| 1689 | 1707 | ||
| 1690 | if (ret < 0) | 1708 | if (ret < 0) |
| 1691 | goto out; | 1709 | goto out; |
| @@ -1706,6 +1724,224 @@ out_nofds: | |||
| 1706 | return ret; | 1724 | return ret; |
| 1707 | } | 1725 | } |
| 1708 | 1726 | ||
| 1727 | asmlinkage long compat_sys_select(int n, compat_ulong_t __user *inp, | ||
| 1728 | compat_ulong_t __user *outp, compat_ulong_t __user *exp, | ||
| 1729 | struct compat_timeval __user *tvp) | ||
| 1730 | { | ||
| 1731 | s64 timeout = -1; | ||
| 1732 | struct compat_timeval tv; | ||
| 1733 | int ret; | ||
| 1734 | |||
| 1735 | if (tvp) { | ||
| 1736 | if (copy_from_user(&tv, tvp, sizeof(tv))) | ||
| 1737 | return -EFAULT; | ||
| 1738 | |||
| 1739 | if (tv.tv_sec < 0 || tv.tv_usec < 0) | ||
| 1740 | return -EINVAL; | ||
| 1741 | |||
| 1742 | /* Cast to u64 to make GCC stop complaining */ | ||
| 1743 | if ((u64)tv.tv_sec >= (u64)MAX_INT64_SECONDS) | ||
| 1744 | timeout = -1; /* infinite */ | ||
| 1745 | else { | ||
| 1746 | timeout = ROUND_UP(tv.tv_sec, 1000000/HZ); | ||
| 1747 | timeout += tv.tv_sec * HZ; | ||
| 1748 | } | ||
| 1749 | } | ||
| 1750 | |||
| 1751 | ret = compat_core_sys_select(n, inp, outp, exp, &timeout); | ||
| 1752 | |||
| 1753 | if (tvp) { | ||
| 1754 | if (current->personality & STICKY_TIMEOUTS) | ||
| 1755 | goto sticky; | ||
| 1756 | tv.tv_usec = jiffies_to_usecs(do_div((*(u64*)&timeout), HZ)); | ||
| 1757 | tv.tv_sec = timeout; | ||
| 1758 | if (copy_to_user(tvp, &tv, sizeof(tv))) { | ||
| 1759 | sticky: | ||
| 1760 | /* | ||
| 1761 | * If an application puts its timeval in read-only | ||
| 1762 | * memory, we don't want the Linux-specific update to | ||
| 1763 | * the timeval to cause a fault after the select has | ||
| 1764 | * completed successfully. However, because we're not | ||
| 1765 | * updating the timeval, we can't restart the system | ||
| 1766 | * call. | ||
| 1767 | */ | ||
| 1768 | if (ret == -ERESTARTNOHAND) | ||
| 1769 | ret = -EINTR; | ||
| 1770 | } | ||
| 1771 | } | ||
| 1772 | |||
| 1773 | return ret; | ||
| 1774 | } | ||
| 1775 | |||
| 1776 | #ifdef TIF_RESTORE_SIGMASK | ||
| 1777 | asmlinkage long compat_sys_pselect7(int n, compat_ulong_t __user *inp, | ||
| 1778 | compat_ulong_t __user *outp, compat_ulong_t __user *exp, | ||
| 1779 | struct compat_timespec __user *tsp, compat_sigset_t __user *sigmask, | ||
| 1780 | compat_size_t sigsetsize) | ||
| 1781 | { | ||
| 1782 | compat_sigset_t ss32; | ||
| 1783 | sigset_t ksigmask, sigsaved; | ||
| 1784 | long timeout = MAX_SCHEDULE_TIMEOUT; | ||
| 1785 | struct compat_timespec ts; | ||
| 1786 | int ret; | ||
| 1787 | |||
| 1788 | if (tsp) { | ||
| 1789 | if (copy_from_user(&ts, tsp, sizeof(ts))) | ||
| 1790 | return -EFAULT; | ||
| 1791 | |||
| 1792 | if (ts.tv_sec < 0 || ts.tv_nsec < 0) | ||
| 1793 | return -EINVAL; | ||
| 1794 | } | ||
| 1795 | |||
| 1796 | if (sigmask) { | ||
| 1797 | if (sigsetsize != sizeof(compat_sigset_t)) | ||
| 1798 | return -EINVAL; | ||
| 1799 | if (copy_from_user(&ss32, sigmask, sizeof(ss32))) | ||
| 1800 | return -EFAULT; | ||
| 1801 | sigset_from_compat(&ksigmask, &ss32); | ||
| 1802 | |||
| 1803 | sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP)); | ||
| 1804 | sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); | ||
| 1805 | } | ||
| 1806 | |||
| 1807 | do { | ||
| 1808 | if (tsp) { | ||
| 1809 | if ((unsigned long)ts.tv_sec < MAX_SELECT_SECONDS) { | ||
| 1810 | timeout = ROUND_UP(ts.tv_nsec, 1000000000/HZ); | ||
| 1811 | timeout += ts.tv_sec * (unsigned long)HZ; | ||
| 1812 | ts.tv_sec = 0; | ||
| 1813 | ts.tv_nsec = 0; | ||
| 1814 | } else { | ||
| 1815 | ts.tv_sec -= MAX_SELECT_SECONDS; | ||
| 1816 | timeout = MAX_SELECT_SECONDS * HZ; | ||
| 1817 | } | ||
| 1818 | } | ||
| 1819 | |||
| 1820 | ret = compat_core_sys_select(n, inp, outp, exp, &timeout); | ||
| 1821 | |||
| 1822 | } while (!ret && !timeout && tsp && (ts.tv_sec || ts.tv_nsec)); | ||
| 1823 | |||
| 1824 | if (tsp && !(current->personality & STICKY_TIMEOUTS)) { | ||
| 1825 | ts.tv_sec += timeout / HZ; | ||
| 1826 | ts.tv_nsec += (timeout % HZ) * (1000000000/HZ); | ||
| 1827 | if (ts.tv_nsec >= 1000000000) { | ||
| 1828 | ts.tv_sec++; | ||
| 1829 | ts.tv_nsec -= 1000000000; | ||
| 1830 | } | ||
| 1831 | (void)copy_to_user(tsp, &ts, sizeof(ts)); | ||
| 1832 | } | ||
| 1833 | |||
| 1834 | if (ret == -ERESTARTNOHAND) { | ||
| 1835 | /* | ||
| 1836 | * Don't restore the signal mask yet. Let do_signal() deliver | ||
| 1837 | * the signal on the way back to userspace, before the signal | ||
| 1838 | * mask is restored. | ||
| 1839 | */ | ||
| 1840 | if (sigmask) { | ||
| 1841 | memcpy(¤t->saved_sigmask, &sigsaved, | ||
| 1842 | sizeof(sigsaved)); | ||
| 1843 | set_thread_flag(TIF_RESTORE_SIGMASK); | ||
| 1844 | } | ||
| 1845 | } else if (sigmask) | ||
| 1846 | sigprocmask(SIG_SETMASK, &sigsaved, NULL); | ||
| 1847 | |||
| 1848 | return ret; | ||
| 1849 | } | ||
| 1850 | |||
| 1851 | asmlinkage long compat_sys_pselect6(int n, compat_ulong_t __user *inp, | ||
| 1852 | compat_ulong_t __user *outp, compat_ulong_t __user *exp, | ||
| 1853 | struct compat_timespec __user *tsp, void __user *sig) | ||
| 1854 | { | ||
| 1855 | compat_size_t sigsetsize = 0; | ||
| 1856 | compat_uptr_t up = 0; | ||
| 1857 | |||
| 1858 | if (sig) { | ||
| 1859 | if (!access_ok(VERIFY_READ, sig, | ||
| 1860 | sizeof(compat_uptr_t)+sizeof(compat_size_t)) || | ||
| 1861 | __get_user(up, (compat_uptr_t __user *)sig) || | ||
| 1862 | __get_user(sigsetsize, | ||
| 1863 | (compat_size_t __user *)(sig+sizeof(up)))) | ||
| 1864 | return -EFAULT; | ||
| 1865 | } | ||
| 1866 | return compat_sys_pselect7(n, inp, outp, exp, tsp, compat_ptr(up), | ||
| 1867 | sigsetsize); | ||
| 1868 | } | ||
| 1869 | |||
| 1870 | asmlinkage long compat_sys_ppoll(struct pollfd __user *ufds, | ||
| 1871 | unsigned int nfds, struct compat_timespec __user *tsp, | ||
| 1872 | const compat_sigset_t __user *sigmask, compat_size_t sigsetsize) | ||
| 1873 | { | ||
| 1874 | compat_sigset_t ss32; | ||
| 1875 | sigset_t ksigmask, sigsaved; | ||
| 1876 | struct compat_timespec ts; | ||
| 1877 | s64 timeout = -1; | ||
| 1878 | int ret; | ||
| 1879 | |||
| 1880 | if (tsp) { | ||
| 1881 | if (copy_from_user(&ts, tsp, sizeof(ts))) | ||
| 1882 | return -EFAULT; | ||
| 1883 | |||
| 1884 | /* We assume that ts.tv_sec is always lower than | ||
| 1885 | the number of seconds that can be expressed in | ||
| 1886 | an s64. Otherwise the compiler bitches at us */ | ||
| 1887 | timeout = ROUND_UP(ts.tv_sec, 1000000000/HZ); | ||
| 1888 | timeout += ts.tv_sec * HZ; | ||
| 1889 | } | ||
| 1890 | |||
| 1891 | if (sigmask) { | ||
| 1892 | if (sigsetsize |= sizeof(compat_sigset_t)) | ||
| 1893 | return -EINVAL; | ||
| 1894 | if (copy_from_user(&ss32, sigmask, sizeof(ss32))) | ||
| 1895 | return -EFAULT; | ||
| 1896 | sigset_from_compat(&ksigmask, &ss32); | ||
| 1897 | |||
| 1898 | sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP)); | ||
| 1899 | sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); | ||
| 1900 | } | ||
| 1901 | |||
| 1902 | ret = do_sys_poll(ufds, nfds, &timeout); | ||
| 1903 | |||
| 1904 | /* We can restart this syscall, usually */ | ||
| 1905 | if (ret == -EINTR) { | ||
| 1906 | /* | ||
| 1907 | * Don't restore the signal mask yet. Let do_signal() deliver | ||
| 1908 | * the signal on the way back to userspace, before the signal | ||
| 1909 | * mask is restored. | ||
| 1910 | */ | ||
| 1911 | if (sigmask) { | ||
| 1912 | memcpy(¤t->saved_sigmask, &sigsaved, | ||
| 1913 | sizeof(sigsaved)); | ||
| 1914 | set_thread_flag(TIF_RESTORE_SIGMASK); | ||
| 1915 | } | ||
| 1916 | ret = -ERESTARTNOHAND; | ||
| 1917 | } else if (sigmask) | ||
| 1918 | sigprocmask(SIG_SETMASK, &sigsaved, NULL); | ||
| 1919 | |||
| 1920 | if (tsp && timeout >= 0) { | ||
| 1921 | if (current->personality & STICKY_TIMEOUTS) | ||
| 1922 | goto sticky; | ||
| 1923 | /* Yes, we know it's actually an s64, but it's also positive. */ | ||
| 1924 | ts.tv_nsec = jiffies_to_usecs(do_div((*(u64*)&timeout), HZ)) * 1000; | ||
| 1925 | ts.tv_sec = timeout; | ||
| 1926 | if (copy_to_user(tsp, &ts, sizeof(ts))) { | ||
| 1927 | sticky: | ||
| 1928 | /* | ||
| 1929 | * If an application puts its timeval in read-only | ||
| 1930 | * memory, we don't want the Linux-specific update to | ||
| 1931 | * the timeval to cause a fault after the select has | ||
| 1932 | * completed successfully. However, because we're not | ||
| 1933 | * updating the timeval, we can't restart the system | ||
| 1934 | * call. | ||
| 1935 | */ | ||
| 1936 | if (ret == -ERESTARTNOHAND && timeout >= 0) | ||
| 1937 | ret = -EINTR; | ||
| 1938 | } | ||
| 1939 | } | ||
| 1940 | |||
| 1941 | return ret; | ||
| 1942 | } | ||
| 1943 | #endif /* TIF_RESTORE_SIGMASK */ | ||
| 1944 | |||
| 1709 | #if defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE) | 1945 | #if defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE) |
| 1710 | /* Stuff for NFS server syscalls... */ | 1946 | /* Stuff for NFS server syscalls... */ |
| 1711 | struct compat_nfsctl_svc { | 1947 | struct compat_nfsctl_svc { |
