summaryrefslogtreecommitdiffstats
path: root/libmount/src/context.c
diff options
context:
space:
mode:
authorKarel Zak2013-01-15 13:55:29 +0100
committerKarel Zak2013-01-15 13:55:29 +0100
commit6498ece0e777ae1aeab1319a21abec7457fb940f (patch)
tree52269349b81bcf2c37ed0e97603cb4b8dcb49d9f /libmount/src/context.c
parentkill: add note about threads to the man page (diff)
downloadkernel-qcow2-util-linux-6498ece0e777ae1aeab1319a21abec7457fb940f.tar.gz
kernel-qcow2-util-linux-6498ece0e777ae1aeab1319a21abec7457fb940f.tar.xz
kernel-qcow2-util-linux-6498ece0e777ae1aeab1319a21abec7457fb940f.zip
libmount: allow to use propagation flags in fstab
Linux kernel does not allow to change more than one propagation flag by one mount(2) syscall. The flags also cannot be mixed with another mount options. It means that the propagation flags cannot be stored in /etc/fstab, manual "mount --make-* <mountpoint>" is always necessary after successful mount. Painful... This patch implements additional mount(2) after previous successful mount(2) (or exec /sbin/mount.<type>). For example: mount /dev/sda1 /A -o private,unbindable,ro or fstab entry: /dev/sda1 /A auto ro,private,unbindable is implemented by three mount(2) calls: - 1st mounts /dev/sda1 with MS_RDONLY - 2nd sets MS_PRIVATE flag - 3rd sets MS_UNBINDABLE flag. It's the same as as to manually call: mount /dev/sda1 /A -o ro mount --make-private /A mount --make-unbindable /A This solution is not atomic, and umount(2) is not called if propagation flags are not successfully applied, only error is returned. This change does not affect libmount API, so one beautiful day when mount(2) syscall will be improved we can drop this nasty patch. Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'libmount/src/context.c')
-rw-r--r--libmount/src/context.c47
1 files changed, 41 insertions, 6 deletions
diff --git a/libmount/src/context.c b/libmount/src/context.c
index 6a282910d..2e28d650a 100644
--- a/libmount/src/context.c
+++ b/libmount/src/context.c
@@ -49,6 +49,8 @@ struct libmnt_context *mnt_new_context(void)
if (!cxt)
return NULL;
+ INIT_LIST_HEAD(&cxt->addmounts);
+
ruid = getuid();
euid = geteuid();
@@ -152,6 +154,14 @@ int mnt_reset_context(struct libmnt_context *cxt)
cxt->mountdata = NULL;
cxt->flags = MNT_FL_DEFAULT;
+ /* free additional mounts list */
+ while (!list_empty(&cxt->addmounts)) {
+ struct libmnt_addmount *ad = list_entry(cxt->addmounts.next,
+ struct libmnt_addmount,
+ mounts);
+ mnt_free_addmount(ad);
+ }
+
mnt_context_reset_status(cxt);
mnt_context_set_tabfilter(cxt, NULL, NULL);
@@ -1308,7 +1318,7 @@ int mnt_context_prepare_srcpath(struct libmnt_context *cxt)
src = mnt_fs_get_source(cxt->fs);
- if (!src && (cxt->mountflags & MS_PROPAGATION))
+ if (!src && mnt_context_propagation_only(cxt))
/* mount --make-{shared,private,...} */
return mnt_fs_set_source(cxt->fs, "none");
@@ -1348,8 +1358,8 @@ int mnt_context_prepare_srcpath(struct libmnt_context *cxt)
if (!path)
path = src;
- if ((cxt->mountflags & (MS_BIND | MS_MOVE | MS_PROPAGATION | MS_REMOUNT)) ||
- mnt_fs_is_pseudofs(cxt->fs)) {
+ if ((cxt->mountflags & (MS_BIND | MS_MOVE | MS_REMOUNT))
+ || mnt_fs_is_pseudofs(cxt->fs)) {
DBG(CXT, mnt_debug_h(cxt, "REMOUNT/BIND/MOVE/pseudo FS source: %s", path));
return rc;
}
@@ -1471,7 +1481,8 @@ int mnt_context_guess_fstype(struct libmnt_context *cxt)
if (!cxt || !cxt->fs)
return -EINVAL;
- if (cxt->mountflags & (MS_BIND | MS_MOVE | MS_PROPAGATION))
+ if ((cxt->mountflags & (MS_BIND | MS_MOVE))
+ || mnt_context_propagation_only(cxt))
goto none;
type = (char *) mnt_fs_get_fstype(cxt->fs);
@@ -1622,8 +1633,8 @@ int mnt_context_prepare_update(struct libmnt_context *cxt)
DBG(CXT, mnt_debug_h(cxt, "prepare update"));
- if (cxt->mountflags & MS_PROPAGATION) {
- DBG(CXT, mnt_debug_h(cxt, "skip update: MS_PROPAGATION"));
+ if (mnt_context_propagation_only(cxt)) {
+ DBG(CXT, mnt_debug_h(cxt, "skip update: only MS_PROPAGATION"));
return 0;
}
@@ -1880,6 +1891,30 @@ int mnt_context_tab_applied(struct libmnt_context *cxt)
return cxt->flags & MNT_FL_TAB_APPLIED;
}
+/*
+ * This is not public function!
+ *
+ * Returns 1 if *only propagation flags* change is requested.
+ */
+int mnt_context_propagation_only(struct libmnt_context *cxt)
+{
+ assert(cxt);
+ assert(cxt->fs);
+
+ if (cxt->action != MNT_ACT_MOUNT)
+ return 0;
+
+ /* has to be called after context_mount.c: fix_opts() */
+ assert((cxt->flags & MNT_FL_MOUNTOPTS_FIXED));
+
+ /* all propagation mounts are in cxt->addmount */
+ return !list_empty(&cxt->addmounts)
+ && (cxt->mountflags == 0 || cxt->mountflags == MS_SILENT)
+ && cxt->fs
+ && (!cxt->fs->fstype || strcmp(cxt->fs->fstype, "none") == 0)
+ && (!cxt->fs->source || strcmp(cxt->fs->source, "none") == 0);
+}
+
/**
* mnt_context_get_status:
* @cxt: mount context