diff options
| author | Filipe Manana <fdmanana@kernel.org> | 2023-08-17 10:20:13 +0100 |
|---|---|---|
| committer | Karel Zak <kzak@redhat.com> | 2023-08-17 11:44:51 +0200 |
| commit | 2b99ee2526ae61be761b0e31c50e106dbec5e9e4 (patch) | |
| tree | afe69314f24c8d29c9cb4365ad5e4b8ba0fcec12 /libmount/src | |
| parent | 71abc103429d22c76e577ac19af060328475453b (diff) | |
| download | util-linux-2b99ee2526ae61be761b0e31c50e106dbec5e9e4.tar.gz | |
libmount: Fix regression when mounting with atime
A regression was introduced in v2.39 that causes mounting with the atime
option to fail:
$ mkfs.ext4 -F /dev/sdi
$ mount -o atime /dev/sdi /mnt/sdi
mount: /mnt/sdi: not mount point or bad option.
dmesg(1) may have more information after failed mount system call.
The failure comes from the mount_setattr(2) call returning -EINVAL. This
is because we pass an invalid value for the attr_clr argument. From a
strace capture we have:
mount_setattr(4, "", AT_EMPTY_PATH, {attr_set=0, attr_clr=MOUNT_ATTR_NOATIME, propagation=0 /* MS_??? */, userns_fd=0}, 32) = -1 EINVAL (Invalid argument)
We can't pass MOUNT_ATTR_NOATIME to mount_setattr(2) through the attr_clr
argument because all atime options are exclusive, so in order to set atime
one has to pass MOUNT_ATTR__ATIME to attr_clr and leave attr_set as
MOUNT_ATTR_RELATIME (which is defined as a value of 0).
This can be read from the man page for mount_setattr(2) and also from the
kernel source:
$ cat fs/namespace.c
static int build_mount_kattr(const struct mount_attr *attr, size_t usize,
struct mount_kattr *kattr, unsigned int flags)
{
(...)
/*
* Since the MOUNT_ATTR_<atime> values are an enum, not a bitmap,
* users wanting to transition to a different atime setting cannot
* simply specify the atime setting in @attr_set, but must also
* specify MOUNT_ATTR__ATIME in the @attr_clr field.
* So ensure that MOUNT_ATTR__ATIME can't be partially set in
* @attr_clr and that @attr_set can't have any atime bits set if
* MOUNT_ATTR__ATIME isn't set in @attr_clr.
*/
if (attr->attr_clr & MOUNT_ATTR__ATIME) {
if ((attr->attr_clr & MOUNT_ATTR__ATIME) != MOUNT_ATTR__ATIME)
return -EINVAL;
/*
* Clear all previous time settings as they are mutually
* exclusive.
*/
kattr->attr_clr |= MNT_RELATIME | MNT_NOATIME;
switch (attr->attr_set & MOUNT_ATTR__ATIME) {
case MOUNT_ATTR_RELATIME:
kattr->attr_set |= MNT_RELATIME;
break;
case MOUNT_ATTR_NOATIME:
kattr->attr_set |= MNT_NOATIME;
break;
case MOUNT_ATTR_STRICTATIME:
break;
default:
return -EINVAL;
}
(...)
So fix this by setting attr_clr MOUNT_ATTR__ATIME if we want to clear any
atime related option.
Signed-off-by: Filipe Manana <fdmanana@kernel.org>
Diffstat (limited to 'libmount/src')
| -rw-r--r-- | libmount/src/optlist.c | 13 |
1 files changed, 12 insertions, 1 deletions
diff --git a/libmount/src/optlist.c b/libmount/src/optlist.c index e93810b47f..d0afc94f72 100644 --- a/libmount/src/optlist.c +++ b/libmount/src/optlist.c @@ -875,7 +875,18 @@ int mnt_optlist_get_attrs(struct libmnt_optlist *ls, uint64_t *set, uint64_t *cl if (opt->ent->mask & MNT_INVERT) { DBG(OPTLIST, ul_debugobj(ls, " clr: %s", opt->ent->name)); - *clr |= x; + /* + * All atime settings are mutually exclusive so *clr must + * have MOUNT_ATTR__ATIME set. + * + * See the function fs/namespace.c:build_mount_kattr() + * in the linux kernel source. + */ + if (x == MOUNT_ATTR_RELATIME || x == MOUNT_ATTR_NOATIME || + x == MOUNT_ATTR_STRICTATIME) + *clr |= MOUNT_ATTR__ATIME; + else + *clr |= x; } else { DBG(OPTLIST, ul_debugobj(ls, " set: %s", opt->ent->name)); *set |= x; |
