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