static void nlmsvc_release_block(struct nlm_block *block);
 static void    nlmsvc_insert_block(struct nlm_block *block, unsigned long);
-static int     nlmsvc_remove_block(struct nlm_block *block);
+static void    nlmsvc_remove_block(struct nlm_block *block);
 
 static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock);
 static void nlmsvc_freegrantargs(struct nlm_rqst *call);
 /*
  * The list of blocked locks to retry
  */
-static struct nlm_block *      nlm_blocked;
+static LIST_HEAD(nlm_blocked);
 
 /*
  * Insert a blocked lock into the global list
 static void
 nlmsvc_insert_block(struct nlm_block *block, unsigned long when)
 {
-       struct nlm_block **bp, *b;
+       struct nlm_block *b;
+       struct list_head *pos;
 
        dprintk("lockd: nlmsvc_insert_block(%p, %ld)\n", block, when);
-       kref_get(&block->b_count);
-       if (block->b_queued)
-               nlmsvc_remove_block(block);
-       bp = &nlm_blocked;
+       if (list_empty(&block->b_list)) {
+               kref_get(&block->b_count);
+       } else {
+               list_del_init(&block->b_list);
+       }
+
+       pos = &nlm_blocked;
        if (when != NLM_NEVER) {
                if ((when += jiffies) == NLM_NEVER)
                        when ++;
-               while ((b = *bp) && time_before_eq(b->b_when,when) && b->b_when != NLM_NEVER)
-                       bp = &b->b_next;
-       } else
-               while ((b = *bp) != 0)
-                       bp = &b->b_next;
+               list_for_each(pos, &nlm_blocked) {
+                       b = list_entry(pos, struct nlm_block, b_list);
+                       if (time_after(b->b_when,when) || b->b_when == NLM_NEVER)
+                               break;
+               }
+               /* On normal exit from the loop, pos == &nlm_blocked,
+                * so we will be adding to the end of the list - good
+                */
+       }
 
-       block->b_queued = 1;
+       list_add_tail(&block->b_list, pos);
        block->b_when = when;
-       block->b_next = b;
-       *bp = block;
 }
 
 /*
  * Remove a block from the global list
  */
-static int
+static inline void
 nlmsvc_remove_block(struct nlm_block *block)
 {
-       struct nlm_block **bp, *b;
-
-       if (!block->b_queued)
-               return 1;
-       for (bp = &nlm_blocked; (b = *bp) != 0; bp = &b->b_next) {
-               if (b == block) {
-                       *bp = block->b_next;
-                       block->b_queued = 0;
-                       nlmsvc_release_block(block);
-                       return 1;
-               }
+       if (!list_empty(&block->b_list)) {
+               list_del_init(&block->b_list);
+               nlmsvc_release_block(block);
        }
-
-       return 0;
 }
 
 /*
 static struct nlm_block *
 nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock)
 {
-       struct nlm_block        **head, *block;
+       struct nlm_block        *block;
        struct file_lock        *fl;
 
        dprintk("lockd: nlmsvc_lookup_block f=%p pd=%d %Ld-%Ld ty=%d\n",
                                file, lock->fl.fl_pid,
                                (long long)lock->fl.fl_start,
                                (long long)lock->fl.fl_end, lock->fl.fl_type);
-       for (head = &nlm_blocked; (block = *head) != 0; head = &block->b_next) {
+       list_for_each_entry(block, &nlm_blocked, b_list) {
                fl = &block->b_call->a_args.lock.fl;
                dprintk("lockd: check f=%p pd=%d %Ld-%Ld ty=%d cookie=%s\n",
                                block->b_file, fl->fl_pid,
 {
        struct nlm_block *block;
 
-       for (block = nlm_blocked; block; block = block->b_next) {
-               dprintk("cookie: head of blocked queue %p, block %p\n", 
-                       nlm_blocked, block);
+       list_for_each_entry(block, &nlm_blocked, b_list) {
                if (nlm_cookie_match(&block->b_call->a_args.cookie,cookie)
                                && nlm_cmp_addr(sin, &block->b_host->h_addr))
-                       break;
+                       goto found;
        }
 
-       if (block != NULL)
-               kref_get(&block->b_count);
+       return NULL;
+
+found:
+       kref_get(&block->b_count);
        return block;
 }
 
        if (block == NULL)
                goto failed;
        kref_init(&block->b_count);
+       INIT_LIST_HEAD(&block->b_list);
+       INIT_LIST_HEAD(&block->b_flist);
 
        if (!nlmsvc_setgrantargs(call, lock))
                goto failed_free;
        file->f_count++;
 
        /* Add to file's list of blocks */
-       block->b_fnext  = file->f_blocks;
-       file->f_blocks  = block;
+       list_add(&block->b_flist, &file->f_blocks);
 
        /* Set up RPC arguments for callback */
        block->b_call = call;
 {
        struct nlm_block *block = container_of(kref, struct nlm_block, b_count);
        struct nlm_file         *file = block->b_file;
-       struct nlm_block        **bp;
 
        dprintk("lockd: freeing block %p...\n", block);
 
-       down(&file->f_sema);
        /* Remove block from file's list of blocks */
-       for (bp = &file->f_blocks; *bp; bp = &(*bp)->b_fnext) {
-               if (*bp == block) {
-                       *bp = block->b_fnext;
-                       break;
-               }
-       }
+       down(&file->f_sema);
+       list_del_init(&block->b_flist);
        up(&file->f_sema);
 
        nlmsvc_freegrantargs(block->b_call);
        struct nlm_block *block;
 
        down(&file->f_sema);
-       for (block = file->f_blocks; block != NULL; block = block->b_fnext)
+       list_for_each_entry(block, &file->f_blocks, b_flist)
                block->b_host->h_inuse = 1;
        up(&file->f_sema);
 }
 
 static void nlmsvc_act_unlock(struct nlm_host *host, struct nlm_file *file)
 {
-       struct nlm_block *block;
+       struct nlm_block *block, *next;
 
 restart:
        down(&file->f_sema);
-       for (block = file->f_blocks; block != NULL; block = block->b_fnext) {
+       list_for_each_entry_safe(block, next, &file->f_blocks, b_flist) {
                if (host != NULL && host != block->b_host)
                        continue;
-               if (!block->b_queued)
+               /* Do not destroy blocks that are not on
+                * the global retry list - why? */
+               if (list_empty(&block->b_list))
                        continue;
                kref_get(&block->b_count);
                up(&file->f_sema);
 static void
 nlmsvc_notify_blocked(struct file_lock *fl)
 {
-       struct nlm_block        **bp, *block;
+       struct nlm_block        *block;
 
        dprintk("lockd: VFS unblock notification for block %p\n", fl);
-       for (bp = &nlm_blocked; (block = *bp) != 0; bp = &block->b_next) {
+       list_for_each_entry(block, &nlm_blocked, b_list) {
                if (nlm_compare_locks(&block->b_call->a_args.lock.fl, fl)) {
                        nlmsvc_insert_block(block, 0);
                        svc_wake_up(block->b_daemon);
 unsigned long
 nlmsvc_retry_blocked(void)
 {
-       struct nlm_block        *block;
+       unsigned long   timeout = MAX_SCHEDULE_TIMEOUT;
+       struct nlm_block *block;
+
+       while (!list_empty(&nlm_blocked)) {
+               block = list_entry(nlm_blocked.next, struct nlm_block, b_list);
 
-       dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n",
-                       nlm_blocked,
-                       nlm_blocked? nlm_blocked->b_when : 0);
-       while ((block = nlm_blocked) != 0) {
                if (block->b_when == NLM_NEVER)
                        break;
-               if (time_after(block->b_when,jiffies))
+               if (time_after(block->b_when,jiffies)) {
+                       timeout = block->b_when - jiffies;
                        break;
+               }
+
                dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n",
                        block, block->b_when);
                kref_get(&block->b_count);
                nlmsvc_release_block(block);
        }
 
-       if ((block = nlm_blocked) && block->b_when != NLM_NEVER)
-               return (block->b_when - jiffies);
-
-       return MAX_SCHEDULE_TIMEOUT;
+       return timeout;
 }