diff options
Diffstat (limited to 'fs')
47 files changed, 1429 insertions, 608 deletions
diff --git a/fs/9p/Makefile b/fs/9p/Makefile index 3d023089707e..2f4ce43f7b6c 100644 --- a/fs/9p/Makefile +++ b/fs/9p/Makefile | |||
@@ -8,6 +8,7 @@ obj-$(CONFIG_9P_FS) := 9p2000.o | |||
8 | conv.o \ | 8 | conv.o \ |
9 | vfs_super.o \ | 9 | vfs_super.o \ |
10 | vfs_inode.o \ | 10 | vfs_inode.o \ |
11 | vfs_addr.o \ | ||
11 | vfs_file.o \ | 12 | vfs_file.o \ |
12 | vfs_dir.o \ | 13 | vfs_dir.o \ |
13 | vfs_dentry.o \ | 14 | vfs_dentry.o \ |
diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h index c78502ad00ed..69cf2905dc90 100644 --- a/fs/9p/v9fs_vfs.h +++ b/fs/9p/v9fs_vfs.h | |||
@@ -39,6 +39,7 @@ | |||
39 | */ | 39 | */ |
40 | 40 | ||
41 | extern struct file_system_type v9fs_fs_type; | 41 | extern struct file_system_type v9fs_fs_type; |
42 | extern struct address_space_operations v9fs_addr_operations; | ||
42 | extern struct file_operations v9fs_file_operations; | 43 | extern struct file_operations v9fs_file_operations; |
43 | extern struct file_operations v9fs_dir_operations; | 44 | extern struct file_operations v9fs_dir_operations; |
44 | extern struct dentry_operations v9fs_dentry_operations; | 45 | extern struct dentry_operations v9fs_dentry_operations; |
diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c new file mode 100644 index 000000000000..8100fb5171b7 --- /dev/null +++ b/fs/9p/vfs_addr.c | |||
@@ -0,0 +1,109 @@ | |||
1 | /* | ||
2 | * linux/fs/9p/vfs_addr.c | ||
3 | * | ||
4 | * This file contians vfs address (mmap) ops for 9P2000. | ||
5 | * | ||
6 | * Copyright (C) 2005 by Eric Van Hensbergen <ericvh@gmail.com> | ||
7 | * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to: | ||
21 | * Free Software Foundation | ||
22 | * 51 Franklin Street, Fifth Floor | ||
23 | * Boston, MA 02111-1301 USA | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #include <linux/module.h> | ||
28 | #include <linux/errno.h> | ||
29 | #include <linux/fs.h> | ||
30 | #include <linux/file.h> | ||
31 | #include <linux/stat.h> | ||
32 | #include <linux/string.h> | ||
33 | #include <linux/smp_lock.h> | ||
34 | #include <linux/inet.h> | ||
35 | #include <linux/version.h> | ||
36 | #include <linux/pagemap.h> | ||
37 | #include <linux/idr.h> | ||
38 | |||
39 | #include "debug.h" | ||
40 | #include "v9fs.h" | ||
41 | #include "9p.h" | ||
42 | #include "v9fs_vfs.h" | ||
43 | #include "fid.h" | ||
44 | |||
45 | /** | ||
46 | * v9fs_vfs_readpage - read an entire page in from 9P | ||
47 | * | ||
48 | * @file: file being read | ||
49 | * @page: structure to page | ||
50 | * | ||
51 | */ | ||
52 | |||
53 | static int v9fs_vfs_readpage(struct file *filp, struct page *page) | ||
54 | { | ||
55 | char *buffer = NULL; | ||
56 | int retval = -EIO; | ||
57 | loff_t offset = page_offset(page); | ||
58 | int count = PAGE_CACHE_SIZE; | ||
59 | struct inode *inode = filp->f_dentry->d_inode; | ||
60 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); | ||
61 | int rsize = v9ses->maxdata - V9FS_IOHDRSZ; | ||
62 | struct v9fs_fid *v9f = filp->private_data; | ||
63 | struct v9fs_fcall *fcall = NULL; | ||
64 | int fid = v9f->fid; | ||
65 | int total = 0; | ||
66 | int result = 0; | ||
67 | |||
68 | buffer = kmap(page); | ||
69 | do { | ||
70 | if (count < rsize) | ||
71 | rsize = count; | ||
72 | |||
73 | result = v9fs_t_read(v9ses, fid, offset, rsize, &fcall); | ||
74 | |||
75 | if (result < 0) { | ||
76 | printk(KERN_ERR "v9fs_t_read returned %d\n", | ||
77 | result); | ||
78 | |||
79 | kfree(fcall); | ||
80 | goto UnmapAndUnlock; | ||
81 | } else | ||
82 | offset += result; | ||
83 | |||
84 | memcpy(buffer, fcall->params.rread.data, result); | ||
85 | |||
86 | count -= result; | ||
87 | buffer += result; | ||
88 | total += result; | ||
89 | |||
90 | kfree(fcall); | ||
91 | |||
92 | if (result < rsize) | ||
93 | break; | ||
94 | } while (count); | ||
95 | |||
96 | memset(buffer, 0, count); | ||
97 | flush_dcache_page(page); | ||
98 | SetPageUptodate(page); | ||
99 | retval = 0; | ||
100 | |||
101 | UnmapAndUnlock: | ||
102 | kunmap(page); | ||
103 | unlock_page(page); | ||
104 | return retval; | ||
105 | } | ||
106 | |||
107 | struct address_space_operations v9fs_addr_operations = { | ||
108 | .readpage = v9fs_vfs_readpage, | ||
109 | }; | ||
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index 6852f0eb96ed..c7e14d917215 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c | |||
@@ -289,6 +289,9 @@ v9fs_file_write(struct file *filp, const char __user * data, | |||
289 | total += result; | 289 | total += result; |
290 | } while (count); | 290 | } while (count); |
291 | 291 | ||
292 | if(inode->i_mapping->nrpages) | ||
293 | invalidate_inode_pages2(inode->i_mapping); | ||
294 | |||
292 | return total; | 295 | return total; |
293 | } | 296 | } |
294 | 297 | ||
@@ -299,4 +302,5 @@ struct file_operations v9fs_file_operations = { | |||
299 | .open = v9fs_file_open, | 302 | .open = v9fs_file_open, |
300 | .release = v9fs_dir_release, | 303 | .release = v9fs_dir_release, |
301 | .lock = v9fs_file_lock, | 304 | .lock = v9fs_file_lock, |
305 | .mmap = generic_file_mmap, | ||
302 | }; | 306 | }; |
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index a17b28854288..91f552454c76 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c | |||
@@ -177,6 +177,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode) | |||
177 | inode->i_blocks = 0; | 177 | inode->i_blocks = 0; |
178 | inode->i_rdev = 0; | 178 | inode->i_rdev = 0; |
179 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | 179 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; |
180 | inode->i_mapping->a_ops = &v9fs_addr_operations; | ||
180 | 181 | ||
181 | switch (mode & S_IFMT) { | 182 | switch (mode & S_IFMT) { |
182 | case S_IFIFO: | 183 | case S_IFIFO: |
diff --git a/fs/compat.c b/fs/compat.c index 2468ac1df2f0..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 | ||
@@ -1290,7 +1318,17 @@ out: | |||
1290 | asmlinkage long | 1318 | asmlinkage long |
1291 | compat_sys_open(const char __user *filename, int flags, int mode) | 1319 | compat_sys_open(const char __user *filename, int flags, int mode) |
1292 | { | 1320 | { |
1293 | 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); | ||
1294 | } | 1332 | } |
1295 | 1333 | ||
1296 | /* | 1334 | /* |
@@ -1621,36 +1659,14 @@ static void select_bits_free(void *bits, int size) | |||
1621 | #define MAX_SELECT_SECONDS \ | 1659 | #define MAX_SELECT_SECONDS \ |
1622 | ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1) | 1660 | ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1) |
1623 | 1661 | ||
1624 | asmlinkage long | 1662 | int compat_core_sys_select(int n, compat_ulong_t __user *inp, |
1625 | 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) |
1626 | compat_ulong_t __user *exp, struct compat_timeval __user *tvp) | ||
1627 | { | 1664 | { |
1628 | fd_set_bits fds; | 1665 | fd_set_bits fds; |
1629 | char *bits; | 1666 | char *bits; |
1630 | long timeout; | ||
1631 | int size, max_fdset, ret = -EINVAL; | 1667 | int size, max_fdset, ret = -EINVAL; |
1632 | struct fdtable *fdt; | 1668 | struct fdtable *fdt; |
1633 | 1669 | ||
1634 | timeout = MAX_SCHEDULE_TIMEOUT; | ||
1635 | if (tvp) { | ||
1636 | time_t sec, usec; | ||
1637 | |||
1638 | if (!access_ok(VERIFY_READ, tvp, sizeof(*tvp)) | ||
1639 | || __get_user(sec, &tvp->tv_sec) | ||
1640 | || __get_user(usec, &tvp->tv_usec)) { | ||
1641 | ret = -EFAULT; | ||
1642 | goto out_nofds; | ||
1643 | } | ||
1644 | |||
1645 | if (sec < 0 || usec < 0) | ||
1646 | goto out_nofds; | ||
1647 | |||
1648 | if ((unsigned long) sec < MAX_SELECT_SECONDS) { | ||
1649 | timeout = ROUND_UP(usec, 1000000/HZ); | ||
1650 | timeout += sec * (unsigned long) HZ; | ||
1651 | } | ||
1652 | } | ||
1653 | |||
1654 | if (n < 0) | 1670 | if (n < 0) |
1655 | goto out_nofds; | 1671 | goto out_nofds; |
1656 | 1672 | ||
@@ -1687,19 +1703,7 @@ compat_sys_select(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp | |||
1687 | zero_fd_set(n, fds.res_out); | 1703 | zero_fd_set(n, fds.res_out); |
1688 | zero_fd_set(n, fds.res_ex); | 1704 | zero_fd_set(n, fds.res_ex); |
1689 | 1705 | ||
1690 | ret = do_select(n, &fds, &timeout); | 1706 | ret = do_select(n, &fds, timeout); |
1691 | |||
1692 | if (tvp && !(current->personality & STICKY_TIMEOUTS)) { | ||
1693 | time_t sec = 0, usec = 0; | ||
1694 | if (timeout) { | ||
1695 | sec = timeout / HZ; | ||
1696 | usec = timeout % HZ; | ||
1697 | usec *= (1000000/HZ); | ||
1698 | } | ||
1699 | if (put_user(sec, &tvp->tv_sec) || | ||
1700 | put_user(usec, &tvp->tv_usec)) | ||
1701 | ret = -EFAULT; | ||
1702 | } | ||
1703 | 1707 | ||
1704 | if (ret < 0) | 1708 | if (ret < 0) |
1705 | goto out; | 1709 | goto out; |
@@ -1720,6 +1724,224 @@ out_nofds: | |||
1720 | return ret; | 1724 | return ret; |
1721 | } | 1725 | } |
1722 | 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 | |||
1723 | #if defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE) | 1945 | #if defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE) |
1724 | /* Stuff for NFS server syscalls... */ | 1946 | /* Stuff for NFS server syscalls... */ |
1725 | struct compat_nfsctl_svc { | 1947 | struct compat_nfsctl_svc { |
@@ -477,7 +477,7 @@ struct file *open_exec(const char *name) | |||
477 | int err; | 477 | int err; |
478 | struct file *file; | 478 | struct file *file; |
479 | 479 | ||
480 | err = path_lookup_open(name, LOOKUP_FOLLOW, &nd, FMODE_READ); | 480 | err = path_lookup_open(AT_FDCWD, name, LOOKUP_FOLLOW, &nd, FMODE_READ); |
481 | file = ERR_PTR(err); | 481 | file = ERR_PTR(err); |
482 | 482 | ||
483 | if (!err) { | 483 | if (!err) { |
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c index 5bfe40085fbc..b06b54f1bbbb 100644 --- a/fs/exportfs/expfs.c +++ b/fs/exportfs/expfs.c | |||
@@ -11,6 +11,33 @@ struct export_operations export_op_default; | |||
11 | 11 | ||
12 | #define dprintk(fmt, args...) do{}while(0) | 12 | #define dprintk(fmt, args...) do{}while(0) |
13 | 13 | ||
14 | static struct dentry * | ||
15 | find_acceptable_alias(struct dentry *result, | ||
16 | int (*acceptable)(void *context, struct dentry *dentry), | ||
17 | void *context) | ||
18 | { | ||
19 | struct dentry *dentry, *toput = NULL; | ||
20 | |||
21 | spin_lock(&dcache_lock); | ||
22 | list_for_each_entry(dentry, &result->d_inode->i_dentry, d_alias) { | ||
23 | dget_locked(dentry); | ||
24 | spin_unlock(&dcache_lock); | ||
25 | if (toput) | ||
26 | dput(toput); | ||
27 | if (dentry != result && acceptable(context, dentry)) { | ||
28 | dput(result); | ||
29 | return dentry; | ||
30 | } | ||
31 | spin_lock(&dcache_lock); | ||
32 | toput = dentry; | ||
33 | } | ||
34 | spin_unlock(&dcache_lock); | ||
35 | |||
36 | if (toput) | ||
37 | dput(toput); | ||
38 | return NULL; | ||
39 | } | ||
40 | |||
14 | /** | 41 | /** |
15 | * find_exported_dentry - helper routine to implement export_operations->decode_fh | 42 | * find_exported_dentry - helper routine to implement export_operations->decode_fh |
16 | * @sb: The &super_block identifying the filesystem | 43 | * @sb: The &super_block identifying the filesystem |
@@ -52,8 +79,7 @@ find_exported_dentry(struct super_block *sb, void *obj, void *parent, | |||
52 | struct dentry *target_dir; | 79 | struct dentry *target_dir; |
53 | int err; | 80 | int err; |
54 | struct export_operations *nops = sb->s_export_op; | 81 | struct export_operations *nops = sb->s_export_op; |
55 | struct list_head *le, *head; | 82 | struct dentry *alias; |
56 | struct dentry *toput = NULL; | ||
57 | int noprogress; | 83 | int noprogress; |
58 | char nbuf[NAME_MAX+1]; | 84 | char nbuf[NAME_MAX+1]; |
59 | 85 | ||
@@ -79,27 +105,10 @@ find_exported_dentry(struct super_block *sb, void *obj, void *parent, | |||
79 | /* there is no other dentry, so fail */ | 105 | /* there is no other dentry, so fail */ |
80 | goto err_result; | 106 | goto err_result; |
81 | } | 107 | } |
82 | /* try any other aliases */ | 108 | |
83 | spin_lock(&dcache_lock); | 109 | alias = find_acceptable_alias(result, acceptable, context); |
84 | head = &result->d_inode->i_dentry; | 110 | if (alias) |
85 | list_for_each(le, head) { | 111 | return alias; |
86 | struct dentry *dentry = list_entry(le, struct dentry, d_alias); | ||
87 | dget_locked(dentry); | ||
88 | spin_unlock(&dcache_lock); | ||
89 | if (toput) | ||
90 | dput(toput); | ||
91 | toput = NULL; | ||
92 | if (dentry != result && | ||
93 | acceptable(context, dentry)) { | ||
94 | dput(result); | ||
95 | return dentry; | ||
96 | } | ||
97 | spin_lock(&dcache_lock); | ||
98 | toput = dentry; | ||
99 | } | ||
100 | spin_unlock(&dcache_lock); | ||
101 | if (toput) | ||
102 | dput(toput); | ||
103 | } | 112 | } |
104 | 113 | ||
105 | /* It's a directory, or we are required to confirm the file's | 114 | /* It's a directory, or we are required to confirm the file's |
@@ -258,26 +267,10 @@ find_exported_dentry(struct super_block *sb, void *obj, void *parent, | |||
258 | /* now result is properly connected, it is our best bet */ | 267 | /* now result is properly connected, it is our best bet */ |
259 | if (acceptable(context, result)) | 268 | if (acceptable(context, result)) |
260 | return result; | 269 | return result; |
261 | /* one last try of the aliases.. */ | 270 | |
262 | spin_lock(&dcache_lock); | 271 | alias = find_acceptable_alias(result, acceptable, context); |
263 | toput = NULL; | 272 | if (alias) |
264 | head = &result->d_inode->i_dentry; | 273 | return alias; |
265 | list_for_each(le, head) { | ||
266 | struct dentry *dentry = list_entry(le, struct dentry, d_alias); | ||
267 | dget_locked(dentry); | ||
268 | spin_unlock(&dcache_lock); | ||
269 | if (toput) dput(toput); | ||
270 | if (dentry != result && | ||
271 | acceptable(context, dentry)) { | ||
272 | dput(result); | ||
273 | return dentry; | ||
274 | } | ||
275 | spin_lock(&dcache_lock); | ||
276 | toput = dentry; | ||
277 | } | ||
278 | spin_unlock(&dcache_lock); | ||
279 | if (toput) | ||
280 | dput(toput); | ||
281 | 274 | ||
282 | /* drat - I just cannot find anything acceptable */ | 275 | /* drat - I just cannot find anything acceptable */ |
283 | dput(result); | 276 | dput(result); |
diff --git a/fs/hfs/bfind.c b/fs/hfs/bfind.c index 89450ae32228..f13f1494d4fe 100644 --- a/fs/hfs/bfind.c +++ b/fs/hfs/bfind.c | |||
@@ -64,7 +64,6 @@ int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd) | |||
64 | else | 64 | else |
65 | e = rec - 1; | 65 | e = rec - 1; |
66 | } while (b <= e); | 66 | } while (b <= e); |
67 | //printk("%d: %d,%d,%d\n", bnode->this, b, e, rec); | ||
68 | if (rec != e && e >= 0) { | 67 | if (rec != e && e >= 0) { |
69 | len = hfs_brec_lenoff(bnode, e, &off); | 68 | len = hfs_brec_lenoff(bnode, e, &off); |
70 | keylen = hfs_brec_keylen(bnode, e); | 69 | keylen = hfs_brec_keylen(bnode, e); |
@@ -127,7 +126,7 @@ int hfs_brec_find(struct hfs_find_data *fd) | |||
127 | return res; | 126 | return res; |
128 | 127 | ||
129 | invalid: | 128 | invalid: |
130 | printk("HFS: inconsistency in B*Tree (%d,%d,%d,%u,%u)\n", | 129 | printk(KERN_ERR "hfs: inconsistency in B*Tree (%d,%d,%d,%u,%u)\n", |
131 | height, bnode->height, bnode->type, nidx, parent); | 130 | height, bnode->height, bnode->type, nidx, parent); |
132 | res = -EIO; | 131 | res = -EIO; |
133 | release: | 132 | release: |
diff --git a/fs/hfs/bnode.c b/fs/hfs/bnode.c index 3d5cdc6847c0..a7a7d77f3fd3 100644 --- a/fs/hfs/bnode.c +++ b/fs/hfs/bnode.c | |||
@@ -198,7 +198,7 @@ void hfs_bnode_unlink(struct hfs_bnode *node) | |||
198 | 198 | ||
199 | // move down? | 199 | // move down? |
200 | if (!node->prev && !node->next) { | 200 | if (!node->prev && !node->next) { |
201 | printk("hfs_btree_del_level\n"); | 201 | printk(KERN_DEBUG "hfs_btree_del_level\n"); |
202 | } | 202 | } |
203 | if (!node->parent) { | 203 | if (!node->parent) { |
204 | tree->root = 0; | 204 | tree->root = 0; |
@@ -219,7 +219,7 @@ struct hfs_bnode *hfs_bnode_findhash(struct hfs_btree *tree, u32 cnid) | |||
219 | struct hfs_bnode *node; | 219 | struct hfs_bnode *node; |
220 | 220 | ||
221 | if (cnid >= tree->node_count) { | 221 | if (cnid >= tree->node_count) { |
222 | printk("HFS: request for non-existent node %d in B*Tree\n", cnid); | 222 | printk(KERN_ERR "hfs: request for non-existent node %d in B*Tree\n", cnid); |
223 | return NULL; | 223 | return NULL; |
224 | } | 224 | } |
225 | 225 | ||
@@ -242,7 +242,7 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid) | |||
242 | loff_t off; | 242 | loff_t off; |
243 | 243 | ||
244 | if (cnid >= tree->node_count) { | 244 | if (cnid >= tree->node_count) { |
245 | printk("HFS: request for non-existent node %d in B*Tree\n", cnid); | 245 | printk(KERN_ERR "hfs: request for non-existent node %d in B*Tree\n", cnid); |
246 | return NULL; | 246 | return NULL; |
247 | } | 247 | } |
248 | 248 | ||
diff --git a/fs/hfs/brec.c b/fs/hfs/brec.c index 7d8fff2c25fc..5c87cf4801fc 100644 --- a/fs/hfs/brec.c +++ b/fs/hfs/brec.c | |||
@@ -362,7 +362,7 @@ again: | |||
362 | end_off = hfs_bnode_read_u16(parent, end_rec_off); | 362 | end_off = hfs_bnode_read_u16(parent, end_rec_off); |
363 | if (end_rec_off - end_off < diff) { | 363 | if (end_rec_off - end_off < diff) { |
364 | 364 | ||
365 | printk("splitting index node...\n"); | 365 | printk(KERN_DEBUG "hfs: splitting index node...\n"); |
366 | fd->bnode = parent; | 366 | fd->bnode = parent; |
367 | new_node = hfs_bnode_split(fd); | 367 | new_node = hfs_bnode_split(fd); |
368 | if (IS_ERR(new_node)) | 368 | if (IS_ERR(new_node)) |
diff --git a/fs/hfs/btree.c b/fs/hfs/btree.c index 394725efa1c8..7bb11edd1488 100644 --- a/fs/hfs/btree.c +++ b/fs/hfs/btree.c | |||
@@ -111,7 +111,7 @@ void hfs_btree_close(struct hfs_btree *tree) | |||
111 | while ((node = tree->node_hash[i])) { | 111 | while ((node = tree->node_hash[i])) { |
112 | tree->node_hash[i] = node->next_hash; | 112 | tree->node_hash[i] = node->next_hash; |
113 | if (atomic_read(&node->refcnt)) | 113 | if (atomic_read(&node->refcnt)) |
114 | printk("HFS: node %d:%d still has %d user(s)!\n", | 114 | printk(KERN_ERR "hfs: node %d:%d still has %d user(s)!\n", |
115 | node->tree->cnid, node->this, atomic_read(&node->refcnt)); | 115 | node->tree->cnid, node->this, atomic_read(&node->refcnt)); |
116 | hfs_bnode_free(node); | 116 | hfs_bnode_free(node); |
117 | tree->node_hash_cnt--; | 117 | tree->node_hash_cnt--; |
@@ -252,7 +252,7 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree) | |||
252 | kunmap(*pagep); | 252 | kunmap(*pagep); |
253 | nidx = node->next; | 253 | nidx = node->next; |
254 | if (!nidx) { | 254 | if (!nidx) { |
255 | printk("create new bmap node...\n"); | 255 | printk(KERN_DEBUG "hfs: create new bmap node...\n"); |
256 | next_node = hfs_bmap_new_bmap(node, idx); | 256 | next_node = hfs_bmap_new_bmap(node, idx); |
257 | } else | 257 | } else |
258 | next_node = hfs_bnode_find(tree, nidx); | 258 | next_node = hfs_bnode_find(tree, nidx); |
@@ -292,7 +292,7 @@ void hfs_bmap_free(struct hfs_bnode *node) | |||
292 | hfs_bnode_put(node); | 292 | hfs_bnode_put(node); |
293 | if (!i) { | 293 | if (!i) { |
294 | /* panic */; | 294 | /* panic */; |
295 | printk("HFS: unable to free bnode %u. bmap not found!\n", node->this); | 295 | printk(KERN_CRIT "hfs: unable to free bnode %u. bmap not found!\n", node->this); |
296 | return; | 296 | return; |
297 | } | 297 | } |
298 | node = hfs_bnode_find(tree, i); | 298 | node = hfs_bnode_find(tree, i); |
@@ -300,7 +300,7 @@ void hfs_bmap_free(struct hfs_bnode *node) | |||
300 | return; | 300 | return; |
301 | if (node->type != HFS_NODE_MAP) { | 301 | if (node->type != HFS_NODE_MAP) { |
302 | /* panic */; | 302 | /* panic */; |
303 | printk("HFS: invalid bmap found! (%u,%d)\n", node->this, node->type); | 303 | printk(KERN_CRIT "hfs: invalid bmap found! (%u,%d)\n", node->this, node->type); |
304 | hfs_bnode_put(node); | 304 | hfs_bnode_put(node); |
305 | return; | 305 | return; |
306 | } | 306 | } |
@@ -313,7 +313,7 @@ void hfs_bmap_free(struct hfs_bnode *node) | |||
313 | m = 1 << (~nidx & 7); | 313 | m = 1 << (~nidx & 7); |
314 | byte = data[off]; | 314 | byte = data[off]; |
315 | if (!(byte & m)) { | 315 | if (!(byte & m)) { |
316 | printk("HFS: trying to free free bnode %u(%d)\n", node->this, node->type); | 316 | printk(KERN_CRIT "hfs: trying to free free bnode %u(%d)\n", node->this, node->type); |
317 | kunmap(page); | 317 | kunmap(page); |
318 | hfs_bnode_put(node); | 318 | hfs_bnode_put(node); |
319 | return; | 319 | return; |
diff --git a/fs/hfs/catalog.c b/fs/hfs/catalog.c index 2fcd679f0238..ba851576ebb1 100644 --- a/fs/hfs/catalog.c +++ b/fs/hfs/catalog.c | |||
@@ -184,7 +184,7 @@ int hfs_cat_find_brec(struct super_block *sb, u32 cnid, | |||
184 | 184 | ||
185 | type = rec.type; | 185 | type = rec.type; |
186 | if (type != HFS_CDR_THD && type != HFS_CDR_FTH) { | 186 | if (type != HFS_CDR_THD && type != HFS_CDR_FTH) { |
187 | printk("HFS-fs: Found bad thread record in catalog\n"); | 187 | printk(KERN_ERR "hfs: found bad thread record in catalog\n"); |
188 | return -EIO; | 188 | return -EIO; |
189 | } | 189 | } |
190 | 190 | ||
diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c index e1f24befba58..534e5a7480ef 100644 --- a/fs/hfs/dir.c +++ b/fs/hfs/dir.c | |||
@@ -81,12 +81,12 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
81 | case 1: | 81 | case 1: |
82 | hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength); | 82 | hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength); |
83 | if (entry.type != HFS_CDR_THD) { | 83 | if (entry.type != HFS_CDR_THD) { |
84 | printk("HFS: bad catalog folder thread\n"); | 84 | printk(KERN_ERR "hfs: bad catalog folder thread\n"); |
85 | err = -EIO; | 85 | err = -EIO; |
86 | goto out; | 86 | goto out; |
87 | } | 87 | } |
88 | //if (fd.entrylength < HFS_MIN_THREAD_SZ) { | 88 | //if (fd.entrylength < HFS_MIN_THREAD_SZ) { |
89 | // printk("HFS: truncated catalog thread\n"); | 89 | // printk(KERN_ERR "hfs: truncated catalog thread\n"); |
90 | // err = -EIO; | 90 | // err = -EIO; |
91 | // goto out; | 91 | // goto out; |
92 | //} | 92 | //} |
@@ -105,7 +105,7 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
105 | 105 | ||
106 | for (;;) { | 106 | for (;;) { |
107 | if (be32_to_cpu(fd.key->cat.ParID) != inode->i_ino) { | 107 | if (be32_to_cpu(fd.key->cat.ParID) != inode->i_ino) { |
108 | printk("HFS: walked past end of dir\n"); | 108 | printk(KERN_ERR "hfs: walked past end of dir\n"); |
109 | err = -EIO; | 109 | err = -EIO; |
110 | goto out; | 110 | goto out; |
111 | } | 111 | } |
@@ -114,7 +114,7 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
114 | len = hfs_mac2asc(sb, strbuf, &fd.key->cat.CName); | 114 | len = hfs_mac2asc(sb, strbuf, &fd.key->cat.CName); |
115 | if (type == HFS_CDR_DIR) { | 115 | if (type == HFS_CDR_DIR) { |
116 | if (fd.entrylength < sizeof(struct hfs_cat_dir)) { | 116 | if (fd.entrylength < sizeof(struct hfs_cat_dir)) { |
117 | printk("HFS: small dir entry\n"); | 117 | printk(KERN_ERR "hfs: small dir entry\n"); |
118 | err = -EIO; | 118 | err = -EIO; |
119 | goto out; | 119 | goto out; |
120 | } | 120 | } |
@@ -123,7 +123,7 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
123 | break; | 123 | break; |
124 | } else if (type == HFS_CDR_FIL) { | 124 | } else if (type == HFS_CDR_FIL) { |
125 | if (fd.entrylength < sizeof(struct hfs_cat_file)) { | 125 | if (fd.entrylength < sizeof(struct hfs_cat_file)) { |
126 | printk("HFS: small file entry\n"); | 126 | printk(KERN_ERR "hfs: small file entry\n"); |
127 | err = -EIO; | 127 | err = -EIO; |
128 | goto out; | 128 | goto out; |
129 | } | 129 | } |
@@ -131,7 +131,7 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
131 | be32_to_cpu(entry.file.FlNum), DT_REG)) | 131 | be32_to_cpu(entry.file.FlNum), DT_REG)) |
132 | break; | 132 | break; |
133 | } else { | 133 | } else { |
134 | printk("HFS: bad catalog entry type %d\n", type); | 134 | printk(KERN_ERR "hfs: bad catalog entry type %d\n", type); |
135 | err = -EIO; | 135 | err = -EIO; |
136 | goto out; | 136 | goto out; |
137 | } | 137 | } |
diff --git a/fs/hfs/hfs_fs.h b/fs/hfs/hfs_fs.h index cc5dcd52e23d..18ce47ab1b71 100644 --- a/fs/hfs/hfs_fs.h +++ b/fs/hfs/hfs_fs.h | |||
@@ -35,9 +35,6 @@ | |||
35 | #define dprint(flg, fmt, args...) \ | 35 | #define dprint(flg, fmt, args...) \ |
36 | if (flg & DBG_MASK) printk(fmt , ## args) | 36 | if (flg & DBG_MASK) printk(fmt , ## args) |
37 | 37 | ||
38 | #define hfs_warn(format, args...) printk(KERN_WARNING format , ## args) | ||
39 | #define hfs_error(format, args...) printk(KERN_ERR format , ## args) | ||
40 | |||
41 | /* | 38 | /* |
42 | * struct hfs_inode_info | 39 | * struct hfs_inode_info |
43 | * | 40 | * |
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c index 050a49276499..39fd85b9b916 100644 --- a/fs/hfs/inode.c +++ b/fs/hfs/inode.c | |||
@@ -95,7 +95,6 @@ static int hfs_releasepage(struct page *page, gfp_t mask) | |||
95 | } while (--i && nidx < tree->node_count); | 95 | } while (--i && nidx < tree->node_count); |
96 | spin_unlock(&tree->hash_lock); | 96 | spin_unlock(&tree->hash_lock); |
97 | } | 97 | } |
98 | //printk("releasepage: %lu,%x = %d\n", page->index, mask, res); | ||
99 | return res ? try_to_free_buffers(page) : 0; | 98 | return res ? try_to_free_buffers(page) : 0; |
100 | } | 99 | } |
101 | 100 | ||
diff --git a/fs/hfs/mdb.c b/fs/hfs/mdb.c index 0a473f79c89f..b4651e128d7f 100644 --- a/fs/hfs/mdb.c +++ b/fs/hfs/mdb.c | |||
@@ -47,7 +47,7 @@ static int hfs_get_last_session(struct super_block *sb, | |||
47 | *start = (sector_t)te.cdte_addr.lba << 2; | 47 | *start = (sector_t)te.cdte_addr.lba << 2; |
48 | return 0; | 48 | return 0; |
49 | } | 49 | } |
50 | printk(KERN_ERR "HFS: Invalid session number or type of track\n"); | 50 | printk(KERN_ERR "hfs: invalid session number or type of track\n"); |
51 | return -EINVAL; | 51 | return -EINVAL; |
52 | } | 52 | } |
53 | ms_info.addr_format = CDROM_LBA; | 53 | ms_info.addr_format = CDROM_LBA; |
@@ -100,7 +100,7 @@ int hfs_mdb_get(struct super_block *sb) | |||
100 | 100 | ||
101 | HFS_SB(sb)->alloc_blksz = size = be32_to_cpu(mdb->drAlBlkSiz); | 101 | HFS_SB(sb)->alloc_blksz = size = be32_to_cpu(mdb->drAlBlkSiz); |
102 | if (!size || (size & (HFS_SECTOR_SIZE - 1))) { | 102 | if (!size || (size & (HFS_SECTOR_SIZE - 1))) { |
103 | hfs_warn("hfs_fs: bad allocation block size %d\n", size); | 103 | printk(KERN_ERR "hfs: bad allocation block size %d\n", size); |
104 | goto out_bh; | 104 | goto out_bh; |
105 | } | 105 | } |
106 | 106 | ||
@@ -117,7 +117,7 @@ int hfs_mdb_get(struct super_block *sb) | |||
117 | size >>= 1; | 117 | size >>= 1; |
118 | brelse(bh); | 118 | brelse(bh); |
119 | if (!sb_set_blocksize(sb, size)) { | 119 | if (!sb_set_blocksize(sb, size)) { |
120 | printk("hfs_fs: unable to set blocksize to %u\n", size); | 120 | printk(KERN_ERR "hfs: unable to set blocksize to %u\n", size); |
121 | goto out; | 121 | goto out; |
122 | } | 122 | } |
123 | 123 | ||
@@ -161,8 +161,8 @@ int hfs_mdb_get(struct super_block *sb) | |||
161 | } | 161 | } |
162 | 162 | ||
163 | if (!HFS_SB(sb)->alt_mdb) { | 163 | if (!HFS_SB(sb)->alt_mdb) { |
164 | hfs_warn("hfs_fs: unable to locate alternate MDB\n"); | 164 | printk(KERN_WARNING "hfs: unable to locate alternate MDB\n"); |
165 | hfs_warn("hfs_fs: continuing without an alternate MDB\n"); | 165 | printk(KERN_WARNING "hfs: continuing without an alternate MDB\n"); |
166 | } | 166 | } |
167 | 167 | ||
168 | HFS_SB(sb)->bitmap = (__be32 *)__get_free_pages(GFP_KERNEL, PAGE_SIZE < 8192 ? 1 : 0); | 168 | HFS_SB(sb)->bitmap = (__be32 *)__get_free_pages(GFP_KERNEL, PAGE_SIZE < 8192 ? 1 : 0); |
@@ -177,7 +177,7 @@ int hfs_mdb_get(struct super_block *sb) | |||
177 | while (size) { | 177 | while (size) { |
178 | bh = sb_bread(sb, off >> sb->s_blocksize_bits); | 178 | bh = sb_bread(sb, off >> sb->s_blocksize_bits); |
179 | if (!bh) { | 179 | if (!bh) { |
180 | hfs_warn("hfs_fs: unable to read volume bitmap\n"); | 180 | printk(KERN_ERR "hfs: unable to read volume bitmap\n"); |
181 | goto out; | 181 | goto out; |
182 | } | 182 | } |
183 | off2 = off & (sb->s_blocksize - 1); | 183 | off2 = off & (sb->s_blocksize - 1); |
@@ -191,23 +191,23 @@ int hfs_mdb_get(struct super_block *sb) | |||
191 | 191 | ||
192 | HFS_SB(sb)->ext_tree = hfs_btree_open(sb, HFS_EXT_CNID, hfs_ext_keycmp); | 192 | HFS_SB(sb)->ext_tree = hfs_btree_open(sb, HFS_EXT_CNID, hfs_ext_keycmp); |
193 | if (!HFS_SB(sb)->ext_tree) { | 193 | if (!HFS_SB(sb)->ext_tree) { |
194 | hfs_warn("hfs_fs: unable to open extent tree\n"); | 194 | printk(KERN_ERR "hfs: unable to open extent tree\n"); |
195 | goto out; | 195 | goto out; |
196 | } | 196 | } |
197 | HFS_SB(sb)->cat_tree = hfs_btree_open(sb, HFS_CAT_CNID, hfs_cat_keycmp); | 197 | HFS_SB(sb)->cat_tree = hfs_btree_open(sb, HFS_CAT_CNID, hfs_cat_keycmp); |
198 | if (!HFS_SB(sb)->cat_tree) { | 198 | if (!HFS_SB(sb)->cat_tree) { |
199 | hfs_warn("hfs_fs: unable to open catalog tree\n"); | 199 | printk(KERN_ERR "hfs: unable to open catalog tree\n"); |
200 | goto out; | 200 | goto out; |
201 | } | 201 | } |
202 | 202 | ||
203 | attrib = mdb->drAtrb; | 203 | attrib = mdb->drAtrb; |
204 | if (!(attrib & cpu_to_be16(HFS_SB_ATTRIB_UNMNT))) { | 204 | if (!(attrib & cpu_to_be16(HFS_SB_ATTRIB_UNMNT))) { |
205 | hfs_warn("HFS-fs warning: Filesystem was not cleanly unmounted, " | 205 | printk(KERN_WARNING "hfs: filesystem was not cleanly unmounted, " |
206 | "running fsck.hfs is recommended. mounting read-only.\n"); | 206 | "running fsck.hfs is recommended. mounting read-only.\n"); |
207 | sb->s_flags |= MS_RDONLY; | 207 | sb->s_flags |= MS_RDONLY; |
208 | } | 208 | } |
209 | if ((attrib & cpu_to_be16(HFS_SB_ATTRIB_SLOCK))) { | 209 | if ((attrib & cpu_to_be16(HFS_SB_ATTRIB_SLOCK))) { |
210 | hfs_warn("HFS-fs: Filesystem is marked locked, mounting read-only.\n"); | 210 | printk(KERN_WARNING "hfs: filesystem is marked locked, mounting read-only.\n"); |
211 | sb->s_flags |= MS_RDONLY; | 211 | sb->s_flags |= MS_RDONLY; |
212 | } | 212 | } |
213 | if (!(sb->s_flags & MS_RDONLY)) { | 213 | if (!(sb->s_flags & MS_RDONLY)) { |
@@ -303,7 +303,7 @@ void hfs_mdb_commit(struct super_block *sb) | |||
303 | while (size) { | 303 | while (size) { |
304 | bh = sb_bread(sb, block); | 304 | bh = sb_bread(sb, block); |
305 | if (!bh) { | 305 | if (!bh) { |
306 | hfs_warn("hfs_fs: unable to read volume bitmap\n"); | 306 | printk(KERN_ERR "hfs: unable to read volume bitmap\n"); |
307 | break; | 307 | break; |
308 | } | 308 | } |
309 | len = min((int)sb->s_blocksize - off, size); | 309 | len = min((int)sb->s_blocksize - off, size); |
diff --git a/fs/hfs/super.c b/fs/hfs/super.c index c5074aeafcae..1181d116117d 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c | |||
@@ -101,12 +101,12 @@ static int hfs_remount(struct super_block *sb, int *flags, char *data) | |||
101 | return 0; | 101 | return 0; |
102 | if (!(*flags & MS_RDONLY)) { | 102 | if (!(*flags & MS_RDONLY)) { |
103 | if (!(HFS_SB(sb)->mdb->drAtrb & cpu_to_be16(HFS_SB_ATTRIB_UNMNT))) { | 103 | if (!(HFS_SB(sb)->mdb->drAtrb & cpu_to_be16(HFS_SB_ATTRIB_UNMNT))) { |
104 | printk("HFS-fs warning: Filesystem was not cleanly unmounted, " | 104 | printk(KERN_WARNING "hfs: filesystem was not cleanly unmounted, " |
105 | "running fsck.hfs is recommended. leaving read-only.\n"); | 105 | "running fsck.hfs is recommended. leaving read-only.\n"); |
106 | sb->s_flags |= MS_RDONLY; | 106 | sb->s_flags |= MS_RDONLY; |
107 | *flags |= MS_RDONLY; | 107 | *flags |= MS_RDONLY; |
108 | } else if (HFS_SB(sb)->mdb->drAtrb & cpu_to_be16(HFS_SB_ATTRIB_SLOCK)) { | 108 | } else if (HFS_SB(sb)->mdb->drAtrb & cpu_to_be16(HFS_SB_ATTRIB_SLOCK)) { |
109 | printk("HFS-fs: Filesystem is marked locked, leaving read-only.\n"); | 109 | printk(KERN_WARNING "hfs: filesystem is marked locked, leaving read-only.\n"); |
110 | sb->s_flags |= MS_RDONLY; | 110 | sb->s_flags |= MS_RDONLY; |
111 | *flags |= MS_RDONLY; | 111 | *flags |= MS_RDONLY; |
112 | } | 112 | } |
@@ -229,21 +229,21 @@ static int parse_options(char *options, struct hfs_sb_info *hsb) | |||
229 | switch (token) { | 229 | switch (token) { |
230 | case opt_uid: | 230 | case opt_uid: |
231 | if (match_int(&args[0], &tmp)) { | 231 | if (match_int(&args[0], &tmp)) { |
232 | printk("HFS: uid requires an argument\n"); | 232 | printk(KERN_ERR "hfs: uid requires an argument\n"); |
233 | return 0; | 233 | return 0; |
234 | } | 234 | } |
235 | hsb->s_uid = (uid_t)tmp; | 235 | hsb->s_uid = (uid_t)tmp; |
236 | break; | 236 | break; |
237 | case opt_gid: | 237 | case opt_gid: |
238 | if (match_int(&args[0], &tmp)) { | 238 | if (match_int(&args[0], &tmp)) { |
239 | printk("HFS: gid requires an argument\n"); | 239 | printk(KERN_ERR "hfs: gid requires an argument\n"); |
240 | return 0; | 240 | return 0; |
241 | } | 241 | } |
242 | hsb->s_gid = (gid_t)tmp; | 242 | hsb->s_gid = (gid_t)tmp; |
243 | break; | 243 | break; |
244 | case opt_umask: | 244 | case opt_umask: |
245 | if (match_octal(&args[0], &tmp)) { | 245 | if (match_octal(&args[0], &tmp)) { |
246 | printk("HFS: umask requires a value\n"); | 246 | printk(KERN_ERR "hfs: umask requires a value\n"); |
247 | return 0; | 247 | return 0; |
248 | } | 248 | } |
249 | hsb->s_file_umask = (umode_t)tmp; | 249 | hsb->s_file_umask = (umode_t)tmp; |
@@ -251,39 +251,39 @@ static int parse_options(char *options, struct hfs_sb_info *hsb) | |||
251 | break; | 251 | break; |
252 | case opt_file_umask: | 252 | case opt_file_umask: |
253 | if (match_octal(&args[0], &tmp)) { | 253 | if (match_octal(&args[0], &tmp)) { |
254 | printk("HFS: file_umask requires a value\n"); | 254 | printk(KERN_ERR "hfs: file_umask requires a value\n"); |
255 | return 0; | 255 | return 0; |
256 | } | 256 | } |
257 | hsb->s_file_umask = (umode_t)tmp; | 257 | hsb->s_file_umask = (umode_t)tmp; |
258 | break; | 258 | break; |
259 | case opt_dir_umask: | 259 | case opt_dir_umask: |
260 | if (match_octal(&args[0], &tmp)) { | 260 | if (match_octal(&args[0], &tmp)) { |
261 | printk("HFS: dir_umask requires a value\n"); | 261 | printk(KERN_ERR "hfs: dir_umask requires a value\n"); |
262 | return 0; | 262 | return 0; |
263 | } | 263 | } |
264 | hsb->s_dir_umask = (umode_t)tmp; | 264 | hsb->s_dir_umask = (umode_t)tmp; |
265 | break; | 265 | break; |
266 | case opt_part: | 266 | case opt_part: |
267 | if (match_int(&args[0], &hsb->part)) { | 267 | if (match_int(&args[0], &hsb->part)) { |
268 | printk("HFS: part requires an argument\n"); | 268 | printk(KERN_ERR "hfs: part requires an argument\n"); |
269 | return 0; | 269 | return 0; |
270 | } | 270 | } |
271 | break; | 271 | break; |
272 | case opt_session: | 272 | case opt_session: |
273 | if (match_int(&args[0], &hsb->session)) { | 273 | if (match_int(&args[0], &hsb->session)) { |
274 | printk("HFS: session requires an argument\n"); | 274 | printk(KERN_ERR "hfs: session requires an argument\n"); |
275 | return 0; | 275 | return 0; |
276 | } | 276 | } |
277 | break; | 277 | break; |
278 | case opt_type: | 278 | case opt_type: |
279 | if (match_fourchar(&args[0], &hsb->s_type)) { | 279 | if (match_fourchar(&args[0], &hsb->s_type)) { |
280 | printk("HFS+-fs: type requires a 4 character value\n"); | 280 | printk(KERN_ERR "hfs: type requires a 4 character value\n"); |
281 | return 0; | 281 | return 0; |
282 | } | 282 | } |
283 | break; | 283 | break; |
284 | case opt_creator: | 284 | case opt_creator: |
285 | if (match_fourchar(&args[0], &hsb->s_creator)) { | 285 | if (match_fourchar(&args[0], &hsb->s_creator)) { |
286 | printk("HFS+-fs: creator requires a 4 character value\n"); | 286 | printk(KERN_ERR "hfs: creator requires a 4 character value\n"); |
287 | return 0; | 287 | return 0; |
288 | } | 288 | } |
289 | break; | 289 | break; |
@@ -292,13 +292,13 @@ static int parse_options(char *options, struct hfs_sb_info *hsb) | |||
292 | break; | 292 | break; |
293 | case opt_codepage: | 293 | case opt_codepage: |
294 | if (hsb->nls_disk) { | 294 | if (hsb->nls_disk) { |
295 | printk("HFS+-fs: unable to change codepage\n"); | 295 | printk(KERN_ERR "hfs: unable to change codepage\n"); |
296 | return 0; | 296 | return 0; |
297 | } | 297 | } |
298 | p = match_strdup(&args[0]); | 298 | p = match_strdup(&args[0]); |
299 | hsb->nls_disk = load_nls(p); | 299 | hsb->nls_disk = load_nls(p); |
300 | if (!hsb->nls_disk) { | 300 | if (!hsb->nls_disk) { |
301 | printk("HFS+-fs: unable to load codepage \"%s\"\n", p); | 301 | printk(KERN_ERR "hfs: unable to load codepage \"%s\"\n", p); |
302 | kfree(p); | 302 | kfree(p); |
303 | return 0; | 303 | return 0; |
304 | } | 304 | } |
@@ -306,13 +306,13 @@ static int parse_options(char *options, struct hfs_sb_info *hsb) | |||
306 | break; | 306 | break; |
307 | case opt_iocharset: | 307 | case opt_iocharset: |
308 | if (hsb->nls_io) { | 308 | if (hsb->nls_io) { |
309 | printk("HFS: unable to change iocharset\n"); | 309 | printk(KERN_ERR "hfs: unable to change iocharset\n"); |
310 | return 0; | 310 | return 0; |
311 | } | 311 | } |
312 | p = match_strdup(&args[0]); | 312 | p = match_strdup(&args[0]); |
313 | hsb->nls_io = load_nls(p); | 313 | hsb->nls_io = load_nls(p); |
314 | if (!hsb->nls_io) { | 314 | if (!hsb->nls_io) { |
315 | printk("HFS: unable to load iocharset \"%s\"\n", p); | 315 | printk(KERN_ERR "hfs: unable to load iocharset \"%s\"\n", p); |
316 | kfree(p); | 316 | kfree(p); |
317 | return 0; | 317 | return 0; |
318 | } | 318 | } |
@@ -326,7 +326,7 @@ static int parse_options(char *options, struct hfs_sb_info *hsb) | |||
326 | if (hsb->nls_disk && !hsb->nls_io) { | 326 | if (hsb->nls_disk && !hsb->nls_io) { |
327 | hsb->nls_io = load_nls_default(); | 327 | hsb->nls_io = load_nls_default(); |
328 | if (!hsb->nls_io) { | 328 | if (!hsb->nls_io) { |
329 | printk("HFS: unable to load default iocharset\n"); | 329 | printk(KERN_ERR "hfs: unable to load default iocharset\n"); |
330 | return 0; | 330 | return 0; |
331 | } | 331 | } |
332 | } | 332 | } |
@@ -364,7 +364,7 @@ static int hfs_fill_super(struct super_block *sb, void *data, int silent) | |||
364 | 364 | ||
365 | res = -EINVAL; | 365 | res = -EINVAL; |
366 | if (!parse_options((char *)data, sbi)) { | 366 | if (!parse_options((char *)data, sbi)) { |
367 | hfs_warn("hfs_fs: unable to parse mount options.\n"); | 367 | printk(KERN_ERR "hfs: unable to parse mount options.\n"); |
368 | goto bail; | 368 | goto bail; |
369 | } | 369 | } |
370 | 370 | ||
@@ -375,7 +375,7 @@ static int hfs_fill_super(struct super_block *sb, void *data, int silent) | |||
375 | res = hfs_mdb_get(sb); | 375 | res = hfs_mdb_get(sb); |
376 | if (res) { | 376 | if (res) { |
377 | if (!silent) | 377 | if (!silent) |
378 | hfs_warn("VFS: Can't find a HFS filesystem on dev %s.\n", | 378 | printk(KERN_WARNING "hfs: can't find a HFS filesystem on dev %s.\n", |
379 | hfs_mdb_name(sb)); | 379 | hfs_mdb_name(sb)); |
380 | res = -EINVAL; | 380 | res = -EINVAL; |
381 | goto bail; | 381 | goto bail; |
@@ -407,7 +407,7 @@ static int hfs_fill_super(struct super_block *sb, void *data, int silent) | |||
407 | bail_iput: | 407 | bail_iput: |
408 | iput(root_inode); | 408 | iput(root_inode); |
409 | bail_no_root: | 409 | bail_no_root: |
410 | hfs_warn("hfs_fs: get root inode failed.\n"); | 410 | printk(KERN_ERR "hfs: get root inode failed.\n"); |
411 | bail: | 411 | bail: |
412 | hfs_mdb_put(sb); | 412 | hfs_mdb_put(sb); |
413 | return res; | 413 | return res; |
@@ -454,7 +454,7 @@ static void __exit exit_hfs_fs(void) | |||
454 | { | 454 | { |
455 | unregister_filesystem(&hfs_fs_type); | 455 | unregister_filesystem(&hfs_fs_type); |
456 | if (kmem_cache_destroy(hfs_inode_cachep)) | 456 | if (kmem_cache_destroy(hfs_inode_cachep)) |
457 | printk(KERN_INFO "hfs_inode_cache: not all structures were freed\n"); | 457 | printk(KERN_ERR "hfs_inode_cache: not all structures were freed\n"); |
458 | } | 458 | } |
459 | 459 | ||
460 | module_init(init_hfs_fs) | 460 | module_init(init_hfs_fs) |
diff --git a/fs/hfsplus/bfind.c b/fs/hfsplus/bfind.c index 257cdde0514b..5007a41f1be9 100644 --- a/fs/hfsplus/bfind.c +++ b/fs/hfsplus/bfind.c | |||
@@ -64,7 +64,6 @@ int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd) | |||
64 | else | 64 | else |
65 | e = rec - 1; | 65 | e = rec - 1; |
66 | } while (b <= e); | 66 | } while (b <= e); |
67 | //printk("%d: %d,%d,%d\n", bnode->this, b, e, rec); | ||
68 | if (rec != e && e >= 0) { | 67 | if (rec != e && e >= 0) { |
69 | len = hfs_brec_lenoff(bnode, e, &off); | 68 | len = hfs_brec_lenoff(bnode, e, &off); |
70 | keylen = hfs_brec_keylen(bnode, e); | 69 | keylen = hfs_brec_keylen(bnode, e); |
@@ -127,7 +126,7 @@ int hfs_brec_find(struct hfs_find_data *fd) | |||
127 | return res; | 126 | return res; |
128 | 127 | ||
129 | invalid: | 128 | invalid: |
130 | printk("HFS+-fs: inconsistency in B*Tree (%d,%d,%d,%u,%u)\n", | 129 | printk(KERN_ERR "hfs: inconsistency in B*Tree (%d,%d,%d,%u,%u)\n", |
131 | height, bnode->height, bnode->type, nidx, parent); | 130 | height, bnode->height, bnode->type, nidx, parent); |
132 | res = -EIO; | 131 | res = -EIO; |
133 | release: | 132 | release: |
diff --git a/fs/hfsplus/bnode.c b/fs/hfsplus/bnode.c index 930cd9212de8..8f07e8fbd03d 100644 --- a/fs/hfsplus/bnode.c +++ b/fs/hfsplus/bnode.c | |||
@@ -358,7 +358,7 @@ void hfs_bnode_unlink(struct hfs_bnode *node) | |||
358 | 358 | ||
359 | // move down? | 359 | // move down? |
360 | if (!node->prev && !node->next) { | 360 | if (!node->prev && !node->next) { |
361 | printk("hfs_btree_del_level\n"); | 361 | printk(KERN_DEBUG "hfs_btree_del_level\n"); |
362 | } | 362 | } |
363 | if (!node->parent) { | 363 | if (!node->parent) { |
364 | tree->root = 0; | 364 | tree->root = 0; |
@@ -379,7 +379,7 @@ struct hfs_bnode *hfs_bnode_findhash(struct hfs_btree *tree, u32 cnid) | |||
379 | struct hfs_bnode *node; | 379 | struct hfs_bnode *node; |
380 | 380 | ||
381 | if (cnid >= tree->node_count) { | 381 | if (cnid >= tree->node_count) { |
382 | printk("HFS+-fs: request for non-existent node %d in B*Tree\n", cnid); | 382 | printk(KERN_ERR "hfs: request for non-existent node %d in B*Tree\n", cnid); |
383 | return NULL; | 383 | return NULL; |
384 | } | 384 | } |
385 | 385 | ||
@@ -402,7 +402,7 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid) | |||
402 | loff_t off; | 402 | loff_t off; |
403 | 403 | ||
404 | if (cnid >= tree->node_count) { | 404 | if (cnid >= tree->node_count) { |
405 | printk("HFS+-fs: request for non-existent node %d in B*Tree\n", cnid); | 405 | printk(KERN_ERR "hfs: request for non-existent node %d in B*Tree\n", cnid); |
406 | return NULL; | 406 | return NULL; |
407 | } | 407 | } |
408 | 408 | ||
@@ -576,8 +576,9 @@ struct hfs_bnode *hfs_bnode_create(struct hfs_btree *tree, u32 num) | |||
576 | node = hfs_bnode_findhash(tree, num); | 576 | node = hfs_bnode_findhash(tree, num); |
577 | spin_unlock(&tree->hash_lock); | 577 | spin_unlock(&tree->hash_lock); |
578 | if (node) { | 578 | if (node) { |
579 | printk("new node %u already hashed?\n", num); | 579 | printk(KERN_CRIT "new node %u already hashed?\n", num); |
580 | BUG(); | 580 | WARN_ON(1); |
581 | return node; | ||
581 | } | 582 | } |
582 | node = __hfs_bnode_create(tree, num); | 583 | node = __hfs_bnode_create(tree, num); |
583 | if (!node) | 584 | if (!node) |
diff --git a/fs/hfsplus/brec.c b/fs/hfsplus/brec.c index 0ccef2ab790c..c88e5d72a402 100644 --- a/fs/hfsplus/brec.c +++ b/fs/hfsplus/brec.c | |||
@@ -360,7 +360,7 @@ again: | |||
360 | end_off = hfs_bnode_read_u16(parent, end_rec_off); | 360 | end_off = hfs_bnode_read_u16(parent, end_rec_off); |
361 | if (end_rec_off - end_off < diff) { | 361 | if (end_rec_off - end_off < diff) { |
362 | 362 | ||
363 | printk("splitting index node...\n"); | 363 | printk(KERN_DEBUG "hfs: splitting index node...\n"); |
364 | fd->bnode = parent; | 364 | fd->bnode = parent; |
365 | new_node = hfs_bnode_split(fd); | 365 | new_node = hfs_bnode_split(fd); |
366 | if (IS_ERR(new_node)) | 366 | if (IS_ERR(new_node)) |
diff --git a/fs/hfsplus/btree.c b/fs/hfsplus/btree.c index 44326aa2bd34..a67edfa34e9e 100644 --- a/fs/hfsplus/btree.c +++ b/fs/hfsplus/btree.c | |||
@@ -31,17 +31,8 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id) | |||
31 | 31 | ||
32 | init_MUTEX(&tree->tree_lock); | 32 | init_MUTEX(&tree->tree_lock); |
33 | spin_lock_init(&tree->hash_lock); | 33 | spin_lock_init(&tree->hash_lock); |
34 | /* Set the correct compare function */ | ||
35 | tree->sb = sb; | 34 | tree->sb = sb; |
36 | tree->cnid = id; | 35 | tree->cnid = id; |
37 | if (id == HFSPLUS_EXT_CNID) { | ||
38 | tree->keycmp = hfsplus_ext_cmp_key; | ||
39 | } else if (id == HFSPLUS_CAT_CNID) { | ||
40 | tree->keycmp = hfsplus_cat_cmp_key; | ||
41 | } else { | ||
42 | printk("HFS+-fs: unknown B*Tree requested\n"); | ||
43 | goto free_tree; | ||
44 | } | ||
45 | tree->inode = iget(sb, id); | 36 | tree->inode = iget(sb, id); |
46 | if (!tree->inode) | 37 | if (!tree->inode) |
47 | goto free_tree; | 38 | goto free_tree; |
@@ -64,6 +55,20 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id) | |||
64 | tree->max_key_len = be16_to_cpu(head->max_key_len); | 55 | tree->max_key_len = be16_to_cpu(head->max_key_len); |
65 | tree->depth = be16_to_cpu(head->depth); | 56 | tree->depth = be16_to_cpu(head->depth); |
66 | 57 | ||
58 | /* Set the correct compare function */ | ||
59 | if (id == HFSPLUS_EXT_CNID) { | ||
60 | tree->keycmp = hfsplus_ext_cmp_key; | ||
61 | } else if (id == HFSPLUS_CAT_CNID) { | ||
62 | if ((HFSPLUS_SB(sb).flags & HFSPLUS_SB_HFSX) && | ||
63 | (head->key_type == HFSPLUS_KEY_BINARY)) | ||
64 | tree->keycmp = hfsplus_cat_bin_cmp_key; | ||
65 | else | ||
66 | tree->keycmp = hfsplus_cat_case_cmp_key; | ||
67 | } else { | ||
68 | printk(KERN_ERR "hfs: unknown B*Tree requested\n"); | ||
69 | goto fail_page; | ||
70 | } | ||
71 | |||
67 | size = tree->node_size; | 72 | size = tree->node_size; |
68 | if (!size || size & (size - 1)) | 73 | if (!size || size & (size - 1)) |
69 | goto fail_page; | 74 | goto fail_page; |
@@ -99,7 +104,7 @@ void hfs_btree_close(struct hfs_btree *tree) | |||
99 | while ((node = tree->node_hash[i])) { | 104 | while ((node = tree->node_hash[i])) { |
100 | tree->node_hash[i] = node->next_hash; | 105 | tree->node_hash[i] = node->next_hash; |
101 | if (atomic_read(&node->refcnt)) | 106 | if (atomic_read(&node->refcnt)) |
102 | printk("HFS+: node %d:%d still has %d user(s)!\n", | 107 | printk(KERN_CRIT "hfs: node %d:%d still has %d user(s)!\n", |
103 | node->tree->cnid, node->this, atomic_read(&node->refcnt)); | 108 | node->tree->cnid, node->this, atomic_read(&node->refcnt)); |
104 | hfs_bnode_free(node); | 109 | hfs_bnode_free(node); |
105 | tree->node_hash_cnt--; | 110 | tree->node_hash_cnt--; |
@@ -223,10 +228,6 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree) | |||
223 | tree->free_nodes--; | 228 | tree->free_nodes--; |
224 | mark_inode_dirty(tree->inode); | 229 | mark_inode_dirty(tree->inode); |
225 | hfs_bnode_put(node); | 230 | hfs_bnode_put(node); |
226 | if (!idx) { | ||
227 | printk("unexpected idx %u (%u)\n", idx, node->this); | ||
228 | BUG(); | ||
229 | } | ||
230 | return hfs_bnode_create(tree, idx); | 231 | return hfs_bnode_create(tree, idx); |
231 | } | 232 | } |
232 | } | 233 | } |
@@ -242,7 +243,7 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree) | |||
242 | kunmap(*pagep); | 243 | kunmap(*pagep); |
243 | nidx = node->next; | 244 | nidx = node->next; |
244 | if (!nidx) { | 245 | if (!nidx) { |
245 | printk("create new bmap node...\n"); | 246 | printk(KERN_DEBUG "hfs: create new bmap node...\n"); |
246 | next_node = hfs_bmap_new_bmap(node, idx); | 247 | next_node = hfs_bmap_new_bmap(node, idx); |
247 | } else | 248 | } else |
248 | next_node = hfs_bnode_find(tree, nidx); | 249 | next_node = hfs_bnode_find(tree, nidx); |
@@ -284,7 +285,7 @@ void hfs_bmap_free(struct hfs_bnode *node) | |||
284 | hfs_bnode_put(node); | 285 | hfs_bnode_put(node); |
285 | if (!i) { | 286 | if (!i) { |
286 | /* panic */; | 287 | /* panic */; |
287 | printk("HFS: unable to free bnode %u. bmap not found!\n", node->this); | 288 | printk(KERN_CRIT "hfs: unable to free bnode %u. bmap not found!\n", node->this); |
288 | return; | 289 | return; |
289 | } | 290 | } |
290 | node = hfs_bnode_find(tree, i); | 291 | node = hfs_bnode_find(tree, i); |
@@ -292,7 +293,7 @@ void hfs_bmap_free(struct hfs_bnode *node) | |||
292 | return; | 293 | return; |
293 | if (node->type != HFS_NODE_MAP) { | 294 | if (node->type != HFS_NODE_MAP) { |
294 | /* panic */; | 295 | /* panic */; |
295 | printk("HFS: invalid bmap found! (%u,%d)\n", node->this, node->type); | 296 | printk(KERN_CRIT "hfs: invalid bmap found! (%u,%d)\n", node->this, node->type); |
296 | hfs_bnode_put(node); | 297 | hfs_bnode_put(node); |
297 | return; | 298 | return; |
298 | } | 299 | } |
@@ -305,7 +306,7 @@ void hfs_bmap_free(struct hfs_bnode *node) | |||
305 | m = 1 << (~nidx & 7); | 306 | m = 1 << (~nidx & 7); |
306 | byte = data[off]; | 307 | byte = data[off]; |
307 | if (!(byte & m)) { | 308 | if (!(byte & m)) { |
308 | printk("HFS: trying to free free bnode %u(%d)\n", node->this, node->type); | 309 | printk(KERN_CRIT "hfs: trying to free free bnode %u(%d)\n", node->this, node->type); |
309 | kunmap(page); | 310 | kunmap(page); |
310 | hfs_bnode_put(node); | 311 | hfs_bnode_put(node); |
311 | return; | 312 | return; |
diff --git a/fs/hfsplus/catalog.c b/fs/hfsplus/catalog.c index 94712790c8b3..f2d7c49ce759 100644 --- a/fs/hfsplus/catalog.c +++ b/fs/hfsplus/catalog.c | |||
@@ -13,7 +13,8 @@ | |||
13 | #include "hfsplus_fs.h" | 13 | #include "hfsplus_fs.h" |
14 | #include "hfsplus_raw.h" | 14 | #include "hfsplus_raw.h" |
15 | 15 | ||
16 | int hfsplus_cat_cmp_key(hfsplus_btree_key *k1, hfsplus_btree_key *k2) | 16 | int hfsplus_cat_case_cmp_key(const hfsplus_btree_key *k1, |
17 | const hfsplus_btree_key *k2) | ||
17 | { | 18 | { |
18 | __be32 k1p, k2p; | 19 | __be32 k1p, k2p; |
19 | 20 | ||
@@ -22,7 +23,20 @@ int hfsplus_cat_cmp_key(hfsplus_btree_key *k1, hfsplus_btree_key *k2) | |||
22 | if (k1p != k2p) | 23 | if (k1p != k2p) |
23 | return be32_to_cpu(k1p) < be32_to_cpu(k2p) ? -1 : 1; | 24 | return be32_to_cpu(k1p) < be32_to_cpu(k2p) ? -1 : 1; |
24 | 25 | ||
25 | return hfsplus_unistrcmp(&k1->cat.name, &k2->cat.name); | 26 | return hfsplus_strcasecmp(&k1->cat.name, &k2->cat.name); |
27 | } | ||
28 | |||
29 | int hfsplus_cat_bin_cmp_key(const hfsplus_btree_key *k1, | ||
30 | const hfsplus_btree_key *k2) | ||
31 | { | ||
32 | __be32 k1p, k2p; | ||
33 | |||
34 | k1p = k1->cat.parent; | ||
35 | k2p = k2->cat.parent; | ||
36 | if (k1p != k2p) | ||
37 | return be32_to_cpu(k1p) < be32_to_cpu(k2p) ? -1 : 1; | ||
38 | |||
39 | return hfsplus_strcmp(&k1->cat.name, &k2->cat.name); | ||
26 | } | 40 | } |
27 | 41 | ||
28 | void hfsplus_cat_build_key(struct super_block *sb, hfsplus_btree_key *key, | 42 | void hfsplus_cat_build_key(struct super_block *sb, hfsplus_btree_key *key, |
@@ -80,8 +94,11 @@ static int hfsplus_cat_build_record(hfsplus_cat_entry *entry, u32 cnid, struct i | |||
80 | memset(folder, 0, sizeof(*folder)); | 94 | memset(folder, 0, sizeof(*folder)); |
81 | folder->type = cpu_to_be16(HFSPLUS_FOLDER); | 95 | folder->type = cpu_to_be16(HFSPLUS_FOLDER); |
82 | folder->id = cpu_to_be32(inode->i_ino); | 96 | folder->id = cpu_to_be32(inode->i_ino); |
83 | folder->create_date = folder->content_mod_date = | 97 | HFSPLUS_I(inode).create_date = |
84 | folder->attribute_mod_date = folder->access_date = hfsp_now2mt(); | 98 | folder->create_date = |
99 | folder->content_mod_date = | ||
100 | folder->attribute_mod_date = | ||
101 | folder->access_date = hfsp_now2mt(); | ||
85 | hfsplus_set_perms(inode, &folder->permissions); | 102 | hfsplus_set_perms(inode, &folder->permissions); |
86 | if (inode == HFSPLUS_SB(inode->i_sb).hidden_dir) | 103 | if (inode == HFSPLUS_SB(inode->i_sb).hidden_dir) |
87 | /* invisible and namelocked */ | 104 | /* invisible and namelocked */ |
@@ -95,18 +112,27 @@ static int hfsplus_cat_build_record(hfsplus_cat_entry *entry, u32 cnid, struct i | |||
95 | file->type = cpu_to_be16(HFSPLUS_FILE); | 112 | file->type = cpu_to_be16(HFSPLUS_FILE); |
96 | file->flags = cpu_to_be16(HFSPLUS_FILE_THREAD_EXISTS); | 113 | file->flags = cpu_to_be16(HFSPLUS_FILE_THREAD_EXISTS); |
97 | file->id = cpu_to_be32(cnid); | 114 | file->id = cpu_to_be32(cnid); |
98 | file->create_date = file->content_mod_date = | 115 | HFSPLUS_I(inode).create_date = |
99 | file->attribute_mod_date = file->access_date = hfsp_now2mt(); | 116 | file->create_date = |
117 | file->content_mod_date = | ||
118 | file->attribute_mod_date = | ||
119 | file->access_date = hfsp_now2mt(); | ||
100 | if (cnid == inode->i_ino) { | 120 | if (cnid == inode->i_ino) { |
101 | hfsplus_set_perms(inode, &file->permissions); | 121 | hfsplus_set_perms(inode, &file->permissions); |
102 | file->user_info.fdType = cpu_to_be32(HFSPLUS_SB(inode->i_sb).type); | 122 | if (S_ISLNK(inode->i_mode)) { |
103 | file->user_info.fdCreator = cpu_to_be32(HFSPLUS_SB(inode->i_sb).creator); | 123 | file->user_info.fdType = cpu_to_be32(HFSP_SYMLINK_TYPE); |
124 | file->user_info.fdCreator = cpu_to_be32(HFSP_SYMLINK_CREATOR); | ||
125 | } else { | ||
126 | file->user_info.fdType = cpu_to_be32(HFSPLUS_SB(inode->i_sb).type); | ||
127 | file->user_info.fdCreator = cpu_to_be32(HFSPLUS_SB(inode->i_sb).creator); | ||
128 | } | ||
104 | if ((file->permissions.rootflags | file->permissions.userflags) & HFSPLUS_FLG_IMMUTABLE) | 129 | if ((file->permissions.rootflags | file->permissions.userflags) & HFSPLUS_FLG_IMMUTABLE) |
105 | file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED); | 130 | file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED); |
106 | } else { | 131 | } else { |
107 | file->user_info.fdType = cpu_to_be32(HFSP_HARDLINK_TYPE); | 132 | file->user_info.fdType = cpu_to_be32(HFSP_HARDLINK_TYPE); |
108 | file->user_info.fdCreator = cpu_to_be32(HFSP_HFSPLUS_CREATOR); | 133 | file->user_info.fdCreator = cpu_to_be32(HFSP_HFSPLUS_CREATOR); |
109 | file->user_info.fdFlags = cpu_to_be16(0x100); | 134 | file->user_info.fdFlags = cpu_to_be16(0x100); |
135 | file->create_date = HFSPLUS_I(HFSPLUS_SB(inode->i_sb).hidden_dir).create_date; | ||
110 | file->permissions.dev = cpu_to_be32(HFSPLUS_I(inode).dev); | 136 | file->permissions.dev = cpu_to_be32(HFSPLUS_I(inode).dev); |
111 | } | 137 | } |
112 | return sizeof(*file); | 138 | return sizeof(*file); |
@@ -139,7 +165,7 @@ int hfsplus_find_cat(struct super_block *sb, u32 cnid, | |||
139 | 165 | ||
140 | type = be16_to_cpu(tmp.type); | 166 | type = be16_to_cpu(tmp.type); |
141 | if (type != HFSPLUS_FOLDER_THREAD && type != HFSPLUS_FILE_THREAD) { | 167 | if (type != HFSPLUS_FOLDER_THREAD && type != HFSPLUS_FILE_THREAD) { |
142 | printk("HFS+-fs: Found bad thread record in catalog\n"); | 168 | printk(KERN_ERR "hfs: found bad thread record in catalog\n"); |
143 | return -EIO; | 169 | return -EIO; |
144 | } | 170 | } |
145 | 171 | ||
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c index 50c8f44b6c66..01a6fe3a395c 100644 --- a/fs/hfsplus/dir.c +++ b/fs/hfsplus/dir.c | |||
@@ -66,25 +66,32 @@ again: | |||
66 | } | 66 | } |
67 | cnid = be32_to_cpu(entry.file.id); | 67 | cnid = be32_to_cpu(entry.file.id); |
68 | if (entry.file.user_info.fdType == cpu_to_be32(HFSP_HARDLINK_TYPE) && | 68 | if (entry.file.user_info.fdType == cpu_to_be32(HFSP_HARDLINK_TYPE) && |
69 | entry.file.user_info.fdCreator == cpu_to_be32(HFSP_HFSPLUS_CREATOR)) { | 69 | entry.file.user_info.fdCreator == cpu_to_be32(HFSP_HFSPLUS_CREATOR) && |
70 | (entry.file.create_date == HFSPLUS_I(HFSPLUS_SB(sb).hidden_dir).create_date || | ||
71 | entry.file.create_date == HFSPLUS_I(sb->s_root->d_inode).create_date) && | ||
72 | HFSPLUS_SB(sb).hidden_dir) { | ||
70 | struct qstr str; | 73 | struct qstr str; |
71 | char name[32]; | 74 | char name[32]; |
72 | 75 | ||
73 | if (dentry->d_fsdata) { | 76 | if (dentry->d_fsdata) { |
74 | err = -ENOENT; | 77 | /* |
75 | inode = NULL; | 78 | * We found a link pointing to another link, |
76 | goto out; | 79 | * so ignore it and treat it as regular file. |
80 | */ | ||
81 | cnid = (unsigned long)dentry->d_fsdata; | ||
82 | linkid = 0; | ||
83 | } else { | ||
84 | dentry->d_fsdata = (void *)(unsigned long)cnid; | ||
85 | linkid = be32_to_cpu(entry.file.permissions.dev); | ||
86 | str.len = sprintf(name, "iNode%d", linkid); | ||
87 | str.name = name; | ||
88 | hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_SB(sb).hidden_dir->i_ino, &str); | ||
89 | goto again; | ||
77 | } | 90 | } |
78 | dentry->d_fsdata = (void *)(unsigned long)cnid; | ||
79 | linkid = be32_to_cpu(entry.file.permissions.dev); | ||
80 | str.len = sprintf(name, "iNode%d", linkid); | ||
81 | str.name = name; | ||
82 | hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_SB(sb).hidden_dir->i_ino, &str); | ||
83 | goto again; | ||
84 | } else if (!dentry->d_fsdata) | 91 | } else if (!dentry->d_fsdata) |
85 | dentry->d_fsdata = (void *)(unsigned long)cnid; | 92 | dentry->d_fsdata = (void *)(unsigned long)cnid; |
86 | } else { | 93 | } else { |
87 | printk("HFS+-fs: Illegal catalog entry type in lookup\n"); | 94 | printk(KERN_ERR "hfs: invalid catalog entry type in lookup\n"); |
88 | err = -EIO; | 95 | err = -EIO; |
89 | goto fail; | 96 | goto fail; |
90 | } | 97 | } |
@@ -132,12 +139,12 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
132 | case 1: | 139 | case 1: |
133 | hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength); | 140 | hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength); |
134 | if (be16_to_cpu(entry.type) != HFSPLUS_FOLDER_THREAD) { | 141 | if (be16_to_cpu(entry.type) != HFSPLUS_FOLDER_THREAD) { |
135 | printk("HFS+-fs: bad catalog folder thread\n"); | 142 | printk(KERN_ERR "hfs: bad catalog folder thread\n"); |
136 | err = -EIO; | 143 | err = -EIO; |
137 | goto out; | 144 | goto out; |
138 | } | 145 | } |
139 | if (fd.entrylength < HFSPLUS_MIN_THREAD_SZ) { | 146 | if (fd.entrylength < HFSPLUS_MIN_THREAD_SZ) { |
140 | printk("HFS+-fs: truncated catalog thread\n"); | 147 | printk(KERN_ERR "hfs: truncated catalog thread\n"); |
141 | err = -EIO; | 148 | err = -EIO; |
142 | goto out; | 149 | goto out; |
143 | } | 150 | } |
@@ -156,7 +163,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
156 | 163 | ||
157 | for (;;) { | 164 | for (;;) { |
158 | if (be32_to_cpu(fd.key->cat.parent) != inode->i_ino) { | 165 | if (be32_to_cpu(fd.key->cat.parent) != inode->i_ino) { |
159 | printk("HFS+-fs: walked past end of dir\n"); | 166 | printk(KERN_ERR "hfs: walked past end of dir\n"); |
160 | err = -EIO; | 167 | err = -EIO; |
161 | goto out; | 168 | goto out; |
162 | } | 169 | } |
@@ -168,7 +175,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
168 | goto out; | 175 | goto out; |
169 | if (type == HFSPLUS_FOLDER) { | 176 | if (type == HFSPLUS_FOLDER) { |
170 | if (fd.entrylength < sizeof(struct hfsplus_cat_folder)) { | 177 | if (fd.entrylength < sizeof(struct hfsplus_cat_folder)) { |
171 | printk("HFS+-fs: small dir entry\n"); | 178 | printk(KERN_ERR "hfs: small dir entry\n"); |
172 | err = -EIO; | 179 | err = -EIO; |
173 | goto out; | 180 | goto out; |
174 | } | 181 | } |
@@ -180,7 +187,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
180 | break; | 187 | break; |
181 | } else if (type == HFSPLUS_FILE) { | 188 | } else if (type == HFSPLUS_FILE) { |
182 | if (fd.entrylength < sizeof(struct hfsplus_cat_file)) { | 189 | if (fd.entrylength < sizeof(struct hfsplus_cat_file)) { |
183 | printk("HFS+-fs: small file entry\n"); | 190 | printk(KERN_ERR "hfs: small file entry\n"); |
184 | err = -EIO; | 191 | err = -EIO; |
185 | goto out; | 192 | goto out; |
186 | } | 193 | } |
@@ -188,7 +195,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
188 | be32_to_cpu(entry.file.id), DT_REG)) | 195 | be32_to_cpu(entry.file.id), DT_REG)) |
189 | break; | 196 | break; |
190 | } else { | 197 | } else { |
191 | printk("HFS+-fs: bad catalog entry type\n"); | 198 | printk(KERN_ERR "hfs: bad catalog entry type\n"); |
192 | err = -EIO; | 199 | err = -EIO; |
193 | goto out; | 200 | goto out; |
194 | } | 201 | } |
@@ -330,7 +337,8 @@ static int hfsplus_unlink(struct inode *dir, struct dentry *dentry) | |||
330 | if (res) | 337 | if (res) |
331 | return res; | 338 | return res; |
332 | 339 | ||
333 | inode->i_nlink--; | 340 | if (inode->i_nlink > 0) |
341 | inode->i_nlink--; | ||
334 | hfsplus_delete_inode(inode); | 342 | hfsplus_delete_inode(inode); |
335 | if (inode->i_ino != cnid && !inode->i_nlink) { | 343 | if (inode->i_ino != cnid && !inode->i_nlink) { |
336 | if (!atomic_read(&HFSPLUS_I(inode).opencnt)) { | 344 | if (!atomic_read(&HFSPLUS_I(inode).opencnt)) { |
@@ -339,7 +347,8 @@ static int hfsplus_unlink(struct inode *dir, struct dentry *dentry) | |||
339 | hfsplus_delete_inode(inode); | 347 | hfsplus_delete_inode(inode); |
340 | } else | 348 | } else |
341 | inode->i_flags |= S_DEAD; | 349 | inode->i_flags |= S_DEAD; |
342 | } | 350 | } else |
351 | inode->i_nlink = 0; | ||
343 | inode->i_ctime = CURRENT_TIME_SEC; | 352 | inode->i_ctime = CURRENT_TIME_SEC; |
344 | mark_inode_dirty(inode); | 353 | mark_inode_dirty(inode); |
345 | 354 | ||
diff --git a/fs/hfsplus/extents.c b/fs/hfsplus/extents.c index e3ff56a03011..1a7480089e82 100644 --- a/fs/hfsplus/extents.c +++ b/fs/hfsplus/extents.c | |||
@@ -16,7 +16,8 @@ | |||
16 | #include "hfsplus_raw.h" | 16 | #include "hfsplus_raw.h" |
17 | 17 | ||
18 | /* Compare two extents keys, returns 0 on same, pos/neg for difference */ | 18 | /* Compare two extents keys, returns 0 on same, pos/neg for difference */ |
19 | int hfsplus_ext_cmp_key(hfsplus_btree_key *k1, hfsplus_btree_key *k2) | 19 | int hfsplus_ext_cmp_key(const hfsplus_btree_key *k1, |
20 | const hfsplus_btree_key *k2) | ||
20 | { | 21 | { |
21 | __be32 k1id, k2id; | 22 | __be32 k1id, k2id; |
22 | __be32 k1s, k2s; | 23 | __be32 k1s, k2s; |
@@ -349,10 +350,9 @@ int hfsplus_file_extend(struct inode *inode) | |||
349 | 350 | ||
350 | if (HFSPLUS_SB(sb).alloc_file->i_size * 8 < HFSPLUS_SB(sb).total_blocks - HFSPLUS_SB(sb).free_blocks + 8) { | 351 | if (HFSPLUS_SB(sb).alloc_file->i_size * 8 < HFSPLUS_SB(sb).total_blocks - HFSPLUS_SB(sb).free_blocks + 8) { |
351 | // extend alloc file | 352 | // extend alloc file |
352 | printk("extend alloc file! (%Lu,%u,%u)\n", HFSPLUS_SB(sb).alloc_file->i_size * 8, | 353 | printk(KERN_ERR "hfs: extend alloc file! (%Lu,%u,%u)\n", HFSPLUS_SB(sb).alloc_file->i_size * 8, |
353 | HFSPLUS_SB(sb).total_blocks, HFSPLUS_SB(sb).free_blocks); | 354 | HFSPLUS_SB(sb).total_blocks, HFSPLUS_SB(sb).free_blocks); |
354 | return -ENOSPC; | 355 | return -ENOSPC; |
355 | //BUG(); | ||
356 | } | 356 | } |
357 | 357 | ||
358 | down(&HFSPLUS_I(inode).extents_lock); | 358 | down(&HFSPLUS_I(inode).extents_lock); |
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h index 0fa1ab6250bf..7ae393637a0c 100644 --- a/fs/hfsplus/hfsplus_fs.h +++ b/fs/hfsplus/hfsplus_fs.h | |||
@@ -36,7 +36,7 @@ | |||
36 | #define HFSPLUS_TYPE_DATA 0x00 | 36 | #define HFSPLUS_TYPE_DATA 0x00 |
37 | #define HFSPLUS_TYPE_RSRC 0xFF | 37 | #define HFSPLUS_TYPE_RSRC 0xFF |
38 | 38 | ||
39 | typedef int (*btree_keycmp)(hfsplus_btree_key *, hfsplus_btree_key *); | 39 | typedef int (*btree_keycmp)(const hfsplus_btree_key *, const hfsplus_btree_key *); |
40 | 40 | ||
41 | #define NODE_HASH_SIZE 256 | 41 | #define NODE_HASH_SIZE 256 |
42 | 42 | ||
@@ -149,6 +149,7 @@ struct hfsplus_sb_info { | |||
149 | #define HFSPLUS_SB_WRITEBACKUP 0x0001 | 149 | #define HFSPLUS_SB_WRITEBACKUP 0x0001 |
150 | #define HFSPLUS_SB_NODECOMPOSE 0x0002 | 150 | #define HFSPLUS_SB_NODECOMPOSE 0x0002 |
151 | #define HFSPLUS_SB_FORCE 0x0004 | 151 | #define HFSPLUS_SB_FORCE 0x0004 |
152 | #define HFSPLUS_SB_HFSX 0x0008 | ||
152 | 153 | ||
153 | 154 | ||
154 | struct hfsplus_inode_info { | 155 | struct hfsplus_inode_info { |
@@ -165,6 +166,7 @@ struct hfsplus_inode_info { | |||
165 | struct inode *rsrc_inode; | 166 | struct inode *rsrc_inode; |
166 | unsigned long flags; | 167 | unsigned long flags; |
167 | 168 | ||
169 | __be32 create_date; | ||
168 | /* Device number in hfsplus_permissions in catalog */ | 170 | /* Device number in hfsplus_permissions in catalog */ |
169 | u32 dev; | 171 | u32 dev; |
170 | /* BSD system and user file flags */ | 172 | /* BSD system and user file flags */ |
@@ -303,7 +305,8 @@ int hfs_brec_read(struct hfs_find_data *, void *, int); | |||
303 | int hfs_brec_goto(struct hfs_find_data *, int); | 305 | int hfs_brec_goto(struct hfs_find_data *, int); |
304 | 306 | ||
305 | /* catalog.c */ | 307 | /* catalog.c */ |
306 | int hfsplus_cat_cmp_key(hfsplus_btree_key *, hfsplus_btree_key *); | 308 | int hfsplus_cat_case_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *); |
309 | int hfsplus_cat_bin_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *); | ||
307 | void hfsplus_cat_build_key(struct super_block *sb, hfsplus_btree_key *, u32, struct qstr *); | 310 | void hfsplus_cat_build_key(struct super_block *sb, hfsplus_btree_key *, u32, struct qstr *); |
308 | int hfsplus_find_cat(struct super_block *, u32, struct hfs_find_data *); | 311 | int hfsplus_find_cat(struct super_block *, u32, struct hfs_find_data *); |
309 | int hfsplus_create_cat(u32, struct inode *, struct qstr *, struct inode *); | 312 | int hfsplus_create_cat(u32, struct inode *, struct qstr *, struct inode *); |
@@ -312,7 +315,7 @@ int hfsplus_rename_cat(u32, struct inode *, struct qstr *, | |||
312 | struct inode *, struct qstr *); | 315 | struct inode *, struct qstr *); |
313 | 316 | ||
314 | /* extents.c */ | 317 | /* extents.c */ |
315 | int hfsplus_ext_cmp_key(hfsplus_btree_key *, hfsplus_btree_key *); | 318 | int hfsplus_ext_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *); |
316 | void hfsplus_ext_write_extent(struct inode *); | 319 | void hfsplus_ext_write_extent(struct inode *); |
317 | int hfsplus_get_block(struct inode *, sector_t, struct buffer_head *, int); | 320 | int hfsplus_get_block(struct inode *, sector_t, struct buffer_head *, int); |
318 | int hfsplus_free_fork(struct super_block *, u32, struct hfsplus_fork_raw *, int); | 321 | int hfsplus_free_fork(struct super_block *, u32, struct hfsplus_fork_raw *, int); |
@@ -350,7 +353,8 @@ extern u16 hfsplus_decompose_table[]; | |||
350 | extern u16 hfsplus_compose_table[]; | 353 | extern u16 hfsplus_compose_table[]; |
351 | 354 | ||
352 | /* unicode.c */ | 355 | /* unicode.c */ |
353 | int hfsplus_unistrcmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *); | 356 | int hfsplus_strcasecmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *); |
357 | int hfsplus_strcmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *); | ||
354 | int hfsplus_uni2asc(struct super_block *, const struct hfsplus_unistr *, char *, int *); | 358 | int hfsplus_uni2asc(struct super_block *, const struct hfsplus_unistr *, char *, int *); |
355 | int hfsplus_asc2uni(struct super_block *, struct hfsplus_unistr *, const char *, int); | 359 | int hfsplus_asc2uni(struct super_block *, struct hfsplus_unistr *, const char *, int); |
356 | 360 | ||
diff --git a/fs/hfsplus/hfsplus_raw.h b/fs/hfsplus/hfsplus_raw.h index b4fbed633219..49205531a500 100644 --- a/fs/hfsplus/hfsplus_raw.h +++ b/fs/hfsplus/hfsplus_raw.h | |||
@@ -22,8 +22,10 @@ | |||
22 | #define HFSPLUS_SECTOR_SHIFT 9 | 22 | #define HFSPLUS_SECTOR_SHIFT 9 |
23 | #define HFSPLUS_VOLHEAD_SECTOR 2 | 23 | #define HFSPLUS_VOLHEAD_SECTOR 2 |
24 | #define HFSPLUS_VOLHEAD_SIG 0x482b | 24 | #define HFSPLUS_VOLHEAD_SIG 0x482b |
25 | #define HFSPLUS_VOLHEAD_SIGX 0x4858 | ||
25 | #define HFSPLUS_SUPER_MAGIC 0x482b | 26 | #define HFSPLUS_SUPER_MAGIC 0x482b |
26 | #define HFSPLUS_CURRENT_VERSION 4 | 27 | #define HFSPLUS_MIN_VERSION 4 |
28 | #define HFSPLUS_CURRENT_VERSION 5 | ||
27 | 29 | ||
28 | #define HFSP_WRAP_MAGIC 0x4244 | 30 | #define HFSP_WRAP_MAGIC 0x4244 |
29 | #define HFSP_WRAP_ATTRIB_SLOCK 0x8000 | 31 | #define HFSP_WRAP_ATTRIB_SLOCK 0x8000 |
@@ -41,6 +43,9 @@ | |||
41 | #define HFSP_HARDLINK_TYPE 0x686c6e6b /* 'hlnk' */ | 43 | #define HFSP_HARDLINK_TYPE 0x686c6e6b /* 'hlnk' */ |
42 | #define HFSP_HFSPLUS_CREATOR 0x6866732b /* 'hfs+' */ | 44 | #define HFSP_HFSPLUS_CREATOR 0x6866732b /* 'hfs+' */ |
43 | 45 | ||
46 | #define HFSP_SYMLINK_TYPE 0x736c6e6b /* 'slnk' */ | ||
47 | #define HFSP_SYMLINK_CREATOR 0x72686170 /* 'rhap' */ | ||
48 | |||
44 | #define HFSP_MOUNT_VERSION 0x482b4c78 /* 'H+Lx' */ | 49 | #define HFSP_MOUNT_VERSION 0x482b4c78 /* 'H+Lx' */ |
45 | 50 | ||
46 | /* Structures used on disk */ | 51 | /* Structures used on disk */ |
@@ -161,7 +166,7 @@ struct hfs_btree_header_rec { | |||
161 | u16 reserved1; | 166 | u16 reserved1; |
162 | __be32 clump_size; | 167 | __be32 clump_size; |
163 | u8 btree_type; | 168 | u8 btree_type; |
164 | u8 reserved2; | 169 | u8 key_type; |
165 | __be32 attributes; | 170 | __be32 attributes; |
166 | u32 reserved3[16]; | 171 | u32 reserved3[16]; |
167 | } __packed; | 172 | } __packed; |
@@ -186,6 +191,10 @@ struct hfs_btree_header_rec { | |||
186 | #define HFSPLUS_EXCH_CNID 15 /* ExchangeFiles temp id */ | 191 | #define HFSPLUS_EXCH_CNID 15 /* ExchangeFiles temp id */ |
187 | #define HFSPLUS_FIRSTUSER_CNID 16 /* first available user id */ | 192 | #define HFSPLUS_FIRSTUSER_CNID 16 /* first available user id */ |
188 | 193 | ||
194 | /* btree key type */ | ||
195 | #define HFSPLUS_KEY_CASEFOLDING 0xCF /* case-insensitive */ | ||
196 | #define HFSPLUS_KEY_BINARY 0xBC /* case-sensitive */ | ||
197 | |||
189 | /* HFS+ catalog entry key */ | 198 | /* HFS+ catalog entry key */ |
190 | struct hfsplus_cat_key { | 199 | struct hfsplus_cat_key { |
191 | __be16 key_len; | 200 | __be16 key_len; |
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index 7acff6c5464f..12ed2b7d046b 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c | |||
@@ -18,13 +18,11 @@ | |||
18 | 18 | ||
19 | static int hfsplus_readpage(struct file *file, struct page *page) | 19 | static int hfsplus_readpage(struct file *file, struct page *page) |
20 | { | 20 | { |
21 | //printk("readpage: %lu\n", page->index); | ||
22 | return block_read_full_page(page, hfsplus_get_block); | 21 | return block_read_full_page(page, hfsplus_get_block); |
23 | } | 22 | } |
24 | 23 | ||
25 | static int hfsplus_writepage(struct page *page, struct writeback_control *wbc) | 24 | static int hfsplus_writepage(struct page *page, struct writeback_control *wbc) |
26 | { | 25 | { |
27 | //printk("writepage: %lu\n", page->index); | ||
28 | return block_write_full_page(page, hfsplus_get_block, wbc); | 26 | return block_write_full_page(page, hfsplus_get_block, wbc); |
29 | } | 27 | } |
30 | 28 | ||
@@ -92,7 +90,6 @@ static int hfsplus_releasepage(struct page *page, gfp_t mask) | |||
92 | } while (--i && nidx < tree->node_count); | 90 | } while (--i && nidx < tree->node_count); |
93 | spin_unlock(&tree->hash_lock); | 91 | spin_unlock(&tree->hash_lock); |
94 | } | 92 | } |
95 | //printk("releasepage: %lu,%x = %d\n", page->index, mask, res); | ||
96 | return res ? try_to_free_buffers(page) : 0; | 93 | return res ? try_to_free_buffers(page) : 0; |
97 | } | 94 | } |
98 | 95 | ||
@@ -434,7 +431,8 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd) | |||
434 | inode->i_size = 2 + be32_to_cpu(folder->valence); | 431 | inode->i_size = 2 + be32_to_cpu(folder->valence); |
435 | inode->i_atime = hfsp_mt2ut(folder->access_date); | 432 | inode->i_atime = hfsp_mt2ut(folder->access_date); |
436 | inode->i_mtime = hfsp_mt2ut(folder->content_mod_date); | 433 | inode->i_mtime = hfsp_mt2ut(folder->content_mod_date); |
437 | inode->i_ctime = inode->i_mtime; | 434 | inode->i_ctime = hfsp_mt2ut(folder->attribute_mod_date); |
435 | HFSPLUS_I(inode).create_date = folder->create_date; | ||
438 | HFSPLUS_I(inode).fs_blocks = 0; | 436 | HFSPLUS_I(inode).fs_blocks = 0; |
439 | inode->i_op = &hfsplus_dir_inode_operations; | 437 | inode->i_op = &hfsplus_dir_inode_operations; |
440 | inode->i_fop = &hfsplus_dir_operations; | 438 | inode->i_fop = &hfsplus_dir_operations; |
@@ -465,9 +463,10 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd) | |||
465 | } | 463 | } |
466 | inode->i_atime = hfsp_mt2ut(file->access_date); | 464 | inode->i_atime = hfsp_mt2ut(file->access_date); |
467 | inode->i_mtime = hfsp_mt2ut(file->content_mod_date); | 465 | inode->i_mtime = hfsp_mt2ut(file->content_mod_date); |
468 | inode->i_ctime = inode->i_mtime; | 466 | inode->i_ctime = hfsp_mt2ut(file->attribute_mod_date); |
467 | HFSPLUS_I(inode).create_date = file->create_date; | ||
469 | } else { | 468 | } else { |
470 | printk("HFS+-fs: bad catalog entry used to create inode\n"); | 469 | printk(KERN_ERR "hfs: bad catalog entry used to create inode\n"); |
471 | res = -EIO; | 470 | res = -EIO; |
472 | } | 471 | } |
473 | return res; | 472 | return res; |
diff --git a/fs/hfsplus/options.c b/fs/hfsplus/options.c index 935dafba0078..dc64fac00831 100644 --- a/fs/hfsplus/options.c +++ b/fs/hfsplus/options.c | |||
@@ -83,58 +83,58 @@ int hfsplus_parse_options(char *input, struct hfsplus_sb_info *sbi) | |||
83 | switch (token) { | 83 | switch (token) { |
84 | case opt_creator: | 84 | case opt_creator: |
85 | if (match_fourchar(&args[0], &sbi->creator)) { | 85 | if (match_fourchar(&args[0], &sbi->creator)) { |
86 | printk("HFS+-fs: creator requires a 4 character value\n"); | 86 | printk(KERN_ERR "hfs: creator requires a 4 character value\n"); |
87 | return 0; | 87 | return 0; |
88 | } | 88 | } |
89 | break; | 89 | break; |
90 | case opt_type: | 90 | case opt_type: |
91 | if (match_fourchar(&args[0], &sbi->type)) { | 91 | if (match_fourchar(&args[0], &sbi->type)) { |
92 | printk("HFS+-fs: type requires a 4 character value\n"); | 92 | printk(KERN_ERR "hfs: type requires a 4 character value\n"); |
93 | return 0; | 93 | return 0; |
94 | } | 94 | } |
95 | break; | 95 | break; |
96 | case opt_umask: | 96 | case opt_umask: |
97 | if (match_octal(&args[0], &tmp)) { | 97 | if (match_octal(&args[0], &tmp)) { |
98 | printk("HFS+-fs: umask requires a value\n"); | 98 | printk(KERN_ERR "hfs: umask requires a value\n"); |
99 | return 0; | 99 | return 0; |
100 | } | 100 | } |
101 | sbi->umask = (umode_t)tmp; | 101 | sbi->umask = (umode_t)tmp; |
102 | break; | 102 | break; |
103 | case opt_uid: | 103 | case opt_uid: |
104 | if (match_int(&args[0], &tmp)) { | 104 | if (match_int(&args[0], &tmp)) { |
105 | printk("HFS+-fs: uid requires an argument\n"); | 105 | printk(KERN_ERR "hfs: uid requires an argument\n"); |
106 | return 0; | 106 | return 0; |
107 | } | 107 | } |
108 | sbi->uid = (uid_t)tmp; | 108 | sbi->uid = (uid_t)tmp; |
109 | break; | 109 | break; |
110 | case opt_gid: | 110 | case opt_gid: |
111 | if (match_int(&args[0], &tmp)) { | 111 | if (match_int(&args[0], &tmp)) { |
112 | printk("HFS+-fs: gid requires an argument\n"); | 112 | printk(KERN_ERR "hfs: gid requires an argument\n"); |
113 | return 0; | 113 | return 0; |
114 | } | 114 | } |
115 | sbi->gid = (gid_t)tmp; | 115 | sbi->gid = (gid_t)tmp; |
116 | break; | 116 | break; |
117 | case opt_part: | 117 | case opt_part: |
118 | if (match_int(&args[0], &sbi->part)) { | 118 | if (match_int(&args[0], &sbi->part)) { |
119 | printk("HFS+-fs: part requires an argument\n"); | 119 | printk(KERN_ERR "hfs: part requires an argument\n"); |
120 | return 0; | 120 | return 0; |
121 | } | 121 | } |
122 | break; | 122 | break; |
123 | case opt_session: | 123 | case opt_session: |
124 | if (match_int(&args[0], &sbi->session)) { | 124 | if (match_int(&args[0], &sbi->session)) { |
125 | printk("HFS+-fs: session requires an argument\n"); | 125 | printk(KERN_ERR "hfs: session requires an argument\n"); |
126 | return 0; | 126 | return 0; |
127 | } | 127 | } |
128 | break; | 128 | break; |
129 | case opt_nls: | 129 | case opt_nls: |
130 | if (sbi->nls) { | 130 | if (sbi->nls) { |
131 | printk("HFS+-fs: unable to change nls mapping\n"); | 131 | printk(KERN_ERR "hfs: unable to change nls mapping\n"); |
132 | return 0; | 132 | return 0; |
133 | } | 133 | } |
134 | p = match_strdup(&args[0]); | 134 | p = match_strdup(&args[0]); |
135 | sbi->nls = load_nls(p); | 135 | sbi->nls = load_nls(p); |
136 | if (!sbi->nls) { | 136 | if (!sbi->nls) { |
137 | printk("HFS+-fs: unable to load nls mapping \"%s\"\n", p); | 137 | printk(KERN_ERR "hfs: unable to load nls mapping \"%s\"\n", p); |
138 | kfree(p); | 138 | kfree(p); |
139 | return 0; | 139 | return 0; |
140 | } | 140 | } |
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index d791780def50..7843f792a4b7 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c | |||
@@ -169,7 +169,7 @@ static void hfsplus_write_super(struct super_block *sb) | |||
169 | block = HFSPLUS_SB(sb).blockoffset; | 169 | block = HFSPLUS_SB(sb).blockoffset; |
170 | block += (HFSPLUS_SB(sb).sect_count - 2) >> (sb->s_blocksize_bits - 9); | 170 | block += (HFSPLUS_SB(sb).sect_count - 2) >> (sb->s_blocksize_bits - 9); |
171 | offset = ((HFSPLUS_SB(sb).sect_count - 2) << 9) & (sb->s_blocksize - 1); | 171 | offset = ((HFSPLUS_SB(sb).sect_count - 2) << 9) & (sb->s_blocksize - 1); |
172 | printk("backup: %u,%u,%u,%u\n", HFSPLUS_SB(sb).blockoffset, | 172 | printk(KERN_DEBUG "hfs: backup: %u,%u,%u,%u\n", HFSPLUS_SB(sb).blockoffset, |
173 | HFSPLUS_SB(sb).sect_count, block, offset); | 173 | HFSPLUS_SB(sb).sect_count, block, offset); |
174 | bh = sb_bread(sb, block); | 174 | bh = sb_bread(sb, block); |
175 | if (bh) { | 175 | if (bh) { |
@@ -179,7 +179,7 @@ static void hfsplus_write_super(struct super_block *sb) | |||
179 | mark_buffer_dirty(bh); | 179 | mark_buffer_dirty(bh); |
180 | brelse(bh); | 180 | brelse(bh); |
181 | } else | 181 | } else |
182 | printk("backup not found!\n"); | 182 | printk(KERN_WARNING "hfs: backup not found!\n"); |
183 | } | 183 | } |
184 | } | 184 | } |
185 | HFSPLUS_SB(sb).flags &= ~HFSPLUS_SB_WRITEBACKUP; | 185 | HFSPLUS_SB(sb).flags &= ~HFSPLUS_SB_WRITEBACKUP; |
@@ -240,18 +240,18 @@ static int hfsplus_remount(struct super_block *sb, int *flags, char *data) | |||
240 | return -EINVAL; | 240 | return -EINVAL; |
241 | 241 | ||
242 | if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) { | 242 | if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) { |
243 | printk("HFS+-fs warning: Filesystem was not cleanly unmounted, " | 243 | printk(KERN_WARNING "hfs: filesystem was not cleanly unmounted, " |
244 | "running fsck.hfsplus is recommended. leaving read-only.\n"); | 244 | "running fsck.hfsplus is recommended. leaving read-only.\n"); |
245 | sb->s_flags |= MS_RDONLY; | 245 | sb->s_flags |= MS_RDONLY; |
246 | *flags |= MS_RDONLY; | 246 | *flags |= MS_RDONLY; |
247 | } else if (sbi.flags & HFSPLUS_SB_FORCE) { | 247 | } else if (sbi.flags & HFSPLUS_SB_FORCE) { |
248 | /* nothing */ | 248 | /* nothing */ |
249 | } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) { | 249 | } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) { |
250 | printk("HFS+-fs: Filesystem is marked locked, leaving read-only.\n"); | 250 | printk(KERN_WARNING "hfs: filesystem is marked locked, leaving read-only.\n"); |
251 | sb->s_flags |= MS_RDONLY; | 251 | sb->s_flags |= MS_RDONLY; |
252 | *flags |= MS_RDONLY; | 252 | *flags |= MS_RDONLY; |
253 | } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) { | 253 | } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) { |
254 | printk("HFS+-fs: Filesystem is marked journaled, leaving read-only.\n"); | 254 | printk(KERN_WARNING "hfs: filesystem is marked journaled, leaving read-only.\n"); |
255 | sb->s_flags |= MS_RDONLY; | 255 | sb->s_flags |= MS_RDONLY; |
256 | *flags |= MS_RDONLY; | 256 | *flags |= MS_RDONLY; |
257 | } | 257 | } |
@@ -292,8 +292,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) | |||
292 | INIT_HLIST_HEAD(&sbi->rsrc_inodes); | 292 | INIT_HLIST_HEAD(&sbi->rsrc_inodes); |
293 | hfsplus_fill_defaults(sbi); | 293 | hfsplus_fill_defaults(sbi); |
294 | if (!hfsplus_parse_options(data, sbi)) { | 294 | if (!hfsplus_parse_options(data, sbi)) { |
295 | if (!silent) | 295 | printk(KERN_ERR "hfs: unable to parse mount options\n"); |
296 | printk("HFS+-fs: unable to parse mount options\n"); | ||
297 | err = -EINVAL; | 296 | err = -EINVAL; |
298 | goto cleanup; | 297 | goto cleanup; |
299 | } | 298 | } |
@@ -302,7 +301,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) | |||
302 | nls = sbi->nls; | 301 | nls = sbi->nls; |
303 | sbi->nls = load_nls("utf8"); | 302 | sbi->nls = load_nls("utf8"); |
304 | if (!sbi->nls) { | 303 | if (!sbi->nls) { |
305 | printk("HFS+: unable to load nls for utf8\n"); | 304 | printk(KERN_ERR "hfs: unable to load nls for utf8\n"); |
306 | err = -EINVAL; | 305 | err = -EINVAL; |
307 | goto cleanup; | 306 | goto cleanup; |
308 | } | 307 | } |
@@ -310,17 +309,17 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) | |||
310 | /* Grab the volume header */ | 309 | /* Grab the volume header */ |
311 | if (hfsplus_read_wrapper(sb)) { | 310 | if (hfsplus_read_wrapper(sb)) { |
312 | if (!silent) | 311 | if (!silent) |
313 | printk("HFS+-fs: unable to find HFS+ superblock\n"); | 312 | printk(KERN_WARNING "hfs: unable to find HFS+ superblock\n"); |
314 | err = -EINVAL; | 313 | err = -EINVAL; |
315 | goto cleanup; | 314 | goto cleanup; |
316 | } | 315 | } |
317 | vhdr = HFSPLUS_SB(sb).s_vhdr; | 316 | vhdr = HFSPLUS_SB(sb).s_vhdr; |
318 | 317 | ||
319 | /* Copy parts of the volume header into the superblock */ | 318 | /* Copy parts of the volume header into the superblock */ |
320 | sb->s_magic = be16_to_cpu(vhdr->signature); | 319 | sb->s_magic = HFSPLUS_VOLHEAD_SIG; |
321 | if (be16_to_cpu(vhdr->version) != HFSPLUS_CURRENT_VERSION) { | 320 | if (be16_to_cpu(vhdr->version) < HFSPLUS_MIN_VERSION || |
322 | if (!silent) | 321 | be16_to_cpu(vhdr->version) > HFSPLUS_CURRENT_VERSION) { |
323 | printk("HFS+-fs: wrong filesystem version\n"); | 322 | printk(KERN_ERR "hfs: wrong filesystem version\n"); |
324 | goto cleanup; | 323 | goto cleanup; |
325 | } | 324 | } |
326 | HFSPLUS_SB(sb).total_blocks = be32_to_cpu(vhdr->total_blocks); | 325 | HFSPLUS_SB(sb).total_blocks = be32_to_cpu(vhdr->total_blocks); |
@@ -341,20 +340,17 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) | |||
341 | sb->s_maxbytes = MAX_LFS_FILESIZE; | 340 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
342 | 341 | ||
343 | if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) { | 342 | if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) { |
344 | if (!silent) | 343 | printk(KERN_WARNING "hfs: Filesystem was not cleanly unmounted, " |
345 | printk("HFS+-fs warning: Filesystem was not cleanly unmounted, " | 344 | "running fsck.hfsplus is recommended. mounting read-only.\n"); |
346 | "running fsck.hfsplus is recommended. mounting read-only.\n"); | ||
347 | sb->s_flags |= MS_RDONLY; | 345 | sb->s_flags |= MS_RDONLY; |
348 | } else if (sbi->flags & HFSPLUS_SB_FORCE) { | 346 | } else if (sbi->flags & HFSPLUS_SB_FORCE) { |
349 | /* nothing */ | 347 | /* nothing */ |
350 | } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) { | 348 | } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) { |
351 | if (!silent) | 349 | printk(KERN_WARNING "hfs: Filesystem is marked locked, mounting read-only.\n"); |
352 | printk("HFS+-fs: Filesystem is marked locked, mounting read-only.\n"); | ||
353 | sb->s_flags |= MS_RDONLY; | 350 | sb->s_flags |= MS_RDONLY; |
354 | } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) { | 351 | } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) { |
355 | if (!silent) | 352 | printk(KERN_WARNING "hfs: write access to a jounaled filesystem is not supported, " |
356 | printk("HFS+-fs: write access to a jounaled filesystem is not supported, " | 353 | "use the force option at your own risk, mounting read-only.\n"); |
357 | "use the force option at your own risk, mounting read-only.\n"); | ||
358 | sb->s_flags |= MS_RDONLY; | 354 | sb->s_flags |= MS_RDONLY; |
359 | } | 355 | } |
360 | sbi->flags &= ~HFSPLUS_SB_FORCE; | 356 | sbi->flags &= ~HFSPLUS_SB_FORCE; |
@@ -362,21 +358,18 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) | |||
362 | /* Load metadata objects (B*Trees) */ | 358 | /* Load metadata objects (B*Trees) */ |
363 | HFSPLUS_SB(sb).ext_tree = hfs_btree_open(sb, HFSPLUS_EXT_CNID); | 359 | HFSPLUS_SB(sb).ext_tree = hfs_btree_open(sb, HFSPLUS_EXT_CNID); |
364 | if (!HFSPLUS_SB(sb).ext_tree) { | 360 | if (!HFSPLUS_SB(sb).ext_tree) { |
365 | if (!silent) | 361 | printk(KERN_ERR "hfs: failed to load extents file\n"); |
366 | printk("HFS+-fs: failed to load extents file\n"); | ||
367 | goto cleanup; | 362 | goto cleanup; |
368 | } | 363 | } |
369 | HFSPLUS_SB(sb).cat_tree = hfs_btree_open(sb, HFSPLUS_CAT_CNID); | 364 | HFSPLUS_SB(sb).cat_tree = hfs_btree_open(sb, HFSPLUS_CAT_CNID); |
370 | if (!HFSPLUS_SB(sb).cat_tree) { | 365 | if (!HFSPLUS_SB(sb).cat_tree) { |
371 | if (!silent) | 366 | printk(KERN_ERR "hfs: failed to load catalog file\n"); |
372 | printk("HFS+-fs: failed to load catalog file\n"); | ||
373 | goto cleanup; | 367 | goto cleanup; |
374 | } | 368 | } |
375 | 369 | ||
376 | HFSPLUS_SB(sb).alloc_file = iget(sb, HFSPLUS_ALLOC_CNID); | 370 | HFSPLUS_SB(sb).alloc_file = iget(sb, HFSPLUS_ALLOC_CNID); |
377 | if (!HFSPLUS_SB(sb).alloc_file) { | 371 | if (!HFSPLUS_SB(sb).alloc_file) { |
378 | if (!silent) | 372 | printk(KERN_ERR "hfs: failed to load allocation file\n"); |
379 | printk("HFS+-fs: failed to load allocation file\n"); | ||
380 | goto cleanup; | 373 | goto cleanup; |
381 | } | 374 | } |
382 | 375 | ||
@@ -384,8 +377,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) | |||
384 | root = iget(sb, HFSPLUS_ROOT_CNID); | 377 | root = iget(sb, HFSPLUS_ROOT_CNID); |
385 | sb->s_root = d_alloc_root(root); | 378 | sb->s_root = d_alloc_root(root); |
386 | if (!sb->s_root) { | 379 | if (!sb->s_root) { |
387 | if (!silent) | 380 | printk(KERN_ERR "hfs: failed to load root directory\n"); |
388 | printk("HFS+-fs: failed to load root directory\n"); | ||
389 | iput(root); | 381 | iput(root); |
390 | goto cleanup; | 382 | goto cleanup; |
391 | } | 383 | } |
@@ -419,7 +411,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) | |||
419 | sync_dirty_buffer(HFSPLUS_SB(sb).s_vhbh); | 411 | sync_dirty_buffer(HFSPLUS_SB(sb).s_vhbh); |
420 | 412 | ||
421 | if (!HFSPLUS_SB(sb).hidden_dir) { | 413 | if (!HFSPLUS_SB(sb).hidden_dir) { |
422 | printk("HFS+: create hidden dir...\n"); | 414 | printk(KERN_DEBUG "hfs: create hidden dir...\n"); |
423 | HFSPLUS_SB(sb).hidden_dir = hfsplus_new_inode(sb, S_IFDIR); | 415 | HFSPLUS_SB(sb).hidden_dir = hfsplus_new_inode(sb, S_IFDIR); |
424 | hfsplus_create_cat(HFSPLUS_SB(sb).hidden_dir->i_ino, sb->s_root->d_inode, | 416 | hfsplus_create_cat(HFSPLUS_SB(sb).hidden_dir->i_ino, sb->s_root->d_inode, |
425 | &str, HFSPLUS_SB(sb).hidden_dir); | 417 | &str, HFSPLUS_SB(sb).hidden_dir); |
@@ -499,7 +491,7 @@ static void __exit exit_hfsplus_fs(void) | |||
499 | { | 491 | { |
500 | unregister_filesystem(&hfsplus_fs_type); | 492 | unregister_filesystem(&hfsplus_fs_type); |
501 | if (kmem_cache_destroy(hfsplus_inode_cachep)) | 493 | if (kmem_cache_destroy(hfsplus_inode_cachep)) |
502 | printk(KERN_INFO "hfsplus_inode_cache: not all structures were freed\n"); | 494 | printk(KERN_ERR "hfsplus_inode_cache: not all structures were freed\n"); |
503 | } | 495 | } |
504 | 496 | ||
505 | module_init(init_hfsplus_fs) | 497 | module_init(init_hfsplus_fs) |
diff --git a/fs/hfsplus/unicode.c b/fs/hfsplus/unicode.c index 060c69048c3d..689c8bd721fb 100644 --- a/fs/hfsplus/unicode.c +++ b/fs/hfsplus/unicode.c | |||
@@ -28,7 +28,8 @@ static inline u16 case_fold(u16 c) | |||
28 | } | 28 | } |
29 | 29 | ||
30 | /* Compare unicode strings, return values like normal strcmp */ | 30 | /* Compare unicode strings, return values like normal strcmp */ |
31 | int hfsplus_unistrcmp(const struct hfsplus_unistr *s1, const struct hfsplus_unistr *s2) | 31 | int hfsplus_strcasecmp(const struct hfsplus_unistr *s1, |
32 | const struct hfsplus_unistr *s2) | ||
32 | { | 33 | { |
33 | u16 len1, len2, c1, c2; | 34 | u16 len1, len2, c1, c2; |
34 | const hfsplus_unichr *p1, *p2; | 35 | const hfsplus_unichr *p1, *p2; |
@@ -59,6 +60,33 @@ int hfsplus_unistrcmp(const struct hfsplus_unistr *s1, const struct hfsplus_unis | |||
59 | } | 60 | } |
60 | } | 61 | } |
61 | 62 | ||
63 | /* Compare names as a sequence of 16-bit unsigned integers */ | ||
64 | int hfsplus_strcmp(const struct hfsplus_unistr *s1, | ||
65 | const struct hfsplus_unistr *s2) | ||
66 | { | ||
67 | u16 len1, len2, c1, c2; | ||
68 | const hfsplus_unichr *p1, *p2; | ||
69 | int len; | ||
70 | |||
71 | len1 = be16_to_cpu(s1->length); | ||
72 | len2 = be16_to_cpu(s2->length); | ||
73 | p1 = s1->unicode; | ||
74 | p2 = s2->unicode; | ||
75 | |||
76 | for (len = min(len1, len2); len > 0; len--) { | ||
77 | c1 = be16_to_cpu(*p1); | ||
78 | c2 = be16_to_cpu(*p2); | ||
79 | if (c1 != c2) | ||
80 | return c1 < c2 ? -1 : 1; | ||
81 | p1++; | ||
82 | p2++; | ||
83 | } | ||
84 | |||
85 | return len1 < len2 ? -1 : | ||
86 | len1 > len2 ? 1 : 0; | ||
87 | } | ||
88 | |||
89 | |||
62 | #define Hangul_SBase 0xac00 | 90 | #define Hangul_SBase 0xac00 |
63 | #define Hangul_LBase 0x1100 | 91 | #define Hangul_LBase 0x1100 |
64 | #define Hangul_VBase 0x1161 | 92 | #define Hangul_VBase 0x1161 |
diff --git a/fs/hfsplus/wrapper.c b/fs/hfsplus/wrapper.c index 95455e839231..72cab78f0509 100644 --- a/fs/hfsplus/wrapper.c +++ b/fs/hfsplus/wrapper.c | |||
@@ -28,8 +28,11 @@ static int hfsplus_read_mdb(void *bufptr, struct hfsplus_wd *wd) | |||
28 | { | 28 | { |
29 | u32 extent; | 29 | u32 extent; |
30 | u16 attrib; | 30 | u16 attrib; |
31 | __be16 sig; | ||
31 | 32 | ||
32 | if (be16_to_cpu(*(__be16 *)(bufptr + HFSP_WRAPOFF_EMBEDSIG)) != HFSPLUS_VOLHEAD_SIG) | 33 | sig = *(__be16 *)(bufptr + HFSP_WRAPOFF_EMBEDSIG); |
34 | if (sig != cpu_to_be16(HFSPLUS_VOLHEAD_SIG) && | ||
35 | sig != cpu_to_be16(HFSPLUS_VOLHEAD_SIGX)) | ||
33 | return 0; | 36 | return 0; |
34 | 37 | ||
35 | attrib = be16_to_cpu(*(__be16 *)(bufptr + HFSP_WRAPOFF_ATTRIB)); | 38 | attrib = be16_to_cpu(*(__be16 *)(bufptr + HFSP_WRAPOFF_ATTRIB)); |
@@ -70,7 +73,7 @@ static int hfsplus_get_last_session(struct super_block *sb, | |||
70 | *start = (sector_t)te.cdte_addr.lba << 2; | 73 | *start = (sector_t)te.cdte_addr.lba << 2; |
71 | return 0; | 74 | return 0; |
72 | } | 75 | } |
73 | printk(KERN_ERR "HFS: Invalid session number or type of track\n"); | 76 | printk(KERN_ERR "hfs: invalid session number or type of track\n"); |
74 | return -EINVAL; | 77 | return -EINVAL; |
75 | } | 78 | } |
76 | ms_info.addr_format = CDROM_LBA; | 79 | ms_info.addr_format = CDROM_LBA; |
@@ -114,6 +117,10 @@ int hfsplus_read_wrapper(struct super_block *sb) | |||
114 | } | 117 | } |
115 | if (vhdr->signature == cpu_to_be16(HFSPLUS_VOLHEAD_SIG)) | 118 | if (vhdr->signature == cpu_to_be16(HFSPLUS_VOLHEAD_SIG)) |
116 | break; | 119 | break; |
120 | if (vhdr->signature == cpu_to_be16(HFSPLUS_VOLHEAD_SIGX)) { | ||
121 | HFSPLUS_SB(sb).flags |= HFSPLUS_SB_HFSX; | ||
122 | break; | ||
123 | } | ||
117 | brelse(bh); | 124 | brelse(bh); |
118 | 125 | ||
119 | /* check for a partition block | 126 | /* check for a partition block |
@@ -143,7 +150,7 @@ int hfsplus_read_wrapper(struct super_block *sb) | |||
143 | blocksize >>= 1; | 150 | blocksize >>= 1; |
144 | 151 | ||
145 | if (sb_set_blocksize(sb, blocksize) != blocksize) { | 152 | if (sb_set_blocksize(sb, blocksize) != blocksize) { |
146 | printk("HFS+: unable to blocksize to %u!\n", blocksize); | 153 | printk(KERN_ERR "hfs: unable to set blocksize to %u!\n", blocksize); |
147 | return -EINVAL; | 154 | return -EINVAL; |
148 | } | 155 | } |
149 | 156 | ||
@@ -158,7 +165,9 @@ int hfsplus_read_wrapper(struct super_block *sb) | |||
158 | return -EIO; | 165 | return -EIO; |
159 | 166 | ||
160 | /* should still be the same... */ | 167 | /* should still be the same... */ |
161 | if (be16_to_cpu(vhdr->signature) != HFSPLUS_VOLHEAD_SIG) | 168 | if (vhdr->signature != (HFSPLUS_SB(sb).flags & HFSPLUS_SB_HFSX ? |
169 | cpu_to_be16(HFSPLUS_VOLHEAD_SIGX) : | ||
170 | cpu_to_be16(HFSPLUS_VOLHEAD_SIG))) | ||
162 | goto error; | 171 | goto error; |
163 | HFSPLUS_SB(sb).s_vhbh = bh; | 172 | HFSPLUS_SB(sb).s_vhbh = bh; |
164 | HFSPLUS_SB(sb).s_vhdr = vhdr; | 173 | HFSPLUS_SB(sb).s_vhdr = vhdr; |
diff --git a/fs/inotify.c b/fs/inotify.c index 2fecb7af4a77..878ccca61213 100644 --- a/fs/inotify.c +++ b/fs/inotify.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/list.h> | 33 | #include <linux/list.h> |
34 | #include <linux/writeback.h> | 34 | #include <linux/writeback.h> |
35 | #include <linux/inotify.h> | 35 | #include <linux/inotify.h> |
36 | #include <linux/syscalls.h> | ||
36 | 37 | ||
37 | #include <asm/ioctls.h> | 38 | #include <asm/ioctls.h> |
38 | 39 | ||
diff --git a/fs/jbd/checkpoint.c b/fs/jbd/checkpoint.c index cb3cef525c3b..e6265a0b56b8 100644 --- a/fs/jbd/checkpoint.c +++ b/fs/jbd/checkpoint.c | |||
@@ -338,7 +338,7 @@ restart: | |||
338 | * done (maybe it's a new transaction, but it fell at the same | 338 | * done (maybe it's a new transaction, but it fell at the same |
339 | * address). | 339 | * address). |
340 | */ | 340 | */ |
341 | if (journal->j_checkpoint_transactions == transaction || | 341 | if (journal->j_checkpoint_transactions == transaction && |
342 | transaction->t_tid == this_tid) { | 342 | transaction->t_tid == this_tid) { |
343 | int batch_count = 0; | 343 | int batch_count = 0; |
344 | struct buffer_head *bhs[NR_BATCH]; | 344 | struct buffer_head *bhs[NR_BATCH]; |
diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c index 002ad2bbc769..29e62d98bae6 100644 --- a/fs/jbd/commit.c +++ b/fs/jbd/commit.c | |||
@@ -829,7 +829,8 @@ restart_loop: | |||
829 | journal->j_committing_transaction = NULL; | 829 | journal->j_committing_transaction = NULL; |
830 | spin_unlock(&journal->j_state_lock); | 830 | spin_unlock(&journal->j_state_lock); |
831 | 831 | ||
832 | if (commit_transaction->t_checkpoint_list == NULL) { | 832 | if (commit_transaction->t_checkpoint_list == NULL && |
833 | commit_transaction->t_checkpoint_io_list == NULL) { | ||
833 | __journal_drop_transaction(journal, commit_transaction); | 834 | __journal_drop_transaction(journal, commit_transaction); |
834 | } else { | 835 | } else { |
835 | if (journal->j_checkpoint_transactions == NULL) { | 836 | if (journal->j_checkpoint_transactions == NULL) { |
diff --git a/fs/namei.c b/fs/namei.c index 33fb5bd34a81..4acdac043b6b 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -30,6 +30,8 @@ | |||
30 | #include <linux/audit.h> | 30 | #include <linux/audit.h> |
31 | #include <linux/capability.h> | 31 | #include <linux/capability.h> |
32 | #include <linux/file.h> | 32 | #include <linux/file.h> |
33 | #include <linux/fcntl.h> | ||
34 | #include <linux/namei.h> | ||
33 | #include <asm/namei.h> | 35 | #include <asm/namei.h> |
34 | #include <asm/uaccess.h> | 36 | #include <asm/uaccess.h> |
35 | 37 | ||
@@ -1063,7 +1065,8 @@ set_it: | |||
1063 | } | 1065 | } |
1064 | 1066 | ||
1065 | /* Returns 0 and nd will be valid on success; Retuns error, otherwise. */ | 1067 | /* Returns 0 and nd will be valid on success; Retuns error, otherwise. */ |
1066 | int fastcall path_lookup(const char *name, unsigned int flags, struct nameidata *nd) | 1068 | static int fastcall do_path_lookup(int dfd, const char *name, |
1069 | unsigned int flags, struct nameidata *nd) | ||
1067 | { | 1070 | { |
1068 | int retval = 0; | 1071 | int retval = 0; |
1069 | 1072 | ||
@@ -1083,9 +1086,38 @@ int fastcall path_lookup(const char *name, unsigned int flags, struct nameidata | |||
1083 | } | 1086 | } |
1084 | nd->mnt = mntget(current->fs->rootmnt); | 1087 | nd->mnt = mntget(current->fs->rootmnt); |
1085 | nd->dentry = dget(current->fs->root); | 1088 | nd->dentry = dget(current->fs->root); |
1086 | } else { | 1089 | } else if (dfd == AT_FDCWD) { |
1087 | nd->mnt = mntget(current->fs->pwdmnt); | 1090 | nd->mnt = mntget(current->fs->pwdmnt); |
1088 | nd->dentry = dget(current->fs->pwd); | 1091 | nd->dentry = dget(current->fs->pwd); |
1092 | } else { | ||
1093 | struct file *file; | ||
1094 | int fput_needed; | ||
1095 | struct dentry *dentry; | ||
1096 | |||
1097 | file = fget_light(dfd, &fput_needed); | ||
1098 | if (!file) { | ||
1099 | retval = -EBADF; | ||
1100 | goto out_fail; | ||
1101 | } | ||
1102 | |||
1103 | dentry = file->f_dentry; | ||
1104 | |||
1105 | if (!S_ISDIR(dentry->d_inode->i_mode)) { | ||
1106 | retval = -ENOTDIR; | ||
1107 | fput_light(file, fput_needed); | ||
1108 | goto out_fail; | ||
1109 | } | ||
1110 | |||
1111 | retval = file_permission(file, MAY_EXEC); | ||
1112 | if (retval) { | ||
1113 | fput_light(file, fput_needed); | ||
1114 | goto out_fail; | ||
1115 | } | ||
1116 | |||
1117 | nd->mnt = mntget(file->f_vfsmnt); | ||
1118 | nd->dentry = dget(dentry); | ||
1119 | |||
1120 | fput_light(file, fput_needed); | ||
1089 | } | 1121 | } |
1090 | read_unlock(¤t->fs->lock); | 1122 | read_unlock(¤t->fs->lock); |
1091 | current->total_link_count = 0; | 1123 | current->total_link_count = 0; |
@@ -1094,11 +1126,19 @@ out: | |||
1094 | if (unlikely(current->audit_context | 1126 | if (unlikely(current->audit_context |
1095 | && nd && nd->dentry && nd->dentry->d_inode)) | 1127 | && nd && nd->dentry && nd->dentry->d_inode)) |
1096 | audit_inode(name, nd->dentry->d_inode, flags); | 1128 | audit_inode(name, nd->dentry->d_inode, flags); |
1129 | out_fail: | ||
1097 | return retval; | 1130 | return retval; |
1098 | } | 1131 | } |
1099 | 1132 | ||
1100 | static int __path_lookup_intent_open(const char *name, unsigned int lookup_flags, | 1133 | int fastcall path_lookup(const char *name, unsigned int flags, |
1101 | struct nameidata *nd, int open_flags, int create_mode) | 1134 | struct nameidata *nd) |
1135 | { | ||
1136 | return do_path_lookup(AT_FDCWD, name, flags, nd); | ||
1137 | } | ||
1138 | |||
1139 | static int __path_lookup_intent_open(int dfd, const char *name, | ||
1140 | unsigned int lookup_flags, struct nameidata *nd, | ||
1141 | int open_flags, int create_mode) | ||
1102 | { | 1142 | { |
1103 | struct file *filp = get_empty_filp(); | 1143 | struct file *filp = get_empty_filp(); |
1104 | int err; | 1144 | int err; |
@@ -1108,7 +1148,7 @@ static int __path_lookup_intent_open(const char *name, unsigned int lookup_flags | |||
1108 | nd->intent.open.file = filp; | 1148 | nd->intent.open.file = filp; |
1109 | nd->intent.open.flags = open_flags; | 1149 | nd->intent.open.flags = open_flags; |
1110 | nd->intent.open.create_mode = create_mode; | 1150 | nd->intent.open.create_mode = create_mode; |
1111 | err = path_lookup(name, lookup_flags|LOOKUP_OPEN, nd); | 1151 | err = do_path_lookup(dfd, name, lookup_flags|LOOKUP_OPEN, nd); |
1112 | if (IS_ERR(nd->intent.open.file)) { | 1152 | if (IS_ERR(nd->intent.open.file)) { |
1113 | if (err == 0) { | 1153 | if (err == 0) { |
1114 | err = PTR_ERR(nd->intent.open.file); | 1154 | err = PTR_ERR(nd->intent.open.file); |
@@ -1126,10 +1166,10 @@ static int __path_lookup_intent_open(const char *name, unsigned int lookup_flags | |||
1126 | * @nd: pointer to nameidata | 1166 | * @nd: pointer to nameidata |
1127 | * @open_flags: open intent flags | 1167 | * @open_flags: open intent flags |
1128 | */ | 1168 | */ |
1129 | int path_lookup_open(const char *name, unsigned int lookup_flags, | 1169 | int path_lookup_open(int dfd, const char *name, unsigned int lookup_flags, |
1130 | struct nameidata *nd, int open_flags) | 1170 | struct nameidata *nd, int open_flags) |
1131 | { | 1171 | { |
1132 | return __path_lookup_intent_open(name, lookup_flags, nd, | 1172 | return __path_lookup_intent_open(dfd, name, lookup_flags, nd, |
1133 | open_flags, 0); | 1173 | open_flags, 0); |
1134 | } | 1174 | } |
1135 | 1175 | ||
@@ -1141,12 +1181,12 @@ int path_lookup_open(const char *name, unsigned int lookup_flags, | |||
1141 | * @open_flags: open intent flags | 1181 | * @open_flags: open intent flags |
1142 | * @create_mode: create intent flags | 1182 | * @create_mode: create intent flags |
1143 | */ | 1183 | */ |
1144 | static int path_lookup_create(const char *name, unsigned int lookup_flags, | 1184 | static int path_lookup_create(int dfd, const char *name, |
1145 | struct nameidata *nd, int open_flags, | 1185 | unsigned int lookup_flags, struct nameidata *nd, |
1146 | int create_mode) | 1186 | int open_flags, int create_mode) |
1147 | { | 1187 | { |
1148 | return __path_lookup_intent_open(name, lookup_flags|LOOKUP_CREATE, nd, | 1188 | return __path_lookup_intent_open(dfd, name, lookup_flags|LOOKUP_CREATE, |
1149 | open_flags, create_mode); | 1189 | nd, open_flags, create_mode); |
1150 | } | 1190 | } |
1151 | 1191 | ||
1152 | int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags, | 1192 | int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags, |
@@ -1156,7 +1196,7 @@ int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags, | |||
1156 | int err = PTR_ERR(tmp); | 1196 | int err = PTR_ERR(tmp); |
1157 | 1197 | ||
1158 | if (!IS_ERR(tmp)) { | 1198 | if (!IS_ERR(tmp)) { |
1159 | err = __path_lookup_intent_open(tmp, lookup_flags, nd, open_flags, 0); | 1199 | err = __path_lookup_intent_open(AT_FDCWD, tmp, lookup_flags, nd, open_flags, 0); |
1160 | putname(tmp); | 1200 | putname(tmp); |
1161 | } | 1201 | } |
1162 | return err; | 1202 | return err; |
@@ -1248,18 +1288,24 @@ access: | |||
1248 | * that namei follows links, while lnamei does not. | 1288 | * that namei follows links, while lnamei does not. |
1249 | * SMP-safe | 1289 | * SMP-safe |
1250 | */ | 1290 | */ |
1251 | int fastcall __user_walk(const char __user *name, unsigned flags, struct nameidata *nd) | 1291 | int fastcall __user_walk_fd(int dfd, const char __user *name, unsigned flags, |
1292 | struct nameidata *nd) | ||
1252 | { | 1293 | { |
1253 | char *tmp = getname(name); | 1294 | char *tmp = getname(name); |
1254 | int err = PTR_ERR(tmp); | 1295 | int err = PTR_ERR(tmp); |
1255 | 1296 | ||
1256 | if (!IS_ERR(tmp)) { | 1297 | if (!IS_ERR(tmp)) { |
1257 | err = path_lookup(tmp, flags, nd); | 1298 | err = do_path_lookup(dfd, tmp, flags, nd); |
1258 | putname(tmp); | 1299 | putname(tmp); |
1259 | } | 1300 | } |
1260 | return err; | 1301 | return err; |
1261 | } | 1302 | } |
1262 | 1303 | ||
1304 | int fastcall __user_walk(const char __user *name, unsigned flags, struct nameidata *nd) | ||
1305 | { | ||
1306 | return __user_walk_fd(AT_FDCWD, name, flags, nd); | ||
1307 | } | ||
1308 | |||
1263 | /* | 1309 | /* |
1264 | * It's inline, so penalty for filesystems that don't use sticky bit is | 1310 | * It's inline, so penalty for filesystems that don't use sticky bit is |
1265 | * minimal. | 1311 | * minimal. |
@@ -1518,7 +1564,8 @@ int may_open(struct nameidata *nd, int acc_mode, int flag) | |||
1518 | * for symlinks (where the permissions are checked later). | 1564 | * for symlinks (where the permissions are checked later). |
1519 | * SMP-safe | 1565 | * SMP-safe |
1520 | */ | 1566 | */ |
1521 | int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) | 1567 | int open_namei(int dfd, const char *pathname, int flag, |
1568 | int mode, struct nameidata *nd) | ||
1522 | { | 1569 | { |
1523 | int acc_mode, error; | 1570 | int acc_mode, error; |
1524 | struct path path; | 1571 | struct path path; |
@@ -1540,7 +1587,8 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) | |||
1540 | * The simplest case - just a plain lookup. | 1587 | * The simplest case - just a plain lookup. |
1541 | */ | 1588 | */ |
1542 | if (!(flag & O_CREAT)) { | 1589 | if (!(flag & O_CREAT)) { |
1543 | error = path_lookup_open(pathname, lookup_flags(flag), nd, flag); | 1590 | error = path_lookup_open(dfd, pathname, lookup_flags(flag), |
1591 | nd, flag); | ||
1544 | if (error) | 1592 | if (error) |
1545 | return error; | 1593 | return error; |
1546 | goto ok; | 1594 | goto ok; |
@@ -1549,7 +1597,7 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) | |||
1549 | /* | 1597 | /* |
1550 | * Create - we need to know the parent. | 1598 | * Create - we need to know the parent. |
1551 | */ | 1599 | */ |
1552 | error = path_lookup_create(pathname, LOOKUP_PARENT, nd, flag, mode); | 1600 | error = path_lookup_create(dfd,pathname,LOOKUP_PARENT,nd,flag,mode); |
1553 | if (error) | 1601 | if (error) |
1554 | return error; | 1602 | return error; |
1555 | 1603 | ||
@@ -1744,7 +1792,8 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) | |||
1744 | return error; | 1792 | return error; |
1745 | } | 1793 | } |
1746 | 1794 | ||
1747 | asmlinkage long sys_mknod(const char __user * filename, int mode, unsigned dev) | 1795 | asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode, |
1796 | unsigned dev) | ||
1748 | { | 1797 | { |
1749 | int error = 0; | 1798 | int error = 0; |
1750 | char * tmp; | 1799 | char * tmp; |
@@ -1757,7 +1806,7 @@ asmlinkage long sys_mknod(const char __user * filename, int mode, unsigned dev) | |||
1757 | if (IS_ERR(tmp)) | 1806 | if (IS_ERR(tmp)) |
1758 | return PTR_ERR(tmp); | 1807 | return PTR_ERR(tmp); |
1759 | 1808 | ||
1760 | error = path_lookup(tmp, LOOKUP_PARENT, &nd); | 1809 | error = do_path_lookup(dfd, tmp, LOOKUP_PARENT, &nd); |
1761 | if (error) | 1810 | if (error) |
1762 | goto out; | 1811 | goto out; |
1763 | dentry = lookup_create(&nd, 0); | 1812 | dentry = lookup_create(&nd, 0); |
@@ -1793,6 +1842,11 @@ out: | |||
1793 | return error; | 1842 | return error; |
1794 | } | 1843 | } |
1795 | 1844 | ||
1845 | asmlinkage long sys_mknod(const char __user *filename, int mode, unsigned dev) | ||
1846 | { | ||
1847 | return sys_mknodat(AT_FDCWD, filename, mode, dev); | ||
1848 | } | ||
1849 | |||
1796 | int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | 1850 | int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) |
1797 | { | 1851 | { |
1798 | int error = may_create(dir, dentry, NULL); | 1852 | int error = may_create(dir, dentry, NULL); |
@@ -1815,7 +1869,7 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
1815 | return error; | 1869 | return error; |
1816 | } | 1870 | } |
1817 | 1871 | ||
1818 | asmlinkage long sys_mkdir(const char __user * pathname, int mode) | 1872 | asmlinkage long sys_mkdirat(int dfd, const char __user *pathname, int mode) |
1819 | { | 1873 | { |
1820 | int error = 0; | 1874 | int error = 0; |
1821 | char * tmp; | 1875 | char * tmp; |
@@ -1826,7 +1880,7 @@ asmlinkage long sys_mkdir(const char __user * pathname, int mode) | |||
1826 | struct dentry *dentry; | 1880 | struct dentry *dentry; |
1827 | struct nameidata nd; | 1881 | struct nameidata nd; |
1828 | 1882 | ||
1829 | error = path_lookup(tmp, LOOKUP_PARENT, &nd); | 1883 | error = do_path_lookup(dfd, tmp, LOOKUP_PARENT, &nd); |
1830 | if (error) | 1884 | if (error) |
1831 | goto out; | 1885 | goto out; |
1832 | dentry = lookup_create(&nd, 1); | 1886 | dentry = lookup_create(&nd, 1); |
@@ -1846,6 +1900,11 @@ out: | |||
1846 | return error; | 1900 | return error; |
1847 | } | 1901 | } |
1848 | 1902 | ||
1903 | asmlinkage long sys_mkdir(const char __user *pathname, int mode) | ||
1904 | { | ||
1905 | return sys_mkdirat(AT_FDCWD, pathname, mode); | ||
1906 | } | ||
1907 | |||
1849 | /* | 1908 | /* |
1850 | * We try to drop the dentry early: we should have | 1909 | * We try to drop the dentry early: we should have |
1851 | * a usage count of 2 if we're the only user of this | 1910 | * a usage count of 2 if we're the only user of this |
@@ -1907,7 +1966,7 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
1907 | return error; | 1966 | return error; |
1908 | } | 1967 | } |
1909 | 1968 | ||
1910 | asmlinkage long sys_rmdir(const char __user * pathname) | 1969 | static long do_rmdir(int dfd, const char __user *pathname) |
1911 | { | 1970 | { |
1912 | int error = 0; | 1971 | int error = 0; |
1913 | char * name; | 1972 | char * name; |
@@ -1918,7 +1977,7 @@ asmlinkage long sys_rmdir(const char __user * pathname) | |||
1918 | if(IS_ERR(name)) | 1977 | if(IS_ERR(name)) |
1919 | return PTR_ERR(name); | 1978 | return PTR_ERR(name); |
1920 | 1979 | ||
1921 | error = path_lookup(name, LOOKUP_PARENT, &nd); | 1980 | error = do_path_lookup(dfd, name, LOOKUP_PARENT, &nd); |
1922 | if (error) | 1981 | if (error) |
1923 | goto exit; | 1982 | goto exit; |
1924 | 1983 | ||
@@ -1948,6 +2007,11 @@ exit: | |||
1948 | return error; | 2007 | return error; |
1949 | } | 2008 | } |
1950 | 2009 | ||
2010 | asmlinkage long sys_rmdir(const char __user *pathname) | ||
2011 | { | ||
2012 | return do_rmdir(AT_FDCWD, pathname); | ||
2013 | } | ||
2014 | |||
1951 | int vfs_unlink(struct inode *dir, struct dentry *dentry) | 2015 | int vfs_unlink(struct inode *dir, struct dentry *dentry) |
1952 | { | 2016 | { |
1953 | int error = may_delete(dir, dentry, 0); | 2017 | int error = may_delete(dir, dentry, 0); |
@@ -1984,7 +2048,7 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry) | |||
1984 | * writeout happening, and we don't want to prevent access to the directory | 2048 | * writeout happening, and we don't want to prevent access to the directory |
1985 | * while waiting on the I/O. | 2049 | * while waiting on the I/O. |
1986 | */ | 2050 | */ |
1987 | asmlinkage long sys_unlink(const char __user * pathname) | 2051 | static long do_unlinkat(int dfd, const char __user *pathname) |
1988 | { | 2052 | { |
1989 | int error = 0; | 2053 | int error = 0; |
1990 | char * name; | 2054 | char * name; |
@@ -1996,7 +2060,7 @@ asmlinkage long sys_unlink(const char __user * pathname) | |||
1996 | if(IS_ERR(name)) | 2060 | if(IS_ERR(name)) |
1997 | return PTR_ERR(name); | 2061 | return PTR_ERR(name); |
1998 | 2062 | ||
1999 | error = path_lookup(name, LOOKUP_PARENT, &nd); | 2063 | error = do_path_lookup(dfd, name, LOOKUP_PARENT, &nd); |
2000 | if (error) | 2064 | if (error) |
2001 | goto exit; | 2065 | goto exit; |
2002 | error = -EISDIR; | 2066 | error = -EISDIR; |
@@ -2031,6 +2095,22 @@ slashes: | |||
2031 | goto exit2; | 2095 | goto exit2; |
2032 | } | 2096 | } |
2033 | 2097 | ||
2098 | asmlinkage long sys_unlinkat(int dfd, const char __user *pathname, int flag) | ||
2099 | { | ||
2100 | if ((flag & ~AT_REMOVEDIR) != 0) | ||
2101 | return -EINVAL; | ||
2102 | |||
2103 | if (flag & AT_REMOVEDIR) | ||
2104 | return do_rmdir(dfd, pathname); | ||
2105 | |||
2106 | return do_unlinkat(dfd, pathname); | ||
2107 | } | ||
2108 | |||
2109 | asmlinkage long sys_unlink(const char __user *pathname) | ||
2110 | { | ||
2111 | return do_unlinkat(AT_FDCWD, pathname); | ||
2112 | } | ||
2113 | |||
2034 | int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname, int mode) | 2114 | int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname, int mode) |
2035 | { | 2115 | { |
2036 | int error = may_create(dir, dentry, NULL); | 2116 | int error = may_create(dir, dentry, NULL); |
@@ -2052,7 +2132,8 @@ int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname, i | |||
2052 | return error; | 2132 | return error; |
2053 | } | 2133 | } |
2054 | 2134 | ||
2055 | asmlinkage long sys_symlink(const char __user * oldname, const char __user * newname) | 2135 | asmlinkage long sys_symlinkat(const char __user *oldname, |
2136 | int newdfd, const char __user *newname) | ||
2056 | { | 2137 | { |
2057 | int error = 0; | 2138 | int error = 0; |
2058 | char * from; | 2139 | char * from; |
@@ -2067,7 +2148,7 @@ asmlinkage long sys_symlink(const char __user * oldname, const char __user * new | |||
2067 | struct dentry *dentry; | 2148 | struct dentry *dentry; |
2068 | struct nameidata nd; | 2149 | struct nameidata nd; |
2069 | 2150 | ||
2070 | error = path_lookup(to, LOOKUP_PARENT, &nd); | 2151 | error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd); |
2071 | if (error) | 2152 | if (error) |
2072 | goto out; | 2153 | goto out; |
2073 | dentry = lookup_create(&nd, 0); | 2154 | dentry = lookup_create(&nd, 0); |
@@ -2085,6 +2166,11 @@ out: | |||
2085 | return error; | 2166 | return error; |
2086 | } | 2167 | } |
2087 | 2168 | ||
2169 | asmlinkage long sys_symlink(const char __user *oldname, const char __user *newname) | ||
2170 | { | ||
2171 | return sys_symlinkat(oldname, AT_FDCWD, newname); | ||
2172 | } | ||
2173 | |||
2088 | int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) | 2174 | int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) |
2089 | { | 2175 | { |
2090 | struct inode *inode = old_dentry->d_inode; | 2176 | struct inode *inode = old_dentry->d_inode; |
@@ -2132,7 +2218,8 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de | |||
2132 | * with linux 2.0, and to avoid hard-linking to directories | 2218 | * with linux 2.0, and to avoid hard-linking to directories |
2133 | * and other special files. --ADM | 2219 | * and other special files. --ADM |
2134 | */ | 2220 | */ |
2135 | asmlinkage long sys_link(const char __user * oldname, const char __user * newname) | 2221 | asmlinkage long sys_linkat(int olddfd, const char __user *oldname, |
2222 | int newdfd, const char __user *newname) | ||
2136 | { | 2223 | { |
2137 | struct dentry *new_dentry; | 2224 | struct dentry *new_dentry; |
2138 | struct nameidata nd, old_nd; | 2225 | struct nameidata nd, old_nd; |
@@ -2143,10 +2230,10 @@ asmlinkage long sys_link(const char __user * oldname, const char __user * newnam | |||
2143 | if (IS_ERR(to)) | 2230 | if (IS_ERR(to)) |
2144 | return PTR_ERR(to); | 2231 | return PTR_ERR(to); |
2145 | 2232 | ||
2146 | error = __user_walk(oldname, 0, &old_nd); | 2233 | error = __user_walk_fd(olddfd, oldname, 0, &old_nd); |
2147 | if (error) | 2234 | if (error) |
2148 | goto exit; | 2235 | goto exit; |
2149 | error = path_lookup(to, LOOKUP_PARENT, &nd); | 2236 | error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd); |
2150 | if (error) | 2237 | if (error) |
2151 | goto out; | 2238 | goto out; |
2152 | error = -EXDEV; | 2239 | error = -EXDEV; |
@@ -2169,6 +2256,11 @@ exit: | |||
2169 | return error; | 2256 | return error; |
2170 | } | 2257 | } |
2171 | 2258 | ||
2259 | asmlinkage long sys_link(const char __user *oldname, const char __user *newname) | ||
2260 | { | ||
2261 | return sys_linkat(AT_FDCWD, oldname, AT_FDCWD, newname); | ||
2262 | } | ||
2263 | |||
2172 | /* | 2264 | /* |
2173 | * The worst of all namespace operations - renaming directory. "Perverted" | 2265 | * The worst of all namespace operations - renaming directory. "Perverted" |
2174 | * doesn't even start to describe it. Somebody in UCB had a heck of a trip... | 2266 | * doesn't even start to describe it. Somebody in UCB had a heck of a trip... |
@@ -2315,7 +2407,8 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
2315 | return error; | 2407 | return error; |
2316 | } | 2408 | } |
2317 | 2409 | ||
2318 | static int do_rename(const char * oldname, const char * newname) | 2410 | static int do_rename(int olddfd, const char *oldname, |
2411 | int newdfd, const char *newname) | ||
2319 | { | 2412 | { |
2320 | int error = 0; | 2413 | int error = 0; |
2321 | struct dentry * old_dir, * new_dir; | 2414 | struct dentry * old_dir, * new_dir; |
@@ -2323,11 +2416,11 @@ static int do_rename(const char * oldname, const char * newname) | |||
2323 | struct dentry * trap; | 2416 | struct dentry * trap; |
2324 | struct nameidata oldnd, newnd; | 2417 | struct nameidata oldnd, newnd; |
2325 | 2418 | ||
2326 | error = path_lookup(oldname, LOOKUP_PARENT, &oldnd); | 2419 | error = do_path_lookup(olddfd, oldname, LOOKUP_PARENT, &oldnd); |
2327 | if (error) | 2420 | if (error) |
2328 | goto exit; | 2421 | goto exit; |
2329 | 2422 | ||
2330 | error = path_lookup(newname, LOOKUP_PARENT, &newnd); | 2423 | error = do_path_lookup(newdfd, newname, LOOKUP_PARENT, &newnd); |
2331 | if (error) | 2424 | if (error) |
2332 | goto exit1; | 2425 | goto exit1; |
2333 | 2426 | ||
@@ -2391,7 +2484,8 @@ exit: | |||
2391 | return error; | 2484 | return error; |
2392 | } | 2485 | } |
2393 | 2486 | ||
2394 | asmlinkage long sys_rename(const char __user * oldname, const char __user * newname) | 2487 | asmlinkage long sys_renameat(int olddfd, const char __user *oldname, |
2488 | int newdfd, const char __user *newname) | ||
2395 | { | 2489 | { |
2396 | int error; | 2490 | int error; |
2397 | char * from; | 2491 | char * from; |
@@ -2403,13 +2497,18 @@ asmlinkage long sys_rename(const char __user * oldname, const char __user * newn | |||
2403 | to = getname(newname); | 2497 | to = getname(newname); |
2404 | error = PTR_ERR(to); | 2498 | error = PTR_ERR(to); |
2405 | if (!IS_ERR(to)) { | 2499 | if (!IS_ERR(to)) { |
2406 | error = do_rename(from,to); | 2500 | error = do_rename(olddfd, from, newdfd, to); |
2407 | putname(to); | 2501 | putname(to); |
2408 | } | 2502 | } |
2409 | putname(from); | 2503 | putname(from); |
2410 | return error; | 2504 | return error; |
2411 | } | 2505 | } |
2412 | 2506 | ||
2507 | asmlinkage long sys_rename(const char __user *oldname, const char __user *newname) | ||
2508 | { | ||
2509 | return sys_renameat(AT_FDCWD, oldname, AT_FDCWD, newname); | ||
2510 | } | ||
2511 | |||
2413 | int vfs_readlink(struct dentry *dentry, char __user *buffer, int buflen, const char *link) | 2512 | int vfs_readlink(struct dentry *dentry, char __user *buffer, int buflen, const char *link) |
2414 | { | 2513 | { |
2415 | int len; | 2514 | int len; |
@@ -2553,6 +2652,7 @@ struct inode_operations page_symlink_inode_operations = { | |||
2553 | }; | 2652 | }; |
2554 | 2653 | ||
2555 | EXPORT_SYMBOL(__user_walk); | 2654 | EXPORT_SYMBOL(__user_walk); |
2655 | EXPORT_SYMBOL(__user_walk_fd); | ||
2556 | EXPORT_SYMBOL(follow_down); | 2656 | EXPORT_SYMBOL(follow_down); |
2557 | EXPORT_SYMBOL(follow_up); | 2657 | EXPORT_SYMBOL(follow_up); |
2558 | EXPORT_SYMBOL(get_write_access); /* binfmt_aout */ | 2658 | EXPORT_SYMBOL(get_write_access); /* binfmt_aout */ |
diff --git a/fs/nfsctl.c b/fs/nfsctl.c index 0b14938b5b62..0d4cf9486068 100644 --- a/fs/nfsctl.c +++ b/fs/nfsctl.c | |||
@@ -5,6 +5,7 @@ | |||
5 | * | 5 | * |
6 | */ | 6 | */ |
7 | #include <linux/config.h> | 7 | #include <linux/config.h> |
8 | #include <linux/types.h> | ||
8 | #include <linux/file.h> | 9 | #include <linux/file.h> |
9 | #include <linux/fs.h> | 10 | #include <linux/fs.h> |
10 | #include <linux/sunrpc/svc.h> | 11 | #include <linux/sunrpc/svc.h> |
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 361b4007d4a0..a00fe8686293 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
@@ -192,6 +192,14 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open | |||
192 | } | 192 | } |
193 | if (status) | 193 | if (status) |
194 | goto out; | 194 | goto out; |
195 | |||
196 | /* Openowner is now set, so sequence id will get bumped. Now we need | ||
197 | * these checks before we do any creates: */ | ||
198 | if (nfs4_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS) | ||
199 | return nfserr_grace; | ||
200 | if (!nfs4_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) | ||
201 | return nfserr_no_grace; | ||
202 | |||
195 | switch (open->op_claim_type) { | 203 | switch (open->op_claim_type) { |
196 | case NFS4_OPEN_CLAIM_DELEGATE_CUR: | 204 | case NFS4_OPEN_CLAIM_DELEGATE_CUR: |
197 | status = nfserr_inval; | 205 | status = nfserr_inval; |
@@ -210,6 +218,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open | |||
210 | goto out; | 218 | goto out; |
211 | break; | 219 | break; |
212 | case NFS4_OPEN_CLAIM_PREVIOUS: | 220 | case NFS4_OPEN_CLAIM_PREVIOUS: |
221 | open->op_stateowner->so_confirmed = 1; | ||
213 | /* | 222 | /* |
214 | * The CURRENT_FH is already set to the file being | 223 | * The CURRENT_FH is already set to the file being |
215 | * opened. (1) set open->op_cinfo, (2) set | 224 | * opened. (1) set open->op_cinfo, (2) set |
@@ -221,6 +230,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open | |||
221 | goto out; | 230 | goto out; |
222 | break; | 231 | break; |
223 | case NFS4_OPEN_CLAIM_DELEGATE_PREV: | 232 | case NFS4_OPEN_CLAIM_DELEGATE_PREV: |
233 | open->op_stateowner->so_confirmed = 1; | ||
224 | printk("NFSD: unsupported OPEN claim type %d\n", | 234 | printk("NFSD: unsupported OPEN claim type %d\n", |
225 | open->op_claim_type); | 235 | open->op_claim_type); |
226 | status = nfserr_notsupp; | 236 | status = nfserr_notsupp; |
@@ -584,31 +594,23 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_se | |||
584 | { | 594 | { |
585 | int status = nfs_ok; | 595 | int status = nfs_ok; |
586 | 596 | ||
587 | if (!current_fh->fh_dentry) | ||
588 | return nfserr_nofilehandle; | ||
589 | |||
590 | status = nfs_ok; | ||
591 | if (setattr->sa_iattr.ia_valid & ATTR_SIZE) { | 597 | if (setattr->sa_iattr.ia_valid & ATTR_SIZE) { |
592 | nfs4_lock_state(); | 598 | nfs4_lock_state(); |
593 | if ((status = nfs4_preprocess_stateid_op(current_fh, | 599 | status = nfs4_preprocess_stateid_op(current_fh, |
594 | &setattr->sa_stateid, | 600 | &setattr->sa_stateid, CHECK_FH | WR_STATE, NULL); |
595 | CHECK_FH | WR_STATE, NULL))) { | ||
596 | dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n"); | ||
597 | goto out_unlock; | ||
598 | } | ||
599 | nfs4_unlock_state(); | 601 | nfs4_unlock_state(); |
602 | if (status) { | ||
603 | dprintk("NFSD: nfsd4_setattr: couldn't process stateid!"); | ||
604 | return status; | ||
605 | } | ||
600 | } | 606 | } |
601 | status = nfs_ok; | 607 | status = nfs_ok; |
602 | if (setattr->sa_acl != NULL) | 608 | if (setattr->sa_acl != NULL) |
603 | status = nfsd4_set_nfs4_acl(rqstp, current_fh, setattr->sa_acl); | 609 | status = nfsd4_set_nfs4_acl(rqstp, current_fh, setattr->sa_acl); |
604 | if (status) | 610 | if (status) |
605 | goto out; | 611 | return status; |
606 | status = nfsd_setattr(rqstp, current_fh, &setattr->sa_iattr, | 612 | status = nfsd_setattr(rqstp, current_fh, &setattr->sa_iattr, |
607 | 0, (time_t)0); | 613 | 0, (time_t)0); |
608 | out: | ||
609 | return status; | ||
610 | out_unlock: | ||
611 | nfs4_unlock_state(); | ||
612 | return status; | 614 | return status; |
613 | } | 615 | } |
614 | 616 | ||
@@ -626,15 +628,17 @@ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_writ | |||
626 | return nfserr_inval; | 628 | return nfserr_inval; |
627 | 629 | ||
628 | nfs4_lock_state(); | 630 | nfs4_lock_state(); |
629 | if ((status = nfs4_preprocess_stateid_op(current_fh, stateid, | 631 | status = nfs4_preprocess_stateid_op(current_fh, stateid, |
630 | CHECK_FH | WR_STATE, &filp))) { | 632 | CHECK_FH | WR_STATE, &filp); |
631 | dprintk("NFSD: nfsd4_write: couldn't process stateid!\n"); | ||
632 | goto out; | ||
633 | } | ||
634 | if (filp) | 633 | if (filp) |
635 | get_file(filp); | 634 | get_file(filp); |
636 | nfs4_unlock_state(); | 635 | nfs4_unlock_state(); |
637 | 636 | ||
637 | if (status) { | ||
638 | dprintk("NFSD: nfsd4_write: couldn't process stateid!\n"); | ||
639 | return status; | ||
640 | } | ||
641 | |||
638 | write->wr_bytes_written = write->wr_buflen; | 642 | write->wr_bytes_written = write->wr_buflen; |
639 | write->wr_how_written = write->wr_stable_how; | 643 | write->wr_how_written = write->wr_stable_how; |
640 | p = (u32 *)write->wr_verifier.data; | 644 | p = (u32 *)write->wr_verifier.data; |
@@ -650,9 +654,6 @@ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_writ | |||
650 | if (status == nfserr_symlink) | 654 | if (status == nfserr_symlink) |
651 | status = nfserr_inval; | 655 | status = nfserr_inval; |
652 | return status; | 656 | return status; |
653 | out: | ||
654 | nfs4_unlock_state(); | ||
655 | return status; | ||
656 | } | 657 | } |
657 | 658 | ||
658 | /* This routine never returns NFS_OK! If there are no other errors, it | 659 | /* This routine never returns NFS_OK! If there are no other errors, it |
@@ -768,6 +769,8 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
768 | while (!status && resp->opcnt < args->opcnt) { | 769 | while (!status && resp->opcnt < args->opcnt) { |
769 | op = &args->ops[resp->opcnt++]; | 770 | op = &args->ops[resp->opcnt++]; |
770 | 771 | ||
772 | dprintk("nfsv4 compound op #%d: %d\n", resp->opcnt, op->opnum); | ||
773 | |||
771 | /* | 774 | /* |
772 | * The XDR decode routines may have pre-set op->status; | 775 | * The XDR decode routines may have pre-set op->status; |
773 | * for example, if there is a miscellaneous XDR error | 776 | * for example, if there is a miscellaneous XDR error |
@@ -792,17 +795,13 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
792 | /* All operations except RENEW, SETCLIENTID, RESTOREFH | 795 | /* All operations except RENEW, SETCLIENTID, RESTOREFH |
793 | * SETCLIENTID_CONFIRM, PUTFH and PUTROOTFH | 796 | * SETCLIENTID_CONFIRM, PUTFH and PUTROOTFH |
794 | * require a valid current filehandle | 797 | * require a valid current filehandle |
795 | * | ||
796 | * SETATTR NOFILEHANDLE error handled in nfsd4_setattr | ||
797 | * due to required returned bitmap argument | ||
798 | */ | 798 | */ |
799 | if ((!current_fh->fh_dentry) && | 799 | if ((!current_fh->fh_dentry) && |
800 | !((op->opnum == OP_PUTFH) || (op->opnum == OP_PUTROOTFH) || | 800 | !((op->opnum == OP_PUTFH) || (op->opnum == OP_PUTROOTFH) || |
801 | (op->opnum == OP_SETCLIENTID) || | 801 | (op->opnum == OP_SETCLIENTID) || |
802 | (op->opnum == OP_SETCLIENTID_CONFIRM) || | 802 | (op->opnum == OP_SETCLIENTID_CONFIRM) || |
803 | (op->opnum == OP_RENEW) || (op->opnum == OP_RESTOREFH) || | 803 | (op->opnum == OP_RENEW) || (op->opnum == OP_RESTOREFH) || |
804 | (op->opnum == OP_RELEASE_LOCKOWNER) || | 804 | (op->opnum == OP_RELEASE_LOCKOWNER))) { |
805 | (op->opnum == OP_SETATTR))) { | ||
806 | op->status = nfserr_nofilehandle; | 805 | op->status = nfserr_nofilehandle; |
807 | goto encode_op; | 806 | goto encode_op; |
808 | } | 807 | } |
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index be963a133aaa..06da7506363c 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c | |||
@@ -222,8 +222,7 @@ nfsd4_list_rec_dir(struct dentry *dir, recdir_func *f) | |||
222 | 222 | ||
223 | nfs4_save_user(&uid, &gid); | 223 | nfs4_save_user(&uid, &gid); |
224 | 224 | ||
225 | filp = dentry_open(dget(dir), mntget(rec_dir.mnt), | 225 | filp = dentry_open(dget(dir), mntget(rec_dir.mnt), O_RDONLY); |
226 | O_RDWR); | ||
227 | status = PTR_ERR(filp); | 226 | status = PTR_ERR(filp); |
228 | if (IS_ERR(filp)) | 227 | if (IS_ERR(filp)) |
229 | goto out; | 228 | goto out; |
@@ -400,9 +399,10 @@ nfsd4_init_recdir(char *rec_dirname) | |||
400 | 399 | ||
401 | nfs4_save_user(&uid, &gid); | 400 | nfs4_save_user(&uid, &gid); |
402 | 401 | ||
403 | status = path_lookup(rec_dirname, LOOKUP_FOLLOW, &rec_dir); | 402 | status = path_lookup(rec_dirname, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, |
404 | if (status == -ENOENT) | 403 | &rec_dir); |
405 | printk("NFSD: recovery directory %s doesn't exist\n", | 404 | if (status) |
405 | printk("NFSD: unable to find recovery directory %s\n", | ||
406 | rec_dirname); | 406 | rec_dirname); |
407 | 407 | ||
408 | if (!status) | 408 | if (!status) |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 6bbefd06f10d..1143cfb64549 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -1088,7 +1088,7 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, str | |||
1088 | sop->so_seqid = open->op_seqid; | 1088 | sop->so_seqid = open->op_seqid; |
1089 | sop->so_confirmed = 0; | 1089 | sop->so_confirmed = 0; |
1090 | rp = &sop->so_replay; | 1090 | rp = &sop->so_replay; |
1091 | rp->rp_status = NFSERR_SERVERFAULT; | 1091 | rp->rp_status = nfserr_serverfault; |
1092 | rp->rp_buflen = 0; | 1092 | rp->rp_buflen = 0; |
1093 | rp->rp_buf = rp->rp_ibuf; | 1093 | rp->rp_buf = rp->rp_ibuf; |
1094 | return sop; | 1094 | return sop; |
@@ -1178,7 +1178,6 @@ release_stateid(struct nfs4_stateid *stp, int flags) | |||
1178 | locks_remove_posix(filp, (fl_owner_t) stp->st_stateowner); | 1178 | locks_remove_posix(filp, (fl_owner_t) stp->st_stateowner); |
1179 | put_nfs4_file(stp->st_file); | 1179 | put_nfs4_file(stp->st_file); |
1180 | kmem_cache_free(stateid_slab, stp); | 1180 | kmem_cache_free(stateid_slab, stp); |
1181 | stp = NULL; | ||
1182 | } | 1181 | } |
1183 | 1182 | ||
1184 | static void | 1183 | static void |
@@ -1191,22 +1190,6 @@ move_to_close_lru(struct nfs4_stateowner *sop) | |||
1191 | sop->so_time = get_seconds(); | 1190 | sop->so_time = get_seconds(); |
1192 | } | 1191 | } |
1193 | 1192 | ||
1194 | static void | ||
1195 | release_state_owner(struct nfs4_stateid *stp, int flag) | ||
1196 | { | ||
1197 | struct nfs4_stateowner *sop = stp->st_stateowner; | ||
1198 | |||
1199 | dprintk("NFSD: release_state_owner\n"); | ||
1200 | release_stateid(stp, flag); | ||
1201 | |||
1202 | /* place unused nfs4_stateowners on so_close_lru list to be | ||
1203 | * released by the laundromat service after the lease period | ||
1204 | * to enable us to handle CLOSE replay | ||
1205 | */ | ||
1206 | if (sop->so_confirmed && list_empty(&sop->so_stateids)) | ||
1207 | move_to_close_lru(sop); | ||
1208 | } | ||
1209 | |||
1210 | static int | 1193 | static int |
1211 | cmp_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner, clientid_t *clid) { | 1194 | cmp_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner, clientid_t *clid) { |
1212 | return ((sop->so_owner.len == owner->len) && | 1195 | return ((sop->so_owner.len == owner->len) && |
@@ -1446,92 +1429,61 @@ static struct lock_manager_operations nfsd_lease_mng_ops = { | |||
1446 | }; | 1429 | }; |
1447 | 1430 | ||
1448 | 1431 | ||
1449 | /* | ||
1450 | * nfsd4_process_open1() | ||
1451 | * lookup stateowner. | ||
1452 | * found: | ||
1453 | * check confirmed | ||
1454 | * confirmed: | ||
1455 | * check seqid | ||
1456 | * not confirmed: | ||
1457 | * delete owner | ||
1458 | * create new owner | ||
1459 | * notfound: | ||
1460 | * verify clientid | ||
1461 | * create new owner | ||
1462 | * | ||
1463 | * called with nfs4_lock_state() held. | ||
1464 | */ | ||
1465 | int | 1432 | int |
1466 | nfsd4_process_open1(struct nfsd4_open *open) | 1433 | nfsd4_process_open1(struct nfsd4_open *open) |
1467 | { | 1434 | { |
1468 | int status; | ||
1469 | clientid_t *clientid = &open->op_clientid; | 1435 | clientid_t *clientid = &open->op_clientid; |
1470 | struct nfs4_client *clp = NULL; | 1436 | struct nfs4_client *clp = NULL; |
1471 | unsigned int strhashval; | 1437 | unsigned int strhashval; |
1472 | struct nfs4_stateowner *sop = NULL; | 1438 | struct nfs4_stateowner *sop = NULL; |
1473 | 1439 | ||
1474 | status = nfserr_inval; | ||
1475 | if (!check_name(open->op_owner)) | 1440 | if (!check_name(open->op_owner)) |
1476 | goto out; | 1441 | return nfserr_inval; |
1477 | 1442 | ||
1478 | if (STALE_CLIENTID(&open->op_clientid)) | 1443 | if (STALE_CLIENTID(&open->op_clientid)) |
1479 | return nfserr_stale_clientid; | 1444 | return nfserr_stale_clientid; |
1480 | 1445 | ||
1481 | strhashval = ownerstr_hashval(clientid->cl_id, open->op_owner); | 1446 | strhashval = ownerstr_hashval(clientid->cl_id, open->op_owner); |
1482 | sop = find_openstateowner_str(strhashval, open); | 1447 | sop = find_openstateowner_str(strhashval, open); |
1483 | if (sop) { | 1448 | open->op_stateowner = sop; |
1484 | open->op_stateowner = sop; | 1449 | if (!sop) { |
1485 | /* check for replay */ | 1450 | /* Make sure the client's lease hasn't expired. */ |
1486 | if (open->op_seqid == sop->so_seqid - 1){ | ||
1487 | if (sop->so_replay.rp_buflen) | ||
1488 | return NFSERR_REPLAY_ME; | ||
1489 | else { | ||
1490 | /* The original OPEN failed so spectacularly | ||
1491 | * that we don't even have replay data saved! | ||
1492 | * Therefore, we have no choice but to continue | ||
1493 | * processing this OPEN; presumably, we'll | ||
1494 | * fail again for the same reason. | ||
1495 | */ | ||
1496 | dprintk("nfsd4_process_open1:" | ||
1497 | " replay with no replay cache\n"); | ||
1498 | goto renew; | ||
1499 | } | ||
1500 | } else if (sop->so_confirmed) { | ||
1501 | if (open->op_seqid == sop->so_seqid) | ||
1502 | goto renew; | ||
1503 | status = nfserr_bad_seqid; | ||
1504 | goto out; | ||
1505 | } else { | ||
1506 | /* If we get here, we received an OPEN for an | ||
1507 | * unconfirmed nfs4_stateowner. Since the seqid's are | ||
1508 | * different, purge the existing nfs4_stateowner, and | ||
1509 | * instantiate a new one. | ||
1510 | */ | ||
1511 | clp = sop->so_client; | ||
1512 | release_stateowner(sop); | ||
1513 | } | ||
1514 | } else { | ||
1515 | /* nfs4_stateowner not found. | ||
1516 | * Verify clientid and instantiate new nfs4_stateowner. | ||
1517 | * If verify fails this is presumably the result of the | ||
1518 | * client's lease expiring. | ||
1519 | */ | ||
1520 | status = nfserr_expired; | ||
1521 | clp = find_confirmed_client(clientid); | 1451 | clp = find_confirmed_client(clientid); |
1522 | if (clp == NULL) | 1452 | if (clp == NULL) |
1523 | goto out; | 1453 | return nfserr_expired; |
1454 | goto renew; | ||
1524 | } | 1455 | } |
1525 | status = nfserr_resource; | 1456 | if (!sop->so_confirmed) { |
1526 | sop = alloc_init_open_stateowner(strhashval, clp, open); | 1457 | /* Replace unconfirmed owners without checking for replay. */ |
1527 | if (sop == NULL) | 1458 | clp = sop->so_client; |
1528 | goto out; | 1459 | release_stateowner(sop); |
1529 | open->op_stateowner = sop; | 1460 | open->op_stateowner = NULL; |
1461 | goto renew; | ||
1462 | } | ||
1463 | if (open->op_seqid == sop->so_seqid - 1) { | ||
1464 | if (sop->so_replay.rp_buflen) | ||
1465 | return NFSERR_REPLAY_ME; | ||
1466 | /* The original OPEN failed so spectacularly | ||
1467 | * that we don't even have replay data saved! | ||
1468 | * Therefore, we have no choice but to continue | ||
1469 | * processing this OPEN; presumably, we'll | ||
1470 | * fail again for the same reason. | ||
1471 | */ | ||
1472 | dprintk("nfsd4_process_open1: replay with no replay cache\n"); | ||
1473 | goto renew; | ||
1474 | } | ||
1475 | if (open->op_seqid != sop->so_seqid) | ||
1476 | return nfserr_bad_seqid; | ||
1530 | renew: | 1477 | renew: |
1531 | status = nfs_ok; | 1478 | if (open->op_stateowner == NULL) { |
1479 | sop = alloc_init_open_stateowner(strhashval, clp, open); | ||
1480 | if (sop == NULL) | ||
1481 | return nfserr_resource; | ||
1482 | open->op_stateowner = sop; | ||
1483 | } | ||
1484 | list_del_init(&sop->so_close_lru); | ||
1532 | renew_client(sop->so_client); | 1485 | renew_client(sop->so_client); |
1533 | out: | 1486 | return nfs_ok; |
1534 | return status; | ||
1535 | } | 1487 | } |
1536 | 1488 | ||
1537 | static inline int | 1489 | static inline int |
@@ -1648,7 +1600,7 @@ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, | |||
1648 | if (!open->op_truncate) | 1600 | if (!open->op_truncate) |
1649 | return 0; | 1601 | return 0; |
1650 | if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) | 1602 | if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) |
1651 | return -EINVAL; | 1603 | return nfserr_inval; |
1652 | return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0); | 1604 | return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0); |
1653 | } | 1605 | } |
1654 | 1606 | ||
@@ -1657,26 +1609,26 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct svc_fh *cur_fh, struct nfs4_sta | |||
1657 | { | 1609 | { |
1658 | struct file *filp = stp->st_vfs_file; | 1610 | struct file *filp = stp->st_vfs_file; |
1659 | struct inode *inode = filp->f_dentry->d_inode; | 1611 | struct inode *inode = filp->f_dentry->d_inode; |
1660 | unsigned int share_access; | 1612 | unsigned int share_access, new_writer; |
1661 | int status; | 1613 | int status; |
1662 | 1614 | ||
1663 | set_access(&share_access, stp->st_access_bmap); | 1615 | set_access(&share_access, stp->st_access_bmap); |
1664 | share_access = ~share_access; | 1616 | new_writer = (~share_access) & open->op_share_access |
1665 | share_access &= open->op_share_access; | 1617 | & NFS4_SHARE_ACCESS_WRITE; |
1666 | |||
1667 | if (!(share_access & NFS4_SHARE_ACCESS_WRITE)) | ||
1668 | return nfsd4_truncate(rqstp, cur_fh, open); | ||
1669 | 1618 | ||
1670 | status = get_write_access(inode); | 1619 | if (new_writer) { |
1671 | if (status) | 1620 | status = get_write_access(inode); |
1672 | return nfserrno(status); | 1621 | if (status) |
1622 | return nfserrno(status); | ||
1623 | } | ||
1673 | status = nfsd4_truncate(rqstp, cur_fh, open); | 1624 | status = nfsd4_truncate(rqstp, cur_fh, open); |
1674 | if (status) { | 1625 | if (status) { |
1675 | put_write_access(inode); | 1626 | if (new_writer) |
1627 | put_write_access(inode); | ||
1676 | return status; | 1628 | return status; |
1677 | } | 1629 | } |
1678 | /* remember the open */ | 1630 | /* remember the open */ |
1679 | filp->f_mode = (filp->f_mode | FMODE_WRITE) & ~FMODE_READ; | 1631 | filp->f_mode |= open->op_share_access; |
1680 | set_bit(open->op_share_access, &stp->st_access_bmap); | 1632 | set_bit(open->op_share_access, &stp->st_access_bmap); |
1681 | set_bit(open->op_share_deny, &stp->st_deny_bmap); | 1633 | set_bit(open->op_share_deny, &stp->st_deny_bmap); |
1682 | 1634 | ||
@@ -1780,12 +1732,6 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf | |||
1780 | struct nfs4_delegation *dp = NULL; | 1732 | struct nfs4_delegation *dp = NULL; |
1781 | int status; | 1733 | int status; |
1782 | 1734 | ||
1783 | if (nfs4_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS) | ||
1784 | return nfserr_grace; | ||
1785 | |||
1786 | if (!nfs4_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) | ||
1787 | return nfserr_no_grace; | ||
1788 | |||
1789 | status = nfserr_inval; | 1735 | status = nfserr_inval; |
1790 | if (!TEST_ACCESS(open->op_share_access) || !TEST_DENY(open->op_share_deny)) | 1736 | if (!TEST_ACCESS(open->op_share_access) || !TEST_DENY(open->op_share_deny)) |
1791 | goto out; | 1737 | goto out; |
@@ -2423,15 +2369,19 @@ nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_clos | |||
2423 | CHECK_FH | OPEN_STATE | CLOSE_STATE, | 2369 | CHECK_FH | OPEN_STATE | CLOSE_STATE, |
2424 | &close->cl_stateowner, &stp, NULL))) | 2370 | &close->cl_stateowner, &stp, NULL))) |
2425 | goto out; | 2371 | goto out; |
2426 | /* | ||
2427 | * Return success, but first update the stateid. | ||
2428 | */ | ||
2429 | status = nfs_ok; | 2372 | status = nfs_ok; |
2430 | update_stateid(&stp->st_stateid); | 2373 | update_stateid(&stp->st_stateid); |
2431 | memcpy(&close->cl_stateid, &stp->st_stateid, sizeof(stateid_t)); | 2374 | memcpy(&close->cl_stateid, &stp->st_stateid, sizeof(stateid_t)); |
2432 | 2375 | ||
2433 | /* release_state_owner() calls nfsd_close() if needed */ | 2376 | /* release_stateid() calls nfsd_close() if needed */ |
2434 | release_state_owner(stp, OPEN_STATE); | 2377 | release_stateid(stp, OPEN_STATE); |
2378 | |||
2379 | /* place unused nfs4_stateowners on so_close_lru list to be | ||
2380 | * released by the laundromat service after the lease period | ||
2381 | * to enable us to handle CLOSE replay | ||
2382 | */ | ||
2383 | if (list_empty(&close->cl_stateowner->so_stateids)) | ||
2384 | move_to_close_lru(close->cl_stateowner); | ||
2435 | out: | 2385 | out: |
2436 | if (close->cl_stateowner) { | 2386 | if (close->cl_stateowner) { |
2437 | nfs4_get_stateowner(close->cl_stateowner); | 2387 | nfs4_get_stateowner(close->cl_stateowner); |
@@ -2633,7 +2583,7 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, str | |||
2633 | sop->so_seqid = lock->lk_new_lock_seqid + 1; | 2583 | sop->so_seqid = lock->lk_new_lock_seqid + 1; |
2634 | sop->so_confirmed = 1; | 2584 | sop->so_confirmed = 1; |
2635 | rp = &sop->so_replay; | 2585 | rp = &sop->so_replay; |
2636 | rp->rp_status = NFSERR_SERVERFAULT; | 2586 | rp->rp_status = nfserr_serverfault; |
2637 | rp->rp_buflen = 0; | 2587 | rp->rp_buflen = 0; |
2638 | rp->rp_buf = rp->rp_ibuf; | 2588 | rp->rp_buf = rp->rp_ibuf; |
2639 | return sop; | 2589 | return sop; |
@@ -2700,6 +2650,11 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock | |||
2700 | if (check_lock_length(lock->lk_offset, lock->lk_length)) | 2650 | if (check_lock_length(lock->lk_offset, lock->lk_length)) |
2701 | return nfserr_inval; | 2651 | return nfserr_inval; |
2702 | 2652 | ||
2653 | if ((status = fh_verify(rqstp, current_fh, S_IFREG, MAY_LOCK))) { | ||
2654 | dprintk("NFSD: nfsd4_lock: permission denied!\n"); | ||
2655 | return status; | ||
2656 | } | ||
2657 | |||
2703 | nfs4_lock_state(); | 2658 | nfs4_lock_state(); |
2704 | 2659 | ||
2705 | if (lock->lk_is_new) { | 2660 | if (lock->lk_is_new) { |
@@ -2720,11 +2675,11 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock | |||
2720 | lock->lk_new_open_seqid, | 2675 | lock->lk_new_open_seqid, |
2721 | &lock->lk_new_open_stateid, | 2676 | &lock->lk_new_open_stateid, |
2722 | CHECK_FH | OPEN_STATE, | 2677 | CHECK_FH | OPEN_STATE, |
2723 | &lock->lk_stateowner, &open_stp, | 2678 | &lock->lk_replay_owner, &open_stp, |
2724 | lock); | 2679 | lock); |
2725 | if (status) | 2680 | if (status) |
2726 | goto out; | 2681 | goto out; |
2727 | open_sop = lock->lk_stateowner; | 2682 | open_sop = lock->lk_replay_owner; |
2728 | /* create lockowner and lock stateid */ | 2683 | /* create lockowner and lock stateid */ |
2729 | fp = open_stp->st_file; | 2684 | fp = open_stp->st_file; |
2730 | strhashval = lock_ownerstr_hashval(fp->fi_inode, | 2685 | strhashval = lock_ownerstr_hashval(fp->fi_inode, |
@@ -2739,29 +2694,22 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock | |||
2739 | if (lock_sop == NULL) | 2694 | if (lock_sop == NULL) |
2740 | goto out; | 2695 | goto out; |
2741 | lock_stp = alloc_init_lock_stateid(lock_sop, fp, open_stp); | 2696 | lock_stp = alloc_init_lock_stateid(lock_sop, fp, open_stp); |
2742 | if (lock_stp == NULL) { | 2697 | if (lock_stp == NULL) |
2743 | release_stateowner(lock_sop); | ||
2744 | goto out; | 2698 | goto out; |
2745 | } | ||
2746 | } else { | 2699 | } else { |
2747 | /* lock (lock owner + lock stateid) already exists */ | 2700 | /* lock (lock owner + lock stateid) already exists */ |
2748 | status = nfs4_preprocess_seqid_op(current_fh, | 2701 | status = nfs4_preprocess_seqid_op(current_fh, |
2749 | lock->lk_old_lock_seqid, | 2702 | lock->lk_old_lock_seqid, |
2750 | &lock->lk_old_lock_stateid, | 2703 | &lock->lk_old_lock_stateid, |
2751 | CHECK_FH | LOCK_STATE, | 2704 | CHECK_FH | LOCK_STATE, |
2752 | &lock->lk_stateowner, &lock_stp, lock); | 2705 | &lock->lk_replay_owner, &lock_stp, lock); |
2753 | if (status) | 2706 | if (status) |
2754 | goto out; | 2707 | goto out; |
2755 | lock_sop = lock->lk_stateowner; | 2708 | lock_sop = lock->lk_replay_owner; |
2756 | } | 2709 | } |
2757 | /* lock->lk_stateowner and lock_stp have been created or found */ | 2710 | /* lock->lk_replay_owner and lock_stp have been created or found */ |
2758 | filp = lock_stp->st_vfs_file; | 2711 | filp = lock_stp->st_vfs_file; |
2759 | 2712 | ||
2760 | if ((status = fh_verify(rqstp, current_fh, S_IFREG, MAY_LOCK))) { | ||
2761 | dprintk("NFSD: nfsd4_lock: permission denied!\n"); | ||
2762 | goto out; | ||
2763 | } | ||
2764 | |||
2765 | status = nfserr_grace; | 2713 | status = nfserr_grace; |
2766 | if (nfs4_in_grace() && !lock->lk_reclaim) | 2714 | if (nfs4_in_grace() && !lock->lk_reclaim) |
2767 | goto out; | 2715 | goto out; |
@@ -2802,8 +2750,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock | |||
2802 | */ | 2750 | */ |
2803 | 2751 | ||
2804 | status = posix_lock_file(filp, &file_lock); | 2752 | status = posix_lock_file(filp, &file_lock); |
2805 | if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private) | ||
2806 | file_lock.fl_ops->fl_release_private(&file_lock); | ||
2807 | dprintk("NFSD: nfsd4_lock: posix_lock_file status %d\n",status); | 2753 | dprintk("NFSD: nfsd4_lock: posix_lock_file status %d\n",status); |
2808 | switch (-status) { | 2754 | switch (-status) { |
2809 | case 0: /* success! */ | 2755 | case 0: /* success! */ |
@@ -2815,9 +2761,12 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock | |||
2815 | goto conflicting_lock; | 2761 | goto conflicting_lock; |
2816 | case (EDEADLK): | 2762 | case (EDEADLK): |
2817 | status = nfserr_deadlock; | 2763 | status = nfserr_deadlock; |
2764 | dprintk("NFSD: nfsd4_lock: posix_lock_file() failed! status %d\n",status); | ||
2765 | goto out; | ||
2818 | default: | 2766 | default: |
2767 | status = nfserrno(status); | ||
2819 | dprintk("NFSD: nfsd4_lock: posix_lock_file() failed! status %d\n",status); | 2768 | dprintk("NFSD: nfsd4_lock: posix_lock_file() failed! status %d\n",status); |
2820 | goto out_destroy_new_stateid; | 2769 | goto out; |
2821 | } | 2770 | } |
2822 | 2771 | ||
2823 | conflicting_lock: | 2772 | conflicting_lock: |
@@ -2831,20 +2780,12 @@ conflicting_lock: | |||
2831 | goto out; | 2780 | goto out; |
2832 | } | 2781 | } |
2833 | nfs4_set_lock_denied(conflock, &lock->lk_denied); | 2782 | nfs4_set_lock_denied(conflock, &lock->lk_denied); |
2834 | |||
2835 | out_destroy_new_stateid: | ||
2836 | if (lock->lk_is_new) { | ||
2837 | dprintk("NFSD: nfsd4_lock: destroy new stateid!\n"); | ||
2838 | /* | ||
2839 | * An error encountered after instantiation of the new | ||
2840 | * stateid has forced us to destroy it. | ||
2841 | */ | ||
2842 | release_state_owner(lock_stp, LOCK_STATE); | ||
2843 | } | ||
2844 | out: | 2783 | out: |
2845 | if (lock->lk_stateowner) { | 2784 | if (status && lock->lk_is_new && lock_sop) |
2846 | nfs4_get_stateowner(lock->lk_stateowner); | 2785 | release_stateowner(lock_sop); |
2847 | *replay_owner = lock->lk_stateowner; | 2786 | if (lock->lk_replay_owner) { |
2787 | nfs4_get_stateowner(lock->lk_replay_owner); | ||
2788 | *replay_owner = lock->lk_replay_owner; | ||
2848 | } | 2789 | } |
2849 | nfs4_unlock_state(); | 2790 | nfs4_unlock_state(); |
2850 | return status; | 2791 | return status; |
@@ -2977,8 +2918,6 @@ nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock | |||
2977 | * Try to unlock the file in the VFS. | 2918 | * Try to unlock the file in the VFS. |
2978 | */ | 2919 | */ |
2979 | status = posix_lock_file(filp, &file_lock); | 2920 | status = posix_lock_file(filp, &file_lock); |
2980 | if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private) | ||
2981 | file_lock.fl_ops->fl_release_private(&file_lock); | ||
2982 | if (status) { | 2921 | if (status) { |
2983 | dprintk("NFSD: nfs4_locku: posix_lock_file failed!\n"); | 2922 | dprintk("NFSD: nfs4_locku: posix_lock_file failed!\n"); |
2984 | goto out_nfserr; | 2923 | goto out_nfserr; |
@@ -3016,9 +2955,10 @@ check_for_locks(struct file *filp, struct nfs4_stateowner *lowner) | |||
3016 | 2955 | ||
3017 | lock_kernel(); | 2956 | lock_kernel(); |
3018 | for (flpp = &inode->i_flock; *flpp != NULL; flpp = &(*flpp)->fl_next) { | 2957 | for (flpp = &inode->i_flock; *flpp != NULL; flpp = &(*flpp)->fl_next) { |
3019 | if ((*flpp)->fl_owner == (fl_owner_t)lowner) | 2958 | if ((*flpp)->fl_owner == (fl_owner_t)lowner) { |
3020 | status = 1; | 2959 | status = 1; |
3021 | goto out; | 2960 | goto out; |
2961 | } | ||
3022 | } | 2962 | } |
3023 | out: | 2963 | out: |
3024 | unlock_kernel(); | 2964 | unlock_kernel(); |
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index dcd673186944..69d3501173a8 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -528,7 +528,7 @@ nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock) | |||
528 | { | 528 | { |
529 | DECODE_HEAD; | 529 | DECODE_HEAD; |
530 | 530 | ||
531 | lock->lk_stateowner = NULL; | 531 | lock->lk_replay_owner = NULL; |
532 | /* | 532 | /* |
533 | * type, reclaim(boolean), offset, length, new_lock_owner(boolean) | 533 | * type, reclaim(boolean), offset, length, new_lock_owner(boolean) |
534 | */ | 534 | */ |
@@ -1764,10 +1764,11 @@ nfsd4_encode_dirent(struct readdir_cd *ccd, const char *name, int namlen, | |||
1764 | */ | 1764 | */ |
1765 | if (!(cd->rd_bmval[0] & FATTR4_WORD0_RDATTR_ERROR)) | 1765 | if (!(cd->rd_bmval[0] & FATTR4_WORD0_RDATTR_ERROR)) |
1766 | goto fail; | 1766 | goto fail; |
1767 | nfserr = nfserr_toosmall; | ||
1768 | p = nfsd4_encode_rdattr_error(p, buflen, nfserr); | 1767 | p = nfsd4_encode_rdattr_error(p, buflen, nfserr); |
1769 | if (p == NULL) | 1768 | if (p == NULL) { |
1769 | nfserr = nfserr_toosmall; | ||
1770 | goto fail; | 1770 | goto fail; |
1771 | } | ||
1771 | } | 1772 | } |
1772 | cd->buflen -= (p - cd->buffer); | 1773 | cd->buflen -= (p - cd->buffer); |
1773 | cd->buffer = p; | 1774 | cd->buffer = p; |
@@ -1895,7 +1896,6 @@ nfsd4_encode_lock_denied(struct nfsd4_compoundres *resp, struct nfsd4_lock_denie | |||
1895 | static void | 1896 | static void |
1896 | nfsd4_encode_lock(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_lock *lock) | 1897 | nfsd4_encode_lock(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_lock *lock) |
1897 | { | 1898 | { |
1898 | |||
1899 | ENCODE_SEQID_OP_HEAD; | 1899 | ENCODE_SEQID_OP_HEAD; |
1900 | 1900 | ||
1901 | if (!nfserr) { | 1901 | if (!nfserr) { |
@@ -1906,7 +1906,7 @@ nfsd4_encode_lock(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_lock | |||
1906 | } else if (nfserr == nfserr_denied) | 1906 | } else if (nfserr == nfserr_denied) |
1907 | nfsd4_encode_lock_denied(resp, &lock->lk_denied); | 1907 | nfsd4_encode_lock_denied(resp, &lock->lk_denied); |
1908 | 1908 | ||
1909 | ENCODE_SEQID_OP_TAIL(lock->lk_stateowner); | 1909 | ENCODE_SEQID_OP_TAIL(lock->lk_replay_owner); |
1910 | } | 1910 | } |
1911 | 1911 | ||
1912 | static void | 1912 | static void |
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index 0aa1b9603d7f..3e6b75cd90fd 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c | |||
@@ -36,6 +36,22 @@ nfsd_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) | |||
36 | return nfs_ok; | 36 | return nfs_ok; |
37 | } | 37 | } |
38 | 38 | ||
39 | static int | ||
40 | nfsd_return_attrs(int err, struct nfsd_attrstat *resp) | ||
41 | { | ||
42 | if (err) return err; | ||
43 | return nfserrno(vfs_getattr(resp->fh.fh_export->ex_mnt, | ||
44 | resp->fh.fh_dentry, | ||
45 | &resp->stat)); | ||
46 | } | ||
47 | static int | ||
48 | nfsd_return_dirop(int err, struct nfsd_diropres *resp) | ||
49 | { | ||
50 | if (err) return err; | ||
51 | return nfserrno(vfs_getattr(resp->fh.fh_export->ex_mnt, | ||
52 | resp->fh.fh_dentry, | ||
53 | &resp->stat)); | ||
54 | } | ||
39 | /* | 55 | /* |
40 | * Get a file's attributes | 56 | * Get a file's attributes |
41 | * N.B. After this call resp->fh needs an fh_put | 57 | * N.B. After this call resp->fh needs an fh_put |
@@ -44,10 +60,12 @@ static int | |||
44 | nfsd_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp, | 60 | nfsd_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp, |
45 | struct nfsd_attrstat *resp) | 61 | struct nfsd_attrstat *resp) |
46 | { | 62 | { |
63 | int nfserr; | ||
47 | dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh)); | 64 | dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh)); |
48 | 65 | ||
49 | fh_copy(&resp->fh, &argp->fh); | 66 | fh_copy(&resp->fh, &argp->fh); |
50 | return fh_verify(rqstp, &resp->fh, 0, MAY_NOP); | 67 | nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP); |
68 | return nfsd_return_attrs(nfserr, resp); | ||
51 | } | 69 | } |
52 | 70 | ||
53 | /* | 71 | /* |
@@ -58,12 +76,14 @@ static int | |||
58 | nfsd_proc_setattr(struct svc_rqst *rqstp, struct nfsd_sattrargs *argp, | 76 | nfsd_proc_setattr(struct svc_rqst *rqstp, struct nfsd_sattrargs *argp, |
59 | struct nfsd_attrstat *resp) | 77 | struct nfsd_attrstat *resp) |
60 | { | 78 | { |
79 | int nfserr; | ||
61 | dprintk("nfsd: SETATTR %s, valid=%x, size=%ld\n", | 80 | dprintk("nfsd: SETATTR %s, valid=%x, size=%ld\n", |
62 | SVCFH_fmt(&argp->fh), | 81 | SVCFH_fmt(&argp->fh), |
63 | argp->attrs.ia_valid, (long) argp->attrs.ia_size); | 82 | argp->attrs.ia_valid, (long) argp->attrs.ia_size); |
64 | 83 | ||
65 | fh_copy(&resp->fh, &argp->fh); | 84 | fh_copy(&resp->fh, &argp->fh); |
66 | return nfsd_setattr(rqstp, &resp->fh, &argp->attrs,0, (time_t)0); | 85 | nfserr = nfsd_setattr(rqstp, &resp->fh, &argp->attrs,0, (time_t)0); |
86 | return nfsd_return_attrs(nfserr, resp); | ||
67 | } | 87 | } |
68 | 88 | ||
69 | /* | 89 | /* |
@@ -86,7 +106,7 @@ nfsd_proc_lookup(struct svc_rqst *rqstp, struct nfsd_diropargs *argp, | |||
86 | &resp->fh); | 106 | &resp->fh); |
87 | 107 | ||
88 | fh_put(&argp->fh); | 108 | fh_put(&argp->fh); |
89 | return nfserr; | 109 | return nfsd_return_dirop(nfserr, resp); |
90 | } | 110 | } |
91 | 111 | ||
92 | /* | 112 | /* |
@@ -142,7 +162,10 @@ nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp, | |||
142 | argp->vec, argp->vlen, | 162 | argp->vec, argp->vlen, |
143 | &resp->count); | 163 | &resp->count); |
144 | 164 | ||
145 | return nfserr; | 165 | if (nfserr) return nfserr; |
166 | return nfserrno(vfs_getattr(resp->fh.fh_export->ex_mnt, | ||
167 | resp->fh.fh_dentry, | ||
168 | &resp->stat)); | ||
146 | } | 169 | } |
147 | 170 | ||
148 | /* | 171 | /* |
@@ -165,7 +188,7 @@ nfsd_proc_write(struct svc_rqst *rqstp, struct nfsd_writeargs *argp, | |||
165 | argp->vec, argp->vlen, | 188 | argp->vec, argp->vlen, |
166 | argp->len, | 189 | argp->len, |
167 | &stable); | 190 | &stable); |
168 | return nfserr; | 191 | return nfsd_return_attrs(nfserr, resp); |
169 | } | 192 | } |
170 | 193 | ||
171 | /* | 194 | /* |
@@ -322,7 +345,7 @@ out_unlock: | |||
322 | 345 | ||
323 | done: | 346 | done: |
324 | fh_put(dirfhp); | 347 | fh_put(dirfhp); |
325 | return nfserr; | 348 | return nfsd_return_dirop(nfserr, resp); |
326 | } | 349 | } |
327 | 350 | ||
328 | static int | 351 | static int |
@@ -425,7 +448,7 @@ nfsd_proc_mkdir(struct svc_rqst *rqstp, struct nfsd_createargs *argp, | |||
425 | nfserr = nfsd_create(rqstp, &argp->fh, argp->name, argp->len, | 448 | nfserr = nfsd_create(rqstp, &argp->fh, argp->name, argp->len, |
426 | &argp->attrs, S_IFDIR, 0, &resp->fh); | 449 | &argp->attrs, S_IFDIR, 0, &resp->fh); |
427 | fh_put(&argp->fh); | 450 | fh_put(&argp->fh); |
428 | return nfserr; | 451 | return nfsd_return_dirop(nfserr, resp); |
429 | } | 452 | } |
430 | 453 | ||
431 | /* | 454 | /* |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index eef0576a7785..5320e5afaddb 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -710,14 +710,15 @@ static inline int nfsd_dosync(struct file *filp, struct dentry *dp, | |||
710 | { | 710 | { |
711 | struct inode *inode = dp->d_inode; | 711 | struct inode *inode = dp->d_inode; |
712 | int (*fsync) (struct file *, struct dentry *, int); | 712 | int (*fsync) (struct file *, struct dentry *, int); |
713 | int err = nfs_ok; | 713 | int err; |
714 | 714 | ||
715 | filemap_fdatawrite(inode->i_mapping); | 715 | err = filemap_fdatawrite(inode->i_mapping); |
716 | if (fop && (fsync = fop->fsync)) | 716 | if (err == 0 && fop && (fsync = fop->fsync)) |
717 | err=fsync(filp, dp, 0); | 717 | err = fsync(filp, dp, 0); |
718 | filemap_fdatawait(inode->i_mapping); | 718 | if (err == 0) |
719 | err = filemap_fdatawait(inode->i_mapping); | ||
719 | 720 | ||
720 | return nfserrno(err); | 721 | return err; |
721 | } | 722 | } |
722 | 723 | ||
723 | 724 | ||
@@ -734,10 +735,10 @@ nfsd_sync(struct file *filp) | |||
734 | return err; | 735 | return err; |
735 | } | 736 | } |
736 | 737 | ||
737 | void | 738 | int |
738 | nfsd_sync_dir(struct dentry *dp) | 739 | nfsd_sync_dir(struct dentry *dp) |
739 | { | 740 | { |
740 | nfsd_dosync(NULL, dp, dp->d_inode->i_fop); | 741 | return nfsd_dosync(NULL, dp, dp->d_inode->i_fop); |
741 | } | 742 | } |
742 | 743 | ||
743 | /* | 744 | /* |
@@ -814,7 +815,7 @@ nfsd_read_actor(read_descriptor_t *desc, struct page *page, unsigned long offset | |||
814 | return size; | 815 | return size; |
815 | } | 816 | } |
816 | 817 | ||
817 | static inline int | 818 | static int |
818 | nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | 819 | nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, |
819 | loff_t offset, struct kvec *vec, int vlen, unsigned long *count) | 820 | loff_t offset, struct kvec *vec, int vlen, unsigned long *count) |
820 | { | 821 | { |
@@ -878,7 +879,7 @@ static void kill_suid(struct dentry *dentry) | |||
878 | mutex_unlock(&dentry->d_inode->i_mutex); | 879 | mutex_unlock(&dentry->d_inode->i_mutex); |
879 | } | 880 | } |
880 | 881 | ||
881 | static inline int | 882 | static int |
882 | nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | 883 | nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, |
883 | loff_t offset, struct kvec *vec, int vlen, | 884 | loff_t offset, struct kvec *vec, int vlen, |
884 | unsigned long cnt, int *stablep) | 885 | unsigned long cnt, int *stablep) |
@@ -890,9 +891,9 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
890 | int err = 0; | 891 | int err = 0; |
891 | int stable = *stablep; | 892 | int stable = *stablep; |
892 | 893 | ||
894 | #ifdef MSNFS | ||
893 | err = nfserr_perm; | 895 | err = nfserr_perm; |
894 | 896 | ||
895 | #ifdef MSNFS | ||
896 | if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && | 897 | if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && |
897 | (!lock_may_write(file->f_dentry->d_inode, offset, cnt))) | 898 | (!lock_may_write(file->f_dentry->d_inode, offset, cnt))) |
898 | goto out; | 899 | goto out; |
@@ -1064,7 +1065,7 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1064 | return err; | 1065 | return err; |
1065 | if (EX_ISSYNC(fhp->fh_export)) { | 1066 | if (EX_ISSYNC(fhp->fh_export)) { |
1066 | if (file->f_op && file->f_op->fsync) { | 1067 | if (file->f_op && file->f_op->fsync) { |
1067 | err = nfsd_sync(file); | 1068 | err = nfserrno(nfsd_sync(file)); |
1068 | } else { | 1069 | } else { |
1069 | err = nfserr_notsupp; | 1070 | err = nfserr_notsupp; |
1070 | } | 1071 | } |
@@ -1132,7 +1133,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1132 | "nfsd_create: parent %s/%s not locked!\n", | 1133 | "nfsd_create: parent %s/%s not locked!\n", |
1133 | dentry->d_parent->d_name.name, | 1134 | dentry->d_parent->d_name.name, |
1134 | dentry->d_name.name); | 1135 | dentry->d_name.name); |
1135 | err = -EIO; | 1136 | err = nfserr_io; |
1136 | goto out; | 1137 | goto out; |
1137 | } | 1138 | } |
1138 | } | 1139 | } |
@@ -1175,7 +1176,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1175 | goto out_nfserr; | 1176 | goto out_nfserr; |
1176 | 1177 | ||
1177 | if (EX_ISSYNC(fhp->fh_export)) { | 1178 | if (EX_ISSYNC(fhp->fh_export)) { |
1178 | nfsd_sync_dir(dentry); | 1179 | err = nfserrno(nfsd_sync_dir(dentry)); |
1179 | write_inode_now(dchild->d_inode, 1); | 1180 | write_inode_now(dchild->d_inode, 1); |
1180 | } | 1181 | } |
1181 | 1182 | ||
@@ -1185,9 +1186,11 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1185 | * send along the gid when it tries to implement setgid | 1186 | * send along the gid when it tries to implement setgid |
1186 | * directories via NFS. | 1187 | * directories via NFS. |
1187 | */ | 1188 | */ |
1188 | err = 0; | 1189 | if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) { |
1189 | if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) | 1190 | int err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0); |
1190 | err = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0); | 1191 | if (err2) |
1192 | err = err2; | ||
1193 | } | ||
1191 | /* | 1194 | /* |
1192 | * Update the file handle to get the new inode info. | 1195 | * Update the file handle to get the new inode info. |
1193 | */ | 1196 | */ |
@@ -1306,17 +1309,10 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1306 | goto out_nfserr; | 1309 | goto out_nfserr; |
1307 | 1310 | ||
1308 | if (EX_ISSYNC(fhp->fh_export)) { | 1311 | if (EX_ISSYNC(fhp->fh_export)) { |
1309 | nfsd_sync_dir(dentry); | 1312 | err = nfserrno(nfsd_sync_dir(dentry)); |
1310 | /* setattr will sync the child (or not) */ | 1313 | /* setattr will sync the child (or not) */ |
1311 | } | 1314 | } |
1312 | 1315 | ||
1313 | /* | ||
1314 | * Update the filehandle to get the new inode info. | ||
1315 | */ | ||
1316 | err = fh_update(resfhp); | ||
1317 | if (err) | ||
1318 | goto out; | ||
1319 | |||
1320 | if (createmode == NFS3_CREATE_EXCLUSIVE) { | 1316 | if (createmode == NFS3_CREATE_EXCLUSIVE) { |
1321 | /* Cram the verifier into atime/mtime/mode */ | 1317 | /* Cram the verifier into atime/mtime/mode */ |
1322 | iap->ia_valid = ATTR_MTIME|ATTR_ATIME | 1318 | iap->ia_valid = ATTR_MTIME|ATTR_ATIME |
@@ -1337,8 +1333,17 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1337 | * implement setgid directories via NFS. Clear out all that cruft. | 1333 | * implement setgid directories via NFS. Clear out all that cruft. |
1338 | */ | 1334 | */ |
1339 | set_attr: | 1335 | set_attr: |
1340 | if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID)) != 0) | 1336 | if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID)) != 0) { |
1341 | err = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0); | 1337 | int err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0); |
1338 | if (err2) | ||
1339 | err = err2; | ||
1340 | } | ||
1341 | |||
1342 | /* | ||
1343 | * Update the filehandle to get the new inode info. | ||
1344 | */ | ||
1345 | if (!err) | ||
1346 | err = fh_update(resfhp); | ||
1342 | 1347 | ||
1343 | out: | 1348 | out: |
1344 | fh_unlock(fhp); | 1349 | fh_unlock(fhp); |
@@ -1447,10 +1452,10 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1447 | } else | 1452 | } else |
1448 | err = vfs_symlink(dentry->d_inode, dnew, path, mode); | 1453 | err = vfs_symlink(dentry->d_inode, dnew, path, mode); |
1449 | 1454 | ||
1450 | if (!err) { | 1455 | if (!err) |
1451 | if (EX_ISSYNC(fhp->fh_export)) | 1456 | if (EX_ISSYNC(fhp->fh_export)) |
1452 | nfsd_sync_dir(dentry); | 1457 | err = nfsd_sync_dir(dentry); |
1453 | } else | 1458 | if (err) |
1454 | err = nfserrno(err); | 1459 | err = nfserrno(err); |
1455 | fh_unlock(fhp); | 1460 | fh_unlock(fhp); |
1456 | 1461 | ||
@@ -1506,7 +1511,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, | |||
1506 | err = vfs_link(dold, dirp, dnew); | 1511 | err = vfs_link(dold, dirp, dnew); |
1507 | if (!err) { | 1512 | if (!err) { |
1508 | if (EX_ISSYNC(ffhp->fh_export)) { | 1513 | if (EX_ISSYNC(ffhp->fh_export)) { |
1509 | nfsd_sync_dir(ddir); | 1514 | err = nfserrno(nfsd_sync_dir(ddir)); |
1510 | write_inode_now(dest, 1); | 1515 | write_inode_now(dest, 1); |
1511 | } | 1516 | } |
1512 | } else { | 1517 | } else { |
@@ -1590,13 +1595,14 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, | |||
1590 | if ((ffhp->fh_export->ex_flags & NFSEXP_MSNFS) && | 1595 | if ((ffhp->fh_export->ex_flags & NFSEXP_MSNFS) && |
1591 | ((atomic_read(&odentry->d_count) > 1) | 1596 | ((atomic_read(&odentry->d_count) > 1) |
1592 | || (atomic_read(&ndentry->d_count) > 1))) { | 1597 | || (atomic_read(&ndentry->d_count) > 1))) { |
1593 | err = nfserr_perm; | 1598 | err = -EPERM; |
1594 | } else | 1599 | } else |
1595 | #endif | 1600 | #endif |
1596 | err = vfs_rename(fdir, odentry, tdir, ndentry); | 1601 | err = vfs_rename(fdir, odentry, tdir, ndentry); |
1597 | if (!err && EX_ISSYNC(tfhp->fh_export)) { | 1602 | if (!err && EX_ISSYNC(tfhp->fh_export)) { |
1598 | nfsd_sync_dir(tdentry); | 1603 | err = nfsd_sync_dir(tdentry); |
1599 | nfsd_sync_dir(fdentry); | 1604 | if (!err) |
1605 | err = nfsd_sync_dir(fdentry); | ||
1600 | } | 1606 | } |
1601 | 1607 | ||
1602 | out_dput_new: | 1608 | out_dput_new: |
@@ -1661,7 +1667,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
1661 | #ifdef MSNFS | 1667 | #ifdef MSNFS |
1662 | if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && | 1668 | if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && |
1663 | (atomic_read(&rdentry->d_count) > 1)) { | 1669 | (atomic_read(&rdentry->d_count) > 1)) { |
1664 | err = nfserr_perm; | 1670 | err = -EPERM; |
1665 | } else | 1671 | } else |
1666 | #endif | 1672 | #endif |
1667 | err = vfs_unlink(dirp, rdentry); | 1673 | err = vfs_unlink(dirp, rdentry); |
@@ -1671,17 +1677,14 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
1671 | 1677 | ||
1672 | dput(rdentry); | 1678 | dput(rdentry); |
1673 | 1679 | ||
1674 | if (err) | 1680 | if (err == 0 && |
1675 | goto out_nfserr; | 1681 | EX_ISSYNC(fhp->fh_export)) |
1676 | if (EX_ISSYNC(fhp->fh_export)) | 1682 | err = nfsd_sync_dir(dentry); |
1677 | nfsd_sync_dir(dentry); | ||
1678 | |||
1679 | out: | ||
1680 | return err; | ||
1681 | 1683 | ||
1682 | out_nfserr: | 1684 | out_nfserr: |
1683 | err = nfserrno(err); | 1685 | err = nfserrno(err); |
1684 | goto out; | 1686 | out: |
1687 | return err; | ||
1685 | } | 1688 | } |
1686 | 1689 | ||
1687 | /* | 1690 | /* |
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/security.h> | 20 | #include <linux/security.h> |
21 | #include <linux/mount.h> | 21 | #include <linux/mount.h> |
22 | #include <linux/vfs.h> | 22 | #include <linux/vfs.h> |
23 | #include <linux/fcntl.h> | ||
23 | #include <asm/uaccess.h> | 24 | #include <asm/uaccess.h> |
24 | #include <linux/fs.h> | 25 | #include <linux/fs.h> |
25 | #include <linux/personality.h> | 26 | #include <linux/personality.h> |
@@ -383,7 +384,7 @@ asmlinkage long sys_utime(char __user * filename, struct utimbuf __user * times) | |||
383 | 384 | ||
384 | error = get_user(newattrs.ia_atime.tv_sec, ×->actime); | 385 | error = get_user(newattrs.ia_atime.tv_sec, ×->actime); |
385 | newattrs.ia_atime.tv_nsec = 0; | 386 | newattrs.ia_atime.tv_nsec = 0; |
386 | if (!error) | 387 | if (!error) |
387 | error = get_user(newattrs.ia_mtime.tv_sec, ×->modtime); | 388 | error = get_user(newattrs.ia_mtime.tv_sec, ×->modtime); |
388 | newattrs.ia_mtime.tv_nsec = 0; | 389 | newattrs.ia_mtime.tv_nsec = 0; |
389 | if (error) | 390 | if (error) |
@@ -414,14 +415,14 @@ out: | |||
414 | * must be owner or have write permission. | 415 | * must be owner or have write permission. |
415 | * Else, update from *times, must be owner or super user. | 416 | * Else, update from *times, must be owner or super user. |
416 | */ | 417 | */ |
417 | long do_utimes(char __user * filename, struct timeval * times) | 418 | long do_utimes(int dfd, char __user *filename, struct timeval *times) |
418 | { | 419 | { |
419 | int error; | 420 | int error; |
420 | struct nameidata nd; | 421 | struct nameidata nd; |
421 | struct inode * inode; | 422 | struct inode * inode; |
422 | struct iattr newattrs; | 423 | struct iattr newattrs; |
423 | 424 | ||
424 | error = user_path_walk(filename, &nd); | 425 | error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd); |
425 | 426 | ||
426 | if (error) | 427 | if (error) |
427 | goto out; | 428 | goto out; |
@@ -461,13 +462,18 @@ out: | |||
461 | return error; | 462 | return error; |
462 | } | 463 | } |
463 | 464 | ||
464 | asmlinkage long sys_utimes(char __user * filename, struct timeval __user * utimes) | 465 | asmlinkage long sys_futimesat(int dfd, char __user *filename, struct timeval __user *utimes) |
465 | { | 466 | { |
466 | struct timeval times[2]; | 467 | struct timeval times[2]; |
467 | 468 | ||
468 | if (utimes && copy_from_user(×, utimes, sizeof(times))) | 469 | if (utimes && copy_from_user(×, utimes, sizeof(times))) |
469 | return -EFAULT; | 470 | return -EFAULT; |
470 | return do_utimes(filename, utimes ? times : NULL); | 471 | return do_utimes(dfd, filename, utimes ? times : NULL); |
472 | } | ||
473 | |||
474 | asmlinkage long sys_utimes(char __user *filename, struct timeval __user *utimes) | ||
475 | { | ||
476 | return sys_futimesat(AT_FDCWD, filename, utimes); | ||
471 | } | 477 | } |
472 | 478 | ||
473 | 479 | ||
@@ -476,7 +482,7 @@ asmlinkage long sys_utimes(char __user * filename, struct timeval __user * utime | |||
476 | * We do this by temporarily clearing all FS-related capabilities and | 482 | * We do this by temporarily clearing all FS-related capabilities and |
477 | * switching the fsuid/fsgid around to the real ones. | 483 | * switching the fsuid/fsgid around to the real ones. |
478 | */ | 484 | */ |
479 | asmlinkage long sys_access(const char __user * filename, int mode) | 485 | asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode) |
480 | { | 486 | { |
481 | struct nameidata nd; | 487 | struct nameidata nd; |
482 | int old_fsuid, old_fsgid; | 488 | int old_fsuid, old_fsgid; |
@@ -506,7 +512,7 @@ asmlinkage long sys_access(const char __user * filename, int mode) | |||
506 | else | 512 | else |
507 | current->cap_effective = current->cap_permitted; | 513 | current->cap_effective = current->cap_permitted; |
508 | 514 | ||
509 | res = __user_walk(filename, LOOKUP_FOLLOW|LOOKUP_ACCESS, &nd); | 515 | res = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW|LOOKUP_ACCESS, &nd); |
510 | if (!res) { | 516 | if (!res) { |
511 | res = vfs_permission(&nd, mode); | 517 | res = vfs_permission(&nd, mode); |
512 | /* SuS v2 requires we report a read only fs too */ | 518 | /* SuS v2 requires we report a read only fs too */ |
@@ -523,6 +529,11 @@ asmlinkage long sys_access(const char __user * filename, int mode) | |||
523 | return res; | 529 | return res; |
524 | } | 530 | } |
525 | 531 | ||
532 | asmlinkage long sys_access(const char __user *filename, int mode) | ||
533 | { | ||
534 | return sys_faccessat(AT_FDCWD, filename, mode); | ||
535 | } | ||
536 | |||
526 | asmlinkage long sys_chdir(const char __user * filename) | 537 | asmlinkage long sys_chdir(const char __user * filename) |
527 | { | 538 | { |
528 | struct nameidata nd; | 539 | struct nameidata nd; |
@@ -635,14 +646,15 @@ out: | |||
635 | return err; | 646 | return err; |
636 | } | 647 | } |
637 | 648 | ||
638 | asmlinkage long sys_chmod(const char __user * filename, mode_t mode) | 649 | asmlinkage long sys_fchmodat(int dfd, const char __user *filename, |
650 | mode_t mode) | ||
639 | { | 651 | { |
640 | struct nameidata nd; | 652 | struct nameidata nd; |
641 | struct inode * inode; | 653 | struct inode * inode; |
642 | int error; | 654 | int error; |
643 | struct iattr newattrs; | 655 | struct iattr newattrs; |
644 | 656 | ||
645 | error = user_path_walk(filename, &nd); | 657 | error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd); |
646 | if (error) | 658 | if (error) |
647 | goto out; | 659 | goto out; |
648 | inode = nd.dentry->d_inode; | 660 | inode = nd.dentry->d_inode; |
@@ -669,6 +681,11 @@ out: | |||
669 | return error; | 681 | return error; |
670 | } | 682 | } |
671 | 683 | ||
684 | asmlinkage long sys_chmod(const char __user *filename, mode_t mode) | ||
685 | { | ||
686 | return sys_fchmodat(AT_FDCWD, filename, mode); | ||
687 | } | ||
688 | |||
672 | static int chown_common(struct dentry * dentry, uid_t user, gid_t group) | 689 | static int chown_common(struct dentry * dentry, uid_t user, gid_t group) |
673 | { | 690 | { |
674 | struct inode * inode; | 691 | struct inode * inode; |
@@ -717,6 +734,26 @@ asmlinkage long sys_chown(const char __user * filename, uid_t user, gid_t group) | |||
717 | return error; | 734 | return error; |
718 | } | 735 | } |
719 | 736 | ||
737 | asmlinkage long sys_fchownat(int dfd, const char __user *filename, uid_t user, | ||
738 | gid_t group, int flag) | ||
739 | { | ||
740 | struct nameidata nd; | ||
741 | int error = -EINVAL; | ||
742 | int follow; | ||
743 | |||
744 | if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0) | ||
745 | goto out; | ||
746 | |||
747 | follow = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW; | ||
748 | error = __user_walk_fd(dfd, filename, follow, &nd); | ||
749 | if (!error) { | ||
750 | error = chown_common(nd.dentry, user, group); | ||
751 | path_release(&nd); | ||
752 | } | ||
753 | out: | ||
754 | return error; | ||
755 | } | ||
756 | |||
720 | asmlinkage long sys_lchown(const char __user * filename, uid_t user, gid_t group) | 757 | asmlinkage long sys_lchown(const char __user * filename, uid_t user, gid_t group) |
721 | { | 758 | { |
722 | struct nameidata nd; | 759 | struct nameidata nd; |
@@ -820,7 +857,8 @@ cleanup_file: | |||
820 | * for the internal routines (ie open_namei()/follow_link() etc). 00 is | 857 | * for the internal routines (ie open_namei()/follow_link() etc). 00 is |
821 | * used by symlinks. | 858 | * used by symlinks. |
822 | */ | 859 | */ |
823 | struct file *filp_open(const char * filename, int flags, int mode) | 860 | static struct file *do_filp_open(int dfd, const char *filename, int flags, |
861 | int mode) | ||
824 | { | 862 | { |
825 | int namei_flags, error; | 863 | int namei_flags, error; |
826 | struct nameidata nd; | 864 | struct nameidata nd; |
@@ -829,12 +867,17 @@ struct file *filp_open(const char * filename, int flags, int mode) | |||
829 | if ((namei_flags+1) & O_ACCMODE) | 867 | if ((namei_flags+1) & O_ACCMODE) |
830 | namei_flags++; | 868 | namei_flags++; |
831 | 869 | ||
832 | error = open_namei(filename, namei_flags, mode, &nd); | 870 | error = open_namei(dfd, filename, namei_flags, mode, &nd); |
833 | if (!error) | 871 | if (!error) |
834 | return nameidata_to_filp(&nd, flags); | 872 | return nameidata_to_filp(&nd, flags); |
835 | 873 | ||
836 | return ERR_PTR(error); | 874 | return ERR_PTR(error); |
837 | } | 875 | } |
876 | |||
877 | struct file *filp_open(const char *filename, int flags, int mode) | ||
878 | { | ||
879 | return do_filp_open(AT_FDCWD, filename, flags, mode); | ||
880 | } | ||
838 | EXPORT_SYMBOL(filp_open); | 881 | EXPORT_SYMBOL(filp_open); |
839 | 882 | ||
840 | /** | 883 | /** |
@@ -991,7 +1034,7 @@ void fastcall put_unused_fd(unsigned int fd) | |||
991 | EXPORT_SYMBOL(put_unused_fd); | 1034 | EXPORT_SYMBOL(put_unused_fd); |
992 | 1035 | ||
993 | /* | 1036 | /* |
994 | * Install a file pointer in the fd array. | 1037 | * Install a file pointer in the fd array. |
995 | * | 1038 | * |
996 | * The VFS is full of places where we drop the files lock between | 1039 | * The VFS is full of places where we drop the files lock between |
997 | * setting the open_fds bitmap and installing the file in the file | 1040 | * setting the open_fds bitmap and installing the file in the file |
@@ -1016,7 +1059,7 @@ void fastcall fd_install(unsigned int fd, struct file * file) | |||
1016 | 1059 | ||
1017 | EXPORT_SYMBOL(fd_install); | 1060 | EXPORT_SYMBOL(fd_install); |
1018 | 1061 | ||
1019 | long do_sys_open(const char __user *filename, int flags, int mode) | 1062 | long do_sys_open(int dfd, const char __user *filename, int flags, int mode) |
1020 | { | 1063 | { |
1021 | char *tmp = getname(filename); | 1064 | char *tmp = getname(filename); |
1022 | int fd = PTR_ERR(tmp); | 1065 | int fd = PTR_ERR(tmp); |
@@ -1024,7 +1067,7 @@ long do_sys_open(const char __user *filename, int flags, int mode) | |||
1024 | if (!IS_ERR(tmp)) { | 1067 | if (!IS_ERR(tmp)) { |
1025 | fd = get_unused_fd(); | 1068 | fd = get_unused_fd(); |
1026 | if (fd >= 0) { | 1069 | if (fd >= 0) { |
1027 | struct file *f = filp_open(tmp, flags, mode); | 1070 | struct file *f = do_filp_open(dfd, tmp, flags, mode); |
1028 | if (IS_ERR(f)) { | 1071 | if (IS_ERR(f)) { |
1029 | put_unused_fd(fd); | 1072 | put_unused_fd(fd); |
1030 | fd = PTR_ERR(f); | 1073 | fd = PTR_ERR(f); |
@@ -1043,10 +1086,20 @@ asmlinkage long sys_open(const char __user *filename, int flags, int mode) | |||
1043 | if (force_o_largefile()) | 1086 | if (force_o_largefile()) |
1044 | flags |= O_LARGEFILE; | 1087 | flags |= O_LARGEFILE; |
1045 | 1088 | ||
1046 | return do_sys_open(filename, flags, mode); | 1089 | return do_sys_open(AT_FDCWD, filename, flags, mode); |
1047 | } | 1090 | } |
1048 | EXPORT_SYMBOL_GPL(sys_open); | 1091 | EXPORT_SYMBOL_GPL(sys_open); |
1049 | 1092 | ||
1093 | asmlinkage long sys_openat(int dfd, const char __user *filename, int flags, | ||
1094 | int mode) | ||
1095 | { | ||
1096 | if (force_o_largefile()) | ||
1097 | flags |= O_LARGEFILE; | ||
1098 | |||
1099 | return do_sys_open(dfd, filename, flags, mode); | ||
1100 | } | ||
1101 | EXPORT_SYMBOL_GPL(sys_openat); | ||
1102 | |||
1050 | #ifndef __alpha__ | 1103 | #ifndef __alpha__ |
1051 | 1104 | ||
1052 | /* | 1105 | /* |
diff --git a/fs/select.c b/fs/select.c index f10a10317d54..c0f02d36c60e 100644 --- a/fs/select.c +++ b/fs/select.c | |||
@@ -179,12 +179,11 @@ get_max: | |||
179 | #define POLLOUT_SET (POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR) | 179 | #define POLLOUT_SET (POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR) |
180 | #define POLLEX_SET (POLLPRI) | 180 | #define POLLEX_SET (POLLPRI) |
181 | 181 | ||
182 | int do_select(int n, fd_set_bits *fds, long *timeout) | 182 | int do_select(int n, fd_set_bits *fds, s64 *timeout) |
183 | { | 183 | { |
184 | struct poll_wqueues table; | 184 | struct poll_wqueues table; |
185 | poll_table *wait; | 185 | poll_table *wait; |
186 | int retval, i; | 186 | int retval, i; |
187 | long __timeout = *timeout; | ||
188 | 187 | ||
189 | rcu_read_lock(); | 188 | rcu_read_lock(); |
190 | retval = max_select_fd(n, fds); | 189 | retval = max_select_fd(n, fds); |
@@ -196,11 +195,12 @@ int do_select(int n, fd_set_bits *fds, long *timeout) | |||
196 | 195 | ||
197 | poll_initwait(&table); | 196 | poll_initwait(&table); |
198 | wait = &table.pt; | 197 | wait = &table.pt; |
199 | if (!__timeout) | 198 | if (!*timeout) |
200 | wait = NULL; | 199 | wait = NULL; |
201 | retval = 0; | 200 | retval = 0; |
202 | for (;;) { | 201 | for (;;) { |
203 | unsigned long *rinp, *routp, *rexp, *inp, *outp, *exp; | 202 | unsigned long *rinp, *routp, *rexp, *inp, *outp, *exp; |
203 | long __timeout; | ||
204 | 204 | ||
205 | set_current_state(TASK_INTERRUPTIBLE); | 205 | set_current_state(TASK_INTERRUPTIBLE); |
206 | 206 | ||
@@ -255,22 +255,32 @@ int do_select(int n, fd_set_bits *fds, long *timeout) | |||
255 | *rexp = res_ex; | 255 | *rexp = res_ex; |
256 | } | 256 | } |
257 | wait = NULL; | 257 | wait = NULL; |
258 | if (retval || !__timeout || signal_pending(current)) | 258 | if (retval || !*timeout || signal_pending(current)) |
259 | break; | 259 | break; |
260 | if(table.error) { | 260 | if(table.error) { |
261 | retval = table.error; | 261 | retval = table.error; |
262 | break; | 262 | break; |
263 | } | 263 | } |
264 | |||
265 | if (*timeout < 0) { | ||
266 | /* Wait indefinitely */ | ||
267 | __timeout = MAX_SCHEDULE_TIMEOUT; | ||
268 | } else if (unlikely(*timeout >= (s64)MAX_SCHEDULE_TIMEOUT - 1)) { | ||
269 | /* Wait for longer than MAX_SCHEDULE_TIMEOUT. Do it in a loop */ | ||
270 | __timeout = MAX_SCHEDULE_TIMEOUT - 1; | ||
271 | *timeout -= __timeout; | ||
272 | } else { | ||
273 | __timeout = *timeout; | ||
274 | *timeout = 0; | ||
275 | } | ||
264 | __timeout = schedule_timeout(__timeout); | 276 | __timeout = schedule_timeout(__timeout); |
277 | if (*timeout >= 0) | ||
278 | *timeout += __timeout; | ||
265 | } | 279 | } |
266 | __set_current_state(TASK_RUNNING); | 280 | __set_current_state(TASK_RUNNING); |
267 | 281 | ||
268 | poll_freewait(&table); | 282 | poll_freewait(&table); |
269 | 283 | ||
270 | /* | ||
271 | * Up-to-date the caller timeout. | ||
272 | */ | ||
273 | *timeout = __timeout; | ||
274 | return retval; | 284 | return retval; |
275 | } | 285 | } |
276 | 286 | ||
@@ -295,36 +305,14 @@ static void select_bits_free(void *bits, int size) | |||
295 | #define MAX_SELECT_SECONDS \ | 305 | #define MAX_SELECT_SECONDS \ |
296 | ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1) | 306 | ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1) |
297 | 307 | ||
298 | asmlinkage long | 308 | static int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp, |
299 | sys_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, struct timeval __user *tvp) | 309 | fd_set __user *exp, s64 *timeout) |
300 | { | 310 | { |
301 | fd_set_bits fds; | 311 | fd_set_bits fds; |
302 | char *bits; | 312 | char *bits; |
303 | long timeout; | ||
304 | int ret, size, max_fdset; | 313 | int ret, size, max_fdset; |
305 | struct fdtable *fdt; | 314 | struct fdtable *fdt; |
306 | 315 | ||
307 | timeout = MAX_SCHEDULE_TIMEOUT; | ||
308 | if (tvp) { | ||
309 | time_t sec, usec; | ||
310 | |||
311 | if (!access_ok(VERIFY_READ, tvp, sizeof(*tvp)) | ||
312 | || __get_user(sec, &tvp->tv_sec) | ||
313 | || __get_user(usec, &tvp->tv_usec)) { | ||
314 | ret = -EFAULT; | ||
315 | goto out_nofds; | ||
316 | } | ||
317 | |||
318 | ret = -EINVAL; | ||
319 | if (sec < 0 || usec < 0) | ||
320 | goto out_nofds; | ||
321 | |||
322 | if ((unsigned long) sec < MAX_SELECT_SECONDS) { | ||
323 | timeout = ROUND_UP(usec, 1000000/HZ); | ||
324 | timeout += sec * (unsigned long) HZ; | ||
325 | } | ||
326 | } | ||
327 | |||
328 | ret = -EINVAL; | 316 | ret = -EINVAL; |
329 | if (n < 0) | 317 | if (n < 0) |
330 | goto out_nofds; | 318 | goto out_nofds; |
@@ -362,18 +350,7 @@ sys_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, s | |||
362 | zero_fd_set(n, fds.res_out); | 350 | zero_fd_set(n, fds.res_out); |
363 | zero_fd_set(n, fds.res_ex); | 351 | zero_fd_set(n, fds.res_ex); |
364 | 352 | ||
365 | ret = do_select(n, &fds, &timeout); | 353 | ret = do_select(n, &fds, timeout); |
366 | |||
367 | if (tvp && !(current->personality & STICKY_TIMEOUTS)) { | ||
368 | time_t sec = 0, usec = 0; | ||
369 | if (timeout) { | ||
370 | sec = timeout / HZ; | ||
371 | usec = timeout % HZ; | ||
372 | usec *= (1000000/HZ); | ||
373 | } | ||
374 | put_user(sec, &tvp->tv_sec); | ||
375 | put_user(usec, &tvp->tv_usec); | ||
376 | } | ||
377 | 354 | ||
378 | if (ret < 0) | 355 | if (ret < 0) |
379 | goto out; | 356 | goto out; |
@@ -395,6 +372,154 @@ out_nofds: | |||
395 | return ret; | 372 | return ret; |
396 | } | 373 | } |
397 | 374 | ||
375 | asmlinkage long sys_select(int n, fd_set __user *inp, fd_set __user *outp, | ||
376 | fd_set __user *exp, struct timeval __user *tvp) | ||
377 | { | ||
378 | s64 timeout = -1; | ||
379 | struct timeval tv; | ||
380 | int ret; | ||
381 | |||
382 | if (tvp) { | ||
383 | if (copy_from_user(&tv, tvp, sizeof(tv))) | ||
384 | return -EFAULT; | ||
385 | |||
386 | if (tv.tv_sec < 0 || tv.tv_usec < 0) | ||
387 | return -EINVAL; | ||
388 | |||
389 | /* Cast to u64 to make GCC stop complaining */ | ||
390 | if ((u64)tv.tv_sec >= (u64)MAX_INT64_SECONDS) | ||
391 | timeout = -1; /* infinite */ | ||
392 | else { | ||
393 | timeout = ROUND_UP(tv.tv_usec, USEC_PER_SEC/HZ); | ||
394 | timeout += tv.tv_sec * HZ; | ||
395 | } | ||
396 | } | ||
397 | |||
398 | ret = core_sys_select(n, inp, outp, exp, &timeout); | ||
399 | |||
400 | if (tvp) { | ||
401 | if (current->personality & STICKY_TIMEOUTS) | ||
402 | goto sticky; | ||
403 | tv.tv_usec = jiffies_to_usecs(do_div((*(u64*)&timeout), HZ)); | ||
404 | tv.tv_sec = timeout; | ||
405 | if (copy_to_user(tvp, &tv, sizeof(tv))) { | ||
406 | sticky: | ||
407 | /* | ||
408 | * If an application puts its timeval in read-only | ||
409 | * memory, we don't want the Linux-specific update to | ||
410 | * the timeval to cause a fault after the select has | ||
411 | * completed successfully. However, because we're not | ||
412 | * updating the timeval, we can't restart the system | ||
413 | * call. | ||
414 | */ | ||
415 | if (ret == -ERESTARTNOHAND) | ||
416 | ret = -EINTR; | ||
417 | } | ||
418 | } | ||
419 | |||
420 | return ret; | ||
421 | } | ||
422 | |||
423 | #ifdef TIF_RESTORE_SIGMASK | ||
424 | asmlinkage long sys_pselect7(int n, fd_set __user *inp, fd_set __user *outp, | ||
425 | fd_set __user *exp, struct timespec __user *tsp, | ||
426 | const sigset_t __user *sigmask, size_t sigsetsize) | ||
427 | { | ||
428 | s64 timeout = MAX_SCHEDULE_TIMEOUT; | ||
429 | sigset_t ksigmask, sigsaved; | ||
430 | struct timespec ts; | ||
431 | int ret; | ||
432 | |||
433 | if (tsp) { | ||
434 | if (copy_from_user(&ts, tsp, sizeof(ts))) | ||
435 | return -EFAULT; | ||
436 | |||
437 | if (ts.tv_sec < 0 || ts.tv_nsec < 0) | ||
438 | return -EINVAL; | ||
439 | |||
440 | /* Cast to u64 to make GCC stop complaining */ | ||
441 | if ((u64)ts.tv_sec >= (u64)MAX_INT64_SECONDS) | ||
442 | timeout = -1; /* infinite */ | ||
443 | else { | ||
444 | timeout = ROUND_UP(ts.tv_nsec, NSEC_PER_SEC/HZ); | ||
445 | timeout += ts.tv_sec * HZ; | ||
446 | } | ||
447 | } | ||
448 | |||
449 | if (sigmask) { | ||
450 | /* XXX: Don't preclude handling different sized sigset_t's. */ | ||
451 | if (sigsetsize != sizeof(sigset_t)) | ||
452 | return -EINVAL; | ||
453 | if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask))) | ||
454 | return -EFAULT; | ||
455 | |||
456 | sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP)); | ||
457 | sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); | ||
458 | } | ||
459 | |||
460 | ret = core_sys_select(n, inp, outp, exp, &timeout); | ||
461 | |||
462 | if (tsp) { | ||
463 | if (current->personality & STICKY_TIMEOUTS) | ||
464 | goto sticky; | ||
465 | ts.tv_nsec = jiffies_to_usecs(do_div((*(u64*)&timeout), HZ)) * 1000; | ||
466 | ts.tv_sec = timeout; | ||
467 | if (copy_to_user(tsp, &ts, sizeof(ts))) { | ||
468 | sticky: | ||
469 | /* | ||
470 | * If an application puts its timeval in read-only | ||
471 | * memory, we don't want the Linux-specific update to | ||
472 | * the timeval to cause a fault after the select has | ||
473 | * completed successfully. However, because we're not | ||
474 | * updating the timeval, we can't restart the system | ||
475 | * call. | ||
476 | */ | ||
477 | if (ret == -ERESTARTNOHAND) | ||
478 | ret = -EINTR; | ||
479 | } | ||
480 | } | ||
481 | |||
482 | if (ret == -ERESTARTNOHAND) { | ||
483 | /* | ||
484 | * Don't restore the signal mask yet. Let do_signal() deliver | ||
485 | * the signal on the way back to userspace, before the signal | ||
486 | * mask is restored. | ||
487 | */ | ||
488 | if (sigmask) { | ||
489 | memcpy(¤t->saved_sigmask, &sigsaved, | ||
490 | sizeof(sigsaved)); | ||
491 | set_thread_flag(TIF_RESTORE_SIGMASK); | ||
492 | } | ||
493 | } else if (sigmask) | ||
494 | sigprocmask(SIG_SETMASK, &sigsaved, NULL); | ||
495 | |||
496 | return ret; | ||
497 | } | ||
498 | |||
499 | /* | ||
500 | * Most architectures can't handle 7-argument syscalls. So we provide a | ||
501 | * 6-argument version where the sixth argument is a pointer to a structure | ||
502 | * which has a pointer to the sigset_t itself followed by a size_t containing | ||
503 | * the sigset size. | ||
504 | */ | ||
505 | asmlinkage long sys_pselect6(int n, fd_set __user *inp, fd_set __user *outp, | ||
506 | fd_set __user *exp, struct timespec __user *tsp, void __user *sig) | ||
507 | { | ||
508 | size_t sigsetsize = 0; | ||
509 | sigset_t __user *up = NULL; | ||
510 | |||
511 | if (sig) { | ||
512 | if (!access_ok(VERIFY_READ, sig, sizeof(void *)+sizeof(size_t)) | ||
513 | || __get_user(up, (sigset_t * __user *)sig) | ||
514 | || __get_user(sigsetsize, | ||
515 | (size_t * __user)(sig+sizeof(void *)))) | ||
516 | return -EFAULT; | ||
517 | } | ||
518 | |||
519 | return sys_pselect7(n, inp, outp, exp, tsp, up, sigsetsize); | ||
520 | } | ||
521 | #endif /* TIF_RESTORE_SIGMASK */ | ||
522 | |||
398 | struct poll_list { | 523 | struct poll_list { |
399 | struct poll_list *next; | 524 | struct poll_list *next; |
400 | int len; | 525 | int len; |
@@ -436,16 +561,19 @@ static void do_pollfd(unsigned int num, struct pollfd * fdpage, | |||
436 | } | 561 | } |
437 | 562 | ||
438 | static int do_poll(unsigned int nfds, struct poll_list *list, | 563 | static int do_poll(unsigned int nfds, struct poll_list *list, |
439 | struct poll_wqueues *wait, long timeout) | 564 | struct poll_wqueues *wait, s64 *timeout) |
440 | { | 565 | { |
441 | int count = 0; | 566 | int count = 0; |
442 | poll_table* pt = &wait->pt; | 567 | poll_table* pt = &wait->pt; |
443 | 568 | ||
444 | if (!timeout) | 569 | /* Optimise the no-wait case */ |
570 | if (!(*timeout)) | ||
445 | pt = NULL; | 571 | pt = NULL; |
446 | 572 | ||
447 | for (;;) { | 573 | for (;;) { |
448 | struct poll_list *walk; | 574 | struct poll_list *walk; |
575 | long __timeout; | ||
576 | |||
449 | set_current_state(TASK_INTERRUPTIBLE); | 577 | set_current_state(TASK_INTERRUPTIBLE); |
450 | walk = list; | 578 | walk = list; |
451 | while(walk != NULL) { | 579 | while(walk != NULL) { |
@@ -453,18 +581,36 @@ static int do_poll(unsigned int nfds, struct poll_list *list, | |||
453 | walk = walk->next; | 581 | walk = walk->next; |
454 | } | 582 | } |
455 | pt = NULL; | 583 | pt = NULL; |
456 | if (count || !timeout || signal_pending(current)) | 584 | if (count || !*timeout || signal_pending(current)) |
457 | break; | 585 | break; |
458 | count = wait->error; | 586 | count = wait->error; |
459 | if (count) | 587 | if (count) |
460 | break; | 588 | break; |
461 | timeout = schedule_timeout(timeout); | 589 | |
590 | if (*timeout < 0) { | ||
591 | /* Wait indefinitely */ | ||
592 | __timeout = MAX_SCHEDULE_TIMEOUT; | ||
593 | } else if (unlikely(*timeout >= (s64)MAX_SCHEDULE_TIMEOUT-1)) { | ||
594 | /* | ||
595 | * Wait for longer than MAX_SCHEDULE_TIMEOUT. Do it in | ||
596 | * a loop | ||
597 | */ | ||
598 | __timeout = MAX_SCHEDULE_TIMEOUT - 1; | ||
599 | *timeout -= __timeout; | ||
600 | } else { | ||
601 | __timeout = *timeout; | ||
602 | *timeout = 0; | ||
603 | } | ||
604 | |||
605 | __timeout = schedule_timeout(__timeout); | ||
606 | if (*timeout >= 0) | ||
607 | *timeout += __timeout; | ||
462 | } | 608 | } |
463 | __set_current_state(TASK_RUNNING); | 609 | __set_current_state(TASK_RUNNING); |
464 | return count; | 610 | return count; |
465 | } | 611 | } |
466 | 612 | ||
467 | asmlinkage long sys_poll(struct pollfd __user * ufds, unsigned int nfds, long timeout) | 613 | int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds, s64 *timeout) |
468 | { | 614 | { |
469 | struct poll_wqueues table; | 615 | struct poll_wqueues table; |
470 | int fdcount, err; | 616 | int fdcount, err; |
@@ -482,14 +628,6 @@ asmlinkage long sys_poll(struct pollfd __user * ufds, unsigned int nfds, long ti | |||
482 | if (nfds > max_fdset && nfds > OPEN_MAX) | 628 | if (nfds > max_fdset && nfds > OPEN_MAX) |
483 | return -EINVAL; | 629 | return -EINVAL; |
484 | 630 | ||
485 | if (timeout) { | ||
486 | /* Careful about overflow in the intermediate values */ | ||
487 | if ((unsigned long) timeout < MAX_SCHEDULE_TIMEOUT / HZ) | ||
488 | timeout = (unsigned long)(timeout*HZ+999)/1000+1; | ||
489 | else /* Negative or overflow */ | ||
490 | timeout = MAX_SCHEDULE_TIMEOUT; | ||
491 | } | ||
492 | |||
493 | poll_initwait(&table); | 631 | poll_initwait(&table); |
494 | 632 | ||
495 | head = NULL; | 633 | head = NULL; |
@@ -519,6 +657,7 @@ asmlinkage long sys_poll(struct pollfd __user * ufds, unsigned int nfds, long ti | |||
519 | } | 657 | } |
520 | i -= pp->len; | 658 | i -= pp->len; |
521 | } | 659 | } |
660 | |||
522 | fdcount = do_poll(nfds, head, &table, timeout); | 661 | fdcount = do_poll(nfds, head, &table, timeout); |
523 | 662 | ||
524 | /* OK, now copy the revents fields back to user space. */ | 663 | /* OK, now copy the revents fields back to user space. */ |
@@ -547,3 +686,98 @@ out_fds: | |||
547 | poll_freewait(&table); | 686 | poll_freewait(&table); |
548 | return err; | 687 | return err; |
549 | } | 688 | } |
689 | |||
690 | asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds, | ||
691 | long timeout_msecs) | ||
692 | { | ||
693 | s64 timeout_jiffies = 0; | ||
694 | |||
695 | if (timeout_msecs) { | ||
696 | #if HZ > 1000 | ||
697 | /* We can only overflow if HZ > 1000 */ | ||
698 | if (timeout_msecs / 1000 > (s64)0x7fffffffffffffffULL / (s64)HZ) | ||
699 | timeout_jiffies = -1; | ||
700 | else | ||
701 | #endif | ||
702 | timeout_jiffies = msecs_to_jiffies(timeout_msecs); | ||
703 | } | ||
704 | |||
705 | return do_sys_poll(ufds, nfds, &timeout_jiffies); | ||
706 | } | ||
707 | |||
708 | #ifdef TIF_RESTORE_SIGMASK | ||
709 | asmlinkage long sys_ppoll(struct pollfd __user *ufds, unsigned int nfds, | ||
710 | struct timespec __user *tsp, const sigset_t __user *sigmask, | ||
711 | size_t sigsetsize) | ||
712 | { | ||
713 | sigset_t ksigmask, sigsaved; | ||
714 | struct timespec ts; | ||
715 | s64 timeout = -1; | ||
716 | int ret; | ||
717 | |||
718 | if (tsp) { | ||
719 | if (copy_from_user(&ts, tsp, sizeof(ts))) | ||
720 | return -EFAULT; | ||
721 | |||
722 | /* Cast to u64 to make GCC stop complaining */ | ||
723 | if ((u64)ts.tv_sec >= (u64)MAX_INT64_SECONDS) | ||
724 | timeout = -1; /* infinite */ | ||
725 | else { | ||
726 | timeout = ROUND_UP(ts.tv_nsec, NSEC_PER_SEC/HZ); | ||
727 | timeout += ts.tv_sec * HZ; | ||
728 | } | ||
729 | } | ||
730 | |||
731 | if (sigmask) { | ||
732 | /* XXX: Don't preclude handling different sized sigset_t's. */ | ||
733 | if (sigsetsize != sizeof(sigset_t)) | ||
734 | return -EINVAL; | ||
735 | if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask))) | ||
736 | return -EFAULT; | ||
737 | |||
738 | sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP)); | ||
739 | sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); | ||
740 | } | ||
741 | |||
742 | ret = do_sys_poll(ufds, nfds, &timeout); | ||
743 | |||
744 | /* We can restart this syscall, usually */ | ||
745 | if (ret == -EINTR) { | ||
746 | /* | ||
747 | * Don't restore the signal mask yet. Let do_signal() deliver | ||
748 | * the signal on the way back to userspace, before the signal | ||
749 | * mask is restored. | ||
750 | */ | ||
751 | if (sigmask) { | ||
752 | memcpy(¤t->saved_sigmask, &sigsaved, | ||
753 | sizeof(sigsaved)); | ||
754 | set_thread_flag(TIF_RESTORE_SIGMASK); | ||
755 | } | ||
756 | ret = -ERESTARTNOHAND; | ||
757 | } else if (sigmask) | ||
758 | sigprocmask(SIG_SETMASK, &sigsaved, NULL); | ||
759 | |||
760 | if (tsp && timeout >= 0) { | ||
761 | if (current->personality & STICKY_TIMEOUTS) | ||
762 | goto sticky; | ||
763 | /* Yes, we know it's actually an s64, but it's also positive. */ | ||
764 | ts.tv_nsec = jiffies_to_usecs(do_div((*(u64*)&timeout), HZ)) * 1000; | ||
765 | ts.tv_sec = timeout; | ||
766 | if (copy_to_user(tsp, &ts, sizeof(ts))) { | ||
767 | sticky: | ||
768 | /* | ||
769 | * If an application puts its timeval in read-only | ||
770 | * memory, we don't want the Linux-specific update to | ||
771 | * the timeval to cause a fault after the select has | ||
772 | * completed successfully. However, because we're not | ||
773 | * updating the timeval, we can't restart the system | ||
774 | * call. | ||
775 | */ | ||
776 | if (ret == -ERESTARTNOHAND && timeout >= 0) | ||
777 | ret = -EINTR; | ||
778 | } | ||
779 | } | ||
780 | |||
781 | return ret; | ||
782 | } | ||
783 | #endif /* TIF_RESTORE_SIGMASK */ | ||
@@ -63,12 +63,12 @@ int vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | |||
63 | 63 | ||
64 | EXPORT_SYMBOL(vfs_getattr); | 64 | EXPORT_SYMBOL(vfs_getattr); |
65 | 65 | ||
66 | int vfs_stat(char __user *name, struct kstat *stat) | 66 | int vfs_stat_fd(int dfd, char __user *name, struct kstat *stat) |
67 | { | 67 | { |
68 | struct nameidata nd; | 68 | struct nameidata nd; |
69 | int error; | 69 | int error; |
70 | 70 | ||
71 | error = user_path_walk(name, &nd); | 71 | error = __user_walk_fd(dfd, name, LOOKUP_FOLLOW, &nd); |
72 | if (!error) { | 72 | if (!error) { |
73 | error = vfs_getattr(nd.mnt, nd.dentry, stat); | 73 | error = vfs_getattr(nd.mnt, nd.dentry, stat); |
74 | path_release(&nd); | 74 | path_release(&nd); |
@@ -76,14 +76,19 @@ int vfs_stat(char __user *name, struct kstat *stat) | |||
76 | return error; | 76 | return error; |
77 | } | 77 | } |
78 | 78 | ||
79 | int vfs_stat(char __user *name, struct kstat *stat) | ||
80 | { | ||
81 | return vfs_stat_fd(AT_FDCWD, name, stat); | ||
82 | } | ||
83 | |||
79 | EXPORT_SYMBOL(vfs_stat); | 84 | EXPORT_SYMBOL(vfs_stat); |
80 | 85 | ||
81 | int vfs_lstat(char __user *name, struct kstat *stat) | 86 | int vfs_lstat_fd(int dfd, char __user *name, struct kstat *stat) |
82 | { | 87 | { |
83 | struct nameidata nd; | 88 | struct nameidata nd; |
84 | int error; | 89 | int error; |
85 | 90 | ||
86 | error = user_path_walk_link(name, &nd); | 91 | error = __user_walk_fd(dfd, name, 0, &nd); |
87 | if (!error) { | 92 | if (!error) { |
88 | error = vfs_getattr(nd.mnt, nd.dentry, stat); | 93 | error = vfs_getattr(nd.mnt, nd.dentry, stat); |
89 | path_release(&nd); | 94 | path_release(&nd); |
@@ -91,6 +96,11 @@ int vfs_lstat(char __user *name, struct kstat *stat) | |||
91 | return error; | 96 | return error; |
92 | } | 97 | } |
93 | 98 | ||
99 | int vfs_lstat(char __user *name, struct kstat *stat) | ||
100 | { | ||
101 | return vfs_lstat_fd(AT_FDCWD, name, stat); | ||
102 | } | ||
103 | |||
94 | EXPORT_SYMBOL(vfs_lstat); | 104 | EXPORT_SYMBOL(vfs_lstat); |
95 | 105 | ||
96 | int vfs_fstat(unsigned int fd, struct kstat *stat) | 106 | int vfs_fstat(unsigned int fd, struct kstat *stat) |
@@ -151,7 +161,7 @@ static int cp_old_stat(struct kstat *stat, struct __old_kernel_stat __user * sta | |||
151 | asmlinkage long sys_stat(char __user * filename, struct __old_kernel_stat __user * statbuf) | 161 | asmlinkage long sys_stat(char __user * filename, struct __old_kernel_stat __user * statbuf) |
152 | { | 162 | { |
153 | struct kstat stat; | 163 | struct kstat stat; |
154 | int error = vfs_stat(filename, &stat); | 164 | int error = vfs_stat_fd(AT_FDCWD, filename, &stat); |
155 | 165 | ||
156 | if (!error) | 166 | if (!error) |
157 | error = cp_old_stat(&stat, statbuf); | 167 | error = cp_old_stat(&stat, statbuf); |
@@ -161,7 +171,7 @@ asmlinkage long sys_stat(char __user * filename, struct __old_kernel_stat __user | |||
161 | asmlinkage long sys_lstat(char __user * filename, struct __old_kernel_stat __user * statbuf) | 171 | asmlinkage long sys_lstat(char __user * filename, struct __old_kernel_stat __user * statbuf) |
162 | { | 172 | { |
163 | struct kstat stat; | 173 | struct kstat stat; |
164 | int error = vfs_lstat(filename, &stat); | 174 | int error = vfs_lstat_fd(AT_FDCWD, filename, &stat); |
165 | 175 | ||
166 | if (!error) | 176 | if (!error) |
167 | error = cp_old_stat(&stat, statbuf); | 177 | error = cp_old_stat(&stat, statbuf); |
@@ -229,27 +239,50 @@ static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf) | |||
229 | return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; | 239 | return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; |
230 | } | 240 | } |
231 | 241 | ||
232 | asmlinkage long sys_newstat(char __user * filename, struct stat __user * statbuf) | 242 | asmlinkage long sys_newstat(char __user *filename, struct stat __user *statbuf) |
233 | { | 243 | { |
234 | struct kstat stat; | 244 | struct kstat stat; |
235 | int error = vfs_stat(filename, &stat); | 245 | int error = vfs_stat_fd(AT_FDCWD, filename, &stat); |
236 | 246 | ||
237 | if (!error) | 247 | if (!error) |
238 | error = cp_new_stat(&stat, statbuf); | 248 | error = cp_new_stat(&stat, statbuf); |
239 | 249 | ||
240 | return error; | 250 | return error; |
241 | } | 251 | } |
242 | asmlinkage long sys_newlstat(char __user * filename, struct stat __user * statbuf) | 252 | |
253 | asmlinkage long sys_newlstat(char __user *filename, struct stat __user *statbuf) | ||
243 | { | 254 | { |
244 | struct kstat stat; | 255 | struct kstat stat; |
245 | int error = vfs_lstat(filename, &stat); | 256 | int error = vfs_lstat_fd(AT_FDCWD, filename, &stat); |
246 | 257 | ||
247 | if (!error) | 258 | if (!error) |
248 | error = cp_new_stat(&stat, statbuf); | 259 | error = cp_new_stat(&stat, statbuf); |
249 | 260 | ||
250 | return error; | 261 | return error; |
251 | } | 262 | } |
252 | asmlinkage long sys_newfstat(unsigned int fd, struct stat __user * statbuf) | 263 | |
264 | asmlinkage long sys_newfstatat(int dfd, char __user *filename, | ||
265 | struct stat __user *statbuf, int flag) | ||
266 | { | ||
267 | struct kstat stat; | ||
268 | int error = -EINVAL; | ||
269 | |||
270 | if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0) | ||
271 | goto out; | ||
272 | |||
273 | if (flag & AT_SYMLINK_NOFOLLOW) | ||
274 | error = vfs_lstat_fd(dfd, filename, &stat); | ||
275 | else | ||
276 | error = vfs_stat_fd(dfd, filename, &stat); | ||
277 | |||
278 | if (!error) | ||
279 | error = cp_new_stat(&stat, statbuf); | ||
280 | |||
281 | out: | ||
282 | return error; | ||
283 | } | ||
284 | |||
285 | asmlinkage long sys_newfstat(unsigned int fd, struct stat __user *statbuf) | ||
253 | { | 286 | { |
254 | struct kstat stat; | 287 | struct kstat stat; |
255 | int error = vfs_fstat(fd, &stat); | 288 | int error = vfs_fstat(fd, &stat); |
@@ -260,7 +293,8 @@ asmlinkage long sys_newfstat(unsigned int fd, struct stat __user * statbuf) | |||
260 | return error; | 293 | return error; |
261 | } | 294 | } |
262 | 295 | ||
263 | asmlinkage long sys_readlink(const char __user * path, char __user * buf, int bufsiz) | 296 | asmlinkage long sys_readlinkat(int dfd, const char __user *path, |
297 | char __user *buf, int bufsiz) | ||
264 | { | 298 | { |
265 | struct nameidata nd; | 299 | struct nameidata nd; |
266 | int error; | 300 | int error; |
@@ -268,7 +302,7 @@ asmlinkage long sys_readlink(const char __user * path, char __user * buf, int bu | |||
268 | if (bufsiz <= 0) | 302 | if (bufsiz <= 0) |
269 | return -EINVAL; | 303 | return -EINVAL; |
270 | 304 | ||
271 | error = user_path_walk_link(path, &nd); | 305 | error = __user_walk_fd(dfd, path, 0, &nd); |
272 | if (!error) { | 306 | if (!error) { |
273 | struct inode * inode = nd.dentry->d_inode; | 307 | struct inode * inode = nd.dentry->d_inode; |
274 | 308 | ||
@@ -285,6 +319,12 @@ asmlinkage long sys_readlink(const char __user * path, char __user * buf, int bu | |||
285 | return error; | 319 | return error; |
286 | } | 320 | } |
287 | 321 | ||
322 | asmlinkage long sys_readlink(const char __user *path, char __user *buf, | ||
323 | int bufsiz) | ||
324 | { | ||
325 | return sys_readlinkat(AT_FDCWD, path, buf, bufsiz); | ||
326 | } | ||
327 | |||
288 | 328 | ||
289 | /* ---------- LFS-64 ----------- */ | 329 | /* ---------- LFS-64 ----------- */ |
290 | #ifdef __ARCH_WANT_STAT64 | 330 | #ifdef __ARCH_WANT_STAT64 |
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index d1db8c17a74e..120626789406 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c | |||
@@ -336,24 +336,47 @@ static inline int bio_add_buffer(struct bio *bio, struct buffer_head *bh) | |||
336 | } | 336 | } |
337 | 337 | ||
338 | /* | 338 | /* |
339 | * Submit all of the bios for all of the ioends we have saved up, | 339 | * Submit all of the bios for all of the ioends we have saved up, covering the |
340 | * covering the initial writepage page and also any probed pages. | 340 | * initial writepage page and also any probed pages. |
341 | * | ||
342 | * Because we may have multiple ioends spanning a page, we need to start | ||
343 | * writeback on all the buffers before we submit them for I/O. If we mark the | ||
344 | * buffers as we got, then we can end up with a page that only has buffers | ||
345 | * marked async write and I/O complete on can occur before we mark the other | ||
346 | * buffers async write. | ||
347 | * | ||
348 | * The end result of this is that we trip a bug in end_page_writeback() because | ||
349 | * we call it twice for the one page as the code in end_buffer_async_write() | ||
350 | * assumes that all buffers on the page are started at the same time. | ||
351 | * | ||
352 | * The fix is two passes across the ioend list - one to start writeback on the | ||
353 | * bufferheads, and then the second one submit them for I/O. | ||
341 | */ | 354 | */ |
342 | STATIC void | 355 | STATIC void |
343 | xfs_submit_ioend( | 356 | xfs_submit_ioend( |
344 | xfs_ioend_t *ioend) | 357 | xfs_ioend_t *ioend) |
345 | { | 358 | { |
359 | xfs_ioend_t *head = ioend; | ||
346 | xfs_ioend_t *next; | 360 | xfs_ioend_t *next; |
347 | struct buffer_head *bh; | 361 | struct buffer_head *bh; |
348 | struct bio *bio; | 362 | struct bio *bio; |
349 | sector_t lastblock = 0; | 363 | sector_t lastblock = 0; |
350 | 364 | ||
365 | /* Pass 1 - start writeback */ | ||
366 | do { | ||
367 | next = ioend->io_list; | ||
368 | for (bh = ioend->io_buffer_head; bh; bh = bh->b_private) { | ||
369 | xfs_start_buffer_writeback(bh); | ||
370 | } | ||
371 | } while ((ioend = next) != NULL); | ||
372 | |||
373 | /* Pass 2 - submit I/O */ | ||
374 | ioend = head; | ||
351 | do { | 375 | do { |
352 | next = ioend->io_list; | 376 | next = ioend->io_list; |
353 | bio = NULL; | 377 | bio = NULL; |
354 | 378 | ||
355 | for (bh = ioend->io_buffer_head; bh; bh = bh->b_private) { | 379 | for (bh = ioend->io_buffer_head; bh; bh = bh->b_private) { |
356 | xfs_start_buffer_writeback(bh); | ||
357 | 380 | ||
358 | if (!bio) { | 381 | if (!bio) { |
359 | retry: | 382 | retry: |