
Originally from: Herbert Poetzl <herbert@13thfloor.at>

This is the core of the read-only bind mount patch set.

This patch introduces MNT_RDONLY and ensures that it is
propagated into vfsmount->mnt_flags via do_loopback().
It then modifies inode_is_readonly() and file_readonly()
to check for the flag.
DESC
mnt_may_-checks
EDESC
Originally from: Herbert Poetzl <herbert@13thfloor.at>

This part adds mnt_may_create() and mnt_may_unlink() checks
and uses them in lookup_create(), sys_rmdir() and sys_unlink()
it also adds a RDONLY check to generic_write_checks().

check with Trond Myklebust <trond.myklebust () fys ! uio ! no>
about duplicate checks

Original versions:

+static inline int mnt_may_create(struct vfsmount *mnt, struct inode *dir,
+                                struct dentry *child)
+{
+       if (child->d_inode)
+               return -EEXIST;
+       if (IS_DEADDIR(dir))
+               return -ENOENT;
+       if (mnt_flag_set(mnt, MNT_RDONLY))
+               return -EROFS;
+       return 0;
+}
+
+static inline int ent_may_unlink(struct vfsmount *mnt, struct dentry *child)
+{
+       if (!child->d_inode)
+               return -ENOENT;
+       if (mnt_flag_set(mnt, MNT_RDONLY))
+               return -EROFS;
+       return 0;
+}


Why do we need the child and IS_DEADDDIR checks?  
DESC
include-mount.h
EDESC

Signed-off-by: Dave Hansen <haveblue@us.ibm.com>
---

 lxc-dave/fs/file.c             |    4 +++-
 lxc-dave/fs/inode.c            |    2 +-
 lxc-dave/fs/namespace.c        |    8 ++++++--
 lxc-dave/include/linux/mount.h |    1 +
 lxc-dave/mm/filemap.c          |    3 +++
 5 files changed, 14 insertions(+), 4 deletions(-)

diff -puN fs/file.c~D8-actually-add-flags fs/file.c
--- lxc/fs/file.c~D8-actually-add-flags	2006-05-31 12:48:55.000000000 -0700
+++ lxc-dave/fs/file.c	2006-05-31 12:48:55.000000000 -0700
@@ -12,6 +12,7 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/file.h>
+#include <linux/mount.h>
 #include <linux/bitops.h>
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
@@ -379,6 +380,7 @@ void __init files_defer_init(void)
 
 int file_readonly(struct file *file)
 {
-	return IS_RDONLY(file->f_dentry->d_inode);
+	return IS_RDONLY(file->f_dentry->d_inode) ||
+		mnt_flag_set(file->f_vfsmnt, MNT_RDONLY);
 }
 
diff -puN fs/inode.c~D8-actually-add-flags fs/inode.c
--- lxc/fs/inode.c~D8-actually-add-flags	2006-05-31 12:48:55.000000000 -0700
+++ lxc-dave/fs/inode.c	2006-05-31 12:48:55.000000000 -0700
@@ -1420,5 +1420,5 @@ EXPORT_SYMBOL(init_special_inode);
 
 int inode_is_readonly(struct inode *inode, struct vfsmount *mnt)
 {
-	return IS_RDONLY(inode);
+	return IS_RDONLY(inode) || mnt_flag_set(mnt, MNT_RDONLY);
 }
diff -puN fs/namespace.c~D8-actually-add-flags fs/namespace.c
--- lxc/fs/namespace.c~D8-actually-add-flags	2006-05-31 12:48:55.000000000 -0700
+++ lxc-dave/fs/namespace.c	2006-05-31 12:48:55.000000000 -0700
@@ -900,7 +900,8 @@ static int do_change_type(struct nameida
 /*
  * do loopback mount.
  */
-static int do_loopback(struct nameidata *nd, char *old_name, int recurse)
+static int do_loopback(struct nameidata *nd, char *old_name,
+		       int recurse, int mnt_flags)
 {
 	struct nameidata old_nd;
 	struct vfsmount *mnt = NULL;
@@ -938,6 +939,7 @@ static int do_loopback(struct nameidata 
 		spin_unlock(&vfsmount_lock);
 		release_mounts(&umount_list);
 	}
+	mnt->mnt_flags = mnt_flags;
 
 out:
 	up_write(&namespace_sem);
@@ -1398,6 +1400,8 @@ long do_mount(char *dev_name, char *dir_
 		((char *)data_page)[PAGE_SIZE - 1] = 0;
 
 	/* Separate the per-mountpoint flags */
+	if (flags & MS_RDONLY)
+		mnt_flags |= MNT_RDONLY;
 	if (flags & MS_NOSUID)
 		mnt_flags |= MNT_NOSUID;
 	if (flags & MS_NODEV)
@@ -1425,7 +1429,7 @@ long do_mount(char *dev_name, char *dir_
 		retval = do_remount(&nd, flags & ~MS_REMOUNT, mnt_flags,
 				    data_page);
 	else if (flags & MS_BIND)
-		retval = do_loopback(&nd, dev_name, flags & MS_REC);
+		retval = do_loopback(&nd, dev_name, flags & MS_REC, mnt_flags);
 	else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
 		retval = do_change_type(&nd, flags);
 	else if (flags & MS_MOVE)
diff -puN include/linux/mount.h~D8-actually-add-flags include/linux/mount.h
--- lxc/include/linux/mount.h~D8-actually-add-flags	2006-05-31 12:48:55.000000000 -0700
+++ lxc-dave/include/linux/mount.h	2006-05-31 12:48:55.000000000 -0700
@@ -22,6 +22,7 @@
 #define MNT_NOEXEC	0x04
 #define MNT_NOATIME	0x08
 #define MNT_NODIRATIME	0x10
+#define MNT_RDONLY	0x20
 
 #define MNT_SHRINKABLE	0x100
 
diff -puN mm/filemap.c~D8-actually-add-flags mm/filemap.c
--- lxc/mm/filemap.c~D8-actually-add-flags	2006-05-31 12:48:55.000000000 -0700
+++ lxc-dave/mm/filemap.c	2006-05-31 12:48:55.000000000 -0700
@@ -23,6 +23,7 @@
 #include <linux/mman.h>
 #include <linux/pagemap.h>
 #include <linux/file.h>
+#include <linux/mount.h>
 #include <linux/uio.h>
 #include <linux/hash.h>
 #include <linux/writeback.h>
@@ -1872,6 +1873,8 @@ inline int generic_write_checks(struct f
                 return -EINVAL;
 
 	if (!isblk) {
+		if (mnt_flag_set(file->f_vfsmnt, MNT_RDONLY))
+			return -EROFS;
 		/* FIXME: this is for backwards compatibility with 2.4 */
 		if (file->f_flags & O_APPEND)
                         *pos = i_size_read(inode);
_
