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