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