diff options
| author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-25 12:18:27 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-25 12:18:27 -0500 |
| commit | 53846a21c1766326bb14ce8ab6e997a0c120675d (patch) | |
| tree | 37b04485e29844b4e734479181276a2f4d2447e4 /fs/lockd/clntproc.c | |
| parent | 2e9abdd9bad485970b37cd53a82f92702054984c (diff) | |
| parent | 1ebbe2b20091d306453a5cf480a87e6cd28ae76f (diff) | |
Merge git://git.linux-nfs.org/pub/linux/nfs-2.6
* git://git.linux-nfs.org/pub/linux/nfs-2.6: (103 commits)
SUNRPC,RPCSEC_GSS: spkm3--fix config dependencies
SUNRPC,RPCSEC_GSS: spkm3: import contexts using NID_cast5_cbc
LOCKD: Make nlmsvc_traverse_shares return void
LOCKD: nlmsvc_traverse_blocks return is unused
SUNRPC,RPCSEC_GSS: fix krb5 sequence numbers.
NFSv4: Dont list system.nfs4_acl for filesystems that don't support it.
SUNRPC,RPCSEC_GSS: remove unnecessary kmalloc of a checksum
SUNRPC: Ensure rpc_call_async() always calls tk_ops->rpc_release()
SUNRPC: Fix memory barriers for req->rq_received
NFS: Fix a race in nfs_sync_inode()
NFS: Clean up nfs_flush_list()
NFS: Fix a race with PG_private and nfs_release_page()
NFSv4: Ensure the callback daemon flushes signals
SUNRPC: Fix a 'Busy inodes' error in rpc_pipefs
NFS, NLM: Allow blocking locks to respect signals
NFS: Make nfs_fhget() return appropriate error values
NFSv4: Fix an oops in nfs4_fill_super
lockd: blocks should hold a reference to the nlm_file
NFSv4: SETCLIENTID_CONFIRM should handle NFS4ERR_DELAY/NFS4ERR_RESOURCE
NFSv4: Send the delegation stateid for SETATTR calls
...
Diffstat (limited to 'fs/lockd/clntproc.c')
| -rw-r--r-- | fs/lockd/clntproc.c | 317 |
1 files changed, 119 insertions, 198 deletions
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index 970b6a6aa337..f96e38155b5c 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c | |||
| @@ -132,59 +132,18 @@ static void nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl) | |||
| 132 | memcpy(&lock->fh, NFS_FH(fl->fl_file->f_dentry->d_inode), sizeof(struct nfs_fh)); | 132 | memcpy(&lock->fh, NFS_FH(fl->fl_file->f_dentry->d_inode), sizeof(struct nfs_fh)); |
| 133 | lock->caller = system_utsname.nodename; | 133 | lock->caller = system_utsname.nodename; |
| 134 | lock->oh.data = req->a_owner; | 134 | lock->oh.data = req->a_owner; |
| 135 | lock->oh.len = sprintf(req->a_owner, "%d@%s", | 135 | lock->oh.len = snprintf(req->a_owner, sizeof(req->a_owner), "%u@%s", |
| 136 | current->pid, system_utsname.nodename); | 136 | (unsigned int)fl->fl_u.nfs_fl.owner->pid, |
| 137 | locks_copy_lock(&lock->fl, fl); | 137 | system_utsname.nodename); |
| 138 | lock->svid = fl->fl_u.nfs_fl.owner->pid; | ||
| 139 | lock->fl.fl_start = fl->fl_start; | ||
| 140 | lock->fl.fl_end = fl->fl_end; | ||
| 141 | lock->fl.fl_type = fl->fl_type; | ||
| 138 | } | 142 | } |
| 139 | 143 | ||
| 140 | static void nlmclnt_release_lockargs(struct nlm_rqst *req) | 144 | static void nlmclnt_release_lockargs(struct nlm_rqst *req) |
| 141 | { | 145 | { |
| 142 | struct file_lock *fl = &req->a_args.lock.fl; | 146 | BUG_ON(req->a_args.lock.fl.fl_ops != NULL); |
| 143 | |||
| 144 | if (fl->fl_ops && fl->fl_ops->fl_release_private) | ||
| 145 | fl->fl_ops->fl_release_private(fl); | ||
| 146 | } | ||
| 147 | |||
| 148 | /* | ||
| 149 | * Initialize arguments for GRANTED call. The nlm_rqst structure | ||
| 150 | * has been cleared already. | ||
| 151 | */ | ||
| 152 | int | ||
| 153 | nlmclnt_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock) | ||
| 154 | { | ||
| 155 | locks_copy_lock(&call->a_args.lock.fl, &lock->fl); | ||
| 156 | memcpy(&call->a_args.lock.fh, &lock->fh, sizeof(call->a_args.lock.fh)); | ||
| 157 | call->a_args.lock.caller = system_utsname.nodename; | ||
| 158 | call->a_args.lock.oh.len = lock->oh.len; | ||
| 159 | |||
| 160 | /* set default data area */ | ||
| 161 | call->a_args.lock.oh.data = call->a_owner; | ||
| 162 | |||
| 163 | if (lock->oh.len > NLMCLNT_OHSIZE) { | ||
| 164 | void *data = kmalloc(lock->oh.len, GFP_KERNEL); | ||
| 165 | if (!data) { | ||
| 166 | nlmclnt_freegrantargs(call); | ||
| 167 | return 0; | ||
| 168 | } | ||
| 169 | call->a_args.lock.oh.data = (u8 *) data; | ||
| 170 | } | ||
| 171 | |||
| 172 | memcpy(call->a_args.lock.oh.data, lock->oh.data, lock->oh.len); | ||
| 173 | return 1; | ||
| 174 | } | ||
| 175 | |||
| 176 | void | ||
| 177 | nlmclnt_freegrantargs(struct nlm_rqst *call) | ||
| 178 | { | ||
| 179 | struct file_lock *fl = &call->a_args.lock.fl; | ||
| 180 | /* | ||
| 181 | * Check whether we allocated memory for the owner. | ||
| 182 | */ | ||
| 183 | if (call->a_args.lock.oh.data != (u8 *) call->a_owner) { | ||
| 184 | kfree(call->a_args.lock.oh.data); | ||
| 185 | } | ||
| 186 | if (fl->fl_ops && fl->fl_ops->fl_release_private) | ||
| 187 | fl->fl_ops->fl_release_private(fl); | ||
| 188 | } | 147 | } |
| 189 | 148 | ||
| 190 | /* | 149 | /* |
| @@ -193,9 +152,8 @@ nlmclnt_freegrantargs(struct nlm_rqst *call) | |||
| 193 | int | 152 | int |
| 194 | nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl) | 153 | nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl) |
| 195 | { | 154 | { |
| 196 | struct nfs_server *nfssrv = NFS_SERVER(inode); | ||
| 197 | struct nlm_host *host; | 155 | struct nlm_host *host; |
| 198 | struct nlm_rqst reqst, *call = &reqst; | 156 | struct nlm_rqst *call; |
| 199 | sigset_t oldset; | 157 | sigset_t oldset; |
| 200 | unsigned long flags; | 158 | unsigned long flags; |
| 201 | int status, proto, vers; | 159 | int status, proto, vers; |
| @@ -209,23 +167,17 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl) | |||
| 209 | /* Retrieve transport protocol from NFS client */ | 167 | /* Retrieve transport protocol from NFS client */ |
| 210 | proto = NFS_CLIENT(inode)->cl_xprt->prot; | 168 | proto = NFS_CLIENT(inode)->cl_xprt->prot; |
| 211 | 169 | ||
| 212 | if (!(host = nlmclnt_lookup_host(NFS_ADDR(inode), proto, vers))) | 170 | host = nlmclnt_lookup_host(NFS_ADDR(inode), proto, vers); |
| 171 | if (host == NULL) | ||
| 213 | return -ENOLCK; | 172 | return -ENOLCK; |
| 214 | 173 | ||
| 215 | /* Create RPC client handle if not there, and copy soft | 174 | call = nlm_alloc_call(host); |
| 216 | * and intr flags from NFS client. */ | 175 | if (call == NULL) |
| 217 | if (host->h_rpcclnt == NULL) { | 176 | return -ENOMEM; |
| 218 | struct rpc_clnt *clnt; | ||
| 219 | 177 | ||
| 220 | /* Bind an rpc client to this host handle (does not | 178 | nlmclnt_locks_init_private(fl, host); |
| 221 | * perform a portmapper lookup) */ | 179 | /* Set up the argument struct */ |
| 222 | if (!(clnt = nlm_bind_host(host))) { | 180 | nlmclnt_setlockargs(call, fl); |
| 223 | status = -ENOLCK; | ||
| 224 | goto done; | ||
| 225 | } | ||
| 226 | clnt->cl_softrtry = nfssrv->client->cl_softrtry; | ||
| 227 | clnt->cl_intr = nfssrv->client->cl_intr; | ||
| 228 | } | ||
| 229 | 181 | ||
| 230 | /* Keep the old signal mask */ | 182 | /* Keep the old signal mask */ |
| 231 | spin_lock_irqsave(¤t->sighand->siglock, flags); | 183 | spin_lock_irqsave(¤t->sighand->siglock, flags); |
| @@ -238,26 +190,10 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl) | |||
| 238 | && (current->flags & PF_EXITING)) { | 190 | && (current->flags & PF_EXITING)) { |
| 239 | sigfillset(¤t->blocked); /* Mask all signals */ | 191 | sigfillset(¤t->blocked); /* Mask all signals */ |
| 240 | recalc_sigpending(); | 192 | recalc_sigpending(); |
| 241 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | ||
| 242 | 193 | ||
| 243 | call = nlmclnt_alloc_call(); | ||
| 244 | if (!call) { | ||
| 245 | status = -ENOMEM; | ||
| 246 | goto out_restore; | ||
| 247 | } | ||
| 248 | call->a_flags = RPC_TASK_ASYNC; | 194 | call->a_flags = RPC_TASK_ASYNC; |
| 249 | } else { | ||
| 250 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | ||
| 251 | memset(call, 0, sizeof(*call)); | ||
| 252 | locks_init_lock(&call->a_args.lock.fl); | ||
| 253 | locks_init_lock(&call->a_res.lock.fl); | ||
| 254 | } | 195 | } |
| 255 | call->a_host = host; | 196 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); |
| 256 | |||
| 257 | nlmclnt_locks_init_private(fl, host); | ||
| 258 | |||
| 259 | /* Set up the argument struct */ | ||
| 260 | nlmclnt_setlockargs(call, fl); | ||
| 261 | 197 | ||
| 262 | if (IS_SETLK(cmd) || IS_SETLKW(cmd)) { | 198 | if (IS_SETLK(cmd) || IS_SETLKW(cmd)) { |
| 263 | if (fl->fl_type != F_UNLCK) { | 199 | if (fl->fl_type != F_UNLCK) { |
| @@ -270,41 +206,58 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl) | |||
| 270 | else | 206 | else |
| 271 | status = -EINVAL; | 207 | status = -EINVAL; |
| 272 | 208 | ||
| 273 | out_restore: | 209 | fl->fl_ops->fl_release_private(fl); |
| 210 | fl->fl_ops = NULL; | ||
| 211 | |||
| 274 | spin_lock_irqsave(¤t->sighand->siglock, flags); | 212 | spin_lock_irqsave(¤t->sighand->siglock, flags); |
| 275 | current->blocked = oldset; | 213 | current->blocked = oldset; |
| 276 | recalc_sigpending(); | 214 | recalc_sigpending(); |
| 277 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | 215 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); |
| 278 | 216 | ||
| 279 | done: | ||
| 280 | dprintk("lockd: clnt proc returns %d\n", status); | 217 | dprintk("lockd: clnt proc returns %d\n", status); |
| 281 | nlm_release_host(host); | ||
| 282 | return status; | 218 | return status; |
| 283 | } | 219 | } |
| 284 | EXPORT_SYMBOL(nlmclnt_proc); | 220 | EXPORT_SYMBOL(nlmclnt_proc); |
| 285 | 221 | ||
| 286 | /* | 222 | /* |
| 287 | * Allocate an NLM RPC call struct | 223 | * Allocate an NLM RPC call struct |
| 224 | * | ||
| 225 | * Note: the caller must hold a reference to host. In case of failure, | ||
| 226 | * this reference will be released. | ||
| 288 | */ | 227 | */ |
| 289 | struct nlm_rqst * | 228 | struct nlm_rqst *nlm_alloc_call(struct nlm_host *host) |
| 290 | nlmclnt_alloc_call(void) | ||
| 291 | { | 229 | { |
| 292 | struct nlm_rqst *call; | 230 | struct nlm_rqst *call; |
| 293 | 231 | ||
| 294 | while (!signalled()) { | 232 | for(;;) { |
| 295 | call = (struct nlm_rqst *) kmalloc(sizeof(struct nlm_rqst), GFP_KERNEL); | 233 | call = kzalloc(sizeof(*call), GFP_KERNEL); |
| 296 | if (call) { | 234 | if (call != NULL) { |
| 297 | memset(call, 0, sizeof(*call)); | ||
| 298 | locks_init_lock(&call->a_args.lock.fl); | 235 | locks_init_lock(&call->a_args.lock.fl); |
| 299 | locks_init_lock(&call->a_res.lock.fl); | 236 | locks_init_lock(&call->a_res.lock.fl); |
| 237 | call->a_host = host; | ||
| 300 | return call; | 238 | return call; |
| 301 | } | 239 | } |
| 302 | printk("nlmclnt_alloc_call: failed, waiting for memory\n"); | 240 | if (signalled()) |
| 241 | break; | ||
| 242 | printk("nlm_alloc_call: failed, waiting for memory\n"); | ||
| 303 | schedule_timeout_interruptible(5*HZ); | 243 | schedule_timeout_interruptible(5*HZ); |
| 304 | } | 244 | } |
| 245 | nlm_release_host(host); | ||
| 305 | return NULL; | 246 | return NULL; |
| 306 | } | 247 | } |
| 307 | 248 | ||
| 249 | void nlm_release_call(struct nlm_rqst *call) | ||
| 250 | { | ||
| 251 | nlm_release_host(call->a_host); | ||
| 252 | nlmclnt_release_lockargs(call); | ||
| 253 | kfree(call); | ||
| 254 | } | ||
| 255 | |||
| 256 | static void nlmclnt_rpc_release(void *data) | ||
| 257 | { | ||
| 258 | return nlm_release_call(data); | ||
| 259 | } | ||
| 260 | |||
| 308 | static int nlm_wait_on_grace(wait_queue_head_t *queue) | 261 | static int nlm_wait_on_grace(wait_queue_head_t *queue) |
| 309 | { | 262 | { |
| 310 | DEFINE_WAIT(wait); | 263 | DEFINE_WAIT(wait); |
| @@ -401,57 +354,45 @@ in_grace_period: | |||
| 401 | /* | 354 | /* |
| 402 | * Generic NLM call, async version. | 355 | * Generic NLM call, async version. |
| 403 | */ | 356 | */ |
| 404 | int nlmsvc_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) | 357 | static int __nlm_async_call(struct nlm_rqst *req, u32 proc, struct rpc_message *msg, const struct rpc_call_ops *tk_ops) |
| 405 | { | 358 | { |
| 406 | struct nlm_host *host = req->a_host; | 359 | struct nlm_host *host = req->a_host; |
| 407 | struct rpc_clnt *clnt; | 360 | struct rpc_clnt *clnt; |
| 408 | struct rpc_message msg = { | 361 | int status = -ENOLCK; |
| 409 | .rpc_argp = &req->a_args, | ||
| 410 | .rpc_resp = &req->a_res, | ||
| 411 | }; | ||
| 412 | int status; | ||
| 413 | 362 | ||
| 414 | dprintk("lockd: call procedure %d on %s (async)\n", | 363 | dprintk("lockd: call procedure %d on %s (async)\n", |
| 415 | (int)proc, host->h_name); | 364 | (int)proc, host->h_name); |
| 416 | 365 | ||
| 417 | /* If we have no RPC client yet, create one. */ | 366 | /* If we have no RPC client yet, create one. */ |
| 418 | if ((clnt = nlm_bind_host(host)) == NULL) | 367 | clnt = nlm_bind_host(host); |
| 419 | return -ENOLCK; | 368 | if (clnt == NULL) |
| 420 | msg.rpc_proc = &clnt->cl_procinfo[proc]; | 369 | goto out_err; |
| 370 | msg->rpc_proc = &clnt->cl_procinfo[proc]; | ||
| 421 | 371 | ||
| 422 | /* bootstrap and kick off the async RPC call */ | 372 | /* bootstrap and kick off the async RPC call */ |
| 423 | status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, tk_ops, req); | 373 | status = rpc_call_async(clnt, msg, RPC_TASK_ASYNC, tk_ops, req); |
| 424 | 374 | if (status == 0) | |
| 375 | return 0; | ||
| 376 | out_err: | ||
| 377 | nlm_release_call(req); | ||
| 425 | return status; | 378 | return status; |
| 426 | } | 379 | } |
| 427 | 380 | ||
| 428 | static int nlmclnt_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) | 381 | int nlm_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) |
| 429 | { | 382 | { |
| 430 | struct nlm_host *host = req->a_host; | ||
| 431 | struct rpc_clnt *clnt; | ||
| 432 | struct nlm_args *argp = &req->a_args; | ||
| 433 | struct nlm_res *resp = &req->a_res; | ||
| 434 | struct rpc_message msg = { | 383 | struct rpc_message msg = { |
| 435 | .rpc_argp = argp, | 384 | .rpc_argp = &req->a_args, |
| 436 | .rpc_resp = resp, | 385 | .rpc_resp = &req->a_res, |
| 437 | }; | 386 | }; |
| 438 | int status; | 387 | return __nlm_async_call(req, proc, &msg, tk_ops); |
| 439 | 388 | } | |
| 440 | dprintk("lockd: call procedure %d on %s (async)\n", | ||
| 441 | (int)proc, host->h_name); | ||
| 442 | |||
| 443 | /* If we have no RPC client yet, create one. */ | ||
| 444 | if ((clnt = nlm_bind_host(host)) == NULL) | ||
| 445 | return -ENOLCK; | ||
| 446 | msg.rpc_proc = &clnt->cl_procinfo[proc]; | ||
| 447 | 389 | ||
| 448 | /* Increment host refcount */ | 390 | int nlm_async_reply(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) |
| 449 | nlm_get_host(host); | 391 | { |
| 450 | /* bootstrap and kick off the async RPC call */ | 392 | struct rpc_message msg = { |
| 451 | status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, tk_ops, req); | 393 | .rpc_argp = &req->a_res, |
| 452 | if (status < 0) | 394 | }; |
| 453 | nlm_release_host(host); | 395 | return __nlm_async_call(req, proc, &msg, tk_ops); |
| 454 | return status; | ||
| 455 | } | 396 | } |
| 456 | 397 | ||
| 457 | /* | 398 | /* |
| @@ -463,36 +404,41 @@ nlmclnt_test(struct nlm_rqst *req, struct file_lock *fl) | |||
| 463 | int status; | 404 | int status; |
| 464 | 405 | ||
| 465 | status = nlmclnt_call(req, NLMPROC_TEST); | 406 | status = nlmclnt_call(req, NLMPROC_TEST); |
| 466 | nlmclnt_release_lockargs(req); | ||
| 467 | if (status < 0) | 407 | if (status < 0) |
| 468 | return status; | 408 | goto out; |
| 469 | 409 | ||
| 470 | status = req->a_res.status; | 410 | switch (req->a_res.status) { |
| 471 | if (status == NLM_LCK_GRANTED) { | 411 | case NLM_LCK_GRANTED: |
| 472 | fl->fl_type = F_UNLCK; | 412 | fl->fl_type = F_UNLCK; |
| 473 | } if (status == NLM_LCK_DENIED) { | 413 | break; |
| 474 | /* | 414 | case NLM_LCK_DENIED: |
| 475 | * Report the conflicting lock back to the application. | 415 | /* |
| 476 | */ | 416 | * Report the conflicting lock back to the application. |
| 477 | locks_copy_lock(fl, &req->a_res.lock.fl); | 417 | */ |
| 478 | fl->fl_pid = 0; | 418 | fl->fl_start = req->a_res.lock.fl.fl_start; |
| 479 | } else { | 419 | fl->fl_end = req->a_res.lock.fl.fl_start; |
| 480 | return nlm_stat_to_errno(req->a_res.status); | 420 | fl->fl_type = req->a_res.lock.fl.fl_type; |
| 421 | fl->fl_pid = 0; | ||
| 422 | break; | ||
| 423 | default: | ||
| 424 | status = nlm_stat_to_errno(req->a_res.status); | ||
| 481 | } | 425 | } |
| 482 | 426 | out: | |
| 483 | return 0; | 427 | nlm_release_call(req); |
| 428 | return status; | ||
| 484 | } | 429 | } |
| 485 | 430 | ||
| 486 | static void nlmclnt_locks_copy_lock(struct file_lock *new, struct file_lock *fl) | 431 | static void nlmclnt_locks_copy_lock(struct file_lock *new, struct file_lock *fl) |
| 487 | { | 432 | { |
| 488 | memcpy(&new->fl_u.nfs_fl, &fl->fl_u.nfs_fl, sizeof(new->fl_u.nfs_fl)); | 433 | new->fl_u.nfs_fl.state = fl->fl_u.nfs_fl.state; |
| 489 | nlm_get_lockowner(new->fl_u.nfs_fl.owner); | 434 | new->fl_u.nfs_fl.owner = nlm_get_lockowner(fl->fl_u.nfs_fl.owner); |
| 435 | list_add_tail(&new->fl_u.nfs_fl.list, &fl->fl_u.nfs_fl.owner->host->h_granted); | ||
| 490 | } | 436 | } |
| 491 | 437 | ||
| 492 | static void nlmclnt_locks_release_private(struct file_lock *fl) | 438 | static void nlmclnt_locks_release_private(struct file_lock *fl) |
| 493 | { | 439 | { |
| 440 | list_del(&fl->fl_u.nfs_fl.list); | ||
| 494 | nlm_put_lockowner(fl->fl_u.nfs_fl.owner); | 441 | nlm_put_lockowner(fl->fl_u.nfs_fl.owner); |
| 495 | fl->fl_ops = NULL; | ||
| 496 | } | 442 | } |
| 497 | 443 | ||
| 498 | static struct file_lock_operations nlmclnt_lock_ops = { | 444 | static struct file_lock_operations nlmclnt_lock_ops = { |
| @@ -504,8 +450,8 @@ static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *ho | |||
| 504 | { | 450 | { |
| 505 | BUG_ON(fl->fl_ops != NULL); | 451 | BUG_ON(fl->fl_ops != NULL); |
| 506 | fl->fl_u.nfs_fl.state = 0; | 452 | fl->fl_u.nfs_fl.state = 0; |
| 507 | fl->fl_u.nfs_fl.flags = 0; | ||
| 508 | fl->fl_u.nfs_fl.owner = nlm_find_lockowner(host, fl->fl_owner); | 453 | fl->fl_u.nfs_fl.owner = nlm_find_lockowner(host, fl->fl_owner); |
| 454 | INIT_LIST_HEAD(&fl->fl_u.nfs_fl.list); | ||
| 509 | fl->fl_ops = &nlmclnt_lock_ops; | 455 | fl->fl_ops = &nlmclnt_lock_ops; |
| 510 | } | 456 | } |
| 511 | 457 | ||
| @@ -552,57 +498,52 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) | |||
| 552 | { | 498 | { |
| 553 | struct nlm_host *host = req->a_host; | 499 | struct nlm_host *host = req->a_host; |
| 554 | struct nlm_res *resp = &req->a_res; | 500 | struct nlm_res *resp = &req->a_res; |
| 555 | long timeout; | 501 | struct nlm_wait *block = NULL; |
| 556 | int status; | 502 | int status = -ENOLCK; |
| 557 | 503 | ||
| 558 | if (!host->h_monitored && nsm_monitor(host) < 0) { | 504 | if (!host->h_monitored && nsm_monitor(host) < 0) { |
| 559 | printk(KERN_NOTICE "lockd: failed to monitor %s\n", | 505 | printk(KERN_NOTICE "lockd: failed to monitor %s\n", |
| 560 | host->h_name); | 506 | host->h_name); |
| 561 | status = -ENOLCK; | ||
| 562 | goto out; | 507 | goto out; |
| 563 | } | 508 | } |
| 564 | 509 | ||
| 565 | if (req->a_args.block) { | 510 | block = nlmclnt_prepare_block(host, fl); |
| 566 | status = nlmclnt_prepare_block(req, host, fl); | ||
| 567 | if (status < 0) | ||
| 568 | goto out; | ||
| 569 | } | ||
| 570 | for(;;) { | 511 | for(;;) { |
| 571 | status = nlmclnt_call(req, NLMPROC_LOCK); | 512 | status = nlmclnt_call(req, NLMPROC_LOCK); |
| 572 | if (status < 0) | 513 | if (status < 0) |
| 573 | goto out_unblock; | 514 | goto out_unblock; |
| 574 | if (resp->status != NLM_LCK_BLOCKED) | 515 | if (!req->a_args.block) |
| 575 | break; | 516 | break; |
| 576 | /* Wait on an NLM blocking lock */ | ||
| 577 | timeout = nlmclnt_block(req, NLMCLNT_POLL_TIMEOUT); | ||
| 578 | /* Did a reclaimer thread notify us of a server reboot? */ | 517 | /* Did a reclaimer thread notify us of a server reboot? */ |
| 579 | if (resp->status == NLM_LCK_DENIED_GRACE_PERIOD) | 518 | if (resp->status == NLM_LCK_DENIED_GRACE_PERIOD) |
| 580 | continue; | 519 | continue; |
| 581 | if (resp->status != NLM_LCK_BLOCKED) | 520 | if (resp->status != NLM_LCK_BLOCKED) |
| 582 | break; | 521 | break; |
| 583 | if (timeout >= 0) | 522 | /* Wait on an NLM blocking lock */ |
| 584 | continue; | 523 | status = nlmclnt_block(block, req, NLMCLNT_POLL_TIMEOUT); |
| 585 | /* We were interrupted. Send a CANCEL request to the server | 524 | /* if we were interrupted. Send a CANCEL request to the server |
| 586 | * and exit | 525 | * and exit |
| 587 | */ | 526 | */ |
| 588 | status = (int)timeout; | 527 | if (status < 0) |
| 589 | goto out_unblock; | 528 | goto out_unblock; |
| 529 | if (resp->status != NLM_LCK_BLOCKED) | ||
| 530 | break; | ||
| 590 | } | 531 | } |
| 591 | 532 | ||
| 592 | if (resp->status == NLM_LCK_GRANTED) { | 533 | if (resp->status == NLM_LCK_GRANTED) { |
| 593 | fl->fl_u.nfs_fl.state = host->h_state; | 534 | fl->fl_u.nfs_fl.state = host->h_state; |
| 594 | fl->fl_u.nfs_fl.flags |= NFS_LCK_GRANTED; | ||
| 595 | fl->fl_flags |= FL_SLEEP; | 535 | fl->fl_flags |= FL_SLEEP; |
| 536 | /* Ensure the resulting lock will get added to granted list */ | ||
| 596 | do_vfs_lock(fl); | 537 | do_vfs_lock(fl); |
| 597 | } | 538 | } |
| 598 | status = nlm_stat_to_errno(resp->status); | 539 | status = nlm_stat_to_errno(resp->status); |
| 599 | out_unblock: | 540 | out_unblock: |
| 600 | nlmclnt_finish_block(req); | 541 | nlmclnt_finish_block(block); |
| 601 | /* Cancel the blocked request if it is still pending */ | 542 | /* Cancel the blocked request if it is still pending */ |
| 602 | if (resp->status == NLM_LCK_BLOCKED) | 543 | if (resp->status == NLM_LCK_BLOCKED) |
| 603 | nlmclnt_cancel(host, req->a_args.block, fl); | 544 | nlmclnt_cancel(host, req->a_args.block, fl); |
| 604 | out: | 545 | out: |
| 605 | nlmclnt_release_lockargs(req); | 546 | nlm_release_call(req); |
| 606 | return status; | 547 | return status; |
| 607 | } | 548 | } |
| 608 | 549 | ||
| @@ -658,10 +599,6 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) | |||
| 658 | struct nlm_res *resp = &req->a_res; | 599 | struct nlm_res *resp = &req->a_res; |
| 659 | int status; | 600 | int status; |
| 660 | 601 | ||
| 661 | /* Clean the GRANTED flag now so the lock doesn't get | ||
| 662 | * reclaimed while we're stuck in the unlock call. */ | ||
| 663 | fl->fl_u.nfs_fl.flags &= ~NFS_LCK_GRANTED; | ||
| 664 | |||
| 665 | /* | 602 | /* |
| 666 | * Note: the server is supposed to either grant us the unlock | 603 | * Note: the server is supposed to either grant us the unlock |
| 667 | * request, or to deny it with NLM_LCK_DENIED_GRACE_PERIOD. In either | 604 | * request, or to deny it with NLM_LCK_DENIED_GRACE_PERIOD. In either |
| @@ -669,32 +606,24 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) | |||
| 669 | */ | 606 | */ |
| 670 | do_vfs_lock(fl); | 607 | do_vfs_lock(fl); |
| 671 | 608 | ||
| 672 | if (req->a_flags & RPC_TASK_ASYNC) { | 609 | if (req->a_flags & RPC_TASK_ASYNC) |
| 673 | status = nlmclnt_async_call(req, NLMPROC_UNLOCK, | 610 | return nlm_async_call(req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops); |
| 674 | &nlmclnt_unlock_ops); | ||
| 675 | /* Hrmf... Do the unlock early since locks_remove_posix() | ||
| 676 | * really expects us to free the lock synchronously */ | ||
| 677 | if (status < 0) { | ||
| 678 | nlmclnt_release_lockargs(req); | ||
| 679 | kfree(req); | ||
| 680 | } | ||
| 681 | return status; | ||
| 682 | } | ||
| 683 | 611 | ||
| 684 | status = nlmclnt_call(req, NLMPROC_UNLOCK); | 612 | status = nlmclnt_call(req, NLMPROC_UNLOCK); |
| 685 | nlmclnt_release_lockargs(req); | ||
| 686 | if (status < 0) | 613 | if (status < 0) |
| 687 | return status; | 614 | goto out; |
| 688 | 615 | ||
| 616 | status = 0; | ||
| 689 | if (resp->status == NLM_LCK_GRANTED) | 617 | if (resp->status == NLM_LCK_GRANTED) |
| 690 | return 0; | 618 | goto out; |
| 691 | 619 | ||
| 692 | if (resp->status != NLM_LCK_DENIED_NOLOCKS) | 620 | if (resp->status != NLM_LCK_DENIED_NOLOCKS) |
| 693 | printk("lockd: unexpected unlock status: %d\n", resp->status); | 621 | printk("lockd: unexpected unlock status: %d\n", resp->status); |
| 694 | |||
| 695 | /* What to do now? I'm out of my depth... */ | 622 | /* What to do now? I'm out of my depth... */ |
| 696 | 623 | status = -ENOLCK; | |
| 697 | return -ENOLCK; | 624 | out: |
| 625 | nlm_release_call(req); | ||
| 626 | return status; | ||
| 698 | } | 627 | } |
| 699 | 628 | ||
| 700 | static void nlmclnt_unlock_callback(struct rpc_task *task, void *data) | 629 | static void nlmclnt_unlock_callback(struct rpc_task *task, void *data) |
| @@ -716,9 +645,6 @@ static void nlmclnt_unlock_callback(struct rpc_task *task, void *data) | |||
| 716 | if (status != NLM_LCK_GRANTED) | 645 | if (status != NLM_LCK_GRANTED) |
| 717 | printk(KERN_WARNING "lockd: unexpected unlock status: %d\n", status); | 646 | printk(KERN_WARNING "lockd: unexpected unlock status: %d\n", status); |
| 718 | die: | 647 | die: |
| 719 | nlm_release_host(req->a_host); | ||
| 720 | nlmclnt_release_lockargs(req); | ||
| 721 | kfree(req); | ||
| 722 | return; | 648 | return; |
| 723 | retry_rebind: | 649 | retry_rebind: |
| 724 | nlm_rebind_host(req->a_host); | 650 | nlm_rebind_host(req->a_host); |
| @@ -728,6 +654,7 @@ die: | |||
| 728 | 654 | ||
| 729 | static const struct rpc_call_ops nlmclnt_unlock_ops = { | 655 | static const struct rpc_call_ops nlmclnt_unlock_ops = { |
| 730 | .rpc_call_done = nlmclnt_unlock_callback, | 656 | .rpc_call_done = nlmclnt_unlock_callback, |
| 657 | .rpc_release = nlmclnt_rpc_release, | ||
| 731 | }; | 658 | }; |
| 732 | 659 | ||
| 733 | /* | 660 | /* |
| @@ -749,20 +676,15 @@ static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl | |||
| 749 | recalc_sigpending(); | 676 | recalc_sigpending(); |
| 750 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | 677 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); |
| 751 | 678 | ||
| 752 | req = nlmclnt_alloc_call(); | 679 | req = nlm_alloc_call(nlm_get_host(host)); |
| 753 | if (!req) | 680 | if (!req) |
| 754 | return -ENOMEM; | 681 | return -ENOMEM; |
| 755 | req->a_host = host; | ||
| 756 | req->a_flags = RPC_TASK_ASYNC; | 682 | req->a_flags = RPC_TASK_ASYNC; |
| 757 | 683 | ||
| 758 | nlmclnt_setlockargs(req, fl); | 684 | nlmclnt_setlockargs(req, fl); |
| 759 | req->a_args.block = block; | 685 | req->a_args.block = block; |
| 760 | 686 | ||
| 761 | status = nlmclnt_async_call(req, NLMPROC_CANCEL, &nlmclnt_cancel_ops); | 687 | status = nlm_async_call(req, NLMPROC_CANCEL, &nlmclnt_cancel_ops); |
| 762 | if (status < 0) { | ||
| 763 | nlmclnt_release_lockargs(req); | ||
| 764 | kfree(req); | ||
| 765 | } | ||
| 766 | 688 | ||
| 767 | spin_lock_irqsave(¤t->sighand->siglock, flags); | 689 | spin_lock_irqsave(¤t->sighand->siglock, flags); |
| 768 | current->blocked = oldset; | 690 | current->blocked = oldset; |
| @@ -791,6 +713,7 @@ static void nlmclnt_cancel_callback(struct rpc_task *task, void *data) | |||
| 791 | switch (req->a_res.status) { | 713 | switch (req->a_res.status) { |
| 792 | case NLM_LCK_GRANTED: | 714 | case NLM_LCK_GRANTED: |
| 793 | case NLM_LCK_DENIED_GRACE_PERIOD: | 715 | case NLM_LCK_DENIED_GRACE_PERIOD: |
| 716 | case NLM_LCK_DENIED: | ||
| 794 | /* Everything's good */ | 717 | /* Everything's good */ |
| 795 | break; | 718 | break; |
| 796 | case NLM_LCK_DENIED_NOLOCKS: | 719 | case NLM_LCK_DENIED_NOLOCKS: |
| @@ -802,9 +725,6 @@ static void nlmclnt_cancel_callback(struct rpc_task *task, void *data) | |||
| 802 | } | 725 | } |
| 803 | 726 | ||
| 804 | die: | 727 | die: |
| 805 | nlm_release_host(req->a_host); | ||
| 806 | nlmclnt_release_lockargs(req); | ||
| 807 | kfree(req); | ||
| 808 | return; | 728 | return; |
| 809 | 729 | ||
| 810 | retry_cancel: | 730 | retry_cancel: |
| @@ -818,6 +738,7 @@ retry_cancel: | |||
| 818 | 738 | ||
| 819 | static const struct rpc_call_ops nlmclnt_cancel_ops = { | 739 | static const struct rpc_call_ops nlmclnt_cancel_ops = { |
| 820 | .rpc_call_done = nlmclnt_cancel_callback, | 740 | .rpc_call_done = nlmclnt_cancel_callback, |
| 741 | .rpc_release = nlmclnt_rpc_release, | ||
| 821 | }; | 742 | }; |
| 822 | 743 | ||
| 823 | /* | 744 | /* |
