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