On 10/24/2012 05:04 PM, Simo Sorce wrote:
In sssd_nss you also need to take a F_WRLCK on the first byte of the
file, however in sssd_nss case you want to retry a few times just in
case you races with sss_cache. I think retrying a couple of times
waiting a few milliseconds between each retry would be fine.

Say 3 retries waiting 50ms between each.


Ok. I used this for both old (to be unlinked) and new (created) memcache files. But why is F_SETLKW not sufficient here (sssd_nss)? Are you afraid of possible deadlock (it could happen if more sssd's were running at the same time, like it happened recently because of a bug with pidfile creation)? Or is there some other reason?

NOTE: This patch applies on top of the recently posted patch in (see thread: [SSSD] [PATCH] sss_cache: Multiple domains not handled properly)

I tested it and it worked well for me. Any comments appreciated.

Thanks
Michal

>From 0f6080c0b2db8b00aa8c7bd19b23b527e97c21a7 Mon Sep 17 00:00:00 2001
From: Michal Zidek <mzi...@redhat.com>
Date: Fri, 26 Oct 2012 17:36:51 +0200
Subject: [PATCH] sss_cache: Remove fastcache even if sssd is not running.

https://fedorahosted.org/sssd/ticket/1584
---
 src/responder/nss/nsssrv_mmap_cache.c |  65 ++++++++++++++++++++++
 src/tools/sss_cache.c                 |  78 +++++++++++++++++++-------
 src/tools/tools_util.c                | 101 ++++++++++++++++++++++++++++++++++
 src/tools/tools_util.h                |   2 +
 4 files changed, 226 insertions(+), 20 deletions(-)

diff --git a/src/responder/nss/nsssrv_mmap_cache.c b/src/responder/nss/nsssrv_mmap_cache.c
index f402564..ffa0bc6 100644
--- a/src/responder/nss/nsssrv_mmap_cache.c
+++ b/src/responder/nss/nsssrv_mmap_cache.c
@@ -537,9 +537,46 @@ static errno_t sss_mc_create_file(struct sss_mc_ctx *mc_ctx)
     mode_t old_mask;
     int ofd;
     int ret;
+    int retries_left;
+    struct flock mc_lock;
+    useconds_t t = 50000;
+
+    mc_lock.l_type = F_WRLCK;
+    mc_lock.l_whence = SEEK_SET;
+    mc_lock.l_start = 0;
+    mc_lock.l_start = 1;
+    mc_lock.l_pid = getpid();
 
     ofd = open(mc_ctx->file, O_RDWR);
     if (ofd != -1) {
+        for (retries_left = 2; retries_left >= 0; retries_left--) {
+            ret = fcntl(ofd, F_SETLK, &mc_lock);
+            if (ret == EACCES || ret == EAGAIN || ret == EINTR) {
+                /* File is locked by someone else */
+                DEBUG(SSSDBG_TRACE_FUNC,
+                      ("Failed to lock mc file %s. Retries left: %d\n",
+                       mc_ctx->file, retries_left));
+                ret = usleep(t);
+                if (ret == -1) {
+                    DEBUG(SSSDBG_MINOR_FAILURE,
+                          ("usleep() failed -> ignoring\n"));
+                }
+            } else if (ret == 0) {
+                /* File successfuly locked */
+                break;
+            } else {
+                /* Error occurred */
+                DEBUG(SSSDBG_CRIT_FAILURE,
+                      ("Unable to lock mc file %s\n", mc_ctx->file));
+                return ret;
+            }
+        }
+        if (retries_left < 0) {
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  ("Unable to lock mc file %s\n", mc_ctx->file));
+            return ret;
+        }
+
         ret = sss_mc_set_recycled(ofd);
         if (ret) {
             DEBUG(SSSDBG_TRACE_FUNC, ("Failed to mark mmap file %s as"
@@ -570,6 +607,34 @@ static errno_t sss_mc_create_file(struct sss_mc_ctx *mc_ctx)
                                     mc_ctx->file, ret, strerror(ret)));
     }
 
+    for (retries_left = 2; retries_left >= 0; retries_left--) {
+        ret = fcntl(mc_ctx->fd, F_SETLK, &mc_lock);
+        if (ret == EACCES || ret == EAGAIN || ret == EINTR) {
+            /* File is locked by someone else */
+            DEBUG(SSSDBG_TRACE_FUNC,
+                  ("Failed to lock mc file %s. Retries left: %d\n",
+                   mc_ctx->file, retries_left));
+            ret = usleep(t);
+            if (ret == -1) {
+                DEBUG(SSSDBG_MINOR_FAILURE,
+                      ("usleep() failed -> ignoring\n"));
+            }
+        } else if (ret == 0) {
+            /* File successfuly locked */
+            break;
+        } else {
+            /* Error occurred */
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  ("Unable to lock mc file %s\n", mc_ctx->file));
+            return ret;
+        }
+    }
+    if (retries_left < 0) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              ("Unable to lock mc file %s\n", mc_ctx->file));
+        return ret;
+    }
+
     /* reset mask back */
     umask(old_mask);
 
diff --git a/src/tools/sss_cache.c b/src/tools/sss_cache.c
index 36e425c..a647294 100644
--- a/src/tools/sss_cache.c
+++ b/src/tools/sss_cache.c
@@ -92,6 +92,7 @@ errno_t invalidate_entry(TALLOC_CTX *ctx, struct sysdb_ctx *sysdb,
 bool invalidate_entries(TALLOC_CTX *ctx, struct sysdb_ctx *sysdb,
                         enum sss_cache_entry entry_type, const char *filter,
                         const char *name);
+static int clear_fastcache(bool *sssd_nss_is_off);
 
 int main(int argc, const char *argv[])
 {
@@ -99,6 +100,7 @@ int main(int argc, const char *argv[])
     struct cache_tool_ctx *tctx = NULL;
     struct sysdb_ctx *sysdb;
     int i;
+    bool sssd_nss_is_off;
     bool skipped = true;
     FILE *clear_mc_flag;
 
@@ -143,29 +145,36 @@ int main(int argc, const char *argv[])
         ret = ENOENT;
         goto done;
     } else {
-        /*Local cache changed -> signal monitor to invalidate fastcache */
-        clear_mc_flag = fopen(SSS_NSS_MCACHE_DIR"/"CLEAR_MC_FLAG, "w");
-        if (clear_mc_flag == NULL) {
-            DEBUG(SSSDBG_CRIT_FAILURE,
-                  ("Failed to create clear_mc_flag file. "
-                  "Memory cache will not be cleared.\n"));
+        ret = clear_fastcache(&sssd_nss_is_off);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to clear caches.\n"));
             goto done;
         }
-        ret = fclose(clear_mc_flag);
-        if (ret != 0) {
-            ret = errno;
-            DEBUG(SSSDBG_CRIT_FAILURE,
-                  ("Unable to close file descriptor: %s\n",
-                   strerror(ret)));
-             goto done;
-        }
+        if (!sssd_nss_is_off) {
+            /* sssd_nss is running -> signal monitor to invalidate fastcache */
+            clear_mc_flag = fopen(SSS_NSS_MCACHE_DIR"/"CLEAR_MC_FLAG, "w");
+            if (clear_mc_flag == NULL) {
+                DEBUG(SSSDBG_CRIT_FAILURE,
+                      ("Failed to create clear_mc_flag file. "
+                       "Memory cache will not be cleared.\n"));
+                goto done;
+            }
+            ret = fclose(clear_mc_flag);
+            if (ret != 0) {
+                ret = errno;
+                DEBUG(SSSDBG_CRIT_FAILURE,
+                      ("Unable to close file descriptor: %s\n",
+                       strerror(ret)));
+                goto done;
+            }
 
-        DEBUG(SSSDBG_TRACE_FUNC, ("Sending SIGHUP to monitor.\n"));
-        ret = signal_sssd(SIGHUP);
-        if (ret != EOK) {
-            DEBUG(SSSDBG_CRIT_FAILURE,
-                  ("Failed to send SIGHUP to monitor.\n"));
-            goto done;
+            DEBUG(SSSDBG_TRACE_FUNC, ("Sending SIGHUP to monitor.\n"));
+            ret = signal_sssd(SIGHUP);
+            if (ret != EOK) {
+                DEBUG(SSSDBG_CRIT_FAILURE,
+                      ("Failed to send SIGHUP to monitor.\n"));
+                goto done;
+            }
         }
     }
 
@@ -174,6 +183,33 @@ done:
     return ret;
 }
 
+static int clear_fastcache(bool *sssd_nss_is_off)
+{
+    int ret;
+    ret = sss_memcache_invalidate(SSS_NSS_MCACHE_DIR"/passwd");
+    if (ret != EOK) {
+        if (ret == EACCES) {
+            *sssd_nss_is_off = false;
+            return EOK;
+        } else {
+            return ret;
+        }
+    }
+
+    ret = sss_memcache_invalidate(SSS_NSS_MCACHE_DIR"/group");
+    if (ret != EOK) {
+        if (ret == EACCES) {
+            *sssd_nss_is_off = false;
+            return EOK;
+        } else {
+            return ret;
+        }
+    }
+
+    *sssd_nss_is_off = true;
+    return EOK;
+}
+
 bool invalidate_entries(TALLOC_CTX *ctx, struct sysdb_ctx *sysdb,
                         enum sss_cache_entry entry_type, const char *filter,
                         const char *name)
@@ -549,3 +585,5 @@ search_autofsmaps(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb,
     return ENOSYS;
 #endif  /* BUILD_AUTOFS */
 }
+
+
diff --git a/src/tools/tools_util.c b/src/tools/tools_util.c
index 049a4f5..cdea29d 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,103 @@ 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;
+    struct flock mc_lock;
+    errno_t ret;
+    bool locked = false;
+
+    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;
+        }
+    }
+
+    mc_lock.l_type = F_WRLCK;
+    mc_lock.l_whence = SEEK_SET;
+    mc_lock.l_start = 0;
+    mc_lock.l_start = 1;
+    mc_lock.l_pid = getpid();
+
+    ret = fcntl(mc_fd, F_SETLK, &mc_lock);
+    if (ret == -1) {
+        ret = errno;
+        if (ret == EACCES || ret == EAGAIN || ret == EINTR) {
+            /* File already locked by sssd_nss */
+            ret = EACCES;
+            goto done;
+        } else {
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  ("Failed to lock memory cache file %s: %s\n",
+                   mc_filename, strerror(ret)));
+            goto done;
+        }
+    }
+    locked = true;
+
+    /* 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 (locked) {
+        mc_lock.l_type = F_UNLCK;
+        fcntl(mc_fd, F_SETLK, &mc_lock);
+    }
+
+    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
sssd-devel@lists.fedorahosted.org
https://lists.fedorahosted.org/mailman/listinfo/sssd-devel

Reply via email to