05ad79
From 2218dc0d130bb72809e2d8b26a36402bf6293727 Mon Sep 17 00:00:00 2001
05ad79
From: Karel Zak <kzak@redhat.com>
05ad79
Date: Mon, 17 Aug 2015 11:54:26 +0200
05ad79
Subject: [PATCH 84/86] libmount: add support for "bind,ro"
05ad79
05ad79
Now it's necessary to use two mount(8) calls to create a read-only
05ad79
mount:
05ad79
05ad79
  mount /foo /bar -o bind
05ad79
  mount /bar -o remount,ro,bind
05ad79
05ad79
This patch allows to specify "bind,ro" and the remount is done
05ad79
automatically by libmount by additional mount(2) syscall. It's not
05ad79
atomic of course.
05ad79
05ad79
Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1281839
05ad79
Signed-off-by: Karel Zak <kzak@redhat.com>
05ad79
---
05ad79
 libmount/src/context_mount.c | 46 ++++++++++++++++++++++++++++++++++++++++++++
05ad79
 sys-utils/mount.8            | 37 ++++++++++++++++++-----------------
05ad79
 2 files changed, 65 insertions(+), 18 deletions(-)
05ad79
05ad79
diff --git a/libmount/src/context_mount.c b/libmount/src/context_mount.c
05ad79
index d6691eb..4df2646 100644
05ad79
--- a/libmount/src/context_mount.c
05ad79
+++ b/libmount/src/context_mount.c
05ad79
@@ -62,6 +62,10 @@ static int mnt_context_append_additional_mount(struct libmnt_context *cxt,
05ad79
 	return 0;
05ad79
 }
05ad79
 
05ad79
+/*
05ad79
+ * add additional mount(2) syscall requests when necessary to set propagation flags
05ad79
+ * after regular mount(2).
05ad79
+ */
05ad79
 static int init_propagation(struct libmnt_context *cxt)
05ad79
 {
05ad79
 	char *name;
05ad79
@@ -102,6 +106,41 @@ static int init_propagation(struct libmnt_context *cxt)
05ad79
 }
05ad79
 
05ad79
 /*
05ad79
+ * add additional mount(2) syscall request to implement "ro,bind", the first regular
05ad79
+ * mount(2) is the "bind" operation, the second is "remount,ro,bind" call.
05ad79
+ *
05ad79
+ * Note that we don't remove "ro" from the first syscall (kernel silently
05ad79
+ * ignores this flags for bind operation) -- maybe one day kernel will support
05ad79
+ * read-only binds in one step and then all will be done by the firts mount(2) and the
05ad79
+ * second remount will be noop...
05ad79
+ */
05ad79
+static int init_robind(struct libmnt_context *cxt)
05ad79
+{
05ad79
+	struct libmnt_addmount *ad;
05ad79
+	int rc;
05ad79
+
05ad79
+	assert(cxt);
05ad79
+	assert(cxt->mountflags & MS_BIND);
05ad79
+	assert(cxt->mountflags & MS_RDONLY);
05ad79
+	assert(!(cxt->mountflags & MS_REMOUNT));
05ad79
+
05ad79
+	DBG(CXT, mnt_debug_h(cxt, "mount: initialize additional ro,bind mount"));
05ad79
+
05ad79
+	ad = mnt_new_addmount();
05ad79
+	if (!ad)
05ad79
+		return -ENOMEM;
05ad79
+
05ad79
+	ad->mountflags = MS_REMOUNT | MS_BIND | MS_RDONLY;
05ad79
+	if (cxt->mountflags & MS_REC)
05ad79
+		ad->mountflags |= MS_REC;
05ad79
+	rc = mnt_context_append_additional_mount(cxt, ad);
05ad79
+	if (rc)
05ad79
+		return rc;
05ad79
+
05ad79
+	return 0;
05ad79
+}
05ad79
+
05ad79
+/*
05ad79
  * this has to be called after mnt_context_evaluate_permissions()
05ad79
  */
05ad79
 static int fix_optstr(struct libmnt_context *cxt)
05ad79
@@ -174,6 +213,13 @@ static int fix_optstr(struct libmnt_context *cxt)
05ad79
 		if (rc)
05ad79
 			return rc;
05ad79
 	}
05ad79
+	if ((cxt->mountflags & MS_BIND)
05ad79
+	    && (cxt->mountflags & MS_RDONLY)
05ad79
+	    && !(cxt->mountflags & MS_REMOUNT)) {
05ad79
+		rc = init_robind(cxt);
05ad79
+		if (rc)
05ad79
+			return rc;
05ad79
+	}
05ad79
 
05ad79
 	next = fs->fs_optstr;
05ad79
 
05ad79
diff --git a/sys-utils/mount.8 b/sys-utils/mount.8
05ad79
index 3648870..49cb281 100644
05ad79
--- a/sys-utils/mount.8
05ad79
+++ b/sys-utils/mount.8
05ad79
@@ -388,25 +388,25 @@ or shortoption
05ad79
 .\" available since Linux 2.4.11.
05ad79
 
05ad79
 Note that the filesystem mount options will remain the same as those
05ad79
-on the original mount point, and cannot be changed by passing the -o
05ad79
-option along with --bind/--rbind. The mount options can be
05ad79
-changed by a separate remount command, for example:
05ad79
+on the original mount point.
05ad79
+
05ad79
+.BR mount(8)
05ad79
+since v2.27 (backported to RHEL7.3) allow to change the options by passing the
05ad79
+.B \-o
05ad79
+option along with
05ad79
+.BR \-\-bind
05ad79
+for example:
05ad79
 
05ad79
 .RS
05ad79
 .br
05ad79
-.B mount --bind
05ad79
-.I olddir newdir
05ad79
-.br
05ad79
-.B mount -o remount,ro
05ad79
-.I newdir
05ad79
+.B mount \-\-bind,ro foo foo
05ad79
 .RE
05ad79
 
05ad79
-Note that behavior of the remount operation depends on the /etc/mtab file. The
05ad79
-first command stores the 'bind' flag to the /etc/mtab file and the second
05ad79
-command reads the flag from the file.  If you have a system without the
05ad79
-/etc/mtab file or if you explicitly define source and target for the remount
05ad79
-command (then mount(8) does not read /etc/mtab), then you have to use bind flag
05ad79
-(or option) for the remount command too. For example:
05ad79
+This feature is not supported by Linux kernel and it is implemented in userspace
05ad79
+by additional remount mount(2) syscall. This solution is not atomic.
05ad79
+
05ad79
+The alternative (classic) way to create a read-only bind mount is to use remount
05ad79
+operation, for example:
05ad79
 
05ad79
 .RS
05ad79
 .br
05ad79
@@ -417,14 +417,15 @@ command (then mount(8) does not read /etc/mtab), then you have to use bind flag
05ad79
 .I olddir newdir
05ad79
 .RE
05ad79
 
05ad79
-Note that
05ad79
-.I remount,ro,bind
05ad79
-will create a read-only mountpoint (VFS entry), but the original filesystem suberblock
05ad79
-will be still writable, it means that the
05ad79
+Note that read-only bind will create a read-only mountpoint (VFS entry), but the
05ad79
+original filesystem superblock will still be writable, meaning that the
05ad79
 .I olddir
05ad79
 will be writable, but the
05ad79
 .I newdir
05ad79
 will be read-only.
05ad79
+
05ad79
+It's impossible to change mount options recursively
05ad79
+(for example with \fB -o rbind,ro\fR).
05ad79
 .RE
05ad79
 
05ad79
 .B The move operation.
05ad79
-- 
05ad79
2.7.4
05ad79