mirror of
https://github.com/systemd/systemd.git
synced 2024-10-30 23:21:22 +03:00
umount: Provide the same mount flags too when remounting read-only
This most likely amounts to no real benefits and is just here for completeness sake.
This commit is contained in:
parent
1d62d22d94
commit
3bc341bee9
@ -48,7 +48,8 @@
|
|||||||
|
|
||||||
typedef struct MountPoint {
|
typedef struct MountPoint {
|
||||||
char *path;
|
char *path;
|
||||||
char *options;
|
char *remount_options;
|
||||||
|
unsigned long remount_flags;
|
||||||
bool try_remount_ro;
|
bool try_remount_ro;
|
||||||
dev_t devnum;
|
dev_t devnum;
|
||||||
LIST_FIELDS(struct MountPoint, mount_point);
|
LIST_FIELDS(struct MountPoint, mount_point);
|
||||||
@ -61,7 +62,7 @@ static void mount_point_free(MountPoint **head, MountPoint *m) {
|
|||||||
LIST_REMOVE(mount_point, *head, m);
|
LIST_REMOVE(mount_point, *head, m);
|
||||||
|
|
||||||
free(m->path);
|
free(m->path);
|
||||||
free(m->options);
|
free(m->remount_options);
|
||||||
free(m);
|
free(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,7 +85,7 @@ static int mount_points_list_get(MountPoint **head) {
|
|||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
for (i = 1;; i++) {
|
for (i = 1;; i++) {
|
||||||
_cleanup_free_ char *path = NULL, *options = NULL, *type = NULL, *p = NULL;
|
_cleanup_free_ char *path = NULL, *options = NULL, *flags = NULL, *type = NULL, *p = NULL;
|
||||||
MountPoint *m;
|
MountPoint *m;
|
||||||
int k;
|
int k;
|
||||||
|
|
||||||
@ -94,15 +95,15 @@ static int mount_points_list_get(MountPoint **head) {
|
|||||||
"%*s " /* (3) major:minor */
|
"%*s " /* (3) major:minor */
|
||||||
"%*s " /* (4) root */
|
"%*s " /* (4) root */
|
||||||
"%ms " /* (5) mount point */
|
"%ms " /* (5) mount point */
|
||||||
"%*s" /* (6) mount flags */
|
"%ms" /* (6) mount flags */
|
||||||
"%*[^-]" /* (7) optional fields */
|
"%*[^-]" /* (7) optional fields */
|
||||||
"- " /* (8) separator */
|
"- " /* (8) separator */
|
||||||
"%ms " /* (9) file system type */
|
"%ms " /* (9) file system type */
|
||||||
"%*s" /* (10) mount source */
|
"%*s" /* (10) mount source */
|
||||||
"%ms" /* (11) mount options */
|
"%ms" /* (11) mount options */
|
||||||
"%*[^\n]", /* some rubbish at the end */
|
"%*[^\n]", /* some rubbish at the end */
|
||||||
&path, &type, &options);
|
&path, &flags, &type, &options);
|
||||||
if (k != 3) {
|
if (k != 4) {
|
||||||
if (k == EOF)
|
if (k == EOF)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -132,6 +133,8 @@ static int mount_points_list_get(MountPoint **head) {
|
|||||||
if (!m)
|
if (!m)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
free_and_replace(m->path, p);
|
||||||
|
|
||||||
/* If we are in a container, don't attempt to
|
/* If we are in a container, don't attempt to
|
||||||
* read-only mount anything as that brings no real
|
* read-only mount anything as that brings no real
|
||||||
* benefits, but might confuse the host, as we remount
|
* benefits, but might confuse the host, as we remount
|
||||||
@ -146,8 +149,28 @@ static int mount_points_list_get(MountPoint **head) {
|
|||||||
!fstype_is_network(type) &&
|
!fstype_is_network(type) &&
|
||||||
!fstab_test_yes_no_option(options, "ro\0rw\0");
|
!fstab_test_yes_no_option(options, "ro\0rw\0");
|
||||||
|
|
||||||
free_and_replace(m->path, p);
|
if (m->try_remount_ro) {
|
||||||
free_and_replace(m->options, options);
|
_cleanup_free_ char *unknown_flags = NULL;
|
||||||
|
|
||||||
|
/* mount(2) states that mount flags and options need to be exactly the same
|
||||||
|
* as they were when the filesystem was mounted, except for the desired
|
||||||
|
* changes. So we reconstruct both here and adjust them for the later
|
||||||
|
* remount call too. */
|
||||||
|
|
||||||
|
r = mount_option_mangle(flags, 0, &m->remount_flags, &unknown_flags);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (!isempty(unknown_flags))
|
||||||
|
log_warning("Ignoring unknown mount flags '%s'.", unknown_flags);
|
||||||
|
|
||||||
|
r = mount_option_mangle(options, m->remount_flags, &m->remount_flags, &m->remount_options);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
/* MS_BIND is special. If it is provided it will only make the mount-point
|
||||||
|
* read-only. If left out, the super block itself is remounted, which we want. */
|
||||||
|
m->remount_flags = (m->remount_flags|MS_REMOUNT|MS_RDONLY) & ~MS_BIND;
|
||||||
|
}
|
||||||
|
|
||||||
LIST_PREPEND(mount_point, *head, m);
|
LIST_PREPEND(mount_point, *head, m);
|
||||||
}
|
}
|
||||||
@ -389,14 +412,13 @@ static bool nonunmountable_path(const char *path) {
|
|||||||
|| path_startswith(path, "/run/initramfs");
|
|| path_startswith(path, "/run/initramfs");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int remount_with_timeout(MountPoint *m, char *options) {
|
static int remount_with_timeout(MountPoint *m) {
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
BLOCK_SIGNALS(SIGCHLD);
|
BLOCK_SIGNALS(SIGCHLD);
|
||||||
|
|
||||||
assert(m);
|
assert(m);
|
||||||
assert(options);
|
|
||||||
|
|
||||||
/* Due to the possiblity of a remount operation hanging, we
|
/* Due to the possiblity of a remount operation hanging, we
|
||||||
* fork a child process and set a timeout. If the timeout
|
* fork a child process and set a timeout. If the timeout
|
||||||
@ -406,10 +428,10 @@ static int remount_with_timeout(MountPoint *m, char *options) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
if (r == 0) {
|
if (r == 0) {
|
||||||
log_info("Remounting '%s' read-only in with options '%s'.", m->path, options);
|
log_info("Remounting '%s' read-only in with options '%s'.", m->path, m->remount_options);
|
||||||
|
|
||||||
/* Start the mount operation here in the child */
|
/* Start the mount operation here in the child */
|
||||||
r = mount(NULL, m->path, NULL, MS_REMOUNT|MS_RDONLY, options);
|
r = mount(NULL, m->path, NULL, m->remount_flags, m->remount_options);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_error_errno(errno, "Failed to remount '%s' read-only: %m", m->path);
|
log_error_errno(errno, "Failed to remount '%s' read-only: %m", m->path);
|
||||||
|
|
||||||
@ -474,7 +496,6 @@ static int umount_with_timeout(MountPoint *m) {
|
|||||||
|
|
||||||
/* This includes remounting readonly, which changes the kernel mount options.
|
/* This includes remounting readonly, which changes the kernel mount options.
|
||||||
* Therefore the list passed to this function is invalidated, and should not be reused. */
|
* Therefore the list passed to this function is invalidated, and should not be reused. */
|
||||||
|
|
||||||
static int mount_points_list_umount(MountPoint **head, bool *changed) {
|
static int mount_points_list_umount(MountPoint **head, bool *changed) {
|
||||||
MountPoint *m;
|
MountPoint *m;
|
||||||
int n_failed = 0;
|
int n_failed = 0;
|
||||||
@ -484,14 +505,6 @@ static int mount_points_list_umount(MountPoint **head, bool *changed) {
|
|||||||
|
|
||||||
LIST_FOREACH(mount_point, m, *head) {
|
LIST_FOREACH(mount_point, m, *head) {
|
||||||
if (m->try_remount_ro) {
|
if (m->try_remount_ro) {
|
||||||
_cleanup_free_ char *options = NULL;
|
|
||||||
/* MS_REMOUNT requires that the data parameter
|
|
||||||
* should be the same from the original mount
|
|
||||||
* except for the desired changes. Since we want
|
|
||||||
* to remount read-only, we should filter out
|
|
||||||
* rw (and ro too, because it confuses the kernel) */
|
|
||||||
(void) fstab_filter_options(m->options, "rw\0ro\0", NULL, NULL, &options);
|
|
||||||
|
|
||||||
/* We always try to remount directories
|
/* We always try to remount directories
|
||||||
* read-only first, before we go on and umount
|
* read-only first, before we go on and umount
|
||||||
* them.
|
* them.
|
||||||
@ -512,7 +525,7 @@ static int mount_points_list_umount(MountPoint **head, bool *changed) {
|
|||||||
* Since the remount can hang in the instance of
|
* Since the remount can hang in the instance of
|
||||||
* remote filesystems, we remount asynchronously
|
* remote filesystems, we remount asynchronously
|
||||||
* and skip the subsequent umount if it fails */
|
* and skip the subsequent umount if it fails */
|
||||||
if (remount_with_timeout(m, options) < 0) {
|
if (remount_with_timeout(m) < 0) {
|
||||||
if (nonunmountable_path(m->path))
|
if (nonunmountable_path(m->path))
|
||||||
n_failed++;
|
n_failed++;
|
||||||
continue;
|
continue;
|
||||||
|
Loading…
Reference in New Issue
Block a user