diff --git a/SOURCES/0085-libuuid-Implement-continuous-clock-handling-for-time.patch b/SOURCES/0085-libuuid-Implement-continuous-clock-handling-for-time.patch
new file mode 100644
index 0000000..9495ff0
--- /dev/null
+++ b/SOURCES/0085-libuuid-Implement-continuous-clock-handling-for-time.patch
@@ -0,0 +1,375 @@
+From ccc5db8102728d37e2e28dd50da3370e8c8de33a Mon Sep 17 00:00:00 2001
+From: Michael Trapp <michael.trapp@sap.com>
+Date: Mon, 20 Jun 2022 17:10:36 +0200
+Subject: libuuid: Implement continuous clock handling for time based UUIDs
+
+In a uuidd setup, the daemon is a singleton and can maintain it's own
+resources for time based UUID generation. This requires a dedicated
+'clock sequence range' but does not need any further lock/update of
+the LIBUUID_CLOCK_FILE from uuidd. The range of available clock values
+is extended by a continuous handling of the clock updates - instead of
+updating the value to the current timestamp, it is incremented by
+the number of requested UUIDs.
+
+[kzak@redhat.com: - backport from upstream v2.39 to to RHEL-8]
+
+Upstream: http://github.com/util-linux/util-linux/commit/3cfba7d39b66eff4307218fefd8bb34bb1621f83
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=2141969
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ libuuid/src/gen_uuid.c  | 91 ++++++++++++++++++++++++++++++++++++++---
+ libuuid/src/libuuid.sym |  1 +
+ libuuid/src/uuidd.h     |  1 +
+ misc-utils/uuidd.8.in   | 12 ++++++
+ misc-utils/uuidd.c      | 86 ++++++++++++++++++++++++++++++++++++--
+ 5 files changed, 182 insertions(+), 9 deletions(-)
+
+diff --git a/libuuid/src/gen_uuid.c b/libuuid/src/gen_uuid.c
+index 27c135db5..f557053f7 100644
+--- a/libuuid/src/gen_uuid.c
++++ b/libuuid/src/gen_uuid.c
+@@ -209,6 +209,8 @@ static int get_node_id(unsigned char *node_id)
+ 
+ /* Assume that the gettimeofday() has microsecond granularity */
+ #define MAX_ADJUSTMENT 10
++/* Reserve a clock_seq value for the 'continuous clock' implementation */
++#define CLOCK_SEQ_CONT 0
+ 
+ /*
+  * Get clock from global sequence clock counter.
+@@ -275,8 +277,10 @@ static int get_clock(uint32_t *clock_high, uint32_t *clock_low,
+ 	}
+ 
+ 	if ((last.tv_sec == 0) && (last.tv_usec == 0)) {
+-		random_get_bytes(&clock_seq, sizeof(clock_seq));
+-		clock_seq &= 0x3FFF;
++		do {
++			random_get_bytes(&clock_seq, sizeof(clock_seq));
++			clock_seq &= 0x3FFF;
++		} while (clock_seq == CLOCK_SEQ_CONT);
+ 		gettimeofday(&last, NULL);
+ 		last.tv_sec--;
+ 	}
+@@ -286,7 +290,9 @@ try_again:
+ 	if ((tv.tv_sec < last.tv_sec) ||
+ 	    ((tv.tv_sec == last.tv_sec) &&
+ 	     (tv.tv_usec < last.tv_usec))) {
+-		clock_seq = (clock_seq+1) & 0x3FFF;
++		do {
++			clock_seq = (clock_seq+1) & 0x3FFF;
++		} while (clock_seq == CLOCK_SEQ_CONT);
+ 		adjustment = 0;
+ 		last = tv;
+ 	} else if ((tv.tv_sec == last.tv_sec) &&
+@@ -331,6 +337,64 @@ try_again:
+ 	return ret;
+ }
+ 
++/*
++ * Get current time in 100ns ticks.
++ */
++static uint64_t get_clock_counter(void)
++{
++	struct timeval tv;
++	uint64_t clock_reg;
++
++	gettimeofday(&tv, NULL);
++	clock_reg = tv.tv_usec*10;
++	clock_reg += ((uint64_t) tv.tv_sec) * 10000000ULL;
++
++	return clock_reg;
++}
++
++/*
++ * Get continuous clock value.
++ *
++ * Return -1 if there is no further 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.
++ */
++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. */
++	const uint64_t reg_offset = (((uint64_t) 0x01B21DD2) << 32) + 0x13814000;
++	static uint64_t last_clock_reg = 0;
++	uint64_t clock_reg;
++
++	if (last_clock_reg == 0)
++		last_clock_reg = get_clock_counter();
++
++	clock_reg = get_clock_counter();
++	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;
++	}
++
++	clock_reg += MAX_ADJUSTMENT;
++
++	if ((last_clock_reg + num) >= clock_reg)
++		return -1;
++
++	*clock_high = (last_clock_reg + reg_offset) >> 32;
++	*clock_low = last_clock_reg + reg_offset;
++	last_clock_reg += num;
++
++	return 0;
++}
++
+ #if defined(HAVE_UUIDD) && defined(HAVE_SYS_UN_H)
+ 
+ /*
+@@ -403,7 +467,7 @@ static int get_uuid_via_daemon(int op __attribute__((__unused__)),
+ }
+ #endif
+ 
+-int __uuid_generate_time(uuid_t out, int *num)
++static int __uuid_generate_time_internal(uuid_t out, int *num, uint32_t cont_offset)
+ {
+ 	static unsigned char node_id[6];
+ 	static int has_init = 0;
+@@ -423,7 +487,14 @@ int __uuid_generate_time(uuid_t out, int *num)
+ 		}
+ 		has_init = 1;
+ 	}
+-	ret = get_clock(&clock_mid, &uu.time_low, &uu.clock_seq, num);
++	if (cont_offset) {
++		ret = get_clock_cont(&clock_mid, &uu.time_low, *num, cont_offset);
++		uu.clock_seq = CLOCK_SEQ_CONT;
++		if (ret != 0)	/* fallback to previous implpementation */
++			ret = get_clock(&clock_mid, &uu.time_low, &uu.clock_seq, num);
++	} else {
++		ret = get_clock(&clock_mid, &uu.time_low, &uu.clock_seq, num);
++	}
+ 	uu.clock_seq |= 0x8000;
+ 	uu.time_mid = (uint16_t) clock_mid;
+ 	uu.time_hi_and_version = ((clock_mid >> 16) & 0x0FFF) | 0x1000;
+@@ -432,6 +503,16 @@ int __uuid_generate_time(uuid_t out, int *num)
+ 	return ret;
+ }
+ 
++int __uuid_generate_time(uuid_t out, int *num)
++{
++	return __uuid_generate_time_internal(out, num, 0);
++}
++
++int __uuid_generate_time_cont(uuid_t out, int *num, uint32_t cont_offset)
++{
++	return __uuid_generate_time_internal(out, num, cont_offset);
++}
++
+ /*
+  * Generate time-based UUID and store it to @out
+  *
+diff --git a/libuuid/src/libuuid.sym b/libuuid/src/libuuid.sym
+index 9e3e80035..0a072b703 100644
+--- a/libuuid/src/libuuid.sym
++++ b/libuuid/src/libuuid.sym
+@@ -51,6 +51,7 @@ global:
+ UUIDD_PRIVATE {
+ global:
+ 	__uuid_generate_time;
++	__uuid_generate_time_cont;
+ 	__uuid_generate_random;
+ local:
+ 	*;
+diff --git a/libuuid/src/uuidd.h b/libuuid/src/uuidd.h
+index e55c86f2f..14a01ade2 100644
+--- a/libuuid/src/uuidd.h
++++ b/libuuid/src/uuidd.h
+@@ -50,5 +50,6 @@
+ 
+ extern int __uuid_generate_time(uuid_t out, int *num);
+ extern void __uuid_generate_random(uuid_t out, int *num);
++extern int __uuid_generate_time_cont(uuid_t out, int *num, uint32_t cont);
+ 
+ #endif /* _UUID_UUID_H */
+diff --git a/misc-utils/uuidd.8.in b/misc-utils/uuidd.8.in
+index 0a5cf471b..28bcb48b5 100644
+--- a/misc-utils/uuidd.8.in
++++ b/misc-utils/uuidd.8.in
+@@ -16,6 +16,18 @@ universally unique identifiers (UUIDs), especially time-based UUIDs,
+ in a secure and guaranteed-unique fashion, even in the face of large
+ numbers of threads running on different CPUs trying to grab UUIDs.
+ .SH OPTIONS
++
++.TP
++.BR \-C , " \-\-cont\-clock " [\fInumber\fR]
++Activate continuous clock handling for time based UUIDs. uuidd could use all
++possible clock values, beginning with the daemon's start time. The optional
++argument can be used to set a value for the max_clock_offset. This gurantees,
++that a clock value of a UUID will always be within the range of the
++max_clock_offset. '-C' or '--cont-clock' enables the feature with a default
++max_clock_offset of 2 hours. '-C<NUM>[hd]' or '--cont-clock=<NUM>[hd]' enables
++the feature with a max_clock_offset of NUM seconds. In case of an appended h or
++d, the NUM value is read in hours or days. The minimum value is 60 seconds, the
++maximum value is 365 days.
+ .TP
+ .BR \-d , " \-\-debug "
+ Run uuidd in debugging mode.  This prevents uuidd from running as a daemon.
+diff --git a/misc-utils/uuidd.c b/misc-utils/uuidd.c
+index 8b83d91c0..e3c0abad7 100644
+--- a/misc-utils/uuidd.c
++++ b/misc-utils/uuidd.c
+@@ -49,6 +49,8 @@ struct uuidd_cxt_t {
+ 	const char	*cleanup_pidfile;
+ 	const char	*cleanup_socket;
+ 	uint32_t	timeout;
++	uint32_t	cont_clock_offset;
++
+ 	unsigned int	debug: 1,
+ 			quiet: 1,
+ 			no_fork: 1,
+@@ -73,6 +75,8 @@ static void __attribute__((__noreturn__)) usage(void)
+ 	fputs(_(" -P, --no-pid            do not create pid file\n"), out);
+ 	fputs(_(" -F, --no-fork           do not daemonize using double-fork\n"), out);
+ 	fputs(_(" -S, --socket-activation do not create listening socket\n"), out);
++	fputs(_(" -C, --cont-clock[=<NUM>[hd]]\n"), out);
++	fputs(_("                         activate continuous clock handling\n"), out);
+ 	fputs(_(" -d, --debug             run in debugging mode\n"), out);
+ 	fputs(_(" -q, --quiet             turn on quiet mode\n"), out);
+ 	fputs(USAGE_SEPARATOR, out);
+@@ -401,6 +405,15 @@ 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 ?
+@@ -458,7 +471,7 @@ static void server_loop(const char *socket_path, const char *pidfile_path,
+ 			break;
+ 		case UUIDD_OP_TIME_UUID:
+ 			num = 1;
+-			__uuid_generate_time(uu, &num);
++			__uuid_generate_time_cont(uu, &num, uuidd_cxt->cont_clock_offset);
+ 			if (uuidd_cxt->debug) {
+ 				uuid_unparse(uu, str);
+ 				fprintf(stderr, _("Generated time UUID: %s\n"), str);
+@@ -477,7 +490,7 @@ static void server_loop(const char *socket_path, const char *pidfile_path,
+ 			reply_len = sizeof(uu);
+ 			break;
+ 		case UUIDD_OP_BULK_TIME_UUID:
+-			__uuid_generate_time(uu, &num);
++			 __uuid_generate_time_cont(uu, &num, uuidd_cxt->cont_clock_offset);
+ 			if (uuidd_cxt->debug) {
+ 				uuid_unparse(uu, str);
+ 				fprintf(stderr, P_("Generated time UUID %s "
+@@ -530,6 +543,64 @@ static void __attribute__ ((__noreturn__)) unexpected_size(int size)
+ 	errx(EXIT_FAILURE, _("Unexpected reply length from server %d"), size);
+ }
+ 
++/* Backport from v2.39 lib/strutils.c */
++static int ul_strtos64(const char *str, int64_t *num, int base)
++{
++	char *end = NULL;
++
++	if (str == NULL || *str == '\0')
++		return -(errno = EINVAL);
++
++	errno = 0;
++	*num = (int64_t) strtoimax(str, &end, base);
++
++	if (errno != 0)
++		return -errno;
++	if (str == end || (end && *end))
++		return -(errno = EINVAL);
++	return 0;
++}
++
++/* Backport from v2.39 lib/strutils.c */
++static int64_t str2num_or_err(const char *str, int base, const char *errmesg,
++			     int64_t low, int64_t up)
++{
++	int64_t num = 0;
++	int rc;
++
++	rc = ul_strtos64(str, &num, base);
++	if (rc == 0 && ((low && num < low) || (up && num > up)))
++		rc = -(errno = ERANGE);
++
++	if (rc) {
++		if (errno == ERANGE)
++			err(EXIT_FAILURE, "%s: '%s'", errmesg, str);
++		errx(EXIT_FAILURE, "%s: '%s'", errmesg, str);
++	}
++	return num;
++}
++
++static uint32_t parse_cont_clock(char *arg)
++{
++	uint32_t min_val = 60,
++		 max_val = (3600 * 24 * 365),
++		 factor = 1;
++	char *p = &arg[strlen(arg)-1];
++
++	if ('h' == *p) {
++		*p = '\0';
++		factor = 3600;
++		min_val = 1;
++	}
++	if ('d' == *p) {
++		*p = '\0';
++		factor = 24 * 3600;
++		min_val = 1;
++	}
++	return factor * str2num_or_err(optarg, 10, _("failed to parse --cont-clock/-C"),
++				       min_val, max_val / factor);
++}
++
+ int main(int argc, char **argv)
+ {
+ 	const char	*socket_path = UUIDD_SOCKET_PATH;
+@@ -543,7 +614,7 @@ int main(int argc, char **argv)
+ 	int		no_pid = 0;
+ 	int		s_flag = 0;
+ 
+-	struct uuidd_cxt_t uuidd_cxt = { .timeout = 0 };
++	struct uuidd_cxt_t uuidd_cxt = { .timeout = 0, .cont_clock_offset = 0 };
+ 
+ 	static const struct option longopts[] = {
+ 		{"pid", required_argument, NULL, 'p'},
+@@ -556,6 +627,7 @@ int main(int argc, char **argv)
+ 		{"no-pid", no_argument, NULL, 'P'},
+ 		{"no-fork", no_argument, NULL, 'F'},
+ 		{"socket-activation", no_argument, NULL, 'S'},
++		{"cont-clock", optional_argument, NULL, 'C'},
+ 		{"debug", no_argument, NULL, 'd'},
+ 		{"quiet", no_argument, NULL, 'q'},
+ 		{"version", no_argument, NULL, 'V'},
+@@ -576,10 +648,16 @@ int main(int argc, char **argv)
+ 	atexit(close_stdout);
+ 
+ 	while ((c =
+-		getopt_long(argc, argv, "p:s:T:krtn:PFSdqVh", longopts,
++		getopt_long(argc, argv, "p:s:T:krtn:PFSC::dqVh", longopts,
+ 			    NULL)) != -1) {
+ 		err_exclusive_options(c, longopts, excl, excl_st);
+ 		switch (c) {
++		case 'C':
++			if (optarg != NULL)
++				uuidd_cxt.cont_clock_offset = parse_cont_clock(optarg);
++			else
++				uuidd_cxt.cont_clock_offset = 7200; /* default 2h */
++			break;
+ 		case 'd':
+ 			uuidd_cxt.debug = 1;
+ 			break;
+-- 
+2.38.1
+
diff --git a/SOURCES/0086-libuuid-check-clock-value-from-LIBUUID_CLOCK_FILE.patch b/SOURCES/0086-libuuid-check-clock-value-from-LIBUUID_CLOCK_FILE.patch
new file mode 100644
index 0000000..4352651
--- /dev/null
+++ b/SOURCES/0086-libuuid-check-clock-value-from-LIBUUID_CLOCK_FILE.patch
@@ -0,0 +1,35 @@
+From 44cebf3e692053541f362b62f88f327c2c96e70e Mon Sep 17 00:00:00 2001
+From: Michael Trapp <michael.trapp@sap.com>
+Date: Tue, 2 Aug 2022 14:16:43 +0200
+Subject: libuuid: check clock value from LIBUUID_CLOCK_FILE
+
+The clock value from the LIBUUID_CLOCK_FILE must be checked in
+case of an update of libuuid. If clock==CLOCK_SEQ_CONT it must
+be set to a new value.
+
+Signed-off-by: Karel Zak <kzak@redhat.com>
+Upstream: http://github.com/util-linux/util-linux/commit/5d1424d85ac9e2a1369ee920038825c154ee5443
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=2141969
+---
+ libuuid/src/gen_uuid.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/libuuid/src/gen_uuid.c b/libuuid/src/gen_uuid.c
+index f557053f7..8dc38559f 100644
+--- a/libuuid/src/gen_uuid.c
++++ b/libuuid/src/gen_uuid.c
+@@ -274,6 +274,11 @@ static int get_clock(uint32_t *clock_high, uint32_t *clock_low,
+ 			last.tv_usec = tv2;
+ 			adjustment = a;
+ 		}
++		// reset in case of reserved CLOCK_SEQ_CONT
++		if (clock_seq == CLOCK_SEQ_CONT) {
++			last.tv_sec = 0;
++			last.tv_usec = 0;
++		}
+ 	}
+ 
+ 	if ((last.tv_sec == 0) && (last.tv_usec == 0)) {
+-- 
+2.38.1
+
diff --git a/SOURCES/0087-fstrim-backport-entries-de-duplication.patch b/SOURCES/0087-fstrim-backport-entries-de-duplication.patch
new file mode 100644
index 0000000..921ad25
--- /dev/null
+++ b/SOURCES/0087-fstrim-backport-entries-de-duplication.patch
@@ -0,0 +1,190 @@
+From 9272023b42febae7db1ec828016a980146095a83 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Thu, 2 Feb 2023 13:21:33 +0100
+Subject: fstrim: backport entries de-duplication
+
+Upstream: http://github.com/util-linux/util-linux/commit/9dbc073e4c58a56f68da8209df19789131446f5e
+Upstream: http://github.com/util-linux/util-linux/commit/67f974d41d62c8b521fe81e1aac92562366f6a0a
+Upstream: http://github.com/util-linux/util-linux/commit/20af6cee463cd6329b4f06db3282a09be942bd7a
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=2121699
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ sys-utils/fstrim.c | 88 ++++++++++++++++++++++++++++++++++++++--------
+ 1 file changed, 74 insertions(+), 14 deletions(-)
+
+diff --git a/sys-utils/fstrim.c b/sys-utils/fstrim.c
+index 70870ef69..6aa523d72 100644
+--- a/sys-utils/fstrim.c
++++ b/sys-utils/fstrim.c
+@@ -35,6 +35,7 @@
+ 
+ #include <sys/ioctl.h>
+ #include <sys/stat.h>
++#include <sys/vfs.h>
+ #include <linux/fs.h>
+ 
+ #include "nls.h"
+@@ -43,6 +44,7 @@
+ #include "closestream.h"
+ #include "pathnames.h"
+ #include "sysfs.h"
++#include "statfs_magic.h"
+ 
+ #include <libmount.h>
+ 
+@@ -84,6 +86,7 @@ static int fstrim_filesystem(const char *path, struct fstrim_range *rangetpl,
+ 		goto done;
+ 	}
+ 	errno = 0;
++
+ 	if (ioctl(fd, FITRIM, &range)) {
+ 		rc = errno == EOPNOTSUPP || errno == ENOTTY ? 1 : -errno;
+ 
+@@ -114,7 +117,7 @@ static int has_discard(const char *devname, struct sysfs_cxt *wholedisk)
+ 	struct sysfs_cxt cxt, *parent = NULL;
+ 	uint64_t dg = 0;
+ 	dev_t disk = 0, dev;
+-	int rc;
++	int rc, rdonly = 0;
+ 
+ 	dev = sysfs_devname_to_devno(devname, NULL);
+ 	if (!dev)
+@@ -139,11 +142,46 @@ static int has_discard(const char *devname, struct sysfs_cxt *wholedisk)
+ 	rc = sysfs_init(&cxt, dev, parent);
+ 	if (!rc)
+ 		rc = sysfs_read_u64(&cxt, "queue/discard_granularity", &dg);
++	if (!rc)
++		sysfs_scanf(&cxt, "ro", "%d", &rdonly);
+ 
+ 	sysfs_deinit(&cxt);
+-	return rc == 0 && dg > 0;
++	return rc == 0 && dg > 0 && rdonly == 0;
+ }
+ 
++static int is_unwanted_fs(struct libmnt_fs *fs, const char *tgt)
++{
++	struct statfs vfs;
++	int fd, rc;
++
++	if (mnt_fs_is_pseudofs(fs))
++		return 1;
++	if (mnt_fs_is_netfs(fs))
++		return 1;
++	if (mnt_fs_is_swaparea(fs))
++		return 1;
++	if (mnt_fs_match_fstype(fs, "autofs"))
++		return 1;
++	if (mnt_fs_match_options(fs, "ro"))
++		return 1;
++
++	fd = open(tgt, O_PATH);
++	if (fd < 0)
++		return 1;
++	rc = fstatfs(fd, &vfs) != 0 || vfs.f_type == STATFS_AUTOFS_MAGIC;
++	close(fd);
++	if (rc)
++		return 1;
++
++	/* FITRIM on read-only filesystem can fail, and it can fail */
++	if (access(tgt, W_OK) != 0) {
++		if (errno == EROFS)
++			return 1;
++		if (errno == EACCES)
++			return 1;
++	}
++	return 0;
++}
+ 
+ static int uniq_fs_target_cmp(
+ 		struct libmnt_table *tb __attribute__((__unused__)),
+@@ -182,30 +220,38 @@ static int fstrim_all(struct fstrim_range *rangetpl, int verbose)
+ 
+ 	mnt_init_debug(0);
+ 
+-	itr = mnt_new_iter(MNT_ITER_BACKWARD);
+-	if (!itr)
+-		err(MNT_EX_FAIL, _("failed to initialize libmount iterator"));
+-
+ 	tab = mnt_new_table_from_file(_PATH_PROC_MOUNTINFO);
+ 	if (!tab)
+ 		err(MNT_EX_FAIL, _("failed to parse %s"), _PATH_PROC_MOUNTINFO);
+ 
++	if (mnt_table_is_empty(tab)) {
++		mnt_unref_table(tab);
++		return MNT_EX_SUCCESS;
++	}
++
+ 	/* de-duplicate by mountpoints */
+ 	mnt_table_uniq_fs(tab, 0, uniq_fs_target_cmp);
+ 
+-	/* de-duplicate by source */
+-	mnt_table_uniq_fs(tab, MNT_UNIQ_FORWARD, uniq_fs_source_cmp);
++	itr = mnt_new_iter(MNT_ITER_BACKWARD);
++	if (!itr)
++		err(MNT_EX_FAIL, _("failed to initialize libmount iterator"));
+ 
++	/* Remove useless entries and canonicalize the table */
+ 	while (mnt_table_next_fs(tab, itr, &fs) == 0) {
+ 		const char *src = mnt_fs_get_srcpath(fs),
+ 			   *tgt = mnt_fs_get_target(fs);
+ 		char *path;
+ 		int rc = 1;
+ 
+-		if (!src || !tgt || *src != '/' ||
+-		    mnt_fs_is_pseudofs(fs) ||
+-		    mnt_fs_is_netfs(fs))
++		if (!tgt || is_unwanted_fs(fs, tgt)) {
++			mnt_table_remove_fs(tab, fs);
+ 			continue;
++		}
++
++		if (!src || *src != '/') {
++			mnt_table_remove_fs(tab, fs);
++			continue;
++		}
+ 
+ 		/* Is it really accessible mountpoint? Not all mountpoints are
+ 		 * accessible (maybe over mounted by another filesystem) */
+@@ -213,11 +259,25 @@ static int fstrim_all(struct fstrim_range *rangetpl, int verbose)
+ 		if (path && strcmp(path, tgt) == 0)
+ 			rc = 0;
+ 		free(path);
+-		if (rc)
++		if (rc) {
++			mnt_table_remove_fs(tab, fs);
+ 			continue;	/* overlaying mount */
++		}
+ 
+-		if (!has_discard(src, &wholedisk))
++		if (!has_discard(src, &wholedisk)) {
++			mnt_table_remove_fs(tab, fs);
+ 			continue;
++		}
++	}
++
++	/* de-duplicate by source */
++	mnt_table_uniq_fs(tab, MNT_UNIQ_FORWARD, uniq_fs_source_cmp);
++
++	mnt_reset_iter(itr, MNT_ITER_BACKWARD);
++
++	/* Do FITRIM */
++	while (mnt_table_next_fs(tab, itr, &fs) == 0) {
++		const char *tgt = mnt_fs_get_target(fs);
+ 		cnt++;
+ 
+ 		/*
+@@ -231,10 +291,10 @@ static int fstrim_all(struct fstrim_range *rangetpl, int verbose)
+ 		if (fstrim_filesystem(tgt, rangetpl, verbose) < 0)
+ 		       cnt_err++;
+ 	}
++	mnt_free_iter(itr);
+ 
+ 	sysfs_deinit(&wholedisk);
+ 	mnt_unref_table(tab);
+-	mnt_free_iter(itr);
+ 
+ 	if (cnt && cnt == cnt_err)
+ 		return MNT_EX_FAIL;		/* all failed */
+-- 
+2.39.1
+
diff --git a/SOURCES/0088-tests-don-t-reply-on-scsi_debug-partitions.patch b/SOURCES/0088-tests-don-t-reply-on-scsi_debug-partitions.patch
new file mode 100644
index 0000000..2ed72a4
--- /dev/null
+++ b/SOURCES/0088-tests-don-t-reply-on-scsi_debug-partitions.patch
@@ -0,0 +1,66 @@
+From a95ff5ed155c29734824f3a79350678901b22e43 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Thu, 11 Feb 2021 12:44:44 +0100
+Subject: tests: don't reply on scsi_debug partitions
+
+The disk layout as created by scsi_debug depends on kernel version.
+Let's make the partition sizes hardcoded in our tests than rely on
+kernel.
+
+Signed-off-by: Karel Zak <kzak@redhat.com>
+Upstream: http://github.com/util-linux/util-linux/commit/15a37d00e5e59f0f628d0a6b6cd2f9636702fd7c
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=2142496
+---
+ tests/expected/partx/partx-detect-parts |  6 +++---
+ tests/ts/partx/partx                    | 14 +++++++++++---
+ 2 files changed, 14 insertions(+), 6 deletions(-)
+
+diff --git a/tests/expected/partx/partx-detect-parts b/tests/expected/partx/partx-detect-parts
+index 33d42a58c..0adc85577 100644
+--- a/tests/expected/partx/partx-detect-parts
++++ b/tests/expected/partx/partx-detect-parts
+@@ -1,5 +1,5 @@
+ NR START    END SECTORS  SIZE NAME UUID
+- 1    32  33791   33760 16.5M      
+- 2 33792  67583   33792 16.5M      
+- 3 67584 102399   34816   17M      
++ 1    32  33791   33760 16.5M      1ddc8a79-01
++ 2 33792  67583   33792 16.5M      1ddc8a79-02
++ 3 67584 102399   34816   17M      1ddc8a79-03
+ OK
+diff --git a/tests/ts/partx/partx b/tests/ts/partx/partx
+index 84c286a94..6514ae62c 100755
+--- a/tests/ts/partx/partx
++++ b/tests/ts/partx/partx
+@@ -26,6 +26,7 @@ ts_init "$*"
+ ts_check_test_command "$TS_CMD_PARTX"
+ ts_check_test_command "$TS_CMD_ADDPART"
+ ts_check_test_command "$TS_CMD_DELPART"
++ts_check_test_command "$TS_CMD_SFDISK"
+ 
+ ts_skip_nonroot
+ 
+@@ -70,10 +71,17 @@ ts_init_subtest "delpart"
+ } >$TS_OUTPUT 2>&1
+ ts_finalize_subtest
+ 
+-ts_scsi_debug_rmmod
+ 
+-# set global variable TS_DEVICE
+-ts_scsi_debug_init dev_size_mb=50 num_parts=$PARTS
++udevadm settle
++$TS_CMD_SFDISK $TS_DEVICE &> /dev/null <<EOF
++label: dos
++label-id: 0x1ddc8a79
++32,33760,,
++33792,33792,,
++67584,34816,,
++EOF
++udevadm settle
++
+ 
+ ts_init_subtest "detect-parts"
+ {
+-- 
+2.39.1
+
diff --git a/SOURCES/0089-libmount-use-generic-error-message-for-EACCES-on-umo.patch b/SOURCES/0089-libmount-use-generic-error-message-for-EACCES-on-umo.patch
new file mode 100644
index 0000000..16f352c
--- /dev/null
+++ b/SOURCES/0089-libmount-use-generic-error-message-for-EACCES-on-umo.patch
@@ -0,0 +1,27 @@
+From 301dc3d820434cbc65a7b5565d448e417293fcfb Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Thu, 2 Feb 2023 14:47:04 +0100
+Subject: libmount: use generic error message for EACCES on umount
+
+Signed-off-by: Karel Zak <kzak@redhat.com>
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=2149394
+---
+ libmount/src/context_umount.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/libmount/src/context_umount.c b/libmount/src/context_umount.c
+index 240ec3be6..23aaae395 100644
+--- a/libmount/src/context_umount.c
++++ b/libmount/src/context_umount.c
+@@ -1123,7 +1123,7 @@ int mnt_context_get_umount_excode(
+ 			snprintf(buf, bufsz, _("must be superuser to unmount"));
+ 			break;
+ 		case EACCES:
+-			snprintf(buf, bufsz, _("block devices are not permitted on filesystem"));
++			snprintf(buf, bufsz, _("filesystem not accessible"));
+ 			break;
+ 		default:
+ 			return mnt_context_get_generic_excode(syserr, buf, bufsz,_("umount(2) system call failed: %m"));
+-- 
+2.39.1
+
diff --git a/SOURCES/0090-lslogins-man-explain-password-statuses.patch b/SOURCES/0090-lslogins-man-explain-password-statuses.patch
new file mode 100644
index 0000000..7dbc434
--- /dev/null
+++ b/SOURCES/0090-lslogins-man-explain-password-statuses.patch
@@ -0,0 +1,45 @@
+From ea1ad5e7260c770b21e547702b1e0acef9e4854c Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Thu, 2 Feb 2023 14:52:35 +0100
+Subject: lslogins: (man) explain password statuses
+
+Upstream: http://github.com/util-linux/util-linux/commit/95ea3dd4128b625ab12691229020ebc50d578e71
+Upstream: http://github.com/util-linux/util-linux/commit/8001bffb03eda8d23d6a04a5dc1469cce932ae36
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=2159544
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ login-utils/lslogins.1 | 18 ++++++++++++++++++
+ 1 file changed, 18 insertions(+)
+
+diff --git a/login-utils/lslogins.1 b/login-utils/lslogins.1
+index c831739d9..5c327caf5 100644
+--- a/login-utils/lslogins.1
++++ b/login-utils/lslogins.1
+@@ -116,6 +116,24 @@ Delimit user entries with a nul character, instead of a newline.
+ 
+ .SH NOTES
+ The default UID thresholds are read from /etc/login.defs.
++.SS "Password status"
++.sp
++Multiple fields describe password status.
++.sp
++\fB"Login by password disabled"\fP
++.RS 4
++\*(Aqyes\*(Aq means that there is no valid password. The password hash is missing, or the hash method is unknown or contains invalid chars.
++.RE
++.sp
++\fB"Password not required (empty)"\fP
++.RS 4
++The password is not set (hash is missing); this is common for locked system accounts. Not requiring a password does not mean the user can log\-in without a password. It depends on the password "lock" status.
++.RE
++.sp
++\fB"Password is locked"\fP
++.RS 4
++The password is prefixed by \*(Aq!!\*(Aq, and the user cannot login although the password is set or empty. This is common for new accounts without a set password.
++.RE
+ 
+ .SH EXIT STATUS
+ .TP
+-- 
+2.39.1
+
diff --git a/SOURCES/0091-last-sync-utmp-strings-use-with-upstream-code.patch b/SOURCES/0091-last-sync-utmp-strings-use-with-upstream-code.patch
new file mode 100644
index 0000000..6e0abc3
--- /dev/null
+++ b/SOURCES/0091-last-sync-utmp-strings-use-with-upstream-code.patch
@@ -0,0 +1,245 @@
+From 25f7136d326753cb0bb7612a98db6542c9fdc3bd Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Thu, 2 Feb 2023 15:22:52 +0100
+Subject: last: sync utmp strings use with upstream code
+
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=2160321
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ include/strutils.h  | 30 +++++++++++++++++++
+ include/timeutils.h |  1 +
+ login-utils/last.c  | 73 +++++++++++++++++++++++----------------------
+ 3 files changed, 69 insertions(+), 35 deletions(-)
+
+diff --git a/include/strutils.h b/include/strutils.h
+index 5d07fcc7c..193f1acbc 100644
+--- a/include/strutils.h
++++ b/include/strutils.h
+@@ -65,6 +65,36 @@ static inline void xstrncpy(char *dest, const char *src, size_t n)
+ 	dest[n-1] = 0;
+ }
+ 
++/* This is like strncpy(), but based on memcpy(), so compilers and static
++ * analyzers do not complain when sizeof(destination) is the same as 'n' and
++ * result is not terminated by zero.
++ *
++ * Use this function to copy string to logs with fixed sizes (wtmp/utmp. ...)
++ * where string terminator is optional.
++ */
++static inline void * __attribute__((nonnull (1)))
++str2memcpy(void *dest, const char *src, size_t n)
++{
++	size_t bytes = strlen(src) + 1;
++
++	if (bytes > n)
++		bytes = n;
++
++	memcpy(dest, src, bytes);
++	return dest;
++}
++
++static inline char * __attribute__((nonnull (1)))
++mem2strcpy(char *dest, const void *src, size_t n, size_t nmax)
++{
++	if (n + 1 > nmax)
++		n = nmax - 1;
++
++	memset(dest, '\0', nmax);
++	memcpy(dest, src, n);
++	return dest;
++}
++
+ static inline int strdup_to_offset(void *stru, size_t offset, const char *str)
+ {
+ 	char *n = NULL;
+diff --git a/include/timeutils.h b/include/timeutils.h
+index 230e6db5f..f1540a183 100644
+--- a/include/timeutils.h
++++ b/include/timeutils.h
+@@ -74,6 +74,7 @@ enum {
+ 	ISO_TIMESTAMP_COMMA_GT  = ISO_TIMESTAMP_COMMA_G | ISO_T
+ };
+ 
++#define CTIME_BUFSIZ    26
+ #define ISO_BUFSIZ	42
+ 
+ int strtimeval_iso(struct timeval *tv, int flags, char *buf, size_t bufsz);
+diff --git a/login-utils/last.c b/login-utils/last.c
+index 80d77d20b..8f7c36984 100644
+--- a/login-utils/last.c
++++ b/login-utils/last.c
+@@ -339,15 +339,22 @@ static int time_formatter(int fmt, char *dst, size_t dlen, time_t *when)
+ 		break;
+ 	case LAST_TIMEFTM_HHMM:
+ 	{
+-		struct tm *tm = localtime(when);
+-		if (!snprintf(dst, dlen, "%02d:%02d", tm->tm_hour, tm->tm_min))
++		struct tm tm;
++
++		localtime_r(when, &tm);
++		if (!snprintf(dst, dlen, "%02d:%02d", tm.tm_hour, tm.tm_min))
+ 			ret = -1;
+ 		break;
+ 	}
+ 	case LAST_TIMEFTM_CTIME:
+-		snprintf(dst, dlen, "%s", ctime(when));
++	{
++		char buf[CTIME_BUFSIZ];
++
++		ctime_r(when, buf);
++		snprintf(dst, dlen, "%s", buf);
+ 		ret = rtrim_whitespace((unsigned char *) dst);
+ 		break;
++	}
+ 	case LAST_TIMEFTM_ISO8601:
+ 		ret = strtime_iso(when, ISO_TIMESTAMP_T, dst, dlen);
+ 		break;
+@@ -394,8 +401,7 @@ static int list(const struct last_control *ctl, struct utmpx *p, time_t logout_t
+ 	/*
+ 	 *	uucp and ftp have special-type entries
+ 	 */
+-	utline[0] = 0;
+-	strncat(utline, p->ut_line, sizeof(p->ut_line));
++	mem2strcpy(utline, p->ut_line, sizeof(p->ut_line), sizeof(utline));
+ 	if (strncmp(utline, "ftp", 3) == 0 && isdigit(utline[3]))
+ 		utline[3] = 0;
+ 	if (strncmp(utline, "uucp", 4) == 0 && isdigit(utline[4]))
+@@ -447,48 +453,48 @@ static int list(const struct last_control *ctl, struct utmpx *p, time_t logout_t
+ 
+ 	if (logout_time == currentdate) {
+ 		if (ctl->time_fmt > LAST_TIMEFTM_SHORT) {
+-			sprintf(logouttime, "  still running");
++			snprintf(logouttime, sizeof(logouttime), "  still running");
+ 			length[0] = 0;
+ 		} else {
+-			sprintf(logouttime, "  still");
+-			sprintf(length, "running");
++			snprintf(logouttime, sizeof(logouttime), "  still");
++			snprintf(length, sizeof(length), "running");
+ 		}
+ 	} else if (days) {
+-		sprintf(length, "(%d+%02d:%02d)", days, abs(hours), abs(mins)); /* hours and mins always shown as positive (w/o minus sign!) even if secs < 0 */
++		snprintf(length, sizeof(length), "(%d+%02d:%02d)", days, abs(hours), abs(mins)); /* hours and mins always shown as positive (w/o minus sign!) even if secs < 0 */
+ 	} else if (hours) {
+-		sprintf(length, " (%02d:%02d)", hours, abs(mins));  /* mins always shown as positive (w/o minus sign!) even if secs < 0 */
++		snprintf(length, sizeof(length), " (%02d:%02d)", hours, abs(mins));  /* mins always shown as positive (w/o minus sign!) even if secs < 0 */
+ 	} else if (secs >= 0) {
+-		sprintf(length, " (%02d:%02d)", hours, mins); 
++		snprintf(length, sizeof(length), " (%02d:%02d)", hours, mins);
+ 	} else {
+-		sprintf(length, " (-00:%02d)", abs(mins));  /* mins always shown as positive (w/o minus sign!) even if secs < 0 */
++		snprintf(length, sizeof(length), " (-00:%02d)", abs(mins));  /* mins always shown as positive (w/o minus sign!) even if secs < 0 */
+ 	}
+ 
+ 	switch(what) {
+ 		case R_CRASH:
+-			sprintf(logouttime, "- crash");
++			snprintf(logouttime, sizeof(logouttime), "- crash");
+ 			break;
+ 		case R_DOWN:
+-			sprintf(logouttime, "- down ");
++			snprintf(logouttime, sizeof(logouttime), "- down ");
+ 			break;
+ 		case R_NOW:
+ 			if (ctl->time_fmt > LAST_TIMEFTM_SHORT) {
+-				sprintf(logouttime, "  still logged in");
++				snprintf(logouttime, sizeof(logouttime), "  still logged in");
+ 				length[0] = 0;
+ 			} else {
+-				sprintf(logouttime, "  still");
+-				sprintf(length, "logged in");
++				snprintf(logouttime, sizeof(logouttime), "  still");
++				snprintf(length, sizeof(length), "logged in");
+ 			}
+ 			break;
+ 		case R_PHANTOM:
+ 			if (ctl->time_fmt > LAST_TIMEFTM_SHORT) {
+-				sprintf(logouttime, "  gone - no logout");
++				snprintf(logouttime, sizeof(logouttime), "  gone - no logout");
+ 				length[0] = 0;
+ 			} else if (ctl->time_fmt == LAST_TIMEFTM_SHORT) {
+-				sprintf(logouttime, "   gone");
+-				sprintf(length, "- no logout");
++				snprintf(logouttime, sizeof(logouttime), "   gone");
++				snprintf(length, sizeof(length), "- no logout");
+ 			} else {
+ 				logouttime[0] = 0;
+-				sprintf(length, "no logout");
++				snprintf(length, sizeof(length), "no logout");
+ 			}
+ 			break;
+ 		case R_TIMECHANGE:
+@@ -508,15 +514,8 @@ static int list(const struct last_control *ctl, struct utmpx *p, time_t logout_t
+ 	r = -1;
+ 	if (ctl->usedns || ctl->useip)
+ 		r = dns_lookup(domain, sizeof(domain), ctl->useip, (int32_t*)p->ut_addr_v6);
+-	if (r < 0) {
+-		size_t sz = sizeof(p->ut_host);
+-
+-		if (sz > sizeof(domain))
+-			sz = sizeof(domain);
+-
+-		xstrncpy(domain, p->ut_host, sz);
+-	}
+-
++	if (r < 0)
++		mem2strcpy(domain, p->ut_host, sizeof(p->ut_host), sizeof(domain));
+ 
+ 	if (ctl->showhost) {
+ 		if (!ctl->altlist) {
+@@ -607,10 +606,11 @@ static int is_phantom(const struct last_control *ctl, struct utmpx *ut)
+ 
+ 	if (ut->ut_tv.tv_sec < ctl->boot_time.tv_sec)
+ 		return 1;
++	ut->ut_user[sizeof(ut->ut_user) - 1] = '\0';
+ 	pw = getpwnam(ut->ut_user);
+ 	if (!pw)
+ 		return 1;
+-	sprintf(path, "/proc/%u/loginuid", ut->ut_pid);
++	snprintf(path, sizeof(path), "/proc/%u/loginuid", ut->ut_pid);
+ 	if (access(path, R_OK) == 0) {
+ 		unsigned int loginuid;
+ 		FILE *f = NULL;
+@@ -624,8 +624,11 @@ static int is_phantom(const struct last_control *ctl, struct utmpx *ut)
+ 			return 1;
+ 	} else {
+ 		struct stat st;
++		char utline[sizeof(ut->ut_line) + 1];
++
++		mem2strcpy(utline, ut->ut_line, sizeof(ut->ut_line), sizeof(utline));
+ 
+-		sprintf(path, "/dev/%s", ut->ut_line);
++		snprintf(path, sizeof(path), "/dev/%s", utline);
+ 		if (stat(path, &st))
+ 			return 1;
+ 		if (pw->pw_uid != st.st_uid)
+@@ -736,7 +739,7 @@ static void process_wtmp_file(const struct last_control *ctl,
+ 		else {
+ 			if (ut.ut_type != DEAD_PROCESS &&
+ 			    ut.ut_user[0] && ut.ut_line[0] &&
+-			    strcmp(ut.ut_user, "LOGIN") != 0)
++			    strncmp(ut.ut_user, "LOGIN", 5) != 0)
+ 				ut.ut_type = USER_PROCESS;
+ 			/*
+ 			 * Even worse, applications that write ghost
+@@ -749,7 +752,7 @@ static void process_wtmp_file(const struct last_control *ctl,
+ 			/*
+ 			 * Clock changes.
+ 			 */
+-			if (strcmp(ut.ut_user, "date") == 0) {
++			if (strncmp(ut.ut_user, "date", 4) == 0) {
+ 				if (ut.ut_line[0] == '|')
+ 					ut.ut_type = OLD_TIME;
+ 				if (ut.ut_line[0] == '{')
+@@ -784,7 +787,7 @@ static void process_wtmp_file(const struct last_control *ctl,
+ 		case RUN_LVL:
+ 			x = ut.ut_pid & 255;
+ 			if (ctl->extended) {
+-				sprintf(ut.ut_line, "(to lvl %c)", x);
++				snprintf(ut.ut_line, sizeof(ut.ut_line), "(to lvl %c)", x);
+ 				quit = list(ctl, &ut, lastrch, R_NORMAL);
+ 			}
+ 			if (x == '0' || x == '6') {
+-- 
+2.39.1
+
diff --git a/SOURCES/0092-last-use-full-size-of-the-username.patch b/SOURCES/0092-last-use-full-size-of-the-username.patch
new file mode 100644
index 0000000..a676580
--- /dev/null
+++ b/SOURCES/0092-last-use-full-size-of-the-username.patch
@@ -0,0 +1,55 @@
+From f435f80b9ae88caf9fe8af2e9b705dc8296ad6f3 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Mon, 13 Feb 2023 16:22:23 +0100
+Subject: last: use full size of the username
+
+utmp uses 32 bytes for username, last(1) truncates it to 31 when calls getpwnam().
+
+Reported-by: Radka Skvarilova <rskvaril@redhat.com>
+Signed-off-by: Karel Zak <kzak@redhat.com>
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=2160321
+Upstream: http://github.com/util-linux/util-linux/commit/4b646f01600a5efcf16e8e8991010b49b250bdfe
+---
+ login-utils/last.1 | 4 ++++
+ login-utils/last.c | 6 ++++--
+ 2 files changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/login-utils/last.1 b/login-utils/last.1
+index 94b4ed012..9169abd35 100644
+--- a/login-utils/last.1
++++ b/login-utils/last.1
+@@ -178,6 +178,10 @@ files to be used, they can be created with a simple
+ .BR touch (1)
+ command (for example,
+ .IR "touch /var/log/wtmp" ).
++
++The utmp file format uses fixed sizes of strings, which means that very long strings are
++impossible to store in the file and impossible to display by last. The usual limits are 32
++bytes for a user and line name and 256 bytes for a hostname.
+ .SH FILES
+ /var/log/wtmp
+ .br
+diff --git a/login-utils/last.c b/login-utils/last.c
+index 8f7c36984..41ce03894 100644
+--- a/login-utils/last.c
++++ b/login-utils/last.c
+@@ -602,12 +602,14 @@ static int is_phantom(const struct last_control *ctl, struct utmpx *ut)
+ {
+ 	struct passwd *pw;
+ 	char path[sizeof(ut->ut_line) + 16];
++	char user[sizeof(ut->ut_user) + 1];
+ 	int ret = 0;
+ 
+ 	if (ut->ut_tv.tv_sec < ctl->boot_time.tv_sec)
+ 		return 1;
+-	ut->ut_user[sizeof(ut->ut_user) - 1] = '\0';
+-	pw = getpwnam(ut->ut_user);
++
++	mem2strcpy(user, ut->ut_user, sizeof(ut->ut_user), sizeof(user));
++	pw = getpwnam(user);
+ 	if (!pw)
+ 		return 1;
+ 	snprintf(path, sizeof(path), "/proc/%u/loginuid", ut->ut_pid);
+-- 
+2.39.1
+
diff --git a/SPECS/util-linux.spec b/SPECS/util-linux.spec
index 8a4c731..e0bd216 100644
--- a/SPECS/util-linux.spec
+++ b/SPECS/util-linux.spec
@@ -2,7 +2,7 @@
 Summary: A collection of basic system utilities
 Name: util-linux
 Version: 2.32.1
-Release: 38.1%{?dist}
+Release: 41.1%{?dist}
 License: GPLv2 and GPLv2+ and LGPLv2+ and BSD with advertising and Public Domain
 Group: System Environment/Base
 URL: http://en.wikipedia.org/wiki/Util-linux
@@ -261,6 +261,23 @@ Patch82: 0082-lslogins-improve-prefixes-interpretation.patch
 Patch83: 0083-tests-update-atari-blkid-tests.patch
 Patch84: 0084-tests-update-atari-partx-tests.patch
 
+### RHEL-8.8
+###
+# 2141969 - Add --cont-clock feature for libuuid and uuidd [rhel-8]
+Patch85: 0085-libuuid-Implement-continuous-clock-handling-for-time.patch
+Patch86: 0086-libuuid-check-clock-value-from-LIBUUID_CLOCK_FILE.patch
+# 2121699 - fstrim -av fails to trim root filesystem on Red Hat Coreos 
+Patch87: 0087-fstrim-backport-entries-de-duplication.patch
+# 2142496 - update upstream tests
+Patch88: 0088-tests-don-t-reply-on-scsi_debug-partitions.patch
+# 2149394 - umount outputs inaccurate error message when umount() fails with EACCES
+Patch89: 0089-libmount-use-generic-error-message-for-EACCES-on-umo.patch
+# 2159544 - lslogins "Password is locked" status changed in util-linux-2.32.1-38
+Patch90: 0090-lslogins-man-explain-password-statuses.patch
+# 2160321 - [last] ut->ut_user is not null terminated
+Patch91: 0091-last-sync-utmp-strings-use-with-upstream-code.patch
+Patch92: 0092-last-use-full-size-of-the-username.patch
+
 ### Hyperscale (1000-9999)
 ###
 Patch1000: 1000-setpriv-add-reset-env.patch
@@ -268,7 +285,6 @@ Patch1001: 1001-losetup-avoid-infinite-busy-loop.patch
 Patch1002: 1002-losetup-increase-limit-of-setup-attempts.patch
 Patch1003: 1003-lib-loopdev-perform-retry-on-EAGAIN.patch
 
-
 %description
 The util-linux package contains a large variety of low-level system
 utilities that are necessary for a Linux system to function. Among
@@ -1122,6 +1138,22 @@ fi
 %{_libdir}/python*/site-packages/libmount/
 
 %changelog
+* Sun Apr 02 2023 Davide Cavalca <dcavalca@centosproject.org> 2.32.1-41.1
+- Merge upstream changes for Hyperscale
+
+* Mon Feb 13 2023 Karel Zak <kzak@redhat.com> 2.32.1-41
+- improve #2160321 - [last] ut->ut_user is not null terminated
+
+* Mon Feb 06 2023 Karel Zak <kzak@redhat.com> 2.32.1-40
+- fix #2121699 - fstrim -av fails to trim root filesystem on Red Hat Coreos
+- fix #2142496 - update upstream tests
+- fix #2149394 - umount outputs inaccurate error message when umount() fails with EACCES
+- fix #2159544 - lslogins "Password is locked" status changed in util-linux-2.32.1-38
+- fix #2160321 - [last] ut->ut_user is not null terminated
+
+* Fri Nov 11 2022 Karel Zak <kzak@redhat.com> 2.32.1-39
+- fix #2141969 - Add --cont-clock feature for libuuid and uuidd
+
 * Wed Nov 02 2022 Anita Zhang <anitazha@fb.com> 2.32.1-38.1
 - Merge C8s upstream changes
 - Fix 1000-setpriv-add-reset-env.patch merge conflicts