diff options
Diffstat (limited to 'fs')
36 files changed, 1376 insertions, 932 deletions
diff --git a/fs/Kconfig b/fs/Kconfig index 8b18a8758677..2e43d46f65d6 100644 --- a/fs/Kconfig +++ b/fs/Kconfig | |||
@@ -411,7 +411,7 @@ config JFS_STATISTICS | |||
411 | to be made available to the user in the /proc/fs/jfs/ directory. | 411 | to be made available to the user in the /proc/fs/jfs/ directory. |
412 | 412 | ||
413 | config FS_POSIX_ACL | 413 | config FS_POSIX_ACL |
414 | # Posix ACL utility routines (for now, only ext2/ext3/jfs/reiserfs) | 414 | # Posix ACL utility routines (for now, only ext2/ext3/jfs/reiserfs/nfs4) |
415 | # | 415 | # |
416 | # NOTE: you can implement Posix ACLs without these helpers (XFS does). | 416 | # NOTE: you can implement Posix ACLs without these helpers (XFS does). |
417 | # Never use this symbol for ifdefs. | 417 | # Never use this symbol for ifdefs. |
@@ -1664,105 +1664,86 @@ config NFS_V4 | |||
1664 | 1664 | ||
1665 | If unsure, say N. | 1665 | If unsure, say N. |
1666 | 1666 | ||
1667 | config NFS_DIRECTIO | ||
1668 | bool "Allow direct I/O on NFS files" | ||
1669 | depends on NFS_FS | ||
1670 | help | ||
1671 | This option enables applications to perform uncached I/O on files | ||
1672 | in NFS file systems using the O_DIRECT open() flag. When O_DIRECT | ||
1673 | is set for a file, its data is not cached in the system's page | ||
1674 | cache. Data is moved to and from user-level application buffers | ||
1675 | directly. Unlike local disk-based file systems, NFS O_DIRECT has | ||
1676 | no alignment restrictions. | ||
1677 | |||
1678 | Unless your program is designed to use O_DIRECT properly, you are | ||
1679 | much better off allowing the NFS client to manage data caching for | ||
1680 | you. Misusing O_DIRECT can cause poor server performance or network | ||
1681 | storms. This kernel build option defaults OFF to avoid exposing | ||
1682 | system administrators unwittingly to a potentially hazardous | ||
1683 | feature. | ||
1684 | |||
1685 | For more details on NFS O_DIRECT, see fs/nfs/direct.c. | ||
1686 | |||
1687 | If unsure, say N. This reduces the size of the NFS client, and | ||
1688 | causes open() to return EINVAL if a file residing in NFS is | ||
1689 | opened with the O_DIRECT flag. | ||
1690 | |||
1691 | config NFSD | 1667 | config NFSD |
1692 | tristate "NFS server support" | 1668 | tristate "NFS server support" |
1693 | depends on INET | 1669 | depends on INET |
1694 | select LOCKD | 1670 | select LOCKD |
1695 | select SUNRPC | 1671 | select SUNRPC |
1696 | select EXPORTFS | 1672 | select EXPORTFS |
1697 | select NFSD_V2_ACL if NFSD_V3_ACL | ||
1698 | select NFS_ACL_SUPPORT if NFSD_V2_ACL | 1673 | select NFS_ACL_SUPPORT if NFSD_V2_ACL |
1699 | select NFSD_TCP if NFSD_V4 | 1674 | help |
1700 | select CRYPTO_MD5 if NFSD_V4 | 1675 | Choose Y here if you want to allow other computers to access |
1701 | select CRYPTO if NFSD_V4 | 1676 | files residing on this system using Sun's Network File System |
1702 | select FS_POSIX_ACL if NFSD_V4 | 1677 | protocol. To compile the NFS server support as a module, |
1703 | select PROC_FS if NFSD_V4 | 1678 | choose M here: the module will be called nfsd. |
1704 | select PROC_FS if SUNRPC_GSS | 1679 | |
1705 | help | 1680 | You may choose to use a user-space NFS server instead, in which |
1706 | If you want your Linux box to act as an NFS *server*, so that other | 1681 | case you can choose N here. |
1707 | computers on your local network which support NFS can access certain | 1682 | |
1708 | directories on your box transparently, you have two options: you can | 1683 | To export local file systems using NFS, you also need to install |
1709 | use the self-contained user space program nfsd, in which case you | 1684 | user space programs which can be found in the Linux nfs-utils |
1710 | should say N here, or you can say Y and use the kernel based NFS | 1685 | package, available from http://linux-nfs.org/. More detail about |
1711 | server. The advantage of the kernel based solution is that it is | 1686 | the Linux NFS server implementation is available via the |
1712 | faster. | 1687 | exports(5) man page. |
1713 | 1688 | ||
1714 | In either case, you will need support software; the respective | 1689 | Below you can choose which versions of the NFS protocol are |
1715 | locations are given in the file <file:Documentation/Changes> in the | 1690 | available to clients mounting the NFS server on this system. |
1716 | NFS section. | 1691 | Support for NFS version 2 (RFC 1094) is always available when |
1717 | 1692 | CONFIG_NFSD is selected. | |
1718 | If you say Y here, you will get support for version 2 of the NFS | 1693 | |
1719 | protocol (NFSv2). If you also want NFSv3, say Y to the next question | 1694 | If unsure, say N. |
1720 | as well. | ||
1721 | |||
1722 | Please read the NFS-HOWTO, available from | ||
1723 | <http://www.tldp.org/docs.html#howto>. | ||
1724 | |||
1725 | To compile the NFS server support as a module, choose M here: the | ||
1726 | module will be called nfsd. If unsure, say N. | ||
1727 | 1695 | ||
1728 | config NFSD_V2_ACL | 1696 | config NFSD_V2_ACL |
1729 | bool | 1697 | bool |
1730 | depends on NFSD | 1698 | depends on NFSD |
1731 | 1699 | ||
1732 | config NFSD_V3 | 1700 | config NFSD_V3 |
1733 | bool "Provide NFSv3 server support" | 1701 | bool "NFS server support for NFS version 3" |
1734 | depends on NFSD | 1702 | depends on NFSD |
1735 | help | 1703 | help |
1736 | If you would like to include the NFSv3 server as well as the NFSv2 | 1704 | This option enables support in your system's NFS server for |
1737 | server, say Y here. If unsure, say Y. | 1705 | version 3 of the NFS protocol (RFC 1813). |
1706 | |||
1707 | If unsure, say Y. | ||
1738 | 1708 | ||
1739 | config NFSD_V3_ACL | 1709 | config NFSD_V3_ACL |
1740 | bool "Provide server support for the NFSv3 ACL protocol extension" | 1710 | bool "NFS server support for the NFSv3 ACL protocol extension" |
1741 | depends on NFSD_V3 | 1711 | depends on NFSD_V3 |
1712 | select NFSD_V2_ACL | ||
1742 | help | 1713 | help |
1743 | Implement the NFSv3 ACL protocol extension for manipulating POSIX | 1714 | Solaris NFS servers support an auxiliary NFSv3 ACL protocol that |
1744 | Access Control Lists on exported file systems. NFS clients should | 1715 | never became an official part of the NFS version 3 protocol. |
1745 | be compiled with the NFSv3 ACL protocol extension; see the | 1716 | This protocol extension allows applications on NFS clients to |
1746 | CONFIG_NFS_V3_ACL option. If unsure, say N. | 1717 | manipulate POSIX Access Control Lists on files residing on NFS |
1718 | servers. NFS servers enforce POSIX ACLs on local files whether | ||
1719 | this protocol is available or not. | ||
1720 | |||
1721 | This option enables support in your system's NFS server for the | ||
1722 | NFSv3 ACL protocol extension allowing NFS clients to manipulate | ||
1723 | POSIX ACLs on files exported by your system's NFS server. NFS | ||
1724 | clients which support the Solaris NFSv3 ACL protocol can then | ||
1725 | access and modify ACLs on your NFS server. | ||
1726 | |||
1727 | To store ACLs on your NFS server, you also need to enable ACL- | ||
1728 | related CONFIG options for your local file systems of choice. | ||
1729 | |||
1730 | If unsure, say N. | ||
1747 | 1731 | ||
1748 | config NFSD_V4 | 1732 | config NFSD_V4 |
1749 | bool "Provide NFSv4 server support (EXPERIMENTAL)" | 1733 | bool "NFS server support for NFS version 4 (EXPERIMENTAL)" |
1750 | depends on NFSD && NFSD_V3 && EXPERIMENTAL | 1734 | depends on NFSD && PROC_FS && EXPERIMENTAL |
1735 | select NFSD_V3 | ||
1736 | select FS_POSIX_ACL | ||
1751 | select RPCSEC_GSS_KRB5 | 1737 | select RPCSEC_GSS_KRB5 |
1752 | help | 1738 | help |
1753 | If you would like to include the NFSv4 server as well as the NFSv2 | 1739 | This option enables support in your system's NFS server for |
1754 | and NFSv3 servers, say Y here. This feature is experimental, and | 1740 | version 4 of the NFS protocol (RFC 3530). |
1755 | should only be used if you are interested in helping to test NFSv4. | ||
1756 | If unsure, say N. | ||
1757 | 1741 | ||
1758 | config NFSD_TCP | 1742 | To export files using NFSv4, you need to install additional user |
1759 | bool "Provide NFS server over TCP support" | 1743 | space programs which can be found in the Linux nfs-utils package, |
1760 | depends on NFSD | 1744 | available from http://linux-nfs.org/. |
1761 | default y | 1745 | |
1762 | help | 1746 | If unsure, say N. |
1763 | If you want your NFS server to support TCP connections, say Y here. | ||
1764 | TCP connections usually perform better than the default UDP when | ||
1765 | the network is lossy or congested. If unsure, say Y. | ||
1766 | 1747 | ||
1767 | config ROOT_NFS | 1748 | config ROOT_NFS |
1768 | bool "Root file system on NFS" | 1749 | bool "Root file system on NFS" |
@@ -1808,15 +1789,33 @@ config SUNRPC_XPRT_RDMA | |||
1808 | tristate | 1789 | tristate |
1809 | depends on SUNRPC && INFINIBAND && EXPERIMENTAL | 1790 | depends on SUNRPC && INFINIBAND && EXPERIMENTAL |
1810 | default SUNRPC && INFINIBAND | 1791 | default SUNRPC && INFINIBAND |
1792 | help | ||
1793 | This option enables an RPC client transport capability that | ||
1794 | allows the NFS client to mount servers via an RDMA-enabled | ||
1795 | transport. | ||
1796 | |||
1797 | To compile RPC client RDMA transport support as a module, | ||
1798 | choose M here: the module will be called xprtrdma. | ||
1799 | |||
1800 | If unsure, say N. | ||
1811 | 1801 | ||
1812 | config SUNRPC_BIND34 | 1802 | config SUNRPC_BIND34 |
1813 | bool "Support for rpcbind versions 3 & 4 (EXPERIMENTAL)" | 1803 | bool "Support for rpcbind versions 3 & 4 (EXPERIMENTAL)" |
1814 | depends on SUNRPC && EXPERIMENTAL | 1804 | depends on SUNRPC && EXPERIMENTAL |
1805 | default n | ||
1815 | help | 1806 | help |
1816 | Provides kernel support for querying rpcbind servers via versions 3 | 1807 | RPC requests over IPv6 networks require support for larger |
1817 | and 4 of the rpcbind protocol. The kernel automatically falls back | 1808 | addresses when performing an RPC bind. Sun added support for |
1818 | to version 2 if a remote rpcbind service does not support versions | 1809 | IPv6 addressing by creating two new versions of the rpcbind |
1819 | 3 or 4. | 1810 | protocol (RFC 1833). |
1811 | |||
1812 | This option enables support in the kernel RPC client for | ||
1813 | querying rpcbind servers via versions 3 and 4 of the rpcbind | ||
1814 | protocol. The kernel automatically falls back to version 2 | ||
1815 | if a remote rpcbind service does not support versions 3 or 4. | ||
1816 | By themselves, these new versions do not provide support for | ||
1817 | RPC over IPv6, but the new protocol versions are necessary to | ||
1818 | support it. | ||
1820 | 1819 | ||
1821 | If unsure, say N to get traditional behavior (version 2 rpcbind | 1820 | If unsure, say N to get traditional behavior (version 2 rpcbind |
1822 | requests only). | 1821 | requests only). |
@@ -1830,12 +1829,13 @@ config RPCSEC_GSS_KRB5 | |||
1830 | select CRYPTO_DES | 1829 | select CRYPTO_DES |
1831 | select CRYPTO_CBC | 1830 | select CRYPTO_CBC |
1832 | help | 1831 | help |
1833 | Provides for secure RPC calls by means of a gss-api | 1832 | Choose Y here to enable Secure RPC using the Kerberos version 5 |
1834 | mechanism based on Kerberos V5. This is required for | 1833 | GSS-API mechanism (RFC 1964). |
1835 | NFSv4. | ||
1836 | 1834 | ||
1837 | Note: Requires an auxiliary userspace daemon which may be found on | 1835 | Secure RPC calls with Kerberos require an auxiliary user-space |
1838 | http://www.citi.umich.edu/projects/nfsv4/ | 1836 | daemon which may be found in the Linux nfs-utils package |
1837 | available from http://linux-nfs.org/. In addition, user-space | ||
1838 | Kerberos support should be installed. | ||
1839 | 1839 | ||
1840 | If unsure, say N. | 1840 | If unsure, say N. |
1841 | 1841 | ||
@@ -1849,11 +1849,12 @@ config RPCSEC_GSS_SPKM3 | |||
1849 | select CRYPTO_CAST5 | 1849 | select CRYPTO_CAST5 |
1850 | select CRYPTO_CBC | 1850 | select CRYPTO_CBC |
1851 | help | 1851 | help |
1852 | Provides for secure RPC calls by means of a gss-api | 1852 | Choose Y here to enable Secure RPC using the SPKM3 public key |
1853 | mechanism based on the SPKM3 public-key mechanism. | 1853 | GSS-API mechansim (RFC 2025). |
1854 | 1854 | ||
1855 | Note: Requires an auxiliary userspace daemon which may be found on | 1855 | Secure RPC calls with SPKM3 require an auxiliary userspace |
1856 | http://www.citi.umich.edu/projects/nfsv4/ | 1856 | daemon which may be found in the Linux nfs-utils package |
1857 | available from http://linux-nfs.org/. | ||
1857 | 1858 | ||
1858 | If unsure, say N. | 1859 | If unsure, say N. |
1859 | 1860 | ||
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index b6b74a60e1eb..40b16f23e49a 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c | |||
@@ -155,8 +155,6 @@ static void nlmclnt_release_lockargs(struct nlm_rqst *req) | |||
155 | int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl) | 155 | int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl) |
156 | { | 156 | { |
157 | struct nlm_rqst *call; | 157 | struct nlm_rqst *call; |
158 | sigset_t oldset; | ||
159 | unsigned long flags; | ||
160 | int status; | 158 | int status; |
161 | 159 | ||
162 | nlm_get_host(host); | 160 | nlm_get_host(host); |
@@ -168,22 +166,6 @@ int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl) | |||
168 | /* Set up the argument struct */ | 166 | /* Set up the argument struct */ |
169 | nlmclnt_setlockargs(call, fl); | 167 | nlmclnt_setlockargs(call, fl); |
170 | 168 | ||
171 | /* Keep the old signal mask */ | ||
172 | spin_lock_irqsave(¤t->sighand->siglock, flags); | ||
173 | oldset = current->blocked; | ||
174 | |||
175 | /* If we're cleaning up locks because the process is exiting, | ||
176 | * perform the RPC call asynchronously. */ | ||
177 | if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) | ||
178 | && fl->fl_type == F_UNLCK | ||
179 | && (current->flags & PF_EXITING)) { | ||
180 | sigfillset(¤t->blocked); /* Mask all signals */ | ||
181 | recalc_sigpending(); | ||
182 | |||
183 | call->a_flags = RPC_TASK_ASYNC; | ||
184 | } | ||
185 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | ||
186 | |||
187 | if (IS_SETLK(cmd) || IS_SETLKW(cmd)) { | 169 | if (IS_SETLK(cmd) || IS_SETLKW(cmd)) { |
188 | if (fl->fl_type != F_UNLCK) { | 170 | if (fl->fl_type != F_UNLCK) { |
189 | call->a_args.block = IS_SETLKW(cmd) ? 1 : 0; | 171 | call->a_args.block = IS_SETLKW(cmd) ? 1 : 0; |
@@ -198,11 +180,6 @@ int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl) | |||
198 | fl->fl_ops->fl_release_private(fl); | 180 | fl->fl_ops->fl_release_private(fl); |
199 | fl->fl_ops = NULL; | 181 | fl->fl_ops = NULL; |
200 | 182 | ||
201 | spin_lock_irqsave(¤t->sighand->siglock, flags); | ||
202 | current->blocked = oldset; | ||
203 | recalc_sigpending(); | ||
204 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | ||
205 | |||
206 | dprintk("lockd: clnt proc returns %d\n", status); | 183 | dprintk("lockd: clnt proc returns %d\n", status); |
207 | return status; | 184 | return status; |
208 | } | 185 | } |
@@ -221,6 +198,7 @@ struct nlm_rqst *nlm_alloc_call(struct nlm_host *host) | |||
221 | for(;;) { | 198 | for(;;) { |
222 | call = kzalloc(sizeof(*call), GFP_KERNEL); | 199 | call = kzalloc(sizeof(*call), GFP_KERNEL); |
223 | if (call != NULL) { | 200 | if (call != NULL) { |
201 | atomic_set(&call->a_count, 1); | ||
224 | locks_init_lock(&call->a_args.lock.fl); | 202 | locks_init_lock(&call->a_args.lock.fl); |
225 | locks_init_lock(&call->a_res.lock.fl); | 203 | locks_init_lock(&call->a_res.lock.fl); |
226 | call->a_host = host; | 204 | call->a_host = host; |
@@ -237,6 +215,8 @@ struct nlm_rqst *nlm_alloc_call(struct nlm_host *host) | |||
237 | 215 | ||
238 | void nlm_release_call(struct nlm_rqst *call) | 216 | void nlm_release_call(struct nlm_rqst *call) |
239 | { | 217 | { |
218 | if (!atomic_dec_and_test(&call->a_count)) | ||
219 | return; | ||
240 | nlm_release_host(call->a_host); | 220 | nlm_release_host(call->a_host); |
241 | nlmclnt_release_lockargs(call); | 221 | nlmclnt_release_lockargs(call); |
242 | kfree(call); | 222 | kfree(call); |
@@ -267,7 +247,7 @@ static int nlm_wait_on_grace(wait_queue_head_t *queue) | |||
267 | * Generic NLM call | 247 | * Generic NLM call |
268 | */ | 248 | */ |
269 | static int | 249 | static int |
270 | nlmclnt_call(struct nlm_rqst *req, u32 proc) | 250 | nlmclnt_call(struct rpc_cred *cred, struct nlm_rqst *req, u32 proc) |
271 | { | 251 | { |
272 | struct nlm_host *host = req->a_host; | 252 | struct nlm_host *host = req->a_host; |
273 | struct rpc_clnt *clnt; | 253 | struct rpc_clnt *clnt; |
@@ -276,6 +256,7 @@ nlmclnt_call(struct nlm_rqst *req, u32 proc) | |||
276 | struct rpc_message msg = { | 256 | struct rpc_message msg = { |
277 | .rpc_argp = argp, | 257 | .rpc_argp = argp, |
278 | .rpc_resp = resp, | 258 | .rpc_resp = resp, |
259 | .rpc_cred = cred, | ||
279 | }; | 260 | }; |
280 | int status; | 261 | int status; |
281 | 262 | ||
@@ -343,10 +324,16 @@ in_grace_period: | |||
343 | /* | 324 | /* |
344 | * Generic NLM call, async version. | 325 | * Generic NLM call, async version. |
345 | */ | 326 | */ |
346 | static int __nlm_async_call(struct nlm_rqst *req, u32 proc, struct rpc_message *msg, const struct rpc_call_ops *tk_ops) | 327 | static struct rpc_task *__nlm_async_call(struct nlm_rqst *req, u32 proc, struct rpc_message *msg, const struct rpc_call_ops *tk_ops) |
347 | { | 328 | { |
348 | struct nlm_host *host = req->a_host; | 329 | struct nlm_host *host = req->a_host; |
349 | struct rpc_clnt *clnt; | 330 | struct rpc_clnt *clnt; |
331 | struct rpc_task_setup task_setup_data = { | ||
332 | .rpc_message = msg, | ||
333 | .callback_ops = tk_ops, | ||
334 | .callback_data = req, | ||
335 | .flags = RPC_TASK_ASYNC, | ||
336 | }; | ||
350 | 337 | ||
351 | dprintk("lockd: call procedure %d on %s (async)\n", | 338 | dprintk("lockd: call procedure %d on %s (async)\n", |
352 | (int)proc, host->h_name); | 339 | (int)proc, host->h_name); |
@@ -356,21 +343,36 @@ static int __nlm_async_call(struct nlm_rqst *req, u32 proc, struct rpc_message * | |||
356 | if (clnt == NULL) | 343 | if (clnt == NULL) |
357 | goto out_err; | 344 | goto out_err; |
358 | msg->rpc_proc = &clnt->cl_procinfo[proc]; | 345 | msg->rpc_proc = &clnt->cl_procinfo[proc]; |
346 | task_setup_data.rpc_client = clnt; | ||
359 | 347 | ||
360 | /* bootstrap and kick off the async RPC call */ | 348 | /* bootstrap and kick off the async RPC call */ |
361 | return rpc_call_async(clnt, msg, RPC_TASK_ASYNC, tk_ops, req); | 349 | return rpc_run_task(&task_setup_data); |
362 | out_err: | 350 | out_err: |
363 | tk_ops->rpc_release(req); | 351 | tk_ops->rpc_release(req); |
364 | return -ENOLCK; | 352 | return ERR_PTR(-ENOLCK); |
365 | } | 353 | } |
366 | 354 | ||
355 | static int nlm_do_async_call(struct nlm_rqst *req, u32 proc, struct rpc_message *msg, const struct rpc_call_ops *tk_ops) | ||
356 | { | ||
357 | struct rpc_task *task; | ||
358 | |||
359 | task = __nlm_async_call(req, proc, msg, tk_ops); | ||
360 | if (IS_ERR(task)) | ||
361 | return PTR_ERR(task); | ||
362 | rpc_put_task(task); | ||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | /* | ||
367 | * NLM asynchronous call. | ||
368 | */ | ||
367 | int nlm_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) | 369 | int nlm_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) |
368 | { | 370 | { |
369 | struct rpc_message msg = { | 371 | struct rpc_message msg = { |
370 | .rpc_argp = &req->a_args, | 372 | .rpc_argp = &req->a_args, |
371 | .rpc_resp = &req->a_res, | 373 | .rpc_resp = &req->a_res, |
372 | }; | 374 | }; |
373 | return __nlm_async_call(req, proc, &msg, tk_ops); | 375 | return nlm_do_async_call(req, proc, &msg, tk_ops); |
374 | } | 376 | } |
375 | 377 | ||
376 | int nlm_async_reply(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) | 378 | int nlm_async_reply(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) |
@@ -378,7 +380,33 @@ int nlm_async_reply(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *t | |||
378 | struct rpc_message msg = { | 380 | struct rpc_message msg = { |
379 | .rpc_argp = &req->a_res, | 381 | .rpc_argp = &req->a_res, |
380 | }; | 382 | }; |
381 | return __nlm_async_call(req, proc, &msg, tk_ops); | 383 | return nlm_do_async_call(req, proc, &msg, tk_ops); |
384 | } | ||
385 | |||
386 | /* | ||
387 | * NLM client asynchronous call. | ||
388 | * | ||
389 | * Note that although the calls are asynchronous, and are therefore | ||
390 | * guaranteed to complete, we still always attempt to wait for | ||
391 | * completion in order to be able to correctly track the lock | ||
392 | * state. | ||
393 | */ | ||
394 | static int nlmclnt_async_call(struct rpc_cred *cred, struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) | ||
395 | { | ||
396 | struct rpc_message msg = { | ||
397 | .rpc_argp = &req->a_args, | ||
398 | .rpc_resp = &req->a_res, | ||
399 | .rpc_cred = cred, | ||
400 | }; | ||
401 | struct rpc_task *task; | ||
402 | int err; | ||
403 | |||
404 | task = __nlm_async_call(req, proc, &msg, tk_ops); | ||
405 | if (IS_ERR(task)) | ||
406 | return PTR_ERR(task); | ||
407 | err = rpc_wait_for_completion_task(task); | ||
408 | rpc_put_task(task); | ||
409 | return err; | ||
382 | } | 410 | } |
383 | 411 | ||
384 | /* | 412 | /* |
@@ -389,7 +417,7 @@ nlmclnt_test(struct nlm_rqst *req, struct file_lock *fl) | |||
389 | { | 417 | { |
390 | int status; | 418 | int status; |
391 | 419 | ||
392 | status = nlmclnt_call(req, NLMPROC_TEST); | 420 | status = nlmclnt_call(nfs_file_cred(fl->fl_file), req, NLMPROC_TEST); |
393 | if (status < 0) | 421 | if (status < 0) |
394 | goto out; | 422 | goto out; |
395 | 423 | ||
@@ -480,10 +508,12 @@ static int do_vfs_lock(struct file_lock *fl) | |||
480 | static int | 508 | static int |
481 | nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) | 509 | nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) |
482 | { | 510 | { |
511 | struct rpc_cred *cred = nfs_file_cred(fl->fl_file); | ||
483 | struct nlm_host *host = req->a_host; | 512 | struct nlm_host *host = req->a_host; |
484 | struct nlm_res *resp = &req->a_res; | 513 | struct nlm_res *resp = &req->a_res; |
485 | struct nlm_wait *block = NULL; | 514 | struct nlm_wait *block = NULL; |
486 | unsigned char fl_flags = fl->fl_flags; | 515 | unsigned char fl_flags = fl->fl_flags; |
516 | unsigned char fl_type; | ||
487 | int status = -ENOLCK; | 517 | int status = -ENOLCK; |
488 | 518 | ||
489 | if (nsm_monitor(host) < 0) { | 519 | if (nsm_monitor(host) < 0) { |
@@ -493,18 +523,22 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) | |||
493 | } | 523 | } |
494 | fl->fl_flags |= FL_ACCESS; | 524 | fl->fl_flags |= FL_ACCESS; |
495 | status = do_vfs_lock(fl); | 525 | status = do_vfs_lock(fl); |
526 | fl->fl_flags = fl_flags; | ||
496 | if (status < 0) | 527 | if (status < 0) |
497 | goto out; | 528 | goto out; |
498 | 529 | ||
499 | block = nlmclnt_prepare_block(host, fl); | 530 | block = nlmclnt_prepare_block(host, fl); |
500 | again: | 531 | again: |
532 | /* | ||
533 | * Initialise resp->status to a valid non-zero value, | ||
534 | * since 0 == nlm_lck_granted | ||
535 | */ | ||
536 | resp->status = nlm_lck_blocked; | ||
501 | for(;;) { | 537 | for(;;) { |
502 | /* Reboot protection */ | 538 | /* Reboot protection */ |
503 | fl->fl_u.nfs_fl.state = host->h_state; | 539 | fl->fl_u.nfs_fl.state = host->h_state; |
504 | status = nlmclnt_call(req, NLMPROC_LOCK); | 540 | status = nlmclnt_call(cred, req, NLMPROC_LOCK); |
505 | if (status < 0) | 541 | if (status < 0) |
506 | goto out_unblock; | ||
507 | if (!req->a_args.block) | ||
508 | break; | 542 | break; |
509 | /* Did a reclaimer thread notify us of a server reboot? */ | 543 | /* Did a reclaimer thread notify us of a server reboot? */ |
510 | if (resp->status == nlm_lck_denied_grace_period) | 544 | if (resp->status == nlm_lck_denied_grace_period) |
@@ -513,15 +547,22 @@ again: | |||
513 | break; | 547 | break; |
514 | /* Wait on an NLM blocking lock */ | 548 | /* Wait on an NLM blocking lock */ |
515 | status = nlmclnt_block(block, req, NLMCLNT_POLL_TIMEOUT); | 549 | status = nlmclnt_block(block, req, NLMCLNT_POLL_TIMEOUT); |
516 | /* if we were interrupted. Send a CANCEL request to the server | ||
517 | * and exit | ||
518 | */ | ||
519 | if (status < 0) | 550 | if (status < 0) |
520 | goto out_unblock; | 551 | break; |
521 | if (resp->status != nlm_lck_blocked) | 552 | if (resp->status != nlm_lck_blocked) |
522 | break; | 553 | break; |
523 | } | 554 | } |
524 | 555 | ||
556 | /* if we were interrupted while blocking, then cancel the lock request | ||
557 | * and exit | ||
558 | */ | ||
559 | if (resp->status == nlm_lck_blocked) { | ||
560 | if (!req->a_args.block) | ||
561 | goto out_unlock; | ||
562 | if (nlmclnt_cancel(host, req->a_args.block, fl) == 0) | ||
563 | goto out_unblock; | ||
564 | } | ||
565 | |||
525 | if (resp->status == nlm_granted) { | 566 | if (resp->status == nlm_granted) { |
526 | down_read(&host->h_rwsem); | 567 | down_read(&host->h_rwsem); |
527 | /* Check whether or not the server has rebooted */ | 568 | /* Check whether or not the server has rebooted */ |
@@ -530,20 +571,34 @@ again: | |||
530 | goto again; | 571 | goto again; |
531 | } | 572 | } |
532 | /* Ensure the resulting lock will get added to granted list */ | 573 | /* Ensure the resulting lock will get added to granted list */ |
533 | fl->fl_flags = fl_flags | FL_SLEEP; | 574 | fl->fl_flags |= FL_SLEEP; |
534 | if (do_vfs_lock(fl) < 0) | 575 | if (do_vfs_lock(fl) < 0) |
535 | printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__); | 576 | printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__); |
536 | up_read(&host->h_rwsem); | 577 | up_read(&host->h_rwsem); |
578 | fl->fl_flags = fl_flags; | ||
579 | status = 0; | ||
537 | } | 580 | } |
581 | if (status < 0) | ||
582 | goto out_unlock; | ||
538 | status = nlm_stat_to_errno(resp->status); | 583 | status = nlm_stat_to_errno(resp->status); |
539 | out_unblock: | 584 | out_unblock: |
540 | nlmclnt_finish_block(block); | 585 | nlmclnt_finish_block(block); |
541 | /* Cancel the blocked request if it is still pending */ | ||
542 | if (resp->status == nlm_lck_blocked) | ||
543 | nlmclnt_cancel(host, req->a_args.block, fl); | ||
544 | out: | 586 | out: |
545 | nlm_release_call(req); | 587 | nlm_release_call(req); |
588 | return status; | ||
589 | out_unlock: | ||
590 | /* Fatal error: ensure that we remove the lock altogether */ | ||
591 | dprintk("lockd: lock attempt ended in fatal error.\n" | ||
592 | " Attempting to unlock.\n"); | ||
593 | nlmclnt_finish_block(block); | ||
594 | fl_type = fl->fl_type; | ||
595 | fl->fl_type = F_UNLCK; | ||
596 | down_read(&host->h_rwsem); | ||
597 | do_vfs_lock(fl); | ||
598 | up_read(&host->h_rwsem); | ||
599 | fl->fl_type = fl_type; | ||
546 | fl->fl_flags = fl_flags; | 600 | fl->fl_flags = fl_flags; |
601 | nlmclnt_async_call(cred, req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops); | ||
547 | return status; | 602 | return status; |
548 | } | 603 | } |
549 | 604 | ||
@@ -567,8 +622,8 @@ nlmclnt_reclaim(struct nlm_host *host, struct file_lock *fl) | |||
567 | nlmclnt_setlockargs(req, fl); | 622 | nlmclnt_setlockargs(req, fl); |
568 | req->a_args.reclaim = 1; | 623 | req->a_args.reclaim = 1; |
569 | 624 | ||
570 | if ((status = nlmclnt_call(req, NLMPROC_LOCK)) >= 0 | 625 | status = nlmclnt_call(nfs_file_cred(fl->fl_file), req, NLMPROC_LOCK); |
571 | && req->a_res.status == nlm_granted) | 626 | if (status >= 0 && req->a_res.status == nlm_granted) |
572 | return 0; | 627 | return 0; |
573 | 628 | ||
574 | printk(KERN_WARNING "lockd: failed to reclaim lock for pid %d " | 629 | printk(KERN_WARNING "lockd: failed to reclaim lock for pid %d " |
@@ -598,7 +653,8 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) | |||
598 | { | 653 | { |
599 | struct nlm_host *host = req->a_host; | 654 | struct nlm_host *host = req->a_host; |
600 | struct nlm_res *resp = &req->a_res; | 655 | struct nlm_res *resp = &req->a_res; |
601 | int status = 0; | 656 | int status; |
657 | unsigned char fl_flags = fl->fl_flags; | ||
602 | 658 | ||
603 | /* | 659 | /* |
604 | * Note: the server is supposed to either grant us the unlock | 660 | * Note: the server is supposed to either grant us the unlock |
@@ -607,16 +663,17 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) | |||
607 | */ | 663 | */ |
608 | fl->fl_flags |= FL_EXISTS; | 664 | fl->fl_flags |= FL_EXISTS; |
609 | down_read(&host->h_rwsem); | 665 | down_read(&host->h_rwsem); |
610 | if (do_vfs_lock(fl) == -ENOENT) { | 666 | status = do_vfs_lock(fl); |
611 | up_read(&host->h_rwsem); | 667 | up_read(&host->h_rwsem); |
668 | fl->fl_flags = fl_flags; | ||
669 | if (status == -ENOENT) { | ||
670 | status = 0; | ||
612 | goto out; | 671 | goto out; |
613 | } | 672 | } |
614 | up_read(&host->h_rwsem); | ||
615 | |||
616 | if (req->a_flags & RPC_TASK_ASYNC) | ||
617 | return nlm_async_call(req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops); | ||
618 | 673 | ||
619 | status = nlmclnt_call(req, NLMPROC_UNLOCK); | 674 | atomic_inc(&req->a_count); |
675 | status = nlmclnt_async_call(nfs_file_cred(fl->fl_file), req, | ||
676 | NLMPROC_UNLOCK, &nlmclnt_unlock_ops); | ||
620 | if (status < 0) | 677 | if (status < 0) |
621 | goto out; | 678 | goto out; |
622 | 679 | ||
@@ -671,16 +728,10 @@ static const struct rpc_call_ops nlmclnt_unlock_ops = { | |||
671 | static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl) | 728 | static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl) |
672 | { | 729 | { |
673 | struct nlm_rqst *req; | 730 | struct nlm_rqst *req; |
674 | unsigned long flags; | 731 | int status; |
675 | sigset_t oldset; | ||
676 | int status; | ||
677 | 732 | ||
678 | /* Block all signals while setting up call */ | 733 | dprintk("lockd: blocking lock attempt was interrupted by a signal.\n" |
679 | spin_lock_irqsave(¤t->sighand->siglock, flags); | 734 | " Attempting to cancel lock.\n"); |
680 | oldset = current->blocked; | ||
681 | sigfillset(¤t->blocked); | ||
682 | recalc_sigpending(); | ||
683 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | ||
684 | 735 | ||
685 | req = nlm_alloc_call(nlm_get_host(host)); | 736 | req = nlm_alloc_call(nlm_get_host(host)); |
686 | if (!req) | 737 | if (!req) |
@@ -690,13 +741,12 @@ static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl | |||
690 | nlmclnt_setlockargs(req, fl); | 741 | nlmclnt_setlockargs(req, fl); |
691 | req->a_args.block = block; | 742 | req->a_args.block = block; |
692 | 743 | ||
693 | status = nlm_async_call(req, NLMPROC_CANCEL, &nlmclnt_cancel_ops); | 744 | atomic_inc(&req->a_count); |
694 | 745 | status = nlmclnt_async_call(nfs_file_cred(fl->fl_file), req, | |
695 | spin_lock_irqsave(¤t->sighand->siglock, flags); | 746 | NLMPROC_CANCEL, &nlmclnt_cancel_ops); |
696 | current->blocked = oldset; | 747 | if (status == 0 && req->a_res.status == nlm_lck_denied) |
697 | recalc_sigpending(); | 748 | status = -ENOLCK; |
698 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | 749 | nlm_release_call(req); |
699 | |||
700 | return status; | 750 | return status; |
701 | } | 751 | } |
702 | 752 | ||
diff --git a/fs/lockd/host.c b/fs/lockd/host.c index f1ef49fff118..a17664c7eacc 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c | |||
@@ -19,12 +19,11 @@ | |||
19 | 19 | ||
20 | 20 | ||
21 | #define NLMDBG_FACILITY NLMDBG_HOSTCACHE | 21 | #define NLMDBG_FACILITY NLMDBG_HOSTCACHE |
22 | #define NLM_HOST_MAX 64 | ||
23 | #define NLM_HOST_NRHASH 32 | 22 | #define NLM_HOST_NRHASH 32 |
24 | #define NLM_ADDRHASH(addr) (ntohl(addr) & (NLM_HOST_NRHASH-1)) | 23 | #define NLM_ADDRHASH(addr) (ntohl(addr) & (NLM_HOST_NRHASH-1)) |
25 | #define NLM_HOST_REBIND (60 * HZ) | 24 | #define NLM_HOST_REBIND (60 * HZ) |
26 | #define NLM_HOST_EXPIRE ((nrhosts > NLM_HOST_MAX)? 300 * HZ : 120 * HZ) | 25 | #define NLM_HOST_EXPIRE (300 * HZ) |
27 | #define NLM_HOST_COLLECT ((nrhosts > NLM_HOST_MAX)? 120 * HZ : 60 * HZ) | 26 | #define NLM_HOST_COLLECT (120 * HZ) |
28 | 27 | ||
29 | static struct hlist_head nlm_hosts[NLM_HOST_NRHASH]; | 28 | static struct hlist_head nlm_hosts[NLM_HOST_NRHASH]; |
30 | static unsigned long next_gc; | 29 | static unsigned long next_gc; |
@@ -42,11 +41,12 @@ static struct nsm_handle * nsm_find(const struct sockaddr_in *sin, | |||
42 | /* | 41 | /* |
43 | * Common host lookup routine for server & client | 42 | * Common host lookup routine for server & client |
44 | */ | 43 | */ |
45 | static struct nlm_host * | 44 | static struct nlm_host *nlm_lookup_host(int server, |
46 | nlm_lookup_host(int server, const struct sockaddr_in *sin, | 45 | const struct sockaddr_in *sin, |
47 | int proto, int version, const char *hostname, | 46 | int proto, u32 version, |
48 | unsigned int hostname_len, | 47 | const char *hostname, |
49 | const struct sockaddr_in *ssin) | 48 | unsigned int hostname_len, |
49 | const struct sockaddr_in *ssin) | ||
50 | { | 50 | { |
51 | struct hlist_head *chain; | 51 | struct hlist_head *chain; |
52 | struct hlist_node *pos; | 52 | struct hlist_node *pos; |
@@ -55,7 +55,7 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin, | |||
55 | int hash; | 55 | int hash; |
56 | 56 | ||
57 | dprintk("lockd: nlm_lookup_host("NIPQUAD_FMT"->"NIPQUAD_FMT | 57 | dprintk("lockd: nlm_lookup_host("NIPQUAD_FMT"->"NIPQUAD_FMT |
58 | ", p=%d, v=%d, my role=%s, name=%.*s)\n", | 58 | ", p=%d, v=%u, my role=%s, name=%.*s)\n", |
59 | NIPQUAD(ssin->sin_addr.s_addr), | 59 | NIPQUAD(ssin->sin_addr.s_addr), |
60 | NIPQUAD(sin->sin_addr.s_addr), proto, version, | 60 | NIPQUAD(sin->sin_addr.s_addr), proto, version, |
61 | server? "server" : "client", | 61 | server? "server" : "client", |
@@ -142,9 +142,7 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin, | |||
142 | INIT_LIST_HEAD(&host->h_granted); | 142 | INIT_LIST_HEAD(&host->h_granted); |
143 | INIT_LIST_HEAD(&host->h_reclaim); | 143 | INIT_LIST_HEAD(&host->h_reclaim); |
144 | 144 | ||
145 | if (++nrhosts > NLM_HOST_MAX) | 145 | nrhosts++; |
146 | next_gc = 0; | ||
147 | |||
148 | out: | 146 | out: |
149 | mutex_unlock(&nlm_host_mutex); | 147 | mutex_unlock(&nlm_host_mutex); |
150 | return host; | 148 | return host; |
@@ -175,9 +173,10 @@ nlm_destroy_host(struct nlm_host *host) | |||
175 | /* | 173 | /* |
176 | * Find an NLM server handle in the cache. If there is none, create it. | 174 | * Find an NLM server handle in the cache. If there is none, create it. |
177 | */ | 175 | */ |
178 | struct nlm_host * | 176 | struct nlm_host *nlmclnt_lookup_host(const struct sockaddr_in *sin, |
179 | nlmclnt_lookup_host(const struct sockaddr_in *sin, int proto, int version, | 177 | int proto, u32 version, |
180 | const char *hostname, unsigned int hostname_len) | 178 | const char *hostname, |
179 | unsigned int hostname_len) | ||
181 | { | 180 | { |
182 | struct sockaddr_in ssin = {0}; | 181 | struct sockaddr_in ssin = {0}; |
183 | 182 | ||
@@ -460,7 +459,7 @@ nlm_gc_hosts(void) | |||
460 | * Manage NSM handles | 459 | * Manage NSM handles |
461 | */ | 460 | */ |
462 | static LIST_HEAD(nsm_handles); | 461 | static LIST_HEAD(nsm_handles); |
463 | static DEFINE_MUTEX(nsm_mutex); | 462 | static DEFINE_SPINLOCK(nsm_lock); |
464 | 463 | ||
465 | static struct nsm_handle * | 464 | static struct nsm_handle * |
466 | __nsm_find(const struct sockaddr_in *sin, | 465 | __nsm_find(const struct sockaddr_in *sin, |
@@ -468,7 +467,7 @@ __nsm_find(const struct sockaddr_in *sin, | |||
468 | int create) | 467 | int create) |
469 | { | 468 | { |
470 | struct nsm_handle *nsm = NULL; | 469 | struct nsm_handle *nsm = NULL; |
471 | struct list_head *pos; | 470 | struct nsm_handle *pos; |
472 | 471 | ||
473 | if (!sin) | 472 | if (!sin) |
474 | return NULL; | 473 | return NULL; |
@@ -482,38 +481,43 @@ __nsm_find(const struct sockaddr_in *sin, | |||
482 | return NULL; | 481 | return NULL; |
483 | } | 482 | } |
484 | 483 | ||
485 | mutex_lock(&nsm_mutex); | 484 | retry: |
486 | list_for_each(pos, &nsm_handles) { | 485 | spin_lock(&nsm_lock); |
487 | nsm = list_entry(pos, struct nsm_handle, sm_link); | 486 | list_for_each_entry(pos, &nsm_handles, sm_link) { |
488 | 487 | ||
489 | if (hostname && nsm_use_hostnames) { | 488 | if (hostname && nsm_use_hostnames) { |
490 | if (strlen(nsm->sm_name) != hostname_len | 489 | if (strlen(pos->sm_name) != hostname_len |
491 | || memcmp(nsm->sm_name, hostname, hostname_len)) | 490 | || memcmp(pos->sm_name, hostname, hostname_len)) |
492 | continue; | 491 | continue; |
493 | } else if (!nlm_cmp_addr(&nsm->sm_addr, sin)) | 492 | } else if (!nlm_cmp_addr(&pos->sm_addr, sin)) |
494 | continue; | 493 | continue; |
495 | atomic_inc(&nsm->sm_count); | 494 | atomic_inc(&pos->sm_count); |
496 | goto out; | 495 | kfree(nsm); |
496 | nsm = pos; | ||
497 | goto found; | ||
497 | } | 498 | } |
498 | 499 | if (nsm) { | |
499 | if (!create) { | 500 | list_add(&nsm->sm_link, &nsm_handles); |
500 | nsm = NULL; | 501 | goto found; |
501 | goto out; | ||
502 | } | 502 | } |
503 | spin_unlock(&nsm_lock); | ||
504 | |||
505 | if (!create) | ||
506 | return NULL; | ||
503 | 507 | ||
504 | nsm = kzalloc(sizeof(*nsm) + hostname_len + 1, GFP_KERNEL); | 508 | nsm = kzalloc(sizeof(*nsm) + hostname_len + 1, GFP_KERNEL); |
505 | if (nsm != NULL) { | 509 | if (nsm == NULL) |
506 | nsm->sm_addr = *sin; | 510 | return NULL; |
507 | nsm->sm_name = (char *) (nsm + 1); | ||
508 | memcpy(nsm->sm_name, hostname, hostname_len); | ||
509 | nsm->sm_name[hostname_len] = '\0'; | ||
510 | atomic_set(&nsm->sm_count, 1); | ||
511 | 511 | ||
512 | list_add(&nsm->sm_link, &nsm_handles); | 512 | nsm->sm_addr = *sin; |
513 | } | 513 | nsm->sm_name = (char *) (nsm + 1); |
514 | memcpy(nsm->sm_name, hostname, hostname_len); | ||
515 | nsm->sm_name[hostname_len] = '\0'; | ||
516 | atomic_set(&nsm->sm_count, 1); | ||
517 | goto retry; | ||
514 | 518 | ||
515 | out: | 519 | found: |
516 | mutex_unlock(&nsm_mutex); | 520 | spin_unlock(&nsm_lock); |
517 | return nsm; | 521 | return nsm; |
518 | } | 522 | } |
519 | 523 | ||
@@ -532,12 +536,9 @@ nsm_release(struct nsm_handle *nsm) | |||
532 | { | 536 | { |
533 | if (!nsm) | 537 | if (!nsm) |
534 | return; | 538 | return; |
535 | if (atomic_dec_and_test(&nsm->sm_count)) { | 539 | if (atomic_dec_and_lock(&nsm->sm_count, &nsm_lock)) { |
536 | mutex_lock(&nsm_mutex); | 540 | list_del(&nsm->sm_link); |
537 | if (atomic_read(&nsm->sm_count) == 0) { | 541 | spin_unlock(&nsm_lock); |
538 | list_del(&nsm->sm_link); | 542 | kfree(nsm); |
539 | kfree(nsm); | ||
540 | } | ||
541 | mutex_unlock(&nsm_mutex); | ||
542 | } | 543 | } |
543 | } | 544 | } |
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 908b23fadd05..e4d563543b11 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c | |||
@@ -18,6 +18,8 @@ | |||
18 | 18 | ||
19 | #define NLMDBG_FACILITY NLMDBG_MONITOR | 19 | #define NLMDBG_FACILITY NLMDBG_MONITOR |
20 | 20 | ||
21 | #define XDR_ADDRBUF_LEN (20) | ||
22 | |||
21 | static struct rpc_clnt * nsm_create(void); | 23 | static struct rpc_clnt * nsm_create(void); |
22 | 24 | ||
23 | static struct rpc_program nsm_program; | 25 | static struct rpc_program nsm_program; |
@@ -147,28 +149,55 @@ nsm_create(void) | |||
147 | 149 | ||
148 | /* | 150 | /* |
149 | * XDR functions for NSM. | 151 | * XDR functions for NSM. |
152 | * | ||
153 | * See http://www.opengroup.org/ for details on the Network | ||
154 | * Status Monitor wire protocol. | ||
150 | */ | 155 | */ |
151 | 156 | ||
152 | static __be32 * | 157 | static __be32 *xdr_encode_nsm_string(__be32 *p, char *string) |
153 | xdr_encode_common(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) | ||
154 | { | 158 | { |
155 | char buffer[20], *name; | 159 | size_t len = strlen(string); |
156 | 160 | ||
157 | /* | 161 | if (len > SM_MAXSTRLEN) |
158 | * Use the dotted-quad IP address of the remote host as | 162 | len = SM_MAXSTRLEN; |
159 | * identifier. Linux statd always looks up the canonical | 163 | return xdr_encode_opaque(p, string, len); |
160 | * hostname first for whatever remote hostname it receives, | 164 | } |
161 | * so this works alright. | 165 | |
162 | */ | 166 | /* |
163 | if (nsm_use_hostnames) { | 167 | * "mon_name" specifies the host to be monitored. |
164 | name = argp->mon_name; | 168 | * |
165 | } else { | 169 | * Linux uses a text version of the IP address of the remote |
166 | sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(argp->addr)); | 170 | * host as the host identifier (the "mon_name" argument). |
171 | * | ||
172 | * Linux statd always looks up the canonical hostname first for | ||
173 | * whatever remote hostname it receives, so this works alright. | ||
174 | */ | ||
175 | static __be32 *xdr_encode_mon_name(__be32 *p, struct nsm_args *argp) | ||
176 | { | ||
177 | char buffer[XDR_ADDRBUF_LEN + 1]; | ||
178 | char *name = argp->mon_name; | ||
179 | |||
180 | if (!nsm_use_hostnames) { | ||
181 | snprintf(buffer, XDR_ADDRBUF_LEN, | ||
182 | NIPQUAD_FMT, NIPQUAD(argp->addr)); | ||
167 | name = buffer; | 183 | name = buffer; |
168 | } | 184 | } |
169 | if (!(p = xdr_encode_string(p, name)) | 185 | |
170 | || !(p = xdr_encode_string(p, utsname()->nodename))) | 186 | return xdr_encode_nsm_string(p, name); |
187 | } | ||
188 | |||
189 | /* | ||
190 | * The "my_id" argument specifies the hostname and RPC procedure | ||
191 | * to be called when the status manager receives notification | ||
192 | * (via the SM_NOTIFY call) that the state of host "mon_name" | ||
193 | * has changed. | ||
194 | */ | ||
195 | static __be32 *xdr_encode_my_id(__be32 *p, struct nsm_args *argp) | ||
196 | { | ||
197 | p = xdr_encode_nsm_string(p, utsname()->nodename); | ||
198 | if (!p) | ||
171 | return ERR_PTR(-EIO); | 199 | return ERR_PTR(-EIO); |
200 | |||
172 | *p++ = htonl(argp->prog); | 201 | *p++ = htonl(argp->prog); |
173 | *p++ = htonl(argp->vers); | 202 | *p++ = htonl(argp->vers); |
174 | *p++ = htonl(argp->proc); | 203 | *p++ = htonl(argp->proc); |
@@ -176,18 +205,48 @@ xdr_encode_common(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) | |||
176 | return p; | 205 | return p; |
177 | } | 206 | } |
178 | 207 | ||
179 | static int | 208 | /* |
180 | xdr_encode_mon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) | 209 | * The "mon_id" argument specifies the non-private arguments |
210 | * of an SM_MON or SM_UNMON call. | ||
211 | */ | ||
212 | static __be32 *xdr_encode_mon_id(__be32 *p, struct nsm_args *argp) | ||
181 | { | 213 | { |
182 | p = xdr_encode_common(rqstp, p, argp); | 214 | p = xdr_encode_mon_name(p, argp); |
183 | if (IS_ERR(p)) | 215 | if (!p) |
184 | return PTR_ERR(p); | 216 | return ERR_PTR(-EIO); |
185 | 217 | ||
186 | /* Surprise - there may even be room for an IPv6 address now */ | 218 | return xdr_encode_my_id(p, argp); |
219 | } | ||
220 | |||
221 | /* | ||
222 | * The "priv" argument may contain private information required | ||
223 | * by the SM_MON call. This information will be supplied in the | ||
224 | * SM_NOTIFY call. | ||
225 | * | ||
226 | * Linux provides the raw IP address of the monitored host, | ||
227 | * left in network byte order. | ||
228 | */ | ||
229 | static __be32 *xdr_encode_priv(__be32 *p, struct nsm_args *argp) | ||
230 | { | ||
187 | *p++ = argp->addr; | 231 | *p++ = argp->addr; |
188 | *p++ = 0; | 232 | *p++ = 0; |
189 | *p++ = 0; | 233 | *p++ = 0; |
190 | *p++ = 0; | 234 | *p++ = 0; |
235 | |||
236 | return p; | ||
237 | } | ||
238 | |||
239 | static int | ||
240 | xdr_encode_mon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) | ||
241 | { | ||
242 | p = xdr_encode_mon_id(p, argp); | ||
243 | if (IS_ERR(p)) | ||
244 | return PTR_ERR(p); | ||
245 | |||
246 | p = xdr_encode_priv(p, argp); | ||
247 | if (IS_ERR(p)) | ||
248 | return PTR_ERR(p); | ||
249 | |||
191 | rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p); | 250 | rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p); |
192 | return 0; | 251 | return 0; |
193 | } | 252 | } |
@@ -195,7 +254,7 @@ xdr_encode_mon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) | |||
195 | static int | 254 | static int |
196 | xdr_encode_unmon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) | 255 | xdr_encode_unmon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) |
197 | { | 256 | { |
198 | p = xdr_encode_common(rqstp, p, argp); | 257 | p = xdr_encode_mon_id(p, argp); |
199 | if (IS_ERR(p)) | 258 | if (IS_ERR(p)) |
200 | return PTR_ERR(p); | 259 | return PTR_ERR(p); |
201 | rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p); | 260 | rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p); |
@@ -220,9 +279,11 @@ xdr_decode_stat(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp) | |||
220 | } | 279 | } |
221 | 280 | ||
222 | #define SM_my_name_sz (1+XDR_QUADLEN(SM_MAXSTRLEN)) | 281 | #define SM_my_name_sz (1+XDR_QUADLEN(SM_MAXSTRLEN)) |
223 | #define SM_my_id_sz (3+1+SM_my_name_sz) | 282 | #define SM_my_id_sz (SM_my_name_sz+3) |
224 | #define SM_mon_id_sz (1+XDR_QUADLEN(20)+SM_my_id_sz) | 283 | #define SM_mon_name_sz (1+XDR_QUADLEN(SM_MAXSTRLEN)) |
225 | #define SM_mon_sz (SM_mon_id_sz+4) | 284 | #define SM_mon_id_sz (SM_mon_name_sz+SM_my_id_sz) |
285 | #define SM_priv_sz (XDR_QUADLEN(SM_PRIV_SIZE)) | ||
286 | #define SM_mon_sz (SM_mon_id_sz+SM_priv_sz) | ||
226 | #define SM_monres_sz 2 | 287 | #define SM_monres_sz 2 |
227 | #define SM_unmonres_sz 1 | 288 | #define SM_unmonres_sz 1 |
228 | 289 | ||
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 1ed8bd4de941..2169af4d5455 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/smp.h> | 25 | #include <linux/smp.h> |
26 | #include <linux/smp_lock.h> | 26 | #include <linux/smp_lock.h> |
27 | #include <linux/mutex.h> | 27 | #include <linux/mutex.h> |
28 | #include <linux/kthread.h> | ||
28 | #include <linux/freezer.h> | 29 | #include <linux/freezer.h> |
29 | 30 | ||
30 | #include <linux/sunrpc/types.h> | 31 | #include <linux/sunrpc/types.h> |
@@ -48,14 +49,11 @@ EXPORT_SYMBOL(nlmsvc_ops); | |||
48 | 49 | ||
49 | static DEFINE_MUTEX(nlmsvc_mutex); | 50 | static DEFINE_MUTEX(nlmsvc_mutex); |
50 | static unsigned int nlmsvc_users; | 51 | static unsigned int nlmsvc_users; |
51 | static pid_t nlmsvc_pid; | 52 | static struct task_struct *nlmsvc_task; |
52 | static struct svc_serv *nlmsvc_serv; | 53 | static struct svc_serv *nlmsvc_serv; |
53 | int nlmsvc_grace_period; | 54 | int nlmsvc_grace_period; |
54 | unsigned long nlmsvc_timeout; | 55 | unsigned long nlmsvc_timeout; |
55 | 56 | ||
56 | static DECLARE_COMPLETION(lockd_start_done); | ||
57 | static DECLARE_WAIT_QUEUE_HEAD(lockd_exit); | ||
58 | |||
59 | /* | 57 | /* |
60 | * These can be set at insmod time (useful for NFS as root filesystem), | 58 | * These can be set at insmod time (useful for NFS as root filesystem), |
61 | * and also changed through the sysctl interface. -- Jamie Lokier, Aug 2003 | 59 | * and also changed through the sysctl interface. -- Jamie Lokier, Aug 2003 |
@@ -74,7 +72,9 @@ static const unsigned long nlm_timeout_min = 3; | |||
74 | static const unsigned long nlm_timeout_max = 20; | 72 | static const unsigned long nlm_timeout_max = 20; |
75 | static const int nlm_port_min = 0, nlm_port_max = 65535; | 73 | static const int nlm_port_min = 0, nlm_port_max = 65535; |
76 | 74 | ||
75 | #ifdef CONFIG_SYSCTL | ||
77 | static struct ctl_table_header * nlm_sysctl_table; | 76 | static struct ctl_table_header * nlm_sysctl_table; |
77 | #endif | ||
78 | 78 | ||
79 | static unsigned long get_lockd_grace_period(void) | 79 | static unsigned long get_lockd_grace_period(void) |
80 | { | 80 | { |
@@ -111,35 +111,30 @@ static inline void clear_grace_period(void) | |||
111 | /* | 111 | /* |
112 | * This is the lockd kernel thread | 112 | * This is the lockd kernel thread |
113 | */ | 113 | */ |
114 | static void | 114 | static int |
115 | lockd(struct svc_rqst *rqstp) | 115 | lockd(void *vrqstp) |
116 | { | 116 | { |
117 | int err = 0; | 117 | int err = 0, preverr = 0; |
118 | struct svc_rqst *rqstp = vrqstp; | ||
118 | unsigned long grace_period_expire; | 119 | unsigned long grace_period_expire; |
119 | 120 | ||
120 | /* Lock module and set up kernel thread */ | 121 | /* try_to_freeze() is called from svc_recv() */ |
121 | /* lockd_up is waiting for us to startup, so will | ||
122 | * be holding a reference to this module, so it | ||
123 | * is safe to just claim another reference | ||
124 | */ | ||
125 | __module_get(THIS_MODULE); | ||
126 | lock_kernel(); | ||
127 | |||
128 | /* | ||
129 | * Let our maker know we're running. | ||
130 | */ | ||
131 | nlmsvc_pid = current->pid; | ||
132 | nlmsvc_serv = rqstp->rq_server; | ||
133 | complete(&lockd_start_done); | ||
134 | |||
135 | daemonize("lockd"); | ||
136 | set_freezable(); | 122 | set_freezable(); |
137 | 123 | ||
138 | /* Process request with signals blocked, but allow SIGKILL. */ | 124 | /* Allow SIGKILL to tell lockd to drop all of its locks */ |
139 | allow_signal(SIGKILL); | 125 | allow_signal(SIGKILL); |
140 | 126 | ||
141 | dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n"); | 127 | dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n"); |
142 | 128 | ||
129 | /* | ||
130 | * FIXME: it would be nice if lockd didn't spend its entire life | ||
131 | * running under the BKL. At the very least, it would be good to | ||
132 | * have someone clarify what it's intended to protect here. I've | ||
133 | * seen some handwavy posts about posix locking needing to be | ||
134 | * done under the BKL, but it's far from clear. | ||
135 | */ | ||
136 | lock_kernel(); | ||
137 | |||
143 | if (!nlm_timeout) | 138 | if (!nlm_timeout) |
144 | nlm_timeout = LOCKD_DFLT_TIMEO; | 139 | nlm_timeout = LOCKD_DFLT_TIMEO; |
145 | nlmsvc_timeout = nlm_timeout * HZ; | 140 | nlmsvc_timeout = nlm_timeout * HZ; |
@@ -148,10 +143,9 @@ lockd(struct svc_rqst *rqstp) | |||
148 | 143 | ||
149 | /* | 144 | /* |
150 | * The main request loop. We don't terminate until the last | 145 | * The main request loop. We don't terminate until the last |
151 | * NFS mount or NFS daemon has gone away, and we've been sent a | 146 | * NFS mount or NFS daemon has gone away. |
152 | * signal, or else another process has taken over our job. | ||
153 | */ | 147 | */ |
154 | while ((nlmsvc_users || !signalled()) && nlmsvc_pid == current->pid) { | 148 | while (!kthread_should_stop()) { |
155 | long timeout = MAX_SCHEDULE_TIMEOUT; | 149 | long timeout = MAX_SCHEDULE_TIMEOUT; |
156 | RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]); | 150 | RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]); |
157 | 151 | ||
@@ -161,6 +155,7 @@ lockd(struct svc_rqst *rqstp) | |||
161 | nlmsvc_invalidate_all(); | 155 | nlmsvc_invalidate_all(); |
162 | grace_period_expire = set_grace_period(); | 156 | grace_period_expire = set_grace_period(); |
163 | } | 157 | } |
158 | continue; | ||
164 | } | 159 | } |
165 | 160 | ||
166 | /* | 161 | /* |
@@ -179,14 +174,20 @@ lockd(struct svc_rqst *rqstp) | |||
179 | * recvfrom routine. | 174 | * recvfrom routine. |
180 | */ | 175 | */ |
181 | err = svc_recv(rqstp, timeout); | 176 | err = svc_recv(rqstp, timeout); |
182 | if (err == -EAGAIN || err == -EINTR) | 177 | if (err == -EAGAIN || err == -EINTR) { |
178 | preverr = err; | ||
183 | continue; | 179 | continue; |
180 | } | ||
184 | if (err < 0) { | 181 | if (err < 0) { |
185 | printk(KERN_WARNING | 182 | if (err != preverr) { |
186 | "lockd: terminating on error %d\n", | 183 | printk(KERN_WARNING "%s: unexpected error " |
187 | -err); | 184 | "from svc_recv (%d)\n", __func__, err); |
188 | break; | 185 | preverr = err; |
186 | } | ||
187 | schedule_timeout_interruptible(HZ); | ||
188 | continue; | ||
189 | } | 189 | } |
190 | preverr = err; | ||
190 | 191 | ||
191 | dprintk("lockd: request from %s\n", | 192 | dprintk("lockd: request from %s\n", |
192 | svc_print_addr(rqstp, buf, sizeof(buf))); | 193 | svc_print_addr(rqstp, buf, sizeof(buf))); |
@@ -195,28 +196,19 @@ lockd(struct svc_rqst *rqstp) | |||
195 | } | 196 | } |
196 | 197 | ||
197 | flush_signals(current); | 198 | flush_signals(current); |
199 | if (nlmsvc_ops) | ||
200 | nlmsvc_invalidate_all(); | ||
201 | nlm_shutdown_hosts(); | ||
198 | 202 | ||
199 | /* | 203 | unlock_kernel(); |
200 | * Check whether there's a new lockd process before | 204 | |
201 | * shutting down the hosts and clearing the slot. | 205 | nlmsvc_task = NULL; |
202 | */ | 206 | nlmsvc_serv = NULL; |
203 | if (!nlmsvc_pid || current->pid == nlmsvc_pid) { | ||
204 | if (nlmsvc_ops) | ||
205 | nlmsvc_invalidate_all(); | ||
206 | nlm_shutdown_hosts(); | ||
207 | nlmsvc_pid = 0; | ||
208 | nlmsvc_serv = NULL; | ||
209 | } else | ||
210 | printk(KERN_DEBUG | ||
211 | "lockd: new process, skipping host shutdown\n"); | ||
212 | wake_up(&lockd_exit); | ||
213 | 207 | ||
214 | /* Exit the RPC thread */ | 208 | /* Exit the RPC thread */ |
215 | svc_exit_thread(rqstp); | 209 | svc_exit_thread(rqstp); |
216 | 210 | ||
217 | /* Release module */ | 211 | return 0; |
218 | unlock_kernel(); | ||
219 | module_put_and_exit(0); | ||
220 | } | 212 | } |
221 | 213 | ||
222 | /* | 214 | /* |
@@ -261,14 +253,15 @@ static int make_socks(struct svc_serv *serv, int proto) | |||
261 | int | 253 | int |
262 | lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */ | 254 | lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */ |
263 | { | 255 | { |
264 | struct svc_serv * serv; | 256 | struct svc_serv *serv; |
265 | int error = 0; | 257 | struct svc_rqst *rqstp; |
258 | int error = 0; | ||
266 | 259 | ||
267 | mutex_lock(&nlmsvc_mutex); | 260 | mutex_lock(&nlmsvc_mutex); |
268 | /* | 261 | /* |
269 | * Check whether we're already up and running. | 262 | * Check whether we're already up and running. |
270 | */ | 263 | */ |
271 | if (nlmsvc_pid) { | 264 | if (nlmsvc_serv) { |
272 | if (proto) | 265 | if (proto) |
273 | error = make_socks(nlmsvc_serv, proto); | 266 | error = make_socks(nlmsvc_serv, proto); |
274 | goto out; | 267 | goto out; |
@@ -295,13 +288,28 @@ lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */ | |||
295 | /* | 288 | /* |
296 | * Create the kernel thread and wait for it to start. | 289 | * Create the kernel thread and wait for it to start. |
297 | */ | 290 | */ |
298 | error = svc_create_thread(lockd, serv); | 291 | rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]); |
299 | if (error) { | 292 | if (IS_ERR(rqstp)) { |
293 | error = PTR_ERR(rqstp); | ||
294 | printk(KERN_WARNING | ||
295 | "lockd_up: svc_rqst allocation failed, error=%d\n", | ||
296 | error); | ||
297 | goto destroy_and_out; | ||
298 | } | ||
299 | |||
300 | svc_sock_update_bufs(serv); | ||
301 | nlmsvc_serv = rqstp->rq_server; | ||
302 | |||
303 | nlmsvc_task = kthread_run(lockd, rqstp, serv->sv_name); | ||
304 | if (IS_ERR(nlmsvc_task)) { | ||
305 | error = PTR_ERR(nlmsvc_task); | ||
306 | nlmsvc_task = NULL; | ||
307 | nlmsvc_serv = NULL; | ||
300 | printk(KERN_WARNING | 308 | printk(KERN_WARNING |
301 | "lockd_up: create thread failed, error=%d\n", error); | 309 | "lockd_up: kthread_run failed, error=%d\n", error); |
310 | svc_exit_thread(rqstp); | ||
302 | goto destroy_and_out; | 311 | goto destroy_and_out; |
303 | } | 312 | } |
304 | wait_for_completion(&lockd_start_done); | ||
305 | 313 | ||
306 | /* | 314 | /* |
307 | * Note: svc_serv structures have an initial use count of 1, | 315 | * Note: svc_serv structures have an initial use count of 1, |
@@ -323,42 +331,28 @@ EXPORT_SYMBOL(lockd_up); | |||
323 | void | 331 | void |
324 | lockd_down(void) | 332 | lockd_down(void) |
325 | { | 333 | { |
326 | static int warned; | ||
327 | |||
328 | mutex_lock(&nlmsvc_mutex); | 334 | mutex_lock(&nlmsvc_mutex); |
329 | if (nlmsvc_users) { | 335 | if (nlmsvc_users) { |
330 | if (--nlmsvc_users) | 336 | if (--nlmsvc_users) |
331 | goto out; | 337 | goto out; |
332 | } else | 338 | } else { |
333 | printk(KERN_WARNING "lockd_down: no users! pid=%d\n", nlmsvc_pid); | 339 | printk(KERN_ERR "lockd_down: no users! task=%p\n", |
334 | 340 | nlmsvc_task); | |
335 | if (!nlmsvc_pid) { | 341 | BUG(); |
336 | if (warned++ == 0) | ||
337 | printk(KERN_WARNING "lockd_down: no lockd running.\n"); | ||
338 | goto out; | ||
339 | } | 342 | } |
340 | warned = 0; | ||
341 | 343 | ||
342 | kill_proc(nlmsvc_pid, SIGKILL, 1); | 344 | if (!nlmsvc_task) { |
343 | /* | 345 | printk(KERN_ERR "lockd_down: no lockd running.\n"); |
344 | * Wait for the lockd process to exit, but since we're holding | 346 | BUG(); |
345 | * the lockd semaphore, we can't wait around forever ... | ||
346 | */ | ||
347 | clear_thread_flag(TIF_SIGPENDING); | ||
348 | interruptible_sleep_on_timeout(&lockd_exit, HZ); | ||
349 | if (nlmsvc_pid) { | ||
350 | printk(KERN_WARNING | ||
351 | "lockd_down: lockd failed to exit, clearing pid\n"); | ||
352 | nlmsvc_pid = 0; | ||
353 | } | 347 | } |
354 | spin_lock_irq(¤t->sighand->siglock); | 348 | kthread_stop(nlmsvc_task); |
355 | recalc_sigpending(); | ||
356 | spin_unlock_irq(¤t->sighand->siglock); | ||
357 | out: | 349 | out: |
358 | mutex_unlock(&nlmsvc_mutex); | 350 | mutex_unlock(&nlmsvc_mutex); |
359 | } | 351 | } |
360 | EXPORT_SYMBOL(lockd_down); | 352 | EXPORT_SYMBOL(lockd_down); |
361 | 353 | ||
354 | #ifdef CONFIG_SYSCTL | ||
355 | |||
362 | /* | 356 | /* |
363 | * Sysctl parameters (same as module parameters, different interface). | 357 | * Sysctl parameters (same as module parameters, different interface). |
364 | */ | 358 | */ |
@@ -443,6 +437,8 @@ static ctl_table nlm_sysctl_root[] = { | |||
443 | { .ctl_name = 0 } | 437 | { .ctl_name = 0 } |
444 | }; | 438 | }; |
445 | 439 | ||
440 | #endif /* CONFIG_SYSCTL */ | ||
441 | |||
446 | /* | 442 | /* |
447 | * Module (and sysfs) parameters. | 443 | * Module (and sysfs) parameters. |
448 | */ | 444 | */ |
@@ -516,15 +512,21 @@ module_param(nsm_use_hostnames, bool, 0644); | |||
516 | 512 | ||
517 | static int __init init_nlm(void) | 513 | static int __init init_nlm(void) |
518 | { | 514 | { |
515 | #ifdef CONFIG_SYSCTL | ||
519 | nlm_sysctl_table = register_sysctl_table(nlm_sysctl_root); | 516 | nlm_sysctl_table = register_sysctl_table(nlm_sysctl_root); |
520 | return nlm_sysctl_table ? 0 : -ENOMEM; | 517 | return nlm_sysctl_table ? 0 : -ENOMEM; |
518 | #else | ||
519 | return 0; | ||
520 | #endif | ||
521 | } | 521 | } |
522 | 522 | ||
523 | static void __exit exit_nlm(void) | 523 | static void __exit exit_nlm(void) |
524 | { | 524 | { |
525 | /* FIXME: delete all NLM clients */ | 525 | /* FIXME: delete all NLM clients */ |
526 | nlm_shutdown_hosts(); | 526 | nlm_shutdown_hosts(); |
527 | #ifdef CONFIG_SYSCTL | ||
527 | unregister_sysctl_table(nlm_sysctl_table); | 528 | unregister_sysctl_table(nlm_sysctl_table); |
529 | #endif | ||
528 | } | 530 | } |
529 | 531 | ||
530 | module_init(init_nlm); | 532 | module_init(init_nlm); |
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index fe9bdb4a220c..1f122c1940af 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/sunrpc/svc.h> | 29 | #include <linux/sunrpc/svc.h> |
30 | #include <linux/lockd/nlm.h> | 30 | #include <linux/lockd/nlm.h> |
31 | #include <linux/lockd/lockd.h> | 31 | #include <linux/lockd/lockd.h> |
32 | #include <linux/kthread.h> | ||
32 | 33 | ||
33 | #define NLMDBG_FACILITY NLMDBG_SVCLOCK | 34 | #define NLMDBG_FACILITY NLMDBG_SVCLOCK |
34 | 35 | ||
@@ -226,8 +227,7 @@ failed: | |||
226 | } | 227 | } |
227 | 228 | ||
228 | /* | 229 | /* |
229 | * Delete a block. If the lock was cancelled or the grant callback | 230 | * Delete a block. |
230 | * failed, unlock is set to 1. | ||
231 | * It is the caller's responsibility to check whether the file | 231 | * It is the caller's responsibility to check whether the file |
232 | * can be closed hereafter. | 232 | * can be closed hereafter. |
233 | */ | 233 | */ |
@@ -887,7 +887,7 @@ nlmsvc_retry_blocked(void) | |||
887 | unsigned long timeout = MAX_SCHEDULE_TIMEOUT; | 887 | unsigned long timeout = MAX_SCHEDULE_TIMEOUT; |
888 | struct nlm_block *block; | 888 | struct nlm_block *block; |
889 | 889 | ||
890 | while (!list_empty(&nlm_blocked)) { | 890 | while (!list_empty(&nlm_blocked) && !kthread_should_stop()) { |
891 | block = list_entry(nlm_blocked.next, struct nlm_block, b_list); | 891 | block = list_entry(nlm_blocked.next, struct nlm_block, b_list); |
892 | 892 | ||
893 | if (block->b_when == NLM_NEVER) | 893 | if (block->b_when == NLM_NEVER) |
diff --git a/fs/lockd/svcshare.c b/fs/lockd/svcshare.c index 068886de4dda..b0ae07008700 100644 --- a/fs/lockd/svcshare.c +++ b/fs/lockd/svcshare.c | |||
@@ -71,7 +71,8 @@ nlmsvc_unshare_file(struct nlm_host *host, struct nlm_file *file, | |||
71 | struct nlm_share *share, **shpp; | 71 | struct nlm_share *share, **shpp; |
72 | struct xdr_netobj *oh = &argp->lock.oh; | 72 | struct xdr_netobj *oh = &argp->lock.oh; |
73 | 73 | ||
74 | for (shpp = &file->f_shares; (share = *shpp) != 0; shpp = &share->s_next) { | 74 | for (shpp = &file->f_shares; (share = *shpp) != NULL; |
75 | shpp = &share->s_next) { | ||
75 | if (share->s_host == host && nlm_cmp_owner(share, oh)) { | 76 | if (share->s_host == host && nlm_cmp_owner(share, oh)) { |
76 | *shpp = share->s_next; | 77 | *shpp = share->s_next; |
77 | kfree(share); | 78 | kfree(share); |
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile index df0f41e09885..ac6170c594a3 100644 --- a/fs/nfs/Makefile +++ b/fs/nfs/Makefile | |||
@@ -5,7 +5,7 @@ | |||
5 | obj-$(CONFIG_NFS_FS) += nfs.o | 5 | obj-$(CONFIG_NFS_FS) += nfs.o |
6 | 6 | ||
7 | nfs-y := client.o dir.o file.o getroot.o inode.o super.o nfs2xdr.o \ | 7 | nfs-y := client.o dir.o file.o getroot.o inode.o super.o nfs2xdr.o \ |
8 | pagelist.o proc.o read.o symlink.o unlink.o \ | 8 | direct.o pagelist.o proc.o read.o symlink.o unlink.o \ |
9 | write.o namespace.o mount_clnt.o | 9 | write.o namespace.o mount_clnt.o |
10 | nfs-$(CONFIG_ROOT_NFS) += nfsroot.o | 10 | nfs-$(CONFIG_ROOT_NFS) += nfsroot.o |
11 | nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o | 11 | nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o |
@@ -14,5 +14,4 @@ nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \ | |||
14 | delegation.o idmap.o \ | 14 | delegation.o idmap.o \ |
15 | callback.o callback_xdr.o callback_proc.o \ | 15 | callback.o callback_xdr.o callback_proc.o \ |
16 | nfs4namespace.o | 16 | nfs4namespace.o |
17 | nfs-$(CONFIG_NFS_DIRECTIO) += direct.o | ||
18 | nfs-$(CONFIG_SYSCTL) += sysctl.o | 17 | nfs-$(CONFIG_SYSCTL) += sysctl.o |
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 66648dd92d97..5606ae3d72d3 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/nfs_fs.h> | 15 | #include <linux/nfs_fs.h> |
16 | #include <linux/mutex.h> | 16 | #include <linux/mutex.h> |
17 | #include <linux/freezer.h> | 17 | #include <linux/freezer.h> |
18 | #include <linux/kthread.h> | ||
18 | 19 | ||
19 | #include <net/inet_sock.h> | 20 | #include <net/inet_sock.h> |
20 | 21 | ||
@@ -27,9 +28,7 @@ | |||
27 | struct nfs_callback_data { | 28 | struct nfs_callback_data { |
28 | unsigned int users; | 29 | unsigned int users; |
29 | struct svc_serv *serv; | 30 | struct svc_serv *serv; |
30 | pid_t pid; | 31 | struct task_struct *task; |
31 | struct completion started; | ||
32 | struct completion stopped; | ||
33 | }; | 32 | }; |
34 | 33 | ||
35 | static struct nfs_callback_data nfs_callback_info; | 34 | static struct nfs_callback_data nfs_callback_info; |
@@ -57,48 +56,44 @@ module_param_call(callback_tcpport, param_set_port, param_get_int, | |||
57 | /* | 56 | /* |
58 | * This is the callback kernel thread. | 57 | * This is the callback kernel thread. |
59 | */ | 58 | */ |
60 | static void nfs_callback_svc(struct svc_rqst *rqstp) | 59 | static int |
60 | nfs_callback_svc(void *vrqstp) | ||
61 | { | 61 | { |
62 | int err; | 62 | int err, preverr = 0; |
63 | struct svc_rqst *rqstp = vrqstp; | ||
63 | 64 | ||
64 | __module_get(THIS_MODULE); | ||
65 | lock_kernel(); | ||
66 | |||
67 | nfs_callback_info.pid = current->pid; | ||
68 | daemonize("nfsv4-svc"); | ||
69 | /* Process request with signals blocked, but allow SIGKILL. */ | ||
70 | allow_signal(SIGKILL); | ||
71 | set_freezable(); | 65 | set_freezable(); |
72 | 66 | ||
73 | complete(&nfs_callback_info.started); | 67 | /* |
74 | 68 | * FIXME: do we really need to run this under the BKL? If so, please | |
75 | for(;;) { | 69 | * add a comment about what it's intended to protect. |
76 | if (signalled()) { | 70 | */ |
77 | if (nfs_callback_info.users == 0) | 71 | lock_kernel(); |
78 | break; | 72 | while (!kthread_should_stop()) { |
79 | flush_signals(current); | ||
80 | } | ||
81 | /* | 73 | /* |
82 | * Listen for a request on the socket | 74 | * Listen for a request on the socket |
83 | */ | 75 | */ |
84 | err = svc_recv(rqstp, MAX_SCHEDULE_TIMEOUT); | 76 | err = svc_recv(rqstp, MAX_SCHEDULE_TIMEOUT); |
85 | if (err == -EAGAIN || err == -EINTR) | 77 | if (err == -EAGAIN || err == -EINTR) { |
78 | preverr = err; | ||
86 | continue; | 79 | continue; |
80 | } | ||
87 | if (err < 0) { | 81 | if (err < 0) { |
88 | printk(KERN_WARNING | 82 | if (err != preverr) { |
89 | "%s: terminating on error %d\n", | 83 | printk(KERN_WARNING "%s: unexpected error " |
90 | __FUNCTION__, -err); | 84 | "from svc_recv (%d)\n", __func__, err); |
91 | break; | 85 | preverr = err; |
86 | } | ||
87 | schedule_timeout_uninterruptible(HZ); | ||
88 | continue; | ||
92 | } | 89 | } |
90 | preverr = err; | ||
93 | svc_process(rqstp); | 91 | svc_process(rqstp); |
94 | } | 92 | } |
95 | |||
96 | flush_signals(current); | ||
97 | svc_exit_thread(rqstp); | ||
98 | nfs_callback_info.pid = 0; | ||
99 | complete(&nfs_callback_info.stopped); | ||
100 | unlock_kernel(); | 93 | unlock_kernel(); |
101 | module_put_and_exit(0); | 94 | nfs_callback_info.task = NULL; |
95 | svc_exit_thread(rqstp); | ||
96 | return 0; | ||
102 | } | 97 | } |
103 | 98 | ||
104 | /* | 99 | /* |
@@ -107,14 +102,13 @@ static void nfs_callback_svc(struct svc_rqst *rqstp) | |||
107 | int nfs_callback_up(void) | 102 | int nfs_callback_up(void) |
108 | { | 103 | { |
109 | struct svc_serv *serv = NULL; | 104 | struct svc_serv *serv = NULL; |
105 | struct svc_rqst *rqstp; | ||
110 | int ret = 0; | 106 | int ret = 0; |
111 | 107 | ||
112 | lock_kernel(); | 108 | lock_kernel(); |
113 | mutex_lock(&nfs_callback_mutex); | 109 | mutex_lock(&nfs_callback_mutex); |
114 | if (nfs_callback_info.users++ || nfs_callback_info.pid != 0) | 110 | if (nfs_callback_info.users++ || nfs_callback_info.task != NULL) |
115 | goto out; | 111 | goto out; |
116 | init_completion(&nfs_callback_info.started); | ||
117 | init_completion(&nfs_callback_info.stopped); | ||
118 | serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL); | 112 | serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL); |
119 | ret = -ENOMEM; | 113 | ret = -ENOMEM; |
120 | if (!serv) | 114 | if (!serv) |
@@ -127,15 +121,28 @@ int nfs_callback_up(void) | |||
127 | nfs_callback_tcpport = ret; | 121 | nfs_callback_tcpport = ret; |
128 | dprintk("Callback port = 0x%x\n", nfs_callback_tcpport); | 122 | dprintk("Callback port = 0x%x\n", nfs_callback_tcpport); |
129 | 123 | ||
130 | ret = svc_create_thread(nfs_callback_svc, serv); | 124 | rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]); |
131 | if (ret < 0) | 125 | if (IS_ERR(rqstp)) { |
126 | ret = PTR_ERR(rqstp); | ||
132 | goto out_err; | 127 | goto out_err; |
128 | } | ||
129 | |||
130 | svc_sock_update_bufs(serv); | ||
133 | nfs_callback_info.serv = serv; | 131 | nfs_callback_info.serv = serv; |
134 | wait_for_completion(&nfs_callback_info.started); | 132 | |
133 | nfs_callback_info.task = kthread_run(nfs_callback_svc, rqstp, | ||
134 | "nfsv4-svc"); | ||
135 | if (IS_ERR(nfs_callback_info.task)) { | ||
136 | ret = PTR_ERR(nfs_callback_info.task); | ||
137 | nfs_callback_info.serv = NULL; | ||
138 | nfs_callback_info.task = NULL; | ||
139 | svc_exit_thread(rqstp); | ||
140 | goto out_err; | ||
141 | } | ||
135 | out: | 142 | out: |
136 | /* | 143 | /* |
137 | * svc_create creates the svc_serv with sv_nrthreads == 1, and then | 144 | * svc_create creates the svc_serv with sv_nrthreads == 1, and then |
138 | * svc_create_thread increments that. So we need to call svc_destroy | 145 | * svc_prepare_thread increments that. So we need to call svc_destroy |
139 | * on both success and failure so that the refcount is 1 when the | 146 | * on both success and failure so that the refcount is 1 when the |
140 | * thread exits. | 147 | * thread exits. |
141 | */ | 148 | */ |
@@ -152,19 +159,15 @@ out_err: | |||
152 | } | 159 | } |
153 | 160 | ||
154 | /* | 161 | /* |
155 | * Kill the server process if it is not already up. | 162 | * Kill the server process if it is not already down. |
156 | */ | 163 | */ |
157 | void nfs_callback_down(void) | 164 | void nfs_callback_down(void) |
158 | { | 165 | { |
159 | lock_kernel(); | 166 | lock_kernel(); |
160 | mutex_lock(&nfs_callback_mutex); | 167 | mutex_lock(&nfs_callback_mutex); |
161 | nfs_callback_info.users--; | 168 | nfs_callback_info.users--; |
162 | do { | 169 | if (nfs_callback_info.users == 0 && nfs_callback_info.task != NULL) |
163 | if (nfs_callback_info.users != 0 || nfs_callback_info.pid == 0) | 170 | kthread_stop(nfs_callback_info.task); |
164 | break; | ||
165 | if (kill_proc(nfs_callback_info.pid, SIGKILL, 1) < 0) | ||
166 | break; | ||
167 | } while (wait_for_completion_timeout(&nfs_callback_info.stopped, 5*HZ) == 0); | ||
168 | mutex_unlock(&nfs_callback_mutex); | 171 | mutex_unlock(&nfs_callback_mutex); |
169 | unlock_kernel(); | 172 | unlock_kernel(); |
170 | } | 173 | } |
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index c5c0175898f6..f2f3b284e6dd 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -112,6 +112,7 @@ struct nfs_client_initdata { | |||
112 | static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init) | 112 | static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init) |
113 | { | 113 | { |
114 | struct nfs_client *clp; | 114 | struct nfs_client *clp; |
115 | struct rpc_cred *cred; | ||
115 | 116 | ||
116 | if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) | 117 | if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) |
117 | goto error_0; | 118 | goto error_0; |
@@ -150,6 +151,9 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
150 | clp->cl_boot_time = CURRENT_TIME; | 151 | clp->cl_boot_time = CURRENT_TIME; |
151 | clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; | 152 | clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; |
152 | #endif | 153 | #endif |
154 | cred = rpc_lookup_machine_cred(); | ||
155 | if (!IS_ERR(cred)) | ||
156 | clp->cl_machine_cred = cred; | ||
153 | 157 | ||
154 | return clp; | 158 | return clp; |
155 | 159 | ||
@@ -170,6 +174,8 @@ static void nfs4_shutdown_client(struct nfs_client *clp) | |||
170 | BUG_ON(!RB_EMPTY_ROOT(&clp->cl_state_owners)); | 174 | BUG_ON(!RB_EMPTY_ROOT(&clp->cl_state_owners)); |
171 | if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state)) | 175 | if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state)) |
172 | nfs_idmap_delete(clp); | 176 | nfs_idmap_delete(clp); |
177 | |||
178 | rpc_destroy_wait_queue(&clp->cl_rpcwaitq); | ||
173 | #endif | 179 | #endif |
174 | } | 180 | } |
175 | 181 | ||
@@ -189,6 +195,9 @@ static void nfs_free_client(struct nfs_client *clp) | |||
189 | if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) | 195 | if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) |
190 | nfs_callback_down(); | 196 | nfs_callback_down(); |
191 | 197 | ||
198 | if (clp->cl_machine_cred != NULL) | ||
199 | put_rpccred(clp->cl_machine_cred); | ||
200 | |||
192 | kfree(clp->cl_hostname); | 201 | kfree(clp->cl_hostname); |
193 | kfree(clp); | 202 | kfree(clp); |
194 | 203 | ||
@@ -680,10 +689,22 @@ static int nfs_init_server(struct nfs_server *server, | |||
680 | if (error < 0) | 689 | if (error < 0) |
681 | goto error; | 690 | goto error; |
682 | 691 | ||
692 | server->port = data->nfs_server.port; | ||
693 | |||
683 | error = nfs_init_server_rpcclient(server, &timeparms, data->auth_flavors[0]); | 694 | error = nfs_init_server_rpcclient(server, &timeparms, data->auth_flavors[0]); |
684 | if (error < 0) | 695 | if (error < 0) |
685 | goto error; | 696 | goto error; |
686 | 697 | ||
698 | /* Preserve the values of mount_server-related mount options */ | ||
699 | if (data->mount_server.addrlen) { | ||
700 | memcpy(&server->mountd_address, &data->mount_server.address, | ||
701 | data->mount_server.addrlen); | ||
702 | server->mountd_addrlen = data->mount_server.addrlen; | ||
703 | } | ||
704 | server->mountd_version = data->mount_server.version; | ||
705 | server->mountd_port = data->mount_server.port; | ||
706 | server->mountd_protocol = data->mount_server.protocol; | ||
707 | |||
687 | server->namelen = data->namlen; | 708 | server->namelen = data->namlen; |
688 | /* Create a client RPC handle for the NFSv3 ACL management interface */ | 709 | /* Create a client RPC handle for the NFSv3 ACL management interface */ |
689 | nfs_init_server_aclclient(server); | 710 | nfs_init_server_aclclient(server); |
@@ -1062,6 +1083,8 @@ static int nfs4_init_server(struct nfs_server *server, | |||
1062 | server->acdirmin = data->acdirmin * HZ; | 1083 | server->acdirmin = data->acdirmin * HZ; |
1063 | server->acdirmax = data->acdirmax * HZ; | 1084 | server->acdirmax = data->acdirmax * HZ; |
1064 | 1085 | ||
1086 | server->port = data->nfs_server.port; | ||
1087 | |||
1065 | error = nfs_init_server_rpcclient(server, &timeparms, data->auth_flavors[0]); | 1088 | error = nfs_init_server_rpcclient(server, &timeparms, data->auth_flavors[0]); |
1066 | 1089 | ||
1067 | error: | 1090 | error: |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index d9e30ac2798d..f288b3ecab4a 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -1967,7 +1967,7 @@ force_lookup: | |||
1967 | if (!NFS_PROTO(inode)->access) | 1967 | if (!NFS_PROTO(inode)->access) |
1968 | goto out_notsup; | 1968 | goto out_notsup; |
1969 | 1969 | ||
1970 | cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0); | 1970 | cred = rpc_lookup_cred(); |
1971 | if (!IS_ERR(cred)) { | 1971 | if (!IS_ERR(cred)) { |
1972 | res = nfs_do_access(inode, cred, mask); | 1972 | res = nfs_do_access(inode, cred, mask); |
1973 | put_rpccred(cred); | 1973 | put_rpccred(cred); |
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 16844f98f50e..4757a2b326a1 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -229,14 +229,20 @@ static void nfs_direct_complete(struct nfs_direct_req *dreq) | |||
229 | static void nfs_direct_read_result(struct rpc_task *task, void *calldata) | 229 | static void nfs_direct_read_result(struct rpc_task *task, void *calldata) |
230 | { | 230 | { |
231 | struct nfs_read_data *data = calldata; | 231 | struct nfs_read_data *data = calldata; |
232 | struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; | ||
233 | 232 | ||
234 | if (nfs_readpage_result(task, data) != 0) | 233 | nfs_readpage_result(task, data); |
235 | return; | 234 | } |
235 | |||
236 | static void nfs_direct_read_release(void *calldata) | ||
237 | { | ||
238 | |||
239 | struct nfs_read_data *data = calldata; | ||
240 | struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; | ||
241 | int status = data->task.tk_status; | ||
236 | 242 | ||
237 | spin_lock(&dreq->lock); | 243 | spin_lock(&dreq->lock); |
238 | if (unlikely(task->tk_status < 0)) { | 244 | if (unlikely(status < 0)) { |
239 | dreq->error = task->tk_status; | 245 | dreq->error = status; |
240 | spin_unlock(&dreq->lock); | 246 | spin_unlock(&dreq->lock); |
241 | } else { | 247 | } else { |
242 | dreq->count += data->res.count; | 248 | dreq->count += data->res.count; |
@@ -249,11 +255,12 @@ static void nfs_direct_read_result(struct rpc_task *task, void *calldata) | |||
249 | 255 | ||
250 | if (put_dreq(dreq)) | 256 | if (put_dreq(dreq)) |
251 | nfs_direct_complete(dreq); | 257 | nfs_direct_complete(dreq); |
258 | nfs_readdata_release(calldata); | ||
252 | } | 259 | } |
253 | 260 | ||
254 | static const struct rpc_call_ops nfs_read_direct_ops = { | 261 | static const struct rpc_call_ops nfs_read_direct_ops = { |
255 | .rpc_call_done = nfs_direct_read_result, | 262 | .rpc_call_done = nfs_direct_read_result, |
256 | .rpc_release = nfs_readdata_release, | 263 | .rpc_release = nfs_direct_read_release, |
257 | }; | 264 | }; |
258 | 265 | ||
259 | /* | 266 | /* |
@@ -280,6 +287,7 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq, | |||
280 | .rpc_client = NFS_CLIENT(inode), | 287 | .rpc_client = NFS_CLIENT(inode), |
281 | .rpc_message = &msg, | 288 | .rpc_message = &msg, |
282 | .callback_ops = &nfs_read_direct_ops, | 289 | .callback_ops = &nfs_read_direct_ops, |
290 | .workqueue = nfsiod_workqueue, | ||
283 | .flags = RPC_TASK_ASYNC, | 291 | .flags = RPC_TASK_ASYNC, |
284 | }; | 292 | }; |
285 | unsigned int pgbase; | 293 | unsigned int pgbase; |
@@ -323,7 +331,7 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq, | |||
323 | data->inode = inode; | 331 | data->inode = inode; |
324 | data->cred = msg.rpc_cred; | 332 | data->cred = msg.rpc_cred; |
325 | data->args.fh = NFS_FH(inode); | 333 | data->args.fh = NFS_FH(inode); |
326 | data->args.context = ctx; | 334 | data->args.context = get_nfs_open_context(ctx); |
327 | data->args.offset = pos; | 335 | data->args.offset = pos; |
328 | data->args.pgbase = pgbase; | 336 | data->args.pgbase = pgbase; |
329 | data->args.pages = data->pagevec; | 337 | data->args.pages = data->pagevec; |
@@ -339,8 +347,9 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq, | |||
339 | NFS_PROTO(inode)->read_setup(data, &msg); | 347 | NFS_PROTO(inode)->read_setup(data, &msg); |
340 | 348 | ||
341 | task = rpc_run_task(&task_setup_data); | 349 | task = rpc_run_task(&task_setup_data); |
342 | if (!IS_ERR(task)) | 350 | if (IS_ERR(task)) |
343 | rpc_put_task(task); | 351 | break; |
352 | rpc_put_task(task); | ||
344 | 353 | ||
345 | dprintk("NFS: %5u initiated direct read call " | 354 | dprintk("NFS: %5u initiated direct read call " |
346 | "(req %s/%Ld, %zu bytes @ offset %Lu)\n", | 355 | "(req %s/%Ld, %zu bytes @ offset %Lu)\n", |
@@ -446,6 +455,7 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) | |||
446 | struct rpc_task_setup task_setup_data = { | 455 | struct rpc_task_setup task_setup_data = { |
447 | .rpc_client = NFS_CLIENT(inode), | 456 | .rpc_client = NFS_CLIENT(inode), |
448 | .callback_ops = &nfs_write_direct_ops, | 457 | .callback_ops = &nfs_write_direct_ops, |
458 | .workqueue = nfsiod_workqueue, | ||
449 | .flags = RPC_TASK_ASYNC, | 459 | .flags = RPC_TASK_ASYNC, |
450 | }; | 460 | }; |
451 | 461 | ||
@@ -499,27 +509,34 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) | |||
499 | static void nfs_direct_commit_result(struct rpc_task *task, void *calldata) | 509 | static void nfs_direct_commit_result(struct rpc_task *task, void *calldata) |
500 | { | 510 | { |
501 | struct nfs_write_data *data = calldata; | 511 | struct nfs_write_data *data = calldata; |
502 | struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; | ||
503 | 512 | ||
504 | /* Call the NFS version-specific code */ | 513 | /* Call the NFS version-specific code */ |
505 | if (NFS_PROTO(data->inode)->commit_done(task, data) != 0) | 514 | NFS_PROTO(data->inode)->commit_done(task, data); |
506 | return; | 515 | } |
507 | if (unlikely(task->tk_status < 0)) { | 516 | |
517 | static void nfs_direct_commit_release(void *calldata) | ||
518 | { | ||
519 | struct nfs_write_data *data = calldata; | ||
520 | struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; | ||
521 | int status = data->task.tk_status; | ||
522 | |||
523 | if (status < 0) { | ||
508 | dprintk("NFS: %5u commit failed with error %d.\n", | 524 | dprintk("NFS: %5u commit failed with error %d.\n", |
509 | task->tk_pid, task->tk_status); | 525 | data->task.tk_pid, status); |
510 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; | 526 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; |
511 | } else if (memcmp(&dreq->verf, &data->verf, sizeof(data->verf))) { | 527 | } else if (memcmp(&dreq->verf, &data->verf, sizeof(data->verf))) { |
512 | dprintk("NFS: %5u commit verify failed\n", task->tk_pid); | 528 | dprintk("NFS: %5u commit verify failed\n", data->task.tk_pid); |
513 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; | 529 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; |
514 | } | 530 | } |
515 | 531 | ||
516 | dprintk("NFS: %5u commit returned %d\n", task->tk_pid, task->tk_status); | 532 | dprintk("NFS: %5u commit returned %d\n", data->task.tk_pid, status); |
517 | nfs_direct_write_complete(dreq, data->inode); | 533 | nfs_direct_write_complete(dreq, data->inode); |
534 | nfs_commitdata_release(calldata); | ||
518 | } | 535 | } |
519 | 536 | ||
520 | static const struct rpc_call_ops nfs_commit_direct_ops = { | 537 | static const struct rpc_call_ops nfs_commit_direct_ops = { |
521 | .rpc_call_done = nfs_direct_commit_result, | 538 | .rpc_call_done = nfs_direct_commit_result, |
522 | .rpc_release = nfs_commit_release, | 539 | .rpc_release = nfs_direct_commit_release, |
523 | }; | 540 | }; |
524 | 541 | ||
525 | static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) | 542 | static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) |
@@ -537,6 +554,7 @@ static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) | |||
537 | .rpc_message = &msg, | 554 | .rpc_message = &msg, |
538 | .callback_ops = &nfs_commit_direct_ops, | 555 | .callback_ops = &nfs_commit_direct_ops, |
539 | .callback_data = data, | 556 | .callback_data = data, |
557 | .workqueue = nfsiod_workqueue, | ||
540 | .flags = RPC_TASK_ASYNC, | 558 | .flags = RPC_TASK_ASYNC, |
541 | }; | 559 | }; |
542 | 560 | ||
@@ -546,6 +564,7 @@ static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) | |||
546 | data->args.fh = NFS_FH(data->inode); | 564 | data->args.fh = NFS_FH(data->inode); |
547 | data->args.offset = 0; | 565 | data->args.offset = 0; |
548 | data->args.count = 0; | 566 | data->args.count = 0; |
567 | data->args.context = get_nfs_open_context(dreq->ctx); | ||
549 | data->res.count = 0; | 568 | data->res.count = 0; |
550 | data->res.fattr = &data->fattr; | 569 | data->res.fattr = &data->fattr; |
551 | data->res.verf = &data->verf; | 570 | data->res.verf = &data->verf; |
@@ -585,7 +604,7 @@ static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode | |||
585 | 604 | ||
586 | static void nfs_alloc_commit_data(struct nfs_direct_req *dreq) | 605 | static void nfs_alloc_commit_data(struct nfs_direct_req *dreq) |
587 | { | 606 | { |
588 | dreq->commit_data = nfs_commit_alloc(); | 607 | dreq->commit_data = nfs_commitdata_alloc(); |
589 | if (dreq->commit_data != NULL) | 608 | if (dreq->commit_data != NULL) |
590 | dreq->commit_data->req = (struct nfs_page *) dreq; | 609 | dreq->commit_data->req = (struct nfs_page *) dreq; |
591 | } | 610 | } |
@@ -606,11 +625,20 @@ static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode | |||
606 | static void nfs_direct_write_result(struct rpc_task *task, void *calldata) | 625 | static void nfs_direct_write_result(struct rpc_task *task, void *calldata) |
607 | { | 626 | { |
608 | struct nfs_write_data *data = calldata; | 627 | struct nfs_write_data *data = calldata; |
609 | struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; | ||
610 | int status = task->tk_status; | ||
611 | 628 | ||
612 | if (nfs_writeback_done(task, data) != 0) | 629 | if (nfs_writeback_done(task, data) != 0) |
613 | return; | 630 | return; |
631 | } | ||
632 | |||
633 | /* | ||
634 | * NB: Return the value of the first error return code. Subsequent | ||
635 | * errors after the first one are ignored. | ||
636 | */ | ||
637 | static void nfs_direct_write_release(void *calldata) | ||
638 | { | ||
639 | struct nfs_write_data *data = calldata; | ||
640 | struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; | ||
641 | int status = data->task.tk_status; | ||
614 | 642 | ||
615 | spin_lock(&dreq->lock); | 643 | spin_lock(&dreq->lock); |
616 | 644 | ||
@@ -632,23 +660,13 @@ static void nfs_direct_write_result(struct rpc_task *task, void *calldata) | |||
632 | break; | 660 | break; |
633 | case NFS_ODIRECT_DO_COMMIT: | 661 | case NFS_ODIRECT_DO_COMMIT: |
634 | if (memcmp(&dreq->verf, &data->verf, sizeof(dreq->verf))) { | 662 | if (memcmp(&dreq->verf, &data->verf, sizeof(dreq->verf))) { |
635 | dprintk("NFS: %5u write verify failed\n", task->tk_pid); | 663 | dprintk("NFS: %5u write verify failed\n", data->task.tk_pid); |
636 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; | 664 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; |
637 | } | 665 | } |
638 | } | 666 | } |
639 | } | 667 | } |
640 | out_unlock: | 668 | out_unlock: |
641 | spin_unlock(&dreq->lock); | 669 | spin_unlock(&dreq->lock); |
642 | } | ||
643 | |||
644 | /* | ||
645 | * NB: Return the value of the first error return code. Subsequent | ||
646 | * errors after the first one are ignored. | ||
647 | */ | ||
648 | static void nfs_direct_write_release(void *calldata) | ||
649 | { | ||
650 | struct nfs_write_data *data = calldata; | ||
651 | struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; | ||
652 | 670 | ||
653 | if (put_dreq(dreq)) | 671 | if (put_dreq(dreq)) |
654 | nfs_direct_write_complete(dreq, data->inode); | 672 | nfs_direct_write_complete(dreq, data->inode); |
@@ -682,6 +700,7 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq, | |||
682 | .rpc_client = NFS_CLIENT(inode), | 700 | .rpc_client = NFS_CLIENT(inode), |
683 | .rpc_message = &msg, | 701 | .rpc_message = &msg, |
684 | .callback_ops = &nfs_write_direct_ops, | 702 | .callback_ops = &nfs_write_direct_ops, |
703 | .workqueue = nfsiod_workqueue, | ||
685 | .flags = RPC_TASK_ASYNC, | 704 | .flags = RPC_TASK_ASYNC, |
686 | }; | 705 | }; |
687 | size_t wsize = NFS_SERVER(inode)->wsize; | 706 | size_t wsize = NFS_SERVER(inode)->wsize; |
@@ -728,7 +747,7 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq, | |||
728 | data->inode = inode; | 747 | data->inode = inode; |
729 | data->cred = msg.rpc_cred; | 748 | data->cred = msg.rpc_cred; |
730 | data->args.fh = NFS_FH(inode); | 749 | data->args.fh = NFS_FH(inode); |
731 | data->args.context = ctx; | 750 | data->args.context = get_nfs_open_context(ctx); |
732 | data->args.offset = pos; | 751 | data->args.offset = pos; |
733 | data->args.pgbase = pgbase; | 752 | data->args.pgbase = pgbase; |
734 | data->args.pages = data->pagevec; | 753 | data->args.pages = data->pagevec; |
@@ -745,8 +764,9 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq, | |||
745 | NFS_PROTO(inode)->write_setup(data, &msg); | 764 | NFS_PROTO(inode)->write_setup(data, &msg); |
746 | 765 | ||
747 | task = rpc_run_task(&task_setup_data); | 766 | task = rpc_run_task(&task_setup_data); |
748 | if (!IS_ERR(task)) | 767 | if (IS_ERR(task)) |
749 | rpc_put_task(task); | 768 | break; |
769 | rpc_put_task(task); | ||
750 | 770 | ||
751 | dprintk("NFS: %5u initiated direct write call " | 771 | dprintk("NFS: %5u initiated direct write call " |
752 | "(req %s/%Ld, %zu bytes @ offset %Lu)\n", | 772 | "(req %s/%Ld, %zu bytes @ offset %Lu)\n", |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 5d2e9d9a4e28..3536b01164f9 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -238,10 +238,8 @@ nfs_file_read(struct kiocb *iocb, const struct iovec *iov, | |||
238 | ssize_t result; | 238 | ssize_t result; |
239 | size_t count = iov_length(iov, nr_segs); | 239 | size_t count = iov_length(iov, nr_segs); |
240 | 240 | ||
241 | #ifdef CONFIG_NFS_DIRECTIO | ||
242 | if (iocb->ki_filp->f_flags & O_DIRECT) | 241 | if (iocb->ki_filp->f_flags & O_DIRECT) |
243 | return nfs_file_direct_read(iocb, iov, nr_segs, pos); | 242 | return nfs_file_direct_read(iocb, iov, nr_segs, pos); |
244 | #endif | ||
245 | 243 | ||
246 | dfprintk(VFS, "nfs: read(%s/%s, %lu@%lu)\n", | 244 | dfprintk(VFS, "nfs: read(%s/%s, %lu@%lu)\n", |
247 | dentry->d_parent->d_name.name, dentry->d_name.name, | 245 | dentry->d_parent->d_name.name, dentry->d_name.name, |
@@ -387,9 +385,7 @@ const struct address_space_operations nfs_file_aops = { | |||
387 | .write_end = nfs_write_end, | 385 | .write_end = nfs_write_end, |
388 | .invalidatepage = nfs_invalidate_page, | 386 | .invalidatepage = nfs_invalidate_page, |
389 | .releasepage = nfs_release_page, | 387 | .releasepage = nfs_release_page, |
390 | #ifdef CONFIG_NFS_DIRECTIO | ||
391 | .direct_IO = nfs_direct_IO, | 388 | .direct_IO = nfs_direct_IO, |
392 | #endif | ||
393 | .launder_page = nfs_launder_page, | 389 | .launder_page = nfs_launder_page, |
394 | }; | 390 | }; |
395 | 391 | ||
@@ -447,10 +443,8 @@ static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov, | |||
447 | ssize_t result; | 443 | ssize_t result; |
448 | size_t count = iov_length(iov, nr_segs); | 444 | size_t count = iov_length(iov, nr_segs); |
449 | 445 | ||
450 | #ifdef CONFIG_NFS_DIRECTIO | ||
451 | if (iocb->ki_filp->f_flags & O_DIRECT) | 446 | if (iocb->ki_filp->f_flags & O_DIRECT) |
452 | return nfs_file_direct_write(iocb, iov, nr_segs, pos); | 447 | return nfs_file_direct_write(iocb, iov, nr_segs, pos); |
453 | #endif | ||
454 | 448 | ||
455 | dfprintk(VFS, "nfs: write(%s/%s(%ld), %lu@%Ld)\n", | 449 | dfprintk(VFS, "nfs: write(%s/%s(%ld), %lu@%Ld)\n", |
456 | dentry->d_parent->d_name.name, dentry->d_name.name, | 450 | dentry->d_parent->d_name.name, dentry->d_name.name, |
@@ -576,17 +570,9 @@ static int do_setlk(struct file *filp, int cmd, struct file_lock *fl) | |||
576 | 570 | ||
577 | lock_kernel(); | 571 | lock_kernel(); |
578 | /* Use local locking if mounted with "-onolock" */ | 572 | /* Use local locking if mounted with "-onolock" */ |
579 | if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)) { | 573 | if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)) |
580 | status = NFS_PROTO(inode)->lock(filp, cmd, fl); | 574 | status = NFS_PROTO(inode)->lock(filp, cmd, fl); |
581 | /* If we were signalled we still need to ensure that | 575 | else |
582 | * we clean up any state on the server. We therefore | ||
583 | * record the lock call as having succeeded in order to | ||
584 | * ensure that locks_remove_posix() cleans it out when | ||
585 | * the process exits. | ||
586 | */ | ||
587 | if (status == -EINTR || status == -ERESTARTSYS) | ||
588 | do_vfs_lock(filp, fl); | ||
589 | } else | ||
590 | status = do_vfs_lock(filp, fl); | 576 | status = do_vfs_lock(filp, fl); |
591 | unlock_kernel(); | 577 | unlock_kernel(); |
592 | if (status < 0) | 578 | if (status < 0) |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 6f88d7c77ac9..5cb3345eb694 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -523,8 +523,12 @@ struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx) | |||
523 | 523 | ||
524 | static void __put_nfs_open_context(struct nfs_open_context *ctx, int wait) | 524 | static void __put_nfs_open_context(struct nfs_open_context *ctx, int wait) |
525 | { | 525 | { |
526 | struct inode *inode = ctx->path.dentry->d_inode; | 526 | struct inode *inode; |
527 | 527 | ||
528 | if (ctx == NULL) | ||
529 | return; | ||
530 | |||
531 | inode = ctx->path.dentry->d_inode; | ||
528 | if (!atomic_dec_and_lock(&ctx->count, &inode->i_lock)) | 532 | if (!atomic_dec_and_lock(&ctx->count, &inode->i_lock)) |
529 | return; | 533 | return; |
530 | list_del(&ctx->list); | 534 | list_del(&ctx->list); |
@@ -610,7 +614,7 @@ int nfs_open(struct inode *inode, struct file *filp) | |||
610 | struct nfs_open_context *ctx; | 614 | struct nfs_open_context *ctx; |
611 | struct rpc_cred *cred; | 615 | struct rpc_cred *cred; |
612 | 616 | ||
613 | cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0); | 617 | cred = rpc_lookup_cred(); |
614 | if (IS_ERR(cred)) | 618 | if (IS_ERR(cred)) |
615 | return PTR_ERR(cred); | 619 | return PTR_ERR(cred); |
616 | ctx = alloc_nfs_open_context(filp->f_path.mnt, filp->f_path.dentry, cred); | 620 | ctx = alloc_nfs_open_context(filp->f_path.mnt, filp->f_path.dentry, cred); |
@@ -1218,6 +1222,36 @@ static void nfs_destroy_inodecache(void) | |||
1218 | kmem_cache_destroy(nfs_inode_cachep); | 1222 | kmem_cache_destroy(nfs_inode_cachep); |
1219 | } | 1223 | } |
1220 | 1224 | ||
1225 | struct workqueue_struct *nfsiod_workqueue; | ||
1226 | |||
1227 | /* | ||
1228 | * start up the nfsiod workqueue | ||
1229 | */ | ||
1230 | static int nfsiod_start(void) | ||
1231 | { | ||
1232 | struct workqueue_struct *wq; | ||
1233 | dprintk("RPC: creating workqueue nfsiod\n"); | ||
1234 | wq = create_singlethread_workqueue("nfsiod"); | ||
1235 | if (wq == NULL) | ||
1236 | return -ENOMEM; | ||
1237 | nfsiod_workqueue = wq; | ||
1238 | return 0; | ||
1239 | } | ||
1240 | |||
1241 | /* | ||
1242 | * Destroy the nfsiod workqueue | ||
1243 | */ | ||
1244 | static void nfsiod_stop(void) | ||
1245 | { | ||
1246 | struct workqueue_struct *wq; | ||
1247 | |||
1248 | wq = nfsiod_workqueue; | ||
1249 | if (wq == NULL) | ||
1250 | return; | ||
1251 | nfsiod_workqueue = NULL; | ||
1252 | destroy_workqueue(wq); | ||
1253 | } | ||
1254 | |||
1221 | /* | 1255 | /* |
1222 | * Initialize NFS | 1256 | * Initialize NFS |
1223 | */ | 1257 | */ |
@@ -1225,6 +1259,10 @@ static int __init init_nfs_fs(void) | |||
1225 | { | 1259 | { |
1226 | int err; | 1260 | int err; |
1227 | 1261 | ||
1262 | err = nfsiod_start(); | ||
1263 | if (err) | ||
1264 | goto out6; | ||
1265 | |||
1228 | err = nfs_fs_proc_init(); | 1266 | err = nfs_fs_proc_init(); |
1229 | if (err) | 1267 | if (err) |
1230 | goto out5; | 1268 | goto out5; |
@@ -1271,6 +1309,8 @@ out3: | |||
1271 | out4: | 1309 | out4: |
1272 | nfs_fs_proc_exit(); | 1310 | nfs_fs_proc_exit(); |
1273 | out5: | 1311 | out5: |
1312 | nfsiod_stop(); | ||
1313 | out6: | ||
1274 | return err; | 1314 | return err; |
1275 | } | 1315 | } |
1276 | 1316 | ||
@@ -1286,6 +1326,7 @@ static void __exit exit_nfs_fs(void) | |||
1286 | #endif | 1326 | #endif |
1287 | unregister_nfs_fs(); | 1327 | unregister_nfs_fs(); |
1288 | nfs_fs_proc_exit(); | 1328 | nfs_fs_proc_exit(); |
1329 | nfsiod_stop(); | ||
1289 | } | 1330 | } |
1290 | 1331 | ||
1291 | /* Not quite true; I just maintain it */ | 1332 | /* Not quite true; I just maintain it */ |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 931992763e68..04ae867dddba 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -46,9 +46,9 @@ struct nfs_parsed_mount_data { | |||
46 | struct sockaddr_storage address; | 46 | struct sockaddr_storage address; |
47 | size_t addrlen; | 47 | size_t addrlen; |
48 | char *hostname; | 48 | char *hostname; |
49 | unsigned int version; | 49 | u32 version; |
50 | unsigned short port; | 50 | unsigned short port; |
51 | int protocol; | 51 | unsigned short protocol; |
52 | } mount_server; | 52 | } mount_server; |
53 | 53 | ||
54 | struct { | 54 | struct { |
@@ -56,7 +56,8 @@ struct nfs_parsed_mount_data { | |||
56 | size_t addrlen; | 56 | size_t addrlen; |
57 | char *hostname; | 57 | char *hostname; |
58 | char *export_path; | 58 | char *export_path; |
59 | int protocol; | 59 | unsigned short port; |
60 | unsigned short protocol; | ||
60 | } nfs_server; | 61 | } nfs_server; |
61 | 62 | ||
62 | struct security_mnt_opts lsm_opts; | 63 | struct security_mnt_opts lsm_opts; |
@@ -115,13 +116,8 @@ extern void nfs_destroy_readpagecache(void); | |||
115 | extern int __init nfs_init_writepagecache(void); | 116 | extern int __init nfs_init_writepagecache(void); |
116 | extern void nfs_destroy_writepagecache(void); | 117 | extern void nfs_destroy_writepagecache(void); |
117 | 118 | ||
118 | #ifdef CONFIG_NFS_DIRECTIO | ||
119 | extern int __init nfs_init_directcache(void); | 119 | extern int __init nfs_init_directcache(void); |
120 | extern void nfs_destroy_directcache(void); | 120 | extern void nfs_destroy_directcache(void); |
121 | #else | ||
122 | #define nfs_init_directcache() (0) | ||
123 | #define nfs_destroy_directcache() do {} while(0) | ||
124 | #endif | ||
125 | 121 | ||
126 | /* nfs2xdr.c */ | 122 | /* nfs2xdr.c */ |
127 | extern int nfs_stat_to_errno(int); | 123 | extern int nfs_stat_to_errno(int); |
@@ -146,6 +142,7 @@ extern struct rpc_procinfo nfs4_procedures[]; | |||
146 | extern int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask); | 142 | extern int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask); |
147 | 143 | ||
148 | /* inode.c */ | 144 | /* inode.c */ |
145 | extern struct workqueue_struct *nfsiod_workqueue; | ||
149 | extern struct inode *nfs_alloc_inode(struct super_block *sb); | 146 | extern struct inode *nfs_alloc_inode(struct super_block *sb); |
150 | extern void nfs_destroy_inode(struct inode *); | 147 | extern void nfs_destroy_inode(struct inode *); |
151 | extern int nfs_write_inode(struct inode *,int); | 148 | extern int nfs_write_inode(struct inode *,int); |
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index 607f6eb9cdb5..af4d0f1e402c 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c | |||
@@ -20,7 +20,7 @@ | |||
20 | 20 | ||
21 | static void nfs_expire_automounts(struct work_struct *work); | 21 | static void nfs_expire_automounts(struct work_struct *work); |
22 | 22 | ||
23 | LIST_HEAD(nfs_automount_list); | 23 | static LIST_HEAD(nfs_automount_list); |
24 | static DECLARE_DELAYED_WORK(nfs_automount_task, nfs_expire_automounts); | 24 | static DECLARE_DELAYED_WORK(nfs_automount_task, nfs_expire_automounts); |
25 | int nfs_mountpoint_expiry_timeout = 500 * HZ; | 25 | int nfs_mountpoint_expiry_timeout = 500 * HZ; |
26 | 26 | ||
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index 1f7ea675e0c5..28bab67d1519 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c | |||
@@ -267,7 +267,7 @@ nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) | |||
267 | int status; | 267 | int status; |
268 | 268 | ||
269 | if ((status = ntohl(*p++))) | 269 | if ((status = ntohl(*p++))) |
270 | return -nfs_stat_to_errno(status); | 270 | return nfs_stat_to_errno(status); |
271 | p = xdr_decode_fattr(p, res->fattr); | 271 | p = xdr_decode_fattr(p, res->fattr); |
272 | 272 | ||
273 | count = ntohl(*p++); | 273 | count = ntohl(*p++); |
@@ -428,11 +428,11 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy) | |||
428 | size_t hdrlen; | 428 | size_t hdrlen; |
429 | unsigned int pglen, recvd; | 429 | unsigned int pglen, recvd; |
430 | u32 len; | 430 | u32 len; |
431 | int status, nr; | 431 | int status, nr = 0; |
432 | __be32 *end, *entry, *kaddr; | 432 | __be32 *end, *entry, *kaddr; |
433 | 433 | ||
434 | if ((status = ntohl(*p++))) | 434 | if ((status = ntohl(*p++))) |
435 | return -nfs_stat_to_errno(status); | 435 | return nfs_stat_to_errno(status); |
436 | 436 | ||
437 | hdrlen = (u8 *) p - (u8 *) iov->iov_base; | 437 | hdrlen = (u8 *) p - (u8 *) iov->iov_base; |
438 | if (iov->iov_len < hdrlen) { | 438 | if (iov->iov_len < hdrlen) { |
@@ -452,7 +452,12 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy) | |||
452 | kaddr = p = kmap_atomic(*page, KM_USER0); | 452 | kaddr = p = kmap_atomic(*page, KM_USER0); |
453 | end = (__be32 *)((char *)p + pglen); | 453 | end = (__be32 *)((char *)p + pglen); |
454 | entry = p; | 454 | entry = p; |
455 | for (nr = 0; *p++; nr++) { | 455 | |
456 | /* Make sure the packet actually has a value_follows and EOF entry */ | ||
457 | if ((entry + 1) > end) | ||
458 | goto short_pkt; | ||
459 | |||
460 | for (; *p++; nr++) { | ||
456 | if (p + 2 > end) | 461 | if (p + 2 > end) |
457 | goto short_pkt; | 462 | goto short_pkt; |
458 | p++; /* fileid */ | 463 | p++; /* fileid */ |
@@ -467,18 +472,32 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy) | |||
467 | goto short_pkt; | 472 | goto short_pkt; |
468 | entry = p; | 473 | entry = p; |
469 | } | 474 | } |
470 | if (!nr && (entry[0] != 0 || entry[1] == 0)) | 475 | |
471 | goto short_pkt; | 476 | /* |
477 | * Apparently some server sends responses that are a valid size, but | ||
478 | * contain no entries, and have value_follows==0 and EOF==0. For | ||
479 | * those, just set the EOF marker. | ||
480 | */ | ||
481 | if (!nr && entry[1] == 0) { | ||
482 | dprintk("NFS: readdir reply truncated!\n"); | ||
483 | entry[1] = 1; | ||
484 | } | ||
472 | out: | 485 | out: |
473 | kunmap_atomic(kaddr, KM_USER0); | 486 | kunmap_atomic(kaddr, KM_USER0); |
474 | return nr; | 487 | return nr; |
475 | short_pkt: | 488 | short_pkt: |
489 | /* | ||
490 | * When we get a short packet there are 2 possibilities. We can | ||
491 | * return an error, or fix up the response to look like a valid | ||
492 | * response and return what we have so far. If there are no | ||
493 | * entries and the packet was short, then return -EIO. If there | ||
494 | * are valid entries in the response, return them and pretend that | ||
495 | * the call was successful, but incomplete. The caller can retry the | ||
496 | * readdir starting at the last cookie. | ||
497 | */ | ||
476 | entry[0] = entry[1] = 0; | 498 | entry[0] = entry[1] = 0; |
477 | /* truncate listing ? */ | 499 | if (!nr) |
478 | if (!nr) { | 500 | nr = -errno_NFSERR_IO; |
479 | dprintk("NFS: readdir reply truncated!\n"); | ||
480 | entry[1] = 1; | ||
481 | } | ||
482 | goto out; | 501 | goto out; |
483 | err_unmap: | 502 | err_unmap: |
484 | nr = -errno_NFSERR_IO; | 503 | nr = -errno_NFSERR_IO; |
@@ -518,7 +537,7 @@ nfs_xdr_stat(struct rpc_rqst *req, __be32 *p, void *dummy) | |||
518 | int status; | 537 | int status; |
519 | 538 | ||
520 | if ((status = ntohl(*p++)) != 0) | 539 | if ((status = ntohl(*p++)) != 0) |
521 | status = -nfs_stat_to_errno(status); | 540 | status = nfs_stat_to_errno(status); |
522 | return status; | 541 | return status; |
523 | } | 542 | } |
524 | 543 | ||
@@ -532,7 +551,7 @@ nfs_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) | |||
532 | int status; | 551 | int status; |
533 | 552 | ||
534 | if ((status = ntohl(*p++))) | 553 | if ((status = ntohl(*p++))) |
535 | return -nfs_stat_to_errno(status); | 554 | return nfs_stat_to_errno(status); |
536 | xdr_decode_fattr(p, fattr); | 555 | xdr_decode_fattr(p, fattr); |
537 | return 0; | 556 | return 0; |
538 | } | 557 | } |
@@ -547,7 +566,7 @@ nfs_xdr_diropres(struct rpc_rqst *req, __be32 *p, struct nfs_diropok *res) | |||
547 | int status; | 566 | int status; |
548 | 567 | ||
549 | if ((status = ntohl(*p++))) | 568 | if ((status = ntohl(*p++))) |
550 | return -nfs_stat_to_errno(status); | 569 | return nfs_stat_to_errno(status); |
551 | p = xdr_decode_fhandle(p, res->fh); | 570 | p = xdr_decode_fhandle(p, res->fh); |
552 | xdr_decode_fattr(p, res->fattr); | 571 | xdr_decode_fattr(p, res->fattr); |
553 | return 0; | 572 | return 0; |
@@ -585,7 +604,7 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy) | |||
585 | int status; | 604 | int status; |
586 | 605 | ||
587 | if ((status = ntohl(*p++))) | 606 | if ((status = ntohl(*p++))) |
588 | return -nfs_stat_to_errno(status); | 607 | return nfs_stat_to_errno(status); |
589 | /* Convert length of symlink */ | 608 | /* Convert length of symlink */ |
590 | len = ntohl(*p++); | 609 | len = ntohl(*p++); |
591 | if (len >= rcvbuf->page_len) { | 610 | if (len >= rcvbuf->page_len) { |
@@ -634,7 +653,7 @@ nfs_xdr_statfsres(struct rpc_rqst *req, __be32 *p, struct nfs2_fsstat *res) | |||
634 | int status; | 653 | int status; |
635 | 654 | ||
636 | if ((status = ntohl(*p++))) | 655 | if ((status = ntohl(*p++))) |
637 | return -nfs_stat_to_errno(status); | 656 | return nfs_stat_to_errno(status); |
638 | 657 | ||
639 | res->tsize = ntohl(*p++); | 658 | res->tsize = ntohl(*p++); |
640 | res->bsize = ntohl(*p++); | 659 | res->bsize = ntohl(*p++); |
@@ -653,39 +672,39 @@ static struct { | |||
653 | int errno; | 672 | int errno; |
654 | } nfs_errtbl[] = { | 673 | } nfs_errtbl[] = { |
655 | { NFS_OK, 0 }, | 674 | { NFS_OK, 0 }, |
656 | { NFSERR_PERM, EPERM }, | 675 | { NFSERR_PERM, -EPERM }, |
657 | { NFSERR_NOENT, ENOENT }, | 676 | { NFSERR_NOENT, -ENOENT }, |
658 | { NFSERR_IO, errno_NFSERR_IO }, | 677 | { NFSERR_IO, -errno_NFSERR_IO}, |
659 | { NFSERR_NXIO, ENXIO }, | 678 | { NFSERR_NXIO, -ENXIO }, |
660 | /* { NFSERR_EAGAIN, EAGAIN }, */ | 679 | /* { NFSERR_EAGAIN, -EAGAIN }, */ |
661 | { NFSERR_ACCES, EACCES }, | 680 | { NFSERR_ACCES, -EACCES }, |
662 | { NFSERR_EXIST, EEXIST }, | 681 | { NFSERR_EXIST, -EEXIST }, |
663 | { NFSERR_XDEV, EXDEV }, | 682 | { NFSERR_XDEV, -EXDEV }, |
664 | { NFSERR_NODEV, ENODEV }, | 683 | { NFSERR_NODEV, -ENODEV }, |
665 | { NFSERR_NOTDIR, ENOTDIR }, | 684 | { NFSERR_NOTDIR, -ENOTDIR }, |
666 | { NFSERR_ISDIR, EISDIR }, | 685 | { NFSERR_ISDIR, -EISDIR }, |
667 | { NFSERR_INVAL, EINVAL }, | 686 | { NFSERR_INVAL, -EINVAL }, |
668 | { NFSERR_FBIG, EFBIG }, | 687 | { NFSERR_FBIG, -EFBIG }, |
669 | { NFSERR_NOSPC, ENOSPC }, | 688 | { NFSERR_NOSPC, -ENOSPC }, |
670 | { NFSERR_ROFS, EROFS }, | 689 | { NFSERR_ROFS, -EROFS }, |
671 | { NFSERR_MLINK, EMLINK }, | 690 | { NFSERR_MLINK, -EMLINK }, |
672 | { NFSERR_NAMETOOLONG, ENAMETOOLONG }, | 691 | { NFSERR_NAMETOOLONG, -ENAMETOOLONG }, |
673 | { NFSERR_NOTEMPTY, ENOTEMPTY }, | 692 | { NFSERR_NOTEMPTY, -ENOTEMPTY }, |
674 | { NFSERR_DQUOT, EDQUOT }, | 693 | { NFSERR_DQUOT, -EDQUOT }, |
675 | { NFSERR_STALE, ESTALE }, | 694 | { NFSERR_STALE, -ESTALE }, |
676 | { NFSERR_REMOTE, EREMOTE }, | 695 | { NFSERR_REMOTE, -EREMOTE }, |
677 | #ifdef EWFLUSH | 696 | #ifdef EWFLUSH |
678 | { NFSERR_WFLUSH, EWFLUSH }, | 697 | { NFSERR_WFLUSH, -EWFLUSH }, |
679 | #endif | 698 | #endif |
680 | { NFSERR_BADHANDLE, EBADHANDLE }, | 699 | { NFSERR_BADHANDLE, -EBADHANDLE }, |
681 | { NFSERR_NOT_SYNC, ENOTSYNC }, | 700 | { NFSERR_NOT_SYNC, -ENOTSYNC }, |
682 | { NFSERR_BAD_COOKIE, EBADCOOKIE }, | 701 | { NFSERR_BAD_COOKIE, -EBADCOOKIE }, |
683 | { NFSERR_NOTSUPP, ENOTSUPP }, | 702 | { NFSERR_NOTSUPP, -ENOTSUPP }, |
684 | { NFSERR_TOOSMALL, ETOOSMALL }, | 703 | { NFSERR_TOOSMALL, -ETOOSMALL }, |
685 | { NFSERR_SERVERFAULT, ESERVERFAULT }, | 704 | { NFSERR_SERVERFAULT, -ESERVERFAULT }, |
686 | { NFSERR_BADTYPE, EBADTYPE }, | 705 | { NFSERR_BADTYPE, -EBADTYPE }, |
687 | { NFSERR_JUKEBOX, EJUKEBOX }, | 706 | { NFSERR_JUKEBOX, -EJUKEBOX }, |
688 | { -1, EIO } | 707 | { -1, -EIO } |
689 | }; | 708 | }; |
690 | 709 | ||
691 | /* | 710 | /* |
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index 3917e2fa4e40..11cdddec1432 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c | |||
@@ -508,14 +508,14 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res | |||
508 | struct page **page; | 508 | struct page **page; |
509 | size_t hdrlen; | 509 | size_t hdrlen; |
510 | u32 len, recvd, pglen; | 510 | u32 len, recvd, pglen; |
511 | int status, nr; | 511 | int status, nr = 0; |
512 | __be32 *entry, *end, *kaddr; | 512 | __be32 *entry, *end, *kaddr; |
513 | 513 | ||
514 | status = ntohl(*p++); | 514 | status = ntohl(*p++); |
515 | /* Decode post_op_attrs */ | 515 | /* Decode post_op_attrs */ |
516 | p = xdr_decode_post_op_attr(p, res->dir_attr); | 516 | p = xdr_decode_post_op_attr(p, res->dir_attr); |
517 | if (status) | 517 | if (status) |
518 | return -nfs_stat_to_errno(status); | 518 | return nfs_stat_to_errno(status); |
519 | /* Decode verifier cookie */ | 519 | /* Decode verifier cookie */ |
520 | if (res->verf) { | 520 | if (res->verf) { |
521 | res->verf[0] = *p++; | 521 | res->verf[0] = *p++; |
@@ -542,7 +542,12 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res | |||
542 | kaddr = p = kmap_atomic(*page, KM_USER0); | 542 | kaddr = p = kmap_atomic(*page, KM_USER0); |
543 | end = (__be32 *)((char *)p + pglen); | 543 | end = (__be32 *)((char *)p + pglen); |
544 | entry = p; | 544 | entry = p; |
545 | for (nr = 0; *p++; nr++) { | 545 | |
546 | /* Make sure the packet actually has a value_follows and EOF entry */ | ||
547 | if ((entry + 1) > end) | ||
548 | goto short_pkt; | ||
549 | |||
550 | for (; *p++; nr++) { | ||
546 | if (p + 3 > end) | 551 | if (p + 3 > end) |
547 | goto short_pkt; | 552 | goto short_pkt; |
548 | p += 2; /* inode # */ | 553 | p += 2; /* inode # */ |
@@ -581,18 +586,32 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res | |||
581 | goto short_pkt; | 586 | goto short_pkt; |
582 | entry = p; | 587 | entry = p; |
583 | } | 588 | } |
584 | if (!nr && (entry[0] != 0 || entry[1] == 0)) | 589 | |
585 | goto short_pkt; | 590 | /* |
591 | * Apparently some server sends responses that are a valid size, but | ||
592 | * contain no entries, and have value_follows==0 and EOF==0. For | ||
593 | * those, just set the EOF marker. | ||
594 | */ | ||
595 | if (!nr && entry[1] == 0) { | ||
596 | dprintk("NFS: readdir reply truncated!\n"); | ||
597 | entry[1] = 1; | ||
598 | } | ||
586 | out: | 599 | out: |
587 | kunmap_atomic(kaddr, KM_USER0); | 600 | kunmap_atomic(kaddr, KM_USER0); |
588 | return nr; | 601 | return nr; |
589 | short_pkt: | 602 | short_pkt: |
603 | /* | ||
604 | * When we get a short packet there are 2 possibilities. We can | ||
605 | * return an error, or fix up the response to look like a valid | ||
606 | * response and return what we have so far. If there are no | ||
607 | * entries and the packet was short, then return -EIO. If there | ||
608 | * are valid entries in the response, return them and pretend that | ||
609 | * the call was successful, but incomplete. The caller can retry the | ||
610 | * readdir starting at the last cookie. | ||
611 | */ | ||
590 | entry[0] = entry[1] = 0; | 612 | entry[0] = entry[1] = 0; |
591 | /* truncate listing ? */ | 613 | if (!nr) |
592 | if (!nr) { | 614 | nr = -errno_NFSERR_IO; |
593 | dprintk("NFS: readdir reply truncated!\n"); | ||
594 | entry[1] = 1; | ||
595 | } | ||
596 | goto out; | 615 | goto out; |
597 | err_unmap: | 616 | err_unmap: |
598 | nr = -errno_NFSERR_IO; | 617 | nr = -errno_NFSERR_IO; |
@@ -732,7 +751,7 @@ nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) | |||
732 | int status; | 751 | int status; |
733 | 752 | ||
734 | if ((status = ntohl(*p++))) | 753 | if ((status = ntohl(*p++))) |
735 | return -nfs_stat_to_errno(status); | 754 | return nfs_stat_to_errno(status); |
736 | xdr_decode_fattr(p, fattr); | 755 | xdr_decode_fattr(p, fattr); |
737 | return 0; | 756 | return 0; |
738 | } | 757 | } |
@@ -747,7 +766,7 @@ nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) | |||
747 | int status; | 766 | int status; |
748 | 767 | ||
749 | if ((status = ntohl(*p++))) | 768 | if ((status = ntohl(*p++))) |
750 | status = -nfs_stat_to_errno(status); | 769 | status = nfs_stat_to_errno(status); |
751 | xdr_decode_wcc_data(p, fattr); | 770 | xdr_decode_wcc_data(p, fattr); |
752 | return status; | 771 | return status; |
753 | } | 772 | } |
@@ -767,7 +786,7 @@ nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res) | |||
767 | int status; | 786 | int status; |
768 | 787 | ||
769 | if ((status = ntohl(*p++))) { | 788 | if ((status = ntohl(*p++))) { |
770 | status = -nfs_stat_to_errno(status); | 789 | status = nfs_stat_to_errno(status); |
771 | } else { | 790 | } else { |
772 | if (!(p = xdr_decode_fhandle(p, res->fh))) | 791 | if (!(p = xdr_decode_fhandle(p, res->fh))) |
773 | return -errno_NFSERR_IO; | 792 | return -errno_NFSERR_IO; |
@@ -787,7 +806,7 @@ nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res) | |||
787 | 806 | ||
788 | p = xdr_decode_post_op_attr(p, res->fattr); | 807 | p = xdr_decode_post_op_attr(p, res->fattr); |
789 | if (status) | 808 | if (status) |
790 | return -nfs_stat_to_errno(status); | 809 | return nfs_stat_to_errno(status); |
791 | res->access = ntohl(*p++); | 810 | res->access = ntohl(*p++); |
792 | return 0; | 811 | return 0; |
793 | } | 812 | } |
@@ -824,7 +843,7 @@ nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) | |||
824 | p = xdr_decode_post_op_attr(p, fattr); | 843 | p = xdr_decode_post_op_attr(p, fattr); |
825 | 844 | ||
826 | if (status != 0) | 845 | if (status != 0) |
827 | return -nfs_stat_to_errno(status); | 846 | return nfs_stat_to_errno(status); |
828 | 847 | ||
829 | /* Convert length of symlink */ | 848 | /* Convert length of symlink */ |
830 | len = ntohl(*p++); | 849 | len = ntohl(*p++); |
@@ -872,7 +891,7 @@ nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) | |||
872 | p = xdr_decode_post_op_attr(p, res->fattr); | 891 | p = xdr_decode_post_op_attr(p, res->fattr); |
873 | 892 | ||
874 | if (status != 0) | 893 | if (status != 0) |
875 | return -nfs_stat_to_errno(status); | 894 | return nfs_stat_to_errno(status); |
876 | 895 | ||
877 | /* Decode reply count and EOF flag. NFSv3 is somewhat redundant | 896 | /* Decode reply count and EOF flag. NFSv3 is somewhat redundant |
878 | * in that it puts the count both in the res struct and in the | 897 | * in that it puts the count both in the res struct and in the |
@@ -922,7 +941,7 @@ nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res) | |||
922 | p = xdr_decode_wcc_data(p, res->fattr); | 941 | p = xdr_decode_wcc_data(p, res->fattr); |
923 | 942 | ||
924 | if (status != 0) | 943 | if (status != 0) |
925 | return -nfs_stat_to_errno(status); | 944 | return nfs_stat_to_errno(status); |
926 | 945 | ||
927 | res->count = ntohl(*p++); | 946 | res->count = ntohl(*p++); |
928 | res->verf->committed = (enum nfs3_stable_how)ntohl(*p++); | 947 | res->verf->committed = (enum nfs3_stable_how)ntohl(*p++); |
@@ -953,7 +972,7 @@ nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res) | |||
953 | res->fattr->valid = 0; | 972 | res->fattr->valid = 0; |
954 | } | 973 | } |
955 | } else { | 974 | } else { |
956 | status = -nfs_stat_to_errno(status); | 975 | status = nfs_stat_to_errno(status); |
957 | } | 976 | } |
958 | p = xdr_decode_wcc_data(p, res->dir_attr); | 977 | p = xdr_decode_wcc_data(p, res->dir_attr); |
959 | return status; | 978 | return status; |
@@ -968,7 +987,7 @@ nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs3_renameres *res) | |||
968 | int status; | 987 | int status; |
969 | 988 | ||
970 | if ((status = ntohl(*p++)) != 0) | 989 | if ((status = ntohl(*p++)) != 0) |
971 | status = -nfs_stat_to_errno(status); | 990 | status = nfs_stat_to_errno(status); |
972 | p = xdr_decode_wcc_data(p, res->fromattr); | 991 | p = xdr_decode_wcc_data(p, res->fromattr); |
973 | p = xdr_decode_wcc_data(p, res->toattr); | 992 | p = xdr_decode_wcc_data(p, res->toattr); |
974 | return status; | 993 | return status; |
@@ -983,7 +1002,7 @@ nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res) | |||
983 | int status; | 1002 | int status; |
984 | 1003 | ||
985 | if ((status = ntohl(*p++)) != 0) | 1004 | if ((status = ntohl(*p++)) != 0) |
986 | status = -nfs_stat_to_errno(status); | 1005 | status = nfs_stat_to_errno(status); |
987 | p = xdr_decode_post_op_attr(p, res->fattr); | 1006 | p = xdr_decode_post_op_attr(p, res->fattr); |
988 | p = xdr_decode_wcc_data(p, res->dir_attr); | 1007 | p = xdr_decode_wcc_data(p, res->dir_attr); |
989 | return status; | 1008 | return status; |
@@ -1001,7 +1020,7 @@ nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res) | |||
1001 | 1020 | ||
1002 | p = xdr_decode_post_op_attr(p, res->fattr); | 1021 | p = xdr_decode_post_op_attr(p, res->fattr); |
1003 | if (status != 0) | 1022 | if (status != 0) |
1004 | return -nfs_stat_to_errno(status); | 1023 | return nfs_stat_to_errno(status); |
1005 | 1024 | ||
1006 | p = xdr_decode_hyper(p, &res->tbytes); | 1025 | p = xdr_decode_hyper(p, &res->tbytes); |
1007 | p = xdr_decode_hyper(p, &res->fbytes); | 1026 | p = xdr_decode_hyper(p, &res->fbytes); |
@@ -1026,7 +1045,7 @@ nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res) | |||
1026 | 1045 | ||
1027 | p = xdr_decode_post_op_attr(p, res->fattr); | 1046 | p = xdr_decode_post_op_attr(p, res->fattr); |
1028 | if (status != 0) | 1047 | if (status != 0) |
1029 | return -nfs_stat_to_errno(status); | 1048 | return nfs_stat_to_errno(status); |
1030 | 1049 | ||
1031 | res->rtmax = ntohl(*p++); | 1050 | res->rtmax = ntohl(*p++); |
1032 | res->rtpref = ntohl(*p++); | 1051 | res->rtpref = ntohl(*p++); |
@@ -1054,7 +1073,7 @@ nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res) | |||
1054 | 1073 | ||
1055 | p = xdr_decode_post_op_attr(p, res->fattr); | 1074 | p = xdr_decode_post_op_attr(p, res->fattr); |
1056 | if (status != 0) | 1075 | if (status != 0) |
1057 | return -nfs_stat_to_errno(status); | 1076 | return nfs_stat_to_errno(status); |
1058 | res->max_link = ntohl(*p++); | 1077 | res->max_link = ntohl(*p++); |
1059 | res->max_namelen = ntohl(*p++); | 1078 | res->max_namelen = ntohl(*p++); |
1060 | 1079 | ||
@@ -1073,7 +1092,7 @@ nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res) | |||
1073 | status = ntohl(*p++); | 1092 | status = ntohl(*p++); |
1074 | p = xdr_decode_wcc_data(p, res->fattr); | 1093 | p = xdr_decode_wcc_data(p, res->fattr); |
1075 | if (status != 0) | 1094 | if (status != 0) |
1076 | return -nfs_stat_to_errno(status); | 1095 | return nfs_stat_to_errno(status); |
1077 | 1096 | ||
1078 | res->verf->verifier[0] = *p++; | 1097 | res->verf->verifier[0] = *p++; |
1079 | res->verf->verifier[1] = *p++; | 1098 | res->verf->verifier[1] = *p++; |
@@ -1095,7 +1114,7 @@ nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p, | |||
1095 | int err, base; | 1114 | int err, base; |
1096 | 1115 | ||
1097 | if (status != 0) | 1116 | if (status != 0) |
1098 | return -nfs_stat_to_errno(status); | 1117 | return nfs_stat_to_errno(status); |
1099 | p = xdr_decode_post_op_attr(p, res->fattr); | 1118 | p = xdr_decode_post_op_attr(p, res->fattr); |
1100 | res->mask = ntohl(*p++); | 1119 | res->mask = ntohl(*p++); |
1101 | if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) | 1120 | if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) |
@@ -1122,7 +1141,7 @@ nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) | |||
1122 | int status = ntohl(*p++); | 1141 | int status = ntohl(*p++); |
1123 | 1142 | ||
1124 | if (status) | 1143 | if (status) |
1125 | return -nfs_stat_to_errno(status); | 1144 | return nfs_stat_to_errno(status); |
1126 | xdr_decode_post_op_attr(p, fattr); | 1145 | xdr_decode_post_op_attr(p, fattr); |
1127 | return 0; | 1146 | return 0; |
1128 | } | 1147 | } |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 7ce07862c2fb..dbc09271af02 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -51,6 +51,7 @@ | |||
51 | 51 | ||
52 | #include "nfs4_fs.h" | 52 | #include "nfs4_fs.h" |
53 | #include "delegation.h" | 53 | #include "delegation.h" |
54 | #include "internal.h" | ||
54 | #include "iostat.h" | 55 | #include "iostat.h" |
55 | 56 | ||
56 | #define NFSDBG_FACILITY NFSDBG_PROC | 57 | #define NFSDBG_FACILITY NFSDBG_PROC |
@@ -239,6 +240,8 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p) | |||
239 | { | 240 | { |
240 | p->o_res.f_attr = &p->f_attr; | 241 | p->o_res.f_attr = &p->f_attr; |
241 | p->o_res.dir_attr = &p->dir_attr; | 242 | p->o_res.dir_attr = &p->dir_attr; |
243 | p->o_res.seqid = p->o_arg.seqid; | ||
244 | p->c_res.seqid = p->c_arg.seqid; | ||
242 | p->o_res.server = p->o_arg.server; | 245 | p->o_res.server = p->o_arg.server; |
243 | nfs_fattr_init(&p->f_attr); | 246 | nfs_fattr_init(&p->f_attr); |
244 | nfs_fattr_init(&p->dir_attr); | 247 | nfs_fattr_init(&p->dir_attr); |
@@ -729,7 +732,6 @@ static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata) | |||
729 | renew_lease(data->o_res.server, data->timestamp); | 732 | renew_lease(data->o_res.server, data->timestamp); |
730 | data->rpc_done = 1; | 733 | data->rpc_done = 1; |
731 | } | 734 | } |
732 | nfs_increment_open_seqid(data->rpc_status, data->c_arg.seqid); | ||
733 | } | 735 | } |
734 | 736 | ||
735 | static void nfs4_open_confirm_release(void *calldata) | 737 | static void nfs4_open_confirm_release(void *calldata) |
@@ -773,6 +775,7 @@ static int _nfs4_proc_open_confirm(struct nfs4_opendata *data) | |||
773 | .rpc_message = &msg, | 775 | .rpc_message = &msg, |
774 | .callback_ops = &nfs4_open_confirm_ops, | 776 | .callback_ops = &nfs4_open_confirm_ops, |
775 | .callback_data = data, | 777 | .callback_data = data, |
778 | .workqueue = nfsiod_workqueue, | ||
776 | .flags = RPC_TASK_ASYNC, | 779 | .flags = RPC_TASK_ASYNC, |
777 | }; | 780 | }; |
778 | int status; | 781 | int status; |
@@ -858,7 +861,6 @@ static void nfs4_open_done(struct rpc_task *task, void *calldata) | |||
858 | if (!(data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM)) | 861 | if (!(data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM)) |
859 | nfs_confirm_seqid(&data->owner->so_seqid, 0); | 862 | nfs_confirm_seqid(&data->owner->so_seqid, 0); |
860 | } | 863 | } |
861 | nfs_increment_open_seqid(data->rpc_status, data->o_arg.seqid); | ||
862 | data->rpc_done = 1; | 864 | data->rpc_done = 1; |
863 | } | 865 | } |
864 | 866 | ||
@@ -910,6 +912,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) | |||
910 | .rpc_message = &msg, | 912 | .rpc_message = &msg, |
911 | .callback_ops = &nfs4_open_ops, | 913 | .callback_ops = &nfs4_open_ops, |
912 | .callback_data = data, | 914 | .callback_data = data, |
915 | .workqueue = nfsiod_workqueue, | ||
913 | .flags = RPC_TASK_ASYNC, | 916 | .flags = RPC_TASK_ASYNC, |
914 | }; | 917 | }; |
915 | int status; | 918 | int status; |
@@ -979,11 +982,8 @@ static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *s | |||
979 | if (IS_ERR(opendata)) | 982 | if (IS_ERR(opendata)) |
980 | return PTR_ERR(opendata); | 983 | return PTR_ERR(opendata); |
981 | ret = nfs4_open_recover(opendata, state); | 984 | ret = nfs4_open_recover(opendata, state); |
982 | if (ret == -ESTALE) { | 985 | if (ret == -ESTALE) |
983 | /* Invalidate the state owner so we don't ever use it again */ | ||
984 | nfs4_drop_state_owner(state->owner); | ||
985 | d_drop(ctx->path.dentry); | 986 | d_drop(ctx->path.dentry); |
986 | } | ||
987 | nfs4_opendata_put(opendata); | 987 | nfs4_opendata_put(opendata); |
988 | return ret; | 988 | return ret; |
989 | } | 989 | } |
@@ -1226,7 +1226,6 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
1226 | /* hmm. we are done with the inode, and in the process of freeing | 1226 | /* hmm. we are done with the inode, and in the process of freeing |
1227 | * the state_owner. we keep this around to process errors | 1227 | * the state_owner. we keep this around to process errors |
1228 | */ | 1228 | */ |
1229 | nfs_increment_open_seqid(task->tk_status, calldata->arg.seqid); | ||
1230 | switch (task->tk_status) { | 1229 | switch (task->tk_status) { |
1231 | case 0: | 1230 | case 0: |
1232 | nfs_set_open_stateid(state, &calldata->res.stateid, 0); | 1231 | nfs_set_open_stateid(state, &calldata->res.stateid, 0); |
@@ -1315,6 +1314,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
1315 | .rpc_client = server->client, | 1314 | .rpc_client = server->client, |
1316 | .rpc_message = &msg, | 1315 | .rpc_message = &msg, |
1317 | .callback_ops = &nfs4_close_ops, | 1316 | .callback_ops = &nfs4_close_ops, |
1317 | .workqueue = nfsiod_workqueue, | ||
1318 | .flags = RPC_TASK_ASYNC, | 1318 | .flags = RPC_TASK_ASYNC, |
1319 | }; | 1319 | }; |
1320 | int status = -ENOMEM; | 1320 | int status = -ENOMEM; |
@@ -1332,6 +1332,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
1332 | goto out_free_calldata; | 1332 | goto out_free_calldata; |
1333 | calldata->arg.bitmask = server->attr_bitmask; | 1333 | calldata->arg.bitmask = server->attr_bitmask; |
1334 | calldata->res.fattr = &calldata->fattr; | 1334 | calldata->res.fattr = &calldata->fattr; |
1335 | calldata->res.seqid = calldata->arg.seqid; | ||
1335 | calldata->res.server = server; | 1336 | calldata->res.server = server; |
1336 | calldata->path.mnt = mntget(path->mnt); | 1337 | calldata->path.mnt = mntget(path->mnt); |
1337 | calldata->path.dentry = dget(path->dentry); | 1338 | calldata->path.dentry = dget(path->dentry); |
@@ -1404,7 +1405,7 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | |||
1404 | BUG_ON(nd->intent.open.flags & O_CREAT); | 1405 | BUG_ON(nd->intent.open.flags & O_CREAT); |
1405 | } | 1406 | } |
1406 | 1407 | ||
1407 | cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); | 1408 | cred = rpc_lookup_cred(); |
1408 | if (IS_ERR(cred)) | 1409 | if (IS_ERR(cred)) |
1409 | return (struct dentry *)cred; | 1410 | return (struct dentry *)cred; |
1410 | parent = dentry->d_parent; | 1411 | parent = dentry->d_parent; |
@@ -1439,7 +1440,7 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st | |||
1439 | struct rpc_cred *cred; | 1440 | struct rpc_cred *cred; |
1440 | struct nfs4_state *state; | 1441 | struct nfs4_state *state; |
1441 | 1442 | ||
1442 | cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); | 1443 | cred = rpc_lookup_cred(); |
1443 | if (IS_ERR(cred)) | 1444 | if (IS_ERR(cred)) |
1444 | return PTR_ERR(cred); | 1445 | return PTR_ERR(cred); |
1445 | state = nfs4_do_open(dir, &path, openflags, NULL, cred); | 1446 | state = nfs4_do_open(dir, &path, openflags, NULL, cred); |
@@ -1656,7 +1657,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | |||
1656 | 1657 | ||
1657 | nfs_fattr_init(fattr); | 1658 | nfs_fattr_init(fattr); |
1658 | 1659 | ||
1659 | cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0); | 1660 | cred = rpc_lookup_cred(); |
1660 | if (IS_ERR(cred)) | 1661 | if (IS_ERR(cred)) |
1661 | return PTR_ERR(cred); | 1662 | return PTR_ERR(cred); |
1662 | 1663 | ||
@@ -1892,7 +1893,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
1892 | struct rpc_cred *cred; | 1893 | struct rpc_cred *cred; |
1893 | int status = 0; | 1894 | int status = 0; |
1894 | 1895 | ||
1895 | cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); | 1896 | cred = rpc_lookup_cred(); |
1896 | if (IS_ERR(cred)) { | 1897 | if (IS_ERR(cred)) { |
1897 | status = PTR_ERR(cred); | 1898 | status = PTR_ERR(cred); |
1898 | goto out; | 1899 | goto out; |
@@ -2761,10 +2762,10 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server) | |||
2761 | case -NFS4ERR_STALE_CLIENTID: | 2762 | case -NFS4ERR_STALE_CLIENTID: |
2762 | case -NFS4ERR_STALE_STATEID: | 2763 | case -NFS4ERR_STALE_STATEID: |
2763 | case -NFS4ERR_EXPIRED: | 2764 | case -NFS4ERR_EXPIRED: |
2764 | rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL, NULL); | 2765 | rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL); |
2765 | nfs4_schedule_state_recovery(clp); | 2766 | nfs4_schedule_state_recovery(clp); |
2766 | if (test_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) == 0) | 2767 | if (test_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) == 0) |
2767 | rpc_wake_up_task(task); | 2768 | rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task); |
2768 | task->tk_status = 0; | 2769 | task->tk_status = 0; |
2769 | return -EAGAIN; | 2770 | return -EAGAIN; |
2770 | case -NFS4ERR_DELAY: | 2771 | case -NFS4ERR_DELAY: |
@@ -2884,7 +2885,7 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short po | |||
2884 | RPC_DISPLAY_ADDR), | 2885 | RPC_DISPLAY_ADDR), |
2885 | rpc_peeraddr2str(clp->cl_rpcclient, | 2886 | rpc_peeraddr2str(clp->cl_rpcclient, |
2886 | RPC_DISPLAY_PROTO), | 2887 | RPC_DISPLAY_PROTO), |
2887 | cred->cr_ops->cr_name, | 2888 | clp->cl_rpcclient->cl_auth->au_ops->au_name, |
2888 | clp->cl_id_uniquifier); | 2889 | clp->cl_id_uniquifier); |
2889 | setclientid.sc_netid_len = scnprintf(setclientid.sc_netid, | 2890 | setclientid.sc_netid_len = scnprintf(setclientid.sc_netid, |
2890 | sizeof(setclientid.sc_netid), | 2891 | sizeof(setclientid.sc_netid), |
@@ -3158,6 +3159,7 @@ static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl, | |||
3158 | p->arg.fh = NFS_FH(inode); | 3159 | p->arg.fh = NFS_FH(inode); |
3159 | p->arg.fl = &p->fl; | 3160 | p->arg.fl = &p->fl; |
3160 | p->arg.seqid = seqid; | 3161 | p->arg.seqid = seqid; |
3162 | p->res.seqid = seqid; | ||
3161 | p->arg.stateid = &lsp->ls_stateid; | 3163 | p->arg.stateid = &lsp->ls_stateid; |
3162 | p->lsp = lsp; | 3164 | p->lsp = lsp; |
3163 | atomic_inc(&lsp->ls_count); | 3165 | atomic_inc(&lsp->ls_count); |
@@ -3183,7 +3185,6 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) | |||
3183 | 3185 | ||
3184 | if (RPC_ASSASSINATED(task)) | 3186 | if (RPC_ASSASSINATED(task)) |
3185 | return; | 3187 | return; |
3186 | nfs_increment_lock_seqid(task->tk_status, calldata->arg.seqid); | ||
3187 | switch (task->tk_status) { | 3188 | switch (task->tk_status) { |
3188 | case 0: | 3189 | case 0: |
3189 | memcpy(calldata->lsp->ls_stateid.data, | 3190 | memcpy(calldata->lsp->ls_stateid.data, |
@@ -3235,6 +3236,7 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl, | |||
3235 | .rpc_client = NFS_CLIENT(lsp->ls_state->inode), | 3236 | .rpc_client = NFS_CLIENT(lsp->ls_state->inode), |
3236 | .rpc_message = &msg, | 3237 | .rpc_message = &msg, |
3237 | .callback_ops = &nfs4_locku_ops, | 3238 | .callback_ops = &nfs4_locku_ops, |
3239 | .workqueue = nfsiod_workqueue, | ||
3238 | .flags = RPC_TASK_ASYNC, | 3240 | .flags = RPC_TASK_ASYNC, |
3239 | }; | 3241 | }; |
3240 | 3242 | ||
@@ -3261,6 +3263,7 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock * | |||
3261 | struct nfs4_lock_state *lsp; | 3263 | struct nfs4_lock_state *lsp; |
3262 | struct rpc_task *task; | 3264 | struct rpc_task *task; |
3263 | int status = 0; | 3265 | int status = 0; |
3266 | unsigned char fl_flags = request->fl_flags; | ||
3264 | 3267 | ||
3265 | status = nfs4_set_lock_state(state, request); | 3268 | status = nfs4_set_lock_state(state, request); |
3266 | /* Unlock _before_ we do the RPC call */ | 3269 | /* Unlock _before_ we do the RPC call */ |
@@ -3284,6 +3287,7 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock * | |||
3284 | status = nfs4_wait_for_completion_rpc_task(task); | 3287 | status = nfs4_wait_for_completion_rpc_task(task); |
3285 | rpc_put_task(task); | 3288 | rpc_put_task(task); |
3286 | out: | 3289 | out: |
3290 | request->fl_flags = fl_flags; | ||
3287 | return status; | 3291 | return status; |
3288 | } | 3292 | } |
3289 | 3293 | ||
@@ -3320,6 +3324,7 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, | |||
3320 | p->arg.lock_stateid = &lsp->ls_stateid; | 3324 | p->arg.lock_stateid = &lsp->ls_stateid; |
3321 | p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; | 3325 | p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; |
3322 | p->arg.lock_owner.id = lsp->ls_id.id; | 3326 | p->arg.lock_owner.id = lsp->ls_id.id; |
3327 | p->res.lock_seqid = p->arg.lock_seqid; | ||
3323 | p->lsp = lsp; | 3328 | p->lsp = lsp; |
3324 | atomic_inc(&lsp->ls_count); | 3329 | atomic_inc(&lsp->ls_count); |
3325 | p->ctx = get_nfs_open_context(ctx); | 3330 | p->ctx = get_nfs_open_context(ctx); |
@@ -3346,6 +3351,7 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata) | |||
3346 | return; | 3351 | return; |
3347 | data->arg.open_stateid = &state->stateid; | 3352 | data->arg.open_stateid = &state->stateid; |
3348 | data->arg.new_lock_owner = 1; | 3353 | data->arg.new_lock_owner = 1; |
3354 | data->res.open_seqid = data->arg.open_seqid; | ||
3349 | } else | 3355 | } else |
3350 | data->arg.new_lock_owner = 0; | 3356 | data->arg.new_lock_owner = 0; |
3351 | data->timestamp = jiffies; | 3357 | data->timestamp = jiffies; |
@@ -3363,7 +3369,6 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata) | |||
3363 | if (RPC_ASSASSINATED(task)) | 3369 | if (RPC_ASSASSINATED(task)) |
3364 | goto out; | 3370 | goto out; |
3365 | if (data->arg.new_lock_owner != 0) { | 3371 | if (data->arg.new_lock_owner != 0) { |
3366 | nfs_increment_open_seqid(data->rpc_status, data->arg.open_seqid); | ||
3367 | if (data->rpc_status == 0) | 3372 | if (data->rpc_status == 0) |
3368 | nfs_confirm_seqid(&data->lsp->ls_seqid, 0); | 3373 | nfs_confirm_seqid(&data->lsp->ls_seqid, 0); |
3369 | else | 3374 | else |
@@ -3375,7 +3380,6 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata) | |||
3375 | data->lsp->ls_flags |= NFS_LOCK_INITIALIZED; | 3380 | data->lsp->ls_flags |= NFS_LOCK_INITIALIZED; |
3376 | renew_lease(NFS_SERVER(data->ctx->path.dentry->d_inode), data->timestamp); | 3381 | renew_lease(NFS_SERVER(data->ctx->path.dentry->d_inode), data->timestamp); |
3377 | } | 3382 | } |
3378 | nfs_increment_lock_seqid(data->rpc_status, data->arg.lock_seqid); | ||
3379 | out: | 3383 | out: |
3380 | dprintk("%s: done, ret = %d!\n", __FUNCTION__, data->rpc_status); | 3384 | dprintk("%s: done, ret = %d!\n", __FUNCTION__, data->rpc_status); |
3381 | } | 3385 | } |
@@ -3419,6 +3423,7 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f | |||
3419 | .rpc_client = NFS_CLIENT(state->inode), | 3423 | .rpc_client = NFS_CLIENT(state->inode), |
3420 | .rpc_message = &msg, | 3424 | .rpc_message = &msg, |
3421 | .callback_ops = &nfs4_lock_ops, | 3425 | .callback_ops = &nfs4_lock_ops, |
3426 | .workqueue = nfsiod_workqueue, | ||
3422 | .flags = RPC_TASK_ASYNC, | 3427 | .flags = RPC_TASK_ASYNC, |
3423 | }; | 3428 | }; |
3424 | int ret; | 3429 | int ret; |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index b962397004c1..46eb624e4f16 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -71,6 +71,29 @@ static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred) | |||
71 | return status; | 71 | return status; |
72 | } | 72 | } |
73 | 73 | ||
74 | static struct rpc_cred *nfs4_get_machine_cred(struct nfs_client *clp) | ||
75 | { | ||
76 | struct rpc_cred *cred = NULL; | ||
77 | |||
78 | spin_lock(&clp->cl_lock); | ||
79 | if (clp->cl_machine_cred != NULL) | ||
80 | cred = get_rpccred(clp->cl_machine_cred); | ||
81 | spin_unlock(&clp->cl_lock); | ||
82 | return cred; | ||
83 | } | ||
84 | |||
85 | static void nfs4_clear_machine_cred(struct nfs_client *clp) | ||
86 | { | ||
87 | struct rpc_cred *cred; | ||
88 | |||
89 | spin_lock(&clp->cl_lock); | ||
90 | cred = clp->cl_machine_cred; | ||
91 | clp->cl_machine_cred = NULL; | ||
92 | spin_unlock(&clp->cl_lock); | ||
93 | if (cred != NULL) | ||
94 | put_rpccred(cred); | ||
95 | } | ||
96 | |||
74 | struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp) | 97 | struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp) |
75 | { | 98 | { |
76 | struct nfs4_state_owner *sp; | 99 | struct nfs4_state_owner *sp; |
@@ -91,13 +114,18 @@ static struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp) | |||
91 | { | 114 | { |
92 | struct nfs4_state_owner *sp; | 115 | struct nfs4_state_owner *sp; |
93 | struct rb_node *pos; | 116 | struct rb_node *pos; |
117 | struct rpc_cred *cred; | ||
94 | 118 | ||
119 | cred = nfs4_get_machine_cred(clp); | ||
120 | if (cred != NULL) | ||
121 | goto out; | ||
95 | pos = rb_first(&clp->cl_state_owners); | 122 | pos = rb_first(&clp->cl_state_owners); |
96 | if (pos != NULL) { | 123 | if (pos != NULL) { |
97 | sp = rb_entry(pos, struct nfs4_state_owner, so_client_node); | 124 | sp = rb_entry(pos, struct nfs4_state_owner, so_client_node); |
98 | return get_rpccred(sp->so_cred); | 125 | cred = get_rpccred(sp->so_cred); |
99 | } | 126 | } |
100 | return NULL; | 127 | out: |
128 | return cred; | ||
101 | } | 129 | } |
102 | 130 | ||
103 | static void nfs_alloc_unique_id(struct rb_root *root, struct nfs_unique_id *new, | 131 | static void nfs_alloc_unique_id(struct rb_root *root, struct nfs_unique_id *new, |
@@ -292,8 +320,10 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct | |||
292 | spin_unlock(&clp->cl_lock); | 320 | spin_unlock(&clp->cl_lock); |
293 | if (sp == new) | 321 | if (sp == new) |
294 | get_rpccred(cred); | 322 | get_rpccred(cred); |
295 | else | 323 | else { |
324 | rpc_destroy_wait_queue(&new->so_sequence.wait); | ||
296 | kfree(new); | 325 | kfree(new); |
326 | } | ||
297 | return sp; | 327 | return sp; |
298 | } | 328 | } |
299 | 329 | ||
@@ -310,6 +340,7 @@ void nfs4_put_state_owner(struct nfs4_state_owner *sp) | |||
310 | return; | 340 | return; |
311 | nfs4_remove_state_owner(clp, sp); | 341 | nfs4_remove_state_owner(clp, sp); |
312 | spin_unlock(&clp->cl_lock); | 342 | spin_unlock(&clp->cl_lock); |
343 | rpc_destroy_wait_queue(&sp->so_sequence.wait); | ||
313 | put_rpccred(cred); | 344 | put_rpccred(cred); |
314 | kfree(sp); | 345 | kfree(sp); |
315 | } | 346 | } |
@@ -529,6 +560,7 @@ static void nfs4_free_lock_state(struct nfs4_lock_state *lsp) | |||
529 | spin_lock(&clp->cl_lock); | 560 | spin_lock(&clp->cl_lock); |
530 | nfs_free_unique_id(&clp->cl_lockowner_id, &lsp->ls_id); | 561 | nfs_free_unique_id(&clp->cl_lockowner_id, &lsp->ls_id); |
531 | spin_unlock(&clp->cl_lock); | 562 | spin_unlock(&clp->cl_lock); |
563 | rpc_destroy_wait_queue(&lsp->ls_sequence.wait); | ||
532 | kfree(lsp); | 564 | kfree(lsp); |
533 | } | 565 | } |
534 | 566 | ||
@@ -731,7 +763,7 @@ int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task) | |||
731 | list_add_tail(&seqid->list, &sequence->list); | 763 | list_add_tail(&seqid->list, &sequence->list); |
732 | if (list_first_entry(&sequence->list, struct nfs_seqid, list) == seqid) | 764 | if (list_first_entry(&sequence->list, struct nfs_seqid, list) == seqid) |
733 | goto unlock; | 765 | goto unlock; |
734 | rpc_sleep_on(&sequence->wait, task, NULL, NULL); | 766 | rpc_sleep_on(&sequence->wait, task, NULL); |
735 | status = -EAGAIN; | 767 | status = -EAGAIN; |
736 | unlock: | 768 | unlock: |
737 | spin_unlock(&sequence->lock); | 769 | spin_unlock(&sequence->lock); |
@@ -920,10 +952,10 @@ restart_loop: | |||
920 | if (cred != NULL) { | 952 | if (cred != NULL) { |
921 | /* Yes there are: try to renew the old lease */ | 953 | /* Yes there are: try to renew the old lease */ |
922 | status = nfs4_proc_renew(clp, cred); | 954 | status = nfs4_proc_renew(clp, cred); |
955 | put_rpccred(cred); | ||
923 | switch (status) { | 956 | switch (status) { |
924 | case 0: | 957 | case 0: |
925 | case -NFS4ERR_CB_PATH_DOWN: | 958 | case -NFS4ERR_CB_PATH_DOWN: |
926 | put_rpccred(cred); | ||
927 | goto out; | 959 | goto out; |
928 | case -NFS4ERR_STALE_CLIENTID: | 960 | case -NFS4ERR_STALE_CLIENTID: |
929 | case -NFS4ERR_LEASE_MOVED: | 961 | case -NFS4ERR_LEASE_MOVED: |
@@ -932,14 +964,19 @@ restart_loop: | |||
932 | } else { | 964 | } else { |
933 | /* "reboot" to ensure we clear all state on the server */ | 965 | /* "reboot" to ensure we clear all state on the server */ |
934 | clp->cl_boot_time = CURRENT_TIME; | 966 | clp->cl_boot_time = CURRENT_TIME; |
935 | cred = nfs4_get_setclientid_cred(clp); | ||
936 | } | 967 | } |
937 | /* We're going to have to re-establish a clientid */ | 968 | /* We're going to have to re-establish a clientid */ |
938 | nfs4_state_mark_reclaim(clp); | 969 | nfs4_state_mark_reclaim(clp); |
939 | status = -ENOENT; | 970 | status = -ENOENT; |
971 | cred = nfs4_get_setclientid_cred(clp); | ||
940 | if (cred != NULL) { | 972 | if (cred != NULL) { |
941 | status = nfs4_init_client(clp, cred); | 973 | status = nfs4_init_client(clp, cred); |
942 | put_rpccred(cred); | 974 | put_rpccred(cred); |
975 | /* Handle case where the user hasn't set up machine creds */ | ||
976 | if (status == -EACCES && cred == clp->cl_machine_cred) { | ||
977 | nfs4_clear_machine_cred(clp); | ||
978 | goto restart_loop; | ||
979 | } | ||
943 | } | 980 | } |
944 | if (status) | 981 | if (status) |
945 | goto out_error; | 982 | goto out_error; |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index db1ed9c46ede..5a2d64927b35 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -110,7 +110,7 @@ static int nfs4_stat_to_errno(int); | |||
110 | #define decode_savefh_maxsz (op_decode_hdr_maxsz) | 110 | #define decode_savefh_maxsz (op_decode_hdr_maxsz) |
111 | #define encode_restorefh_maxsz (op_encode_hdr_maxsz) | 111 | #define encode_restorefh_maxsz (op_encode_hdr_maxsz) |
112 | #define decode_restorefh_maxsz (op_decode_hdr_maxsz) | 112 | #define decode_restorefh_maxsz (op_decode_hdr_maxsz) |
113 | #define encode_fsinfo_maxsz (op_encode_hdr_maxsz + 2) | 113 | #define encode_fsinfo_maxsz (encode_getattr_maxsz) |
114 | #define decode_fsinfo_maxsz (op_decode_hdr_maxsz + 11) | 114 | #define decode_fsinfo_maxsz (op_decode_hdr_maxsz + 11) |
115 | #define encode_renew_maxsz (op_encode_hdr_maxsz + 3) | 115 | #define encode_renew_maxsz (op_encode_hdr_maxsz + 3) |
116 | #define decode_renew_maxsz (op_decode_hdr_maxsz) | 116 | #define decode_renew_maxsz (op_decode_hdr_maxsz) |
@@ -1191,8 +1191,8 @@ static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg | |||
1191 | attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID; | 1191 | attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID; |
1192 | WRITE32(attrs[0] & readdir->bitmask[0]); | 1192 | WRITE32(attrs[0] & readdir->bitmask[0]); |
1193 | WRITE32(attrs[1] & readdir->bitmask[1]); | 1193 | WRITE32(attrs[1] & readdir->bitmask[1]); |
1194 | dprintk("%s: cookie = %Lu, verifier = 0x%x%x, bitmap = 0x%x%x\n", | 1194 | dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n", |
1195 | __FUNCTION__, | 1195 | __func__, |
1196 | (unsigned long long)readdir->cookie, | 1196 | (unsigned long long)readdir->cookie, |
1197 | ((u32 *)readdir->verifier.data)[0], | 1197 | ((u32 *)readdir->verifier.data)[0], |
1198 | ((u32 *)readdir->verifier.data)[1], | 1198 | ((u32 *)readdir->verifier.data)[1], |
@@ -2241,7 +2241,7 @@ static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) | |||
2241 | } | 2241 | } |
2242 | READ32(nfserr); | 2242 | READ32(nfserr); |
2243 | if (nfserr != NFS_OK) | 2243 | if (nfserr != NFS_OK) |
2244 | return -nfs4_stat_to_errno(nfserr); | 2244 | return nfs4_stat_to_errno(nfserr); |
2245 | return 0; | 2245 | return 0; |
2246 | } | 2246 | } |
2247 | 2247 | ||
@@ -2291,7 +2291,7 @@ static int decode_attr_supported(struct xdr_stream *xdr, uint32_t *bitmap, uint3 | |||
2291 | bitmap[0] &= ~FATTR4_WORD0_SUPPORTED_ATTRS; | 2291 | bitmap[0] &= ~FATTR4_WORD0_SUPPORTED_ATTRS; |
2292 | } else | 2292 | } else |
2293 | bitmask[0] = bitmask[1] = 0; | 2293 | bitmask[0] = bitmask[1] = 0; |
2294 | dprintk("%s: bitmask=0x%x%x\n", __FUNCTION__, bitmask[0], bitmask[1]); | 2294 | dprintk("%s: bitmask=%08x:%08x\n", __func__, bitmask[0], bitmask[1]); |
2295 | return 0; | 2295 | return 0; |
2296 | } | 2296 | } |
2297 | 2297 | ||
@@ -3005,6 +3005,8 @@ static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res) | |||
3005 | int status; | 3005 | int status; |
3006 | 3006 | ||
3007 | status = decode_op_hdr(xdr, OP_CLOSE); | 3007 | status = decode_op_hdr(xdr, OP_CLOSE); |
3008 | if (status != -EIO) | ||
3009 | nfs_increment_open_seqid(status, res->seqid); | ||
3008 | if (status) | 3010 | if (status) |
3009 | return status; | 3011 | return status; |
3010 | READ_BUF(NFS4_STATEID_SIZE); | 3012 | READ_BUF(NFS4_STATEID_SIZE); |
@@ -3296,11 +3298,17 @@ static int decode_lock(struct xdr_stream *xdr, struct nfs_lock_res *res) | |||
3296 | int status; | 3298 | int status; |
3297 | 3299 | ||
3298 | status = decode_op_hdr(xdr, OP_LOCK); | 3300 | status = decode_op_hdr(xdr, OP_LOCK); |
3301 | if (status == -EIO) | ||
3302 | goto out; | ||
3299 | if (status == 0) { | 3303 | if (status == 0) { |
3300 | READ_BUF(NFS4_STATEID_SIZE); | 3304 | READ_BUF(NFS4_STATEID_SIZE); |
3301 | COPYMEM(res->stateid.data, NFS4_STATEID_SIZE); | 3305 | COPYMEM(res->stateid.data, NFS4_STATEID_SIZE); |
3302 | } else if (status == -NFS4ERR_DENIED) | 3306 | } else if (status == -NFS4ERR_DENIED) |
3303 | return decode_lock_denied(xdr, NULL); | 3307 | status = decode_lock_denied(xdr, NULL); |
3308 | if (res->open_seqid != NULL) | ||
3309 | nfs_increment_open_seqid(status, res->open_seqid); | ||
3310 | nfs_increment_lock_seqid(status, res->lock_seqid); | ||
3311 | out: | ||
3304 | return status; | 3312 | return status; |
3305 | } | 3313 | } |
3306 | 3314 | ||
@@ -3319,6 +3327,8 @@ static int decode_locku(struct xdr_stream *xdr, struct nfs_locku_res *res) | |||
3319 | int status; | 3327 | int status; |
3320 | 3328 | ||
3321 | status = decode_op_hdr(xdr, OP_LOCKU); | 3329 | status = decode_op_hdr(xdr, OP_LOCKU); |
3330 | if (status != -EIO) | ||
3331 | nfs_increment_lock_seqid(status, res->seqid); | ||
3322 | if (status == 0) { | 3332 | if (status == 0) { |
3323 | READ_BUF(NFS4_STATEID_SIZE); | 3333 | READ_BUF(NFS4_STATEID_SIZE); |
3324 | COPYMEM(res->stateid.data, NFS4_STATEID_SIZE); | 3334 | COPYMEM(res->stateid.data, NFS4_STATEID_SIZE); |
@@ -3384,6 +3394,8 @@ static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res) | |||
3384 | int status; | 3394 | int status; |
3385 | 3395 | ||
3386 | status = decode_op_hdr(xdr, OP_OPEN); | 3396 | status = decode_op_hdr(xdr, OP_OPEN); |
3397 | if (status != -EIO) | ||
3398 | nfs_increment_open_seqid(status, res->seqid); | ||
3387 | if (status) | 3399 | if (status) |
3388 | return status; | 3400 | return status; |
3389 | READ_BUF(NFS4_STATEID_SIZE); | 3401 | READ_BUF(NFS4_STATEID_SIZE); |
@@ -3416,6 +3428,8 @@ static int decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmre | |||
3416 | int status; | 3428 | int status; |
3417 | 3429 | ||
3418 | status = decode_op_hdr(xdr, OP_OPEN_CONFIRM); | 3430 | status = decode_op_hdr(xdr, OP_OPEN_CONFIRM); |
3431 | if (status != -EIO) | ||
3432 | nfs_increment_open_seqid(status, res->seqid); | ||
3419 | if (status) | 3433 | if (status) |
3420 | return status; | 3434 | return status; |
3421 | READ_BUF(NFS4_STATEID_SIZE); | 3435 | READ_BUF(NFS4_STATEID_SIZE); |
@@ -3429,6 +3443,8 @@ static int decode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeres *re | |||
3429 | int status; | 3443 | int status; |
3430 | 3444 | ||
3431 | status = decode_op_hdr(xdr, OP_OPEN_DOWNGRADE); | 3445 | status = decode_op_hdr(xdr, OP_OPEN_DOWNGRADE); |
3446 | if (status != -EIO) | ||
3447 | nfs_increment_open_seqid(status, res->seqid); | ||
3432 | if (status) | 3448 | if (status) |
3433 | return status; | 3449 | return status; |
3434 | READ_BUF(NFS4_STATEID_SIZE); | 3450 | READ_BUF(NFS4_STATEID_SIZE); |
@@ -3481,7 +3497,7 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n | |||
3481 | size_t hdrlen; | 3497 | size_t hdrlen; |
3482 | u32 recvd, pglen = rcvbuf->page_len; | 3498 | u32 recvd, pglen = rcvbuf->page_len; |
3483 | __be32 *end, *entry, *p, *kaddr; | 3499 | __be32 *end, *entry, *p, *kaddr; |
3484 | unsigned int nr; | 3500 | unsigned int nr = 0; |
3485 | int status; | 3501 | int status; |
3486 | 3502 | ||
3487 | status = decode_op_hdr(xdr, OP_READDIR); | 3503 | status = decode_op_hdr(xdr, OP_READDIR); |
@@ -3489,8 +3505,8 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n | |||
3489 | return status; | 3505 | return status; |
3490 | READ_BUF(8); | 3506 | READ_BUF(8); |
3491 | COPYMEM(readdir->verifier.data, 8); | 3507 | COPYMEM(readdir->verifier.data, 8); |
3492 | dprintk("%s: verifier = 0x%x%x\n", | 3508 | dprintk("%s: verifier = %08x:%08x\n", |
3493 | __FUNCTION__, | 3509 | __func__, |
3494 | ((u32 *)readdir->verifier.data)[0], | 3510 | ((u32 *)readdir->verifier.data)[0], |
3495 | ((u32 *)readdir->verifier.data)[1]); | 3511 | ((u32 *)readdir->verifier.data)[1]); |
3496 | 3512 | ||
@@ -3505,7 +3521,12 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n | |||
3505 | kaddr = p = kmap_atomic(page, KM_USER0); | 3521 | kaddr = p = kmap_atomic(page, KM_USER0); |
3506 | end = p + ((pglen + readdir->pgbase) >> 2); | 3522 | end = p + ((pglen + readdir->pgbase) >> 2); |
3507 | entry = p; | 3523 | entry = p; |
3508 | for (nr = 0; *p++; nr++) { | 3524 | |
3525 | /* Make sure the packet actually has a value_follows and EOF entry */ | ||
3526 | if ((entry + 1) > end) | ||
3527 | goto short_pkt; | ||
3528 | |||
3529 | for (; *p++; nr++) { | ||
3509 | u32 len, attrlen, xlen; | 3530 | u32 len, attrlen, xlen; |
3510 | if (end - p < 3) | 3531 | if (end - p < 3) |
3511 | goto short_pkt; | 3532 | goto short_pkt; |
@@ -3532,20 +3553,32 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n | |||
3532 | p += attrlen; /* attributes */ | 3553 | p += attrlen; /* attributes */ |
3533 | entry = p; | 3554 | entry = p; |
3534 | } | 3555 | } |
3535 | if (!nr && (entry[0] != 0 || entry[1] == 0)) | 3556 | /* |
3536 | goto short_pkt; | 3557 | * Apparently some server sends responses that are a valid size, but |
3558 | * contain no entries, and have value_follows==0 and EOF==0. For | ||
3559 | * those, just set the EOF marker. | ||
3560 | */ | ||
3561 | if (!nr && entry[1] == 0) { | ||
3562 | dprintk("NFS: readdir reply truncated!\n"); | ||
3563 | entry[1] = 1; | ||
3564 | } | ||
3537 | out: | 3565 | out: |
3538 | kunmap_atomic(kaddr, KM_USER0); | 3566 | kunmap_atomic(kaddr, KM_USER0); |
3539 | return 0; | 3567 | return 0; |
3540 | short_pkt: | 3568 | short_pkt: |
3569 | /* | ||
3570 | * When we get a short packet there are 2 possibilities. We can | ||
3571 | * return an error, or fix up the response to look like a valid | ||
3572 | * response and return what we have so far. If there are no | ||
3573 | * entries and the packet was short, then return -EIO. If there | ||
3574 | * are valid entries in the response, return them and pretend that | ||
3575 | * the call was successful, but incomplete. The caller can retry the | ||
3576 | * readdir starting at the last cookie. | ||
3577 | */ | ||
3541 | dprintk("%s: short packet at entry %d\n", __FUNCTION__, nr); | 3578 | dprintk("%s: short packet at entry %d\n", __FUNCTION__, nr); |
3542 | entry[0] = entry[1] = 0; | 3579 | entry[0] = entry[1] = 0; |
3543 | /* truncate listing ? */ | 3580 | if (nr) |
3544 | if (!nr) { | 3581 | goto out; |
3545 | dprintk("NFS: readdir reply truncated!\n"); | ||
3546 | entry[1] = 1; | ||
3547 | } | ||
3548 | goto out; | ||
3549 | err_unmap: | 3582 | err_unmap: |
3550 | kunmap_atomic(kaddr, KM_USER0); | 3583 | kunmap_atomic(kaddr, KM_USER0); |
3551 | return -errno_NFSERR_IO; | 3584 | return -errno_NFSERR_IO; |
@@ -3727,7 +3760,7 @@ static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp) | |||
3727 | READ_BUF(len); | 3760 | READ_BUF(len); |
3728 | return -NFSERR_CLID_INUSE; | 3761 | return -NFSERR_CLID_INUSE; |
3729 | } else | 3762 | } else |
3730 | return -nfs4_stat_to_errno(nfserr); | 3763 | return nfs4_stat_to_errno(nfserr); |
3731 | 3764 | ||
3732 | return 0; | 3765 | return 0; |
3733 | } | 3766 | } |
@@ -4389,7 +4422,7 @@ static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs_fsinf | |||
4389 | if (!status) | 4422 | if (!status) |
4390 | status = decode_fsinfo(&xdr, fsinfo); | 4423 | status = decode_fsinfo(&xdr, fsinfo); |
4391 | if (!status) | 4424 | if (!status) |
4392 | status = -nfs4_stat_to_errno(hdr.status); | 4425 | status = nfs4_stat_to_errno(hdr.status); |
4393 | return status; | 4426 | return status; |
4394 | } | 4427 | } |
4395 | 4428 | ||
@@ -4479,7 +4512,7 @@ static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, __be32 *p, | |||
4479 | if (!status) | 4512 | if (!status) |
4480 | status = decode_setclientid(&xdr, clp); | 4513 | status = decode_setclientid(&xdr, clp); |
4481 | if (!status) | 4514 | if (!status) |
4482 | status = -nfs4_stat_to_errno(hdr.status); | 4515 | status = nfs4_stat_to_errno(hdr.status); |
4483 | return status; | 4516 | return status; |
4484 | } | 4517 | } |
4485 | 4518 | ||
@@ -4501,7 +4534,7 @@ static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, __be32 *p, str | |||
4501 | if (!status) | 4534 | if (!status) |
4502 | status = decode_fsinfo(&xdr, fsinfo); | 4535 | status = decode_fsinfo(&xdr, fsinfo); |
4503 | if (!status) | 4536 | if (!status) |
4504 | status = -nfs4_stat_to_errno(hdr.status); | 4537 | status = nfs4_stat_to_errno(hdr.status); |
4505 | return status; | 4538 | return status; |
4506 | } | 4539 | } |
4507 | 4540 | ||
@@ -4611,42 +4644,42 @@ static struct { | |||
4611 | int errno; | 4644 | int errno; |
4612 | } nfs_errtbl[] = { | 4645 | } nfs_errtbl[] = { |
4613 | { NFS4_OK, 0 }, | 4646 | { NFS4_OK, 0 }, |
4614 | { NFS4ERR_PERM, EPERM }, | 4647 | { NFS4ERR_PERM, -EPERM }, |
4615 | { NFS4ERR_NOENT, ENOENT }, | 4648 | { NFS4ERR_NOENT, -ENOENT }, |
4616 | { NFS4ERR_IO, errno_NFSERR_IO }, | 4649 | { NFS4ERR_IO, -errno_NFSERR_IO}, |
4617 | { NFS4ERR_NXIO, ENXIO }, | 4650 | { NFS4ERR_NXIO, -ENXIO }, |
4618 | { NFS4ERR_ACCESS, EACCES }, | 4651 | { NFS4ERR_ACCESS, -EACCES }, |
4619 | { NFS4ERR_EXIST, EEXIST }, | 4652 | { NFS4ERR_EXIST, -EEXIST }, |
4620 | { NFS4ERR_XDEV, EXDEV }, | 4653 | { NFS4ERR_XDEV, -EXDEV }, |
4621 | { NFS4ERR_NOTDIR, ENOTDIR }, | 4654 | { NFS4ERR_NOTDIR, -ENOTDIR }, |
4622 | { NFS4ERR_ISDIR, EISDIR }, | 4655 | { NFS4ERR_ISDIR, -EISDIR }, |
4623 | { NFS4ERR_INVAL, EINVAL }, | 4656 | { NFS4ERR_INVAL, -EINVAL }, |
4624 | { NFS4ERR_FBIG, EFBIG }, | 4657 | { NFS4ERR_FBIG, -EFBIG }, |
4625 | { NFS4ERR_NOSPC, ENOSPC }, | 4658 | { NFS4ERR_NOSPC, -ENOSPC }, |
4626 | { NFS4ERR_ROFS, EROFS }, | 4659 | { NFS4ERR_ROFS, -EROFS }, |
4627 | { NFS4ERR_MLINK, EMLINK }, | 4660 | { NFS4ERR_MLINK, -EMLINK }, |
4628 | { NFS4ERR_NAMETOOLONG, ENAMETOOLONG }, | 4661 | { NFS4ERR_NAMETOOLONG, -ENAMETOOLONG }, |
4629 | { NFS4ERR_NOTEMPTY, ENOTEMPTY }, | 4662 | { NFS4ERR_NOTEMPTY, -ENOTEMPTY }, |
4630 | { NFS4ERR_DQUOT, EDQUOT }, | 4663 | { NFS4ERR_DQUOT, -EDQUOT }, |
4631 | { NFS4ERR_STALE, ESTALE }, | 4664 | { NFS4ERR_STALE, -ESTALE }, |
4632 | { NFS4ERR_BADHANDLE, EBADHANDLE }, | 4665 | { NFS4ERR_BADHANDLE, -EBADHANDLE }, |
4633 | { NFS4ERR_BADOWNER, EINVAL }, | 4666 | { NFS4ERR_BADOWNER, -EINVAL }, |
4634 | { NFS4ERR_BADNAME, EINVAL }, | 4667 | { NFS4ERR_BADNAME, -EINVAL }, |
4635 | { NFS4ERR_BAD_COOKIE, EBADCOOKIE }, | 4668 | { NFS4ERR_BAD_COOKIE, -EBADCOOKIE }, |
4636 | { NFS4ERR_NOTSUPP, ENOTSUPP }, | 4669 | { NFS4ERR_NOTSUPP, -ENOTSUPP }, |
4637 | { NFS4ERR_TOOSMALL, ETOOSMALL }, | 4670 | { NFS4ERR_TOOSMALL, -ETOOSMALL }, |
4638 | { NFS4ERR_SERVERFAULT, ESERVERFAULT }, | 4671 | { NFS4ERR_SERVERFAULT, -ESERVERFAULT }, |
4639 | { NFS4ERR_BADTYPE, EBADTYPE }, | 4672 | { NFS4ERR_BADTYPE, -EBADTYPE }, |
4640 | { NFS4ERR_LOCKED, EAGAIN }, | 4673 | { NFS4ERR_LOCKED, -EAGAIN }, |
4641 | { NFS4ERR_RESOURCE, EREMOTEIO }, | 4674 | { NFS4ERR_RESOURCE, -EREMOTEIO }, |
4642 | { NFS4ERR_SYMLINK, ELOOP }, | 4675 | { NFS4ERR_SYMLINK, -ELOOP }, |
4643 | { NFS4ERR_OP_ILLEGAL, EOPNOTSUPP }, | 4676 | { NFS4ERR_OP_ILLEGAL, -EOPNOTSUPP }, |
4644 | { NFS4ERR_DEADLOCK, EDEADLK }, | 4677 | { NFS4ERR_DEADLOCK, -EDEADLK }, |
4645 | { NFS4ERR_WRONGSEC, EPERM }, /* FIXME: this needs | 4678 | { NFS4ERR_WRONGSEC, -EPERM }, /* FIXME: this needs |
4646 | * to be handled by a | 4679 | * to be handled by a |
4647 | * middle-layer. | 4680 | * middle-layer. |
4648 | */ | 4681 | */ |
4649 | { -1, EIO } | 4682 | { -1, -EIO } |
4650 | }; | 4683 | }; |
4651 | 4684 | ||
4652 | /* | 4685 | /* |
@@ -4663,14 +4696,14 @@ nfs4_stat_to_errno(int stat) | |||
4663 | } | 4696 | } |
4664 | if (stat <= 10000 || stat > 10100) { | 4697 | if (stat <= 10000 || stat > 10100) { |
4665 | /* The server is looney tunes. */ | 4698 | /* The server is looney tunes. */ |
4666 | return ESERVERFAULT; | 4699 | return -ESERVERFAULT; |
4667 | } | 4700 | } |
4668 | /* If we cannot translate the error, the recovery routines should | 4701 | /* If we cannot translate the error, the recovery routines should |
4669 | * handle it. | 4702 | * handle it. |
4670 | * Note: remaining NFSv4 error codes have values > 10000, so should | 4703 | * Note: remaining NFSv4 error codes have values > 10000, so should |
4671 | * not conflict with native Linux error codes. | 4704 | * not conflict with native Linux error codes. |
4672 | */ | 4705 | */ |
4673 | return stat; | 4706 | return -stat; |
4674 | } | 4707 | } |
4675 | 4708 | ||
4676 | #define PROC(proc, argtype, restype) \ | 4709 | #define PROC(proc, argtype, restype) \ |
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 5a70be589bbe..16f57e0af999 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
@@ -58,22 +58,19 @@ struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount) | |||
58 | return p; | 58 | return p; |
59 | } | 59 | } |
60 | 60 | ||
61 | static void nfs_readdata_rcu_free(struct rcu_head *head) | 61 | static void nfs_readdata_free(struct nfs_read_data *p) |
62 | { | 62 | { |
63 | struct nfs_read_data *p = container_of(head, struct nfs_read_data, task.u.tk_rcu); | ||
64 | if (p && (p->pagevec != &p->page_array[0])) | 63 | if (p && (p->pagevec != &p->page_array[0])) |
65 | kfree(p->pagevec); | 64 | kfree(p->pagevec); |
66 | mempool_free(p, nfs_rdata_mempool); | 65 | mempool_free(p, nfs_rdata_mempool); |
67 | } | 66 | } |
68 | 67 | ||
69 | static void nfs_readdata_free(struct nfs_read_data *rdata) | ||
70 | { | ||
71 | call_rcu_bh(&rdata->task.u.tk_rcu, nfs_readdata_rcu_free); | ||
72 | } | ||
73 | |||
74 | void nfs_readdata_release(void *data) | 68 | void nfs_readdata_release(void *data) |
75 | { | 69 | { |
76 | nfs_readdata_free(data); | 70 | struct nfs_read_data *rdata = data; |
71 | |||
72 | put_nfs_open_context(rdata->args.context); | ||
73 | nfs_readdata_free(rdata); | ||
77 | } | 74 | } |
78 | 75 | ||
79 | static | 76 | static |
@@ -156,7 +153,7 @@ static void nfs_readpage_release(struct nfs_page *req) | |||
156 | /* | 153 | /* |
157 | * Set up the NFS read request struct | 154 | * Set up the NFS read request struct |
158 | */ | 155 | */ |
159 | static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, | 156 | static int nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, |
160 | const struct rpc_call_ops *call_ops, | 157 | const struct rpc_call_ops *call_ops, |
161 | unsigned int count, unsigned int offset) | 158 | unsigned int count, unsigned int offset) |
162 | { | 159 | { |
@@ -174,6 +171,7 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, | |||
174 | .rpc_message = &msg, | 171 | .rpc_message = &msg, |
175 | .callback_ops = call_ops, | 172 | .callback_ops = call_ops, |
176 | .callback_data = data, | 173 | .callback_data = data, |
174 | .workqueue = nfsiod_workqueue, | ||
177 | .flags = RPC_TASK_ASYNC | swap_flags, | 175 | .flags = RPC_TASK_ASYNC | swap_flags, |
178 | }; | 176 | }; |
179 | 177 | ||
@@ -186,7 +184,7 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, | |||
186 | data->args.pgbase = req->wb_pgbase + offset; | 184 | data->args.pgbase = req->wb_pgbase + offset; |
187 | data->args.pages = data->pagevec; | 185 | data->args.pages = data->pagevec; |
188 | data->args.count = count; | 186 | data->args.count = count; |
189 | data->args.context = req->wb_context; | 187 | data->args.context = get_nfs_open_context(req->wb_context); |
190 | 188 | ||
191 | data->res.fattr = &data->fattr; | 189 | data->res.fattr = &data->fattr; |
192 | data->res.count = count; | 190 | data->res.count = count; |
@@ -204,8 +202,10 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, | |||
204 | (unsigned long long)data->args.offset); | 202 | (unsigned long long)data->args.offset); |
205 | 203 | ||
206 | task = rpc_run_task(&task_setup_data); | 204 | task = rpc_run_task(&task_setup_data); |
207 | if (!IS_ERR(task)) | 205 | if (IS_ERR(task)) |
208 | rpc_put_task(task); | 206 | return PTR_ERR(task); |
207 | rpc_put_task(task); | ||
208 | return 0; | ||
209 | } | 209 | } |
210 | 210 | ||
211 | static void | 211 | static void |
@@ -242,6 +242,7 @@ static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigne | |||
242 | size_t rsize = NFS_SERVER(inode)->rsize, nbytes; | 242 | size_t rsize = NFS_SERVER(inode)->rsize, nbytes; |
243 | unsigned int offset; | 243 | unsigned int offset; |
244 | int requests = 0; | 244 | int requests = 0; |
245 | int ret = 0; | ||
245 | LIST_HEAD(list); | 246 | LIST_HEAD(list); |
246 | 247 | ||
247 | nfs_list_remove_request(req); | 248 | nfs_list_remove_request(req); |
@@ -253,7 +254,6 @@ static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigne | |||
253 | data = nfs_readdata_alloc(1); | 254 | data = nfs_readdata_alloc(1); |
254 | if (!data) | 255 | if (!data) |
255 | goto out_bad; | 256 | goto out_bad; |
256 | INIT_LIST_HEAD(&data->pages); | ||
257 | list_add(&data->pages, &list); | 257 | list_add(&data->pages, &list); |
258 | requests++; | 258 | requests++; |
259 | nbytes -= len; | 259 | nbytes -= len; |
@@ -264,6 +264,8 @@ static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigne | |||
264 | offset = 0; | 264 | offset = 0; |
265 | nbytes = count; | 265 | nbytes = count; |
266 | do { | 266 | do { |
267 | int ret2; | ||
268 | |||
267 | data = list_entry(list.next, struct nfs_read_data, pages); | 269 | data = list_entry(list.next, struct nfs_read_data, pages); |
268 | list_del_init(&data->pages); | 270 | list_del_init(&data->pages); |
269 | 271 | ||
@@ -271,13 +273,15 @@ static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigne | |||
271 | 273 | ||
272 | if (nbytes < rsize) | 274 | if (nbytes < rsize) |
273 | rsize = nbytes; | 275 | rsize = nbytes; |
274 | nfs_read_rpcsetup(req, data, &nfs_read_partial_ops, | 276 | ret2 = nfs_read_rpcsetup(req, data, &nfs_read_partial_ops, |
275 | rsize, offset); | 277 | rsize, offset); |
278 | if (ret == 0) | ||
279 | ret = ret2; | ||
276 | offset += rsize; | 280 | offset += rsize; |
277 | nbytes -= rsize; | 281 | nbytes -= rsize; |
278 | } while (nbytes != 0); | 282 | } while (nbytes != 0); |
279 | 283 | ||
280 | return 0; | 284 | return ret; |
281 | 285 | ||
282 | out_bad: | 286 | out_bad: |
283 | while (!list_empty(&list)) { | 287 | while (!list_empty(&list)) { |
@@ -295,12 +299,12 @@ static int nfs_pagein_one(struct inode *inode, struct list_head *head, unsigned | |||
295 | struct nfs_page *req; | 299 | struct nfs_page *req; |
296 | struct page **pages; | 300 | struct page **pages; |
297 | struct nfs_read_data *data; | 301 | struct nfs_read_data *data; |
302 | int ret = -ENOMEM; | ||
298 | 303 | ||
299 | data = nfs_readdata_alloc(npages); | 304 | data = nfs_readdata_alloc(npages); |
300 | if (!data) | 305 | if (!data) |
301 | goto out_bad; | 306 | goto out_bad; |
302 | 307 | ||
303 | INIT_LIST_HEAD(&data->pages); | ||
304 | pages = data->pagevec; | 308 | pages = data->pagevec; |
305 | while (!list_empty(head)) { | 309 | while (!list_empty(head)) { |
306 | req = nfs_list_entry(head->next); | 310 | req = nfs_list_entry(head->next); |
@@ -311,11 +315,10 @@ static int nfs_pagein_one(struct inode *inode, struct list_head *head, unsigned | |||
311 | } | 315 | } |
312 | req = nfs_list_entry(data->pages.next); | 316 | req = nfs_list_entry(data->pages.next); |
313 | 317 | ||
314 | nfs_read_rpcsetup(req, data, &nfs_read_full_ops, count, 0); | 318 | return nfs_read_rpcsetup(req, data, &nfs_read_full_ops, count, 0); |
315 | return 0; | ||
316 | out_bad: | 319 | out_bad: |
317 | nfs_async_read_error(head); | 320 | nfs_async_read_error(head); |
318 | return -ENOMEM; | 321 | return ret; |
319 | } | 322 | } |
320 | 323 | ||
321 | /* | 324 | /* |
@@ -342,26 +345,25 @@ int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data) | |||
342 | return 0; | 345 | return 0; |
343 | } | 346 | } |
344 | 347 | ||
345 | static int nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data) | 348 | static void nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data) |
346 | { | 349 | { |
347 | struct nfs_readargs *argp = &data->args; | 350 | struct nfs_readargs *argp = &data->args; |
348 | struct nfs_readres *resp = &data->res; | 351 | struct nfs_readres *resp = &data->res; |
349 | 352 | ||
350 | if (resp->eof || resp->count == argp->count) | 353 | if (resp->eof || resp->count == argp->count) |
351 | return 0; | 354 | return; |
352 | 355 | ||
353 | /* This is a short read! */ | 356 | /* This is a short read! */ |
354 | nfs_inc_stats(data->inode, NFSIOS_SHORTREAD); | 357 | nfs_inc_stats(data->inode, NFSIOS_SHORTREAD); |
355 | /* Has the server at least made some progress? */ | 358 | /* Has the server at least made some progress? */ |
356 | if (resp->count == 0) | 359 | if (resp->count == 0) |
357 | return 0; | 360 | return; |
358 | 361 | ||
359 | /* Yes, so retry the read at the end of the data */ | 362 | /* Yes, so retry the read at the end of the data */ |
360 | argp->offset += resp->count; | 363 | argp->offset += resp->count; |
361 | argp->pgbase += resp->count; | 364 | argp->pgbase += resp->count; |
362 | argp->count -= resp->count; | 365 | argp->count -= resp->count; |
363 | rpc_restart_call(task); | 366 | rpc_restart_call(task); |
364 | return -EAGAIN; | ||
365 | } | 367 | } |
366 | 368 | ||
367 | /* | 369 | /* |
@@ -370,29 +372,37 @@ static int nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data) | |||
370 | static void nfs_readpage_result_partial(struct rpc_task *task, void *calldata) | 372 | static void nfs_readpage_result_partial(struct rpc_task *task, void *calldata) |
371 | { | 373 | { |
372 | struct nfs_read_data *data = calldata; | 374 | struct nfs_read_data *data = calldata; |
373 | struct nfs_page *req = data->req; | ||
374 | struct page *page = req->wb_page; | ||
375 | 375 | ||
376 | if (nfs_readpage_result(task, data) != 0) | 376 | if (nfs_readpage_result(task, data) != 0) |
377 | return; | 377 | return; |
378 | if (task->tk_status < 0) | ||
379 | return; | ||
378 | 380 | ||
379 | if (likely(task->tk_status >= 0)) { | 381 | nfs_readpage_truncate_uninitialised_page(data); |
380 | nfs_readpage_truncate_uninitialised_page(data); | 382 | nfs_readpage_retry(task, data); |
381 | if (nfs_readpage_retry(task, data) != 0) | 383 | } |
382 | return; | 384 | |
383 | } | 385 | static void nfs_readpage_release_partial(void *calldata) |
384 | if (unlikely(task->tk_status < 0)) | 386 | { |
387 | struct nfs_read_data *data = calldata; | ||
388 | struct nfs_page *req = data->req; | ||
389 | struct page *page = req->wb_page; | ||
390 | int status = data->task.tk_status; | ||
391 | |||
392 | if (status < 0) | ||
385 | SetPageError(page); | 393 | SetPageError(page); |
394 | |||
386 | if (atomic_dec_and_test(&req->wb_complete)) { | 395 | if (atomic_dec_and_test(&req->wb_complete)) { |
387 | if (!PageError(page)) | 396 | if (!PageError(page)) |
388 | SetPageUptodate(page); | 397 | SetPageUptodate(page); |
389 | nfs_readpage_release(req); | 398 | nfs_readpage_release(req); |
390 | } | 399 | } |
400 | nfs_readdata_release(calldata); | ||
391 | } | 401 | } |
392 | 402 | ||
393 | static const struct rpc_call_ops nfs_read_partial_ops = { | 403 | static const struct rpc_call_ops nfs_read_partial_ops = { |
394 | .rpc_call_done = nfs_readpage_result_partial, | 404 | .rpc_call_done = nfs_readpage_result_partial, |
395 | .rpc_release = nfs_readdata_release, | 405 | .rpc_release = nfs_readpage_release_partial, |
396 | }; | 406 | }; |
397 | 407 | ||
398 | static void nfs_readpage_set_pages_uptodate(struct nfs_read_data *data) | 408 | static void nfs_readpage_set_pages_uptodate(struct nfs_read_data *data) |
@@ -427,29 +437,35 @@ static void nfs_readpage_result_full(struct rpc_task *task, void *calldata) | |||
427 | 437 | ||
428 | if (nfs_readpage_result(task, data) != 0) | 438 | if (nfs_readpage_result(task, data) != 0) |
429 | return; | 439 | return; |
440 | if (task->tk_status < 0) | ||
441 | return; | ||
430 | /* | 442 | /* |
431 | * Note: nfs_readpage_retry may change the values of | 443 | * Note: nfs_readpage_retry may change the values of |
432 | * data->args. In the multi-page case, we therefore need | 444 | * data->args. In the multi-page case, we therefore need |
433 | * to ensure that we call nfs_readpage_set_pages_uptodate() | 445 | * to ensure that we call nfs_readpage_set_pages_uptodate() |
434 | * first. | 446 | * first. |
435 | */ | 447 | */ |
436 | if (likely(task->tk_status >= 0)) { | 448 | nfs_readpage_truncate_uninitialised_page(data); |
437 | nfs_readpage_truncate_uninitialised_page(data); | 449 | nfs_readpage_set_pages_uptodate(data); |
438 | nfs_readpage_set_pages_uptodate(data); | 450 | nfs_readpage_retry(task, data); |
439 | if (nfs_readpage_retry(task, data) != 0) | 451 | } |
440 | return; | 452 | |
441 | } | 453 | static void nfs_readpage_release_full(void *calldata) |
454 | { | ||
455 | struct nfs_read_data *data = calldata; | ||
456 | |||
442 | while (!list_empty(&data->pages)) { | 457 | while (!list_empty(&data->pages)) { |
443 | struct nfs_page *req = nfs_list_entry(data->pages.next); | 458 | struct nfs_page *req = nfs_list_entry(data->pages.next); |
444 | 459 | ||
445 | nfs_list_remove_request(req); | 460 | nfs_list_remove_request(req); |
446 | nfs_readpage_release(req); | 461 | nfs_readpage_release(req); |
447 | } | 462 | } |
463 | nfs_readdata_release(calldata); | ||
448 | } | 464 | } |
449 | 465 | ||
450 | static const struct rpc_call_ops nfs_read_full_ops = { | 466 | static const struct rpc_call_ops nfs_read_full_ops = { |
451 | .rpc_call_done = nfs_readpage_result_full, | 467 | .rpc_call_done = nfs_readpage_result_full, |
452 | .rpc_release = nfs_readdata_release, | 468 | .rpc_release = nfs_readpage_release_full, |
453 | }; | 469 | }; |
454 | 470 | ||
455 | /* | 471 | /* |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index f9219024f31a..20a1cb1810fe 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -441,10 +441,52 @@ static const char *nfs_pseudoflavour_to_name(rpc_authflavor_t flavour) | |||
441 | return sec_flavours[i].str; | 441 | return sec_flavours[i].str; |
442 | } | 442 | } |
443 | 443 | ||
444 | static void nfs_show_mountd_options(struct seq_file *m, struct nfs_server *nfss, | ||
445 | int showdefaults) | ||
446 | { | ||
447 | struct sockaddr *sap = (struct sockaddr *)&nfss->mountd_address; | ||
448 | |||
449 | switch (sap->sa_family) { | ||
450 | case AF_INET: { | ||
451 | struct sockaddr_in *sin = (struct sockaddr_in *)sap; | ||
452 | seq_printf(m, ",mountaddr=" NIPQUAD_FMT, | ||
453 | NIPQUAD(sin->sin_addr.s_addr)); | ||
454 | break; | ||
455 | } | ||
456 | case AF_INET6: { | ||
457 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; | ||
458 | seq_printf(m, ",mountaddr=" NIP6_FMT, | ||
459 | NIP6(sin6->sin6_addr)); | ||
460 | break; | ||
461 | } | ||
462 | default: | ||
463 | if (showdefaults) | ||
464 | seq_printf(m, ",mountaddr=unspecified"); | ||
465 | } | ||
466 | |||
467 | if (nfss->mountd_version || showdefaults) | ||
468 | seq_printf(m, ",mountvers=%u", nfss->mountd_version); | ||
469 | if (nfss->mountd_port || showdefaults) | ||
470 | seq_printf(m, ",mountport=%u", nfss->mountd_port); | ||
471 | |||
472 | switch (nfss->mountd_protocol) { | ||
473 | case IPPROTO_UDP: | ||
474 | seq_printf(m, ",mountproto=udp"); | ||
475 | break; | ||
476 | case IPPROTO_TCP: | ||
477 | seq_printf(m, ",mountproto=tcp"); | ||
478 | break; | ||
479 | default: | ||
480 | if (showdefaults) | ||
481 | seq_printf(m, ",mountproto=auto"); | ||
482 | } | ||
483 | } | ||
484 | |||
444 | /* | 485 | /* |
445 | * Describe the mount options in force on this server representation | 486 | * Describe the mount options in force on this server representation |
446 | */ | 487 | */ |
447 | static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, int showdefaults) | 488 | static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, |
489 | int showdefaults) | ||
448 | { | 490 | { |
449 | static const struct proc_nfs_info { | 491 | static const struct proc_nfs_info { |
450 | int flag; | 492 | int flag; |
@@ -452,6 +494,8 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
452 | const char *nostr; | 494 | const char *nostr; |
453 | } nfs_info[] = { | 495 | } nfs_info[] = { |
454 | { NFS_MOUNT_SOFT, ",soft", ",hard" }, | 496 | { NFS_MOUNT_SOFT, ",soft", ",hard" }, |
497 | { NFS_MOUNT_INTR, ",intr", ",nointr" }, | ||
498 | { NFS_MOUNT_POSIX, ",posix", "" }, | ||
455 | { NFS_MOUNT_NOCTO, ",nocto", "" }, | 499 | { NFS_MOUNT_NOCTO, ",nocto", "" }, |
456 | { NFS_MOUNT_NOAC, ",noac", "" }, | 500 | { NFS_MOUNT_NOAC, ",noac", "" }, |
457 | { NFS_MOUNT_NONLM, ",nolock", "" }, | 501 | { NFS_MOUNT_NONLM, ",nolock", "" }, |
@@ -462,18 +506,22 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
462 | }; | 506 | }; |
463 | const struct proc_nfs_info *nfs_infop; | 507 | const struct proc_nfs_info *nfs_infop; |
464 | struct nfs_client *clp = nfss->nfs_client; | 508 | struct nfs_client *clp = nfss->nfs_client; |
465 | 509 | u32 version = clp->rpc_ops->version; | |
466 | seq_printf(m, ",vers=%d", clp->rpc_ops->version); | 510 | |
467 | seq_printf(m, ",rsize=%d", nfss->rsize); | 511 | seq_printf(m, ",vers=%u", version); |
468 | seq_printf(m, ",wsize=%d", nfss->wsize); | 512 | seq_printf(m, ",rsize=%u", nfss->rsize); |
513 | seq_printf(m, ",wsize=%u", nfss->wsize); | ||
514 | if (nfss->bsize != 0) | ||
515 | seq_printf(m, ",bsize=%u", nfss->bsize); | ||
516 | seq_printf(m, ",namlen=%u", nfss->namelen); | ||
469 | if (nfss->acregmin != 3*HZ || showdefaults) | 517 | if (nfss->acregmin != 3*HZ || showdefaults) |
470 | seq_printf(m, ",acregmin=%d", nfss->acregmin/HZ); | 518 | seq_printf(m, ",acregmin=%u", nfss->acregmin/HZ); |
471 | if (nfss->acregmax != 60*HZ || showdefaults) | 519 | if (nfss->acregmax != 60*HZ || showdefaults) |
472 | seq_printf(m, ",acregmax=%d", nfss->acregmax/HZ); | 520 | seq_printf(m, ",acregmax=%u", nfss->acregmax/HZ); |
473 | if (nfss->acdirmin != 30*HZ || showdefaults) | 521 | if (nfss->acdirmin != 30*HZ || showdefaults) |
474 | seq_printf(m, ",acdirmin=%d", nfss->acdirmin/HZ); | 522 | seq_printf(m, ",acdirmin=%u", nfss->acdirmin/HZ); |
475 | if (nfss->acdirmax != 60*HZ || showdefaults) | 523 | if (nfss->acdirmax != 60*HZ || showdefaults) |
476 | seq_printf(m, ",acdirmax=%d", nfss->acdirmax/HZ); | 524 | seq_printf(m, ",acdirmax=%u", nfss->acdirmax/HZ); |
477 | for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) { | 525 | for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) { |
478 | if (nfss->flags & nfs_infop->flag) | 526 | if (nfss->flags & nfs_infop->flag) |
479 | seq_puts(m, nfs_infop->str); | 527 | seq_puts(m, nfs_infop->str); |
@@ -482,9 +530,24 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
482 | } | 530 | } |
483 | seq_printf(m, ",proto=%s", | 531 | seq_printf(m, ",proto=%s", |
484 | rpc_peeraddr2str(nfss->client, RPC_DISPLAY_PROTO)); | 532 | rpc_peeraddr2str(nfss->client, RPC_DISPLAY_PROTO)); |
533 | if (version == 4) { | ||
534 | if (nfss->port != NFS_PORT) | ||
535 | seq_printf(m, ",port=%u", nfss->port); | ||
536 | } else | ||
537 | if (nfss->port) | ||
538 | seq_printf(m, ",port=%u", nfss->port); | ||
539 | |||
485 | seq_printf(m, ",timeo=%lu", 10U * nfss->client->cl_timeout->to_initval / HZ); | 540 | seq_printf(m, ",timeo=%lu", 10U * nfss->client->cl_timeout->to_initval / HZ); |
486 | seq_printf(m, ",retrans=%u", nfss->client->cl_timeout->to_retries); | 541 | seq_printf(m, ",retrans=%u", nfss->client->cl_timeout->to_retries); |
487 | seq_printf(m, ",sec=%s", nfs_pseudoflavour_to_name(nfss->client->cl_auth->au_flavor)); | 542 | seq_printf(m, ",sec=%s", nfs_pseudoflavour_to_name(nfss->client->cl_auth->au_flavor)); |
543 | |||
544 | if (version != 4) | ||
545 | nfs_show_mountd_options(m, nfss, showdefaults); | ||
546 | |||
547 | #ifdef CONFIG_NFS_V4 | ||
548 | if (clp->rpc_ops->version == 4) | ||
549 | seq_printf(m, ",clientaddr=%s", clp->cl_ipaddr); | ||
550 | #endif | ||
488 | } | 551 | } |
489 | 552 | ||
490 | /* | 553 | /* |
@@ -529,10 +592,10 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt) | |||
529 | 592 | ||
530 | seq_printf(m, "\n\tcaps:\t"); | 593 | seq_printf(m, "\n\tcaps:\t"); |
531 | seq_printf(m, "caps=0x%x", nfss->caps); | 594 | seq_printf(m, "caps=0x%x", nfss->caps); |
532 | seq_printf(m, ",wtmult=%d", nfss->wtmult); | 595 | seq_printf(m, ",wtmult=%u", nfss->wtmult); |
533 | seq_printf(m, ",dtsize=%d", nfss->dtsize); | 596 | seq_printf(m, ",dtsize=%u", nfss->dtsize); |
534 | seq_printf(m, ",bsize=%d", nfss->bsize); | 597 | seq_printf(m, ",bsize=%u", nfss->bsize); |
535 | seq_printf(m, ",namelen=%d", nfss->namelen); | 598 | seq_printf(m, ",namlen=%u", nfss->namelen); |
536 | 599 | ||
537 | #ifdef CONFIG_NFS_V4 | 600 | #ifdef CONFIG_NFS_V4 |
538 | if (nfss->nfs_client->rpc_ops->version == 4) { | 601 | if (nfss->nfs_client->rpc_ops->version == 4) { |
@@ -546,9 +609,9 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt) | |||
546 | /* | 609 | /* |
547 | * Display security flavor in effect for this mount | 610 | * Display security flavor in effect for this mount |
548 | */ | 611 | */ |
549 | seq_printf(m, "\n\tsec:\tflavor=%d", auth->au_ops->au_flavor); | 612 | seq_printf(m, "\n\tsec:\tflavor=%u", auth->au_ops->au_flavor); |
550 | if (auth->au_flavor) | 613 | if (auth->au_flavor) |
551 | seq_printf(m, ",pseudoflavor=%d", auth->au_flavor); | 614 | seq_printf(m, ",pseudoflavor=%u", auth->au_flavor); |
552 | 615 | ||
553 | /* | 616 | /* |
554 | * Display superblock I/O counters | 617 | * Display superblock I/O counters |
@@ -683,7 +746,6 @@ static int nfs_parse_mount_options(char *raw, | |||
683 | struct nfs_parsed_mount_data *mnt) | 746 | struct nfs_parsed_mount_data *mnt) |
684 | { | 747 | { |
685 | char *p, *string, *secdata; | 748 | char *p, *string, *secdata; |
686 | unsigned short port = 0; | ||
687 | int rc; | 749 | int rc; |
688 | 750 | ||
689 | if (!raw) { | 751 | if (!raw) { |
@@ -798,7 +860,7 @@ static int nfs_parse_mount_options(char *raw, | |||
798 | return 0; | 860 | return 0; |
799 | if (option < 0 || option > 65535) | 861 | if (option < 0 || option > 65535) |
800 | return 0; | 862 | return 0; |
801 | port = option; | 863 | mnt->nfs_server.port = option; |
802 | break; | 864 | break; |
803 | case Opt_rsize: | 865 | case Opt_rsize: |
804 | if (match_int(args, &mnt->rsize)) | 866 | if (match_int(args, &mnt->rsize)) |
@@ -1048,7 +1110,8 @@ static int nfs_parse_mount_options(char *raw, | |||
1048 | } | 1110 | } |
1049 | } | 1111 | } |
1050 | 1112 | ||
1051 | nfs_set_port((struct sockaddr *)&mnt->nfs_server.address, port); | 1113 | nfs_set_port((struct sockaddr *)&mnt->nfs_server.address, |
1114 | mnt->nfs_server.port); | ||
1052 | 1115 | ||
1053 | return 1; | 1116 | return 1; |
1054 | 1117 | ||
@@ -1169,7 +1232,9 @@ static int nfs_validate_mount_data(void *options, | |||
1169 | args->acregmax = 60; | 1232 | args->acregmax = 60; |
1170 | args->acdirmin = 30; | 1233 | args->acdirmin = 30; |
1171 | args->acdirmax = 60; | 1234 | args->acdirmax = 60; |
1235 | args->mount_server.port = 0; /* autobind unless user sets port */ | ||
1172 | args->mount_server.protocol = XPRT_TRANSPORT_UDP; | 1236 | args->mount_server.protocol = XPRT_TRANSPORT_UDP; |
1237 | args->nfs_server.port = 0; /* autobind unless user sets port */ | ||
1173 | args->nfs_server.protocol = XPRT_TRANSPORT_TCP; | 1238 | args->nfs_server.protocol = XPRT_TRANSPORT_TCP; |
1174 | 1239 | ||
1175 | switch (data->version) { | 1240 | switch (data->version) { |
@@ -1208,7 +1273,6 @@ static int nfs_validate_mount_data(void *options, | |||
1208 | args->flags = data->flags; | 1273 | args->flags = data->flags; |
1209 | args->rsize = data->rsize; | 1274 | args->rsize = data->rsize; |
1210 | args->wsize = data->wsize; | 1275 | args->wsize = data->wsize; |
1211 | args->flags = data->flags; | ||
1212 | args->timeo = data->timeo; | 1276 | args->timeo = data->timeo; |
1213 | args->retrans = data->retrans; | 1277 | args->retrans = data->retrans; |
1214 | args->acregmin = data->acregmin; | 1278 | args->acregmin = data->acregmin; |
@@ -1230,6 +1294,8 @@ static int nfs_validate_mount_data(void *options, | |||
1230 | args->namlen = data->namlen; | 1294 | args->namlen = data->namlen; |
1231 | args->bsize = data->bsize; | 1295 | args->bsize = data->bsize; |
1232 | args->auth_flavors[0] = data->pseudoflavor; | 1296 | args->auth_flavors[0] = data->pseudoflavor; |
1297 | if (!args->nfs_server.hostname) | ||
1298 | goto out_nomem; | ||
1233 | 1299 | ||
1234 | /* | 1300 | /* |
1235 | * The legacy version 6 binary mount data from userspace has a | 1301 | * The legacy version 6 binary mount data from userspace has a |
@@ -1276,6 +1342,8 @@ static int nfs_validate_mount_data(void *options, | |||
1276 | len = c - dev_name; | 1342 | len = c - dev_name; |
1277 | /* N.B. caller will free nfs_server.hostname in all cases */ | 1343 | /* N.B. caller will free nfs_server.hostname in all cases */ |
1278 | args->nfs_server.hostname = kstrndup(dev_name, len, GFP_KERNEL); | 1344 | args->nfs_server.hostname = kstrndup(dev_name, len, GFP_KERNEL); |
1345 | if (!args->nfs_server.hostname) | ||
1346 | goto out_nomem; | ||
1279 | 1347 | ||
1280 | c++; | 1348 | c++; |
1281 | if (strlen(c) > NFS_MAXPATHLEN) | 1349 | if (strlen(c) > NFS_MAXPATHLEN) |
@@ -1319,6 +1387,10 @@ out_v3_not_compiled: | |||
1319 | return -EPROTONOSUPPORT; | 1387 | return -EPROTONOSUPPORT; |
1320 | #endif /* !CONFIG_NFS_V3 */ | 1388 | #endif /* !CONFIG_NFS_V3 */ |
1321 | 1389 | ||
1390 | out_nomem: | ||
1391 | dfprintk(MOUNT, "NFS: not enough memory to handle mount options\n"); | ||
1392 | return -ENOMEM; | ||
1393 | |||
1322 | out_no_address: | 1394 | out_no_address: |
1323 | dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n"); | 1395 | dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n"); |
1324 | return -EINVAL; | 1396 | return -EINVAL; |
@@ -1706,28 +1778,6 @@ static void nfs4_fill_super(struct super_block *sb) | |||
1706 | } | 1778 | } |
1707 | 1779 | ||
1708 | /* | 1780 | /* |
1709 | * If the user didn't specify a port, set the port number to | ||
1710 | * the NFS version 4 default port. | ||
1711 | */ | ||
1712 | static void nfs4_default_port(struct sockaddr *sap) | ||
1713 | { | ||
1714 | switch (sap->sa_family) { | ||
1715 | case AF_INET: { | ||
1716 | struct sockaddr_in *ap = (struct sockaddr_in *)sap; | ||
1717 | if (ap->sin_port == 0) | ||
1718 | ap->sin_port = htons(NFS_PORT); | ||
1719 | break; | ||
1720 | } | ||
1721 | case AF_INET6: { | ||
1722 | struct sockaddr_in6 *ap = (struct sockaddr_in6 *)sap; | ||
1723 | if (ap->sin6_port == 0) | ||
1724 | ap->sin6_port = htons(NFS_PORT); | ||
1725 | break; | ||
1726 | } | ||
1727 | } | ||
1728 | } | ||
1729 | |||
1730 | /* | ||
1731 | * Validate NFSv4 mount options | 1781 | * Validate NFSv4 mount options |
1732 | */ | 1782 | */ |
1733 | static int nfs4_validate_mount_data(void *options, | 1783 | static int nfs4_validate_mount_data(void *options, |
@@ -1751,6 +1801,7 @@ static int nfs4_validate_mount_data(void *options, | |||
1751 | args->acregmax = 60; | 1801 | args->acregmax = 60; |
1752 | args->acdirmin = 30; | 1802 | args->acdirmin = 30; |
1753 | args->acdirmax = 60; | 1803 | args->acdirmax = 60; |
1804 | args->nfs_server.port = NFS_PORT; /* 2049 unless user set port= */ | ||
1754 | args->nfs_server.protocol = XPRT_TRANSPORT_TCP; | 1805 | args->nfs_server.protocol = XPRT_TRANSPORT_TCP; |
1755 | 1806 | ||
1756 | switch (data->version) { | 1807 | switch (data->version) { |
@@ -1767,9 +1818,6 @@ static int nfs4_validate_mount_data(void *options, | |||
1767 | &args->nfs_server.address)) | 1818 | &args->nfs_server.address)) |
1768 | goto out_no_address; | 1819 | goto out_no_address; |
1769 | 1820 | ||
1770 | nfs4_default_port((struct sockaddr *) | ||
1771 | &args->nfs_server.address); | ||
1772 | |||
1773 | switch (data->auth_flavourlen) { | 1821 | switch (data->auth_flavourlen) { |
1774 | case 0: | 1822 | case 0: |
1775 | args->auth_flavors[0] = RPC_AUTH_UNIX; | 1823 | args->auth_flavors[0] = RPC_AUTH_UNIX; |
@@ -1827,9 +1875,6 @@ static int nfs4_validate_mount_data(void *options, | |||
1827 | &args->nfs_server.address)) | 1875 | &args->nfs_server.address)) |
1828 | return -EINVAL; | 1876 | return -EINVAL; |
1829 | 1877 | ||
1830 | nfs4_default_port((struct sockaddr *) | ||
1831 | &args->nfs_server.address); | ||
1832 | |||
1833 | switch (args->auth_flavor_len) { | 1878 | switch (args->auth_flavor_len) { |
1834 | case 0: | 1879 | case 0: |
1835 | args->auth_flavors[0] = RPC_AUTH_UNIX; | 1880 | args->auth_flavors[0] = RPC_AUTH_UNIX; |
@@ -1852,12 +1897,16 @@ static int nfs4_validate_mount_data(void *options, | |||
1852 | return -ENAMETOOLONG; | 1897 | return -ENAMETOOLONG; |
1853 | /* N.B. caller will free nfs_server.hostname in all cases */ | 1898 | /* N.B. caller will free nfs_server.hostname in all cases */ |
1854 | args->nfs_server.hostname = kstrndup(dev_name, len, GFP_KERNEL); | 1899 | args->nfs_server.hostname = kstrndup(dev_name, len, GFP_KERNEL); |
1900 | if (!args->nfs_server.hostname) | ||
1901 | goto out_nomem; | ||
1855 | 1902 | ||
1856 | c++; /* step over the ':' */ | 1903 | c++; /* step over the ':' */ |
1857 | len = strlen(c); | 1904 | len = strlen(c); |
1858 | if (len > NFS4_MAXPATHLEN) | 1905 | if (len > NFS4_MAXPATHLEN) |
1859 | return -ENAMETOOLONG; | 1906 | return -ENAMETOOLONG; |
1860 | args->nfs_server.export_path = kstrndup(c, len, GFP_KERNEL); | 1907 | args->nfs_server.export_path = kstrndup(c, len, GFP_KERNEL); |
1908 | if (!args->nfs_server.export_path) | ||
1909 | goto out_nomem; | ||
1861 | 1910 | ||
1862 | dprintk("NFS: MNTPATH: '%s'\n", args->nfs_server.export_path); | 1911 | dprintk("NFS: MNTPATH: '%s'\n", args->nfs_server.export_path); |
1863 | 1912 | ||
@@ -1879,6 +1928,10 @@ out_inval_auth: | |||
1879 | data->auth_flavourlen); | 1928 | data->auth_flavourlen); |
1880 | return -EINVAL; | 1929 | return -EINVAL; |
1881 | 1930 | ||
1931 | out_nomem: | ||
1932 | dfprintk(MOUNT, "NFS4: not enough memory to handle mount options\n"); | ||
1933 | return -ENOMEM; | ||
1934 | |||
1882 | out_no_address: | 1935 | out_no_address: |
1883 | dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n"); | 1936 | dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n"); |
1884 | return -EINVAL; | 1937 | return -EINVAL; |
diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c index 83e865a16ad1..412738dbfbc7 100644 --- a/fs/nfs/symlink.c +++ b/fs/nfs/symlink.c | |||
@@ -10,7 +10,6 @@ | |||
10 | * nfs symlink handling code | 10 | * nfs symlink handling code |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #define NFS_NEED_XDR_TYPES | ||
14 | #include <linux/time.h> | 13 | #include <linux/time.h> |
15 | #include <linux/errno.h> | 14 | #include <linux/errno.h> |
16 | #include <linux/sunrpc/clnt.h> | 15 | #include <linux/sunrpc/clnt.h> |
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 757415363422..3adf8b266461 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c | |||
@@ -234,7 +234,7 @@ nfs_async_unlink(struct inode *dir, struct dentry *dentry) | |||
234 | if (data == NULL) | 234 | if (data == NULL) |
235 | goto out; | 235 | goto out; |
236 | 236 | ||
237 | data->cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); | 237 | data->cred = rpc_lookup_cred(); |
238 | if (IS_ERR(data->cred)) { | 238 | if (IS_ERR(data->cred)) { |
239 | status = PTR_ERR(data->cred); | 239 | status = PTR_ERR(data->cred); |
240 | goto out_free; | 240 | goto out_free; |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index bed63416a55b..1ade11d1ba07 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -48,7 +48,7 @@ static struct kmem_cache *nfs_wdata_cachep; | |||
48 | static mempool_t *nfs_wdata_mempool; | 48 | static mempool_t *nfs_wdata_mempool; |
49 | static mempool_t *nfs_commit_mempool; | 49 | static mempool_t *nfs_commit_mempool; |
50 | 50 | ||
51 | struct nfs_write_data *nfs_commit_alloc(void) | 51 | struct nfs_write_data *nfs_commitdata_alloc(void) |
52 | { | 52 | { |
53 | struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, GFP_NOFS); | 53 | struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, GFP_NOFS); |
54 | 54 | ||
@@ -59,19 +59,13 @@ struct nfs_write_data *nfs_commit_alloc(void) | |||
59 | return p; | 59 | return p; |
60 | } | 60 | } |
61 | 61 | ||
62 | static void nfs_commit_rcu_free(struct rcu_head *head) | 62 | void nfs_commit_free(struct nfs_write_data *p) |
63 | { | 63 | { |
64 | struct nfs_write_data *p = container_of(head, struct nfs_write_data, task.u.tk_rcu); | ||
65 | if (p && (p->pagevec != &p->page_array[0])) | 64 | if (p && (p->pagevec != &p->page_array[0])) |
66 | kfree(p->pagevec); | 65 | kfree(p->pagevec); |
67 | mempool_free(p, nfs_commit_mempool); | 66 | mempool_free(p, nfs_commit_mempool); |
68 | } | 67 | } |
69 | 68 | ||
70 | void nfs_commit_free(struct nfs_write_data *wdata) | ||
71 | { | ||
72 | call_rcu_bh(&wdata->task.u.tk_rcu, nfs_commit_rcu_free); | ||
73 | } | ||
74 | |||
75 | struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount) | 69 | struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount) |
76 | { | 70 | { |
77 | struct nfs_write_data *p = mempool_alloc(nfs_wdata_mempool, GFP_NOFS); | 71 | struct nfs_write_data *p = mempool_alloc(nfs_wdata_mempool, GFP_NOFS); |
@@ -93,21 +87,18 @@ struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount) | |||
93 | return p; | 87 | return p; |
94 | } | 88 | } |
95 | 89 | ||
96 | static void nfs_writedata_rcu_free(struct rcu_head *head) | 90 | static void nfs_writedata_free(struct nfs_write_data *p) |
97 | { | 91 | { |
98 | struct nfs_write_data *p = container_of(head, struct nfs_write_data, task.u.tk_rcu); | ||
99 | if (p && (p->pagevec != &p->page_array[0])) | 92 | if (p && (p->pagevec != &p->page_array[0])) |
100 | kfree(p->pagevec); | 93 | kfree(p->pagevec); |
101 | mempool_free(p, nfs_wdata_mempool); | 94 | mempool_free(p, nfs_wdata_mempool); |
102 | } | 95 | } |
103 | 96 | ||
104 | static void nfs_writedata_free(struct nfs_write_data *wdata) | 97 | void nfs_writedata_release(void *data) |
105 | { | 98 | { |
106 | call_rcu_bh(&wdata->task.u.tk_rcu, nfs_writedata_rcu_free); | 99 | struct nfs_write_data *wdata = data; |
107 | } | ||
108 | 100 | ||
109 | void nfs_writedata_release(void *wdata) | 101 | put_nfs_open_context(wdata->args.context); |
110 | { | ||
111 | nfs_writedata_free(wdata); | 102 | nfs_writedata_free(wdata); |
112 | } | 103 | } |
113 | 104 | ||
@@ -291,8 +282,6 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, | |||
291 | spin_unlock(&inode->i_lock); | 282 | spin_unlock(&inode->i_lock); |
292 | if (!nfs_pageio_add_request(pgio, req)) { | 283 | if (!nfs_pageio_add_request(pgio, req)) { |
293 | nfs_redirty_request(req); | 284 | nfs_redirty_request(req); |
294 | nfs_end_page_writeback(page); | ||
295 | nfs_clear_page_tag_locked(req); | ||
296 | return pgio->pg_error; | 285 | return pgio->pg_error; |
297 | } | 286 | } |
298 | return 0; | 287 | return 0; |
@@ -366,15 +355,13 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) | |||
366 | /* | 355 | /* |
367 | * Insert a write request into an inode | 356 | * Insert a write request into an inode |
368 | */ | 357 | */ |
369 | static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req) | 358 | static void nfs_inode_add_request(struct inode *inode, struct nfs_page *req) |
370 | { | 359 | { |
371 | struct nfs_inode *nfsi = NFS_I(inode); | 360 | struct nfs_inode *nfsi = NFS_I(inode); |
372 | int error; | 361 | int error; |
373 | 362 | ||
374 | error = radix_tree_insert(&nfsi->nfs_page_tree, req->wb_index, req); | 363 | error = radix_tree_insert(&nfsi->nfs_page_tree, req->wb_index, req); |
375 | BUG_ON(error == -EEXIST); | 364 | BUG_ON(error); |
376 | if (error) | ||
377 | return error; | ||
378 | if (!nfsi->npages) { | 365 | if (!nfsi->npages) { |
379 | igrab(inode); | 366 | igrab(inode); |
380 | if (nfs_have_delegation(inode, FMODE_WRITE)) | 367 | if (nfs_have_delegation(inode, FMODE_WRITE)) |
@@ -384,8 +371,8 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req) | |||
384 | set_page_private(req->wb_page, (unsigned long)req); | 371 | set_page_private(req->wb_page, (unsigned long)req); |
385 | nfsi->npages++; | 372 | nfsi->npages++; |
386 | kref_get(&req->wb_kref); | 373 | kref_get(&req->wb_kref); |
387 | radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); | 374 | radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, |
388 | return 0; | 375 | NFS_PAGE_TAG_LOCKED); |
389 | } | 376 | } |
390 | 377 | ||
391 | /* | 378 | /* |
@@ -413,7 +400,7 @@ static void nfs_inode_remove_request(struct nfs_page *req) | |||
413 | } | 400 | } |
414 | 401 | ||
415 | static void | 402 | static void |
416 | nfs_redirty_request(struct nfs_page *req) | 403 | nfs_mark_request_dirty(struct nfs_page *req) |
417 | { | 404 | { |
418 | __set_page_dirty_nobuffers(req->wb_page); | 405 | __set_page_dirty_nobuffers(req->wb_page); |
419 | } | 406 | } |
@@ -467,7 +454,7 @@ int nfs_reschedule_unstable_write(struct nfs_page *req) | |||
467 | return 1; | 454 | return 1; |
468 | } | 455 | } |
469 | if (test_and_clear_bit(PG_NEED_RESCHED, &req->wb_flags)) { | 456 | if (test_and_clear_bit(PG_NEED_RESCHED, &req->wb_flags)) { |
470 | nfs_redirty_request(req); | 457 | nfs_mark_request_dirty(req); |
471 | return 1; | 458 | return 1; |
472 | } | 459 | } |
473 | return 0; | 460 | return 0; |
@@ -597,6 +584,13 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, | |||
597 | /* Loop over all inode entries and see if we find | 584 | /* Loop over all inode entries and see if we find |
598 | * A request for the page we wish to update | 585 | * A request for the page we wish to update |
599 | */ | 586 | */ |
587 | if (new) { | ||
588 | if (radix_tree_preload(GFP_NOFS)) { | ||
589 | nfs_release_request(new); | ||
590 | return ERR_PTR(-ENOMEM); | ||
591 | } | ||
592 | } | ||
593 | |||
600 | spin_lock(&inode->i_lock); | 594 | spin_lock(&inode->i_lock); |
601 | req = nfs_page_find_request_locked(page); | 595 | req = nfs_page_find_request_locked(page); |
602 | if (req) { | 596 | if (req) { |
@@ -607,28 +601,27 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, | |||
607 | error = nfs_wait_on_request(req); | 601 | error = nfs_wait_on_request(req); |
608 | nfs_release_request(req); | 602 | nfs_release_request(req); |
609 | if (error < 0) { | 603 | if (error < 0) { |
610 | if (new) | 604 | if (new) { |
605 | radix_tree_preload_end(); | ||
611 | nfs_release_request(new); | 606 | nfs_release_request(new); |
607 | } | ||
612 | return ERR_PTR(error); | 608 | return ERR_PTR(error); |
613 | } | 609 | } |
614 | continue; | 610 | continue; |
615 | } | 611 | } |
616 | spin_unlock(&inode->i_lock); | 612 | spin_unlock(&inode->i_lock); |
617 | if (new) | 613 | if (new) { |
614 | radix_tree_preload_end(); | ||
618 | nfs_release_request(new); | 615 | nfs_release_request(new); |
616 | } | ||
619 | break; | 617 | break; |
620 | } | 618 | } |
621 | 619 | ||
622 | if (new) { | 620 | if (new) { |
623 | int error; | ||
624 | nfs_lock_request_dontget(new); | 621 | nfs_lock_request_dontget(new); |
625 | error = nfs_inode_add_request(inode, new); | 622 | nfs_inode_add_request(inode, new); |
626 | if (error) { | ||
627 | spin_unlock(&inode->i_lock); | ||
628 | nfs_unlock_request(new); | ||
629 | return ERR_PTR(error); | ||
630 | } | ||
631 | spin_unlock(&inode->i_lock); | 623 | spin_unlock(&inode->i_lock); |
624 | radix_tree_preload_end(); | ||
632 | req = new; | 625 | req = new; |
633 | goto zero_page; | 626 | goto zero_page; |
634 | } | 627 | } |
@@ -785,7 +778,7 @@ static int flush_task_priority(int how) | |||
785 | /* | 778 | /* |
786 | * Set up the argument/result storage required for the RPC call. | 779 | * Set up the argument/result storage required for the RPC call. |
787 | */ | 780 | */ |
788 | static void nfs_write_rpcsetup(struct nfs_page *req, | 781 | static int nfs_write_rpcsetup(struct nfs_page *req, |
789 | struct nfs_write_data *data, | 782 | struct nfs_write_data *data, |
790 | const struct rpc_call_ops *call_ops, | 783 | const struct rpc_call_ops *call_ops, |
791 | unsigned int count, unsigned int offset, | 784 | unsigned int count, unsigned int offset, |
@@ -806,6 +799,7 @@ static void nfs_write_rpcsetup(struct nfs_page *req, | |||
806 | .rpc_message = &msg, | 799 | .rpc_message = &msg, |
807 | .callback_ops = call_ops, | 800 | .callback_ops = call_ops, |
808 | .callback_data = data, | 801 | .callback_data = data, |
802 | .workqueue = nfsiod_workqueue, | ||
809 | .flags = flags, | 803 | .flags = flags, |
810 | .priority = priority, | 804 | .priority = priority, |
811 | }; | 805 | }; |
@@ -822,7 +816,7 @@ static void nfs_write_rpcsetup(struct nfs_page *req, | |||
822 | data->args.pgbase = req->wb_pgbase + offset; | 816 | data->args.pgbase = req->wb_pgbase + offset; |
823 | data->args.pages = data->pagevec; | 817 | data->args.pages = data->pagevec; |
824 | data->args.count = count; | 818 | data->args.count = count; |
825 | data->args.context = req->wb_context; | 819 | data->args.context = get_nfs_open_context(req->wb_context); |
826 | data->args.stable = NFS_UNSTABLE; | 820 | data->args.stable = NFS_UNSTABLE; |
827 | if (how & FLUSH_STABLE) { | 821 | if (how & FLUSH_STABLE) { |
828 | data->args.stable = NFS_DATA_SYNC; | 822 | data->args.stable = NFS_DATA_SYNC; |
@@ -847,8 +841,21 @@ static void nfs_write_rpcsetup(struct nfs_page *req, | |||
847 | (unsigned long long)data->args.offset); | 841 | (unsigned long long)data->args.offset); |
848 | 842 | ||
849 | task = rpc_run_task(&task_setup_data); | 843 | task = rpc_run_task(&task_setup_data); |
850 | if (!IS_ERR(task)) | 844 | if (IS_ERR(task)) |
851 | rpc_put_task(task); | 845 | return PTR_ERR(task); |
846 | rpc_put_task(task); | ||
847 | return 0; | ||
848 | } | ||
849 | |||
850 | /* If a nfs_flush_* function fails, it should remove reqs from @head and | ||
851 | * call this on each, which will prepare them to be retried on next | ||
852 | * writeback using standard nfs. | ||
853 | */ | ||
854 | static void nfs_redirty_request(struct nfs_page *req) | ||
855 | { | ||
856 | nfs_mark_request_dirty(req); | ||
857 | nfs_end_page_writeback(req->wb_page); | ||
858 | nfs_clear_page_tag_locked(req); | ||
852 | } | 859 | } |
853 | 860 | ||
854 | /* | 861 | /* |
@@ -863,6 +870,7 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned | |||
863 | size_t wsize = NFS_SERVER(inode)->wsize, nbytes; | 870 | size_t wsize = NFS_SERVER(inode)->wsize, nbytes; |
864 | unsigned int offset; | 871 | unsigned int offset; |
865 | int requests = 0; | 872 | int requests = 0; |
873 | int ret = 0; | ||
866 | LIST_HEAD(list); | 874 | LIST_HEAD(list); |
867 | 875 | ||
868 | nfs_list_remove_request(req); | 876 | nfs_list_remove_request(req); |
@@ -884,6 +892,8 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned | |||
884 | offset = 0; | 892 | offset = 0; |
885 | nbytes = count; | 893 | nbytes = count; |
886 | do { | 894 | do { |
895 | int ret2; | ||
896 | |||
887 | data = list_entry(list.next, struct nfs_write_data, pages); | 897 | data = list_entry(list.next, struct nfs_write_data, pages); |
888 | list_del_init(&data->pages); | 898 | list_del_init(&data->pages); |
889 | 899 | ||
@@ -891,13 +901,15 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned | |||
891 | 901 | ||
892 | if (nbytes < wsize) | 902 | if (nbytes < wsize) |
893 | wsize = nbytes; | 903 | wsize = nbytes; |
894 | nfs_write_rpcsetup(req, data, &nfs_write_partial_ops, | 904 | ret2 = nfs_write_rpcsetup(req, data, &nfs_write_partial_ops, |
895 | wsize, offset, how); | 905 | wsize, offset, how); |
906 | if (ret == 0) | ||
907 | ret = ret2; | ||
896 | offset += wsize; | 908 | offset += wsize; |
897 | nbytes -= wsize; | 909 | nbytes -= wsize; |
898 | } while (nbytes != 0); | 910 | } while (nbytes != 0); |
899 | 911 | ||
900 | return 0; | 912 | return ret; |
901 | 913 | ||
902 | out_bad: | 914 | out_bad: |
903 | while (!list_empty(&list)) { | 915 | while (!list_empty(&list)) { |
@@ -906,8 +918,6 @@ out_bad: | |||
906 | nfs_writedata_release(data); | 918 | nfs_writedata_release(data); |
907 | } | 919 | } |
908 | nfs_redirty_request(req); | 920 | nfs_redirty_request(req); |
909 | nfs_end_page_writeback(req->wb_page); | ||
910 | nfs_clear_page_tag_locked(req); | ||
911 | return -ENOMEM; | 921 | return -ENOMEM; |
912 | } | 922 | } |
913 | 923 | ||
@@ -940,16 +950,12 @@ static int nfs_flush_one(struct inode *inode, struct list_head *head, unsigned i | |||
940 | req = nfs_list_entry(data->pages.next); | 950 | req = nfs_list_entry(data->pages.next); |
941 | 951 | ||
942 | /* Set up the argument struct */ | 952 | /* Set up the argument struct */ |
943 | nfs_write_rpcsetup(req, data, &nfs_write_full_ops, count, 0, how); | 953 | return nfs_write_rpcsetup(req, data, &nfs_write_full_ops, count, 0, how); |
944 | |||
945 | return 0; | ||
946 | out_bad: | 954 | out_bad: |
947 | while (!list_empty(head)) { | 955 | while (!list_empty(head)) { |
948 | req = nfs_list_entry(head->next); | 956 | req = nfs_list_entry(head->next); |
949 | nfs_list_remove_request(req); | 957 | nfs_list_remove_request(req); |
950 | nfs_redirty_request(req); | 958 | nfs_redirty_request(req); |
951 | nfs_end_page_writeback(req->wb_page); | ||
952 | nfs_clear_page_tag_locked(req); | ||
953 | } | 959 | } |
954 | return -ENOMEM; | 960 | return -ENOMEM; |
955 | } | 961 | } |
@@ -972,7 +978,6 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata) | |||
972 | { | 978 | { |
973 | struct nfs_write_data *data = calldata; | 979 | struct nfs_write_data *data = calldata; |
974 | struct nfs_page *req = data->req; | 980 | struct nfs_page *req = data->req; |
975 | struct page *page = req->wb_page; | ||
976 | 981 | ||
977 | dprintk("NFS: write (%s/%Ld %d@%Ld)", | 982 | dprintk("NFS: write (%s/%Ld %d@%Ld)", |
978 | req->wb_context->path.dentry->d_inode->i_sb->s_id, | 983 | req->wb_context->path.dentry->d_inode->i_sb->s_id, |
@@ -980,13 +985,20 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata) | |||
980 | req->wb_bytes, | 985 | req->wb_bytes, |
981 | (long long)req_offset(req)); | 986 | (long long)req_offset(req)); |
982 | 987 | ||
983 | if (nfs_writeback_done(task, data) != 0) | 988 | nfs_writeback_done(task, data); |
984 | return; | 989 | } |
985 | 990 | ||
986 | if (task->tk_status < 0) { | 991 | static void nfs_writeback_release_partial(void *calldata) |
992 | { | ||
993 | struct nfs_write_data *data = calldata; | ||
994 | struct nfs_page *req = data->req; | ||
995 | struct page *page = req->wb_page; | ||
996 | int status = data->task.tk_status; | ||
997 | |||
998 | if (status < 0) { | ||
987 | nfs_set_pageerror(page); | 999 | nfs_set_pageerror(page); |
988 | nfs_context_set_write_error(req->wb_context, task->tk_status); | 1000 | nfs_context_set_write_error(req->wb_context, status); |
989 | dprintk(", error = %d\n", task->tk_status); | 1001 | dprintk(", error = %d\n", status); |
990 | goto out; | 1002 | goto out; |
991 | } | 1003 | } |
992 | 1004 | ||
@@ -1011,11 +1023,12 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata) | |||
1011 | out: | 1023 | out: |
1012 | if (atomic_dec_and_test(&req->wb_complete)) | 1024 | if (atomic_dec_and_test(&req->wb_complete)) |
1013 | nfs_writepage_release(req); | 1025 | nfs_writepage_release(req); |
1026 | nfs_writedata_release(calldata); | ||
1014 | } | 1027 | } |
1015 | 1028 | ||
1016 | static const struct rpc_call_ops nfs_write_partial_ops = { | 1029 | static const struct rpc_call_ops nfs_write_partial_ops = { |
1017 | .rpc_call_done = nfs_writeback_done_partial, | 1030 | .rpc_call_done = nfs_writeback_done_partial, |
1018 | .rpc_release = nfs_writedata_release, | 1031 | .rpc_release = nfs_writeback_release_partial, |
1019 | }; | 1032 | }; |
1020 | 1033 | ||
1021 | /* | 1034 | /* |
@@ -1028,17 +1041,21 @@ static const struct rpc_call_ops nfs_write_partial_ops = { | |||
1028 | static void nfs_writeback_done_full(struct rpc_task *task, void *calldata) | 1041 | static void nfs_writeback_done_full(struct rpc_task *task, void *calldata) |
1029 | { | 1042 | { |
1030 | struct nfs_write_data *data = calldata; | 1043 | struct nfs_write_data *data = calldata; |
1031 | struct nfs_page *req; | ||
1032 | struct page *page; | ||
1033 | 1044 | ||
1034 | if (nfs_writeback_done(task, data) != 0) | 1045 | nfs_writeback_done(task, data); |
1035 | return; | 1046 | } |
1047 | |||
1048 | static void nfs_writeback_release_full(void *calldata) | ||
1049 | { | ||
1050 | struct nfs_write_data *data = calldata; | ||
1051 | int status = data->task.tk_status; | ||
1036 | 1052 | ||
1037 | /* Update attributes as result of writeback. */ | 1053 | /* Update attributes as result of writeback. */ |
1038 | while (!list_empty(&data->pages)) { | 1054 | while (!list_empty(&data->pages)) { |
1039 | req = nfs_list_entry(data->pages.next); | 1055 | struct nfs_page *req = nfs_list_entry(data->pages.next); |
1056 | struct page *page = req->wb_page; | ||
1057 | |||
1040 | nfs_list_remove_request(req); | 1058 | nfs_list_remove_request(req); |
1041 | page = req->wb_page; | ||
1042 | 1059 | ||
1043 | dprintk("NFS: write (%s/%Ld %d@%Ld)", | 1060 | dprintk("NFS: write (%s/%Ld %d@%Ld)", |
1044 | req->wb_context->path.dentry->d_inode->i_sb->s_id, | 1061 | req->wb_context->path.dentry->d_inode->i_sb->s_id, |
@@ -1046,10 +1063,10 @@ static void nfs_writeback_done_full(struct rpc_task *task, void *calldata) | |||
1046 | req->wb_bytes, | 1063 | req->wb_bytes, |
1047 | (long long)req_offset(req)); | 1064 | (long long)req_offset(req)); |
1048 | 1065 | ||
1049 | if (task->tk_status < 0) { | 1066 | if (status < 0) { |
1050 | nfs_set_pageerror(page); | 1067 | nfs_set_pageerror(page); |
1051 | nfs_context_set_write_error(req->wb_context, task->tk_status); | 1068 | nfs_context_set_write_error(req->wb_context, status); |
1052 | dprintk(", error = %d\n", task->tk_status); | 1069 | dprintk(", error = %d\n", status); |
1053 | goto remove_request; | 1070 | goto remove_request; |
1054 | } | 1071 | } |
1055 | 1072 | ||
@@ -1069,11 +1086,12 @@ remove_request: | |||
1069 | next: | 1086 | next: |
1070 | nfs_clear_page_tag_locked(req); | 1087 | nfs_clear_page_tag_locked(req); |
1071 | } | 1088 | } |
1089 | nfs_writedata_release(calldata); | ||
1072 | } | 1090 | } |
1073 | 1091 | ||
1074 | static const struct rpc_call_ops nfs_write_full_ops = { | 1092 | static const struct rpc_call_ops nfs_write_full_ops = { |
1075 | .rpc_call_done = nfs_writeback_done_full, | 1093 | .rpc_call_done = nfs_writeback_done_full, |
1076 | .rpc_release = nfs_writedata_release, | 1094 | .rpc_release = nfs_writeback_release_full, |
1077 | }; | 1095 | }; |
1078 | 1096 | ||
1079 | 1097 | ||
@@ -1159,15 +1177,18 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1159 | 1177 | ||
1160 | 1178 | ||
1161 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 1179 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
1162 | void nfs_commit_release(void *wdata) | 1180 | void nfs_commitdata_release(void *data) |
1163 | { | 1181 | { |
1182 | struct nfs_write_data *wdata = data; | ||
1183 | |||
1184 | put_nfs_open_context(wdata->args.context); | ||
1164 | nfs_commit_free(wdata); | 1185 | nfs_commit_free(wdata); |
1165 | } | 1186 | } |
1166 | 1187 | ||
1167 | /* | 1188 | /* |
1168 | * Set up the argument/result storage required for the RPC call. | 1189 | * Set up the argument/result storage required for the RPC call. |
1169 | */ | 1190 | */ |
1170 | static void nfs_commit_rpcsetup(struct list_head *head, | 1191 | static int nfs_commit_rpcsetup(struct list_head *head, |
1171 | struct nfs_write_data *data, | 1192 | struct nfs_write_data *data, |
1172 | int how) | 1193 | int how) |
1173 | { | 1194 | { |
@@ -1187,6 +1208,7 @@ static void nfs_commit_rpcsetup(struct list_head *head, | |||
1187 | .rpc_message = &msg, | 1208 | .rpc_message = &msg, |
1188 | .callback_ops = &nfs_commit_ops, | 1209 | .callback_ops = &nfs_commit_ops, |
1189 | .callback_data = data, | 1210 | .callback_data = data, |
1211 | .workqueue = nfsiod_workqueue, | ||
1190 | .flags = flags, | 1212 | .flags = flags, |
1191 | .priority = priority, | 1213 | .priority = priority, |
1192 | }; | 1214 | }; |
@@ -1203,6 +1225,7 @@ static void nfs_commit_rpcsetup(struct list_head *head, | |||
1203 | /* Note: we always request a commit of the entire inode */ | 1225 | /* Note: we always request a commit of the entire inode */ |
1204 | data->args.offset = 0; | 1226 | data->args.offset = 0; |
1205 | data->args.count = 0; | 1227 | data->args.count = 0; |
1228 | data->args.context = get_nfs_open_context(first->wb_context); | ||
1206 | data->res.count = 0; | 1229 | data->res.count = 0; |
1207 | data->res.fattr = &data->fattr; | 1230 | data->res.fattr = &data->fattr; |
1208 | data->res.verf = &data->verf; | 1231 | data->res.verf = &data->verf; |
@@ -1214,8 +1237,10 @@ static void nfs_commit_rpcsetup(struct list_head *head, | |||
1214 | dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid); | 1237 | dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid); |
1215 | 1238 | ||
1216 | task = rpc_run_task(&task_setup_data); | 1239 | task = rpc_run_task(&task_setup_data); |
1217 | if (!IS_ERR(task)) | 1240 | if (IS_ERR(task)) |
1218 | rpc_put_task(task); | 1241 | return PTR_ERR(task); |
1242 | rpc_put_task(task); | ||
1243 | return 0; | ||
1219 | } | 1244 | } |
1220 | 1245 | ||
1221 | /* | 1246 | /* |
@@ -1227,15 +1252,13 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how) | |||
1227 | struct nfs_write_data *data; | 1252 | struct nfs_write_data *data; |
1228 | struct nfs_page *req; | 1253 | struct nfs_page *req; |
1229 | 1254 | ||
1230 | data = nfs_commit_alloc(); | 1255 | data = nfs_commitdata_alloc(); |
1231 | 1256 | ||
1232 | if (!data) | 1257 | if (!data) |
1233 | goto out_bad; | 1258 | goto out_bad; |
1234 | 1259 | ||
1235 | /* Set up the argument struct */ | 1260 | /* Set up the argument struct */ |
1236 | nfs_commit_rpcsetup(head, data, how); | 1261 | return nfs_commit_rpcsetup(head, data, how); |
1237 | |||
1238 | return 0; | ||
1239 | out_bad: | 1262 | out_bad: |
1240 | while (!list_empty(head)) { | 1263 | while (!list_empty(head)) { |
1241 | req = nfs_list_entry(head->next); | 1264 | req = nfs_list_entry(head->next); |
@@ -1255,7 +1278,6 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how) | |||
1255 | static void nfs_commit_done(struct rpc_task *task, void *calldata) | 1278 | static void nfs_commit_done(struct rpc_task *task, void *calldata) |
1256 | { | 1279 | { |
1257 | struct nfs_write_data *data = calldata; | 1280 | struct nfs_write_data *data = calldata; |
1258 | struct nfs_page *req; | ||
1259 | 1281 | ||
1260 | dprintk("NFS: %5u nfs_commit_done (status %d)\n", | 1282 | dprintk("NFS: %5u nfs_commit_done (status %d)\n", |
1261 | task->tk_pid, task->tk_status); | 1283 | task->tk_pid, task->tk_status); |
@@ -1263,6 +1285,13 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata) | |||
1263 | /* Call the NFS version-specific code */ | 1285 | /* Call the NFS version-specific code */ |
1264 | if (NFS_PROTO(data->inode)->commit_done(task, data) != 0) | 1286 | if (NFS_PROTO(data->inode)->commit_done(task, data) != 0) |
1265 | return; | 1287 | return; |
1288 | } | ||
1289 | |||
1290 | static void nfs_commit_release(void *calldata) | ||
1291 | { | ||
1292 | struct nfs_write_data *data = calldata; | ||
1293 | struct nfs_page *req; | ||
1294 | int status = data->task.tk_status; | ||
1266 | 1295 | ||
1267 | while (!list_empty(&data->pages)) { | 1296 | while (!list_empty(&data->pages)) { |
1268 | req = nfs_list_entry(data->pages.next); | 1297 | req = nfs_list_entry(data->pages.next); |
@@ -1277,10 +1306,10 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata) | |||
1277 | (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode), | 1306 | (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode), |
1278 | req->wb_bytes, | 1307 | req->wb_bytes, |
1279 | (long long)req_offset(req)); | 1308 | (long long)req_offset(req)); |
1280 | if (task->tk_status < 0) { | 1309 | if (status < 0) { |
1281 | nfs_context_set_write_error(req->wb_context, task->tk_status); | 1310 | nfs_context_set_write_error(req->wb_context, status); |
1282 | nfs_inode_remove_request(req); | 1311 | nfs_inode_remove_request(req); |
1283 | dprintk(", error = %d\n", task->tk_status); | 1312 | dprintk(", error = %d\n", status); |
1284 | goto next; | 1313 | goto next; |
1285 | } | 1314 | } |
1286 | 1315 | ||
@@ -1297,10 +1326,11 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata) | |||
1297 | } | 1326 | } |
1298 | /* We have a mismatch. Write the page again */ | 1327 | /* We have a mismatch. Write the page again */ |
1299 | dprintk(" mismatch\n"); | 1328 | dprintk(" mismatch\n"); |
1300 | nfs_redirty_request(req); | 1329 | nfs_mark_request_dirty(req); |
1301 | next: | 1330 | next: |
1302 | nfs_clear_page_tag_locked(req); | 1331 | nfs_clear_page_tag_locked(req); |
1303 | } | 1332 | } |
1333 | nfs_commitdata_release(calldata); | ||
1304 | } | 1334 | } |
1305 | 1335 | ||
1306 | static const struct rpc_call_ops nfs_commit_ops = { | 1336 | static const struct rpc_call_ops nfs_commit_ops = { |
@@ -1487,18 +1517,19 @@ static int nfs_wb_page_priority(struct inode *inode, struct page *page, | |||
1487 | }; | 1517 | }; |
1488 | int ret; | 1518 | int ret; |
1489 | 1519 | ||
1490 | BUG_ON(!PageLocked(page)); | 1520 | do { |
1491 | if (clear_page_dirty_for_io(page)) { | 1521 | if (clear_page_dirty_for_io(page)) { |
1492 | ret = nfs_writepage_locked(page, &wbc); | 1522 | ret = nfs_writepage_locked(page, &wbc); |
1523 | if (ret < 0) | ||
1524 | goto out_error; | ||
1525 | } else if (!PagePrivate(page)) | ||
1526 | break; | ||
1527 | ret = nfs_sync_mapping_wait(page->mapping, &wbc, how); | ||
1493 | if (ret < 0) | 1528 | if (ret < 0) |
1494 | goto out; | 1529 | goto out_error; |
1495 | } | 1530 | } while (PagePrivate(page)); |
1496 | if (!PagePrivate(page)) | 1531 | return 0; |
1497 | return 0; | 1532 | out_error: |
1498 | ret = nfs_sync_mapping_wait(page->mapping, &wbc, how); | ||
1499 | if (ret >= 0) | ||
1500 | return 0; | ||
1501 | out: | ||
1502 | __mark_inode_dirty(inode, I_DIRTY_PAGES); | 1533 | __mark_inode_dirty(inode, I_DIRTY_PAGES); |
1503 | return ret; | 1534 | return ret; |
1504 | } | 1535 | } |
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c index d13403e33622..294992e9bf69 100644 --- a/fs/nfsd/auth.c +++ b/fs/nfsd/auth.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/sunrpc/svcauth.h> | 10 | #include <linux/sunrpc/svcauth.h> |
11 | #include <linux/nfsd/nfsd.h> | 11 | #include <linux/nfsd/nfsd.h> |
12 | #include <linux/nfsd/export.h> | 12 | #include <linux/nfsd/export.h> |
13 | #include "auth.h" | ||
13 | 14 | ||
14 | int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp) | 15 | int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp) |
15 | { | 16 | { |
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 8a6f7c924c75..33bfcf09db46 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/lockd/bind.h> | 35 | #include <linux/lockd/bind.h> |
36 | #include <linux/sunrpc/msg_prot.h> | 36 | #include <linux/sunrpc/msg_prot.h> |
37 | #include <linux/sunrpc/gss_api.h> | 37 | #include <linux/sunrpc/gss_api.h> |
38 | #include <net/ipv6.h> | ||
38 | 39 | ||
39 | #define NFSDDBG_FACILITY NFSDDBG_EXPORT | 40 | #define NFSDDBG_FACILITY NFSDDBG_EXPORT |
40 | 41 | ||
@@ -1548,6 +1549,7 @@ exp_addclient(struct nfsctl_client *ncp) | |||
1548 | { | 1549 | { |
1549 | struct auth_domain *dom; | 1550 | struct auth_domain *dom; |
1550 | int i, err; | 1551 | int i, err; |
1552 | struct in6_addr addr6; | ||
1551 | 1553 | ||
1552 | /* First, consistency check. */ | 1554 | /* First, consistency check. */ |
1553 | err = -EINVAL; | 1555 | err = -EINVAL; |
@@ -1566,9 +1568,10 @@ exp_addclient(struct nfsctl_client *ncp) | |||
1566 | goto out_unlock; | 1568 | goto out_unlock; |
1567 | 1569 | ||
1568 | /* Insert client into hashtable. */ | 1570 | /* Insert client into hashtable. */ |
1569 | for (i = 0; i < ncp->cl_naddr; i++) | 1571 | for (i = 0; i < ncp->cl_naddr; i++) { |
1570 | auth_unix_add_addr(ncp->cl_addrlist[i], dom); | 1572 | ipv6_addr_set_v4mapped(ncp->cl_addrlist[i].s_addr, &addr6); |
1571 | 1573 | auth_unix_add_addr(&addr6, dom); | |
1574 | } | ||
1572 | auth_unix_forget_old(dom); | 1575 | auth_unix_forget_old(dom); |
1573 | auth_domain_put(dom); | 1576 | auth_domain_put(dom); |
1574 | 1577 | ||
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index aae2b29ae2c9..562abf3380d0 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
@@ -344,6 +344,21 @@ static struct rpc_version * nfs_cb_version[] = { | |||
344 | &nfs_cb_version4, | 344 | &nfs_cb_version4, |
345 | }; | 345 | }; |
346 | 346 | ||
347 | static struct rpc_program cb_program; | ||
348 | |||
349 | static struct rpc_stat cb_stats = { | ||
350 | .program = &cb_program | ||
351 | }; | ||
352 | |||
353 | #define NFS4_CALLBACK 0x40000000 | ||
354 | static struct rpc_program cb_program = { | ||
355 | .name = "nfs4_cb", | ||
356 | .number = NFS4_CALLBACK, | ||
357 | .nrvers = ARRAY_SIZE(nfs_cb_version), | ||
358 | .version = nfs_cb_version, | ||
359 | .stats = &cb_stats, | ||
360 | }; | ||
361 | |||
347 | /* Reference counting, callback cleanup, etc., all look racy as heck. | 362 | /* Reference counting, callback cleanup, etc., all look racy as heck. |
348 | * And why is cb_set an atomic? */ | 363 | * And why is cb_set an atomic? */ |
349 | 364 | ||
@@ -358,13 +373,12 @@ static int do_probe_callback(void *data) | |||
358 | .to_maxval = (NFSD_LEASE_TIME/2) * HZ, | 373 | .to_maxval = (NFSD_LEASE_TIME/2) * HZ, |
359 | .to_exponential = 1, | 374 | .to_exponential = 1, |
360 | }; | 375 | }; |
361 | struct rpc_program * program = &cb->cb_program; | ||
362 | struct rpc_create_args args = { | 376 | struct rpc_create_args args = { |
363 | .protocol = IPPROTO_TCP, | 377 | .protocol = IPPROTO_TCP, |
364 | .address = (struct sockaddr *)&addr, | 378 | .address = (struct sockaddr *)&addr, |
365 | .addrsize = sizeof(addr), | 379 | .addrsize = sizeof(addr), |
366 | .timeout = &timeparms, | 380 | .timeout = &timeparms, |
367 | .program = program, | 381 | .program = &cb_program, |
368 | .version = nfs_cb_version[1]->number, | 382 | .version = nfs_cb_version[1]->number, |
369 | .authflavor = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */ | 383 | .authflavor = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */ |
370 | .flags = (RPC_CLNT_CREATE_NOPING), | 384 | .flags = (RPC_CLNT_CREATE_NOPING), |
@@ -382,16 +396,8 @@ static int do_probe_callback(void *data) | |||
382 | addr.sin_port = htons(cb->cb_port); | 396 | addr.sin_port = htons(cb->cb_port); |
383 | addr.sin_addr.s_addr = htonl(cb->cb_addr); | 397 | addr.sin_addr.s_addr = htonl(cb->cb_addr); |
384 | 398 | ||
385 | /* Initialize rpc_program */ | ||
386 | program->name = "nfs4_cb"; | ||
387 | program->number = cb->cb_prog; | ||
388 | program->nrvers = ARRAY_SIZE(nfs_cb_version); | ||
389 | program->version = nfs_cb_version; | ||
390 | program->stats = &cb->cb_stat; | ||
391 | |||
392 | /* Initialize rpc_stat */ | 399 | /* Initialize rpc_stat */ |
393 | memset(program->stats, 0, sizeof(cb->cb_stat)); | 400 | memset(args.program->stats, 0, sizeof(struct rpc_stat)); |
394 | program->stats->program = program; | ||
395 | 401 | ||
396 | /* Create RPC client */ | 402 | /* Create RPC client */ |
397 | client = rpc_create(&args); | 403 | client = rpc_create(&args); |
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c index 996bd88b75ba..5b398421b051 100644 --- a/fs/nfsd/nfs4idmap.c +++ b/fs/nfsd/nfs4idmap.c | |||
@@ -202,7 +202,7 @@ static struct cache_detail idtoname_cache = { | |||
202 | .alloc = ent_alloc, | 202 | .alloc = ent_alloc, |
203 | }; | 203 | }; |
204 | 204 | ||
205 | int | 205 | static int |
206 | idtoname_parse(struct cache_detail *cd, char *buf, int buflen) | 206 | idtoname_parse(struct cache_detail *cd, char *buf, int buflen) |
207 | { | 207 | { |
208 | struct ent ent, *res; | 208 | struct ent ent, *res; |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 81a75f3081f4..55dfdd71f1b0 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -1639,6 +1639,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta | |||
1639 | locks_init_lock(&fl); | 1639 | locks_init_lock(&fl); |
1640 | fl.fl_lmops = &nfsd_lease_mng_ops; | 1640 | fl.fl_lmops = &nfsd_lease_mng_ops; |
1641 | fl.fl_flags = FL_LEASE; | 1641 | fl.fl_flags = FL_LEASE; |
1642 | fl.fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK; | ||
1642 | fl.fl_end = OFFSET_MAX; | 1643 | fl.fl_end = OFFSET_MAX; |
1643 | fl.fl_owner = (fl_owner_t)dp; | 1644 | fl.fl_owner = (fl_owner_t)dp; |
1644 | fl.fl_file = stp->st_vfs_file; | 1645 | fl.fl_file = stp->st_vfs_file; |
@@ -1647,8 +1648,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta | |||
1647 | /* vfs_setlease checks to see if delegation should be handed out. | 1648 | /* vfs_setlease checks to see if delegation should be handed out. |
1648 | * the lock_manager callbacks fl_mylease and fl_change are used | 1649 | * the lock_manager callbacks fl_mylease and fl_change are used |
1649 | */ | 1650 | */ |
1650 | if ((status = vfs_setlease(stp->st_vfs_file, | 1651 | if ((status = vfs_setlease(stp->st_vfs_file, fl.fl_type, &flp))) { |
1651 | flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK, &flp))) { | ||
1652 | dprintk("NFSD: setlease failed [%d], no delegation\n", status); | 1652 | dprintk("NFSD: setlease failed [%d], no delegation\n", status); |
1653 | unhash_delegation(dp); | 1653 | unhash_delegation(dp); |
1654 | flag = NFS4_OPEN_DELEGATE_NONE; | 1654 | flag = NFS4_OPEN_DELEGATE_NONE; |
@@ -1763,10 +1763,6 @@ out: | |||
1763 | return status; | 1763 | return status; |
1764 | } | 1764 | } |
1765 | 1765 | ||
1766 | static struct workqueue_struct *laundry_wq; | ||
1767 | static void laundromat_main(struct work_struct *); | ||
1768 | static DECLARE_DELAYED_WORK(laundromat_work, laundromat_main); | ||
1769 | |||
1770 | __be32 | 1766 | __be32 |
1771 | nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 1767 | nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
1772 | clientid_t *clid) | 1768 | clientid_t *clid) |
@@ -1874,7 +1870,11 @@ nfs4_laundromat(void) | |||
1874 | return clientid_val; | 1870 | return clientid_val; |
1875 | } | 1871 | } |
1876 | 1872 | ||
1877 | void | 1873 | static struct workqueue_struct *laundry_wq; |
1874 | static void laundromat_main(struct work_struct *); | ||
1875 | static DECLARE_DELAYED_WORK(laundromat_work, laundromat_main); | ||
1876 | |||
1877 | static void | ||
1878 | laundromat_main(struct work_struct *not_used) | 1878 | laundromat_main(struct work_struct *not_used) |
1879 | { | 1879 | { |
1880 | time_t t; | 1880 | time_t t; |
@@ -1975,6 +1975,26 @@ io_during_grace_disallowed(struct inode *inode, int flags) | |||
1975 | && mandatory_lock(inode); | 1975 | && mandatory_lock(inode); |
1976 | } | 1976 | } |
1977 | 1977 | ||
1978 | static int check_stateid_generation(stateid_t *in, stateid_t *ref) | ||
1979 | { | ||
1980 | /* If the client sends us a stateid from the future, it's buggy: */ | ||
1981 | if (in->si_generation > ref->si_generation) | ||
1982 | return nfserr_bad_stateid; | ||
1983 | /* | ||
1984 | * The following, however, can happen. For example, if the | ||
1985 | * client sends an open and some IO at the same time, the open | ||
1986 | * may bump si_generation while the IO is still in flight. | ||
1987 | * Thanks to hard links and renames, the client never knows what | ||
1988 | * file an open will affect. So it could avoid that situation | ||
1989 | * only by serializing all opens and IO from the same open | ||
1990 | * owner. To recover from the old_stateid error, the client | ||
1991 | * will just have to retry the IO: | ||
1992 | */ | ||
1993 | if (in->si_generation < ref->si_generation) | ||
1994 | return nfserr_old_stateid; | ||
1995 | return nfs_ok; | ||
1996 | } | ||
1997 | |||
1978 | /* | 1998 | /* |
1979 | * Checks for stateid operations | 1999 | * Checks for stateid operations |
1980 | */ | 2000 | */ |
@@ -2023,12 +2043,8 @@ nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int fl | |||
2023 | goto out; | 2043 | goto out; |
2024 | stidp = &stp->st_stateid; | 2044 | stidp = &stp->st_stateid; |
2025 | } | 2045 | } |
2026 | if (stateid->si_generation > stidp->si_generation) | 2046 | status = check_stateid_generation(stateid, stidp); |
2027 | goto out; | 2047 | if (status) |
2028 | |||
2029 | /* OLD STATEID */ | ||
2030 | status = nfserr_old_stateid; | ||
2031 | if (stateid->si_generation < stidp->si_generation) | ||
2032 | goto out; | 2048 | goto out; |
2033 | if (stp) { | 2049 | if (stp) { |
2034 | if ((status = nfs4_check_openmode(stp,flags))) | 2050 | if ((status = nfs4_check_openmode(stp,flags))) |
@@ -2036,7 +2052,7 @@ nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int fl | |||
2036 | renew_client(stp->st_stateowner->so_client); | 2052 | renew_client(stp->st_stateowner->so_client); |
2037 | if (filpp) | 2053 | if (filpp) |
2038 | *filpp = stp->st_vfs_file; | 2054 | *filpp = stp->st_vfs_file; |
2039 | } else if (dp) { | 2055 | } else { |
2040 | if ((status = nfs4_check_delegmode(dp, flags))) | 2056 | if ((status = nfs4_check_delegmode(dp, flags))) |
2041 | goto out; | 2057 | goto out; |
2042 | renew_client(dp->dl_client); | 2058 | renew_client(dp->dl_client); |
@@ -2065,6 +2081,7 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei | |||
2065 | { | 2081 | { |
2066 | struct nfs4_stateid *stp; | 2082 | struct nfs4_stateid *stp; |
2067 | struct nfs4_stateowner *sop; | 2083 | struct nfs4_stateowner *sop; |
2084 | __be32 status; | ||
2068 | 2085 | ||
2069 | dprintk("NFSD: preprocess_seqid_op: seqid=%d " | 2086 | dprintk("NFSD: preprocess_seqid_op: seqid=%d " |
2070 | "stateid = (%08x/%08x/%08x/%08x)\n", seqid, | 2087 | "stateid = (%08x/%08x/%08x/%08x)\n", seqid, |
@@ -2127,7 +2144,7 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei | |||
2127 | } | 2144 | } |
2128 | } | 2145 | } |
2129 | 2146 | ||
2130 | if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) { | 2147 | if (nfs4_check_fh(current_fh, stp)) { |
2131 | dprintk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n"); | 2148 | dprintk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n"); |
2132 | return nfserr_bad_stateid; | 2149 | return nfserr_bad_stateid; |
2133 | } | 2150 | } |
@@ -2150,15 +2167,9 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei | |||
2150 | " confirmed yet!\n"); | 2167 | " confirmed yet!\n"); |
2151 | return nfserr_bad_stateid; | 2168 | return nfserr_bad_stateid; |
2152 | } | 2169 | } |
2153 | if (stateid->si_generation > stp->st_stateid.si_generation) { | 2170 | status = check_stateid_generation(stateid, &stp->st_stateid); |
2154 | dprintk("NFSD: preprocess_seqid_op: future stateid?!\n"); | 2171 | if (status) |
2155 | return nfserr_bad_stateid; | 2172 | return status; |
2156 | } | ||
2157 | |||
2158 | if (stateid->si_generation < stp->st_stateid.si_generation) { | ||
2159 | dprintk("NFSD: preprocess_seqid_op: old stateid!\n"); | ||
2160 | return nfserr_old_stateid; | ||
2161 | } | ||
2162 | renew_client(sop->so_client); | 2173 | renew_client(sop->so_client); |
2163 | return nfs_ok; | 2174 | return nfs_ok; |
2164 | 2175 | ||
@@ -2194,7 +2205,7 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2194 | 2205 | ||
2195 | if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh, | 2206 | if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh, |
2196 | oc->oc_seqid, &oc->oc_req_stateid, | 2207 | oc->oc_seqid, &oc->oc_req_stateid, |
2197 | CHECK_FH | CONFIRM | OPEN_STATE, | 2208 | CONFIRM | OPEN_STATE, |
2198 | &oc->oc_stateowner, &stp, NULL))) | 2209 | &oc->oc_stateowner, &stp, NULL))) |
2199 | goto out; | 2210 | goto out; |
2200 | 2211 | ||
@@ -2265,7 +2276,7 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, | |||
2265 | if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh, | 2276 | if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh, |
2266 | od->od_seqid, | 2277 | od->od_seqid, |
2267 | &od->od_stateid, | 2278 | &od->od_stateid, |
2268 | CHECK_FH | OPEN_STATE, | 2279 | OPEN_STATE, |
2269 | &od->od_stateowner, &stp, NULL))) | 2280 | &od->od_stateowner, &stp, NULL))) |
2270 | goto out; | 2281 | goto out; |
2271 | 2282 | ||
@@ -2318,7 +2329,7 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2318 | if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh, | 2329 | if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh, |
2319 | close->cl_seqid, | 2330 | close->cl_seqid, |
2320 | &close->cl_stateid, | 2331 | &close->cl_stateid, |
2321 | CHECK_FH | OPEN_STATE | CLOSE_STATE, | 2332 | OPEN_STATE | CLOSE_STATE, |
2322 | &close->cl_stateowner, &stp, NULL))) | 2333 | &close->cl_stateowner, &stp, NULL))) |
2323 | goto out; | 2334 | goto out; |
2324 | status = nfs_ok; | 2335 | status = nfs_ok; |
@@ -2623,7 +2634,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2623 | status = nfs4_preprocess_seqid_op(&cstate->current_fh, | 2634 | status = nfs4_preprocess_seqid_op(&cstate->current_fh, |
2624 | lock->lk_new_open_seqid, | 2635 | lock->lk_new_open_seqid, |
2625 | &lock->lk_new_open_stateid, | 2636 | &lock->lk_new_open_stateid, |
2626 | CHECK_FH | OPEN_STATE, | 2637 | OPEN_STATE, |
2627 | &lock->lk_replay_owner, &open_stp, | 2638 | &lock->lk_replay_owner, &open_stp, |
2628 | lock); | 2639 | lock); |
2629 | if (status) | 2640 | if (status) |
@@ -2650,7 +2661,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2650 | status = nfs4_preprocess_seqid_op(&cstate->current_fh, | 2661 | status = nfs4_preprocess_seqid_op(&cstate->current_fh, |
2651 | lock->lk_old_lock_seqid, | 2662 | lock->lk_old_lock_seqid, |
2652 | &lock->lk_old_lock_stateid, | 2663 | &lock->lk_old_lock_stateid, |
2653 | CHECK_FH | LOCK_STATE, | 2664 | LOCK_STATE, |
2654 | &lock->lk_replay_owner, &lock_stp, lock); | 2665 | &lock->lk_replay_owner, &lock_stp, lock); |
2655 | if (status) | 2666 | if (status) |
2656 | goto out; | 2667 | goto out; |
@@ -2847,7 +2858,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2847 | if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh, | 2858 | if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh, |
2848 | locku->lu_seqid, | 2859 | locku->lu_seqid, |
2849 | &locku->lu_stateid, | 2860 | &locku->lu_stateid, |
2850 | CHECK_FH | LOCK_STATE, | 2861 | LOCK_STATE, |
2851 | &locku->lu_stateowner, &stp, NULL))) | 2862 | &locku->lu_stateowner, &stp, NULL))) |
2852 | goto out; | 2863 | goto out; |
2853 | 2864 | ||
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 0e6a179eccaf..1ba7ad981935 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -1867,6 +1867,15 @@ out_serverfault: | |||
1867 | goto out; | 1867 | goto out; |
1868 | } | 1868 | } |
1869 | 1869 | ||
1870 | static inline int attributes_need_mount(u32 *bmval) | ||
1871 | { | ||
1872 | if (bmval[0] & ~(FATTR4_WORD0_RDATTR_ERROR | FATTR4_WORD0_LEASE_TIME)) | ||
1873 | return 1; | ||
1874 | if (bmval[1] & ~FATTR4_WORD1_MOUNTED_ON_FILEID) | ||
1875 | return 1; | ||
1876 | return 0; | ||
1877 | } | ||
1878 | |||
1870 | static __be32 | 1879 | static __be32 |
1871 | nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd, | 1880 | nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd, |
1872 | const char *name, int namlen, __be32 *p, int *buflen) | 1881 | const char *name, int namlen, __be32 *p, int *buflen) |
@@ -1888,9 +1897,7 @@ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd, | |||
1888 | * we will not follow the cross mount and will fill the attribtutes | 1897 | * we will not follow the cross mount and will fill the attribtutes |
1889 | * directly from the mountpoint dentry. | 1898 | * directly from the mountpoint dentry. |
1890 | */ | 1899 | */ |
1891 | if (d_mountpoint(dentry) && | 1900 | if (d_mountpoint(dentry) && !attributes_need_mount(cd->rd_bmval)) |
1892 | (cd->rd_bmval[0] & ~FATTR4_WORD0_RDATTR_ERROR) == 0 && | ||
1893 | (cd->rd_bmval[1] & ~FATTR4_WORD1_MOUNTED_ON_FILEID) == 0) | ||
1894 | ignore_crossmnt = 1; | 1901 | ignore_crossmnt = 1; |
1895 | else if (d_mountpoint(dentry)) { | 1902 | else if (d_mountpoint(dentry)) { |
1896 | int err; | 1903 | int err; |
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 8516137cdbb0..613bcb8171a5 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/nfsd/syscall.h> | 37 | #include <linux/nfsd/syscall.h> |
38 | 38 | ||
39 | #include <asm/uaccess.h> | 39 | #include <asm/uaccess.h> |
40 | #include <net/ipv6.h> | ||
40 | 41 | ||
41 | /* | 42 | /* |
42 | * We have a single directory with 9 nodes in it. | 43 | * We have a single directory with 9 nodes in it. |
@@ -149,7 +150,6 @@ static const struct file_operations transaction_ops = { | |||
149 | .release = simple_transaction_release, | 150 | .release = simple_transaction_release, |
150 | }; | 151 | }; |
151 | 152 | ||
152 | extern struct seq_operations nfs_exports_op; | ||
153 | static int exports_open(struct inode *inode, struct file *file) | 153 | static int exports_open(struct inode *inode, struct file *file) |
154 | { | 154 | { |
155 | return seq_open(file, &nfs_exports_op); | 155 | return seq_open(file, &nfs_exports_op); |
@@ -222,6 +222,7 @@ static ssize_t write_getfs(struct file *file, char *buf, size_t size) | |||
222 | struct auth_domain *clp; | 222 | struct auth_domain *clp; |
223 | int err = 0; | 223 | int err = 0; |
224 | struct knfsd_fh *res; | 224 | struct knfsd_fh *res; |
225 | struct in6_addr in6; | ||
225 | 226 | ||
226 | if (size < sizeof(*data)) | 227 | if (size < sizeof(*data)) |
227 | return -EINVAL; | 228 | return -EINVAL; |
@@ -236,7 +237,11 @@ static ssize_t write_getfs(struct file *file, char *buf, size_t size) | |||
236 | res = (struct knfsd_fh*)buf; | 237 | res = (struct knfsd_fh*)buf; |
237 | 238 | ||
238 | exp_readlock(); | 239 | exp_readlock(); |
239 | if (!(clp = auth_unix_lookup(sin->sin_addr))) | 240 | |
241 | ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6); | ||
242 | |||
243 | clp = auth_unix_lookup(&in6); | ||
244 | if (!clp) | ||
240 | err = -EPERM; | 245 | err = -EPERM; |
241 | else { | 246 | else { |
242 | err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen); | 247 | err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen); |
@@ -257,6 +262,7 @@ static ssize_t write_getfd(struct file *file, char *buf, size_t size) | |||
257 | int err = 0; | 262 | int err = 0; |
258 | struct knfsd_fh fh; | 263 | struct knfsd_fh fh; |
259 | char *res; | 264 | char *res; |
265 | struct in6_addr in6; | ||
260 | 266 | ||
261 | if (size < sizeof(*data)) | 267 | if (size < sizeof(*data)) |
262 | return -EINVAL; | 268 | return -EINVAL; |
@@ -271,7 +277,11 @@ static ssize_t write_getfd(struct file *file, char *buf, size_t size) | |||
271 | res = buf; | 277 | res = buf; |
272 | sin = (struct sockaddr_in *)&data->gd_addr; | 278 | sin = (struct sockaddr_in *)&data->gd_addr; |
273 | exp_readlock(); | 279 | exp_readlock(); |
274 | if (!(clp = auth_unix_lookup(sin->sin_addr))) | 280 | |
281 | ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6); | ||
282 | |||
283 | clp = auth_unix_lookup(&in6); | ||
284 | if (!clp) | ||
275 | err = -EPERM; | 285 | err = -EPERM; |
276 | else { | 286 | else { |
277 | err = exp_rootfh(clp, data->gd_path, &fh, NFS_FHSIZE); | 287 | err = exp_rootfh(clp, data->gd_path, &fh, NFS_FHSIZE); |
@@ -347,8 +357,6 @@ static ssize_t write_filehandle(struct file *file, char *buf, size_t size) | |||
347 | return mesg - buf; | 357 | return mesg - buf; |
348 | } | 358 | } |
349 | 359 | ||
350 | extern int nfsd_nrthreads(void); | ||
351 | |||
352 | static ssize_t write_threads(struct file *file, char *buf, size_t size) | 360 | static ssize_t write_threads(struct file *file, char *buf, size_t size) |
353 | { | 361 | { |
354 | /* if size > 0, look for a number of threads and call nfsd_svc | 362 | /* if size > 0, look for a number of threads and call nfsd_svc |
@@ -371,10 +379,6 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size) | |||
371 | return strlen(buf); | 379 | return strlen(buf); |
372 | } | 380 | } |
373 | 381 | ||
374 | extern int nfsd_nrpools(void); | ||
375 | extern int nfsd_get_nrthreads(int n, int *); | ||
376 | extern int nfsd_set_nrthreads(int n, int *); | ||
377 | |||
378 | static ssize_t write_pool_threads(struct file *file, char *buf, size_t size) | 382 | static ssize_t write_pool_threads(struct file *file, char *buf, size_t size) |
379 | { | 383 | { |
380 | /* if size > 0, look for an array of number of threads per node | 384 | /* if size > 0, look for an array of number of threads per node |
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 3e6b3f41ee1f..100ae5641162 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c | |||
@@ -113,6 +113,124 @@ static __be32 nfsd_setuser_and_check_port(struct svc_rqst *rqstp, | |||
113 | } | 113 | } |
114 | 114 | ||
115 | /* | 115 | /* |
116 | * Use the given filehandle to look up the corresponding export and | ||
117 | * dentry. On success, the results are used to set fh_export and | ||
118 | * fh_dentry. | ||
119 | */ | ||
120 | static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp) | ||
121 | { | ||
122 | struct knfsd_fh *fh = &fhp->fh_handle; | ||
123 | struct fid *fid = NULL, sfid; | ||
124 | struct svc_export *exp; | ||
125 | struct dentry *dentry; | ||
126 | int fileid_type; | ||
127 | int data_left = fh->fh_size/4; | ||
128 | __be32 error; | ||
129 | |||
130 | error = nfserr_stale; | ||
131 | if (rqstp->rq_vers > 2) | ||
132 | error = nfserr_badhandle; | ||
133 | if (rqstp->rq_vers == 4 && fh->fh_size == 0) | ||
134 | return nfserr_nofilehandle; | ||
135 | |||
136 | if (fh->fh_version == 1) { | ||
137 | int len; | ||
138 | |||
139 | if (--data_left < 0) | ||
140 | return error; | ||
141 | if (fh->fh_auth_type != 0) | ||
142 | return error; | ||
143 | len = key_len(fh->fh_fsid_type) / 4; | ||
144 | if (len == 0) | ||
145 | return error; | ||
146 | if (fh->fh_fsid_type == FSID_MAJOR_MINOR) { | ||
147 | /* deprecated, convert to type 3 */ | ||
148 | len = key_len(FSID_ENCODE_DEV)/4; | ||
149 | fh->fh_fsid_type = FSID_ENCODE_DEV; | ||
150 | fh->fh_fsid[0] = new_encode_dev(MKDEV(ntohl(fh->fh_fsid[0]), ntohl(fh->fh_fsid[1]))); | ||
151 | fh->fh_fsid[1] = fh->fh_fsid[2]; | ||
152 | } | ||
153 | data_left -= len; | ||
154 | if (data_left < 0) | ||
155 | return error; | ||
156 | exp = rqst_exp_find(rqstp, fh->fh_fsid_type, fh->fh_auth); | ||
157 | fid = (struct fid *)(fh->fh_auth + len); | ||
158 | } else { | ||
159 | __u32 tfh[2]; | ||
160 | dev_t xdev; | ||
161 | ino_t xino; | ||
162 | |||
163 | if (fh->fh_size != NFS_FHSIZE) | ||
164 | return error; | ||
165 | /* assume old filehandle format */ | ||
166 | xdev = old_decode_dev(fh->ofh_xdev); | ||
167 | xino = u32_to_ino_t(fh->ofh_xino); | ||
168 | mk_fsid(FSID_DEV, tfh, xdev, xino, 0, NULL); | ||
169 | exp = rqst_exp_find(rqstp, FSID_DEV, tfh); | ||
170 | } | ||
171 | |||
172 | error = nfserr_stale; | ||
173 | if (PTR_ERR(exp) == -ENOENT) | ||
174 | return error; | ||
175 | |||
176 | if (IS_ERR(exp)) | ||
177 | return nfserrno(PTR_ERR(exp)); | ||
178 | |||
179 | error = nfsd_setuser_and_check_port(rqstp, exp); | ||
180 | if (error) | ||
181 | goto out; | ||
182 | |||
183 | /* | ||
184 | * Look up the dentry using the NFS file handle. | ||
185 | */ | ||
186 | error = nfserr_stale; | ||
187 | if (rqstp->rq_vers > 2) | ||
188 | error = nfserr_badhandle; | ||
189 | |||
190 | if (fh->fh_version != 1) { | ||
191 | sfid.i32.ino = fh->ofh_ino; | ||
192 | sfid.i32.gen = fh->ofh_generation; | ||
193 | sfid.i32.parent_ino = fh->ofh_dirino; | ||
194 | fid = &sfid; | ||
195 | data_left = 3; | ||
196 | if (fh->ofh_dirino == 0) | ||
197 | fileid_type = FILEID_INO32_GEN; | ||
198 | else | ||
199 | fileid_type = FILEID_INO32_GEN_PARENT; | ||
200 | } else | ||
201 | fileid_type = fh->fh_fileid_type; | ||
202 | |||
203 | if (fileid_type == FILEID_ROOT) | ||
204 | dentry = dget(exp->ex_path.dentry); | ||
205 | else { | ||
206 | dentry = exportfs_decode_fh(exp->ex_path.mnt, fid, | ||
207 | data_left, fileid_type, | ||
208 | nfsd_acceptable, exp); | ||
209 | } | ||
210 | if (dentry == NULL) | ||
211 | goto out; | ||
212 | if (IS_ERR(dentry)) { | ||
213 | if (PTR_ERR(dentry) != -EINVAL) | ||
214 | error = nfserrno(PTR_ERR(dentry)); | ||
215 | goto out; | ||
216 | } | ||
217 | |||
218 | if (S_ISDIR(dentry->d_inode->i_mode) && | ||
219 | (dentry->d_flags & DCACHE_DISCONNECTED)) { | ||
220 | printk("nfsd: find_fh_dentry returned a DISCONNECTED directory: %s/%s\n", | ||
221 | dentry->d_parent->d_name.name, dentry->d_name.name); | ||
222 | } | ||
223 | |||
224 | fhp->fh_dentry = dentry; | ||
225 | fhp->fh_export = exp; | ||
226 | nfsd_nr_verified++; | ||
227 | return 0; | ||
228 | out: | ||
229 | exp_put(exp); | ||
230 | return error; | ||
231 | } | ||
232 | |||
233 | /* | ||
116 | * Perform sanity checks on the dentry in a client's file handle. | 234 | * Perform sanity checks on the dentry in a client's file handle. |
117 | * | 235 | * |
118 | * Note that the file handle dentry may need to be freed even after | 236 | * Note that the file handle dentry may need to be freed even after |
@@ -124,115 +242,18 @@ static __be32 nfsd_setuser_and_check_port(struct svc_rqst *rqstp, | |||
124 | __be32 | 242 | __be32 |
125 | fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) | 243 | fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) |
126 | { | 244 | { |
127 | struct knfsd_fh *fh = &fhp->fh_handle; | 245 | struct svc_export *exp; |
128 | struct svc_export *exp = NULL; | ||
129 | struct dentry *dentry; | 246 | struct dentry *dentry; |
130 | __be32 error = 0; | 247 | __be32 error; |
131 | 248 | ||
132 | dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp)); | 249 | dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp)); |
133 | 250 | ||
134 | if (!fhp->fh_dentry) { | 251 | if (!fhp->fh_dentry) { |
135 | struct fid *fid = NULL, sfid; | 252 | error = nfsd_set_fh_dentry(rqstp, fhp); |
136 | int fileid_type; | ||
137 | int data_left = fh->fh_size/4; | ||
138 | |||
139 | error = nfserr_stale; | ||
140 | if (rqstp->rq_vers > 2) | ||
141 | error = nfserr_badhandle; | ||
142 | if (rqstp->rq_vers == 4 && fh->fh_size == 0) | ||
143 | return nfserr_nofilehandle; | ||
144 | |||
145 | if (fh->fh_version == 1) { | ||
146 | int len; | ||
147 | if (--data_left<0) goto out; | ||
148 | switch (fh->fh_auth_type) { | ||
149 | case 0: break; | ||
150 | default: goto out; | ||
151 | } | ||
152 | len = key_len(fh->fh_fsid_type) / 4; | ||
153 | if (len == 0) goto out; | ||
154 | if (fh->fh_fsid_type == FSID_MAJOR_MINOR) { | ||
155 | /* deprecated, convert to type 3 */ | ||
156 | len = key_len(FSID_ENCODE_DEV)/4; | ||
157 | fh->fh_fsid_type = FSID_ENCODE_DEV; | ||
158 | fh->fh_fsid[0] = new_encode_dev(MKDEV(ntohl(fh->fh_fsid[0]), ntohl(fh->fh_fsid[1]))); | ||
159 | fh->fh_fsid[1] = fh->fh_fsid[2]; | ||
160 | } | ||
161 | if ((data_left -= len)<0) goto out; | ||
162 | exp = rqst_exp_find(rqstp, fh->fh_fsid_type, | ||
163 | fh->fh_auth); | ||
164 | fid = (struct fid *)(fh->fh_auth + len); | ||
165 | } else { | ||
166 | __u32 tfh[2]; | ||
167 | dev_t xdev; | ||
168 | ino_t xino; | ||
169 | if (fh->fh_size != NFS_FHSIZE) | ||
170 | goto out; | ||
171 | /* assume old filehandle format */ | ||
172 | xdev = old_decode_dev(fh->ofh_xdev); | ||
173 | xino = u32_to_ino_t(fh->ofh_xino); | ||
174 | mk_fsid(FSID_DEV, tfh, xdev, xino, 0, NULL); | ||
175 | exp = rqst_exp_find(rqstp, FSID_DEV, tfh); | ||
176 | } | ||
177 | |||
178 | error = nfserr_stale; | ||
179 | if (PTR_ERR(exp) == -ENOENT) | ||
180 | goto out; | ||
181 | |||
182 | if (IS_ERR(exp)) { | ||
183 | error = nfserrno(PTR_ERR(exp)); | ||
184 | goto out; | ||
185 | } | ||
186 | |||
187 | error = nfsd_setuser_and_check_port(rqstp, exp); | ||
188 | if (error) | 253 | if (error) |
189 | goto out; | 254 | goto out; |
190 | 255 | dentry = fhp->fh_dentry; | |
191 | /* | 256 | exp = fhp->fh_export; |
192 | * Look up the dentry using the NFS file handle. | ||
193 | */ | ||
194 | error = nfserr_stale; | ||
195 | if (rqstp->rq_vers > 2) | ||
196 | error = nfserr_badhandle; | ||
197 | |||
198 | if (fh->fh_version != 1) { | ||
199 | sfid.i32.ino = fh->ofh_ino; | ||
200 | sfid.i32.gen = fh->ofh_generation; | ||
201 | sfid.i32.parent_ino = fh->ofh_dirino; | ||
202 | fid = &sfid; | ||
203 | data_left = 3; | ||
204 | if (fh->ofh_dirino == 0) | ||
205 | fileid_type = FILEID_INO32_GEN; | ||
206 | else | ||
207 | fileid_type = FILEID_INO32_GEN_PARENT; | ||
208 | } else | ||
209 | fileid_type = fh->fh_fileid_type; | ||
210 | |||
211 | if (fileid_type == FILEID_ROOT) | ||
212 | dentry = dget(exp->ex_path.dentry); | ||
213 | else { | ||
214 | dentry = exportfs_decode_fh(exp->ex_path.mnt, fid, | ||
215 | data_left, fileid_type, | ||
216 | nfsd_acceptable, exp); | ||
217 | } | ||
218 | if (dentry == NULL) | ||
219 | goto out; | ||
220 | if (IS_ERR(dentry)) { | ||
221 | if (PTR_ERR(dentry) != -EINVAL) | ||
222 | error = nfserrno(PTR_ERR(dentry)); | ||
223 | goto out; | ||
224 | } | ||
225 | |||
226 | if (S_ISDIR(dentry->d_inode->i_mode) && | ||
227 | (dentry->d_flags & DCACHE_DISCONNECTED)) { | ||
228 | printk("nfsd: find_fh_dentry returned a DISCONNECTED directory: %s/%s\n", | ||
229 | dentry->d_parent->d_name.name, dentry->d_name.name); | ||
230 | } | ||
231 | |||
232 | fhp->fh_dentry = dentry; | ||
233 | fhp->fh_export = exp; | ||
234 | nfsd_nr_verified++; | ||
235 | cache_get(&exp->h); | ||
236 | } else { | 257 | } else { |
237 | /* | 258 | /* |
238 | * just rechecking permissions | 259 | * just rechecking permissions |
@@ -242,7 +263,6 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) | |||
242 | dprintk("nfsd: fh_verify - just checking\n"); | 263 | dprintk("nfsd: fh_verify - just checking\n"); |
243 | dentry = fhp->fh_dentry; | 264 | dentry = fhp->fh_dentry; |
244 | exp = fhp->fh_export; | 265 | exp = fhp->fh_export; |
245 | cache_get(&exp->h); | ||
246 | /* | 266 | /* |
247 | * Set user creds for this exportpoint; necessary even | 267 | * Set user creds for this exportpoint; necessary even |
248 | * in the "just checking" case because this may be a | 268 | * in the "just checking" case because this may be a |
@@ -281,8 +301,6 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) | |||
281 | access, ntohl(error)); | 301 | access, ntohl(error)); |
282 | } | 302 | } |
283 | out: | 303 | out: |
284 | if (exp && !IS_ERR(exp)) | ||
285 | exp_put(exp); | ||
286 | if (error == nfserr_stale) | 304 | if (error == nfserr_stale) |
287 | nfsdstats.fh_stale++; | 305 | nfsdstats.fh_stale++; |
288 | return error; | 306 | return error; |
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 9647b0f7bc0c..941041f4b136 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
@@ -244,7 +244,6 @@ static int nfsd_init_socks(int port) | |||
244 | if (error < 0) | 244 | if (error < 0) |
245 | return error; | 245 | return error; |
246 | 246 | ||
247 | #ifdef CONFIG_NFSD_TCP | ||
248 | error = lockd_up(IPPROTO_TCP); | 247 | error = lockd_up(IPPROTO_TCP); |
249 | if (error >= 0) { | 248 | if (error >= 0) { |
250 | error = svc_create_xprt(nfsd_serv, "tcp", port, | 249 | error = svc_create_xprt(nfsd_serv, "tcp", port, |
@@ -254,7 +253,6 @@ static int nfsd_init_socks(int port) | |||
254 | } | 253 | } |
255 | if (error < 0) | 254 | if (error < 0) |
256 | return error; | 255 | return error; |
257 | #endif | ||
258 | return 0; | 256 | return 0; |
259 | } | 257 | } |
260 | 258 | ||
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 304bf5f643c9..a3a291f771f4 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -264,7 +264,6 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, | |||
264 | struct inode *inode; | 264 | struct inode *inode; |
265 | int accmode = MAY_SATTR; | 265 | int accmode = MAY_SATTR; |
266 | int ftype = 0; | 266 | int ftype = 0; |
267 | int imode; | ||
268 | __be32 err; | 267 | __be32 err; |
269 | int host_err; | 268 | int host_err; |
270 | int size_change = 0; | 269 | int size_change = 0; |
@@ -360,25 +359,25 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, | |||
360 | DQUOT_INIT(inode); | 359 | DQUOT_INIT(inode); |
361 | } | 360 | } |
362 | 361 | ||
363 | imode = inode->i_mode; | 362 | /* sanitize the mode change */ |
364 | if (iap->ia_valid & ATTR_MODE) { | 363 | if (iap->ia_valid & ATTR_MODE) { |
365 | iap->ia_mode &= S_IALLUGO; | 364 | iap->ia_mode &= S_IALLUGO; |
366 | imode = iap->ia_mode |= (imode & ~S_IALLUGO); | 365 | iap->ia_mode |= (inode->i_mode & ~S_IALLUGO); |
367 | /* if changing uid/gid revoke setuid/setgid in mode */ | 366 | } |
368 | if ((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid) { | 367 | |
369 | iap->ia_valid |= ATTR_KILL_PRIV; | 368 | /* Revoke setuid/setgid on chown */ |
369 | if (((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid) || | ||
370 | ((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid)) { | ||
371 | iap->ia_valid |= ATTR_KILL_PRIV; | ||
372 | if (iap->ia_valid & ATTR_MODE) { | ||
373 | /* we're setting mode too, just clear the s*id bits */ | ||
370 | iap->ia_mode &= ~S_ISUID; | 374 | iap->ia_mode &= ~S_ISUID; |
375 | if (iap->ia_mode & S_IXGRP) | ||
376 | iap->ia_mode &= ~S_ISGID; | ||
377 | } else { | ||
378 | /* set ATTR_KILL_* bits and let VFS handle it */ | ||
379 | iap->ia_valid |= (ATTR_KILL_SUID | ATTR_KILL_SGID); | ||
371 | } | 380 | } |
372 | if ((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid) | ||
373 | iap->ia_mode &= ~S_ISGID; | ||
374 | } else { | ||
375 | /* | ||
376 | * Revoke setuid/setgid bit on chown/chgrp | ||
377 | */ | ||
378 | if ((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid) | ||
379 | iap->ia_valid |= ATTR_KILL_SUID | ATTR_KILL_PRIV; | ||
380 | if ((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid) | ||
381 | iap->ia_valid |= ATTR_KILL_SGID; | ||
382 | } | 381 | } |
383 | 382 | ||
384 | /* Change the attributes. */ | 383 | /* Change the attributes. */ |
@@ -988,7 +987,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
988 | * flushing the data to disk is handled separately below. | 987 | * flushing the data to disk is handled separately below. |
989 | */ | 988 | */ |
990 | 989 | ||
991 | if (file->f_op->fsync == 0) {/* COMMIT3 cannot work */ | 990 | if (!file->f_op->fsync) {/* COMMIT3 cannot work */ |
992 | stable = 2; | 991 | stable = 2; |
993 | *stablep = 2; /* FILE_SYNC */ | 992 | *stablep = 2; /* FILE_SYNC */ |
994 | } | 993 | } |
@@ -1152,7 +1151,7 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1152 | } | 1151 | } |
1153 | #endif /* CONFIG_NFSD_V3 */ | 1152 | #endif /* CONFIG_NFSD_V3 */ |
1154 | 1153 | ||
1155 | __be32 | 1154 | static __be32 |
1156 | nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *resfhp, | 1155 | nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *resfhp, |
1157 | struct iattr *iap) | 1156 | struct iattr *iap) |
1158 | { | 1157 | { |