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