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