[PATCH v2] uuidd: add cont_clock persistence

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 | 120 ++++++++++++++++++++++++++++++-----------
 libuuid/src/uuidP.h    |   1 +
 misc-utils/uuidd.c     |   9 ----
 3 files changed, 90 insertions(+), 40 deletions(-)

diff --git a/libuuid/src/gen_uuid.c b/libuuid/src/gen_uuid.c
index 826cd2245..79e5e285c 100644
--- a/libuuid/src/gen_uuid.c
+++ b/libuuid/src/gen_uuid.c
@@ -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)
diff --git a/libuuid/src/uuidP.h b/libuuid/src/uuidP.h
index 200702c1e..fef7e6cb5 100644
--- a/libuuid/src/uuidP.h
+++ b/libuuid/src/uuidP.h
@@ -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
diff --git a/misc-utils/uuidd.c b/misc-utils/uuidd.c
index fd121c5bc..42a252dd0 100644
--- a/misc-utils/uuidd.c
+++ b/misc-utils/uuidd.c
@@ -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 ?
-- 
2.39.3 (Apple Git-145)





[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux