linux/fs/lockd/clntxdr.c
<<
>>
Prefs
   1/*
   2 * linux/fs/lockd/clntxdr.c
   3 *
   4 * XDR functions to encode/decode NLM version 3 RPC arguments and results.
   5 * NLM version 3 is backwards compatible with NLM versions 1 and 2.
   6 *
   7 * NLM client-side only.
   8 *
   9 * Copyright (C) 2010, Oracle.  All rights reserved.
  10 */
  11
  12#include <linux/types.h>
  13#include <linux/sunrpc/xdr.h>
  14#include <linux/sunrpc/clnt.h>
  15#include <linux/sunrpc/stats.h>
  16#include <linux/lockd/lockd.h>
  17
  18#include <uapi/linux/nfs2.h>
  19
  20#define NLMDBG_FACILITY         NLMDBG_XDR
  21
  22#if (NLMCLNT_OHSIZE > XDR_MAX_NETOBJ)
  23#  error "NLM host name cannot be larger than XDR_MAX_NETOBJ!"
  24#endif
  25
  26/*
  27 * Declare the space requirements for NLM arguments and replies as
  28 * number of 32bit-words
  29 */
  30#define NLM_cookie_sz           (1+(NLM_MAXCOOKIELEN>>2))
  31#define NLM_caller_sz           (1+(NLMCLNT_OHSIZE>>2))
  32#define NLM_owner_sz            (1+(NLMCLNT_OHSIZE>>2))
  33#define NLM_fhandle_sz          (1+(NFS2_FHSIZE>>2))
  34#define NLM_lock_sz             (3+NLM_caller_sz+NLM_owner_sz+NLM_fhandle_sz)
  35#define NLM_holder_sz           (4+NLM_owner_sz)
  36
  37#define NLM_testargs_sz         (NLM_cookie_sz+1+NLM_lock_sz)
  38#define NLM_lockargs_sz         (NLM_cookie_sz+4+NLM_lock_sz)
  39#define NLM_cancargs_sz         (NLM_cookie_sz+2+NLM_lock_sz)
  40#define NLM_unlockargs_sz       (NLM_cookie_sz+NLM_lock_sz)
  41
  42#define NLM_testres_sz          (NLM_cookie_sz+1+NLM_holder_sz)
  43#define NLM_res_sz              (NLM_cookie_sz+1)
  44#define NLM_norep_sz            (0)
  45
  46
  47static s32 loff_t_to_s32(loff_t offset)
  48{
  49        s32 res;
  50
  51        if (offset >= NLM_OFFSET_MAX)
  52                res = NLM_OFFSET_MAX;
  53        else if (offset <= -NLM_OFFSET_MAX)
  54                res = -NLM_OFFSET_MAX;
  55        else
  56                res = offset;
  57        return res;
  58}
  59
  60static void nlm_compute_offsets(const struct nlm_lock *lock,
  61                                u32 *l_offset, u32 *l_len)
  62{
  63        const struct file_lock *fl = &lock->fl;
  64
  65        *l_offset = loff_t_to_s32(fl->fl_start);
  66        if (fl->fl_end == OFFSET_MAX)
  67                *l_len = 0;
  68        else
  69                *l_len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1);
  70}
  71
  72/*
  73 * Handle decode buffer overflows out-of-line.
  74 */
  75static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
  76{
  77        dprintk("lockd: %s prematurely hit the end of our receive buffer. "
  78                "Remaining buffer length is %tu words.\n",
  79                func, xdr->end - xdr->p);
  80}
  81
  82
  83/*
  84 * Encode/decode NLMv3 basic data types
  85 *
  86 * Basic NLMv3 data types are not defined in an IETF standards
  87 * document.  X/Open has a description of these data types that
  88 * is useful.  See Chapter 10 of "Protocols for Interworking:
  89 * XNFS, Version 3W".
  90 *
  91 * Not all basic data types have their own encoding and decoding
  92 * functions.  For run-time efficiency, some data types are encoded
  93 * or decoded inline.
  94 */
  95
  96static void encode_bool(struct xdr_stream *xdr, const int value)
  97{
  98        __be32 *p;
  99
 100        p = xdr_reserve_space(xdr, 4);
 101        *p = value ? xdr_one : xdr_zero;
 102}
 103
 104static void encode_int32(struct xdr_stream *xdr, const s32 value)
 105{
 106        __be32 *p;
 107
 108        p = xdr_reserve_space(xdr, 4);
 109        *p = cpu_to_be32(value);
 110}
 111
 112/*
 113 *      typedef opaque netobj<MAXNETOBJ_SZ>
 114 */
 115static void encode_netobj(struct xdr_stream *xdr,
 116                          const u8 *data, const unsigned int length)
 117{
 118        __be32 *p;
 119
 120        p = xdr_reserve_space(xdr, 4 + length);
 121        xdr_encode_opaque(p, data, length);
 122}
 123
 124static int decode_netobj(struct xdr_stream *xdr,
 125                         struct xdr_netobj *obj)
 126{
 127        u32 length;
 128        __be32 *p;
 129
 130        p = xdr_inline_decode(xdr, 4);
 131        if (unlikely(p == NULL))
 132                goto out_overflow;
 133        length = be32_to_cpup(p++);
 134        if (unlikely(length > XDR_MAX_NETOBJ))
 135                goto out_size;
 136        obj->len = length;
 137        obj->data = (u8 *)p;
 138        return 0;
 139out_size:
 140        dprintk("NFS: returned netobj was too long: %u\n", length);
 141        return -EIO;
 142out_overflow:
 143        print_overflow_msg(__func__, xdr);
 144        return -EIO;
 145}
 146
 147/*
 148 *      netobj cookie;
 149 */
 150static void encode_cookie(struct xdr_stream *xdr,
 151                          const struct nlm_cookie *cookie)
 152{
 153        encode_netobj(xdr, (u8 *)&cookie->data, cookie->len);
 154}
 155
 156static int decode_cookie(struct xdr_stream *xdr,
 157                         struct nlm_cookie *cookie)
 158{
 159        u32 length;
 160        __be32 *p;
 161
 162        p = xdr_inline_decode(xdr, 4);
 163        if (unlikely(p == NULL))
 164                goto out_overflow;
 165        length = be32_to_cpup(p++);
 166        /* apparently HPUX can return empty cookies */
 167        if (length == 0)
 168                goto out_hpux;
 169        if (length > NLM_MAXCOOKIELEN)
 170                goto out_size;
 171        p = xdr_inline_decode(xdr, length);
 172        if (unlikely(p == NULL))
 173                goto out_overflow;
 174        cookie->len = length;
 175        memcpy(cookie->data, p, length);
 176        return 0;
 177out_hpux:
 178        cookie->len = 4;
 179        memset(cookie->data, 0, 4);
 180        return 0;
 181out_size:
 182        dprintk("NFS: returned cookie was too long: %u\n", length);
 183        return -EIO;
 184out_overflow:
 185        print_overflow_msg(__func__, xdr);
 186        return -EIO;
 187}
 188
 189/*
 190 *      netobj fh;
 191 */
 192static void encode_fh(struct xdr_stream *xdr, const struct nfs_fh *fh)
 193{
 194        encode_netobj(xdr, (u8 *)&fh->data, NFS2_FHSIZE);
 195}
 196
 197/*
 198 *      enum nlm_stats {
 199 *              LCK_GRANTED = 0,
 200 *              LCK_DENIED = 1,
 201 *              LCK_DENIED_NOLOCKS = 2,
 202 *              LCK_BLOCKED = 3,
 203 *              LCK_DENIED_GRACE_PERIOD = 4
 204 *      };
 205 *
 206 *
 207 *      struct nlm_stat {
 208 *              nlm_stats stat;
 209 *      };
 210 *
 211 * NB: we don't swap bytes for the NLM status values.  The upper
 212 * layers deal directly with the status value in network byte
 213 * order.
 214 */
 215
 216static void encode_nlm_stat(struct xdr_stream *xdr,
 217                            const __be32 stat)
 218{
 219        __be32 *p;
 220
 221        WARN_ON_ONCE(be32_to_cpu(stat) > NLM_LCK_DENIED_GRACE_PERIOD);
 222        p = xdr_reserve_space(xdr, 4);
 223        *p = stat;
 224}
 225
 226static int decode_nlm_stat(struct xdr_stream *xdr,
 227                           __be32 *stat)
 228{
 229        __be32 *p;
 230
 231        p = xdr_inline_decode(xdr, 4);
 232        if (unlikely(p == NULL))
 233                goto out_overflow;
 234        if (unlikely(ntohl(*p) > ntohl(nlm_lck_denied_grace_period)))
 235                goto out_enum;
 236        *stat = *p;
 237        return 0;
 238out_enum:
 239        dprintk("%s: server returned invalid nlm_stats value: %u\n",
 240                __func__, be32_to_cpup(p));
 241        return -EIO;
 242out_overflow:
 243        print_overflow_msg(__func__, xdr);
 244        return -EIO;
 245}
 246
 247/*
 248 *      struct nlm_holder {
 249 *              bool exclusive;
 250 *              int uppid;
 251 *              netobj oh;
 252 *              unsigned l_offset;
 253 *              unsigned l_len;
 254 *      };
 255 */
 256static void encode_nlm_holder(struct xdr_stream *xdr,
 257                              const struct nlm_res *result)
 258{
 259        const struct nlm_lock *lock = &result->lock;
 260        u32 l_offset, l_len;
 261        __be32 *p;
 262
 263        encode_bool(xdr, lock->fl.fl_type == F_RDLCK);
 264        encode_int32(xdr, lock->svid);
 265        encode_netobj(xdr, lock->oh.data, lock->oh.len);
 266
 267        p = xdr_reserve_space(xdr, 4 + 4);
 268        nlm_compute_offsets(lock, &l_offset, &l_len);
 269        *p++ = cpu_to_be32(l_offset);
 270        *p   = cpu_to_be32(l_len);
 271}
 272
 273static int decode_nlm_holder(struct xdr_stream *xdr, struct nlm_res *result)
 274{
 275        struct nlm_lock *lock = &result->lock;
 276        struct file_lock *fl = &lock->fl;
 277        u32 exclusive, l_offset, l_len;
 278        int error;
 279        __be32 *p;
 280        s32 end;
 281
 282        memset(lock, 0, sizeof(*lock));
 283        locks_init_lock(fl);
 284
 285        p = xdr_inline_decode(xdr, 4 + 4);
 286        if (unlikely(p == NULL))
 287                goto out_overflow;
 288        exclusive = be32_to_cpup(p++);
 289        lock->svid = be32_to_cpup(p);
 290        fl->fl_pid = (pid_t)lock->svid;
 291
 292        error = decode_netobj(xdr, &lock->oh);
 293        if (unlikely(error))
 294                goto out;
 295
 296        p = xdr_inline_decode(xdr, 4 + 4);
 297        if (unlikely(p == NULL))
 298                goto out_overflow;
 299
 300        fl->fl_flags = FL_POSIX;
 301        fl->fl_type  = exclusive != 0 ? F_WRLCK : F_RDLCK;
 302        l_offset = be32_to_cpup(p++);
 303        l_len = be32_to_cpup(p);
 304        end = l_offset + l_len - 1;
 305
 306        fl->fl_start = (loff_t)l_offset;
 307        if (l_len == 0 || end < 0)
 308                fl->fl_end = OFFSET_MAX;
 309        else
 310                fl->fl_end = (loff_t)end;
 311        error = 0;
 312out:
 313        return error;
 314out_overflow:
 315        print_overflow_msg(__func__, xdr);
 316        return -EIO;
 317}
 318
 319/*
 320 *      string caller_name<LM_MAXSTRLEN>;
 321 */
 322static void encode_caller_name(struct xdr_stream *xdr, const char *name)
 323{
 324        /* NB: client-side does not set lock->len */
 325        u32 length = strlen(name);
 326        __be32 *p;
 327
 328        p = xdr_reserve_space(xdr, 4 + length);
 329        xdr_encode_opaque(p, name, length);
 330}
 331
 332/*
 333 *      struct nlm_lock {
 334 *              string caller_name<LM_MAXSTRLEN>;
 335 *              netobj fh;
 336 *              netobj oh;
 337 *              int uppid;
 338 *              unsigned l_offset;
 339 *              unsigned l_len;
 340 *      };
 341 */
 342static void encode_nlm_lock(struct xdr_stream *xdr,
 343                            const struct nlm_lock *lock)
 344{
 345        u32 l_offset, l_len;
 346        __be32 *p;
 347
 348        encode_caller_name(xdr, lock->caller);
 349        encode_fh(xdr, &lock->fh);
 350        encode_netobj(xdr, lock->oh.data, lock->oh.len);
 351
 352        p = xdr_reserve_space(xdr, 4 + 4 + 4);
 353        *p++ = cpu_to_be32(lock->svid);
 354
 355        nlm_compute_offsets(lock, &l_offset, &l_len);
 356        *p++ = cpu_to_be32(l_offset);
 357        *p   = cpu_to_be32(l_len);
 358}
 359
 360
 361/*
 362 * NLMv3 XDR encode functions
 363 *
 364 * NLMv3 argument types are defined in Chapter 10 of The Open Group's
 365 * "Protocols for Interworking: XNFS, Version 3W".
 366 */
 367
 368/*
 369 *      struct nlm_testargs {
 370 *              netobj cookie;
 371 *              bool exclusive;
 372 *              struct nlm_lock alock;
 373 *      };
 374 */
 375static void nlm_xdr_enc_testargs(struct rpc_rqst *req,
 376                                 struct xdr_stream *xdr,
 377                                 const void *data)
 378{
 379        const struct nlm_args *args = data;
 380        const struct nlm_lock *lock = &args->lock;
 381
 382        encode_cookie(xdr, &args->cookie);
 383        encode_bool(xdr, lock->fl.fl_type == F_WRLCK);
 384        encode_nlm_lock(xdr, lock);
 385}
 386
 387/*
 388 *      struct nlm_lockargs {
 389 *              netobj cookie;
 390 *              bool block;
 391 *              bool exclusive;
 392 *              struct nlm_lock alock;
 393 *              bool reclaim;
 394 *              int state;
 395 *      };
 396 */
 397static void nlm_xdr_enc_lockargs(struct rpc_rqst *req,
 398                                 struct xdr_stream *xdr,
 399                                 const void *data)
 400{
 401        const struct nlm_args *args = data;
 402        const struct nlm_lock *lock = &args->lock;
 403
 404        encode_cookie(xdr, &args->cookie);
 405        encode_bool(xdr, args->block);
 406        encode_bool(xdr, lock->fl.fl_type == F_WRLCK);
 407        encode_nlm_lock(xdr, lock);
 408        encode_bool(xdr, args->reclaim);
 409        encode_int32(xdr, args->state);
 410}
 411
 412/*
 413 *      struct nlm_cancargs {
 414 *              netobj cookie;
 415 *              bool block;
 416 *              bool exclusive;
 417 *              struct nlm_lock alock;
 418 *      };
 419 */
 420static void nlm_xdr_enc_cancargs(struct rpc_rqst *req,
 421                                 struct xdr_stream *xdr,
 422                                 const void *data)
 423{
 424        const struct nlm_args *args = data;
 425        const struct nlm_lock *lock = &args->lock;
 426
 427        encode_cookie(xdr, &args->cookie);
 428        encode_bool(xdr, args->block);
 429        encode_bool(xdr, lock->fl.fl_type == F_WRLCK);
 430        encode_nlm_lock(xdr, lock);
 431}
 432
 433/*
 434 *      struct nlm_unlockargs {
 435 *              netobj cookie;
 436 *              struct nlm_lock alock;
 437 *      };
 438 */
 439static void nlm_xdr_enc_unlockargs(struct rpc_rqst *req,
 440                                   struct xdr_stream *xdr,
 441                                   const void *data)
 442{
 443        const struct nlm_args *args = data;
 444        const struct nlm_lock *lock = &args->lock;
 445
 446        encode_cookie(xdr, &args->cookie);
 447        encode_nlm_lock(xdr, lock);
 448}
 449
 450/*
 451 *      struct nlm_res {
 452 *              netobj cookie;
 453 *              nlm_stat stat;
 454 *      };
 455 */
 456static void nlm_xdr_enc_res(struct rpc_rqst *req,
 457                            struct xdr_stream *xdr,
 458                            const void *data)
 459{
 460        const struct nlm_res *result = data;
 461
 462        encode_cookie(xdr, &result->cookie);
 463        encode_nlm_stat(xdr, result->status);
 464}
 465
 466/*
 467 *      union nlm_testrply switch (nlm_stats stat) {
 468 *      case LCK_DENIED:
 469 *              struct nlm_holder holder;
 470 *      default:
 471 *              void;
 472 *      };
 473 *
 474 *      struct nlm_testres {
 475 *              netobj cookie;
 476 *              nlm_testrply test_stat;
 477 *      };
 478 */
 479static void encode_nlm_testrply(struct xdr_stream *xdr,
 480                                const struct nlm_res *result)
 481{
 482        if (result->status == nlm_lck_denied)
 483                encode_nlm_holder(xdr, result);
 484}
 485
 486static void nlm_xdr_enc_testres(struct rpc_rqst *req,
 487                                struct xdr_stream *xdr,
 488                                const void *data)
 489{
 490        const struct nlm_res *result = data;
 491
 492        encode_cookie(xdr, &result->cookie);
 493        encode_nlm_stat(xdr, result->status);
 494        encode_nlm_testrply(xdr, result);
 495}
 496
 497
 498/*
 499 * NLMv3 XDR decode functions
 500 *
 501 * NLMv3 result types are defined in Chapter 10 of The Open Group's
 502 * "Protocols for Interworking: XNFS, Version 3W".
 503 */
 504
 505/*
 506 *      union nlm_testrply switch (nlm_stats stat) {
 507 *      case LCK_DENIED:
 508 *              struct nlm_holder holder;
 509 *      default:
 510 *              void;
 511 *      };
 512 *
 513 *      struct nlm_testres {
 514 *              netobj cookie;
 515 *              nlm_testrply test_stat;
 516 *      };
 517 */
 518static int decode_nlm_testrply(struct xdr_stream *xdr,
 519                               struct nlm_res *result)
 520{
 521        int error;
 522
 523        error = decode_nlm_stat(xdr, &result->status);
 524        if (unlikely(error))
 525                goto out;
 526        if (result->status == nlm_lck_denied)
 527                error = decode_nlm_holder(xdr, result);
 528out:
 529        return error;
 530}
 531
 532static int nlm_xdr_dec_testres(struct rpc_rqst *req,
 533                               struct xdr_stream *xdr,
 534                               void *data)
 535{
 536        struct nlm_res *result = data;
 537        int error;
 538
 539        error = decode_cookie(xdr, &result->cookie);
 540        if (unlikely(error))
 541                goto out;
 542        error = decode_nlm_testrply(xdr, result);
 543out:
 544        return error;
 545}
 546
 547/*
 548 *      struct nlm_res {
 549 *              netobj cookie;
 550 *              nlm_stat stat;
 551 *      };
 552 */
 553static int nlm_xdr_dec_res(struct rpc_rqst *req,
 554                           struct xdr_stream *xdr,
 555                           void *data)
 556{
 557        struct nlm_res *result = data;
 558        int error;
 559
 560        error = decode_cookie(xdr, &result->cookie);
 561        if (unlikely(error))
 562                goto out;
 563        error = decode_nlm_stat(xdr, &result->status);
 564out:
 565        return error;
 566}
 567
 568
 569/*
 570 * For NLM, a void procedure really returns nothing
 571 */
 572#define nlm_xdr_dec_norep       NULL
 573
 574#define PROC(proc, argtype, restype)    \
 575[NLMPROC_##proc] = {                                                    \
 576        .p_proc      = NLMPROC_##proc,                                  \
 577        .p_encode    = nlm_xdr_enc_##argtype,           \
 578        .p_decode    = nlm_xdr_dec_##restype,                           \
 579        .p_arglen    = NLM_##argtype##_sz,                              \
 580        .p_replen    = NLM_##restype##_sz,                              \
 581        .p_statidx   = NLMPROC_##proc,                                  \
 582        .p_name      = #proc,                                           \
 583        }
 584
 585static const struct rpc_procinfo nlm_procedures[] = {
 586        PROC(TEST,              testargs,       testres),
 587        PROC(LOCK,              lockargs,       res),
 588        PROC(CANCEL,            cancargs,       res),
 589        PROC(UNLOCK,            unlockargs,     res),
 590        PROC(GRANTED,           testargs,       res),
 591        PROC(TEST_MSG,          testargs,       norep),
 592        PROC(LOCK_MSG,          lockargs,       norep),
 593        PROC(CANCEL_MSG,        cancargs,       norep),
 594        PROC(UNLOCK_MSG,        unlockargs,     norep),
 595        PROC(GRANTED_MSG,       testargs,       norep),
 596        PROC(TEST_RES,          testres,        norep),
 597        PROC(LOCK_RES,          res,            norep),
 598        PROC(CANCEL_RES,        res,            norep),
 599        PROC(UNLOCK_RES,        res,            norep),
 600        PROC(GRANTED_RES,       res,            norep),
 601};
 602
 603static unsigned int nlm_version1_counts[ARRAY_SIZE(nlm_procedures)];
 604static const struct rpc_version nlm_version1 = {
 605        .number         = 1,
 606        .nrprocs        = ARRAY_SIZE(nlm_procedures),
 607        .procs          = nlm_procedures,
 608        .counts         = nlm_version1_counts,
 609};
 610
 611static unsigned int nlm_version3_counts[ARRAY_SIZE(nlm_procedures)];
 612static const struct rpc_version nlm_version3 = {
 613        .number         = 3,
 614        .nrprocs        = ARRAY_SIZE(nlm_procedures),
 615        .procs          = nlm_procedures,
 616        .counts         = nlm_version3_counts,
 617};
 618
 619static const struct rpc_version *nlm_versions[] = {
 620        [1] = &nlm_version1,
 621        [3] = &nlm_version3,
 622#ifdef CONFIG_LOCKD_V4
 623        [4] = &nlm_version4,
 624#endif
 625};
 626
 627static struct rpc_stat          nlm_rpc_stats;
 628
 629const struct rpc_program        nlm_program = {
 630        .name           = "lockd",
 631        .number         = NLM_PROGRAM,
 632        .nrvers         = ARRAY_SIZE(nlm_versions),
 633        .version        = nlm_versions,
 634        .stats          = &nlm_rpc_stats,
 635};
 636