lkml.org 
[lkml]   [2003]   [Aug]   [4]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
SubjectRO --bind mount implementation ...

A few days ago, I asked on lkml if mount options
like RO would be useful for --bind mounts, and
Christoph was so nice to refer me to a 'n step'
plan posted by Al 'a while ago', which I could
not find 8-) ...

anyway, I discussed this with some friends, and
they pointed out that this would be useful ...
so here is the first try ...

I hope my approach does not interfere with the
long term plans Alexander has, because I admire
his well designed evolution of the vfs layer ...

enjoy,
Herbert

--------------------------

;
; Bind Mount Extensions
;
; this patch adds some functionality to the --bind
; type of vfs mounts.
;
; (C) 2003 Herbert Pötzl <herbert@13thfloor.at>
;
; Changelog:
;
; 0.01 - readonly bind mounts
;
; this patch is free software; you can redistribute it and/or
; modify it under the terms of the GNU General Public License
; as published by the Free Software Foundation; either version 2
; of the License, or (at your option) any later version.
;
; this patch is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;

diff -NurP --minimal linux-2.4.22-pre10/fs/namei.c linux-2.4.22-pre10-bme0.01/fs/namei.c
--- linux-2.4.22-pre10/fs/namei.c 2003-08-02 02:32:05.000000000 +0200
+++ linux-2.4.22-pre10-bme0.01/fs/namei.c 2003-08-04 23:51:54.000000000 +0200
@@ -935,6 +935,24 @@
return permission(dir,MAY_WRITE | MAY_EXEC);
}

+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->mnt_flags & MNT_RDONLY)
+ return -EROFS;
+ return 0;
+}
+
+static inline int mnt_may_unlink(struct vfsmount *mnt, struct inode *dir, struct dentry *child) {
+ if (!child->d_inode)
+ return -ENOENT;
+ if (mnt->mnt_flags & MNT_RDONLY)
+ return -EROFS;
+ return 0;
+}
+
/*
* Special case: O_CREAT|O_EXCL implies O_NOFOLLOW for security
* reasons.
@@ -1025,6 +1043,9 @@
error = path_lookup(pathname, LOOKUP_PARENT, nd);
if (error)
return error;
+ error = -EROFS;
+ if (MNT_IS_RDONLY(nd->mnt))
+ return error;

/*
* We have the parent and last component. First of all, check
@@ -1120,7 +1141,7 @@
flag &= ~O_TRUNC;
} else {
error = -EROFS;
- if (IS_RDONLY(inode) && (flag & 2))
+ if ((flag & 2) && (IS_RDONLY(inode) || MNT_IS_RDONLY(nd->mnt)))
goto exit;
}
/*
@@ -1216,22 +1237,27 @@
static struct dentry *lookup_create(struct nameidata *nd, int is_dir)
{
struct dentry *dentry;
+ int error;

down(&nd->dentry->d_inode->i_sem);
- dentry = ERR_PTR(-EEXIST);
+ error = -EEXIST;
if (nd->last_type != LAST_NORM)
- goto fail;
+ goto out;
dentry = lookup_hash(&nd->last, nd->dentry);
if (IS_ERR(dentry))
- goto fail;
+ goto ret;
+ error = mnt_may_create(nd->mnt, nd->dentry->d_inode, dentry);
+ if (error)
+ goto fail;
+ error = -ENOENT;
if (!is_dir && nd->last.name[nd->last.len] && !dentry->d_inode)
- goto enoent;
+ goto fail;
+ret:
return dentry;
-enoent:
- dput(dentry);
- dentry = ERR_PTR(-ENOENT);
fail:
- return dentry;
+ dput(dentry);
+out:
+ return ERR_PTR(error);
}

int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
@@ -1457,7 +1483,11 @@
dentry = lookup_hash(&nd.last, nd.dentry);
error = PTR_ERR(dentry);
if (!IS_ERR(dentry)) {
+ error = mnt_may_unlink(nd.mnt, nd.dentry->d_inode, dentry);
+ if (error)
+ goto exit2;
error = vfs_rmdir(nd.dentry->d_inode, dentry);
+ exit2:
dput(dentry);
}
up(&nd.dentry->d_inode->i_sem);
@@ -1519,7 +1549,9 @@
/* Why not before? Because we want correct error value */
if (nd.last.name[nd.last.len])
goto slashes;
- error = vfs_unlink(nd.dentry->d_inode, dentry);
+ error = mnt_may_unlink(nd.mnt, nd.dentry->d_inode, dentry);
+ if (!error)
+ error = vfs_unlink(nd.dentry->d_inode, dentry);
exit2:
dput(dentry);
}
@@ -1893,6 +1925,9 @@
if (newnd.last.name[newnd.last.len])
goto exit4;
}
+ error = -EROFS;
+ if (MNT_IS_RDONLY(newnd.mnt))
+ goto exit4;
new_dentry = lookup_hash(&newnd.last, new_dir);
error = PTR_ERR(new_dentry);
if (IS_ERR(new_dentry))
diff -NurP --minimal linux-2.4.22-pre10/fs/namespace.c linux-2.4.22-pre10-bme0.01/fs/namespace.c
--- linux-2.4.22-pre10/fs/namespace.c 2003-06-13 16:51:37.000000000 +0200
+++ linux-2.4.22-pre10-bme0.01/fs/namespace.c 2003-08-04 23:50:16.000000000 +0200
@@ -226,7 +226,7 @@
free_page((unsigned long) path_buf);
seq_putc(m, ' ');
mangle(m, mnt->mnt_sb->s_type->name);
- seq_puts(m, mnt->mnt_sb->s_flags & MS_RDONLY ? " ro" : " rw");
+ seq_puts(m, (MNT_IS_RDONLY(mnt) || mnt->mnt_sb->s_flags & MS_RDONLY) ? " ro" : " rw");
for (fs_infop = fs_info; fs_infop->flag; fs_infop++) {
if (mnt->mnt_sb->s_flags & fs_infop->flag)
seq_puts(m, fs_infop->str);
@@ -484,11 +484,13 @@
/*
* 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, unsigned long flags, int mnt_flags)
{
struct nameidata old_nd;
struct vfsmount *mnt = NULL;
+ int recurse = flags & MS_REC;
int err = mount_is_safe(nd);
+
if (err)
return err;
if (!old_name || !*old_name)
@@ -515,6 +517,7 @@
spin_unlock(&dcache_lock);
} else
mntput(mnt);
+ mnt->mnt_flags = mnt_flags;
}

up_write(&current->namespace->sem);
@@ -716,6 +719,8 @@
return -EINVAL;

/* 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)
@@ -733,7 +738,7 @@
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, mnt_flags);
else if (flags & MS_MOVE)
retval = do_move_mount(&nd, dev_name);
else
diff -NurP --minimal linux-2.4.22-pre10/include/linux/mount.h linux-2.4.22-pre10-bme0.01/include/linux/mount.h
--- linux-2.4.22-pre10/include/linux/mount.h 2001-10-05 22:05:55.000000000 +0200
+++ linux-2.4.22-pre10-bme0.01/include/linux/mount.h 2003-08-04 23:46:39.000000000 +0200
@@ -12,9 +12,10 @@
#define _LINUX_MOUNT_H
#ifdef __KERNEL__

-#define MNT_NOSUID 1
-#define MNT_NODEV 2
-#define MNT_NOEXEC 4
+#define MNT_RDONLY 1
+#define MNT_NOSUID 2
+#define MNT_NODEV 4
+#define MNT_NOEXEC 8

struct vfsmount
{
@@ -31,6 +32,8 @@
struct list_head mnt_list;
};

+#define MNT_IS_RDONLY(m) ((m)->mnt_flags & MNT_RDONLY)
+
static inline struct vfsmount *mntget(struct vfsmount *mnt)
{
if (mnt)
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

\
 
 \ /
  Last update: 2005-03-22 13:47    [W:0.081 / U:1.460 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site