summaryrefslogtreecommitdiffstats
path: root/utils/gssd
diff options
context:
space:
mode:
authorneilbrown <neilbrown>2006-03-28 00:50:44 +0000
committerneilbrown <neilbrown>2006-03-28 00:50:44 +0000
commit05424b57b5ccfefcfee415f97d5c4063d2ab314e (patch)
tree3a55a8e83e14f33c1eaba3a8cf6cc26a9f1f6293 /utils/gssd
parenta6037e23a8c9d649bf5946ac9d23114f9097b997 (diff)
downloadnfs-utils-05424b57b5ccfefcfee415f97d5c4063d2ab314e.tar.gz
nfs-utils-05424b57b5ccfefcfee415f97d5c4063d2ab314e.tar.xz
nfs-utils-05424b57b5ccfefcfee415f97d5c4063d2ab314e.zip
Don't close and reopen all pipes on every DNOTIFY signal.
From: Vince Busam <vbusam@google.com> Signed-off-by: Kevin Coffman <kwc@citi.umich.edu> Don't unnecessarily close and re-open all pipes after every DNOTIFY signal. These unnecessary closes were triggering a kernel Oops. Original patch modified to correct segfault when unmounting last NFSv4 mount.
Diffstat (limited to 'utils/gssd')
-rw-r--r--utils/gssd/gssd_proc.c123
1 files changed, 87 insertions, 36 deletions
diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c
index 4c3d85d..8b456b0 100644
--- a/utils/gssd/gssd_proc.c
+++ b/utils/gssd/gssd_proc.c
@@ -178,6 +178,12 @@ fail:
static void
destroy_client(struct clnt_info *clp)
{
+ if (clp->krb5_poll_index != -1)
+ memset(&pollarray[clp->krb5_poll_index], 0,
+ sizeof(struct pollfd));
+ if (clp->spkm3_poll_index != -1)
+ memset(&pollarray[clp->spkm3_poll_index], 0,
+ sizeof(struct pollfd));
if (clp->dir_fd != -1) close(clp->dir_fd);
if (clp->krb5_fd != -1) close(clp->krb5_fd);
if (clp->spkm3_fd != -1) close(clp->spkm3_fd);
@@ -216,15 +222,20 @@ process_clnt_dir_files(struct clnt_info * clp)
char sname[32];
char info_file_name[32];
- snprintf(kname, sizeof(kname), "%s/krb5", clp->dirname);
- clp->krb5_fd = open(kname, O_RDWR);
- snprintf(sname, sizeof(sname), "%s/spkm3", clp->dirname);
- clp->spkm3_fd = open(sname, O_RDWR);
+ if (clp->krb5_fd == -1) {
+ snprintf(kname, sizeof(kname), "%s/krb5", clp->dirname);
+ clp->krb5_fd = open(kname, O_RDWR);
+ }
+ if (clp->spkm3_fd == -1) {
+ snprintf(sname, sizeof(sname), "%s/spkm3", clp->dirname);
+ clp->spkm3_fd = open(sname, O_RDWR);
+ }
if((clp->krb5_fd == -1) && (clp->spkm3_fd == -1))
return -1;
snprintf(info_file_name, sizeof(info_file_name), "%s/info",
clp->dirname);
- if (read_service_info(info_file_name, &clp->servicename,
+ if ((clp->servicename == NULL) &&
+ read_service_info(info_file_name, &clp->servicename,
&clp->servername, &clp->prog, &clp->vers,
&clp->protocol))
return -1;
@@ -250,6 +261,31 @@ get_poll_index(int *ind)
return 0;
}
+
+static int
+insert_clnt_poll(struct clnt_info *clp)
+{
+ if ((clp->krb5_fd != -1) && (clp->krb5_poll_index == -1)) {
+ if (get_poll_index(&clp->krb5_poll_index)) {
+ printerr(0, "ERROR: Too many krb5 clients\n");
+ return -1;
+ }
+ pollarray[clp->krb5_poll_index].fd = clp->krb5_fd;
+ pollarray[clp->krb5_poll_index].events |= POLLIN;
+ }
+
+ if ((clp->spkm3_fd != -1) && (clp->spkm3_poll_index == -1)) {
+ if (get_poll_index(&clp->spkm3_poll_index)) {
+ printerr(0, "ERROR: Too many spkm3 clients\n");
+ return -1;
+ }
+ pollarray[clp->spkm3_poll_index].fd = clp->spkm3_fd;
+ pollarray[clp->spkm3_poll_index].events |= POLLIN;
+ }
+
+ return 0;
+}
+
static void
process_clnt_dir(char *dir)
{
@@ -273,23 +309,8 @@ process_clnt_dir(char *dir)
if (process_clnt_dir_files(clp))
goto fail_keep_client;
- if(clp->krb5_fd != -1) {
- if (get_poll_index(&clp->krb5_poll_index)) {
- printerr(0, "ERROR: Too many krb5 clients\n");
- goto fail_destroy_client;
- }
- pollarray[clp->krb5_poll_index].fd = clp->krb5_fd;
- pollarray[clp->krb5_poll_index].events |= POLLIN;
- }
-
- if(clp->spkm3_fd != -1) {
- if (get_poll_index(&clp->spkm3_poll_index)) {
- printerr(0, "ERROR: Too many spkm3 clients\n");
- goto fail_destroy_client;
- }
- pollarray[clp->spkm3_poll_index].fd = clp->spkm3_fd;
- pollarray[clp->spkm3_poll_index].events |= POLLIN;
- }
+ if (insert_clnt_poll(clp))
+ goto fail_destroy_client;
return;
@@ -314,18 +335,50 @@ init_client_list(void)
pollarray = calloc(pollsize, sizeof(struct pollfd));
}
+/*
+ * This is run after a DNOTIFY signal, and should clear up any
+ * directories that are no longer around, and re-scan any existing
+ * directories, since the DNOTIFY could have been in there.
+ */
static void
-destroy_client_list(void)
+update_old_clients(struct dirent **namelist, int size)
{
- struct clnt_info *clp;
+ struct clnt_info *clp;
+ void *saveprev;
+ int i, stillhere;
+
+ for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
+ stillhere = 0;
+ for (i=0; i < size; i++) {
+ if (!strcmp(clp->dirname, namelist[i]->d_name)) {
+ stillhere = 1;
+ break;
+ }
+ }
+ if (!stillhere) {
+ printerr(2, "destroying client %s\n", clp->dirname);
+ saveprev = clp->list.tqe_prev;
+ TAILQ_REMOVE(&clnt_list, clp, list);
+ destroy_client(clp);
+ clp = saveprev;
+ }
+ }
+ for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
+ if (!process_clnt_dir_files(clp))
+ insert_clnt_poll(clp);
+ }
+}
- printerr(1, "processing client list\n");
+/* Search for a client by directory name, return 1 if found, 0 otherwise */
+static int
+find_client(char *dirname)
+{
+ struct clnt_info *clp;
- while (clnt_list.tqh_first != NULL) {
- clp = clnt_list.tqh_first;
- TAILQ_REMOVE(&clnt_list, clp, list);
- destroy_client(clp);
- }
+ for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next)
+ if (!strcmp(clp->dirname, dirname))
+ return 1;
+ return 0;
}
/* Used to read (and re-read) list of clients, set up poll array. */
@@ -333,9 +386,7 @@ int
update_client_list(void)
{
struct dirent **namelist;
- int i,j;
-
- destroy_client_list();
+ int i, j;
if (chdir(pipefsdir) < 0) {
printerr(0, "ERROR: can't chdir to %s: %s\n",
@@ -343,17 +394,17 @@ update_client_list(void)
return -1;
}
- memset(pollarray, 0, pollsize * sizeof(struct pollfd));
-
j = scandir(pipefsdir, &namelist, NULL, alphasort);
if (j < 0) {
printerr(0, "ERROR: can't scandir %s: %s\n",
pipefsdir, strerror(errno));
return -1;
}
+ update_old_clients(namelist, j);
for (i=0; i < j; i++) {
if (i < FD_ALLOC_BLOCK
- && !strncmp(namelist[i]->d_name, "clnt", 4))
+ && !strncmp(namelist[i]->d_name, "clnt", 4)
+ && !find_client(namelist[i]->d_name))
process_clnt_dir(namelist[i]->d_name);
free(namelist[i]);
}