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 24static inline loff_t 25s64_to_loff_t(__s64 offset) 26{ 27 return (loff_t)offset; 28} 29 30 31static inline s64 32loff_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 */ 47static __be32 * 48nlm4_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 74static __be32 * 75nlm4_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 83static __be32 * 84nlm4_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 98static __be32 * 99nlm4_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 */ 110static __be32 * 111nlm4_decode_oh(__be32 *p, struct xdr_netobj *oh) 112{ 113 return xdr_decode_netobj(p, oh); 114} 115 116static __be32 * 117nlm4_encode_oh(__be32 *p, struct xdr_netobj *oh) 118{ 119 return xdr_encode_netobj(p, oh); 120} 121 122static __be32 * 123nlm4_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 */ 157static __be32 * 158nlm4_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 */ 189static __be32 * 190nlm4_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 */ 230int 231nlm4svc_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 247int 248nlm4svc_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 255int 256nlm4svc_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 275int 276nlm4svc_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 291int 292nlm4svc_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 301int 302nlm4svc_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 322int 323nlm4svc_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 332int 333nlm4svc_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 341int 342nlm4svc_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 353int 354nlm4svc_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 366int 367nlm4svc_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 375int 376nlm4svc_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy) 377{ 378 return xdr_argsize_check(rqstp, p); 379} 380 381int 382nlm4svc_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 391static int 392nlm4clt_decode_void(struct rpc_rqst *req, __be32 *p, void *ptr) 393{ 394 return 0; 395} 396#endif 397 398static int 399nlm4clt_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 412static int 413nlm4clt_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 448static int 449nlm4clt_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 465static int 466nlm4clt_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 480static int 481nlm4clt_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 493static int 494nlm4clt_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 503static int 504nlm4clt_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 512static int 513nlm4clt_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 565static 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 589struct rpc_version nlm_version4 = { 590 .number = 4, 591 .nrprocs = 24, 592 .procs = nlm4_procedures, 593}; 594