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