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 21 #define NLMDBG_FACILITY NLMDBG_XDR 22 23 static inline loff_t 24 s64_to_loff_t(__s64 offset) 25 { 26 return (loff_t)offset; 27 } 28 29 30 static inline s64 31 loff_t_to_s64(loff_t offset) 32 { 33 s64 res; 34 if (offset > NLM4_OFFSET_MAX) 35 res = NLM4_OFFSET_MAX; 36 else if (offset < -NLM4_OFFSET_MAX) 37 res = -NLM4_OFFSET_MAX; 38 else 39 res = offset; 40 return res; 41 } 42 43 /* 44 * XDR functions for basic NLM types 45 */ 46 static __be32 * 47 nlm4_decode_cookie(__be32 *p, struct nlm_cookie *c) 48 { 49 unsigned int len; 50 51 len = ntohl(*p++); 52 53 if(len==0) 54 { 55 c->len=4; 56 memset(c->data, 0, 4); /* hockeypux brain damage */ 57 } 58 else if(len<=NLM_MAXCOOKIELEN) 59 { 60 c->len=len; 61 memcpy(c->data, p, len); 62 p+=XDR_QUADLEN(len); 63 } 64 else 65 { 66 dprintk("lockd: bad cookie size %d (only cookies under " 67 "%d bytes are supported.)\n", 68 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 dprintk("lockd: bad fhandle size %d (should be <=%d)\n", 90 f->size, NFS_MAXFHSIZE); 91 return NULL; 92 } 93 memcpy(f->data, p, f->size); 94 return p + XDR_QUADLEN(f->size); 95 } 96 97 static __be32 * 98 nlm4_encode_fh(__be32 *p, struct nfs_fh *f) 99 { 100 *p++ = htonl(f->size); 101 if (f->size) p[XDR_QUADLEN(f->size)-1] = 0; /* don't leak anything */ 102 memcpy(p, f->data, f->size); 103 return p + XDR_QUADLEN(f->size); 104 } 105 106 /* 107 * Encode and decode owner handle 108 */ 109 static __be32 * 110 nlm4_decode_oh(__be32 *p, struct xdr_netobj *oh) 111 { 112 return xdr_decode_netobj(p, oh); 113 } 114 115 static __be32 * 116 nlm4_encode_oh(__be32 *p, struct xdr_netobj *oh) 117 { 118 return xdr_encode_netobj(p, oh); 119 } 120 121 static __be32 * 122 nlm4_decode_lock(__be32 *p, struct nlm_lock *lock) 123 { 124 struct file_lock *fl = &lock->fl; 125 __u64 len, start; 126 __s64 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 memcpy(&argp->priv.data, p, sizeof(argp->priv.data)); 359 p += XDR_QUADLEN(SM_PRIV_SIZE); 360 return xdr_argsize_check(rqstp, p); 361 } 362 363 int 364 nlm4svc_decode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp) 365 { 366 if (!(p = nlm4_decode_cookie(p, &resp->cookie))) 367 return 0; 368 resp->status = *p++; 369 return xdr_argsize_check(rqstp, p); 370 } 371 372 int 373 nlm4svc_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy) 374 { 375 return xdr_argsize_check(rqstp, p); 376 } 377 378 int 379 nlm4svc_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy) 380 { 381 return xdr_ressize_check(rqstp, p); 382 } 383 384 /* 385 * Now, the client side XDR functions 386 */ 387 #ifdef NLMCLNT_SUPPORT_SHARES 388 static int 389 nlm4clt_decode_void(struct rpc_rqst *req, __be32 *p, void *ptr) 390 { 391 return 0; 392 } 393 #endif 394 395 static int 396 nlm4clt_encode_testargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) 397 { 398 struct nlm_lock *lock = &argp->lock; 399 400 if (!(p = nlm4_encode_cookie(p, &argp->cookie))) 401 return -EIO; 402 *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero; 403 if (!(p = nlm4_encode_lock(p, lock))) 404 return -EIO; 405 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 406 return 0; 407 } 408 409 static int 410 nlm4clt_decode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) 411 { 412 if (!(p = nlm4_decode_cookie(p, &resp->cookie))) 413 return -EIO; 414 resp->status = *p++; 415 if (resp->status == nlm_lck_denied) { 416 struct file_lock *fl = &resp->lock.fl; 417 u32 excl; 418 __u64 start, len; 419 __s64 end; 420 421 memset(&resp->lock, 0, sizeof(resp->lock)); 422 locks_init_lock(fl); 423 excl = ntohl(*p++); 424 resp->lock.svid = ntohl(*p++); 425 fl->fl_pid = (pid_t)resp->lock.svid; 426 if (!(p = nlm4_decode_oh(p, &resp->lock.oh))) 427 return -EIO; 428 429 fl->fl_flags = FL_POSIX; 430 fl->fl_type = excl? F_WRLCK : F_RDLCK; 431 p = xdr_decode_hyper(p, &start); 432 p = xdr_decode_hyper(p, &len); 433 end = start + len - 1; 434 435 fl->fl_start = s64_to_loff_t(start); 436 if (len == 0 || end < 0) 437 fl->fl_end = OFFSET_MAX; 438 else 439 fl->fl_end = s64_to_loff_t(end); 440 } 441 return 0; 442 } 443 444 445 static int 446 nlm4clt_encode_lockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) 447 { 448 struct nlm_lock *lock = &argp->lock; 449 450 if (!(p = nlm4_encode_cookie(p, &argp->cookie))) 451 return -EIO; 452 *p++ = argp->block? xdr_one : xdr_zero; 453 *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero; 454 if (!(p = nlm4_encode_lock(p, lock))) 455 return -EIO; 456 *p++ = argp->reclaim? xdr_one : xdr_zero; 457 *p++ = htonl(argp->state); 458 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 459 return 0; 460 } 461 462 static int 463 nlm4clt_encode_cancargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) 464 { 465 struct nlm_lock *lock = &argp->lock; 466 467 if (!(p = nlm4_encode_cookie(p, &argp->cookie))) 468 return -EIO; 469 *p++ = argp->block? xdr_one : xdr_zero; 470 *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero; 471 if (!(p = nlm4_encode_lock(p, lock))) 472 return -EIO; 473 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 474 return 0; 475 } 476 477 static int 478 nlm4clt_encode_unlockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) 479 { 480 struct nlm_lock *lock = &argp->lock; 481 482 if (!(p = nlm4_encode_cookie(p, &argp->cookie))) 483 return -EIO; 484 if (!(p = nlm4_encode_lock(p, lock))) 485 return -EIO; 486 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 487 return 0; 488 } 489 490 static int 491 nlm4clt_encode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) 492 { 493 if (!(p = nlm4_encode_cookie(p, &resp->cookie))) 494 return -EIO; 495 *p++ = resp->status; 496 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 497 return 0; 498 } 499 500 static int 501 nlm4clt_encode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) 502 { 503 if (!(p = nlm4_encode_testres(p, resp))) 504 return -EIO; 505 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 506 return 0; 507 } 508 509 static int 510 nlm4clt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) 511 { 512 if (!(p = nlm4_decode_cookie(p, &resp->cookie))) 513 return -EIO; 514 resp->status = *p++; 515 return 0; 516 } 517 518 #if (NLMCLNT_OHSIZE > XDR_MAX_NETOBJ) 519 # error "NLM host name cannot be larger than XDR_MAX_NETOBJ!" 520 #endif 521 522 #if (NLMCLNT_OHSIZE > NLM_MAXSTRLEN) 523 # error "NLM host name cannot be larger than NLM's maximum string length!" 524 #endif 525 526 /* 527 * Buffer requirements for NLM 528 */ 529 #define NLM4_void_sz 0 530 #define NLM4_cookie_sz 1+XDR_QUADLEN(NLM_MAXCOOKIELEN) 531 #define NLM4_caller_sz 1+XDR_QUADLEN(NLMCLNT_OHSIZE) 532 #define NLM4_owner_sz 1+XDR_QUADLEN(NLMCLNT_OHSIZE) 533 #define NLM4_fhandle_sz 1+XDR_QUADLEN(NFS3_FHSIZE) 534 #define NLM4_lock_sz 5+NLM4_caller_sz+NLM4_owner_sz+NLM4_fhandle_sz 535 #define NLM4_holder_sz 6+NLM4_owner_sz 536 537 #define NLM4_testargs_sz NLM4_cookie_sz+1+NLM4_lock_sz 538 #define NLM4_lockargs_sz NLM4_cookie_sz+4+NLM4_lock_sz 539 #define NLM4_cancargs_sz NLM4_cookie_sz+2+NLM4_lock_sz 540 #define NLM4_unlockargs_sz NLM4_cookie_sz+NLM4_lock_sz 541 542 #define NLM4_testres_sz NLM4_cookie_sz+1+NLM4_holder_sz 543 #define NLM4_res_sz NLM4_cookie_sz+1 544 #define NLM4_norep_sz 0 545 546 /* 547 * For NLM, a void procedure really returns nothing 548 */ 549 #define nlm4clt_decode_norep NULL 550 551 #define PROC(proc, argtype, restype) \ 552 [NLMPROC_##proc] = { \ 553 .p_proc = NLMPROC_##proc, \ 554 .p_encode = (kxdrproc_t) nlm4clt_encode_##argtype, \ 555 .p_decode = (kxdrproc_t) nlm4clt_decode_##restype, \ 556 .p_arglen = NLM4_##argtype##_sz, \ 557 .p_replen = NLM4_##restype##_sz, \ 558 .p_statidx = NLMPROC_##proc, \ 559 .p_name = #proc, \ 560 } 561 562 static struct rpc_procinfo nlm4_procedures[] = { 563 PROC(TEST, testargs, testres), 564 PROC(LOCK, lockargs, res), 565 PROC(CANCEL, cancargs, res), 566 PROC(UNLOCK, unlockargs, res), 567 PROC(GRANTED, testargs, res), 568 PROC(TEST_MSG, testargs, norep), 569 PROC(LOCK_MSG, lockargs, norep), 570 PROC(CANCEL_MSG, cancargs, norep), 571 PROC(UNLOCK_MSG, unlockargs, norep), 572 PROC(GRANTED_MSG, testargs, norep), 573 PROC(TEST_RES, testres, norep), 574 PROC(LOCK_RES, res, norep), 575 PROC(CANCEL_RES, res, norep), 576 PROC(UNLOCK_RES, res, norep), 577 PROC(GRANTED_RES, res, norep), 578 #ifdef NLMCLNT_SUPPORT_SHARES 579 PROC(SHARE, shareargs, shareres), 580 PROC(UNSHARE, shareargs, shareres), 581 PROC(NM_LOCK, lockargs, res), 582 PROC(FREE_ALL, notify, void), 583 #endif 584 }; 585 586 struct rpc_version nlm_version4 = { 587 .number = 4, 588 .nrprocs = 24, 589 .procs = nlm4_procedures, 590 }; 591