summaryrefslogtreecommitdiffstats
path: root/utils/mountd/auth.c
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2007-09-27 06:54:04 -0400
committerNeil Brown <neilb@suse.de>2007-09-28 11:39:57 +1000
commit7a042b78ba064a36d1c7de797d2af796212fca2e (patch)
treec4fb08ef0896a113aafa695dbe44eca14040ba43 /utils/mountd/auth.c
parent180238a295c1a8127953c96f0b462688d0f57a09 (diff)
downloadnfs-utils-7a042b78ba064a36d1c7de797d2af796212fca2e.tar.gz
nfs-utils-7a042b78ba064a36d1c7de797d2af796212fca2e.tar.xz
nfs-utils-7a042b78ba064a36d1c7de797d2af796212fca2e.zip
rpc.mountd: add new mode for handling netgroup-heavy configurations
If a host is a member of a large number of netgroups, it becomes easily possible for client_compose to generate a m_hostname string that overflows the maximum string length allowed by the kernel caches. This patch adds a new mode for mountd where it will map IP address to IP address in the auth.unix.ip cache. When this enabled, mountd doesn't bother using client_compose to build the m_hostname string. It just populates it with the dotted-quad ip address. When mountd handles a mount request, it then has an IP address and a path. It then calls client_check to check the host against export entries where the path has already matched. Since we don't bother looking up netgroups which have no relation to the mount, this can be a big performance gain in netgroup-heavy configurations. The downside is that every host has a corresponding entry in the nfsd.export and nfsd.fh caches as well as the auth.unix.ip cache. The new behavior is automatically enabled if the length of all of the concatenated netgroup names in the export table is longer than half NFSCLNT_IDMAX. The rationale for this logic is that this should allow for a host to be a member of a long list of netgroups while still allowing for other matches. Signed-off-by: Jeff Layton <jlayton@redhat.com> Acked-by: Steve Dickson <steved@redhat.com> Signed-off-by: Neil Brown <neilb@suse.de>
Diffstat (limited to 'utils/mountd/auth.c')
-rw-r--r--utils/mountd/auth.c61
1 files changed, 50 insertions, 11 deletions
diff --git a/utils/mountd/auth.c b/utils/mountd/auth.c
index 84fea30..a821c13 100644
--- a/utils/mountd/auth.c
+++ b/utils/mountd/auth.c
@@ -37,6 +37,7 @@ static nfs_export my_exp;
static nfs_client my_client;
extern int new_cache;
+extern int use_ipaddr;
void
auth_init(char *exports)
@@ -47,6 +48,34 @@ auth_init(char *exports)
xtab_mount_write();
}
+/*
+ * A client can match many different netgroups and it's tough to know
+ * beforehand whether it will. If the concatenated string of netgroup
+ * m_hostnames is >512 bytes, then enable the "use_ipaddr" mode. This
+ * makes mountd change how it matches a client ip address when a mount
+ * request comes in. It's more efficient at handling netgroups at the
+ * expense of larger kernel caches.
+ */
+static void
+check_useipaddr()
+{
+ nfs_client *clp;
+ int old_use_ipaddr = use_ipaddr;
+ unsigned int len = 0;
+
+ /* add length of m_hostname + 1 for the comma */
+ for (clp = clientlist[MCL_NETGROUP]; clp; clp = clp->m_next)
+ len += (strlen(clp->m_hostname) + 1);
+
+ if (len > (NFSCLNT_IDMAX / 2))
+ use_ipaddr = 1;
+ else
+ use_ipaddr = 0;
+
+ if (use_ipaddr != old_use_ipaddr)
+ cache_flush(1);
+}
+
unsigned int
auth_reload()
{
@@ -72,6 +101,7 @@ auth_reload()
export_freeall();
memset(&my_client, 0, sizeof(my_client));
xtab_export_read();
+ check_useipaddr();
++counter;
return counter;
@@ -88,28 +118,37 @@ auth_authenticate_internal(char *what, struct sockaddr_in *caller,
int i;
/* return static nfs_export with details filled in */
char *n;
- my_client.m_addrlist[0] = caller->sin_addr;
- n = client_compose(hp);
- *error = unknown_host;
- if (!n)
- return NULL;
free(my_client.m_hostname);
- if (*n) {
- my_client.m_hostname = n;
+ if (use_ipaddr) {
+ my_client.m_hostname =
+ strdup(inet_ntoa(caller->sin_addr));
} else {
- free(n);
- my_client.m_hostname = xstrdup("DEFAULT");
+ n = client_compose(hp);
+ *error = unknown_host;
+ if (!n)
+ my_client.m_hostname = NULL;
+ else if (*n)
+ my_client.m_hostname = n;
+ else {
+ free(n);
+ my_client.m_hostname = strdup("DEFAULT");
+ }
}
+ if (my_client.m_hostname == NULL)
+ return NULL;
my_client.m_naddr = 1;
+ my_client.m_addrlist[0] = caller->sin_addr;
my_exp.m_client = &my_client;
exp = NULL;
for (i = 0; !exp && i < MCL_MAXTYPES; i++)
for (exp = exportlist[i]; exp; exp = exp->m_next) {
- if (!client_member(my_client.m_hostname, exp->m_client->m_hostname))
- continue;
if (strcmp(path, exp->m_export.e_path))
continue;
+ if (!use_ipaddr && !client_member(my_client.m_hostname, exp->m_client->m_hostname))
+ continue;
+ if (use_ipaddr && !client_check(exp->m_client, hp))
+ continue;
break;
}
*error = not_exported;