lockd: stop abusing file_lock_list
Christoph Hellwig [Mon, 20 Mar 2006 18:44:40 +0000 (13:44 -0500)]
Currently lockd directly access the file_lock_list from fs/locks.c.
It does so to mark locks granted or reclaimable.  This is very
suboptimal, because a) lockd needs to poke into locks.c internals, and
b) it needs to iterate over all locks in the system for marking locks
granted or reclaimable.

This patch adds lists for granted and reclaimable locks to the nlm_host
structure instead, and adds locks to those.

nlmclnt_lock:
now adds the lock to h_granted instead of setting the
NFS_LCK_GRANTED, still O(1)

nlmclnt_mark_reclaim:
goes away completely, replaced by a list_splice_init.
Complexity reduced from O(locks in the system) to O(1)

reclaimer:
iterates over h_reclaim now, complexity reduced from
O(locks in the system) to O(locks per nlm_host)

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

fs/lockd/clntlock.c
fs/lockd/clntproc.c
fs/lockd/host.c
fs/locks.c
include/linux/fs.h
include/linux/lockd/lockd.h
include/linux/nfs_fs_i.h

index 8ae79ae..0fc0ee2 100644 (file)
@@ -155,34 +155,6 @@ u32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *lock)
  */
 
 /*
- * Mark the locks for reclaiming.
- * FIXME: In 2.5 we don't want to iterate through any global file_lock_list.
- *        Maintain NLM lock reclaiming lists in the nlm_host instead.
- */
-static
-void nlmclnt_mark_reclaim(struct nlm_host *host)
-{
-       struct file_lock *fl;
-       struct inode *inode;
-       struct list_head *tmp;
-
-       list_for_each(tmp, &file_lock_list) {
-               fl = list_entry(tmp, struct file_lock, fl_link);
-
-               inode = fl->fl_file->f_dentry->d_inode;
-               if (inode->i_sb->s_magic != NFS_SUPER_MAGIC)
-                       continue;
-               if (fl->fl_u.nfs_fl.owner == NULL)
-                       continue;
-               if (fl->fl_u.nfs_fl.owner->host != host)
-                       continue;
-               if (!(fl->fl_u.nfs_fl.flags & NFS_LCK_GRANTED))
-                       continue;
-               fl->fl_u.nfs_fl.flags |= NFS_LCK_RECLAIM;
-       }
-}
-
-/*
  * Someone has sent us an SM_NOTIFY. Ensure we bind to the new port number,
  * that we mark locks for reclaiming, and that we bump the pseudo NSM state.
  */
@@ -194,7 +166,12 @@ void nlmclnt_prepare_reclaim(struct nlm_host *host, u32 newstate)
        host->h_state++;
        host->h_nextrebind = 0;
        nlm_rebind_host(host);
-       nlmclnt_mark_reclaim(host);
+
+       /*
+        * Mark the locks for reclaiming.
+        */
+       list_splice_init(&host->h_granted, &host->h_reclaim);
+
        dprintk("NLM: reclaiming locks for host %s", host->h_name);
 }
 
@@ -223,9 +200,7 @@ reclaimer(void *ptr)
 {
        struct nlm_host   *host = (struct nlm_host *) ptr;
        struct nlm_wait   *block;
-       struct list_head *tmp;
-       struct file_lock *fl;
-       struct inode *inode;
+       struct file_lock *fl, *next;
 
        daemonize("%s-reclaim", host->h_name);
        allow_signal(SIGKILL);
@@ -237,20 +212,9 @@ reclaimer(void *ptr)
 
        /* First, reclaim all locks that have been marked. */
 restart:
-       list_for_each(tmp, &file_lock_list) {
-               fl = list_entry(tmp, struct file_lock, fl_link);
-
-               inode = fl->fl_file->f_dentry->d_inode;
-               if (inode->i_sb->s_magic != NFS_SUPER_MAGIC)
-                       continue;
-               if (fl->fl_u.nfs_fl.owner == NULL)
-                       continue;
-               if (fl->fl_u.nfs_fl.owner->host != host)
-                       continue;
-               if (!(fl->fl_u.nfs_fl.flags & NFS_LCK_RECLAIM))
-                       continue;
+       list_for_each_entry_safe(fl, next, &host->h_reclaim, fl_u.nfs_fl.list) {
+               list_del(&fl->fl_u.nfs_fl.list);
 
-               fl->fl_u.nfs_fl.flags &= ~NFS_LCK_RECLAIM;
                nlmclnt_reclaim(host, fl);
                if (signalled())
                        break;
index 80ae312..cb46943 100644 (file)
@@ -465,7 +465,6 @@ static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *ho
 {
        BUG_ON(fl->fl_ops != NULL);
        fl->fl_u.nfs_fl.state = 0;
-       fl->fl_u.nfs_fl.flags = 0;
        fl->fl_u.nfs_fl.owner = nlm_find_lockowner(host, fl->fl_owner);
        fl->fl_ops = &nlmclnt_lock_ops;
 }
@@ -552,8 +551,8 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
 
        if (resp->status == NLM_LCK_GRANTED) {
                fl->fl_u.nfs_fl.state = host->h_state;
-               fl->fl_u.nfs_fl.flags |= NFS_LCK_GRANTED;
                fl->fl_flags |= FL_SLEEP;
+               list_add_tail(&fl->fl_u.nfs_fl.list, &host->h_granted);
                do_vfs_lock(fl);
        }
        status = nlm_stat_to_errno(resp->status);
@@ -619,9 +618,11 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
        struct nlm_res  *resp = &req->a_res;
        int             status;
 
-       /* Clean the GRANTED flag now so the lock doesn't get
-        * reclaimed while we're stuck in the unlock call. */
-       fl->fl_u.nfs_fl.flags &= ~NFS_LCK_GRANTED;
+       /*
+        * Remove from the granted list now so the lock doesn't get
+        * reclaimed while we're stuck in the unlock call.
+        */
+       list_del(&fl->fl_u.nfs_fl.list);
 
        /*
         * Note: the server is supposed to either grant us the unlock
index 100e782..f456f8e 100644 (file)
@@ -123,6 +123,8 @@ nlm_lookup_host(int server, struct sockaddr_in *sin,
        nlm_hosts[hash]    = host;
        INIT_LIST_HEAD(&host->h_lockowners);
        spin_lock_init(&host->h_lock);
+       INIT_LIST_HEAD(&host->h_granted);
+       INIT_LIST_HEAD(&host->h_reclaim);
 
        if (++nrhosts > NLM_HOST_MAX)
                next_gc = 0;
index c83b5db..56f996e 100644 (file)
@@ -139,10 +139,7 @@ int lease_break_time = 45;
 #define for_each_lock(inode, lockp) \
        for (lockp = &inode->i_flock; *lockp != NULL; lockp = &(*lockp)->fl_next)
 
-LIST_HEAD(file_lock_list);
-
-EXPORT_SYMBOL(file_lock_list);
-
+static LIST_HEAD(file_lock_list);
 static LIST_HEAD(blocked_list);
 
 static kmem_cache_t *filelock_cache;
index d2cffee..5dc0fa2 100644 (file)
@@ -730,8 +730,6 @@ struct file_lock {
 #define OFFT_OFFSET_MAX        INT_LIMIT(off_t)
 #endif
 
-extern struct list_head file_lock_list;
-
 #include <linux/fcntl.h>
 
 extern int fcntl_getlk(struct file *, struct flock __user *);
index 860a93f..b0f63b6 100644 (file)
@@ -59,6 +59,8 @@ struct nlm_host {
        unsigned long           h_expires;      /* eligible for GC */
        struct list_head        h_lockowners;   /* Lockowners for the client */
        spinlock_t              h_lock;
+       struct list_head        h_granted;      /* Locks in GRANTED state */
+       struct list_head        h_reclaim;      /* Locks in RECLAIM state */
 };
 
 /*
index e2c18da..8617302 100644 (file)
@@ -12,8 +12,8 @@ struct nlm_lockowner;
  */
 struct nfs_lock_info {
        u32             state;
-       u32             flags;
        struct nlm_lockowner *owner;
+       struct list_head list;
 };
 
 struct nfs4_lock_state;
@@ -21,10 +21,4 @@ struct nfs4_lock_info {
        struct nfs4_lock_state *owner;
 };
 
-/*
- * Lock flag values
- */
-#define NFS_LCK_GRANTED                0x0001          /* lock has been granted */
-#define NFS_LCK_RECLAIM                0x0002          /* lock marked for reclaiming */
-
 #endif