https://fedorahosted.org/sssd/ticket/1584

First, I thought the race condition between sssd_nss and sss_cache should be solved by some sort of file locking mechanism, but when started working on it, the places where we needed to check for the file being locked or free were too many and spread among monitor, nss and sss_cache tool processes and it was not clear how the access is controlled.

So I decided to do it this way:
1. sss_cache tries to send_sighup to monitor as usual
2. if signal_sssd returns that sssd is not running, proceed with memcache invalidation
3. As a part of memcache invalidation:
    - it first opens the mc file
    - then it checks if sssd is running (with pgrep)
    - if sssd is running it stops the the process of invalidation
    - if sssd is still not running it proceeds with the invalidation

See that if sssd starts after (or during) the pgrep check (so we will not catch it as running, but will assume it is off) it is not a problem, because we have file descriptor associated with file that was present before sssd was running (we open the file before pgrep call). sssd_nss alwas creates a new memory cache file on startup, so we will only mark the old one as recycled (and not the new one), that we do not care about (because it will be deleted by sssd_nss and marking that as recycled is not a problem, I think -- the worst thing that can happen is race between nss and cache tool while both are marking the OLD file as recycled, but I can not figure out situation where this could be dangerous, because there are no "temp" states that could be harmful. Both processes are changing the value of status, but both to the same value).

Another thing that I like about this is that we do not have to care about communication sssd vs sssd_nss vs sss_cache but only control sssd vs sss_cache, which is much easier to understand.

Can someone see any problems that I missed?

NOTE: The function sss_mc_set_recycled is copied from different module. I did not want to make this function non static and put it to a header file because it is not intended to be used directly.

I tested it and it works fine for me.

The patch is attached.

Thanks
Michal
>From f7d3997950bcab7d753b8fc4ed8f934b74260d4e Mon Sep 17 00:00:00 2001
From: Michal Zidek <[email protected]>
Date: Mon, 22 Oct 2012 12:28:13 +0200
Subject: [PATCH] sss_cache: Remove fastcache even if sssd is not running.

https://fedorahosted.org/sssd/ticket/1584
---
 src/tools/sss_cache.c  | 16 +++++++++-
 src/tools/tools_util.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++
 src/tools/tools_util.h |  2 ++
 3 files changed, 104 insertions(+), 1 deletion(-)

diff --git a/src/tools/sss_cache.c b/src/tools/sss_cache.c
index 73d9965..9580ba9 100644
--- a/src/tools/sss_cache.c
+++ b/src/tools/sss_cache.c
@@ -30,6 +30,7 @@
 #include "db/sysdb.h"
 #include "db/sysdb_services.h"
 #include "db/sysdb_autofs.h"
+#include "responder/nss/nsssrv_mmap_cache.h"
 
 #define INVALIDATE_NONE 0
 #define INVALIDATE_USERS 1
@@ -162,7 +163,20 @@ int main(int argc, const char *argv[])
 
             DEBUG(SSSDBG_TRACE_FUNC, ("Sending SIGHUP to monitor.\n"));
             ret = signal_sssd(SIGHUP);
-            if (ret != EOK) {
+            if (ret == ENOENT) {
+                DEBUG(SSSDBG_TRACE_FUNC, ("sssd is not running. "
+                                          "Invalidate fastchache here.\n"));
+                ret = sss_memcache_invalidate(SSS_NSS_MCACHE_DIR"/passwd");
+                if (ret != EOK) {
+                    DEBUG(SSSDBG_CRIT_FAILURE,
+                          ("Unable to invalidate passwd fastcache.\n"));
+                }
+                ret = sss_memcache_invalidate(SSS_NSS_MCACHE_DIR"/group");
+                if (ret != EOK) {
+                    DEBUG(SSSDBG_CRIT_FAILURE,
+                          ("Unable to invalidate group fastcache.\n"));
+                }
+            } else if (ret != EOK) {
                 DEBUG(SSSDBG_CRIT_FAILURE,
                       ("Failed to send SIGHUP to monitor.\n"));
                 goto done;
diff --git a/src/tools/tools_util.c b/src/tools/tools_util.c
index 049a4f5..794a817 100644
--- a/src/tools/tools_util.c
+++ b/src/tools/tools_util.c
@@ -35,6 +35,7 @@
 #include "db/sysdb.h"
 #include "tools/tools_util.h"
 #include "tools/sss_sync_ops.h"
+#include "util/mmap_cache.h"
 
 static int setup_db(struct tools_ctx *ctx)
 {
@@ -671,3 +672,89 @@ errno_t signal_sssd(int signum)
 
     return EOK;
 }
+
+static errno_t sss_mc_set_recycled(int fd)
+{
+    uint32_t w = SSS_MC_HEADER_RECYCLED;
+    struct sss_mc_header h;
+    off_t offset;
+    off_t pos;
+    int ret;
+
+
+    offset = MC_PTR_DIFF(&h.status, &h);
+
+    pos = lseek(fd, offset, SEEK_SET);
+    if (pos == -1) {
+        /* What do we do now ? */
+        return errno;
+    }
+
+    errno = 0;
+    ret = sss_atomic_write_s(fd, (uint8_t *)&w, sizeof(h.status));
+    if (ret == -1) {
+        return errno;
+    }
+
+    if (ret != sizeof(h.status)) {
+        /* Write error */
+        return EIO;
+    }
+
+    return EOK;
+}
+
+errno_t sss_memcache_invalidate(const char *mc_filename)
+{
+    int mc_fd = -1;
+    errno_t ret;
+
+    if (!mc_filename) {
+        return EINVAL;
+    }
+
+    mc_fd = open(mc_filename, O_RDWR);
+    if (mc_fd == -1) {
+        ret = errno;
+        if (ret == ENOENT) {
+            DEBUG(SSSDBG_TRACE_FUNC,("Memory cache file %s "
+                  "does not exist.\n", mc_filename));
+            return EOK;
+        } else {
+            DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to open file %s: %s\n",
+                  mc_filename, strerror(ret)));
+            return ret;
+        }
+    }
+
+    /* The file is now opened. If sssd is still not runnig
+     * then it is definitely the one we want to recycle. If SSSD started, than
+     * SSSD takes care of the file. */
+    ret = system("pgrep '\\bsssd\\b'");
+    if (ret == 0) {
+        DEBUG(SSSDBG_TRACE_FUNC,
+              ("sssd is running, do not proceed with cache invalidation.\n"));
+        ret = EOK;
+        goto done;
+    } else if (ret == -1) {
+        /* pgrep failed */
+        DEBUG(SSSDBG_CRIT_FAILURE, ("system() returned -1\n"));
+        goto done;
+    }
+
+    /* Mark the mc file as recycled. */
+    ret = sss_mc_set_recycled(mc_fd);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to mark memory cache file %s "
+              "as recycled.\n", mc_filename));
+        goto done;
+    }
+
+    ret = EOK;
+done:
+    if (mc_fd != -1) {
+        close(mc_fd);
+    }
+    return ret;
+}
+
diff --git a/src/tools/tools_util.h b/src/tools/tools_util.h
index 1be17e8..a83c8ee 100644
--- a/src/tools/tools_util.h
+++ b/src/tools/tools_util.h
@@ -104,6 +104,8 @@ int run_userdel_cmd(struct tools_ctx *tctx);
 
 errno_t signal_sssd(int signum);
 
+errno_t sss_memcache_invalidate(const char *mc_filename);
+
 /* from files.c */
 int remove_tree(const char *root);
 
-- 
1.7.11.2

_______________________________________________
sssd-devel mailing list
[email protected]
https://lists.fedorahosted.org/mailman/listinfo/sssd-devel

Reply via email to