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