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