summaryrefslogtreecommitdiffstats
path: root/utils/gssd/gssd.c
diff options
context:
space:
mode:
authorDavid Hardeman <david@hardeman.nu>2015-01-21 17:13:52 -0500
committerSteve Dickson <steved@redhat.com>2015-01-23 14:19:09 -0500
commitda7a3a2f06d77224de821d1fe44c813eacb30ab8 (patch)
treefd902d23b2e55083bd99220cef2aa8aa1a622792 /utils/gssd/gssd.c
parente01a0c33d463fe8f0f465879e0b0e3f0b9519bc7 (diff)
downloadnfs-utils-da7a3a2f06d77224de821d1fe44c813eacb30ab8.tar.gz
nfs-utils-da7a3a2f06d77224de821d1fe44c813eacb30ab8.tar.xz
nfs-utils-da7a3a2f06d77224de821d1fe44c813eacb30ab8.zip
gssd - improve inotify
Make full use of inotify by not rescanning the whole tree on each change, instead keep track of the inotify events and make sure that the minimum work (scan/create/delete) clients is done in most cases. Still detect anomalies and perform a full rescan in those cases. Signed-off-by: David Hardeman <david@hardeman.nu> Signed-off-by: Steve Dickson <steved@redhat.com>
Diffstat (limited to 'utils/gssd/gssd.c')
-rw-r--r--utils/gssd/gssd.c167
1 files changed, 115 insertions, 52 deletions
diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c
index b7a4950..2a768ea 100644
--- a/utils/gssd/gssd.c
+++ b/utils/gssd/gssd.c
@@ -362,36 +362,18 @@ gssd_destroy_client(struct clnt_info *clp)
static void gssd_scan(void);
static void
-gssd_clnt_gssd_cb(int UNUSED(fd), short which, void *data)
+gssd_clnt_gssd_cb(int UNUSED(fd), short UNUSED(which), void *data)
{
struct clnt_info *clp = data;
- if (which != EV_READ) {
- printerr(2, "Closing 'gssd' pipe %s\n", clp->relpath);
- close(clp->gssd_fd);
- clp->gssd_fd = -1;
- event_del(&clp->gssd_ev);
- gssd_scan();
- return;
- }
-
handle_gssd_upcall(clp);
}
static void
-gssd_clnt_krb5_cb(int UNUSED(fd), short which, void *data)
+gssd_clnt_krb5_cb(int UNUSED(fd), short UNUSED(which), void *data)
{
struct clnt_info *clp = data;
- if (which != EV_READ) {
- printerr(2, "Closing 'krb5' pipe %s\n", clp->relpath);
- close(clp->krb5_fd);
- clp->krb5_fd = -1;
- event_del(&clp->krb5_ev);
- gssd_scan();
- return;
- }
-
handle_krb5_upcall(clp);
}
@@ -437,17 +419,12 @@ out:
}
static int
-gssd_scan_clnt(struct topdir *tdi, const char *name)
+gssd_scan_clnt(struct clnt_info *clp)
{
- struct clnt_info *clp;
int clntfd;
bool gssd_was_closed;
bool krb5_was_closed;
- clp = gssd_get_clnt(tdi, name);
- if (!clp)
- return -1;
-
gssd_was_closed = clp->gssd_fd < 0 ? true : false;
krb5_was_closed = clp->krb5_fd < 0 ? true : false;
@@ -459,24 +436,10 @@ gssd_scan_clnt(struct topdir *tdi, const char *name)
}
if (clp->gssd_fd == -1)
- clp->gssd_fd = openat(clntfd, "gssd", O_RDWR);
+ clp->gssd_fd = openat(clntfd, "gssd", O_RDWR | O_NONBLOCK);
- if (clp->gssd_fd == -1) {
- if (clp->krb5_fd == -1)
- clp->krb5_fd = openat(clntfd, "krb5", O_RDWR);
-
- /* If we opened a gss-specific pipe, let's try opening
- * the new upcall pipe again. If we succeed, close
- * gss-specific pipe(s).
- */
- if (clp->krb5_fd != -1) {
- clp->gssd_fd = openat(clntfd, "gssd", O_RDWR);
- if (clp->gssd_fd != -1) {
- close(clp->krb5_fd);
- clp->krb5_fd = -1;
- }
- }
- }
+ if (clp->gssd_fd == -1 && clp->krb5_fd == -1)
+ clp->krb5_fd = openat(clntfd, "krb5", O_RDWR | O_NONBLOCK);
if (gssd_was_closed && clp->gssd_fd >= 0) {
event_set(&clp->gssd_ev, clp->gssd_fd, EV_READ | EV_PERSIST,
@@ -490,7 +453,7 @@ gssd_scan_clnt(struct topdir *tdi, const char *name)
event_add(&clp->krb5_ev, NULL);
}
- if ((clp->krb5_fd == -1) && (clp->gssd_fd == -1))
+ if (clp->krb5_fd == -1 && clp->gssd_fd == -1)
/* not fatal, files might appear later */
goto out;
@@ -503,6 +466,17 @@ out:
return 0;
}
+static int
+gssd_create_clnt(struct topdir *tdi, const char *name)
+{
+ struct clnt_info *clp;
+
+ clp = gssd_get_clnt(tdi, name);
+ if (!clp)
+ return -1;
+
+ return gssd_scan_clnt(clp);
+}
static struct topdir *
gssd_get_topdir(const char *name)
@@ -519,7 +493,7 @@ gssd_get_topdir(const char *name)
return NULL;
}
- tdi->wd = inotify_add_watch(inotify_fd, name, IN_CREATE | IN_DELETE);
+ tdi->wd = inotify_add_watch(inotify_fd, name, IN_CREATE);
if (tdi->wd < 0) {
printerr(0, "ERROR: inotify_add_watch failed for top dir %s: %s\n",
tdi->name, strerror(errno));
@@ -571,7 +545,7 @@ gssd_scan_topdir(const char *name)
if (strncmp(d->d_name, "clnt", strlen("clnt")))
continue;
- gssd_scan_clnt(tdi, d->d_name);
+ gssd_create_clnt(tdi, d->d_name);
}
closedir(dir);
@@ -595,6 +569,7 @@ gssd_scan(void)
{
struct dirent *d;
+ printerr(3, "doing a full rescan\n");
rewinddir(pipefs_dir);
while ((d = readdir(pipefs_dir))) {
@@ -619,10 +594,84 @@ gssd_scan_cb(int UNUSED(fd), short UNUSED(which), void *UNUSED(data))
gssd_scan();
}
+static bool
+gssd_inotify_topdir(struct topdir *tdi, const struct inotify_event *ev)
+{
+ printerr(5, "inotify event for topdir (%s) - "
+ "ev->wd (%d) ev->name (%s) ev->mask (0x%08x)\n",
+ tdi->name, ev->wd, ev->len > 0 ? ev->name : "<?>", ev->mask);
+
+ if (ev->mask & IN_IGNORED) {
+ printerr(0, "ERROR: topdir disappeared!\n");
+ return false;
+ }
+
+ if (ev->len == 0)
+ return false;
+
+ if (ev->mask & IN_CREATE) {
+ if (!(ev->mask & IN_ISDIR))
+ return true;
+
+ if (strncmp(ev->name, "clnt", strlen("clnt")))
+ return true;
+
+ if (gssd_create_clnt(tdi, ev->name))
+ return false;
+
+ return true;
+ }
+
+ return false;
+}
+
+static bool
+gssd_inotify_clnt(struct topdir *tdi, struct clnt_info *clp, const struct inotify_event *ev)
+{
+ printerr(5, "inotify event for clntdir (%s) - "
+ "ev->wd (%d) ev->name (%s) ev->mask (0x%08x)\n",
+ clp->relpath, ev->wd, ev->len > 0 ? ev->name : "<?>", ev->mask);
+
+ if (ev->mask & IN_IGNORED) {
+ TAILQ_REMOVE(&tdi->clnt_list, clp, list);
+ gssd_destroy_client(clp);
+ return true;
+ }
+
+ if (ev->len == 0)
+ return false;
+
+ if (ev->mask & IN_CREATE) {
+ if (!strcmp(ev->name, "gssd") ||
+ !strcmp(ev->name, "krb5") ||
+ !strcmp(ev->name, "info"))
+ if (gssd_scan_clnt(clp))
+ return false;
+
+ return true;
+
+ } else if (ev->mask & IN_DELETE) {
+ if (!strcmp(ev->name, "gssd") && clp->gssd_fd >= 0) {
+ close(clp->gssd_fd);
+ event_del(&clp->gssd_ev);
+ clp->gssd_fd = -1;
+
+ } else if (!strcmp(ev->name, "krb5") && clp->krb5_fd >= 0) {
+ close(clp->krb5_fd);
+ event_del(&clp->krb5_ev);
+ clp->krb5_fd = -1;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
static void
gssd_inotify_cb(int ifd, short UNUSED(which), void *UNUSED(data))
{
- bool rescan = true; /* unconditional rescan, for now */
+ bool rescan = false;
struct topdir *tdi;
struct clnt_info *clp;
@@ -646,18 +695,32 @@ gssd_inotify_cb(int ifd, short UNUSED(which), void *UNUSED(data))
if (ev->mask & IN_Q_OVERFLOW) {
printerr(0, "ERROR: inotify queue overflow\n");
rescan = true;
+ break;
}
- /* NOTE: Set rescan if wd not found */
TAILQ_FOREACH(tdi, &topdir_list, list) {
- if (tdi->wd == ev->wd)
- break;
+ if (tdi->wd == ev->wd) {
+ if (!gssd_inotify_topdir(tdi, ev))
+ rescan = true;
+ goto found;
+ }
TAILQ_FOREACH(clp, &tdi->clnt_list, list) {
- if (clp->wd == ev->wd)
- break;
+ if (clp->wd == ev->wd) {
+ if (!gssd_inotify_clnt(tdi, clp, ev))
+ rescan = true;
+ goto found;
+ }
}
}
+
+found:
+ if (!tdi) {
+ printerr(1, "inotify event for unknown wd!!! - "
+ "ev->wd (%d) ev->name (%s) ev->mask (0x%08x)\n",
+ ev->wd, ev->len > 0 ? ev->name : "<?>", ev->mask);
+ rescan = true;
+ }
}
}