Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
fork

Configure Feed

Select the types of activity you want to include in your feed.

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