linux/fs/lockd/svclock.c
<<
>>
Prefs
   1/*
   2 * linux/fs/lockd/svclock.c
   3 *
   4 * Handling of server-side locks, mostly of the blocked variety.
   5 * This is the ugliest part of lockd because we tread on very thin ice.
   6 * GRANT and CANCEL calls may get stuck, meet in mid-flight, etc.
   7 * IMNSHO introducing the grant callback into the NLM protocol was one
   8 * of the worst ideas Sun ever had. Except maybe for the idea of doing
   9 * NFS file locking at all.
  10 *
  11 * I'm trying hard to avoid race conditions by protecting most accesses
  12 * to a file's list of blocked locks through a semaphore. The global
  13 * list of blocked locks is not protected in this fashion however.
  14 * Therefore, some functions (such as the RPC callback for the async grant
  15 * call) move blocked locks towards the head of the list *while some other
  16 * process might be traversing it*. This should not be a problem in
  17 * practice, because this will only cause functions traversing the list
  18 * to visit some blocks twice.
  19 *
  20 * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
  21 */
  22
  23#include <linux/types.h>
  24#include <linux/slab.h>
  25#include <linux/errno.h>
  26#include <linux/kernel.h>
  27#include <linux/sched.h>
  28#include <linux/sunrpc/clnt.h>
  29#include <linux/sunrpc/svc_xprt.h>
  30#include <linux/lockd/nlm.h>
  31#include <linux/lockd/lockd.h>
  32#include <linux/kthread.h>
  33
  34#define NLMDBG_FACILITY         NLMDBG_SVCLOCK
  35
  36#ifdef CONFIG_LOCKD_V4
  37#define nlm_deadlock    nlm4_deadlock
  38#else
  39#define nlm_deadlock    nlm_lck_denied
  40#endif
  41
  42static void nlmsvc_release_block(struct nlm_block *block);
  43static void     nlmsvc_insert_block(struct nlm_block *block, unsigned long);
  44static void     nlmsvc_remove_block(struct nlm_block *block);
  45
  46static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock);
  47static void nlmsvc_freegrantargs(struct nlm_rqst *call);
  48static const struct rpc_call_ops nlmsvc_grant_ops;
  49
  50/*
  51 * The list of blocked locks to retry
  52 */
  53static LIST_HEAD(nlm_blocked);
  54static DEFINE_SPINLOCK(nlm_blocked_lock);
  55
  56#ifdef LOCKD_DEBUG
  57static const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie)
  58{
  59        /*
  60         * We can get away with a static buffer because we're only
  61         * called with BKL held.
  62         */
  63        static char buf[2*NLM_MAXCOOKIELEN+1];
  64        unsigned int i, len = sizeof(buf);
  65        char *p = buf;
  66
  67        len--;  /* allow for trailing \0 */
  68        if (len < 3)
  69                return "???";
  70        for (i = 0 ; i < cookie->len ; i++) {
  71                if (len < 2) {
  72                        strcpy(p-3, "...");
  73                        break;
  74                }
  75                sprintf(p, "%02x", cookie->data[i]);
  76                p += 2;
  77                len -= 2;
  78        }
  79        *p = '\0';
  80
  81        return buf;
  82}
  83#endif
  84
  85/*
  86 * Insert a blocked lock into the global list
  87 */
  88static void
  89nlmsvc_insert_block_locked(struct nlm_block *block, unsigned long when)
  90{
  91        struct nlm_block *b;
  92        struct list_head *pos;
  93
  94        dprintk("lockd: nlmsvc_insert_block(%p, %ld)\n", block, when);
  95        if (list_empty(&block->b_list)) {
  96                kref_get(&block->b_count);
  97        } else {
  98                list_del_init(&block->b_list);
  99        }
 100
 101        pos = &nlm_blocked;
 102        if (when != NLM_NEVER) {
 103                if ((when += jiffies) == NLM_NEVER)
 104                        when ++;
 105                list_for_each(pos, &nlm_blocked) {
 106                        b = list_entry(pos, struct nlm_block, b_list);
 107                        if (time_after(b->b_when,when) || b->b_when == NLM_NEVER)
 108                                break;
 109                }
 110                /* On normal exit from the loop, pos == &nlm_blocked,
 111                 * so we will be adding to the end of the list - good
 112                 */
 113        }
 114
 115        list_add_tail(&block->b_list, pos);
 116        block->b_when = when;
 117}
 118
 119static void nlmsvc_insert_block(struct nlm_block *block, unsigned long when)
 120{
 121        spin_lock(&nlm_blocked_lock);
 122        nlmsvc_insert_block_locked(block, when);
 123        spin_unlock(&nlm_blocked_lock);
 124}
 125
 126/*
 127 * Remove a block from the global list
 128 */
 129static inline void
 130nlmsvc_remove_block(struct nlm_block *block)
 131{
 132        if (!list_empty(&block->b_list)) {
 133                spin_lock(&nlm_blocked_lock);
 134                list_del_init(&block->b_list);
 135                spin_unlock(&nlm_blocked_lock);
 136                nlmsvc_release_block(block);
 137        }
 138}
 139
 140/*
 141 * Find a block for a given lock
 142 */
 143static struct nlm_block *
 144nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock)
 145{
 146        struct nlm_block        *block;
 147        struct file_lock        *fl;
 148
 149        dprintk("lockd: nlmsvc_lookup_block f=%p pd=%d %Ld-%Ld ty=%d\n",
 150                                file, lock->fl.fl_pid,
 151                                (long long)lock->fl.fl_start,
 152                                (long long)lock->fl.fl_end, lock->fl.fl_type);
 153        list_for_each_entry(block, &nlm_blocked, b_list) {
 154                fl = &block->b_call->a_args.lock.fl;
 155                dprintk("lockd: check f=%p pd=%d %Ld-%Ld ty=%d cookie=%s\n",
 156                                block->b_file, fl->fl_pid,
 157                                (long long)fl->fl_start,
 158                                (long long)fl->fl_end, fl->fl_type,
 159                                nlmdbg_cookie2a(&block->b_call->a_args.cookie));
 160                if (block->b_file == file && nlm_compare_locks(fl, &lock->fl)) {
 161                        kref_get(&block->b_count);
 162                        return block;
 163                }
 164        }
 165
 166        return NULL;
 167}
 168
 169static inline int nlm_cookie_match(struct nlm_cookie *a, struct nlm_cookie *b)
 170{
 171        if (a->len != b->len)
 172                return 0;
 173        if (memcmp(a->data, b->data, a->len))
 174                return 0;
 175        return 1;
 176}
 177
 178/*
 179 * Find a block with a given NLM cookie.
 180 */
 181static inline struct nlm_block *
 182nlmsvc_find_block(struct nlm_cookie *cookie)
 183{
 184        struct nlm_block *block;
 185
 186        list_for_each_entry(block, &nlm_blocked, b_list) {
 187                if (nlm_cookie_match(&block->b_call->a_args.cookie,cookie))
 188                        goto found;
 189        }
 190
 191        return NULL;
 192
 193found:
 194        dprintk("nlmsvc_find_block(%s): block=%p\n", nlmdbg_cookie2a(cookie), block);
 195        kref_get(&block->b_count);
 196        return block;
 197}
 198
 199/*
 200 * Create a block and initialize it.
 201 *
 202 * Note: we explicitly set the cookie of the grant reply to that of
 203 * the blocked lock request. The spec explicitly mentions that the client
 204 * should _not_ rely on the callback containing the same cookie as the
 205 * request, but (as I found out later) that's because some implementations
 206 * do just this. Never mind the standards comittees, they support our
 207 * logging industries.
 208 *
 209 * 10 years later: I hope we can safely ignore these old and broken
 210 * clients by now. Let's fix this so we can uniquely identify an incoming
 211 * GRANTED_RES message by cookie, without having to rely on the client's IP
 212 * address. --okir
 213 */
 214static struct nlm_block *
 215nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_host *host,
 216                    struct nlm_file *file, struct nlm_lock *lock,
 217                    struct nlm_cookie *cookie)
 218{
 219        struct nlm_block        *block;
 220        struct nlm_rqst         *call = NULL;
 221
 222        call = nlm_alloc_call(host);
 223        if (call == NULL)
 224                return NULL;
 225
 226        /* Allocate memory for block, and initialize arguments */
 227        block = kzalloc(sizeof(*block), GFP_KERNEL);
 228        if (block == NULL)
 229                goto failed;
 230        kref_init(&block->b_count);
 231        INIT_LIST_HEAD(&block->b_list);
 232        INIT_LIST_HEAD(&block->b_flist);
 233
 234        if (!nlmsvc_setgrantargs(call, lock))
 235                goto failed_free;
 236
 237        /* Set notifier function for VFS, and init args */
 238        call->a_args.lock.fl.fl_flags |= FL_SLEEP;
 239        call->a_args.lock.fl.fl_lmops = &nlmsvc_lock_operations;
 240        nlmclnt_next_cookie(&call->a_args.cookie);
 241
 242        dprintk("lockd: created block %p...\n", block);
 243
 244        /* Create and initialize the block */
 245        block->b_daemon = rqstp->rq_server;
 246        block->b_host   = host;
 247        block->b_file   = file;
 248        block->b_fl = NULL;
 249        file->f_count++;
 250
 251        /* Add to file's list of blocks */
 252        list_add(&block->b_flist, &file->f_blocks);
 253
 254        /* Set up RPC arguments for callback */
 255        block->b_call = call;
 256        call->a_flags   = RPC_TASK_ASYNC;
 257        call->a_block = block;
 258
 259        return block;
 260
 261failed_free:
 262        kfree(block);
 263failed:
 264        nlmsvc_release_call(call);
 265        return NULL;
 266}
 267
 268/*
 269 * Delete a block.
 270 * It is the caller's responsibility to check whether the file
 271 * can be closed hereafter.
 272 */
 273static int nlmsvc_unlink_block(struct nlm_block *block)
 274{
 275        int status;
 276        dprintk("lockd: unlinking block %p...\n", block);
 277
 278        /* Remove block from list */
 279        status = posix_unblock_lock(block->b_file->f_file, &block->b_call->a_args.lock.fl);
 280        nlmsvc_remove_block(block);
 281        return status;
 282}
 283
 284static void nlmsvc_free_block(struct kref *kref)
 285{
 286        struct nlm_block *block = container_of(kref, struct nlm_block, b_count);
 287        struct nlm_file         *file = block->b_file;
 288
 289        dprintk("lockd: freeing block %p...\n", block);
 290
 291        /* Remove block from file's list of blocks */
 292        list_del_init(&block->b_flist);
 293        mutex_unlock(&file->f_mutex);
 294
 295        nlmsvc_freegrantargs(block->b_call);
 296        nlmsvc_release_call(block->b_call);
 297        nlm_release_file(block->b_file);
 298        kfree(block->b_fl);
 299        kfree(block);
 300}
 301
 302static void nlmsvc_release_block(struct nlm_block *block)
 303{
 304        if (block != NULL)
 305                kref_put_mutex(&block->b_count, nlmsvc_free_block, &block->b_file->f_mutex);
 306}
 307
 308/*
 309 * Loop over all blocks and delete blocks held by
 310 * a matching host.
 311 */
 312void nlmsvc_traverse_blocks(struct nlm_host *host,
 313                        struct nlm_file *file,
 314                        nlm_host_match_fn_t match)
 315{
 316        struct nlm_block *block, *next;
 317
 318restart:
 319        mutex_lock(&file->f_mutex);
 320        list_for_each_entry_safe(block, next, &file->f_blocks, b_flist) {
 321                if (!match(block->b_host, host))
 322                        continue;
 323                /* Do not destroy blocks that are not on
 324                 * the global retry list - why? */
 325                if (list_empty(&block->b_list))
 326                        continue;
 327                kref_get(&block->b_count);
 328                mutex_unlock(&file->f_mutex);
 329                nlmsvc_unlink_block(block);
 330                nlmsvc_release_block(block);
 331                goto restart;
 332        }
 333        mutex_unlock(&file->f_mutex);
 334}
 335
 336/*
 337 * Initialize arguments for GRANTED call. The nlm_rqst structure
 338 * has been cleared already.
 339 */
 340static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock)
 341{
 342        locks_copy_lock(&call->a_args.lock.fl, &lock->fl);
 343        memcpy(&call->a_args.lock.fh, &lock->fh, sizeof(call->a_args.lock.fh));
 344        call->a_args.lock.caller = utsname()->nodename;
 345        call->a_args.lock.oh.len = lock->oh.len;
 346
 347        /* set default data area */
 348        call->a_args.lock.oh.data = call->a_owner;
 349        call->a_args.lock.svid = lock->fl.fl_pid;
 350
 351        if (lock->oh.len > NLMCLNT_OHSIZE) {
 352                void *data = kmalloc(lock->oh.len, GFP_KERNEL);
 353                if (!data)
 354                        return 0;
 355                call->a_args.lock.oh.data = (u8 *) data;
 356        }
 357
 358        memcpy(call->a_args.lock.oh.data, lock->oh.data, lock->oh.len);
 359        return 1;
 360}
 361
 362static void nlmsvc_freegrantargs(struct nlm_rqst *call)
 363{
 364        if (call->a_args.lock.oh.data != call->a_owner)
 365                kfree(call->a_args.lock.oh.data);
 366
 367        locks_release_private(&call->a_args.lock.fl);
 368}
 369
 370/*
 371 * Deferred lock request handling for non-blocking lock
 372 */
 373static __be32
 374nlmsvc_defer_lock_rqst(struct svc_rqst *rqstp, struct nlm_block *block)
 375{
 376        __be32 status = nlm_lck_denied_nolocks;
 377
 378        block->b_flags |= B_QUEUED;
 379
 380        nlmsvc_insert_block(block, NLM_TIMEOUT);
 381
 382        block->b_cache_req = &rqstp->rq_chandle;
 383        if (rqstp->rq_chandle.defer) {
 384                block->b_deferred_req =
 385                        rqstp->rq_chandle.defer(block->b_cache_req);
 386                if (block->b_deferred_req != NULL)
 387                        status = nlm_drop_reply;
 388        }
 389        dprintk("lockd: nlmsvc_defer_lock_rqst block %p flags %d status %d\n",
 390                block, block->b_flags, ntohl(status));
 391
 392        return status;
 393}
 394
 395/*
 396 * Attempt to establish a lock, and if it can't be granted, block it
 397 * if required.
 398 */
 399__be32
 400nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
 401            struct nlm_host *host, struct nlm_lock *lock, int wait,
 402            struct nlm_cookie *cookie, int reclaim)
 403{
 404        struct nlm_block        *block = NULL;
 405        int                     error;
 406        __be32                  ret;
 407
 408        dprintk("lockd: nlmsvc_lock(%s/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n",
 409                                file->f_file->f_path.dentry->d_inode->i_sb->s_id,
 410                                file->f_file->f_path.dentry->d_inode->i_ino,
 411                                lock->fl.fl_type, lock->fl.fl_pid,
 412                                (long long)lock->fl.fl_start,
 413                                (long long)lock->fl.fl_end,
 414                                wait);
 415
 416        /* Lock file against concurrent access */
 417        mutex_lock(&file->f_mutex);
 418        /* Get existing block (in case client is busy-waiting)
 419         * or create new block
 420         */
 421        block = nlmsvc_lookup_block(file, lock);
 422        if (block == NULL) {
 423                block = nlmsvc_create_block(rqstp, host, file, lock, cookie);
 424                ret = nlm_lck_denied_nolocks;
 425                if (block == NULL)
 426                        goto out;
 427                lock = &block->b_call->a_args.lock;
 428        } else
 429                lock->fl.fl_flags &= ~FL_SLEEP;
 430
 431        if (block->b_flags & B_QUEUED) {
 432                dprintk("lockd: nlmsvc_lock deferred block %p flags %d\n",
 433                                                        block, block->b_flags);
 434                if (block->b_granted) {
 435                        nlmsvc_unlink_block(block);
 436                        ret = nlm_granted;
 437                        goto out;
 438                }
 439                if (block->b_flags & B_TIMED_OUT) {
 440                        nlmsvc_unlink_block(block);
 441                        ret = nlm_lck_denied;
 442                        goto out;
 443                }
 444                ret = nlm_drop_reply;
 445                goto out;
 446        }
 447
 448        if (locks_in_grace(SVC_NET(rqstp)) && !reclaim) {
 449                ret = nlm_lck_denied_grace_period;
 450                goto out;
 451        }
 452        if (reclaim && !locks_in_grace(SVC_NET(rqstp))) {
 453                ret = nlm_lck_denied_grace_period;
 454                goto out;
 455        }
 456
 457        if (!wait)
 458                lock->fl.fl_flags &= ~FL_SLEEP;
 459        error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL);
 460        lock->fl.fl_flags &= ~FL_SLEEP;
 461
 462        dprintk("lockd: vfs_lock_file returned %d\n", error);
 463        switch (error) {
 464                case 0:
 465                        ret = nlm_granted;
 466                        goto out;
 467                case -EAGAIN:
 468                        /*
 469                         * If this is a blocking request for an
 470                         * already pending lock request then we need
 471                         * to put it back on lockd's block list
 472                         */
 473                        if (wait)
 474                                break;
 475                        ret = nlm_lck_denied;
 476                        goto out;
 477                case FILE_LOCK_DEFERRED:
 478                        if (wait)
 479                                break;
 480                        /* Filesystem lock operation is in progress
 481                           Add it to the queue waiting for callback */
 482                        ret = nlmsvc_defer_lock_rqst(rqstp, block);
 483                        goto out;
 484                case -EDEADLK:
 485                        ret = nlm_deadlock;
 486                        goto out;
 487                default:                        /* includes ENOLCK */
 488                        ret = nlm_lck_denied_nolocks;
 489                        goto out;
 490        }
 491
 492        ret = nlm_lck_blocked;
 493
 494        /* Append to list of blocked */
 495        nlmsvc_insert_block(block, NLM_NEVER);
 496out:
 497        mutex_unlock(&file->f_mutex);
 498        nlmsvc_release_block(block);
 499        dprintk("lockd: nlmsvc_lock returned %u\n", ret);
 500        return ret;
 501}
 502
 503/*
 504 * Test for presence of a conflicting lock.
 505 */
 506__be32
 507nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
 508                struct nlm_host *host, struct nlm_lock *lock,
 509                struct nlm_lock *conflock, struct nlm_cookie *cookie)
 510{
 511        struct nlm_block        *block = NULL;
 512        int                     error;
 513        __be32                  ret;
 514
 515        dprintk("lockd: nlmsvc_testlock(%s/%ld, ty=%d, %Ld-%Ld)\n",
 516                                file->f_file->f_path.dentry->d_inode->i_sb->s_id,
 517                                file->f_file->f_path.dentry->d_inode->i_ino,
 518                                lock->fl.fl_type,
 519                                (long long)lock->fl.fl_start,
 520                                (long long)lock->fl.fl_end);
 521
 522        /* Get existing block (in case client is busy-waiting) */
 523        block = nlmsvc_lookup_block(file, lock);
 524
 525        if (block == NULL) {
 526                struct file_lock *conf = kzalloc(sizeof(*conf), GFP_KERNEL);
 527
 528                if (conf == NULL)
 529                        return nlm_granted;
 530                block = nlmsvc_create_block(rqstp, host, file, lock, cookie);
 531                if (block == NULL) {
 532                        kfree(conf);
 533                        return nlm_granted;
 534                }
 535                block->b_fl = conf;
 536        }
 537        if (block->b_flags & B_QUEUED) {
 538                dprintk("lockd: nlmsvc_testlock deferred block %p flags %d fl %p\n",
 539                        block, block->b_flags, block->b_fl);
 540                if (block->b_flags & B_TIMED_OUT) {
 541                        nlmsvc_unlink_block(block);
 542                        ret = nlm_lck_denied;
 543                        goto out;
 544                }
 545                if (block->b_flags & B_GOT_CALLBACK) {
 546                        nlmsvc_unlink_block(block);
 547                        if (block->b_fl != NULL
 548                                        && block->b_fl->fl_type != F_UNLCK) {
 549                                lock->fl = *block->b_fl;
 550                                goto conf_lock;
 551                        } else {
 552                                ret = nlm_granted;
 553                                goto out;
 554                        }
 555                }
 556                ret = nlm_drop_reply;
 557                goto out;
 558        }
 559
 560        if (locks_in_grace(SVC_NET(rqstp))) {
 561                ret = nlm_lck_denied_grace_period;
 562                goto out;
 563        }
 564        error = vfs_test_lock(file->f_file, &lock->fl);
 565        if (error == FILE_LOCK_DEFERRED) {
 566                ret = nlmsvc_defer_lock_rqst(rqstp, block);
 567                goto out;
 568        }
 569        if (error) {
 570                ret = nlm_lck_denied_nolocks;
 571                goto out;
 572        }
 573        if (lock->fl.fl_type == F_UNLCK) {
 574                ret = nlm_granted;
 575                goto out;
 576        }
 577
 578conf_lock:
 579        dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n",
 580                lock->fl.fl_type, (long long)lock->fl.fl_start,
 581                (long long)lock->fl.fl_end);
 582        conflock->caller = "somehost";  /* FIXME */
 583        conflock->len = strlen(conflock->caller);
 584        conflock->oh.len = 0;           /* don't return OH info */
 585        conflock->svid = lock->fl.fl_pid;
 586        conflock->fl.fl_type = lock->fl.fl_type;
 587        conflock->fl.fl_start = lock->fl.fl_start;
 588        conflock->fl.fl_end = lock->fl.fl_end;
 589        ret = nlm_lck_denied;
 590out:
 591        if (block)
 592                nlmsvc_release_block(block);
 593        return ret;
 594}
 595
 596/*
 597 * Remove a lock.
 598 * This implies a CANCEL call: We send a GRANT_MSG, the client replies
 599 * with a GRANT_RES call which gets lost, and calls UNLOCK immediately
 600 * afterwards. In this case the block will still be there, and hence
 601 * must be removed.
 602 */
 603__be32
 604nlmsvc_unlock(struct net *net, struct nlm_file *file, struct nlm_lock *lock)
 605{
 606        int     error;
 607
 608        dprintk("lockd: nlmsvc_unlock(%s/%ld, pi=%d, %Ld-%Ld)\n",
 609                                file->f_file->f_path.dentry->d_inode->i_sb->s_id,
 610                                file->f_file->f_path.dentry->d_inode->i_ino,
 611                                lock->fl.fl_pid,
 612                                (long long)lock->fl.fl_start,
 613                                (long long)lock->fl.fl_end);
 614
 615        /* First, cancel any lock that might be there */
 616        nlmsvc_cancel_blocked(net, file, lock);
 617
 618        lock->fl.fl_type = F_UNLCK;
 619        error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL);
 620
 621        return (error < 0)? nlm_lck_denied_nolocks : nlm_granted;
 622}
 623
 624/*
 625 * Cancel a previously blocked request.
 626 *
 627 * A cancel request always overrides any grant that may currently
 628 * be in progress.
 629 * The calling procedure must check whether the file can be closed.
 630 */
 631__be32
 632nlmsvc_cancel_blocked(struct net *net, struct nlm_file *file, struct nlm_lock *lock)
 633{
 634        struct nlm_block        *block;
 635        int status = 0;
 636
 637        dprintk("lockd: nlmsvc_cancel(%s/%ld, pi=%d, %Ld-%Ld)\n",
 638                                file->f_file->f_path.dentry->d_inode->i_sb->s_id,
 639                                file->f_file->f_path.dentry->d_inode->i_ino,
 640                                lock->fl.fl_pid,
 641                                (long long)lock->fl.fl_start,
 642                                (long long)lock->fl.fl_end);
 643
 644        if (locks_in_grace(net))
 645                return nlm_lck_denied_grace_period;
 646
 647        mutex_lock(&file->f_mutex);
 648        block = nlmsvc_lookup_block(file, lock);
 649        mutex_unlock(&file->f_mutex);
 650        if (block != NULL) {
 651                vfs_cancel_lock(block->b_file->f_file,
 652                                &block->b_call->a_args.lock.fl);
 653                status = nlmsvc_unlink_block(block);
 654                nlmsvc_release_block(block);
 655        }
 656        return status ? nlm_lck_denied : nlm_granted;
 657}
 658
 659/*
 660 * This is a callback from the filesystem for VFS file lock requests.
 661 * It will be used if lm_grant is defined and the filesystem can not
 662 * respond to the request immediately.
 663 * For GETLK request it will copy the reply to the nlm_block.
 664 * For SETLK or SETLKW request it will get the local posix lock.
 665 * In all cases it will move the block to the head of nlm_blocked q where
 666 * nlmsvc_retry_blocked() can send back a reply for SETLKW or revisit the
 667 * deferred rpc for GETLK and SETLK.
 668 */
 669static void
 670nlmsvc_update_deferred_block(struct nlm_block *block, struct file_lock *conf,
 671                             int result)
 672{
 673        block->b_flags |= B_GOT_CALLBACK;
 674        if (result == 0)
 675                block->b_granted = 1;
 676        else
 677                block->b_flags |= B_TIMED_OUT;
 678        if (conf) {
 679                if (block->b_fl)
 680                        __locks_copy_lock(block->b_fl, conf);
 681        }
 682}
 683
 684static int nlmsvc_grant_deferred(struct file_lock *fl, struct file_lock *conf,
 685                                        int result)
 686{
 687        struct nlm_block *block;
 688        int rc = -ENOENT;
 689
 690        spin_lock(&nlm_blocked_lock);
 691        list_for_each_entry(block, &nlm_blocked, b_list) {
 692                if (nlm_compare_locks(&block->b_call->a_args.lock.fl, fl)) {
 693                        dprintk("lockd: nlmsvc_notify_blocked block %p flags %d\n",
 694                                                        block, block->b_flags);
 695                        if (block->b_flags & B_QUEUED) {
 696                                if (block->b_flags & B_TIMED_OUT) {
 697                                        rc = -ENOLCK;
 698                                        break;
 699                                }
 700                                nlmsvc_update_deferred_block(block, conf, result);
 701                        } else if (result == 0)
 702                                block->b_granted = 1;
 703
 704                        nlmsvc_insert_block_locked(block, 0);
 705                        svc_wake_up(block->b_daemon);
 706                        rc = 0;
 707                        break;
 708                }
 709        }
 710        spin_unlock(&nlm_blocked_lock);
 711        if (rc == -ENOENT)
 712                printk(KERN_WARNING "lockd: grant for unknown block\n");
 713        return rc;
 714}
 715
 716/*
 717 * Unblock a blocked lock request. This is a callback invoked from the
 718 * VFS layer when a lock on which we blocked is removed.
 719 *
 720 * This function doesn't grant the blocked lock instantly, but rather moves
 721 * the block to the head of nlm_blocked where it can be picked up by lockd.
 722 */
 723static void
 724nlmsvc_notify_blocked(struct file_lock *fl)
 725{
 726        struct nlm_block        *block;
 727
 728        dprintk("lockd: VFS unblock notification for block %p\n", fl);
 729        spin_lock(&nlm_blocked_lock);
 730        list_for_each_entry(block, &nlm_blocked, b_list) {
 731                if (nlm_compare_locks(&block->b_call->a_args.lock.fl, fl)) {
 732                        nlmsvc_insert_block_locked(block, 0);
 733                        spin_unlock(&nlm_blocked_lock);
 734                        svc_wake_up(block->b_daemon);
 735                        return;
 736                }
 737        }
 738        spin_unlock(&nlm_blocked_lock);
 739        printk(KERN_WARNING "lockd: notification for unknown block!\n");
 740}
 741
 742static int nlmsvc_same_owner(struct file_lock *fl1, struct file_lock *fl2)
 743{
 744        return fl1->fl_owner == fl2->fl_owner && fl1->fl_pid == fl2->fl_pid;
 745}
 746
 747const struct lock_manager_operations nlmsvc_lock_operations = {
 748        .lm_compare_owner = nlmsvc_same_owner,
 749        .lm_notify = nlmsvc_notify_blocked,
 750        .lm_grant = nlmsvc_grant_deferred,
 751};
 752
 753/*
 754 * Try to claim a lock that was previously blocked.
 755 *
 756 * Note that we use both the RPC_GRANTED_MSG call _and_ an async
 757 * RPC thread when notifying the client. This seems like overkill...
 758 * Here's why:
 759 *  -   we don't want to use a synchronous RPC thread, otherwise
 760 *      we might find ourselves hanging on a dead portmapper.
 761 *  -   Some lockd implementations (e.g. HP) don't react to
 762 *      RPC_GRANTED calls; they seem to insist on RPC_GRANTED_MSG calls.
 763 */
 764static void
 765nlmsvc_grant_blocked(struct nlm_block *block)
 766{
 767        struct nlm_file         *file = block->b_file;
 768        struct nlm_lock         *lock = &block->b_call->a_args.lock;
 769        int                     error;
 770
 771        dprintk("lockd: grant blocked lock %p\n", block);
 772
 773        kref_get(&block->b_count);
 774
 775        /* Unlink block request from list */
 776        nlmsvc_unlink_block(block);
 777
 778        /* If b_granted is true this means we've been here before.
 779         * Just retry the grant callback, possibly refreshing the RPC
 780         * binding */
 781        if (block->b_granted) {
 782                nlm_rebind_host(block->b_host);
 783                goto callback;
 784        }
 785
 786        /* Try the lock operation again */
 787        lock->fl.fl_flags |= FL_SLEEP;
 788        error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL);
 789        lock->fl.fl_flags &= ~FL_SLEEP;
 790
 791        switch (error) {
 792        case 0:
 793                break;
 794        case FILE_LOCK_DEFERRED:
 795                dprintk("lockd: lock still blocked error %d\n", error);
 796                nlmsvc_insert_block(block, NLM_NEVER);
 797                nlmsvc_release_block(block);
 798                return;
 799        default:
 800                printk(KERN_WARNING "lockd: unexpected error %d in %s!\n",
 801                                -error, __func__);
 802                nlmsvc_insert_block(block, 10 * HZ);
 803                nlmsvc_release_block(block);
 804                return;
 805        }
 806
 807callback:
 808        /* Lock was granted by VFS. */
 809        dprintk("lockd: GRANTing blocked lock.\n");
 810        block->b_granted = 1;
 811
 812        /* keep block on the list, but don't reattempt until the RPC
 813         * completes or the submission fails
 814         */
 815        nlmsvc_insert_block(block, NLM_NEVER);
 816
 817        /* Call the client -- use a soft RPC task since nlmsvc_retry_blocked
 818         * will queue up a new one if this one times out
 819         */
 820        error = nlm_async_call(block->b_call, NLMPROC_GRANTED_MSG,
 821                                &nlmsvc_grant_ops);
 822
 823        /* RPC submission failed, wait a bit and retry */
 824        if (error < 0)
 825                nlmsvc_insert_block(block, 10 * HZ);
 826}
 827
 828/*
 829 * This is the callback from the RPC layer when the NLM_GRANTED_MSG
 830 * RPC call has succeeded or timed out.
 831 * Like all RPC callbacks, it is invoked by the rpciod process, so it
 832 * better not sleep. Therefore, we put the blocked lock on the nlm_blocked
 833 * chain once more in order to have it removed by lockd itself (which can
 834 * then sleep on the file semaphore without disrupting e.g. the nfs client).
 835 */
 836static void nlmsvc_grant_callback(struct rpc_task *task, void *data)
 837{
 838        struct nlm_rqst         *call = data;
 839        struct nlm_block        *block = call->a_block;
 840        unsigned long           timeout;
 841
 842        dprintk("lockd: GRANT_MSG RPC callback\n");
 843
 844        spin_lock(&nlm_blocked_lock);
 845        /* if the block is not on a list at this point then it has
 846         * been invalidated. Don't try to requeue it.
 847         *
 848         * FIXME: it's possible that the block is removed from the list
 849         * after this check but before the nlmsvc_insert_block. In that
 850         * case it will be added back. Perhaps we need better locking
 851         * for nlm_blocked?
 852         */
 853        if (list_empty(&block->b_list))
 854                goto out;
 855
 856        /* Technically, we should down the file semaphore here. Since we
 857         * move the block towards the head of the queue only, no harm
 858         * can be done, though. */
 859        if (task->tk_status < 0) {
 860                /* RPC error: Re-insert for retransmission */
 861                timeout = 10 * HZ;
 862        } else {
 863                /* Call was successful, now wait for client callback */
 864                timeout = 60 * HZ;
 865        }
 866        nlmsvc_insert_block_locked(block, timeout);
 867        svc_wake_up(block->b_daemon);
 868out:
 869        spin_unlock(&nlm_blocked_lock);
 870}
 871
 872/*
 873 * FIXME: nlmsvc_release_block() grabs a mutex.  This is not allowed for an
 874 * .rpc_release rpc_call_op
 875 */
 876static void nlmsvc_grant_release(void *data)
 877{
 878        struct nlm_rqst         *call = data;
 879        nlmsvc_release_block(call->a_block);
 880}
 881
 882static const struct rpc_call_ops nlmsvc_grant_ops = {
 883        .rpc_call_done = nlmsvc_grant_callback,
 884        .rpc_release = nlmsvc_grant_release,
 885};
 886
 887/*
 888 * We received a GRANT_RES callback. Try to find the corresponding
 889 * block.
 890 */
 891void
 892nlmsvc_grant_reply(struct nlm_cookie *cookie, __be32 status)
 893{
 894        struct nlm_block        *block;
 895
 896        dprintk("grant_reply: looking for cookie %x, s=%d \n",
 897                *(unsigned int *)(cookie->data), status);
 898        if (!(block = nlmsvc_find_block(cookie)))
 899                return;
 900
 901        if (block) {
 902                if (status == nlm_lck_denied_grace_period) {
 903                        /* Try again in a couple of seconds */
 904                        nlmsvc_insert_block(block, 10 * HZ);
 905                } else {
 906                        /* Lock is now held by client, or has been rejected.
 907                         * In both cases, the block should be removed. */
 908                        nlmsvc_unlink_block(block);
 909                }
 910        }
 911        nlmsvc_release_block(block);
 912}
 913
 914/* Helper function to handle retry of a deferred block.
 915 * If it is a blocking lock, call grant_blocked.
 916 * For a non-blocking lock or test lock, revisit the request.
 917 */
 918static void
 919retry_deferred_block(struct nlm_block *block)
 920{
 921        if (!(block->b_flags & B_GOT_CALLBACK))
 922                block->b_flags |= B_TIMED_OUT;
 923        nlmsvc_insert_block(block, NLM_TIMEOUT);
 924        dprintk("revisit block %p flags %d\n",  block, block->b_flags);
 925        if (block->b_deferred_req) {
 926                block->b_deferred_req->revisit(block->b_deferred_req, 0);
 927                block->b_deferred_req = NULL;
 928        }
 929}
 930
 931/*
 932 * Retry all blocked locks that have been notified. This is where lockd
 933 * picks up locks that can be granted, or grant notifications that must
 934 * be retransmitted.
 935 */
 936unsigned long
 937nlmsvc_retry_blocked(void)
 938{
 939        unsigned long   timeout = MAX_SCHEDULE_TIMEOUT;
 940        struct nlm_block *block;
 941
 942        while (!list_empty(&nlm_blocked) && !kthread_should_stop()) {
 943                block = list_entry(nlm_blocked.next, struct nlm_block, b_list);
 944
 945                if (block->b_when == NLM_NEVER)
 946                        break;
 947                if (time_after(block->b_when, jiffies)) {
 948                        timeout = block->b_when - jiffies;
 949                        break;
 950                }
 951
 952                dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n",
 953                        block, block->b_when);
 954                if (block->b_flags & B_QUEUED) {
 955                        dprintk("nlmsvc_retry_blocked delete block (%p, granted=%d, flags=%d)\n",
 956                                block, block->b_granted, block->b_flags);
 957                        retry_deferred_block(block);
 958                } else
 959                        nlmsvc_grant_blocked(block);
 960        }
 961
 962        return timeout;
 963}
 964
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.