linux/fs/lockd/svcproc.c
<<
>>
Prefs
   1/*
   2 * linux/fs/lockd/svcproc.c
   3 *
   4 * Lockd server procedures. We don't implement the NLM_*_RES 
   5 * procedures because we don't use the async procedures.
   6 *
   7 * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
   8 */
   9
  10#include <linux/types.h>
  11#include <linux/time.h>
  12#include <linux/lockd/lockd.h>
  13#include <linux/lockd/share.h>
  14#include <linux/sunrpc/svc_xprt.h>
  15
  16#define NLMDBG_FACILITY         NLMDBG_CLIENT
  17
  18#ifdef CONFIG_LOCKD_V4
  19static __be32
  20cast_to_nlm(__be32 status, u32 vers)
  21{
  22        /* Note: status is assumed to be in network byte order !!! */
  23        if (vers != 4){
  24                switch (status) {
  25                case nlm_granted:
  26                case nlm_lck_denied:
  27                case nlm_lck_denied_nolocks:
  28                case nlm_lck_blocked:
  29                case nlm_lck_denied_grace_period:
  30                case nlm_drop_reply:
  31                        break;
  32                case nlm4_deadlock:
  33                        status = nlm_lck_denied;
  34                        break;
  35                default:
  36                        status = nlm_lck_denied_nolocks;
  37                }
  38        }
  39
  40        return (status);
  41}
  42#define cast_status(status) (cast_to_nlm(status, rqstp->rq_vers))
  43#else
  44#define cast_status(status) (status)
  45#endif
  46
  47/*
  48 * Obtain client and file from arguments
  49 */
  50static __be32
  51nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
  52                        struct nlm_host **hostp, struct nlm_file **filp)
  53{
  54        struct nlm_host         *host = NULL;
  55        struct nlm_file         *file = NULL;
  56        struct nlm_lock         *lock = &argp->lock;
  57        __be32                  error = 0;
  58
  59        /* nfsd callbacks must have been installed for this procedure */
  60        if (!nlmsvc_ops)
  61                return nlm_lck_denied_nolocks;
  62
  63        /* Obtain host handle */
  64        if (!(host = nlmsvc_lookup_host(rqstp, lock->caller, lock->len))
  65         || (argp->monitor && nsm_monitor(host) < 0))
  66                goto no_locks;
  67        *hostp = host;
  68
  69        /* Obtain file pointer. Not used by FREE_ALL call. */
  70        if (filp != NULL) {
  71                if ((error = nlm_lookup_file(rqstp, &file, &lock->fh)) != 0)
  72                        goto no_locks;
  73                *filp = file;
  74
  75                /* Set up the missing parts of the file_lock structure */
  76                lock->fl.fl_file  = file->f_file;
  77                lock->fl.fl_owner = (fl_owner_t) host;
  78                lock->fl.fl_lmops = &nlmsvc_lock_operations;
  79        }
  80
  81        return 0;
  82
  83no_locks:
  84        nlmsvc_release_host(host);
  85        if (error)
  86                return error;
  87        return nlm_lck_denied_nolocks;
  88}
  89
  90/*
  91 * NULL: Test for presence of service
  92 */
  93static __be32
  94nlmsvc_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
  95{
  96        dprintk("lockd: NULL          called\n");
  97        return rpc_success;
  98}
  99
 100/*
 101 * TEST: Check for conflicting lock
 102 */
 103static __be32
 104nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
 105                                         struct nlm_res  *resp)
 106{
 107        struct nlm_host *host;
 108        struct nlm_file *file;
 109        __be32 rc = rpc_success;
 110
 111        dprintk("lockd: TEST          called\n");
 112        resp->cookie = argp->cookie;
 113
 114        /* Obtain client and file */
 115        if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
 116                return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
 117
 118        /* Now check for conflicting locks */
 119        resp->status = cast_status(nlmsvc_testlock(rqstp, file, host, &argp->lock, &resp->lock, &resp->cookie));
 120        if (resp->status == nlm_drop_reply)
 121                rc = rpc_drop_reply;
 122        else
 123                dprintk("lockd: TEST          status %d vers %d\n",
 124                        ntohl(resp->status), rqstp->rq_vers);
 125
 126        nlmsvc_release_host(host);
 127        nlm_release_file(file);
 128        return rc;
 129}
 130
 131static __be32
 132nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
 133                                         struct nlm_res  *resp)
 134{
 135        struct nlm_host *host;
 136        struct nlm_file *file;
 137        __be32 rc = rpc_success;
 138
 139        dprintk("lockd: LOCK          called\n");
 140
 141        resp->cookie = argp->cookie;
 142
 143        /* Obtain client and file */
 144        if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
 145                return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
 146
 147#if 0
 148        /* If supplied state doesn't match current state, we assume it's
 149         * an old request that time-warped somehow. Any error return would
 150         * do in this case because it's irrelevant anyway.
 151         *
 152         * NB: We don't retrieve the remote host's state yet.
 153         */
 154        if (host->h_nsmstate && host->h_nsmstate != argp->state) {
 155                resp->status = nlm_lck_denied_nolocks;
 156        } else
 157#endif
 158
 159        /* Now try to lock the file */
 160        resp->status = cast_status(nlmsvc_lock(rqstp, file, host, &argp->lock,
 161                                               argp->block, &argp->cookie,
 162                                               argp->reclaim));
 163        if (resp->status == nlm_drop_reply)
 164                rc = rpc_drop_reply;
 165        else
 166                dprintk("lockd: LOCK         status %d\n", ntohl(resp->status));
 167
 168        nlmsvc_release_host(host);
 169        nlm_release_file(file);
 170        return rc;
 171}
 172
 173static __be32
 174nlmsvc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
 175                                           struct nlm_res  *resp)
 176{
 177        struct nlm_host *host;
 178        struct nlm_file *file;
 179        struct net *net = SVC_NET(rqstp);
 180
 181        dprintk("lockd: CANCEL        called\n");
 182
 183        resp->cookie = argp->cookie;
 184
 185        /* Don't accept requests during grace period */
 186        if (locks_in_grace(net)) {
 187                resp->status = nlm_lck_denied_grace_period;
 188                return rpc_success;
 189        }
 190
 191        /* Obtain client and file */
 192        if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
 193                return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
 194
 195        /* Try to cancel request. */
 196        resp->status = cast_status(nlmsvc_cancel_blocked(net, file, &argp->lock));
 197
 198        dprintk("lockd: CANCEL        status %d\n", ntohl(resp->status));
 199        nlmsvc_release_host(host);
 200        nlm_release_file(file);
 201        return rpc_success;
 202}
 203
 204/*
 205 * UNLOCK: release a lock
 206 */
 207static __be32
 208nlmsvc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
 209                                           struct nlm_res  *resp)
 210{
 211        struct nlm_host *host;
 212        struct nlm_file *file;
 213        struct net *net = SVC_NET(rqstp);
 214
 215        dprintk("lockd: UNLOCK        called\n");
 216
 217        resp->cookie = argp->cookie;
 218
 219        /* Don't accept new lock requests during grace period */
 220        if (locks_in_grace(net)) {
 221                resp->status = nlm_lck_denied_grace_period;
 222                return rpc_success;
 223        }
 224
 225        /* Obtain client and file */
 226        if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
 227                return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
 228
 229        /* Now try to remove the lock */
 230        resp->status = cast_status(nlmsvc_unlock(net, file, &argp->lock));
 231
 232        dprintk("lockd: UNLOCK        status %d\n", ntohl(resp->status));
 233        nlmsvc_release_host(host);
 234        nlm_release_file(file);
 235        return rpc_success;
 236}
 237
 238/*
 239 * GRANTED: A server calls us to tell that a process' lock request
 240 * was granted
 241 */
 242static __be32
 243nlmsvc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp,
 244                                            struct nlm_res  *resp)
 245{
 246        resp->cookie = argp->cookie;
 247
 248        dprintk("lockd: GRANTED       called\n");
 249        resp->status = nlmclnt_grant(svc_addr(rqstp), &argp->lock);
 250        dprintk("lockd: GRANTED       status %d\n", ntohl(resp->status));
 251        return rpc_success;
 252}
 253
 254/*
 255 * This is the generic lockd callback for async RPC calls
 256 */
 257static void nlmsvc_callback_exit(struct rpc_task *task, void *data)
 258{
 259        dprintk("lockd: %5u callback returned %d\n", task->tk_pid,
 260                        -task->tk_status);
 261}
 262
 263void nlmsvc_release_call(struct nlm_rqst *call)
 264{
 265        if (!atomic_dec_and_test(&call->a_count))
 266                return;
 267        nlmsvc_release_host(call->a_host);
 268        kfree(call);
 269}
 270
 271static void nlmsvc_callback_release(void *data)
 272{
 273        nlmsvc_release_call(data);
 274}
 275
 276static const struct rpc_call_ops nlmsvc_callback_ops = {
 277        .rpc_call_done = nlmsvc_callback_exit,
 278        .rpc_release = nlmsvc_callback_release,
 279};
 280
 281/*
 282 * `Async' versions of the above service routines. They aren't really,
 283 * because we send the callback before the reply proper. I hope this
 284 * doesn't break any clients.
 285 */
 286static __be32 nlmsvc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args *argp,
 287                __be32 (*func)(struct svc_rqst *, struct nlm_args *, struct nlm_res  *))
 288{
 289        struct nlm_host *host;
 290        struct nlm_rqst *call;
 291        __be32 stat;
 292
 293        host = nlmsvc_lookup_host(rqstp,
 294                                  argp->lock.caller,
 295                                  argp->lock.len);
 296        if (host == NULL)
 297                return rpc_system_err;
 298
 299        call = nlm_alloc_call(host);
 300        nlmsvc_release_host(host);
 301        if (call == NULL)
 302                return rpc_system_err;
 303
 304        stat = func(rqstp, argp, &call->a_res);
 305        if (stat != 0) {
 306                nlmsvc_release_call(call);
 307                return stat;
 308        }
 309
 310        call->a_flags = RPC_TASK_ASYNC;
 311        if (nlm_async_reply(call, proc, &nlmsvc_callback_ops) < 0)
 312                return rpc_system_err;
 313        return rpc_success;
 314}
 315
 316static __be32 nlmsvc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
 317                                             void            *resp)
 318{
 319        dprintk("lockd: TEST_MSG      called\n");
 320        return nlmsvc_callback(rqstp, NLMPROC_TEST_RES, argp, nlmsvc_proc_test);
 321}
 322
 323static __be32 nlmsvc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
 324                                             void            *resp)
 325{
 326        dprintk("lockd: LOCK_MSG      called\n");
 327        return nlmsvc_callback(rqstp, NLMPROC_LOCK_RES, argp, nlmsvc_proc_lock);
 328}
 329
 330static __be32 nlmsvc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
 331                                               void            *resp)
 332{
 333        dprintk("lockd: CANCEL_MSG    called\n");
 334        return nlmsvc_callback(rqstp, NLMPROC_CANCEL_RES, argp, nlmsvc_proc_cancel);
 335}
 336
 337static __be32
 338nlmsvc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
 339                                               void            *resp)
 340{
 341        dprintk("lockd: UNLOCK_MSG    called\n");
 342        return nlmsvc_callback(rqstp, NLMPROC_UNLOCK_RES, argp, nlmsvc_proc_unlock);
 343}
 344
 345static __be32
 346nlmsvc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
 347                                                void            *resp)
 348{
 349        dprintk("lockd: GRANTED_MSG   called\n");
 350        return nlmsvc_callback(rqstp, NLMPROC_GRANTED_RES, argp, nlmsvc_proc_granted);
 351}
 352
 353/*
 354 * SHARE: create a DOS share or alter existing share.
 355 */
 356static __be32
 357nlmsvc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
 358                                          struct nlm_res  *resp)
 359{
 360        struct nlm_host *host;
 361        struct nlm_file *file;
 362
 363        dprintk("lockd: SHARE         called\n");
 364
 365        resp->cookie = argp->cookie;
 366
 367        /* Don't accept new lock requests during grace period */
 368        if (locks_in_grace(SVC_NET(rqstp)) && !argp->reclaim) {
 369                resp->status = nlm_lck_denied_grace_period;
 370                return rpc_success;
 371        }
 372
 373        /* Obtain client and file */
 374        if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
 375                return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
 376
 377        /* Now try to create the share */
 378        resp->status = cast_status(nlmsvc_share_file(host, file, argp));
 379
 380        dprintk("lockd: SHARE         status %d\n", ntohl(resp->status));
 381        nlmsvc_release_host(host);
 382        nlm_release_file(file);
 383        return rpc_success;
 384}
 385
 386/*
 387 * UNSHARE: Release a DOS share.
 388 */
 389static __be32
 390nlmsvc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
 391                                            struct nlm_res  *resp)
 392{
 393        struct nlm_host *host;
 394        struct nlm_file *file;
 395
 396        dprintk("lockd: UNSHARE       called\n");
 397
 398        resp->cookie = argp->cookie;
 399
 400        /* Don't accept requests during grace period */
 401        if (locks_in_grace(SVC_NET(rqstp))) {
 402                resp->status = nlm_lck_denied_grace_period;
 403                return rpc_success;
 404        }
 405
 406        /* Obtain client and file */
 407        if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
 408                return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
 409
 410        /* Now try to unshare the file */
 411        resp->status = cast_status(nlmsvc_unshare_file(host, file, argp));
 412
 413        dprintk("lockd: UNSHARE       status %d\n", ntohl(resp->status));
 414        nlmsvc_release_host(host);
 415        nlm_release_file(file);
 416        return rpc_success;
 417}
 418
 419/*
 420 * NM_LOCK: Create an unmonitored lock
 421 */
 422static __be32
 423nlmsvc_proc_nm_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
 424                                            struct nlm_res  *resp)
 425{
 426        dprintk("lockd: NM_LOCK       called\n");
 427
 428        argp->monitor = 0;              /* just clean the monitor flag */
 429        return nlmsvc_proc_lock(rqstp, argp, resp);
 430}
 431
 432/*
 433 * FREE_ALL: Release all locks and shares held by client
 434 */
 435static __be32
 436nlmsvc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp,
 437                                             void            *resp)
 438{
 439        struct nlm_host *host;
 440
 441        /* Obtain client */
 442        if (nlmsvc_retrieve_args(rqstp, argp, &host, NULL))
 443                return rpc_success;
 444
 445        nlmsvc_free_host_resources(host);
 446        nlmsvc_release_host(host);
 447        return rpc_success;
 448}
 449
 450/*
 451 * SM_NOTIFY: private callback from statd (not part of official NLM proto)
 452 */
 453static __be32
 454nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
 455                                              void              *resp)
 456{
 457        dprintk("lockd: SM_NOTIFY     called\n");
 458
 459        if (!nlm_privileged_requester(rqstp)) {
 460                char buf[RPC_MAX_ADDRBUFLEN];
 461                printk(KERN_WARNING "lockd: rejected NSM callback from %s\n",
 462                                svc_print_addr(rqstp, buf, sizeof(buf)));
 463                return rpc_system_err;
 464        }
 465
 466        nlm_host_rebooted(argp);
 467        return rpc_success;
 468}
 469
 470/*
 471 * client sent a GRANTED_RES, let's remove the associated block
 472 */
 473static __be32
 474nlmsvc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res  *argp,
 475                                                void            *resp)
 476{
 477        if (!nlmsvc_ops)
 478                return rpc_success;
 479
 480        dprintk("lockd: GRANTED_RES   called\n");
 481
 482        nlmsvc_grant_reply(&argp->cookie, argp->status);
 483        return rpc_success;
 484}
 485
 486/*
 487 * NLM Server procedures.
 488 */
 489
 490#define nlmsvc_encode_norep     nlmsvc_encode_void
 491#define nlmsvc_decode_norep     nlmsvc_decode_void
 492#define nlmsvc_decode_testres   nlmsvc_decode_void
 493#define nlmsvc_decode_lockres   nlmsvc_decode_void
 494#define nlmsvc_decode_unlockres nlmsvc_decode_void
 495#define nlmsvc_decode_cancelres nlmsvc_decode_void
 496#define nlmsvc_decode_grantedres        nlmsvc_decode_void
 497
 498#define nlmsvc_proc_none        nlmsvc_proc_null
 499#define nlmsvc_proc_test_res    nlmsvc_proc_null
 500#define nlmsvc_proc_lock_res    nlmsvc_proc_null
 501#define nlmsvc_proc_cancel_res  nlmsvc_proc_null
 502#define nlmsvc_proc_unlock_res  nlmsvc_proc_null
 503
 504struct nlm_void                 { int dummy; };
 505
 506#define PROC(name, xargt, xrest, argt, rest, respsize)  \
 507 { .pc_func     = (svc_procfunc) nlmsvc_proc_##name,    \
 508   .pc_decode   = (kxdrproc_t) nlmsvc_decode_##xargt,   \
 509   .pc_encode   = (kxdrproc_t) nlmsvc_encode_##xrest,   \
 510   .pc_release  = NULL,                                 \
 511   .pc_argsize  = sizeof(struct nlm_##argt),            \
 512   .pc_ressize  = sizeof(struct nlm_##rest),            \
 513   .pc_xdrressize = respsize,                           \
 514 }
 515
 516#define Ck      (1+XDR_QUADLEN(NLM_MAXCOOKIELEN))       /* cookie */
 517#define St      1                               /* status */
 518#define No      (1+1024/4)                      /* Net Obj */
 519#define Rg      2                               /* range - offset + size */
 520
 521struct svc_procedure            nlmsvc_procedures[] = {
 522  PROC(null,            void,           void,           void,   void, 1),
 523  PROC(test,            testargs,       testres,        args,   res, Ck+St+2+No+Rg),
 524  PROC(lock,            lockargs,       res,            args,   res, Ck+St),
 525  PROC(cancel,          cancargs,       res,            args,   res, Ck+St),
 526  PROC(unlock,          unlockargs,     res,            args,   res, Ck+St),
 527  PROC(granted,         testargs,       res,            args,   res, Ck+St),
 528  PROC(test_msg,        testargs,       norep,          args,   void, 1),
 529  PROC(lock_msg,        lockargs,       norep,          args,   void, 1),
 530  PROC(cancel_msg,      cancargs,       norep,          args,   void, 1),
 531  PROC(unlock_msg,      unlockargs,     norep,          args,   void, 1),
 532  PROC(granted_msg,     testargs,       norep,          args,   void, 1),
 533  PROC(test_res,        testres,        norep,          res,    void, 1),
 534  PROC(lock_res,        lockres,        norep,          res,    void, 1),
 535  PROC(cancel_res,      cancelres,      norep,          res,    void, 1),
 536  PROC(unlock_res,      unlockres,      norep,          res,    void, 1),
 537  PROC(granted_res,     res,            norep,          res,    void, 1),
 538  /* statd callback */
 539  PROC(sm_notify,       reboot,         void,           reboot, void, 1),
 540  PROC(none,            void,           void,           void,   void, 1),
 541  PROC(none,            void,           void,           void,   void, 1),
 542  PROC(none,            void,           void,           void,   void, 1),
 543  PROC(share,           shareargs,      shareres,       args,   res, Ck+St+1),
 544  PROC(unshare,         shareargs,      shareres,       args,   res, Ck+St+1),
 545  PROC(nm_lock,         lockargs,       res,            args,   res, Ck+St),
 546  PROC(free_all,        notify,         void,           args,   void, 0),
 547
 548};
 549
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.