diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/Kconfig | 109 | ||||
-rw-r--r-- | fs/lockd/host.c | 73 | ||||
-rw-r--r-- | fs/lockd/svc.c | 150 | ||||
-rw-r--r-- | fs/lockd/svclock.c | 6 | ||||
-rw-r--r-- | fs/lockd/svcshare.c | 3 | ||||
-rw-r--r-- | fs/nfs/callback.c | 93 | ||||
-rw-r--r-- | fs/nfs/symlink.c | 1 | ||||
-rw-r--r-- | fs/nfsd/auth.c | 1 | ||||
-rw-r--r-- | fs/nfsd/export.c | 9 | ||||
-rw-r--r-- | fs/nfsd/nfs4callback.c | 28 | ||||
-rw-r--r-- | fs/nfsd/nfs4idmap.c | 2 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 71 | ||||
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 13 | ||||
-rw-r--r-- | fs/nfsd/nfsctl.c | 22 | ||||
-rw-r--r-- | fs/nfsd/nfsfh.c | 228 | ||||
-rw-r--r-- | fs/nfsd/nfssvc.c | 2 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 35 |
17 files changed, 445 insertions, 401 deletions
diff --git a/fs/Kconfig b/fs/Kconfig index 8b18a8758677..56c83f40cdbe 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. |
@@ -1694,75 +1694,80 @@ config NFSD | |||
1694 | select LOCKD | 1694 | select LOCKD |
1695 | select SUNRPC | 1695 | select SUNRPC |
1696 | select EXPORTFS | 1696 | select EXPORTFS |
1697 | select NFSD_V2_ACL if NFSD_V3_ACL | ||
1698 | select NFS_ACL_SUPPORT if NFSD_V2_ACL | 1697 | select NFS_ACL_SUPPORT if NFSD_V2_ACL |
1699 | select NFSD_TCP if NFSD_V4 | 1698 | help |
1700 | select CRYPTO_MD5 if NFSD_V4 | 1699 | Choose Y here if you want to allow other computers to access |
1701 | select CRYPTO if NFSD_V4 | 1700 | files residing on this system using Sun's Network File System |
1702 | select FS_POSIX_ACL if NFSD_V4 | 1701 | protocol. To compile the NFS server support as a module, |
1703 | select PROC_FS if NFSD_V4 | 1702 | choose M here: the module will be called nfsd. |
1704 | select PROC_FS if SUNRPC_GSS | 1703 | |
1705 | help | 1704 | 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 | 1705 | case you can choose N here. |
1707 | computers on your local network which support NFS can access certain | 1706 | |
1708 | directories on your box transparently, you have two options: you can | 1707 | 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 | 1708 | 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 | 1709 | package, available from http://linux-nfs.org/. More detail about |
1711 | server. The advantage of the kernel based solution is that it is | 1710 | the Linux NFS server implementation is available via the |
1712 | faster. | 1711 | exports(5) man page. |
1713 | 1712 | ||
1714 | In either case, you will need support software; the respective | 1713 | Below you can choose which versions of the NFS protocol are |
1715 | locations are given in the file <file:Documentation/Changes> in the | 1714 | available to clients mounting the NFS server on this system. |
1716 | NFS section. | 1715 | Support for NFS version 2 (RFC 1094) is always available when |
1717 | 1716 | CONFIG_NFSD is selected. | |
1718 | If you say Y here, you will get support for version 2 of the NFS | 1717 | |
1719 | protocol (NFSv2). If you also want NFSv3, say Y to the next question | 1718 | 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 | 1719 | ||
1728 | config NFSD_V2_ACL | 1720 | config NFSD_V2_ACL |
1729 | bool | 1721 | bool |
1730 | depends on NFSD | 1722 | depends on NFSD |
1731 | 1723 | ||
1732 | config NFSD_V3 | 1724 | config NFSD_V3 |
1733 | bool "Provide NFSv3 server support" | 1725 | bool "NFS server support for NFS version 3" |
1734 | depends on NFSD | 1726 | depends on NFSD |
1735 | help | 1727 | help |
1736 | If you would like to include the NFSv3 server as well as the NFSv2 | 1728 | This option enables support in your system's NFS server for |
1737 | server, say Y here. If unsure, say Y. | 1729 | version 3 of the NFS protocol (RFC 1813). |
1730 | |||
1731 | If unsure, say Y. | ||
1738 | 1732 | ||
1739 | config NFSD_V3_ACL | 1733 | config NFSD_V3_ACL |
1740 | bool "Provide server support for the NFSv3 ACL protocol extension" | 1734 | bool "NFS server support for the NFSv3 ACL protocol extension" |
1741 | depends on NFSD_V3 | 1735 | depends on NFSD_V3 |
1736 | select NFSD_V2_ACL | ||
1742 | help | 1737 | help |
1743 | Implement the NFSv3 ACL protocol extension for manipulating POSIX | 1738 | Solaris NFS servers support an auxiliary NFSv3 ACL protocol that |
1744 | Access Control Lists on exported file systems. NFS clients should | 1739 | never became an official part of the NFS version 3 protocol. |
1745 | be compiled with the NFSv3 ACL protocol extension; see the | 1740 | This protocol extension allows applications on NFS clients to |
1746 | CONFIG_NFS_V3_ACL option. If unsure, say N. | 1741 | manipulate POSIX Access Control Lists on files residing on NFS |
1742 | servers. NFS servers enforce POSIX ACLs on local files whether | ||
1743 | this protocol is available or not. | ||
1744 | |||
1745 | This option enables support in your system's NFS server for the | ||
1746 | NFSv3 ACL protocol extension allowing NFS clients to manipulate | ||
1747 | POSIX ACLs on files exported by your system's NFS server. NFS | ||
1748 | clients which support the Solaris NFSv3 ACL protocol can then | ||
1749 | access and modify ACLs on your NFS server. | ||
1750 | |||
1751 | To store ACLs on your NFS server, you also need to enable ACL- | ||
1752 | related CONFIG options for your local file systems of choice. | ||
1753 | |||
1754 | If unsure, say N. | ||
1747 | 1755 | ||
1748 | config NFSD_V4 | 1756 | config NFSD_V4 |
1749 | bool "Provide NFSv4 server support (EXPERIMENTAL)" | 1757 | bool "NFS server support for NFS version 4 (EXPERIMENTAL)" |
1750 | depends on NFSD && NFSD_V3 && EXPERIMENTAL | 1758 | depends on NFSD && PROC_FS && EXPERIMENTAL |
1759 | select NFSD_V3 | ||
1760 | select FS_POSIX_ACL | ||
1751 | select RPCSEC_GSS_KRB5 | 1761 | select RPCSEC_GSS_KRB5 |
1752 | help | 1762 | help |
1753 | If you would like to include the NFSv4 server as well as the NFSv2 | 1763 | This option enables support in your system's NFS server for |
1754 | and NFSv3 servers, say Y here. This feature is experimental, and | 1764 | 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 | 1765 | ||
1758 | config NFSD_TCP | 1766 | To export files using NFSv4, you need to install additional user |
1759 | bool "Provide NFS server over TCP support" | 1767 | space programs which can be found in the Linux nfs-utils package, |
1760 | depends on NFSD | 1768 | available from http://linux-nfs.org/. |
1761 | default y | 1769 | |
1762 | help | 1770 | 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 | 1771 | ||
1767 | config ROOT_NFS | 1772 | config ROOT_NFS |
1768 | bool "Root file system on NFS" | 1773 | bool "Root file system on NFS" |
diff --git a/fs/lockd/host.c b/fs/lockd/host.c index f1ef49fff118..c7854791898f 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; |
@@ -142,9 +141,7 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin, | |||
142 | INIT_LIST_HEAD(&host->h_granted); | 141 | INIT_LIST_HEAD(&host->h_granted); |
143 | INIT_LIST_HEAD(&host->h_reclaim); | 142 | INIT_LIST_HEAD(&host->h_reclaim); |
144 | 143 | ||
145 | if (++nrhosts > NLM_HOST_MAX) | 144 | nrhosts++; |
146 | next_gc = 0; | ||
147 | |||
148 | out: | 145 | out: |
149 | mutex_unlock(&nlm_host_mutex); | 146 | mutex_unlock(&nlm_host_mutex); |
150 | return host; | 147 | return host; |
@@ -460,7 +457,7 @@ nlm_gc_hosts(void) | |||
460 | * Manage NSM handles | 457 | * Manage NSM handles |
461 | */ | 458 | */ |
462 | static LIST_HEAD(nsm_handles); | 459 | static LIST_HEAD(nsm_handles); |
463 | static DEFINE_MUTEX(nsm_mutex); | 460 | static DEFINE_SPINLOCK(nsm_lock); |
464 | 461 | ||
465 | static struct nsm_handle * | 462 | static struct nsm_handle * |
466 | __nsm_find(const struct sockaddr_in *sin, | 463 | __nsm_find(const struct sockaddr_in *sin, |
@@ -468,7 +465,7 @@ __nsm_find(const struct sockaddr_in *sin, | |||
468 | int create) | 465 | int create) |
469 | { | 466 | { |
470 | struct nsm_handle *nsm = NULL; | 467 | struct nsm_handle *nsm = NULL; |
471 | struct list_head *pos; | 468 | struct nsm_handle *pos; |
472 | 469 | ||
473 | if (!sin) | 470 | if (!sin) |
474 | return NULL; | 471 | return NULL; |
@@ -482,38 +479,43 @@ __nsm_find(const struct sockaddr_in *sin, | |||
482 | return NULL; | 479 | return NULL; |
483 | } | 480 | } |
484 | 481 | ||
485 | mutex_lock(&nsm_mutex); | 482 | retry: |
486 | list_for_each(pos, &nsm_handles) { | 483 | spin_lock(&nsm_lock); |
487 | nsm = list_entry(pos, struct nsm_handle, sm_link); | 484 | list_for_each_entry(pos, &nsm_handles, sm_link) { |
488 | 485 | ||
489 | if (hostname && nsm_use_hostnames) { | 486 | if (hostname && nsm_use_hostnames) { |
490 | if (strlen(nsm->sm_name) != hostname_len | 487 | if (strlen(pos->sm_name) != hostname_len |
491 | || memcmp(nsm->sm_name, hostname, hostname_len)) | 488 | || memcmp(pos->sm_name, hostname, hostname_len)) |
492 | continue; | 489 | continue; |
493 | } else if (!nlm_cmp_addr(&nsm->sm_addr, sin)) | 490 | } else if (!nlm_cmp_addr(&pos->sm_addr, sin)) |
494 | continue; | 491 | continue; |
495 | atomic_inc(&nsm->sm_count); | 492 | atomic_inc(&pos->sm_count); |
496 | goto out; | 493 | kfree(nsm); |
494 | nsm = pos; | ||
495 | goto found; | ||
497 | } | 496 | } |
498 | 497 | if (nsm) { | |
499 | if (!create) { | 498 | list_add(&nsm->sm_link, &nsm_handles); |
500 | nsm = NULL; | 499 | goto found; |
501 | goto out; | ||
502 | } | 500 | } |
501 | spin_unlock(&nsm_lock); | ||
502 | |||
503 | if (!create) | ||
504 | return NULL; | ||
503 | 505 | ||
504 | nsm = kzalloc(sizeof(*nsm) + hostname_len + 1, GFP_KERNEL); | 506 | nsm = kzalloc(sizeof(*nsm) + hostname_len + 1, GFP_KERNEL); |
505 | if (nsm != NULL) { | 507 | if (nsm == NULL) |
506 | nsm->sm_addr = *sin; | 508 | 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 | 509 | ||
512 | list_add(&nsm->sm_link, &nsm_handles); | 510 | nsm->sm_addr = *sin; |
513 | } | 511 | nsm->sm_name = (char *) (nsm + 1); |
512 | memcpy(nsm->sm_name, hostname, hostname_len); | ||
513 | nsm->sm_name[hostname_len] = '\0'; | ||
514 | atomic_set(&nsm->sm_count, 1); | ||
515 | goto retry; | ||
514 | 516 | ||
515 | out: | 517 | found: |
516 | mutex_unlock(&nsm_mutex); | 518 | spin_unlock(&nsm_lock); |
517 | return nsm; | 519 | return nsm; |
518 | } | 520 | } |
519 | 521 | ||
@@ -532,12 +534,9 @@ nsm_release(struct nsm_handle *nsm) | |||
532 | { | 534 | { |
533 | if (!nsm) | 535 | if (!nsm) |
534 | return; | 536 | return; |
535 | if (atomic_dec_and_test(&nsm->sm_count)) { | 537 | if (atomic_dec_and_lock(&nsm->sm_count, &nsm_lock)) { |
536 | mutex_lock(&nsm_mutex); | 538 | list_del(&nsm->sm_link); |
537 | if (atomic_read(&nsm->sm_count) == 0) { | 539 | spin_unlock(&nsm_lock); |
538 | list_del(&nsm->sm_link); | 540 | kfree(nsm); |
539 | kfree(nsm); | ||
540 | } | ||
541 | mutex_unlock(&nsm_mutex); | ||
542 | } | 541 | } |
543 | } | 542 | } |
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 1ed8bd4de941..cf977bbcf303 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 |
@@ -111,35 +109,30 @@ static inline void clear_grace_period(void) | |||
111 | /* | 109 | /* |
112 | * This is the lockd kernel thread | 110 | * This is the lockd kernel thread |
113 | */ | 111 | */ |
114 | static void | 112 | static int |
115 | lockd(struct svc_rqst *rqstp) | 113 | lockd(void *vrqstp) |
116 | { | 114 | { |
117 | int err = 0; | 115 | int err = 0, preverr = 0; |
116 | struct svc_rqst *rqstp = vrqstp; | ||
118 | unsigned long grace_period_expire; | 117 | unsigned long grace_period_expire; |
119 | 118 | ||
120 | /* Lock module and set up kernel thread */ | 119 | /* 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(); | 120 | set_freezable(); |
137 | 121 | ||
138 | /* Process request with signals blocked, but allow SIGKILL. */ | 122 | /* Allow SIGKILL to tell lockd to drop all of its locks */ |
139 | allow_signal(SIGKILL); | 123 | allow_signal(SIGKILL); |
140 | 124 | ||
141 | dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n"); | 125 | dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n"); |
142 | 126 | ||
127 | /* | ||
128 | * FIXME: it would be nice if lockd didn't spend its entire life | ||
129 | * running under the BKL. At the very least, it would be good to | ||
130 | * have someone clarify what it's intended to protect here. I've | ||
131 | * seen some handwavy posts about posix locking needing to be | ||
132 | * done under the BKL, but it's far from clear. | ||
133 | */ | ||
134 | lock_kernel(); | ||
135 | |||
143 | if (!nlm_timeout) | 136 | if (!nlm_timeout) |
144 | nlm_timeout = LOCKD_DFLT_TIMEO; | 137 | nlm_timeout = LOCKD_DFLT_TIMEO; |
145 | nlmsvc_timeout = nlm_timeout * HZ; | 138 | nlmsvc_timeout = nlm_timeout * HZ; |
@@ -148,10 +141,9 @@ lockd(struct svc_rqst *rqstp) | |||
148 | 141 | ||
149 | /* | 142 | /* |
150 | * The main request loop. We don't terminate until the last | 143 | * 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 | 144 | * NFS mount or NFS daemon has gone away. |
152 | * signal, or else another process has taken over our job. | ||
153 | */ | 145 | */ |
154 | while ((nlmsvc_users || !signalled()) && nlmsvc_pid == current->pid) { | 146 | while (!kthread_should_stop()) { |
155 | long timeout = MAX_SCHEDULE_TIMEOUT; | 147 | long timeout = MAX_SCHEDULE_TIMEOUT; |
156 | RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]); | 148 | RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]); |
157 | 149 | ||
@@ -161,6 +153,7 @@ lockd(struct svc_rqst *rqstp) | |||
161 | nlmsvc_invalidate_all(); | 153 | nlmsvc_invalidate_all(); |
162 | grace_period_expire = set_grace_period(); | 154 | grace_period_expire = set_grace_period(); |
163 | } | 155 | } |
156 | continue; | ||
164 | } | 157 | } |
165 | 158 | ||
166 | /* | 159 | /* |
@@ -179,14 +172,20 @@ lockd(struct svc_rqst *rqstp) | |||
179 | * recvfrom routine. | 172 | * recvfrom routine. |
180 | */ | 173 | */ |
181 | err = svc_recv(rqstp, timeout); | 174 | err = svc_recv(rqstp, timeout); |
182 | if (err == -EAGAIN || err == -EINTR) | 175 | if (err == -EAGAIN || err == -EINTR) { |
176 | preverr = err; | ||
183 | continue; | 177 | continue; |
178 | } | ||
184 | if (err < 0) { | 179 | if (err < 0) { |
185 | printk(KERN_WARNING | 180 | if (err != preverr) { |
186 | "lockd: terminating on error %d\n", | 181 | printk(KERN_WARNING "%s: unexpected error " |
187 | -err); | 182 | "from svc_recv (%d)\n", __func__, err); |
188 | break; | 183 | preverr = err; |
184 | } | ||
185 | schedule_timeout_interruptible(HZ); | ||
186 | continue; | ||
189 | } | 187 | } |
188 | preverr = err; | ||
190 | 189 | ||
191 | dprintk("lockd: request from %s\n", | 190 | dprintk("lockd: request from %s\n", |
192 | svc_print_addr(rqstp, buf, sizeof(buf))); | 191 | svc_print_addr(rqstp, buf, sizeof(buf))); |
@@ -195,28 +194,19 @@ lockd(struct svc_rqst *rqstp) | |||
195 | } | 194 | } |
196 | 195 | ||
197 | flush_signals(current); | 196 | flush_signals(current); |
197 | if (nlmsvc_ops) | ||
198 | nlmsvc_invalidate_all(); | ||
199 | nlm_shutdown_hosts(); | ||
198 | 200 | ||
199 | /* | 201 | unlock_kernel(); |
200 | * Check whether there's a new lockd process before | 202 | |
201 | * shutting down the hosts and clearing the slot. | 203 | nlmsvc_task = NULL; |
202 | */ | 204 | 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 | 205 | ||
214 | /* Exit the RPC thread */ | 206 | /* Exit the RPC thread */ |
215 | svc_exit_thread(rqstp); | 207 | svc_exit_thread(rqstp); |
216 | 208 | ||
217 | /* Release module */ | 209 | return 0; |
218 | unlock_kernel(); | ||
219 | module_put_and_exit(0); | ||
220 | } | 210 | } |
221 | 211 | ||
222 | /* | 212 | /* |
@@ -261,14 +251,15 @@ static int make_socks(struct svc_serv *serv, int proto) | |||
261 | int | 251 | int |
262 | lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */ | 252 | lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */ |
263 | { | 253 | { |
264 | struct svc_serv * serv; | 254 | struct svc_serv *serv; |
265 | int error = 0; | 255 | struct svc_rqst *rqstp; |
256 | int error = 0; | ||
266 | 257 | ||
267 | mutex_lock(&nlmsvc_mutex); | 258 | mutex_lock(&nlmsvc_mutex); |
268 | /* | 259 | /* |
269 | * Check whether we're already up and running. | 260 | * Check whether we're already up and running. |
270 | */ | 261 | */ |
271 | if (nlmsvc_pid) { | 262 | if (nlmsvc_serv) { |
272 | if (proto) | 263 | if (proto) |
273 | error = make_socks(nlmsvc_serv, proto); | 264 | error = make_socks(nlmsvc_serv, proto); |
274 | goto out; | 265 | goto out; |
@@ -295,13 +286,28 @@ lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */ | |||
295 | /* | 286 | /* |
296 | * Create the kernel thread and wait for it to start. | 287 | * Create the kernel thread and wait for it to start. |
297 | */ | 288 | */ |
298 | error = svc_create_thread(lockd, serv); | 289 | rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]); |
299 | if (error) { | 290 | if (IS_ERR(rqstp)) { |
291 | error = PTR_ERR(rqstp); | ||
292 | printk(KERN_WARNING | ||
293 | "lockd_up: svc_rqst allocation failed, error=%d\n", | ||
294 | error); | ||
295 | goto destroy_and_out; | ||
296 | } | ||
297 | |||
298 | svc_sock_update_bufs(serv); | ||
299 | nlmsvc_serv = rqstp->rq_server; | ||
300 | |||
301 | nlmsvc_task = kthread_run(lockd, rqstp, serv->sv_name); | ||
302 | if (IS_ERR(nlmsvc_task)) { | ||
303 | error = PTR_ERR(nlmsvc_task); | ||
304 | nlmsvc_task = NULL; | ||
305 | nlmsvc_serv = NULL; | ||
300 | printk(KERN_WARNING | 306 | printk(KERN_WARNING |
301 | "lockd_up: create thread failed, error=%d\n", error); | 307 | "lockd_up: kthread_run failed, error=%d\n", error); |
308 | svc_exit_thread(rqstp); | ||
302 | goto destroy_and_out; | 309 | goto destroy_and_out; |
303 | } | 310 | } |
304 | wait_for_completion(&lockd_start_done); | ||
305 | 311 | ||
306 | /* | 312 | /* |
307 | * Note: svc_serv structures have an initial use count of 1, | 313 | * Note: svc_serv structures have an initial use count of 1, |
@@ -323,37 +329,21 @@ EXPORT_SYMBOL(lockd_up); | |||
323 | void | 329 | void |
324 | lockd_down(void) | 330 | lockd_down(void) |
325 | { | 331 | { |
326 | static int warned; | ||
327 | |||
328 | mutex_lock(&nlmsvc_mutex); | 332 | mutex_lock(&nlmsvc_mutex); |
329 | if (nlmsvc_users) { | 333 | if (nlmsvc_users) { |
330 | if (--nlmsvc_users) | 334 | if (--nlmsvc_users) |
331 | goto out; | 335 | goto out; |
332 | } else | 336 | } else { |
333 | printk(KERN_WARNING "lockd_down: no users! pid=%d\n", nlmsvc_pid); | 337 | printk(KERN_ERR "lockd_down: no users! task=%p\n", |
334 | 338 | nlmsvc_task); | |
335 | if (!nlmsvc_pid) { | 339 | BUG(); |
336 | if (warned++ == 0) | ||
337 | printk(KERN_WARNING "lockd_down: no lockd running.\n"); | ||
338 | goto out; | ||
339 | } | 340 | } |
340 | warned = 0; | ||
341 | 341 | ||
342 | kill_proc(nlmsvc_pid, SIGKILL, 1); | 342 | if (!nlmsvc_task) { |
343 | /* | 343 | printk(KERN_ERR "lockd_down: no lockd running.\n"); |
344 | * Wait for the lockd process to exit, but since we're holding | 344 | 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 | } | 345 | } |
354 | spin_lock_irq(¤t->sighand->siglock); | 346 | kthread_stop(nlmsvc_task); |
355 | recalc_sigpending(); | ||
356 | spin_unlock_irq(¤t->sighand->siglock); | ||
357 | out: | 347 | out: |
358 | mutex_unlock(&nlmsvc_mutex); | 348 | mutex_unlock(&nlmsvc_mutex); |
359 | } | 349 | } |
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/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/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/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 | { |