Skip to content

Commit 542e525

Browse files
committed
ostree-remount: improve do_remount(), use warn()
When we remount read only, we only want to change the vfs read only flag, not the fs one, so use MS_BIND. On the contrary when we remount read write, we want to change both (already ok). To check that we can write, we now use 'access'. Except when using old mount versions, we should never need do_remount(), as everything should have been properly setup by prepare-root, so start to warn() when we actually remounted /sysroot or /etc.
1 parent c169a7d commit 542e525

4 files changed

Lines changed: 41 additions & 25 deletions

File tree

src/switchroot/ostree-remount.c

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
#include "otcore.h"
4444

4545
static void
46-
do_remount (const char *target, bool writable)
46+
do_remount (const char *target, bool writable, bool use_warn)
4747
{
4848
struct stat stbuf;
4949
if (lstat (target, &stbuf) < 0)
@@ -53,18 +53,27 @@ do_remount (const char *target, bool writable)
5353
*/
5454
if (S_ISLNK (stbuf.st_mode))
5555
return;
56-
/* If not a mountpoint, skip it */
56+
5757
struct statvfs stvfsbuf;
5858
if (statvfs (target, &stvfsbuf) == -1)
59-
return;
59+
err (EXIT_FAILURE, "failed to statvfs(%s)", target);
6060

61-
const bool currently_writable = ((stvfsbuf.f_flag & ST_RDONLY) == 0);
62-
if (writable == currently_writable)
63-
return;
61+
if (writable)
62+
{
63+
// vfs could be 'rw' but fs 'ro', so use access to check
64+
if (access (target, W_OK) == 0)
65+
return;
66+
}
67+
else
68+
{
69+
// ensure vfs 'ro' mount flags is set even if fs is ro
70+
if ((stvfsbuf.f_flag & ST_RDONLY) != 0)
71+
return;
72+
}
6473

6574
int mnt_flags = MS_REMOUNT | MS_SILENT;
6675
if (!writable)
67-
mnt_flags |= MS_RDONLY;
76+
mnt_flags |= MS_BIND | MS_RDONLY;
6877
if (mount (target, target, NULL, mnt_flags, NULL) < 0)
6978
{
7079
/* Also ignore EINVAL - if the target isn't a mountpoint
@@ -76,7 +85,10 @@ do_remount (const char *target, bool writable)
7685
return;
7786
}
7887

79-
printf ("Remounted %s: %s\n", writable ? "rw" : "ro", target);
88+
if (use_warn)
89+
warn ("Remounted %s: %s\n", writable ? "rw" : "ro", target);
90+
else
91+
printf ("Remounted %s: %s\n", writable ? "rw" : "ro", target);
8092
}
8193

8294
/* Relabel the directory $real_path, which is going to be an overlayfs mount,
@@ -226,29 +238,25 @@ main (int argc, char *argv[])
226238
}
227239

228240
/* Handle remounting /sysroot; if it's explicitly marked as read-only (opt in)
229-
* then ensure it's readonly, otherwise mount writable, the same as /
241+
* then ensure it's readonly, otherwise remount writable, the same as /
242+
* We should not need this so warn when we do remount.
230243
*/
231244
gboolean sysroot_configured_readonly = FALSE;
232245
g_variant_dict_lookup (ostree_run_metadata, OTCORE_RUN_BOOTED_KEY_SYSROOT_RO, "b",
233246
&sysroot_configured_readonly);
234-
do_remount ("/sysroot", !sysroot_configured_readonly);
247+
do_remount ("/sysroot", !sysroot_configured_readonly, true);
235248

236-
/* And also make sure to make /etc rw again. We make this conditional on
237-
* sysroot_configured_readonly && !transient_etc because only in that case is it a
238-
* bind-mount. */
249+
/* Make sure /etc is 'rw'. We make this conditional on sysroot_configured_readonly
250+
* && !transient_etc because only in that case is it a bind-mount.
251+
* We should not need this so warn when we do remount.
252+
*/
239253
if (sysroot_configured_readonly && !transient_etc)
240-
do_remount ("/etc", true);
241-
242-
/* If /var was created as as an OSTree default bind mount (instead of being a separate
243-
* filesystem) then remounting the root mount read-only also remounted it. So just like /etc, we
244-
* need to make it read-write by default. If it was a separate filesystem, we expect it to be
245-
* writable anyways, so it doesn't hurt to remount it if so.
246-
*
247-
* And if we started out with a writable system root, then we need
248-
* to ensure that the /var bind mount created by the systemd generator
249-
* is writable too.
254+
do_remount ("/etc", true, true);
255+
256+
/* If mount uses the legacy mount API (before util-linux 2.39), then the 'rw'
257+
* mount option in the 'var.mount' unit is ignored, so we need to remount here.
250258
*/
251-
do_remount ("/var", true);
259+
do_remount ("/var", true, false);
252260

253261
exit (EXIT_SUCCESS);
254262
}

tests/kolainst/destructive/root-transient-ro.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ EOF
3636

3737
test '!' -w '/'
3838

39+
journalctl -u ostree-remount.service -o cat > /tmp/ostree-remount.logs
40+
assert_not_file_has_content /tmp/ostree-remount.logs Remount
41+
3942
echo "ok root transient-ro"
4043
;;
4144
*)

tests/kolainst/destructive/soft-reboot.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,9 @@ case "${AUTOPKGTEST_REBOOT_MARK:-}" in
156156
fi
157157
assert_file_has_content_literal err.txt "different kernel state"
158158

159+
journalctl -u ostree-remount.service -o cat > /tmp/ostree-remount.logs
160+
assert_not_file_has_content /tmp/ostree-remount.logs Remount
161+
159162
echo "ok soft reboot all tests"
160163
;;
161164
*)

tests/kolainst/destructive/var-mount.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@ case "${AUTOPKGTEST_REBOOT_MARK:-}" in
88
"")
99
touch "/var/somenewfile"
1010
stateroot=$(ostree admin status 2> /dev/null | grep '^\*' | cut -d ' ' -f2 || true)
11-
echo "/sysroot/ostree/deploy/${stateroot}/var /var none bind 0 0" >> /etc/fstab
11+
echo "/sysroot/ostree/deploy/${stateroot}/var /var none bind,rw 0 0" >> /etc/fstab
1212
/tmp/autopkgtest-reboot "2"
1313
;;
1414
"2")
1515
systemctl status var.mount
1616
test -f /var/somenewfile
17+
journalctl -u ostree-remount.service -o cat > /tmp/ostree-remount.logs
18+
assert_not_file_has_content /tmp/ostree-remount.logs Remount
1719
;;
1820
*) fatal "Unexpected AUTOPKGTEST_REBOOT_MARK=${AUTOPKGTEST_REBOOT_MARK}" ;;
1921
esac

0 commit comments

Comments
 (0)