1 /* 2 * linux/fs/lockd/xdr4.c 3 * 4 * XDR support for lockd and the lock client. 5 * 6 * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> 7 * Copyright (C) 1999, Trond Myklebust <trond.myklebust@fys.uio.no> 8 */ 9 10 #include <linux/types.h> 11 #include <linux/sched.h> 12 #include <linux/utsname.h> 13 #include <linux/nfs.h> 14 15 #include <linux/sunrpc/xdr.h> 16 #include <linux/sunrpc/clnt.h> 17 #include <linux/sunrpc/svc.h> 18 #include <linux/sunrpc/stats.h> 19 #include <linux/lockd/lockd.h> 20 #include <linux/lockd/sm_inter.h> 21 22 #define NLMDBG_FACILITY NLMDBG_XDR 23 24 static inline loff_t 25 s64_to_loff_t(__s64 offset) 26 { 27 return (loff_t)offset; 28 } 29 30 31 static inline s64 32 loff_t_to_s64(loff_t offset) 33 { 34 s64 res; 35 if (offset > NLM4_OFFSET_MAX) 36 res = NLM4_OFFSET_MAX; 37 else if (offset < -NLM4_OFFSET_MAX) 38 res = -NLM4_OFFSET_MAX; 39 else 40 res = offset; 41 return res; 42 } 43 44 /* 45 * XDR functions for basic NLM types 46 */ 47 static __be32 * 48 nlm4_decode_cookie(__be32 *p, struct nlm_cookie *c) 49 { 50 unsigned int len; 51 52 len = ntohl(*p++); 53 54 if(len==0) 55 { 56 c->len=4; 57 memset(c->data, 0, 4); /* hockeypux brain damage */ 58 } 59 else if(len<=NLM_MAXCOOKIELEN) 60 { 61 c->len=len; 62 memcpy(c->data, p, len); 63 p+=XDR_QUADLEN(len); 64 } 65 else 66 { 67 dprintk("lockd: bad cookie size %d (only cookies under " 68 "%d bytes are supported.)\n", 69 len, NLM_MAXCOOKIELEN); 70 return NULL; 71 } 72 return p; 73 } 74 75 static __be32 * 76 nlm4_encode_cookie(__be32 *p, struct nlm_cookie *c) 77 { 78 *p++ = htonl(c->len); 79 memcpy(p, c->data, c->len); 80 p+=XDR_QUADLEN(c->len); 81 return p; 82 } 83 84 static __be32 * 85 nlm4_decode_fh(__be32 *p, struct nfs_fh *f) 86 { 87 memset(f->data, 0, sizeof(f->data)); 88 f->size = ntohl(*p++); 89 if (f->size > NFS_MAXFHSIZE) { 90 dprintk("lockd: bad fhandle size %d (should be <=%d)\n", 91 f->size, NFS_MAXFHSIZE); 92 return NULL; 93 } 94 memcpy(f->data, p, f->size); 95 return p + XDR_QUADLEN(f->size); 96 } 97 98 static __be32 * 99 nlm4_encode_fh(__be32 *p, struct nfs_fh *f) 100 { 101 *p++ = htonl(f->size); 102 if (f->size) p[XDR_QUADLEN(f->size)-1] = 0; /* don't leak anything */ 103 memcpy(p, f->data, f->size); 104 return p + XDR_QUADLEN(f->size); 105 } 106 107 /* 108 * Encode and decode owner handle 109 */ 110 static __be32 * 111 nlm4_decode_oh(__be32 *p, struct xdr_netobj *oh) 112 { 113 return xdr_decode_netobj(p, oh); 114 } 115 116 static __be32 * 117 nlm4_encode_oh(__be32 *p, struct xdr_netobj *oh) 118 { 119 return xdr_encode_netobj(p, oh); 120 } 121 122 static __be32 * 123 nlm4_decode_lock(__be32 *p, struct nlm_lock *lock) 124 { 125 struct file_lock *fl = &lock->fl; 126 __u64 len, start; 127 __s64 end; 128 129 if (!(p = xdr_decode_string_inplace(p, &lock->caller, 130 &lock->len, NLM_MAXSTRLEN)) 131 || !(p = nlm4_decode_fh(p, &lock->fh)) 132 || !(p = nlm4_decode_oh(p, &lock->oh))) 133 return NULL; 134 lock->svid = ntohl(*p++); 135 136 locks_init_lock(fl); 137 fl->fl_owner = current->files; 138 fl->fl_pid = (pid_t)lock->svid; 139 fl->fl_flags = FL_POSIX; 140 fl->fl_type = F_RDLCK; /* as good as anything else */ 141 p = xdr_decode_hyper(p, &start); 142 p = xdr_decode_hyper(p, &len); 143 end = start + len - 1; 144 145 fl->fl_start = s64_to_loff_t(start); 146 147 if (len == 0 || end < 0) 148 fl->fl_end = OFFSET_MAX; 149 else 150 fl->fl_end = s64_to_loff_t(end); 151 return p; 152 } 153 154 /* 155 * Encode a lock as part of an NLM call 156 */ 157 static __be32 * 158 nlm4_encode_lock(__be32 *p, struct nlm_lock *lock) 159 { 160 struct file_lock *fl = &lock->fl; 161 __s64 start, len; 162 163 if (!(p = xdr_encode_string(p, lock->caller)) 164 || !(p = nlm4_encode_fh(p, &lock->fh)) 165 || !(p = nlm4_encode_oh(p, &lock->oh))) 166 return NULL; 167 168 if (fl->fl_start > NLM4_OFFSET_MAX 169 || (fl->fl_end > NLM4_OFFSET_MAX && fl->fl_end != OFFSET_MAX)) 170 return NULL; 171 172 *p++ = htonl(lock->svid); 173 174 start = loff_t_to_s64(fl->fl_start); 175 if (fl->fl_end == OFFSET_MAX) 176 len = 0; 177 else 178 len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1); 179 180 p = xdr_encode_hyper(p, start); 181 p = xdr_encode_hyper(p, len); 182 183 return p; 184 } 185 186 /* 187 * Encode result of a TEST/TEST_MSG call 188 */ 189 static __be32 * 190 nlm4_encode_testres(__be32 *p, struct nlm_res *resp) 191 { 192 s64 start, len; 193 194 dprintk("xdr: before encode_testres (p %p resp %p)\n", p, resp); 195 if (!(p = nlm4_encode_cookie(p, &resp->cookie))) 196 return NULL; 197 *p++ = resp->status; 198 199 if (resp->status == nlm_lck_denied) { 200 struct file_lock *fl = &resp->lock.fl; 201 202 *p++ = (fl->fl_type == F_RDLCK)? xdr_zero : xdr_one; 203 *p++ = htonl(resp->lock.svid); 204 205 /* Encode owner handle. */ 206 if (!(p = xdr_encode_netobj(p, &resp->lock.oh))) 207 return NULL; 208 209 start = loff_t_to_s64(fl->fl_start); 210 if (fl->fl_end == OFFSET_MAX) 211 len = 0; 212 else 213 len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1); 214 215 p = xdr_encode_hyper(p, start); 216 p = xdr_encode_hyper(p, len); 217 dprintk("xdr: encode_testres (status %u pid %d type %d start %Ld end %Ld)\n", 218 resp->status, (int)resp->lock.svid, fl->fl_type, 219 (long long)fl->fl_start, (long long)fl->fl_end); 220 } 221 222 dprintk("xdr: after encode_testres (p %p resp %p)\n", p, resp); 223 return p; 224 } 225 226 227 /* 228 * First, the server side XDR functions 229 */ 230 int 231 nlm4svc_decode_testargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp) 232 { 233 u32 exclusive; 234 235 if (!(p = nlm4_decode_cookie(p, &argp->cookie))) 236 return 0; 237 238 exclusive = ntohl(*p++); 239 if (!(p = nlm4_decode_lock(p, &argp->lock))) 240 return 0; 241 if (exclusive) 242 argp->lock.fl.fl_type = F_WRLCK; 243 244 return xdr_argsize_check(rqstp, p); 245 } 246 247 int 248 nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp) 249 { 250 if (!(p = nlm4_encode_testres(p, resp))) 251 return 0; 252 return xdr_ressize_check(rqstp, p); 253 } 254 255 int 256 nlm4svc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp) 257 { 258 u32 exclusive; 259 260 if (!(p = nlm4_decode_cookie(p, &argp->cookie))) 261 return 0; 262 argp->block = ntohl(*p++); 263 exclusive = ntohl(*p++); 264 if (!(p = nlm4_decode_lock(p, &argp->lock))) 265 return 0; 266 if (exclusive) 267 argp->lock.fl.fl_type = F_WRLCK; 268 argp->reclaim = ntohl(*p++); 269 argp->state = ntohl(*p++); 270 argp->monitor = 1; /* monitor client by default */ 271 272 return xdr_argsize_check(rqstp, p); 273 } 274 275 int 276 nlm4svc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp) 277 { 278 u32 exclusive; 279 280 if (!(p = nlm4_decode_cookie(p, &argp->cookie))) 281 return 0; 282 argp->block = ntohl(*p++); 283 exclusive = ntohl(*p++); 284 if (!(p = nlm4_decode_lock(p, &argp->lock))) 285 return 0; 286 if (exclusive) 287 argp->lock.fl.fl_type = F_WRLCK; 288 return xdr_argsize_check(rqstp, p); 289 } 290 291 int 292 nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp) 293 { 294 if (!(p = nlm4_decode_cookie(p, &argp->cookie)) 295 || !(p = nlm4_decode_lock(p, &argp->lock))) 296 return 0; 297 argp->lock.fl.fl_type = F_UNLCK; 298 return xdr_argsize_check(rqstp, p); 299 } 300 301 int 302 nlm4svc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp) 303 { 304 struct nlm_lock *lock = &argp->lock; 305 306 memset(lock, 0, sizeof(*lock)); 307 locks_init_lock(&lock->fl); 308 lock->svid = ~(u32) 0; 309 lock->fl.fl_pid = (pid_t)lock->svid; 310 311 if (!(p = nlm4_decode_cookie(p, &argp->cookie)) 312 || !(p = xdr_decode_string_inplace(p, &lock->caller, 313 &lock->len, NLM_MAXSTRLEN)) 314 || !(p = nlm4_decode_fh(p, &lock->fh)) 315 || !(p = nlm4_decode_oh(p, &lock->oh))) 316 return 0; 317 argp->fsm_mode = ntohl(*p++); 318 argp->fsm_access = ntohl(*p++); 319 return xdr_argsize_check(rqstp, p); 320 } 321 322 int 323 nlm4svc_encode_shareres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp) 324 { 325 if (!(p = nlm4_encode_cookie(p, &resp->cookie))) 326 return 0; 327 *p++ = resp->status; 328 *p++ = xdr_zero; /* sequence argument */ 329 return xdr_ressize_check(rqstp, p); 330 } 331 332 int 333 nlm4svc_encode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp) 334 { 335 if (!(p = nlm4_encode_cookie(p, &resp->cookie))) 336 return 0; 337 *p++ = resp->status; 338 return xdr_ressize_check(rqstp, p); 339 } 340 341 int 342 nlm4svc_decode_notify(struct svc_rqst *rqstp, __be32 *p, struct nlm_args *argp) 343 { 344 struct nlm_lock *lock = &argp->lock; 345 346 if (!(p = xdr_decode_string_inplace(p, &lock->caller, 347 &lock->len, NLM_MAXSTRLEN))) 348 return 0; 349 argp->state = ntohl(*p++); 350 return xdr_argsize_check(rqstp, p); 351 } 352 353 int 354 nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p, struct nlm_reboot *argp) 355 { 356 if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN))) 357 return 0; 358 argp->state = ntohl(*p++); 359 /* Preserve the address in network byte order */ 360 argp->addr = *p++; 361 argp->vers = *p++; 362 argp->proto = *p++; 363 return xdr_argsize_check(rqstp, p); 364 } 365 366 int 367 nlm4svc_decode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp) 368 { 369 if (!(p = nlm4_decode_cookie(p, &resp->cookie))) 370 return 0; 371 resp->status = *p++; 372 return xdr_argsize_check(rqstp, p); 373 } 374 375 int 376 nlm4svc_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy) 377 { 378 return xdr_argsize_check(rqstp, p); 379 } 380 381 int 382 nlm4svc_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy) 383 { 384 return xdr_ressize_check(rqstp, p); 385 } 386 387 /* 388 * Now, the client side XDR functions 389 */ 390 #ifdef NLMCLNT_SUPPORT_SHARES 391 static int 392 nlm4clt_decode_void(struct rpc_rqst *req, __be32 *p, void *ptr) 393 { 394 return 0; 395 } 396 #endif 397 398 static int 399 nlm4clt_encode_testargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) 400 { 401 struct nlm_lock *lock = &argp->lock; 402 403 if (!(p = nlm4_encode_cookie(p, &argp->cookie))) 404 return -EIO; 405 *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero; 406 if (!(p = nlm4_encode_lock(p, lock))) 407 return -EIO; 408 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 409 return 0; 410 } 411 412 static int 413 nlm4clt_decode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) 414 { 415 if (!(p = nlm4_decode_cookie(p, &resp->cookie))) 416 return -EIO; 417 resp->status = *p++; 418 if (resp->status == nlm_lck_denied) { 419 struct file_lock *fl = &resp->lock.fl; 420 u32 excl; 421 __u64 start, len; 422 __s64 end; 423 424 memset(&resp->lock, 0, sizeof(resp->lock)); 425 locks_init_lock(fl); 426 excl = ntohl(*p++); 427 resp->lock.svid = ntohl(*p++); 428 fl->fl_pid = (pid_t)resp->lock.svid; 429 if (!(p = nlm4_decode_oh(p, &resp->lock.oh))) 430 return -EIO; 431 432 fl->fl_flags = FL_POSIX; 433 fl->fl_type = excl? F_WRLCK : F_RDLCK; 434 p = xdr_decode_hyper(p, &start); 435 p = xdr_decode_hyper(p, &len); 436 end = start + len - 1; 437 438 fl->fl_start = s64_to_loff_t(start); 439 if (len == 0 || end < 0) 440 fl->fl_end = OFFSET_MAX; 441 else 442 fl->fl_end = s64_to_loff_t(end); 443 } 444 return 0; 445 } 446 447 448 static int 449 nlm4clt_encode_lockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) 450 { 451 struct nlm_lock *lock = &argp->lock; 452 453 if (!(p = nlm4_encode_cookie(p, &argp->cookie))) 454 return -EIO; 455 *p++ = argp->block? xdr_one : xdr_zero; 456 *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero; 457 if (!(p = nlm4_encode_lock(p, lock))) 458 return -EIO; 459 *p++ = argp->reclaim? xdr_one : xdr_zero; 460 *p++ = htonl(argp->state); 461 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 462 return 0; 463 } 464 465 static int 466 nlm4clt_encode_cancargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) 467 { 468 struct nlm_lock *lock = &argp->lock; 469 470 if (!(p = nlm4_encode_cookie(p, &argp->cookie))) 471 return -EIO; 472 *p++ = argp->block? xdr_one : xdr_zero; 473 *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero; 474 if (!(p = nlm4_encode_lock(p, lock))) 475 return -EIO; 476 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 477 return 0; 478 } 479 480 static int 481 nlm4clt_encode_unlockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) 482 { 483 struct nlm_lock *lock = &argp->lock; 484 485 if (!(p = nlm4_encode_cookie(p, &argp->cookie))) 486 return -EIO; 487 if (!(p = nlm4_encode_lock(p, lock))) 488 return -EIO; 489 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 490 return 0; 491 } 492 493 static int 494 nlm4clt_encode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) 495 { 496 if (!(p = nlm4_encode_cookie(p, &resp->cookie))) 497 return -EIO; 498 *p++ = resp->status; 499 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 500 return 0; 501 } 502 503 static int 504 nlm4clt_encode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) 505 { 506 if (!(p = nlm4_encode_testres(p, resp))) 507 return -EIO; 508 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 509 return 0; 510 } 511 512 static int 513 nlm4clt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) 514 { 515 if (!(p = nlm4_decode_cookie(p, &resp->cookie))) 516 return -EIO; 517 resp->status = *p++; 518 return 0; 519 } 520 521 #if (NLMCLNT_OHSIZE > XDR_MAX_NETOBJ) 522 # error "NLM host name cannot be larger than XDR_MAX_NETOBJ!" 523 #endif 524 525 #if (NLMCLNT_OHSIZE > NLM_MAXSTRLEN) 526 # error "NLM host name cannot be larger than NLM's maximum string length!" 527 #endif 528 529 /* 530 * Buffer requirements for NLM 531 */ 532 #define NLM4_void_sz 0 533 #define NLM4_cookie_sz 1+XDR_QUADLEN(NLM_MAXCOOKIELEN) 534 #define NLM4_caller_sz 1+XDR_QUADLEN(NLMCLNT_OHSIZE) 535 #define NLM4_owner_sz 1+XDR_QUADLEN(NLMCLNT_OHSIZE) 536 #define NLM4_fhandle_sz 1+XDR_QUADLEN(NFS3_FHSIZE) 537 #define NLM4_lock_sz 5+NLM4_caller_sz+NLM4_owner_sz+NLM4_fhandle_sz 538 #define NLM4_holder_sz 6+NLM4_owner_sz 539 540 #define NLM4_testargs_sz NLM4_cookie_sz+1+NLM4_lock_sz 541 #define NLM4_lockargs_sz NLM4_cookie_sz+4+NLM4_lock_sz 542 #define NLM4_cancargs_sz NLM4_cookie_sz+2+NLM4_lock_sz 543 #define NLM4_unlockargs_sz NLM4_cookie_sz+NLM4_lock_sz 544 545 #define NLM4_testres_sz NLM4_cookie_sz+1+NLM4_holder_sz 546 #define NLM4_res_sz NLM4_cookie_sz+1 547 #define NLM4_norep_sz 0 548 549 /* 550 * For NLM, a void procedure really returns nothing 551 */ 552 #define nlm4clt_decode_norep NULL 553 554 #define PROC(proc, argtype, restype) \ 555 [NLMPROC_##proc] = { \ 556 .p_proc = NLMPROC_##proc, \ 557 .p_encode = (kxdrproc_t) nlm4clt_encode_##argtype, \ 558 .p_decode = (kxdrproc_t) nlm4clt_decode_##restype, \ 559 .p_arglen = NLM4_##argtype##_sz, \ 560 .p_replen = NLM4_##restype##_sz, \ 561 .p_statidx = NLMPROC_##proc, \ 562 .p_name = #proc, \ 563 } 564 565 static struct rpc_procinfo nlm4_procedures[] = { 566 PROC(TEST, testargs, testres), 567 PROC(LOCK, lockargs, res), 568 PROC(CANCEL, cancargs, res), 569 PROC(UNLOCK, unlockargs, res), 570 PROC(GRANTED, testargs, res), 571 PROC(TEST_MSG, testargs, norep), 572 PROC(LOCK_MSG, lockargs, norep), 573 PROC(CANCEL_MSG, cancargs, norep), 574 PROC(UNLOCK_MSG, unlockargs, norep), 575 PROC(GRANTED_MSG, testargs, norep), 576 PROC(TEST_RES, testres, norep), 577 PROC(LOCK_RES, res, norep), 578 PROC(CANCEL_RES, res, norep), 579 PROC(UNLOCK_RES, res, norep), 580 PROC(GRANTED_RES, res, norep), 581 #ifdef NLMCLNT_SUPPORT_SHARES 582 PROC(SHARE, shareargs, shareres), 583 PROC(UNSHARE, shareargs, shareres), 584 PROC(NM_LOCK, lockargs, res), 585 PROC(FREE_ALL, notify, void), 586 #endif 587 }; 588 589 struct rpc_version nlm_version4 = { 590 .number = 4, 591 .nrprocs = 24, 592 .procs = nlm4_procedures, 593 }; 594