]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
uuidd: add cont_clock persistence
authorMichael Trapp <michael.trapp@sap.com>
Wed, 10 Jan 2024 16:29:38 +0000 (17:29 +0100)
committerKarel Zak <kzak@redhat.com>
Fri, 12 Jan 2024 09:26:26 +0000 (10:26 +0100)
cont_clock requires a correct time setup and therefore it
must be possible to detect a step back between uuidd starts.

Reserving the next 10 seconds is sufficient and should not
have a noticeable performance impact. It will also provide
the possibility to start with the clock_reg from the previous
session when the system was rebooted.

Whith that, the early cont_clock initialization in uuidd
should be removed because writing the cont_clock persitence
when -C was not set is useless and might be confusing.

libuuid/src/gen_uuid.c
libuuid/src/uuidP.h
misc-utils/uuidd.c

index 826cd22456796ca653e71ff23ea65be07a46f91a..79e5e285c5b1fd5c2b6f077ac0ba83444de347fa 100644 (file)
@@ -207,6 +207,28 @@ static int get_node_id(unsigned char *node_id)
        return 0;
 }
 
+enum { STATE_FD_ERROR = -1, STATE_FD_INIT = -2 };
+
+static int state_fd_init(const char *clock_file, FILE **fp)
+{
+       mode_t save_umask;
+       int state_fd;
+       FILE *state_f;
+
+       save_umask = umask(0);
+       state_fd = open(clock_file, O_RDWR|O_CREAT|O_CLOEXEC, 0660);
+       (void) umask(save_umask);
+       if (state_fd != -1) {
+               state_f = fdopen(state_fd, "r+" UL_CLOEXECSTR);
+               if (!state_f) {
+                       close(state_fd);
+                       state_fd = STATE_FD_ERROR;
+               } else
+                       *fp = state_f;
+       }
+       return state_fd;
+}
+
 /* Assume that the gettimeofday() has microsecond granularity */
 #define MAX_ADJUSTMENT 10
 /* Reserve a clock_seq value for the 'continuous clock' implementation */
@@ -223,32 +245,16 @@ static int get_clock(uint32_t *clock_high, uint32_t *clock_low,
 {
        THREAD_LOCAL int                adjustment = 0;
        THREAD_LOCAL struct timeval     last = {0, 0};
-       THREAD_LOCAL int                state_fd = -2;
+       THREAD_LOCAL int                state_fd = STATE_FD_INIT;
        THREAD_LOCAL FILE               *state_f;
        THREAD_LOCAL uint16_t           clock_seq;
        struct timeval                  tv;
        uint64_t                        clock_reg;
-       mode_t                          save_umask;
        int                             ret = 0;
 
-       if (state_fd == -1)
-               ret = -1;
+       if (state_fd == STATE_FD_INIT)
+               state_fd = state_fd_init(LIBUUID_CLOCK_FILE, &state_f);
 
-       if (state_fd == -2) {
-               save_umask = umask(0);
-               state_fd = open(LIBUUID_CLOCK_FILE, O_RDWR|O_CREAT|O_CLOEXEC, 0660);
-               (void) umask(save_umask);
-               if (state_fd != -1) {
-                       state_f = fdopen(state_fd, "r+" UL_CLOEXECSTR);
-                       if (!state_f) {
-                               close(state_fd);
-                               state_fd = -1;
-                               ret = -1;
-                       }
-               }
-               else
-                       ret = -1;
-       }
        if (state_fd >= 0) {
                rewind(state_f);
                while (flock(state_fd, LOCK_EX) < 0) {
@@ -256,11 +262,13 @@ static int get_clock(uint32_t *clock_high, uint32_t *clock_low,
                                continue;
                        fclose(state_f);
                        close(state_fd);
-                       state_fd = -1;
+                       state_fd = STATE_FD_ERROR;
                        ret = -1;
                        break;
                }
-       }
+       } else
+               ret = -1;
+
        if (state_fd >= 0) {
                unsigned int cl;
                unsigned long tv1, tv2;
@@ -355,44 +363,94 @@ static uint64_t get_clock_counter(void)
 /*
  * Get continuous clock value.
  *
- * Return -1 if there is no further clock counter available,
+ * Return -1 if there is no valid clock counter available,
  * otherwise return 0.
  *
  * This implementation doesn't deliver clock counters based on
  * the current time because last_clock_reg is only incremented
  * by the number of requested UUIDs.
  * max_clock_offset is used to limit the offset of last_clock_reg.
+ * used/reserved UUIDs are written to LIBUUID_CLOCK_CONT_FILE.
  */
 static int get_clock_cont(uint32_t *clock_high,
                          uint32_t *clock_low,
                          int num,
                          uint32_t max_clock_offset)
 {
-       /* 100ns based time offset according to RFC 4122. 4.1.4. */
+       /* all 64bit clock_reg values in this function represent '100ns ticks'
+        * due to the combination of tv_usec + MAX_ADJUSTMENT */
+
+       /* time offset according to RFC 4122. 4.1.4. */
        const uint64_t reg_offset = (((uint64_t) 0x01B21DD2) << 32) + 0x13814000;
        static uint64_t last_clock_reg = 0;
-       uint64_t clock_reg;
+       static uint64_t saved_clock_reg = 0;
+       static int state_fd = STATE_FD_INIT;
+       static FILE *state_f = NULL;
+       uint64_t clock_reg, next_clock_reg;
 
-       if (last_clock_reg == 0)
-               last_clock_reg = get_clock_counter();
+       if (state_fd == STATE_FD_ERROR)
+               return -1;
 
        clock_reg = get_clock_counter();
+
+       if (state_fd == STATE_FD_INIT) {
+               struct stat st;
+
+               state_fd = state_fd_init(LIBUUID_CLOCK_CONT_FILE, &state_f);
+               if (state_fd == STATE_FD_ERROR)
+                       return -1;
+
+               if (fstat(state_fd, &st))
+                       goto error;
+
+               if (st.st_size) {
+                       rewind(state_f);
+                       if (fscanf(state_f, "cont: %lu\n", &last_clock_reg) != 1)
+                               goto error;
+               } else
+                       last_clock_reg = clock_reg;
+
+               saved_clock_reg = last_clock_reg;
+       }
+
        if (max_clock_offset) {
-               uint64_t clock_offset = max_clock_offset * 10000000ULL;
-               if (last_clock_reg < (clock_reg - clock_offset))
-                       last_clock_reg = clock_reg - clock_offset;
+               uint64_t co = 10000000ULL * (uint64_t)max_clock_offset; // clock_offset in [100ns]
+
+               if ((last_clock_reg + co) < clock_reg)
+                       last_clock_reg = clock_reg - co;
        }
 
        clock_reg += MAX_ADJUSTMENT;
 
-       if ((last_clock_reg + num) >= clock_reg)
+       next_clock_reg = last_clock_reg + (uint64_t)num;
+       if (next_clock_reg >= clock_reg)
                return -1;
 
+       if (next_clock_reg >= saved_clock_reg) {
+               uint64_t cl = next_clock_reg + 100000000ULL;    // 10s interval in [100ns]
+               int l;
+
+               rewind(state_f);
+               l = fprintf(state_f, "cont: %020lu                   \n", cl);
+               if (l < 30 || fflush(state_f))
+                       goto error;
+               saved_clock_reg = cl;
+       }
+
        *clock_high = (last_clock_reg + reg_offset) >> 32;
        *clock_low = last_clock_reg + reg_offset;
-       last_clock_reg += num;
+       last_clock_reg = next_clock_reg;
 
        return 0;
+
+error:
+       if (state_fd >= 0)
+               close(state_fd);
+       if (state_f)
+               fclose(state_f);
+       state_fd = STATE_FD_ERROR;
+       state_f = NULL;
+       return -1;
 }
 
 #if defined(HAVE_UUIDD) && defined(HAVE_SYS_UN_H)
index 200702c1e5281254a8f4e2bf10960ebc57ba6e5b..fef7e6cb56d6ce18c3b716411a6622d14099c749 100644 (file)
@@ -40,6 +40,7 @@
 #include "uuid.h"
 
 #define LIBUUID_CLOCK_FILE     "/var/lib/libuuid/clock.txt"
+#define LIBUUID_CLOCK_CONT_FILE        "/var/lib/libuuid/clock-cont.txt"
 
 /*
  * Offset between 15-Oct-1582 and 1-Jan-70
index fd121c5bca05d242d96c14fa538a9cbe92047111..42a252dd050921b7dbd6d0e0065256847f90968c 100644 (file)
@@ -442,15 +442,6 @@ static void server_loop(const char *socket_path, const char *pidfile_path,
        pfd[POLLFD_SOCKET].fd = s;
        pfd[POLLFD_SIGNAL].events = pfd[POLLFD_SOCKET].events = POLLIN | POLLERR | POLLHUP;
 
-       num = 1;
-       if (uuidd_cxt->cont_clock_offset) {
-               /* trigger initialization */
-               (void) __uuid_generate_time_cont(uu, &num, uuidd_cxt->cont_clock_offset);
-               if (uuidd_cxt->debug)
-                       fprintf(stderr, _("max_clock_offset = %u sec\n"),
-                               uuidd_cxt->cont_clock_offset);
-       }
-
        while (1) {
                ret = poll(pfd, ARRAY_SIZE(pfd),
                                uuidd_cxt->timeout ?