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