1 /* 2 * linux/fs/lockd/svcproc.c 3 * 4 * Lockd server procedures. We don't implement the NLM_*_RES 5 * procedures because we don't use the async procedures. 6 * 7 * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> 8 */ 9 10 #include <linux/config.h> 11 #include <linux/types.h> 12 #include <linux/time.h> 13 #include <linux/slab.h> 14 #include <linux/in.h> 15 #include <linux/sunrpc/svc.h> 16 #include <linux/sunrpc/clnt.h> 17 #include <linux/nfsd/nfsd.h> 18 #include <linux/lockd/lockd.h> 19 #include <linux/lockd/share.h> 20 #include <linux/lockd/sm_inter.h> 21 22 23 #define NLMDBG_FACILITY NLMDBG_CLIENT 24 25 static u32 nlmsvc_callback(struct svc_rqst *, u32, struct nlm_res *); 26 27 static const struct rpc_call_ops nlmsvc_callback_ops; 28 29 #ifdef CONFIG_LOCKD_V4 30 static u32 31 cast_to_nlm(u32 status, u32 vers) 32 { 33 /* Note: status is assumed to be in network byte order !!! */ 34 if (vers != 4){ 35 switch (status) { 36 case nlm_granted: 37 case nlm_lck_denied: 38 case nlm_lck_denied_nolocks: 39 case nlm_lck_blocked: 40 case nlm_lck_denied_grace_period: 41 break; 42 case nlm4_deadlock: 43 status = nlm_lck_denied; 44 break; 45 default: 46 status = nlm_lck_denied_nolocks; 47 } 48 } 49 50 return (status); 51 } 52 #define cast_status(status) (cast_to_nlm(status, rqstp->rq_vers)) 53 #else 54 #define cast_status(status) (status) 55 #endif 56 57 /* 58 * Obtain client and file from arguments 59 */ 60 static u32 61 nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, 62 struct nlm_host **hostp, struct nlm_file **filp) 63 { 64 struct nlm_host *host = NULL; 65 struct nlm_file *file = NULL; 66 struct nlm_lock *lock = &argp->lock; 67 u32 error; 68 69 /* nfsd callbacks must have been installed for this procedure */ 70 if (!nlmsvc_ops) 71 return nlm_lck_denied_nolocks; 72 73 /* Obtain host handle */ 74 if (!(host = nlmsvc_lookup_host(rqstp)) 75 || (argp->monitor && !host->h_monitored && nsm_monitor(host) < 0)) 76 goto no_locks; 77 *hostp = host; 78 79 /* Obtain file pointer. Not used by FREE_ALL call. */ 80 if (filp != NULL) { 81 if ((error = nlm_lookup_file(rqstp, &file, &lock->fh)) != 0) 82 goto no_locks; 83 *filp = file; 84 85 /* Set up the missing parts of the file_lock structure */ 86 lock->fl.fl_file = file->f_file; 87 lock->fl.fl_owner = (fl_owner_t) host; 88 lock->fl.fl_lmops = &nlmsvc_lock_operations; 89 } 90 91 return 0; 92 93 no_locks: 94 if (host) 95 nlm_release_host(host); 96 return nlm_lck_denied_nolocks; 97 } 98 99 /* 100 * NULL: Test for presence of service 101 */ 102 static int 103 nlmsvc_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) 104 { 105 dprintk("lockd: NULL called\n"); 106 return rpc_success; 107 } 108 109 /* 110 * TEST: Check for conflicting lock 111 */ 112 static int 113 nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp, 114 struct nlm_res *resp) 115 { 116 struct nlm_host *host; 117 struct nlm_file *file; 118 119 dprintk("lockd: TEST called\n"); 120 resp->cookie = argp->cookie; 121 122 /* Don't accept test requests during grace period */ 123 if (nlmsvc_grace_period) { 124 resp->status = nlm_lck_denied_grace_period; 125 return rpc_success; 126 } 127 128 /* Obtain client and file */ 129 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) 130 return rpc_success; 131 132 /* Now check for conflicting locks */ 133 resp->status = cast_status(nlmsvc_testlock(file, &argp->lock, &resp->lock)); 134 135 dprintk("lockd: TEST status %d vers %d\n", 136 ntohl(resp->status), rqstp->rq_vers); 137 nlm_release_host(host); 138 nlm_release_file(file); 139 return rpc_success; 140 } 141 142 static int 143 nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp, 144 struct nlm_res *resp) 145 { 146 struct nlm_host *host; 147 struct nlm_file *file; 148 149 dprintk("lockd: LOCK called\n"); 150 151 resp->cookie = argp->cookie; 152 153 /* Don't accept new lock requests during grace period */ 154 if (nlmsvc_grace_period && !argp->reclaim) { 155 resp->status = nlm_lck_denied_grace_period; 156 return rpc_success; 157 } 158 159 /* Obtain client and file */ 160 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) 161 return rpc_success; 162 163 #if 0 164 /* If supplied state doesn't match current state, we assume it's 165 * an old request that time-warped somehow. Any error return would 166 * do in this case because it's irrelevant anyway. 167 * 168 * NB: We don't retrieve the remote host's state yet. 169 */ 170 if (host->h_nsmstate && host->h_nsmstate != argp->state) { 171 resp->status = nlm_lck_denied_nolocks; 172 } else 173 #endif 174 175 /* Now try to lock the file */ 176 resp->status = cast_status(nlmsvc_lock(rqstp, file, &argp->lock, 177 argp->block, &argp->cookie)); 178 179 dprintk("lockd: LOCK status %d\n", ntohl(resp->status)); 180 nlm_release_host(host); 181 nlm_release_file(file); 182 return rpc_success; 183 } 184 185 static int 186 nlmsvc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp, 187 struct nlm_res *resp) 188 { 189 struct nlm_host *host; 190 struct nlm_file *file; 191 192 dprintk("lockd: CANCEL called\n"); 193 194 resp->cookie = argp->cookie; 195 196 /* Don't accept requests during grace period */ 197 if (nlmsvc_grace_period) { 198 resp->status = nlm_lck_denied_grace_period; 199 return rpc_success; 200 } 201 202 /* Obtain client and file */ 203 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) 204 return rpc_success; 205 206 /* Try to cancel request. */ 207 resp->status = cast_status(nlmsvc_cancel_blocked(file, &argp->lock)); 208 209 dprintk("lockd: CANCEL status %d\n", ntohl(resp->status)); 210 nlm_release_host(host); 211 nlm_release_file(file); 212 return rpc_success; 213 } 214 215 /* 216 * UNLOCK: release a lock 217 */ 218 static int 219 nlmsvc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp, 220 struct nlm_res *resp) 221 { 222 struct nlm_host *host; 223 struct nlm_file *file; 224 225 dprintk("lockd: UNLOCK called\n"); 226 227 resp->cookie = argp->cookie; 228 229 /* Don't accept new lock requests during grace period */ 230 if (nlmsvc_grace_period) { 231 resp->status = nlm_lck_denied_grace_period; 232 return rpc_success; 233 } 234 235 /* Obtain client and file */ 236 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) 237 return rpc_success; 238 239 /* Now try to remove the lock */ 240 resp->status = cast_status(nlmsvc_unlock(file, &argp->lock)); 241 242 dprintk("lockd: UNLOCK status %d\n", ntohl(resp->status)); 243 nlm_release_host(host); 244 nlm_release_file(file); 245 return rpc_success; 246 } 247 248 /* 249 * GRANTED: A server calls us to tell that a process' lock request 250 * was granted 251 */ 252 static int 253 nlmsvc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp, 254 struct nlm_res *resp) 255 { 256 resp->cookie = argp->cookie; 257 258 dprintk("lockd: GRANTED called\n"); 259 resp->status = nlmclnt_grant(&argp->lock); 260 dprintk("lockd: GRANTED status %d\n", ntohl(resp->status)); 261 return rpc_success; 262 } 263 264 /* 265 * `Async' versions of the above service routines. They aren't really, 266 * because we send the callback before the reply proper. I hope this 267 * doesn't break any clients. 268 */ 269 static int 270 nlmsvc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp, 271 void *resp) 272 { 273 struct nlm_res res; 274 u32 stat; 275 276 dprintk("lockd: TEST_MSG called\n"); 277 memset(&res, 0, sizeof(res)); 278 279 if ((stat = nlmsvc_proc_test(rqstp, argp, &res)) == 0) 280 stat = nlmsvc_callback(rqstp, NLMPROC_TEST_RES, &res); 281 return stat; 282 } 283 284 static int 285 nlmsvc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp, 286 void *resp) 287 { 288 struct nlm_res res; 289 u32 stat; 290 291 dprintk("lockd: LOCK_MSG called\n"); 292 memset(&res, 0, sizeof(res)); 293 294 if ((stat = nlmsvc_proc_lock(rqstp, argp, &res)) == 0) 295 stat = nlmsvc_callback(rqstp, NLMPROC_LOCK_RES, &res); 296 return stat; 297 } 298 299 static int 300 nlmsvc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp, 301 void *resp) 302 { 303 struct nlm_res res; 304 u32 stat; 305 306 dprintk("lockd: CANCEL_MSG called\n"); 307 memset(&res, 0, sizeof(res)); 308 309 if ((stat = nlmsvc_proc_cancel(rqstp, argp, &res)) == 0) 310 stat = nlmsvc_callback(rqstp, NLMPROC_CANCEL_RES, &res); 311 return stat; 312 } 313 314 static int 315 nlmsvc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp, 316 void *resp) 317 { 318 struct nlm_res res; 319 u32 stat; 320 321 dprintk("lockd: UNLOCK_MSG called\n"); 322 memset(&res, 0, sizeof(res)); 323 324 if ((stat = nlmsvc_proc_unlock(rqstp, argp, &res)) == 0) 325 stat = nlmsvc_callback(rqstp, NLMPROC_UNLOCK_RES, &res); 326 return stat; 327 } 328 329 static int 330 nlmsvc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp, 331 void *resp) 332 { 333 struct nlm_res res; 334 u32 stat; 335 336 dprintk("lockd: GRANTED_MSG called\n"); 337 memset(&res, 0, sizeof(res)); 338 339 if ((stat = nlmsvc_proc_granted(rqstp, argp, &res)) == 0) 340 stat = nlmsvc_callback(rqstp, NLMPROC_GRANTED_RES, &res); 341 return stat; 342 } 343 344 /* 345 * SHARE: create a DOS share or alter existing share. 346 */ 347 static int 348 nlmsvc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp, 349 struct nlm_res *resp) 350 { 351 struct nlm_host *host; 352 struct nlm_file *file; 353 354 dprintk("lockd: SHARE called\n"); 355 356 resp->cookie = argp->cookie; 357 358 /* Don't accept new lock requests during grace period */ 359 if (nlmsvc_grace_period && !argp->reclaim) { 360 resp->status = nlm_lck_denied_grace_period; 361 return rpc_success; 362 } 363 364 /* Obtain client and file */ 365 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) 366 return rpc_success; 367 368 /* Now try to create the share */ 369 resp->status = cast_status(nlmsvc_share_file(host, file, argp)); 370 371 dprintk("lockd: SHARE status %d\n", ntohl(resp->status)); 372 nlm_release_host(host); 373 nlm_release_file(file); 374 return rpc_success; 375 } 376 377 /* 378 * UNSHARE: Release a DOS share. 379 */ 380 static int 381 nlmsvc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp, 382 struct nlm_res *resp) 383 { 384 struct nlm_host *host; 385 struct nlm_file *file; 386 387 dprintk("lockd: UNSHARE called\n"); 388 389 resp->cookie = argp->cookie; 390 391 /* Don't accept requests during grace period */ 392 if (nlmsvc_grace_period) { 393 resp->status = nlm_lck_denied_grace_period; 394 return rpc_success; 395 } 396 397 /* Obtain client and file */ 398 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) 399 return rpc_success; 400 401 /* Now try to unshare the file */ 402 resp->status = cast_status(nlmsvc_unshare_file(host, file, argp)); 403 404 dprintk("lockd: UNSHARE status %d\n", ntohl(resp->status)); 405 nlm_release_host(host); 406 nlm_release_file(file); 407 return rpc_success; 408 } 409 410 /* 411 * NM_LOCK: Create an unmonitored lock 412 */ 413 static int 414 nlmsvc_proc_nm_lock(struct svc_rqst *rqstp, struct nlm_args *argp, 415 struct nlm_res *resp) 416 { 417 dprintk("lockd: NM_LOCK called\n"); 418 419 argp->monitor = 0; /* just clean the monitor flag */ 420 return nlmsvc_proc_lock(rqstp, argp, resp); 421 } 422 423 /* 424 * FREE_ALL: Release all locks and shares held by client 425 */ 426 static int 427 nlmsvc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp, 428 void *resp) 429 { 430 struct nlm_host *host; 431 432 /* Obtain client */ 433 if (nlmsvc_retrieve_args(rqstp, argp, &host, NULL)) 434 return rpc_success; 435 436 nlmsvc_free_host_resources(host); 437 nlm_release_host(host); 438 return rpc_success; 439 } 440 441 /* 442 * SM_NOTIFY: private callback from statd (not part of official NLM proto) 443 */ 444 static int 445 nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, 446 void *resp) 447 { 448 struct sockaddr_in saddr = rqstp->rq_addr; 449 int vers = argp->vers; 450 int prot = argp->proto >> 1; 451 struct nlm_host *host; 452 453 dprintk("lockd: SM_NOTIFY called\n"); 454 if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK) 455 || ntohs(saddr.sin_port) >= 1024) { 456 printk(KERN_WARNING 457 "lockd: rejected NSM callback from %08x:%d\n", 458 ntohl(rqstp->rq_addr.sin_addr.s_addr), 459 ntohs(rqstp->rq_addr.sin_port)); 460 return rpc_system_err; 461 } 462 463 /* Obtain the host pointer for this NFS server and try to 464 * reclaim all locks we hold on this server. 465 */ 466 saddr.sin_addr.s_addr = argp->addr; 467 if ((argp->proto & 1)==0) { 468 if ((host = nlmclnt_lookup_host(&saddr, prot, vers)) != NULL) { 469 nlmclnt_recovery(host, argp->state); 470 nlm_release_host(host); 471 } 472 } else { 473 /* If we run on an NFS server, delete all locks held by the client */ 474 if ((host = nlm_lookup_host(1, &saddr, prot, vers)) != NULL) { 475 nlmsvc_free_host_resources(host); 476 nlm_release_host(host); 477 } 478 } 479 480 return rpc_success; 481 } 482 483 /* 484 * client sent a GRANTED_RES, let's remove the associated block 485 */ 486 static int 487 nlmsvc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res *argp, 488 void *resp) 489 { 490 if (!nlmsvc_ops) 491 return rpc_success; 492 493 dprintk("lockd: GRANTED_RES called\n"); 494 495 nlmsvc_grant_reply(rqstp, &argp->cookie, argp->status); 496 return rpc_success; 497 } 498 499 /* 500 * This is the generic lockd callback for async RPC calls 501 */ 502 static u32 503 nlmsvc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp) 504 { 505 struct nlm_host *host; 506 struct nlm_rqst *call; 507 508 if (!(call = nlmclnt_alloc_call())) 509 return rpc_system_err; 510 511 host = nlmclnt_lookup_host(&rqstp->rq_addr, 512 rqstp->rq_prot, rqstp->rq_vers); 513 if (!host) { 514 kfree(call); 515 return rpc_system_err; 516 } 517 518 call->a_flags = RPC_TASK_ASYNC; 519 call->a_host = host; 520 memcpy(&call->a_args, resp, sizeof(*resp)); 521 522 if (nlmsvc_async_call(call, proc, &nlmsvc_callback_ops) < 0) 523 goto error; 524 525 return rpc_success; 526 error: 527 nlm_release_host(host); 528 kfree(call); 529 return rpc_system_err; 530 } 531 532 static void nlmsvc_callback_exit(struct rpc_task *task, void *data) 533 { 534 struct nlm_rqst *call = data; 535 536 if (task->tk_status < 0) { 537 dprintk("lockd: %4d callback failed (errno = %d)\n", 538 task->tk_pid, -task->tk_status); 539 } 540 nlm_release_host(call->a_host); 541 kfree(call); 542 } 543 544 static const struct rpc_call_ops nlmsvc_callback_ops = { 545 .rpc_call_done = nlmsvc_callback_exit, 546 }; 547 548 /* 549 * NLM Server procedures. 550 */ 551 552 #define nlmsvc_encode_norep nlmsvc_encode_void 553 #define nlmsvc_decode_norep nlmsvc_decode_void 554 #define nlmsvc_decode_testres nlmsvc_decode_void 555 #define nlmsvc_decode_lockres nlmsvc_decode_void 556 #define nlmsvc_decode_unlockres nlmsvc_decode_void 557 #define nlmsvc_decode_cancelres nlmsvc_decode_void 558 #define nlmsvc_decode_grantedres nlmsvc_decode_void 559 560 #define nlmsvc_proc_none nlmsvc_proc_null 561 #define nlmsvc_proc_test_res nlmsvc_proc_null 562 #define nlmsvc_proc_lock_res nlmsvc_proc_null 563 #define nlmsvc_proc_cancel_res nlmsvc_proc_null 564 #define nlmsvc_proc_unlock_res nlmsvc_proc_null 565 566 struct nlm_void { int dummy; }; 567 568 #define PROC(name, xargt, xrest, argt, rest, respsize) \ 569 { .pc_func = (svc_procfunc) nlmsvc_proc_##name, \ 570 .pc_decode = (kxdrproc_t) nlmsvc_decode_##xargt, \ 571 .pc_encode = (kxdrproc_t) nlmsvc_encode_##xrest, \ 572 .pc_release = NULL, \ 573 .pc_argsize = sizeof(struct nlm_##argt), \ 574 .pc_ressize = sizeof(struct nlm_##rest), \ 575 .pc_xdrressize = respsize, \ 576 } 577 578 #define Ck (1+XDR_QUADLEN(NLM_MAXCOOKIELEN)) /* cookie */ 579 #define St 1 /* status */ 580 #define No (1+1024/4) /* Net Obj */ 581 #define Rg 2 /* range - offset + size */ 582 583 struct svc_procedure nlmsvc_procedures[] = { 584 PROC(null, void, void, void, void, 1), 585 PROC(test, testargs, testres, args, res, Ck+St+2+No+Rg), 586 PROC(lock, lockargs, res, args, res, Ck+St), 587 PROC(cancel, cancargs, res, args, res, Ck+St), 588 PROC(unlock, unlockargs, res, args, res, Ck+St), 589 PROC(granted, testargs, res, args, res, Ck+St), 590 PROC(test_msg, testargs, norep, args, void, 1), 591 PROC(lock_msg, lockargs, norep, args, void, 1), 592 PROC(cancel_msg, cancargs, norep, args, void, 1), 593 PROC(unlock_msg, unlockargs, norep, args, void, 1), 594 PROC(granted_msg, testargs, norep, args, void, 1), 595 PROC(test_res, testres, norep, res, void, 1), 596 PROC(lock_res, lockres, norep, res, void, 1), 597 PROC(cancel_res, cancelres, norep, res, void, 1), 598 PROC(unlock_res, unlockres, norep, res, void, 1), 599 PROC(granted_res, res, norep, res, void, 1), 600 /* statd callback */ 601 PROC(sm_notify, reboot, void, reboot, void, 1), 602 PROC(none, void, void, void, void, 1), 603 PROC(none, void, void, void, void, 1), 604 PROC(none, void, void, void, void, 1), 605 PROC(share, shareargs, shareres, args, res, Ck+St+1), 606 PROC(unshare, shareargs, shareres, args, res, Ck+St+1), 607 PROC(nm_lock, lockargs, res, args, res, Ck+St), 608 PROC(free_all, notify, void, args, void, 0), 609 610 }; 611