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