]> source.dussan.org Git - rspamd.git/commitdiff
[Fix] Try to avoid race condition when using rrd
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Wed, 24 Aug 2016 20:45:20 +0000 (21:45 +0100)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Wed, 24 Aug 2016 20:46:17 +0000 (21:46 +0100)
src/controller.c
src/libutil/rrd.c
src/libutil/rrd.h

index 1c533cc0abd5456d8283fea5d2ec9817785ecb88..7280d995119b5301eea3b4ca2bc5d8f560372455 100644 (file)
@@ -2668,6 +2668,7 @@ rspamd_controller_on_terminate (struct rspamd_worker *worker)
        rspamd_controller_store_saved_stats (ctx);
 
        if (ctx->rrd) {
+               msg_info ("closing rrd file: %s", ctx->rrd->filename);
                event_del (ctx->rrd_event);
                rspamd_rrd_close (ctx->rrd);
        }
index ec061dd1acc11285b1aec4398b2190157835f7db..fca4ecad2b14a2696c1d6fa04ba92ae8bb3345ba 100644 (file)
@@ -350,6 +350,40 @@ rspamd_rrd_calculate_checksum (struct rspamd_rrd_file *file)
        }
 }
 
+static int
+rspamd_rrd_open_exclusive (const gchar *filename)
+{
+       struct timespec sleep_ts = {
+                       .tv_sec = 0,
+                       .tv_nsec = 1000000
+       };
+       gint fd;
+
+       fd = open (filename, O_RDWR);
+
+       if (fd == -1) {
+               return -1;
+       }
+
+       for (;;) {
+               if (rspamd_file_lock (fd, TRUE) == -1) {
+                       if (errno == EAGAIN || errno == EWOULDBLOCK) {
+                               nanosleep (&sleep_ts, NULL);
+                               continue;
+                       }
+                       else {
+                               close (fd);
+                               return -1;
+                       }
+               }
+               else {
+                       break;
+               }
+       }
+
+       return fd;
+};
+
 /**
  * Open completed or incompleted rrd file
  * @param filename
@@ -376,7 +410,7 @@ rspamd_rrd_open_common (const gchar *filename, gboolean completed, GError **err)
        }
 
        /* Open file */
-       fd = open (filename, O_RDWR);
+       fd = rspamd_rrd_open_exclusive (filename);
        if (fd == -1) {
                g_set_error (err,
                        rrd_error_quark (), errno, "rrd open error: %s", strerror (errno));
@@ -386,14 +420,17 @@ rspamd_rrd_open_common (const gchar *filename, gboolean completed, GError **err)
        if (fstat (fd, &st) == -1) {
                g_set_error (err,
                        rrd_error_quark (), errno, "rrd stat error: %s", strerror (errno));
+               rspamd_file_unlock (fd, FALSE);
                close (fd);
                return FALSE;
        }
        /* Mmap file */
        file->size = st.st_size;
        if ((file->map =
-               mmap (NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
-               0)) == MAP_FAILED) {
+                       mmap (NULL, st.st_size, PROT_READ | PROT_WRITE,
+                                       MAP_SHARED, fd, 0)) == MAP_FAILED) {
+
+               rspamd_file_unlock (fd, FALSE);
                close (fd);
                g_set_error (err,
                        rrd_error_quark (), ENOMEM, "mmap failed: %s", strerror (errno));
@@ -401,7 +438,7 @@ rspamd_rrd_open_common (const gchar *filename, gboolean completed, GError **err)
                return NULL;
        }
 
-       close (fd);
+       file->fd = fd;
 
        /* Adjust pointers */
        rspamd_rrd_adjust_pointers (file, completed);
@@ -462,7 +499,7 @@ rspamd_rrd_create (const gchar *filename,
        guint i, j;
 
        /* Open file */
-       fd = open (filename, O_RDWR | O_CREAT | O_TRUNC, 0644);
+       fd = open (filename, O_RDWR | O_CREAT | O_EXCL, 0644);
        if (fd == -1) {
                g_set_error (err,
                        rrd_error_quark (), errno, "rrd create error: %s",
@@ -470,6 +507,8 @@ rspamd_rrd_create (const gchar *filename,
                return NULL;
        }
 
+       rspamd_file_lock (fd, FALSE);
+
        /* Fill header */
        memset (&head, 0, sizeof (head));
        head.rra_cnt = rra_count;
@@ -480,6 +519,7 @@ rspamd_rrd_create (const gchar *filename,
        head.float_cookie = RRD_FLOAT_COOKIE;
 
        if (write (fd, &head, sizeof (head)) != sizeof (head)) {
+               rspamd_file_unlock (fd, FALSE);
                close (fd);
                g_set_error (err,
                        rrd_error_quark (), errno, "rrd write error: %s", strerror (errno));
@@ -493,6 +533,7 @@ rspamd_rrd_create (const gchar *filename,
        memset (&ds.par, 0, sizeof (ds.par));
        for (i = 0; i < ds_count; i++) {
                if (write (fd, &ds, sizeof (ds)) != sizeof (ds)) {
+                       rspamd_file_unlock (fd, FALSE);
                        close (fd);
                        g_set_error (err,
                                rrd_error_quark (), errno, "rrd write error: %s",
@@ -508,6 +549,7 @@ rspamd_rrd_create (const gchar *filename,
        memset (&rra.par, 0, sizeof (rra.par));
        for (i = 0; i < rra_count; i++) {
                if (write (fd, &rra, sizeof (rra)) != sizeof (rra)) {
+                       rspamd_file_unlock (fd, FALSE);
                        close (fd);
                        g_set_error (err,
                                rrd_error_quark (), errno, "rrd write error: %s",
@@ -522,6 +564,7 @@ rspamd_rrd_create (const gchar *filename,
        lh.last_up_usec = (glong)((initial_ticks - lh.last_up) * 1e6f);
 
        if (write (fd, &lh, sizeof (lh)) != sizeof (lh)) {
+               rspamd_file_unlock (fd, FALSE);
                close (fd);
                g_set_error (err,
                        rrd_error_quark (), errno, "rrd write error: %s", strerror (errno));
@@ -537,6 +580,7 @@ rspamd_rrd_create (const gchar *filename,
 
        for (i = 0; i < ds_count; i++) {
                if (write (fd, &pdp, sizeof (pdp)) != sizeof (pdp)) {
+                       rspamd_file_unlock (fd, FALSE);
                        close (fd);
                        g_set_error (err,
                                rrd_error_quark (), errno, "rrd write error: %s",
@@ -554,6 +598,7 @@ rspamd_rrd_create (const gchar *filename,
        for (i = 0; i < rra_count; i++) {
                for (j = 0; j < ds_count; j++) {
                        if (write (fd, &cdp, sizeof (cdp)) != sizeof (cdp)) {
+                               rspamd_file_unlock (fd, FALSE);
                                close (fd);
                                g_set_error (err,
                                        rrd_error_quark (), errno, "rrd write error: %s",
@@ -567,6 +612,7 @@ rspamd_rrd_create (const gchar *filename,
        memset (&rra_ptr, 0, sizeof (rra_ptr));
        for (i = 0; i < rra_count; i++) {
                if (write (fd, &rra_ptr, sizeof (rra_ptr)) != sizeof (rra_ptr)) {
+                       rspamd_file_unlock (fd, FALSE);
                        close (fd);
                        g_set_error (err,
                                rrd_error_quark (), errno, "rrd write error: %s",
@@ -575,7 +621,9 @@ rspamd_rrd_create (const gchar *filename,
                }
        }
 
+       rspamd_file_unlock (fd, FALSE);
        close (fd);
+
        new = rspamd_rrd_open_common (filename, FALSE, err);
 
        return new;
@@ -643,18 +691,13 @@ rspamd_rrd_finalize (struct rspamd_rrd_file *file, GError **err)
        gdouble vbuf[1024];
        struct stat st;
 
-       if (file == NULL || file->filename == NULL) {
+       if (file == NULL || file->filename == NULL || file->fd == -1) {
                g_set_error (err,
                        rrd_error_quark (), EINVAL, "rrd add rra failed: wrong arguments");
                return FALSE;
        }
 
-       fd = open (file->filename, O_RDWR);
-       if (fd == -1) {
-               g_set_error (err,
-                       rrd_error_quark (), errno, "rrd open error: %s", strerror (errno));
-               return FALSE;
-       }
+       fd = file->fd;
 
        if (lseek (fd, 0, SEEK_END) == -1) {
                g_set_error (err,
@@ -710,7 +753,7 @@ rspamd_rrd_finalize (struct rspamd_rrd_file *file, GError **err)
                g_slice_free1 (sizeof (struct rspamd_rrd_file), file);
                return FALSE;
        }
-       close (fd);
+
        /* Adjust pointers */
        rspamd_rrd_adjust_pointers (file, TRUE);
 
@@ -1214,6 +1257,7 @@ rspamd_rrd_close (struct rspamd_rrd_file * file)
        }
 
        munmap (file->map, file->size);
+       close (file->fd);
        g_free (file->filename);
        g_free (file->id);
 
index c7bc8008af6350adc7d66c2d953169bd3c38eb4f..d242499654bb14e355230d71cb2373379c16172e 100644 (file)
@@ -204,6 +204,7 @@ struct rspamd_rrd_file {
        gsize size; /* its size */
        gboolean finalized;
        gchar *id;
+       gint fd;
 };