From 16f25ffc54770b552921cc99c22f3c4b069dedcd Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Tue, 1 Sep 2020 12:45:28 +0200 Subject: [PATCH] 2.36-3: remove libmount mountinfo workaround --- ...unt-remove-read-mountinfo-workaround.patch | 396 ++++++++++++++++++ util-linux.spec | 8 +- 2 files changed, 403 insertions(+), 1 deletion(-) create mode 100644 libmount-remove-read-mountinfo-workaround.patch diff --git a/libmount-remove-read-mountinfo-workaround.patch b/libmount-remove-read-mountinfo-workaround.patch new file mode 100644 index 0000000..38f8e34 --- /dev/null +++ b/libmount-remove-read-mountinfo-workaround.patch @@ -0,0 +1,396 @@ +From 57898c3a7ee8fc5933cddd4526bb3980bef85a02 Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Tue, 1 Sep 2020 10:15:14 +0200 +Subject: [PATCH] libmount: remove read-mountinfo workaround + +This workaround has been introduced by +http://github.com/karelzak/util-linux/commit/e4925f591c1bfb83719418b56b952830d15b77eb + +And originally requested by https://github.com/systemd/systemd/issues/10872 + +It seems we do not need it anymore as the problem should be fixed in kernel since 5.8 +(kernel commit 9f6c61f96f2d97cbb5f7fa85607bc398f843ff0f). + +Note that the libmount solution is very expensive as it repeats read() +many times (until we get consistent result) if kernel is busy with +mount table modification. This behaviour makes events management in +systemd (or other places) pretty difficult as read mountinfo takes +time on busy systems. + +Addresses: https://github.com/systemd/systemd/pull/16537 +Signed-off-by: Karel Zak +--- + configure.ac | 1 - + libmount/src/mountP.h | 2 - + libmount/src/tab_parse.c | 87 ++++---------------- + libmount/src/utils.c | 166 --------------------------------------- + 4 files changed, 15 insertions(+), 241 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 2d178f3af..1e31ca3e2 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -504,7 +504,6 @@ AC_CHECK_FUNCS([ \ + err \ + errx \ + explicit_bzero \ +- fmemopen \ + fsync \ + utimensat \ + getdomainname \ +diff --git a/libmount/src/mountP.h b/libmount/src/mountP.h +index d8ba0abad..ee97c6b4a 100644 +--- a/libmount/src/mountP.h ++++ b/libmount/src/mountP.h +@@ -98,7 +98,6 @@ extern int mnt_valid_tagname(const char *tagname); + extern int append_string(char **a, const char *b); + + extern const char *mnt_statfs_get_fstype(struct statfs *vfs); +-extern int is_procfs_fd(int fd); + extern int is_file_empty(const char *name); + + extern int mnt_is_readonly(const char *path) +@@ -124,7 +123,6 @@ extern void mnt_free_filesystems(char **filesystems); + extern char *mnt_get_kernel_cmdline_option(const char *name); + extern int mnt_stat_mountpoint(const char *target, struct stat *st); + extern int mnt_lstat_mountpoint(const char *target, struct stat *st); +-extern FILE *mnt_get_procfs_memstream(int fd, char **membuf); + + /* tab.c */ + extern int is_mountinfo(struct libmnt_table *tb); +diff --git a/libmount/src/tab_parse.c b/libmount/src/tab_parse.c +index 329987bcb..ac12dce54 100644 +--- a/libmount/src/tab_parse.c ++++ b/libmount/src/tab_parse.c +@@ -694,7 +694,15 @@ static int kernel_fs_postparse(struct libmnt_table *tb, + return rc; + } + +-static int __table_parse_stream(struct libmnt_table *tb, FILE *f, const char *filename) ++/** ++ * mnt_table_parse_stream: ++ * @tb: tab pointer ++ * @f: file stream ++ * @filename: filename used for debug and error messages ++ * ++ * Returns: 0 on success, negative number in case of error. ++ */ ++int mnt_table_parse_stream(struct libmnt_table *tb, FILE *f, const char *filename) + { + int rc = -1; + int flags = 0; +@@ -773,40 +781,6 @@ err: + return rc; + } + +-/** +- * mnt_table_parse_stream: +- * @tb: tab pointer +- * @f: file stream +- * @filename: filename used for debug and error messages +- * +- * Returns: 0 on success, negative number in case of error. +- */ +-int mnt_table_parse_stream(struct libmnt_table *tb, FILE *f, const char *filename) +-{ +- int fd, rc; +- FILE *memf = NULL; +- char *membuf = NULL; +- +- /* +- * For /proc/#/{mountinfo,mount} we read all file to memory and use it +- * as memory stream. For more details see mnt_read_procfs_file(). +- */ +- if ((fd = fileno(f)) >= 0 +- && (tb->fmt == MNT_FMT_GUESS || +- tb->fmt == MNT_FMT_MOUNTINFO || +- tb->fmt == MNT_FMT_MTAB) +- && is_procfs_fd(fd) +- && (memf = mnt_get_procfs_memstream(fd, &membuf))) { +- +- rc = __table_parse_stream(tb, memf, filename); +- fclose(memf); +- free(membuf); +- } else +- rc = __table_parse_stream(tb, f, filename); +- +- return rc; +-} +- + /** + * mnt_table_parse_file: + * @tb: tab pointer +@@ -822,49 +796,18 @@ int mnt_table_parse_stream(struct libmnt_table *tb, FILE *f, const char *filenam + int mnt_table_parse_file(struct libmnt_table *tb, const char *filename) + { + FILE *f; +- int rc, fd = -1; ++ int rc; + + if (!filename || !tb) + return -EINVAL; + +- /* +- * Try to use read()+poll() to realiably read all +- * /proc/#/{mount,mountinfo} file to memory +- */ +- if (tb->fmt != MNT_FMT_SWAPS +- && strncmp(filename, "/proc/", 6) == 0) { +- +- FILE *memf; +- char *membuf = NULL; +- +- fd = open(filename, O_RDONLY|O_CLOEXEC); +- if (fd < 0) { +- rc = -errno; +- goto done; +- } +- memf = mnt_get_procfs_memstream(fd, &membuf); +- if (memf) { +- rc = __table_parse_stream(tb, memf, filename); +- +- fclose(memf); +- free(membuf); +- close(fd); +- goto done; +- } +- /* else fallback to fopen/fdopen() */ +- } +- +- if (fd >= 0) +- f = fdopen(fd, "r" UL_CLOEXECSTR); +- else +- f = fopen(filename, "r" UL_CLOEXECSTR); +- ++ f = fopen(filename, "r" UL_CLOEXECSTR); + if (f) { +- rc = __table_parse_stream(tb, f, filename); ++ rc = mnt_table_parse_stream(tb, f, filename); + fclose(f); + } else + rc = -errno; +-done: ++ + DBG(TAB, ul_debugobj(tb, "parsing done [filename=%s, rc=%d]", filename, rc)); + return rc; + } +@@ -921,7 +864,7 @@ static int __mnt_table_parse_dir(struct libmnt_table *tb, const char *dirname) + + f = fopen_at(dd, d->d_name, O_RDONLY|O_CLOEXEC, "r" UL_CLOEXECSTR); + if (f) { +- __table_parse_stream(tb, f, d->d_name); ++ mnt_table_parse_stream(tb, f, d->d_name); + fclose(f); + } + } +@@ -962,7 +905,7 @@ static int __mnt_table_parse_dir(struct libmnt_table *tb, const char *dirname) + f = fopen_at(dirfd(dir), d->d_name, + O_RDONLY|O_CLOEXEC, "r" UL_CLOEXECSTR); + if (f) { +- __table_parse_stream(tb, f, d->d_name); ++ mnt_table_parse_stream(tb, f, d->d_name); + fclose(f); + } + } +diff --git a/libmount/src/utils.c b/libmount/src/utils.c +index 92829ebb0..40b45f11d 100644 +--- a/libmount/src/utils.c ++++ b/libmount/src/utils.c +@@ -19,7 +19,6 @@ + #include + #include + #include +-#include + #include + + #include "strutils.h" +@@ -448,13 +447,6 @@ const char *mnt_statfs_get_fstype(struct statfs *vfs) + return NULL; + } + +-int is_procfs_fd(int fd) +-{ +- struct statfs sfs; +- +- return fstatfs(fd, &sfs) == 0 && sfs.f_type == STATFS_PROC_MAGIC; +-} +- + /** + * mnt_match_fstype: + * @type: filesystem type +@@ -1174,164 +1166,7 @@ done: + return 1; + } + +-#if defined(HAVE_FMEMOPEN) || defined(TEST_PROGRAM) +- +-/* +- * This function tries to minimize possible races when we read +- * /proc/#/{mountinfo,mount} files. +- * +- * The idea is to minimize number of read()s and check by poll() that during +- * the read the mount table has not been modified. If yes, than re-read it +- * (with some limitations to avoid never ending loop). +- * +- * Returns: <0 error, 0 success, 1 too many attempts +- */ +-static int read_procfs_file(int fd, char **buf, size_t *bufsiz) +-{ +- size_t bufmax = 0; +- int rc = 0, tries = 0, ninters = 0; +- char *bufptr = NULL; +- +- assert(buf); +- assert(bufsiz); +- +- *bufsiz = 0; +- *buf = NULL; +- +- do { +- ssize_t ret; +- +- if (!bufptr || bufmax == *bufsiz) { +- char *tmp; +- +- bufmax = bufmax ? bufmax * 2 : (16 * 1024); +- tmp = realloc(*buf, bufmax); +- if (!tmp) +- break; +- *buf = tmp; +- bufptr = tmp + *bufsiz; +- } +- +- errno = 0; +- ret = read(fd, bufptr, bufmax - *bufsiz); +- +- if (ret < 0) { +- /* error */ +- if ((errno == EAGAIN || errno == EINTR) && (ninters++ < 5)) { +- xusleep(200000); +- continue; +- } +- break; +- +- } if (ret > 0) { +- /* success -- verify no event during read */ +- struct pollfd fds[] = { +- { .fd = fd, .events = POLLPRI } +- }; +- +- rc = poll(fds, 1, 0); +- if (rc < 0) +- break; /* poll() error */ +- if (rc > 0) { +- /* event -- read all again */ +- if (lseek(fd, 0, SEEK_SET) != 0) +- break; +- *bufsiz = 0; +- bufptr = *buf; +- tries++; +- +- if (tries > 10) +- /* busy system? -- wait */ +- xusleep(10000); +- continue; +- } +- +- /* successful read() without active poll() */ +- (*bufsiz) += (size_t) ret; +- bufptr += ret; +- tries = ninters = 0; +- } else { +- /* end-of-file */ +- goto success; +- } +- } while (tries <= 100); +- +- rc = errno ? -errno : 1; +- free(*buf); +- return rc; +- +-success: +- return 0; +-} +- +-/* +- * Create FILE stream for data from read_procfs_file() +- */ +-FILE *mnt_get_procfs_memstream(int fd, char **membuf) +-{ +- size_t sz = 0; +- off_t cur; +- +- *membuf = NULL; +- +- /* in case of error, rewind to the original position */ +- cur = lseek(fd, 0, SEEK_CUR); +- +- if (read_procfs_file(fd, membuf, &sz) == 0 && sz > 0) { +- FILE *memf = fmemopen(*membuf, sz, "r"); +- if (memf) +- return memf; /* success */ +- +- free(*membuf); +- *membuf = NULL; +- } +- +- /* error */ +- if (cur != (off_t) -1) +- lseek(fd, cur, SEEK_SET); +- return NULL; +-} +-#else +-FILE *mnt_get_procfs_memstream(int fd __attribute((__unused__)), +- char **membuf __attribute((__unused__))) +-{ +- return NULL; +-} +-#endif /* HAVE_FMEMOPEN */ +- +- + #ifdef TEST_PROGRAM +-static int test_proc_read(struct libmnt_test *ts, int argc, char *argv[]) +-{ +- char *buf = NULL; +- char *filename = argv[1]; +- size_t bufsiz = 0; +- int rc = 0, fd = open(filename, O_RDONLY); +- +- if (fd <= 0) { +- warn("%s: cannot open", filename); +- return -errno; +- } +- +- rc = read_procfs_file(fd, &buf, &bufsiz); +- close(fd); +- +- switch (rc) { +- case 0: +- fwrite(buf, 1, bufsiz, stdout); +- free(buf); +- break; +- case 1: +- warnx("too many attempts"); +- break; +- default: +- warn("%s: cannot read", filename); +- break; +- } +- +- return rc; +-} +- + static int test_match_fstype(struct libmnt_test *ts, int argc, char *argv[]) + { + char *type = argv[1]; +@@ -1513,7 +1348,6 @@ int main(int argc, char *argv[]) + { "--guess-root", test_guess_root, "[]" }, + { "--mkdir", test_mkdir, "" }, + { "--statfs-type", test_statfs_type, "" }, +- { "--read-procfs", test_proc_read, "" }, + + { NULL } + }; +-- +2.25.4 + diff --git a/util-linux.spec b/util-linux.spec index 6e0006b..9819085 100644 --- a/util-linux.spec +++ b/util-linux.spec @@ -2,7 +2,7 @@ Summary: A collection of basic system utilities Name: util-linux Version: 2.36 -Release: 2%{?dist} +Release: 3%{?dist} License: GPLv2 and GPLv2+ and LGPLv2+ and BSD with advertising and Public Domain URL: http://en.wikipedia.org/wiki/Util-linux @@ -101,6 +101,9 @@ Requires: libfdisk = %{version}-%{release} ### # 151635 - makeing /var/log/lastlog Patch0: 2.36-login-lastlog-create.patch +# https://github.com/karelzak/util-linux/commit/57898c3a7ee8fc5933cddd4526bb3980bef85a02 +# The workaround is unnecessary on Fedora with kernel >= 5.8. +Patch1: libmount-remove-read-mountinfo-workaround.patch %description The util-linux package contains a large variety of low-level system @@ -933,6 +936,9 @@ fi %{_libdir}/python*/site-packages/libmount/ %changelog +* Tue Sep 01 2020 Karel Zak - 2.36-3 +- remove mountinfo workaround (unnecessary for kernel 5.8) + * Wed Jul 29 2020 Fedora Release Engineering - 2.36-2 - Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild