diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-24 14:45:00 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-24 14:45:00 -0400 |
| commit | 10c993a6b5418cb1026775765ba4c70ffb70853d (patch) | |
| tree | 717deba79b938c2f3f786ff6fe908d30582f06f8 /fs/lockd/svc.c | |
| parent | c328d54cd4ad120d76284e46dcca6c6cf996154a (diff) | |
| parent | ca456252db0521e5e88024fa2b67535e9739e030 (diff) | |
Merge branch 'for-linus' of git://linux-nfs.org/~bfields/linux
* 'for-linus' of git://linux-nfs.org/~bfields/linux: (52 commits)
knfsd: clear both setuid and setgid whenever a chown is done
knfsd: get rid of imode variable in nfsd_setattr
SUNRPC: Use unsigned loop and array index in svc_init_buffer()
SUNRPC: Use unsigned index when looping over arrays
SUNRPC: Update RPC server's TCP record marker decoder
SUNRPC: RPC server still uses 2.4 method for disabling TCP Nagle
NLM: don't let lockd exit on unexpected svc_recv errors (try #2)
NFS: don't let nfs_callback_svc exit on unexpected svc_recv errors (try #2)
Use a zero sized array for raw field in struct fid
nfsd: use static memory for callback program and stats
SUNRPC: remove svc_create_thread()
nfsd: fix comment
lockd: Fix stale nlmsvc_unlink_block comment
NFSD: Strip __KERNEL__ testing from unexported header files.
sunrpc: make token header values less confusing
gss_krb5: consistently use unsigned for seqnum
NFSD: Remove NFSv4 dependency on NFSv3
SUNRPC: Remove PROC_FS dependency
NFSD: Use "depends on" for PROC_FS dependency
nfsd: move most of fh_verify to separate function
...
Diffstat (limited to 'fs/lockd/svc.c')
| -rw-r--r-- | fs/lockd/svc.c | 150 |
1 files changed, 70 insertions, 80 deletions
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 | } |
