X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fumount.c;h=24c0947f2172c624f76940ab7faf5b7af2897430;hp=4fd6b22ad78620e3585985b0a3f9a19989a827b3;hb=5430f7f2bc7330f3088b894166bf3524a067e3d8;hpb=7fc942b29e7bdb9d6aa3123f53da6680edabd8f0 diff --git a/src/umount.c b/src/umount.c index 4fd6b22ad..24c0947f2 100644 --- a/src/umount.c +++ b/src/umount.c @@ -6,16 +6,16 @@ Copyright 2010 ProFUSION embedded systems systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ @@ -37,6 +37,7 @@ typedef struct MountPoint { char *path; dev_t devnum; + bool skip_ro; LIST_FIELDS (struct MountPoint, mount_point); } MountPoint; @@ -71,6 +72,8 @@ static int mount_points_list_get(MountPoint **head) { for (i = 1;; i++) { int k; MountPoint *m; + char *root; + bool skip_ro; path = p = NULL; @@ -78,7 +81,7 @@ static int mount_points_list_get(MountPoint **head) { "%*s " /* (1) mount id */ "%*s " /* (2) parent id */ "%*s " /* (3) major:minor */ - "%*s " /* (4) root */ + "%ms " /* (4) root */ "%ms " /* (5) mount point */ "%*s" /* (6) mount options */ "%*[^-]" /* (7) optional fields */ @@ -87,7 +90,8 @@ static int mount_points_list_get(MountPoint **head) { "%*s" /* (10) mount source */ "%*s" /* (11) mount options 2 */ "%*[^\n]", /* some rubbish at the end */ - &path)) != 1) { + &root, + &path)) != 2) { if (k == EOF) break; @@ -97,6 +101,11 @@ static int mount_points_list_get(MountPoint **head) { continue; } + /* If we encounter a bind mount, don't try to remount + * the source dir too early */ + skip_ro = !streq(root, "/"); + free(root); + p = cunescape(path); free(path); @@ -117,6 +126,7 @@ static int mount_points_list_get(MountPoint **head) { } m->path = p; + m->skip_ro = skip_ro; LIST_PREPEND(MountPoint, mount_point, *head, m); } @@ -136,7 +146,7 @@ static int swap_list_get(MountPoint **head) { assert(head); if (!(proc_swaps = fopen("/proc/swaps", "re"))) - return -errno; + return (errno == ENOENT) ? 0 : -errno; (void) fscanf(proc_swaps, "%*s %*s %*s %*s %*s\n"); @@ -355,7 +365,7 @@ static int delete_loopback(const char *device) { int fd, r; if ((fd = open(device, O_RDONLY|O_CLOEXEC)) < 0) - return -errno; + return errno == ENOENT ? 0 : -errno; r = ioctl(fd, LOOP_CLR_FD, 0); close_nointr_nofail(fd); @@ -393,25 +403,30 @@ static int delete_dm(dev_t devnum) { return r >= 0 ? 0 : -errno; } -static int mount_points_list_umount(MountPoint **head, bool *changed) { +static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_error) { MountPoint *m, *n; int n_failed = 0; assert(head); LIST_FOREACH_SAFE(mount_point, m, n, *head) { - if (streq(m->path, "/")) { + if (path_equal(m->path, "/") +#ifndef HAVE_SPLIT_USR + || path_equal(m->path, "/usr") +#endif + ) { n_failed++; continue; } /* Trying to umount. Forcing to umount if busy (only for NFS mounts) */ if (umount2(m->path, MNT_FORCE) == 0) { + log_info("Unmounted %s.", m->path); if (changed) *changed = true; mount_point_free(head, m); - } else { + } else if (log_error) { log_warning("Could not unmount %s: %m", m->path); n_failed++; } @@ -428,6 +443,11 @@ static int mount_points_list_remount_read_only(MountPoint **head, bool *changed) LIST_FOREACH_SAFE(mount_point, m, n, *head) { + if (m->skip_ro) { + n_failed++; + continue; + } + /* Trying to remount read-only */ if (mount(NULL, m->path, NULL, MS_MGC_VAL|MS_REMOUNT|MS_RDONLY, NULL) == 0) { if (changed) @@ -536,6 +556,8 @@ static int dm_points_list_detach(MountPoint **head, bool *changed) { int umount_all(bool *changed) { int r; + bool umount_changed; + LIST_HEAD(MountPoint, mp_list_head); LIST_HEAD_INIT(MountPoint, mp_list_head); @@ -544,7 +566,18 @@ int umount_all(bool *changed) { if (r < 0) goto end; - r = mount_points_list_umount(&mp_list_head, changed); + /* retry umount, until nothing can be umounted anymore */ + do { + umount_changed = false; + + mount_points_list_umount(&mp_list_head, &umount_changed, false); + if (umount_changed) + *changed = true; + + } while (umount_changed); + + /* umount one more time with logging enabled */ + r = mount_points_list_umount(&mp_list_head, &umount_changed, true); if (r <= 0) goto end;