From: Olaf Kirch <okir@suse.de>
To: nfs@lists.sourceforge.net
Subject: [PATCH 12/22] lockd: make nlm_traverse_* more flexible
Date: Sat, 5 Aug 2006 15:06:48 +0200 [thread overview]
Message-ID: <20060805130648.GA8075@suse.de> (raw)
From: Olaf Kirch <okir@suse.de>
Subject: lockd: make nlm_traverse_* more flexible
This patch makes nlm_traverse{locks,blocks,shares} and friends
use a function pointer rather than a "action" enum.
This function pointer is given two nlm_hosts (one given by the
caller, the other taken from the lock/block/share currently
visited), and is free to do with them as it wants. If it returns a
non-zero value, the lockd/block/share is released.
Signed-off-by: Olaf Kirch <okir@suse.de>
fs/lockd/svclock.c | 29 ++++--------
fs/lockd/svcshare.c | 20 +++-----
fs/lockd/svcsubs.c | 104 ++++++++++++++++++++++++++++++++------------
include/linux/lockd/lockd.h | 15 ++----
include/linux/lockd/share.h | 3 -
5 files changed, 104 insertions(+), 67 deletions(-)
Index: build/include/linux/lockd/share.h
===================================================================
--- build.orig/include/linux/lockd/share.h
+++ build/include/linux/lockd/share.h
@@ -25,6 +25,7 @@ u32 nlmsvc_share_file(struct nlm_host *,
struct nlm_args *);
u32 nlmsvc_unshare_file(struct nlm_host *, struct nlm_file *,
struct nlm_args *);
-void nlmsvc_traverse_shares(struct nlm_host *, struct nlm_file *, int);
+void nlmsvc_traverse_shares(struct nlm_host *, struct nlm_file *,
+ nlm_host_match_fn_t);
#endif /* LINUX_LOCKD_SHARE_H */
Index: build/fs/lockd/svclock.c
===================================================================
--- build.orig/fs/lockd/svclock.c
+++ build/fs/lockd/svclock.c
@@ -262,24 +262,30 @@ static void nlmsvc_release_block(struct
kref_put(&block->b_count, nlmsvc_free_block);
}
-static void nlmsvc_act_mark(struct nlm_host *host, struct nlm_file *file)
+void nlmsvc_mark_blocks(struct nlm_file *file)
{
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)
+/*
+ * Loop over all blocks and delete blocks held by
+ * a matching host.
+ */
+void nlmsvc_traverse_blocks(struct nlm_host *host,
+ struct nlm_file *file,
+ nlm_host_match_fn_t match)
{
- struct nlm_block *block;
+ struct nlm_block *block, *next;
restart:
down(&file->f_sema);
list_for_each_entry_safe(block, next, &file->f_blocks, b_flist) {
- if (host != NULL && host != block->b_host)
+ if (!match(block->b_host, host))
continue;
/* Do not destroy blocks that are not on
* the global retry list - why? */
@@ -295,19 +301,6 @@ restart:
}
/*
- * Loop over all blocks and perform the action specified.
- * (NLM_ACT_CHECK handled by nlmsvc_inspect_file).
- */
-void
-nlmsvc_traverse_blocks(struct nlm_host *host, struct nlm_file *file, int action)
-{
- if (action == NLM_ACT_MARK)
- nlmsvc_act_mark(host, file);
- else
- nlmsvc_act_unlock(host, file);
-}
-
-/*
* Initialize arguments for GRANTED call. The nlm_rqst structure
* has been cleared already.
*/
Index: build/fs/lockd/svcsubs.c
===================================================================
--- build.orig/fs/lockd/svcsubs.c
+++ build/fs/lockd/svcsubs.c
@@ -165,7 +165,8 @@ nlm_delete_file(struct nlm_file *file)
* action.
*/
static int
-nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file, int action)
+nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file,
+ nlm_host_match_fn_t match)
{
struct inode *inode = nlmsvc_file_inode(file);
struct file_lock *fl;
@@ -179,17 +180,11 @@ again:
/* update current lock count */
file->f_locks++;
+
lockhost = (struct nlm_host *) fl->fl_owner;
- if (action == NLM_ACT_MARK)
- lockhost->h_inuse = 1;
- else if (action == NLM_ACT_CHECK)
- return 1;
- else if (action == NLM_ACT_UNLOCK) {
+ if (match(lockhost, host)) {
struct file_lock lock = *fl;
- if (host && lockhost != host)
- continue;
-
lock.fl_type = F_UNLCK;
lock.fl_start = 0;
lock.fl_end = OFFSET_MAX;
@@ -206,27 +201,42 @@ again:
}
/*
- * Operate on a single file
+ * Inspect a single file
+ */
+static inline int
+nlm_inspect_file(struct nlm_host *host, struct nlm_file *file, nlm_host_match_fn_t match)
+{
+ nlmsvc_traverse_blocks(host, file, match);
+ nlmsvc_traverse_shares(host, file, match);
+ return nlm_traverse_locks(host, file, match);
+}
+
+/*
+ * Quick check whether there are still any locks, blocks or
+ * shares on a given file.
*/
static inline int
-nlm_inspect_file(struct nlm_host *host, struct nlm_file *file, int action)
+nlm_file_inuse(struct nlm_file *file)
{
- if (action == NLM_ACT_CHECK) {
- /* Fast path for mark and sweep garbage collection */
- if (file->f_count || list_empty(&file->f_blocks) || file->f_shares)
+ struct inode *inode = nlmsvc_file_inode(file);
+ struct file_lock *fl;
+
+ if (file->f_count || !list_empty(&file->f_blocks) || file->f_shares)
+ return 1;
+
+ for (fl = inode->i_flock; fl; fl = fl->fl_next) {
+ if (fl->fl_lmops == &nlmsvc_lock_operations)
return 1;
- } else {
- nlmsvc_traverse_blocks(host, file, action);
- nlmsvc_traverse_shares(host, file, action);
}
- return nlm_traverse_locks(host, file, action);
+ file->f_locks = 0;
+ return 0;
}
/*
* Loop over all files in the file table.
*/
static int
-nlm_traverse_files(struct nlm_host *host, int action)
+nlm_traverse_files(struct nlm_host *host, nlm_host_match_fn_t match)
{
struct hlist_node *pos, *next;
struct nlm_file *file;
@@ -237,7 +247,7 @@ nlm_traverse_files(struct nlm_host *host
hlist_for_each_entry_safe(file, pos, next, &nlm_files[i], f_list) {
/* Traverse locks, blocks and shares of this file
* and update file->f_locks count */
- if (nlm_inspect_file(host, file, action)) {
+ if (nlm_inspect_file(host, file, match)) {
mutex_unlock(&nlm_file_mutex);
return 1;
}
@@ -274,23 +284,54 @@ nlm_release_file(struct nlm_file *file)
mutex_lock(&nlm_file_mutex);
/* If there are no more locks etc, delete the file */
- if(--file->f_count == 0) {
- if(!nlm_inspect_file(NULL, file, NLM_ACT_CHECK))
- nlm_delete_file(file);
- }
+ if (--file->f_count == 0 && !nlm_file_inuse(file))
+ nlm_delete_file(file);
mutex_unlock(&nlm_file_mutex);
}
/*
+ * Helpers function for resource traversal
+ *
+ * nlmsvc_mark_host:
+ * used by the garbage collector; simply sets h_inuse.
+ * Always returns 0.
+ *
+ * nlmsvc_same_host:
+ * returns 1 iff the two hosts match. Used to release
+ * all resources bound to a specific host.
+ *
+ * nlmsvc_is_client:
+ * returns 1 iff the host is a client.
+ * Used by nlmsvc_invalidate_all
+ */
+static int
+nlmsvc_mark_host(struct nlm_host *host, struct nlm_host *dummy)
+{
+ host->h_inuse = 1;
+ return 0;
+}
+
+static int
+nlmsvc_same_host(struct nlm_host *host, struct nlm_host *other)
+{
+ return host == other;
+}
+
+static int
+nlmsvc_is_client(struct nlm_host *host, struct nlm_host *dummy)
+{
+ return host->h_server;
+}
+
+/*
* Mark all hosts that still hold resources
*/
void
nlmsvc_mark_resources(void)
{
dprintk("lockd: nlmsvc_mark_resources\n");
-
- nlm_traverse_files(NULL, NLM_ACT_MARK);
+ nlm_traverse_files(NULL, nlmsvc_mark_host);
}
/*
@@ -301,7 +342,7 @@ nlmsvc_free_host_resources(struct nlm_ho
{
dprintk("lockd: nlmsvc_free_host_resources\n");
- if (nlm_traverse_files(host, NLM_ACT_UNLOCK)) {
+ if (nlm_traverse_files(host, nlmsvc_same_host)) {
printk(KERN_WARNING
"lockd: couldn't remove all locks held by %s\n",
host->h_name);
@@ -316,8 +357,15 @@ void
nlmsvc_invalidate_all(void)
{
struct nlm_host *host;
+
+ /* Release all locks held by a NFS clients.
+ * Previously, the code would call
+ * nlmsvc_free_host_resources for each client in
+ * turn, which is about as inefficient as it gets.
+ */
+ nlm_traverse_files(NULL, nlmsvc_is_client);
+
while ((host = nlm_find_client()) != NULL) {
- nlmsvc_free_host_resources(host);
host->h_expires = 0;
host->h_killed = 1;
nlm_release_host(host);
Index: build/include/linux/lockd/lockd.h
===================================================================
--- build.orig/include/linux/lockd/lockd.h
+++ build/include/linux/lockd/lockd.h
@@ -135,13 +135,6 @@ struct nlm_block {
};
/*
- * Valid actions for nlmsvc_traverse_files
- */
-#define NLM_ACT_CHECK 0 /* check for locks */
-#define NLM_ACT_MARK 1 /* mark & sweep */
-#define NLM_ACT_UNLOCK 2 /* release all locks */
-
-/*
* Global variables
*/
extern struct rpc_program nlm_program;
@@ -185,6 +178,12 @@ void nsm_release(struct nsm_handle *)
/*
+ * This is used in garbage collection and resource reclain
+ * A return value != 0 means destroy the lock/block/share
+ */
+typedef int (*nlm_host_match_fn_t)(struct nlm_host *cur, struct nlm_host *ref);
+
+/*
* Server-side lock handling
*/
u32 nlmsvc_lock(struct svc_rqst *, struct nlm_file *,
@@ -195,7 +194,7 @@ u32 nlmsvc_testlock(struct nlm_file *
u32 nlmsvc_cancel_blocked(struct nlm_file *, struct nlm_lock *);
unsigned long nlmsvc_retry_blocked(void);
void nlmsvc_traverse_blocks(struct nlm_host *, struct nlm_file *,
- int action);
+ nlm_host_match_fn_t match);
void nlmsvc_grant_reply(struct svc_rqst *, struct nlm_cookie *, u32);
/*
Index: build/fs/lockd/svcshare.c
===================================================================
--- build.orig/fs/lockd/svcshare.c
+++ build/fs/lockd/svcshare.c
@@ -85,24 +85,20 @@ nlmsvc_unshare_file(struct nlm_host *hos
}
/*
- * Traverse all shares for a given file (and host).
- * NLM_ACT_CHECK is handled by nlmsvc_inspect_file.
+ * Traverse all shares for a given file, and delete
+ * those owned by the given (type of) host
*/
-void
-nlmsvc_traverse_shares(struct nlm_host *host, struct nlm_file *file, int action)
+void nlmsvc_traverse_shares(struct nlm_host *host, struct nlm_file *file,
+ nlm_host_match_fn_t match)
{
struct nlm_share *share, **shpp;
shpp = &file->f_shares;
while ((share = *shpp) != NULL) {
- if (action == NLM_ACT_MARK)
- share->s_host->h_inuse = 1;
- else if (action == NLM_ACT_UNLOCK) {
- if (host == NULL || host == share->s_host) {
- *shpp = share->s_next;
- kfree(share);
- continue;
- }
+ if (match(share->s_host, host)) {
+ *shpp = share->s_next;
+ kfree(share);
+ continue;
}
shpp = &share->s_next;
}
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
NFS maillist - NFS@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/nfs
reply other threads:[~2006-08-05 13:06 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20060805130648.GA8075@suse.de \
--to=okir@suse.de \
--cc=nfs@lists.sourceforge.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.