One last clean up: refactor the nsm_get_handle() function so it uses
the same lookup helpers as the newly added nsm_reboot_lookup()
function.
This also makes it easier if some day we want to use a more
sophisticated lookup algorithm than a linked list search for finding
nsm_handles. It's likely that we would use a different data structure
for each of the different lookups (hostname, priv, or IP address) and
now these are already split into different functions.
There is an additional micro-optimization here. This change moves the
"hostname & nsm_use_hostnames" test out of the list_for_each_entry()
clause in nsm_get_handle(), since it is loop-invariant.
Signed-off-by: Chuck Lever <[email protected]>
---
fs/lockd/mon.c | 97 +++++++++++++++++++++++++++++++++-----------------------
1 files changed, 58 insertions(+), 39 deletions(-)
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c
index d564b6f..3180efc 100644
--- a/fs/lockd/mon.c
+++ b/fs/lockd/mon.c
@@ -122,6 +122,16 @@ static struct nsm_handle *nsm_lookup_hostname(const char *hostname,
return NULL;
}
+static struct nsm_handle *nsm_lookup_addr(const struct sockaddr *sap)
+{
+ struct nsm_handle *nsm;
+
+ list_for_each_entry(nsm, &nsm_handles, sm_link)
+ if (nlm_cmp_addr(nsm_addr(nsm), sap))
+ return nsm;
+ return NULL;
+}
+
/*
* Construct a unique cookie to identify this nsm_handle. It is
* passed to our statd via SM_MON, and returned via NLM_SM_NOTIFY,
@@ -148,6 +158,30 @@ static void nsm_init_private(struct nsm_handle *nsm)
*p = (unsigned long)nsm;
}
+static struct nsm_handle *nsm_init_handle(const struct sockaddr *sap,
+ const size_t salen,
+ const char *hostname,
+ const size_t hostname_len)
+{
+ struct nsm_handle *nsm;
+
+ nsm = kzalloc(sizeof(*nsm) + hostname_len + 1, GFP_KERNEL);
+ if (nsm) {
+ memcpy(nsm_addr(nsm), sap, salen);
+ nsm->sm_addrlen = salen;
+ nsm->sm_name = (char *) (nsm + 1);
+ memcpy(nsm->sm_name, hostname, hostname_len);
+ nsm->sm_name[hostname_len] = '\0';
+ nsm_init_private(nsm);
+ nlm_display_address((struct sockaddr *)&nsm->sm_addr,
+ nsm->sm_addrbuf,
+ sizeof(nsm->sm_addrbuf));
+ atomic_set(&nsm->sm_count, 1);
+ }
+
+ return nsm;
+}
+
/**
* nsm_get_handle - Find a cached nsm_handle by name or address
* @sap: pointer to socket address of handle to find
@@ -160,8 +194,7 @@ struct nsm_handle *nsm_get_handle(const struct sockaddr *sap,
const size_t salen, const char *hostname,
const size_t hostname_len)
{
- struct nsm_handle *nsm = NULL;
- struct nsm_handle *pos;
+ struct nsm_handle *new, *cached;
if (!sap)
return NULL;
@@ -175,45 +208,31 @@ struct nsm_handle *nsm_get_handle(const struct sockaddr *sap,
return NULL;
}
-retry:
- spin_lock(&nsm_lock);
- list_for_each_entry(pos, &nsm_handles, sm_link) {
- if (hostname && nsm_use_hostnames) {
- if (strlen(pos->sm_name) != hostname_len
- || memcmp(pos->sm_name, hostname, hostname_len))
- continue;
- } else if (!nlm_cmp_addr(nsm_addr(pos), sap))
- continue;
-
- atomic_inc(&pos->sm_count);
- kfree(nsm);
- nsm = pos;
- goto found;
- }
- if (nsm) {
- list_add(&nsm->sm_link, &nsm_handles);
- goto found;
- }
- spin_unlock(&nsm_lock);
+ new = NULL;
+ do {
+ spin_lock(&nsm_lock);
- nsm = kzalloc(sizeof(*nsm) + hostname_len + 1, GFP_KERNEL);
- if (nsm == NULL)
- return NULL;
+ if (nsm_use_hostnames && hostname)
+ cached = nsm_lookup_hostname(hostname, hostname_len);
+ else
+ cached = nsm_lookup_addr(sap);
+ if (cached) {
+ atomic_inc(&cached->sm_count);
+ spin_unlock(&nsm_lock);
+ kfree(new);
+ return cached;
+ } else if (new) {
+ list_add(&new->sm_link, &nsm_handles);
+ spin_unlock(&nsm_lock);
+ return new;
+ }
- memcpy(nsm_addr(nsm), sap, salen);
- nsm->sm_addrlen = salen;
- nsm->sm_name = (char *) (nsm + 1);
- memcpy(nsm->sm_name, hostname, hostname_len);
- nsm->sm_name[hostname_len] = '\0';
- nsm_init_private(nsm);
- nlm_display_address((struct sockaddr *)&nsm->sm_addr,
- nsm->sm_addrbuf, sizeof(nsm->sm_addrbuf));
- atomic_set(&nsm->sm_count, 1);
- goto retry;
-
-found:
- spin_unlock(&nsm_lock);
- return nsm;
+ spin_unlock(&nsm_lock);
+
+ new = nsm_init_handle(sap, salen, hostname, hostname_len);
+ } while (new);
+
+ return NULL;
}
/**