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