linux/fs/lockd/xdr.c
<<
>>
Prefs
   1/*
   2 * linux/fs/lockd/xdr.c
   3 *
   4 * XDR support for lockd and the lock client.
   5 *
   6 * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
   7 */
   8
   9#include <linux/types.h>
  10#include <linux/sched.h>
  11#include <linux/nfs.h>
  12
  13#include <linux/sunrpc/xdr.h>
  14#include <linux/sunrpc/clnt.h>
  15#include <linux/sunrpc/svc.h>
  16#include <linux/sunrpc/stats.h>
  17#include <linux/lockd/lockd.h>
  18
  19#define NLMDBG_FACILITY         NLMDBG_XDR
  20
  21
  22static inline loff_t
  23s32_to_loff_t(__s32 offset)
  24{
  25        return (loff_t)offset;
  26}
  27
  28static inline __s32
  29loff_t_to_s32(loff_t offset)
  30{
  31        __s32 res;
  32        if (offset >= NLM_OFFSET_MAX)
  33                res = NLM_OFFSET_MAX;
  34        else if (offset <= -NLM_OFFSET_MAX)
  35                res = -NLM_OFFSET_MAX;
  36        else
  37                res = offset;
  38        return res;
  39}
  40
  41/*
  42 * XDR functions for basic NLM types
  43 */
  44static __be32 *nlm_decode_cookie(__be32 *p, struct nlm_cookie *c)
  45{
  46        unsigned int    len;
  47
  48        len = ntohl(*p++);
  49        
  50        if(len==0)
  51        {
  52                c->len=4;
  53                memset(c->data, 0, 4);  /* hockeypux brain damage */
  54        }
  55        else if(len<=NLM_MAXCOOKIELEN)
  56        {
  57                c->len=len;
  58                memcpy(c->data, p, len);
  59                p+=XDR_QUADLEN(len);
  60        }
  61        else 
  62        {
  63                dprintk("lockd: bad cookie size %d (only cookies under "
  64                        "%d bytes are supported.)\n",
  65                                len, NLM_MAXCOOKIELEN);
  66                return NULL;
  67        }
  68        return p;
  69}
  70
  71static inline __be32 *
  72nlm_encode_cookie(__be32 *p, struct nlm_cookie *c)
  73{
  74        *p++ = htonl(c->len);
  75        memcpy(p, c->data, c->len);
  76        p+=XDR_QUADLEN(c->len);
  77        return p;
  78}
  79
  80static __be32 *
  81nlm_decode_fh(__be32 *p, struct nfs_fh *f)
  82{
  83        unsigned int    len;
  84
  85        if ((len = ntohl(*p++)) != NFS2_FHSIZE) {
  86                dprintk("lockd: bad fhandle size %d (should be %d)\n",
  87                        len, NFS2_FHSIZE);
  88                return NULL;
  89        }
  90        f->size = NFS2_FHSIZE;
  91        memset(f->data, 0, sizeof(f->data));
  92        memcpy(f->data, p, NFS2_FHSIZE);
  93        return p + XDR_QUADLEN(NFS2_FHSIZE);
  94}
  95
  96static inline __be32 *
  97nlm_encode_fh(__be32 *p, struct nfs_fh *f)
  98{
  99        *p++ = htonl(NFS2_FHSIZE);
 100        memcpy(p, f->data, NFS2_FHSIZE);
 101        return p + XDR_QUADLEN(NFS2_FHSIZE);
 102}
 103
 104/*
 105 * Encode and decode owner handle
 106 */
 107static inline __be32 *
 108nlm_decode_oh(__be32 *p, struct xdr_netobj *oh)
 109{
 110        return xdr_decode_netobj(p, oh);
 111}
 112
 113static inline __be32 *
 114nlm_encode_oh(__be32 *p, struct xdr_netobj *oh)
 115{
 116        return xdr_encode_netobj(p, oh);
 117}
 118
 119static __be32 *
 120nlm_decode_lock(__be32 *p, struct nlm_lock *lock)
 121{
 122        struct file_lock        *fl = &lock->fl;
 123        s32                     start, len, end;
 124
 125        if (!(p = xdr_decode_string_inplace(p, &lock->caller,
 126                                            &lock->len,
 127                                            NLM_MAXSTRLEN))
 128         || !(p = nlm_decode_fh(p, &lock->fh))
 129         || !(p = nlm_decode_oh(p, &lock->oh)))
 130                return NULL;
 131        lock->svid  = ntohl(*p++);
 132
 133        locks_init_lock(fl);
 134        fl->fl_owner = current->files;
 135        fl->fl_pid   = (pid_t)lock->svid;
 136        fl->fl_flags = FL_POSIX;
 137        fl->fl_type  = F_RDLCK;         /* as good as anything else */
 138        start = ntohl(*p++);
 139        len = ntohl(*p++);
 140        end = start + len - 1;
 141
 142        fl->fl_start = s32_to_loff_t(start);
 143
 144        if (len == 0 || end < 0)
 145                fl->fl_end = OFFSET_MAX;
 146        else
 147                fl->fl_end = s32_to_loff_t(end);
 148        return p;
 149}
 150
 151/*
 152 * Encode a lock as part of an NLM call
 153 */
 154static __be32 *
 155nlm_encode_lock(__be32 *p, struct nlm_lock *lock)
 156{
 157        struct file_lock        *fl = &lock->fl;
 158        __s32                   start, len;
 159
 160        if (!(p = xdr_encode_string(p, lock->caller))
 161         || !(p = nlm_encode_fh(p, &lock->fh))
 162         || !(p = nlm_encode_oh(p, &lock->oh)))
 163                return NULL;
 164
 165        if (fl->fl_start > NLM_OFFSET_MAX
 166         || (fl->fl_end > NLM_OFFSET_MAX && fl->fl_end != OFFSET_MAX))
 167                return NULL;
 168
 169        start = loff_t_to_s32(fl->fl_start);
 170        if (fl->fl_end == OFFSET_MAX)
 171                len = 0;
 172        else
 173                len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1);
 174
 175        *p++ = htonl(lock->svid);
 176        *p++ = htonl(start);
 177        *p++ = htonl(len);
 178
 179        return p;
 180}
 181
 182/*
 183 * Encode result of a TEST/TEST_MSG call
 184 */
 185static __be32 *
 186nlm_encode_testres(__be32 *p, struct nlm_res *resp)
 187{
 188        s32             start, len;
 189
 190        if (!(p = nlm_encode_cookie(p, &resp->cookie)))
 191                return NULL;
 192        *p++ = resp->status;
 193
 194        if (resp->status == nlm_lck_denied) {
 195                struct file_lock        *fl = &resp->lock.fl;
 196
 197                *p++ = (fl->fl_type == F_RDLCK)? xdr_zero : xdr_one;
 198                *p++ = htonl(resp->lock.svid);
 199
 200                /* Encode owner handle. */
 201                if (!(p = xdr_encode_netobj(p, &resp->lock.oh)))
 202                        return NULL;
 203
 204                start = loff_t_to_s32(fl->fl_start);
 205                if (fl->fl_end == OFFSET_MAX)
 206                        len = 0;
 207                else
 208                        len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1);
 209
 210                *p++ = htonl(start);
 211                *p++ = htonl(len);
 212        }
 213
 214        return p;
 215}
 216
 217
 218/*
 219 * First, the server side XDR functions
 220 */
 221int
 222nlmsvc_decode_testargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
 223{
 224        u32     exclusive;
 225
 226        if (!(p = nlm_decode_cookie(p, &argp->cookie)))
 227                return 0;
 228
 229        exclusive = ntohl(*p++);
 230        if (!(p = nlm_decode_lock(p, &argp->lock)))
 231                return 0;
 232        if (exclusive)
 233                argp->lock.fl.fl_type = F_WRLCK;
 234
 235        return xdr_argsize_check(rqstp, p);
 236}
 237
 238int
 239nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
 240{
 241        if (!(p = nlm_encode_testres(p, resp)))
 242                return 0;
 243        return xdr_ressize_check(rqstp, p);
 244}
 245
 246int
 247nlmsvc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
 248{
 249        u32     exclusive;
 250
 251        if (!(p = nlm_decode_cookie(p, &argp->cookie)))
 252                return 0;
 253        argp->block  = ntohl(*p++);
 254        exclusive    = ntohl(*p++);
 255        if (!(p = nlm_decode_lock(p, &argp->lock)))
 256                return 0;
 257        if (exclusive)
 258                argp->lock.fl.fl_type = F_WRLCK;
 259        argp->reclaim = ntohl(*p++);
 260        argp->state   = ntohl(*p++);
 261        argp->monitor = 1;              /* monitor client by default */
 262
 263        return xdr_argsize_check(rqstp, p);
 264}
 265
 266int
 267nlmsvc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
 268{
 269        u32     exclusive;
 270
 271        if (!(p = nlm_decode_cookie(p, &argp->cookie)))
 272                return 0;
 273        argp->block = ntohl(*p++);
 274        exclusive = ntohl(*p++);
 275        if (!(p = nlm_decode_lock(p, &argp->lock)))
 276                return 0;
 277        if (exclusive)
 278                argp->lock.fl.fl_type = F_WRLCK;
 279        return xdr_argsize_check(rqstp, p);
 280}
 281
 282int
 283nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
 284{
 285        if (!(p = nlm_decode_cookie(p, &argp->cookie))
 286         || !(p = nlm_decode_lock(p, &argp->lock)))
 287                return 0;
 288        argp->lock.fl.fl_type = F_UNLCK;
 289        return xdr_argsize_check(rqstp, p);
 290}
 291
 292int
 293nlmsvc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
 294{
 295        struct nlm_lock *lock = &argp->lock;
 296
 297        memset(lock, 0, sizeof(*lock));
 298        locks_init_lock(&lock->fl);
 299        lock->svid = ~(u32) 0;
 300        lock->fl.fl_pid = (pid_t)lock->svid;
 301
 302        if (!(p = nlm_decode_cookie(p, &argp->cookie))
 303         || !(p = xdr_decode_string_inplace(p, &lock->caller,
 304                                            &lock->len, NLM_MAXSTRLEN))
 305         || !(p = nlm_decode_fh(p, &lock->fh))
 306         || !(p = nlm_decode_oh(p, &lock->oh)))
 307                return 0;
 308        argp->fsm_mode = ntohl(*p++);
 309        argp->fsm_access = ntohl(*p++);
 310        return xdr_argsize_check(rqstp, p);
 311}
 312
 313int
 314nlmsvc_encode_shareres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
 315{
 316        if (!(p = nlm_encode_cookie(p, &resp->cookie)))
 317                return 0;
 318        *p++ = resp->status;
 319        *p++ = xdr_zero;                /* sequence argument */
 320        return xdr_ressize_check(rqstp, p);
 321}
 322
 323int
 324nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
 325{
 326        if (!(p = nlm_encode_cookie(p, &resp->cookie)))
 327                return 0;
 328        *p++ = resp->status;
 329        return xdr_ressize_check(rqstp, p);
 330}
 331
 332int
 333nlmsvc_decode_notify(struct svc_rqst *rqstp, __be32 *p, struct nlm_args *argp)
 334{
 335        struct nlm_lock *lock = &argp->lock;
 336
 337        if (!(p = xdr_decode_string_inplace(p, &lock->caller,
 338                                            &lock->len, NLM_MAXSTRLEN)))
 339                return 0;
 340        argp->state = ntohl(*p++);
 341        return xdr_argsize_check(rqstp, p);
 342}
 343
 344int
 345nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p, struct nlm_reboot *argp)
 346{
 347        if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN)))
 348                return 0;
 349        argp->state = ntohl(*p++);
 350        memcpy(&argp->priv.data, p, sizeof(argp->priv.data));
 351        p += XDR_QUADLEN(SM_PRIV_SIZE);
 352        return xdr_argsize_check(rqstp, p);
 353}
 354
 355int
 356nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
 357{
 358        if (!(p = nlm_decode_cookie(p, &resp->cookie)))
 359                return 0;
 360        resp->status = *p++;
 361        return xdr_argsize_check(rqstp, p);
 362}
 363
 364int
 365nlmsvc_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
 366{
 367        return xdr_argsize_check(rqstp, p);
 368}
 369
 370int
 371nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
 372{
 373        return xdr_ressize_check(rqstp, p);
 374}
 375
 376/*
 377 * Now, the client side XDR functions
 378 */
 379#ifdef NLMCLNT_SUPPORT_SHARES
 380static int
 381nlmclt_decode_void(struct rpc_rqst *req, u32 *p, void *ptr)
 382{
 383        return 0;
 384}
 385#endif
 386
 387static int
 388nlmclt_encode_testargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
 389{
 390        struct nlm_lock *lock = &argp->lock;
 391
 392        if (!(p = nlm_encode_cookie(p, &argp->cookie)))
 393                return -EIO;
 394        *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
 395        if (!(p = nlm_encode_lock(p, lock)))
 396                return -EIO;
 397        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 398        return 0;
 399}
 400
 401static int
 402nlmclt_decode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
 403{
 404        if (!(p = nlm_decode_cookie(p, &resp->cookie)))
 405                return -EIO;
 406        resp->status = *p++;
 407        if (resp->status == nlm_lck_denied) {
 408                struct file_lock        *fl = &resp->lock.fl;
 409                u32                     excl;
 410                s32                     start, len, end;
 411
 412                memset(&resp->lock, 0, sizeof(resp->lock));
 413                locks_init_lock(fl);
 414                excl = ntohl(*p++);
 415                resp->lock.svid = ntohl(*p++);
 416                fl->fl_pid = (pid_t)resp->lock.svid;
 417                if (!(p = nlm_decode_oh(p, &resp->lock.oh)))
 418                        return -EIO;
 419
 420                fl->fl_flags = FL_POSIX;
 421                fl->fl_type  = excl? F_WRLCK : F_RDLCK;
 422                start = ntohl(*p++);
 423                len = ntohl(*p++);
 424                end = start + len - 1;
 425
 426                fl->fl_start = s32_to_loff_t(start);
 427                if (len == 0 || end < 0)
 428                        fl->fl_end = OFFSET_MAX;
 429                else
 430                        fl->fl_end = s32_to_loff_t(end);
 431        }
 432        return 0;
 433}
 434
 435
 436static int
 437nlmclt_encode_lockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
 438{
 439        struct nlm_lock *lock = &argp->lock;
 440
 441        if (!(p = nlm_encode_cookie(p, &argp->cookie)))
 442                return -EIO;
 443        *p++ = argp->block? xdr_one : xdr_zero;
 444        *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
 445        if (!(p = nlm_encode_lock(p, lock)))
 446                return -EIO;
 447        *p++ = argp->reclaim? xdr_one : xdr_zero;
 448        *p++ = htonl(argp->state);
 449        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 450        return 0;
 451}
 452
 453static int
 454nlmclt_encode_cancargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
 455{
 456        struct nlm_lock *lock = &argp->lock;
 457
 458        if (!(p = nlm_encode_cookie(p, &argp->cookie)))
 459                return -EIO;
 460        *p++ = argp->block? xdr_one : xdr_zero;
 461        *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
 462        if (!(p = nlm_encode_lock(p, lock)))
 463                return -EIO;
 464        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 465        return 0;
 466}
 467
 468static int
 469nlmclt_encode_unlockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
 470{
 471        struct nlm_lock *lock = &argp->lock;
 472
 473        if (!(p = nlm_encode_cookie(p, &argp->cookie)))
 474                return -EIO;
 475        if (!(p = nlm_encode_lock(p, lock)))
 476                return -EIO;
 477        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 478        return 0;
 479}
 480
 481static int
 482nlmclt_encode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
 483{
 484        if (!(p = nlm_encode_cookie(p, &resp->cookie)))
 485                return -EIO;
 486        *p++ = resp->status;
 487        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 488        return 0;
 489}
 490
 491static int
 492nlmclt_encode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
 493{
 494        if (!(p = nlm_encode_testres(p, resp)))
 495                return -EIO;
 496        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 497        return 0;
 498}
 499
 500static int
 501nlmclt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
 502{
 503        if (!(p = nlm_decode_cookie(p, &resp->cookie)))
 504                return -EIO;
 505        resp->status = *p++;
 506        return 0;
 507}
 508
 509#if (NLMCLNT_OHSIZE > XDR_MAX_NETOBJ)
 510#  error "NLM host name cannot be larger than XDR_MAX_NETOBJ!"
 511#endif
 512
 513/*
 514 * Buffer requirements for NLM
 515 */
 516#define NLM_void_sz             0
 517#define NLM_cookie_sz           1+XDR_QUADLEN(NLM_MAXCOOKIELEN)
 518#define NLM_caller_sz           1+XDR_QUADLEN(NLMCLNT_OHSIZE)
 519#define NLM_owner_sz            1+XDR_QUADLEN(NLMCLNT_OHSIZE)
 520#define NLM_fhandle_sz          1+XDR_QUADLEN(NFS2_FHSIZE)
 521#define NLM_lock_sz             3+NLM_caller_sz+NLM_owner_sz+NLM_fhandle_sz
 522#define NLM_holder_sz           4+NLM_owner_sz
 523
 524#define NLM_testargs_sz         NLM_cookie_sz+1+NLM_lock_sz
 525#define NLM_lockargs_sz         NLM_cookie_sz+4+NLM_lock_sz
 526#define NLM_cancargs_sz         NLM_cookie_sz+2+NLM_lock_sz
 527#define NLM_unlockargs_sz       NLM_cookie_sz+NLM_lock_sz
 528
 529#define NLM_testres_sz          NLM_cookie_sz+1+NLM_holder_sz
 530#define NLM_res_sz              NLM_cookie_sz+1
 531#define NLM_norep_sz            0
 532
 533/*
 534 * For NLM, a void procedure really returns nothing
 535 */
 536#define nlmclt_decode_norep     NULL
 537
 538#define PROC(proc, argtype, restype)    \
 539[NLMPROC_##proc] = {                                                    \
 540        .p_proc      = NLMPROC_##proc,                                  \
 541        .p_encode    = (kxdrproc_t) nlmclt_encode_##argtype,            \
 542        .p_decode    = (kxdrproc_t) nlmclt_decode_##restype,            \
 543        .p_arglen    = NLM_##argtype##_sz,                              \
 544        .p_replen    = NLM_##restype##_sz,                              \
 545        .p_statidx   = NLMPROC_##proc,                                  \
 546        .p_name      = #proc,                                           \
 547        }
 548
 549static struct rpc_procinfo      nlm_procedures[] = {
 550    PROC(TEST,          testargs,       testres),
 551    PROC(LOCK,          lockargs,       res),
 552    PROC(CANCEL,        cancargs,       res),
 553    PROC(UNLOCK,        unlockargs,     res),
 554    PROC(GRANTED,       testargs,       res),
 555    PROC(TEST_MSG,      testargs,       norep),
 556    PROC(LOCK_MSG,      lockargs,       norep),
 557    PROC(CANCEL_MSG,    cancargs,       norep),
 558    PROC(UNLOCK_MSG,    unlockargs,     norep),
 559    PROC(GRANTED_MSG,   testargs,       norep),
 560    PROC(TEST_RES,      testres,        norep),
 561    PROC(LOCK_RES,      res,            norep),
 562    PROC(CANCEL_RES,    res,            norep),
 563    PROC(UNLOCK_RES,    res,            norep),
 564    PROC(GRANTED_RES,   res,            norep),
 565#ifdef NLMCLNT_SUPPORT_SHARES
 566    PROC(SHARE,         shareargs,      shareres),
 567    PROC(UNSHARE,       shareargs,      shareres),
 568    PROC(NM_LOCK,       lockargs,       res),
 569    PROC(FREE_ALL,      notify,         void),
 570#endif
 571};
 572
 573static struct rpc_version       nlm_version1 = {
 574                .number         = 1,
 575                .nrprocs        = 16,
 576                .procs          = nlm_procedures,
 577};
 578
 579static struct rpc_version       nlm_version3 = {
 580                .number         = 3,
 581                .nrprocs        = 24,
 582                .procs          = nlm_procedures,
 583};
 584
 585static struct rpc_version *     nlm_versions[] = {
 586        [1] = &nlm_version1,
 587        [3] = &nlm_version3,
 588#ifdef  CONFIG_LOCKD_V4
 589        [4] = &nlm_version4,
 590#endif
 591};
 592
 593static struct rpc_stat          nlm_stats;
 594
 595struct rpc_program              nlm_program = {
 596                .name           = "lockd",
 597                .number         = NLM_PROGRAM,
 598                .nrvers         = ARRAY_SIZE(nlm_versions),
 599                .version        = nlm_versions,
 600                .stats          = &nlm_stats,
 601};
 602
 603#ifdef RPC_DEBUG
 604const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie)
 605{
 606        /*
 607         * We can get away with a static buffer because we're only
 608         * called with BKL held.
 609         */
 610        static char buf[2*NLM_MAXCOOKIELEN+1];
 611        unsigned int i, len = sizeof(buf);
 612        char *p = buf;
 613
 614        len--;  /* allow for trailing \0 */
 615        if (len < 3)
 616                return "???";
 617        for (i = 0 ; i < cookie->len ; i++) {
 618                if (len < 2) {
 619                        strcpy(p-3, "...");
 620                        break;
 621                }
 622                sprintf(p, "%02x", cookie->data[i]);
 623                p += 2;
 624                len -= 2;
 625        }
 626        *p = '\0';
 627
 628        return buf;
 629}
 630#endif
 631