summaryrefslogtreecommitdiffstats
path: root/sys-utils/umount.c
diff options
context:
space:
mode:
authorKarel Zak2012-11-15 16:44:07 +0100
committerKarel Zak2012-11-15 16:44:07 +0100
commitae978c4d6ca376bdab6398e635be1664be370ffa (patch)
tree890bd3c6e1818b5efa028e7ff7e7bbaaf4f5922c /sys-utils/umount.c
parenttests: add shared subtrees to umount --recursive test (diff)
downloadkernel-qcow2-util-linux-ae978c4d6ca376bdab6398e635be1664be370ffa.tar.gz
kernel-qcow2-util-linux-ae978c4d6ca376bdab6398e635be1664be370ffa.tar.xz
kernel-qcow2-util-linux-ae978c4d6ca376bdab6398e635be1664be370ffa.zip
umount: (recursive) don't call umount(2) for already unmounted targets
In the umount --recursive we follow entries from mountinfo, but the entries maybe already obsolete. Especially if the hierarchy of the mountpoints contains shared subtrees and umount(2) for one entry may generate umount for some other entry too. Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'sys-utils/umount.c')
-rw-r--r--sys-utils/umount.c38
1 files changed, 31 insertions, 7 deletions
diff --git a/sys-utils/umount.c b/sys-utils/umount.c
index 1cd2ebf67..b21e39674 100644
--- a/sys-utils/umount.c
+++ b/sys-utils/umount.c
@@ -289,11 +289,6 @@ static int umount_one(struct libmnt_context *cxt, const char *spec)
if (!spec)
return MOUNT_EX_SOFTWARE;
- /* We have to reset the context to make this function and the
- * context re-usable more than once (for example in --recursive)
- */
- mnt_reset_context(cxt);
-
if (mnt_context_set_target(cxt, spec))
err(MOUNT_EX_SYSERR, _("failed to set umount target"));
@@ -310,7 +305,7 @@ static int umount_one(struct libmnt_context *cxt, const char *spec)
static int umount_do_recurse(struct libmnt_context *cxt,
struct libmnt_table *tb, struct libmnt_fs *parent)
{
- int rc;
+ int rc, mounted = 0;
struct libmnt_fs *child;
const char *target = mnt_fs_get_target(parent);
struct libmnt_iter *itr = mnt_new_iter(MNT_ITER_BACKWARD);
@@ -334,7 +329,33 @@ static int umount_do_recurse(struct libmnt_context *cxt,
goto done;
}
- rc = umount_one(cxt, target);
+
+ /*
+ * Let's check if the pointpoint is still mounted -- for example with
+ * shared subtrees maybe the mountpoint already unmounted by any
+ * previous umount(2) call.
+ *
+ * Note that here we a little duplicate code from umount_one() and
+ * mnt_context_umount(). It's no problem to call
+ * mnt_context_prepare_umount() more than once. This solution is better
+ * than directly call mnt_context_is_fs_mounted(), because libmount is
+ * able to optimize mtab usage by mnt_context_set_tabfilte().
+ */
+ if (mnt_context_set_target(cxt, mnt_fs_get_target(parent)))
+ err(MOUNT_EX_SYSERR, _("failed to set umount target"));
+
+ rc = mnt_context_prepare_umount(cxt);
+ if (!rc)
+ rc = mnt_context_is_fs_mounted(cxt, parent, &mounted);
+ if (mounted)
+ rc = umount_one(cxt, target);
+ else {
+ if (rc)
+ rc = mk_exit_code(cxt, rc); /* error */
+ else
+ rc = MOUNT_EX_SUCCESS; /* alredy unmounted */
+ mnt_reset_context(cxt);
+ }
done:
mnt_free_iter(itr);
return rc;
@@ -345,6 +366,9 @@ static int umount_recursive(struct libmnt_context *cxt, const char *spec)
struct libmnt_table *tb;
int rc;
+ /* it's always real mountpoint, don't assume that the target maybe a device */
+ mnt_context_disable_swapmatch(cxt, 1);
+
tb = mnt_new_table();
if (!tb)
err(MOUNT_EX_SYSERR, _("libmount table allocation failed"));