From: Marc Fiuczynski Date: Sat, 18 Sep 2004 10:53:07 +0000 (+0000) Subject: bind mount patch (patch-2.6.8.1-bme0.05.1.diff) X-Git-Tag: before-enable-kexec-patch~73 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=9d2a87e9549ce23b248bc8914fb808c49ad66c26;p=linux-2.6.git bind mount patch (patch-2.6.8.1-bme0.05.1.diff) --- diff --git a/arch/sparc64/solaris/fs.c b/arch/sparc64/solaris/fs.c index a237c68ac..6fe66f847 100644 --- a/arch/sparc64/solaris/fs.c +++ b/arch/sparc64/solaris/fs.c @@ -362,7 +362,7 @@ static int report_statvfs(struct vfsmount *mnt, struct inode *inode, u32 buf) int j = strlen (p); if (j > 15) j = 15; - if (IS_RDONLY(inode)) i = 1; + if (IS_RDONLY(inode) || (mnt && MNT_IS_RDONLY(mnt))) i = 1; if (mnt->mnt_flags & MNT_NOSUID) i |= 2; if (!sysv_valid_dev(inode->i_sb->s_dev)) return -EOVERFLOW; @@ -398,7 +398,7 @@ static int report_statvfs64(struct vfsmount *mnt, struct inode *inode, u32 buf) int j = strlen (p); if (j > 15) j = 15; - if (IS_RDONLY(inode)) i = 1; + if (IS_RDONLY(inode) || (mnt && MNT_IS_RDONLY(mnt))) i = 1; if (mnt->mnt_flags & MNT_NOSUID) i |= 2; if (!sysv_valid_dev(inode->i_sb->s_dev)) return -EOVERFLOW; diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c index 89d1df914..74acc7846 100644 --- a/fs/ext2/acl.c +++ b/fs/ext2/acl.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "ext2.h" #include "xattr.h" #include "acl.h" @@ -291,7 +292,8 @@ ext2_permission(struct inode *inode, int mask, struct nameidata *nd) int mode = inode->i_mode; /* Nobody gets write access to a read-only fs */ - if ((mask & MAY_WRITE) && IS_RDONLY(inode) && + if ((mask & MAY_WRITE) && (IS_RDONLY(inode) || + (nd && MNT_IS_RDONLY(nd->mnt))) && (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) return -EROFS; /* Nobody gets write access to an immutable file */ diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c index 2520c2ff5..f6043a6e2 100644 --- a/fs/ext2/ioctl.c +++ b/fs/ext2/ioctl.c @@ -29,7 +29,8 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, case EXT2_IOC_SETFLAGS: { unsigned int oldflags; - if (IS_RDONLY(inode)) + if (IS_RDONLY(inode) || + (filp && MNT_IS_RDONLY(filp->f_vfsmnt))) return -EROFS; if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) @@ -70,7 +71,8 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, case EXT2_IOC_SETVERSION: if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) return -EPERM; - if (IS_RDONLY(inode)) + if (IS_RDONLY(inode) || + (filp && MNT_IS_RDONLY(filp->f_vfsmnt))) return -EROFS; if (get_user(inode->i_generation, (int __user *) arg)) return -EFAULT; diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c index a3cf77de0..cc26948d5 100644 --- a/fs/ext3/acl.c +++ b/fs/ext3/acl.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include "xattr.h" @@ -296,7 +297,8 @@ ext3_permission(struct inode *inode, int mask, struct nameidata *nd) int mode = inode->i_mode; /* Nobody gets write access to a read-only fs */ - if ((mask & MAY_WRITE) && IS_RDONLY(inode) && + if ((mask & MAY_WRITE) && (IS_RDONLY(inode) || + (nd && nd->mnt && MNT_IS_RDONLY(nd->mnt))) && (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) return -EROFS; /* Nobody gets write access to an immutable file */ diff --git a/fs/ext3/ioctl.c b/fs/ext3/ioctl.c index 7765ab0d5..37bd4509d 100644 --- a/fs/ext3/ioctl.c +++ b/fs/ext3/ioctl.c @@ -35,7 +35,8 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, unsigned int oldflags; unsigned int jflag; - if (IS_RDONLY(inode)) + if (IS_RDONLY(inode) || + (filp && MNT_IS_RDONLY(filp->f_vfsmnt))) return -EROFS; if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) @@ -113,7 +114,8 @@ flags_err: if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) return -EPERM; - if (IS_RDONLY(inode)) + if (IS_RDONLY(inode) || + (filp && MNT_IS_RDONLY(filp->f_vfsmnt))) return -EROFS; if (get_user(generation, (int __user *) arg)) return -EFAULT; diff --git a/fs/hfsplus/ioctl.c b/fs/hfsplus/ioctl.c index bd05477cd..cf0118e2d 100644 --- a/fs/hfsplus/ioctl.c +++ b/fs/hfsplus/ioctl.c @@ -33,7 +33,8 @@ int hfsplus_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, flags |= EXT2_FLAG_NODUMP; /* EXT2_NODUMP_FL */ return put_user(flags, (int __user *)arg); case HFSPLUS_IOC_EXT2_SETFLAGS: { - if (IS_RDONLY(inode)) + if (IS_RDONLY(inode) || + (filp && MNT_IS_RDONLY(filp->f_vfsmnt))) return -EROFS; if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) diff --git a/fs/inode.c b/fs/inode.c index 899805f06..d8586166f 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -1210,14 +1210,14 @@ EXPORT_SYMBOL(update_atime); * When ctime_too is specified update the ctime too. */ -void inode_update_time(struct inode *inode, int ctime_too) +void inode_update_time(struct inode *inode, struct vfsmount *mnt, int ctime_too) { struct timespec now; int sync_it = 0; if (IS_NOCMTIME(inode)) return; - if (IS_RDONLY(inode)) + if (IS_RDONLY(inode) || MNT_IS_RDONLY(mnt)) return; now = current_kernel_time(); diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c index 8353f48f7..a1cef90ae 100644 --- a/fs/jfs/acl.c +++ b/fs/jfs/acl.c @@ -136,7 +136,7 @@ int jfs_permission(struct inode * inode, int mask, struct nameidata *nd) /* * Nobody gets write access to a read-only fs. */ - if (IS_RDONLY(inode) && + if ((IS_RDONLY(inode) || (nd && MNT_IS_RDONLY(nd->mnt))) && (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) return -EROFS; diff --git a/fs/namei.c b/fs/namei.c index 44262f3f6..34da5b453 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -228,10 +228,15 @@ int permission(struct inode * inode,int mask, struct nameidata *nd) { int retval; int submask; + umode_t mode = inode->i_mode; /* Ordinary permission routines do not understand MAY_APPEND. */ submask = mask & ~MAY_APPEND; + if (nd && (mask & MAY_WRITE) && MNT_IS_RDONLY(nd->mnt) && + (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) + return -EROFS; + if ((retval = xid_permission(inode, mask, nd))) return retval; if (inode->i_op && inode->i_op->permission) @@ -1166,6 +1171,24 @@ static inline int may_create(struct inode *dir, struct dentry *child, return permission(dir,MAY_WRITE | MAY_EXEC, nd); } +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. @@ -1289,7 +1312,8 @@ int may_open(struct nameidata *nd, int acc_mode, int flag) return -EACCES; flag &= ~O_TRUNC; - } else if (IS_RDONLY(inode) && (flag & FMODE_WRITE)) + } else if ((IS_RDONLY(inode) || (nd && MNT_IS_RDONLY(nd->mnt))) + && (flag & FMODE_WRITE)) return -EROFS; /* * An append-only file must be opened in append mode for writing. @@ -1527,23 +1551,28 @@ do_link: 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; nd->flags &= ~LOOKUP_PARENT; dentry = lookup_hash(&nd->last, nd->dentry); if (IS_ERR(dentry)) + 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) @@ -1772,7 +1801,11 @@ asmlinkage long sys_rmdir(const char __user * pathname) 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); @@ -1844,6 +1877,9 @@ asmlinkage long sys_unlink(const char __user * pathname) /* Why not before? Because we want correct error value */ if (nd.last.name[nd.last.len]) goto slashes; + error = mnt_may_unlink(nd.mnt, nd.dentry->d_inode, dentry); + if (error) + goto exit2; inode = dentry->d_inode; if (inode) atomic_inc(&inode->i_count); @@ -2208,6 +2244,9 @@ static inline int do_rename(const char * oldname, const char * newname) error = -EINVAL; if (old_dentry == trap) 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 --git a/fs/namespace.c b/fs/namespace.c index 9b7d73b2b..96a4d7316 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -223,24 +223,26 @@ static int show_vfsmnt(struct seq_file *m, void *v) struct vfsmount *mnt = v; int err = 0; static struct proc_fs_info { - int flag; - char *str; + int s_flag; + int mnt_flag; + char *set_str; + char *unset_str; } fs_info[] = { - { MS_SYNCHRONOUS, ",sync" }, - { MS_DIRSYNC, ",dirsync" }, - { MS_MANDLOCK, ",mand" }, - { MS_NOATIME, ",noatime" }, - { MS_NODIRATIME, ",nodiratime" }, - { MS_TAGXID, ",tagxid" }, - { 0, NULL } + { MS_RDONLY, MNT_RDONLY, "ro", "rw" }, + { MS_SYNCHRONOUS, 0, ",sync", NULL }, + { MS_DIRSYNC, 0, ",dirsync", NULL }, + { MS_MANDLOCK, 0, ",mand", NULL }, + { MS_NOATIME, MNT_NOATIME, ",noatime", NULL }, + { MS_NODIRATIME, MNT_NODIRATIME, ",nodiratime", NULL }, + { MS_TAGXID, MS_TAGXID, ",tagxid", NULL }, + { 0, MNT_NOSUID, ",nosuid", NULL }, + { 0, MNT_NODEV, ",nodev", NULL }, + { 0, MNT_NOEXEC, ",noexec", NULL }, + { 0, 0, NULL, NULL } }; - static struct proc_fs_info mnt_info[] = { - { MNT_NOSUID, ",nosuid" }, - { MNT_NODEV, ",nodev" }, - { MNT_NOEXEC, ",noexec" }, - { 0, NULL } - }; - struct proc_fs_info *fs_infop; + struct proc_fs_info *p; + unsigned long s_flags = mnt->mnt_sb->s_flags; + int mnt_flags = mnt->mnt_flags; if (vx_flags(VXF_HIDE_MOUNT, 0)) return 0; @@ -250,14 +252,15 @@ static int show_vfsmnt(struct seq_file *m, void *v) seq_path(m, mnt, mnt->mnt_root, " \t\n\\"); seq_putc(m, ' '); mangle(m, mnt->mnt_sb->s_type->name); - seq_puts(m, 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); - } - for (fs_infop = mnt_info; fs_infop->flag; fs_infop++) { - if (mnt->mnt_flags & fs_infop->flag) - seq_puts(m, fs_infop->str); + seq_putc(m, ' '); + for (p = fs_info; (p->s_flag | p->mnt_flag) ; p++) { + if ((s_flags & p->s_flag) || (mnt_flags & p->mnt_flag)) { + if (p->set_str) + seq_puts(m, p->set_str); + } else { + if (p->unset_str) + seq_puts(m, p->unset_str); + } } if (mnt->mnt_sb->s_op->show_options) err = mnt->mnt_sb->s_op->show_options(m, mnt); @@ -644,11 +647,13 @@ out_unlock: /* * 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) @@ -680,6 +685,7 @@ static int do_loopback(struct nameidata *nd, char *old_name, int recurse) spin_unlock(&vfsmount_lock); } else mntput(mnt); + mnt->mnt_flags = mnt_flags; } up_write(¤t->namespace->sem); @@ -1025,12 +1031,18 @@ long do_mount(char * dev_name, char * dir_name, char *type_page, ((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) mnt_flags |= MNT_NODEV; if (flags & MS_NOEXEC) mnt_flags |= MNT_NOEXEC; + if (flags & MS_NOATIME) + mnt_flags |= MNT_NOATIME; + if (flags & MS_NODIRATIME) + mnt_flags |= MNT_NODIRATIME; flags &= ~(MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_ACTIVE); if (vx_ccaps(VXC_SECURE_MOUNT)) @@ -1049,7 +1061,7 @@ long do_mount(char * dev_name, char * dir_name, char *type_page, 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 --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c index c1745b6f1..ed1009dac 100644 --- a/fs/ncpfs/file.c +++ b/fs/ncpfs/file.c @@ -175,7 +175,7 @@ ncp_file_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) *ppos = pos; - if (!IS_RDONLY(inode)) { + if (!IS_RDONLY(inode) || (file && MNT_IS_RDONLY(file->f_vfsmnt))) { inode->i_atime = CURRENT_TIME; } diff --git a/fs/ncpfs/mmap.c b/fs/ncpfs/mmap.c index 5fb8e8716..bae04d66b 100644 --- a/fs/ncpfs/mmap.c +++ b/fs/ncpfs/mmap.c @@ -123,7 +123,7 @@ int ncp_mmap(struct file *file, struct vm_area_struct *vma) if (((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff > (1U << (32 - PAGE_SHIFT))) return -EFBIG; - if (!IS_RDONLY(inode)) { + if (!IS_RDONLY(inode) || (file && MNT_IS_RDONLY(file->f_vfsmnt))) { inode->i_atime = CURRENT_TIME; } diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index f061e70cd..5f9aa3a2d 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -778,7 +778,8 @@ static int is_atomic_open(struct inode *dir, struct nameidata *nd) if (nd->flags & LOOKUP_DIRECTORY) return 0; /* Are we trying to write to a read only partition? */ - if (IS_RDONLY(dir) && (nd->intent.open.flags & (O_CREAT|O_TRUNC|FMODE_WRITE))) + if ((IS_RDONLY(dir) || (nd && MNT_IS_RDONLY(nd->mnt))) && + (nd->intent.open.flags & (O_CREAT|O_TRUNC|FMODE_WRITE))) return 0; return 1; } @@ -1514,7 +1515,7 @@ nfs_permission(struct inode *inode, int mask, struct nameidata *nd) * Nobody gets write access to a read-only fs. * */ - if (IS_RDONLY(inode) && + if ((IS_RDONLY(inode) || (nd && MNT_IS_RDONLY(nd->mnt))) && (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) return -EROFS; diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index d50269bc5..6ad7bc709 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1556,7 +1556,8 @@ nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc) */ if (!(acc & MAY_LOCAL_ACCESS)) if (acc & (MAY_WRITE | MAY_SATTR | MAY_TRUNC)) { - if (EX_RDONLY(exp) || IS_RDONLY(inode)) + if (EX_RDONLY(exp) || IS_RDONLY(inode) + || (exp && MNT_IS_RDONLY(exp->ex_mnt))) return nfserr_rofs; if (/* (acc & MAY_WRITE) && */ IS_IMMUTABLE(inode)) return nfserr_perm; diff --git a/fs/open.c b/fs/open.c index f19fe19a7..6c811736c 100644 --- a/fs/open.c +++ b/fs/open.c @@ -245,7 +245,7 @@ static inline long do_sys_truncate(const char __user * path, loff_t length) goto dput_and_out; error = -EROFS; - if (IS_RDONLY(inode)) + if (IS_RDONLY(inode) || MNT_IS_RDONLY(nd.mnt)) goto dput_and_out; error = -EPERM; @@ -369,7 +369,7 @@ asmlinkage long sys_utime(char __user * filename, struct utimbuf __user * times) inode = nd.dentry->d_inode; error = -EROFS; - if (IS_RDONLY(inode)) + if (IS_RDONLY(inode) || MNT_IS_RDONLY(nd.mnt)) goto dput_and_out; /* Don't worry, the checks are done in inode_change_ok() */ @@ -426,7 +426,7 @@ long do_utimes(char __user * filename, struct timeval * times) inode = nd.dentry->d_inode; error = -EROFS; - if (IS_RDONLY(inode)) + if (IS_RDONLY(inode) || MNT_IS_RDONLY(nd.mnt)) goto dput_and_out; /* Don't worry, the checks are done in inode_change_ok() */ @@ -508,7 +508,8 @@ asmlinkage long sys_access(const char __user * filename, int mode) if (!res) { res = permission(nd.dentry->d_inode, mode, &nd); /* SuS v2 requires we report a read only fs too */ - if(!res && (mode & S_IWOTH) && IS_RDONLY(nd.dentry->d_inode) + if(!res && (mode & S_IWOTH) + && (IS_RDONLY(nd.dentry->d_inode) || MNT_IS_RDONLY(nd.mnt)) && !special_file(nd.dentry->d_inode->i_mode)) res = -EROFS; path_release(&nd); @@ -614,7 +615,7 @@ asmlinkage long sys_fchmod(unsigned int fd, mode_t mode) inode = dentry->d_inode; err = -EROFS; - if (IS_RDONLY(inode)) + if (IS_RDONLY(inode) || (file && MNT_IS_RDONLY(file->f_vfsmnt))) goto out_putf; err = -EPERM; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) @@ -646,7 +647,7 @@ asmlinkage long sys_chmod(const char __user * filename, mode_t mode) inode = nd.dentry->d_inode; error = -EROFS; - if (IS_RDONLY(inode)) + if (IS_RDONLY(inode) || MNT_IS_RDONLY(nd.mnt)) goto dput_and_out; error = -EPERM; @@ -667,7 +668,8 @@ out: return error; } -static int chown_common(struct dentry * dentry, uid_t user, gid_t group) +static int chown_common(struct dentry *dentry, struct vfsmount *mnt, + uid_t user, gid_t group) { struct inode * inode; int error; @@ -679,7 +681,7 @@ static int chown_common(struct dentry * dentry, uid_t user, gid_t group) goto out; } error = -EROFS; - if (IS_RDONLY(inode)) + if (IS_RDONLY(inode) || MNT_IS_RDONLY(mnt)) goto out; error = -EPERM; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) @@ -710,7 +712,7 @@ asmlinkage long sys_chown(const char __user * filename, uid_t user, gid_t group) error = user_path_walk(filename, &nd); if (!error) { - error = chown_common(nd.dentry, user, group); + error = chown_common(nd.dentry, nd.mnt, user, group); path_release(&nd); } return error; @@ -723,7 +725,7 @@ asmlinkage long sys_lchown(const char __user * filename, uid_t user, gid_t group error = user_path_walk_link(filename, &nd); if (!error) { - error = chown_common(nd.dentry, user, group); + error = chown_common(nd.dentry, nd.mnt, user, group); path_release(&nd); } return error; @@ -737,7 +739,7 @@ asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group) file = fget(fd); if (file) { - error = chown_common(file->f_dentry, user, group); + error = chown_common(file->f_dentry, file->f_vfsmnt, user, group); fput(file); } return error; diff --git a/fs/pipe.c b/fs/pipe.c index 36264d573..3e3e2e5c3 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -255,7 +255,7 @@ pipe_writev(struct file *filp, const struct iovec *_iov, kill_fasync(PIPE_FASYNC_READERS(*inode), SIGIO, POLL_IN); } if (ret > 0) - inode_update_time(inode, 1); /* mtime and ctime */ + inode_update_time(inode, filp->f_vfsmnt, 1); /* mtime and ctime */ return ret; } diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c index f52b701fc..11ce15eca 100644 --- a/fs/reiserfs/file.c +++ b/fs/reiserfs/file.c @@ -1160,7 +1160,7 @@ ssize_t reiserfs_file_write( struct file *file, /* the file we are going to writ if (res) goto out; - inode_update_time(inode, 1); /* Both mtime and ctime */ + inode_update_time(inode, file->f_vfsmnt, 1); /* Both mtime and ctime */ // Ok, we are done with all the checks. diff --git a/fs/reiserfs/ioctl.c b/fs/reiserfs/ioctl.c index 6885230ec..201cf8b88 100644 --- a/fs/reiserfs/ioctl.c +++ b/fs/reiserfs/ioctl.c @@ -39,7 +39,8 @@ int reiserfs_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, flags &= REISERFS_FL_USER_VISIBLE; return put_user(flags, (int __user *) arg); case REISERFS_IOC_SETFLAGS: { - if (IS_RDONLY(inode)) + if (IS_RDONLY(inode) || + (filp && MNT_IS_RDONLY(filp->f_vfsmnt))) return -EROFS; if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) @@ -78,7 +79,8 @@ int reiserfs_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, case REISERFS_IOC_SETVERSION: if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) return -EPERM; - if (IS_RDONLY(inode)) + if (IS_RDONLY(inode) || + (filp && MNT_IS_RDONLY(filp->f_vfsmnt))) return -EROFS; if (get_user(inode->i_generation, (int __user *) arg)) return -EFAULT; diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index 7ef7b4545..f8babe603 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c @@ -1342,7 +1342,7 @@ __reiserfs_permission (struct inode *inode, int mask, struct nameidata *nd, /* * Nobody gets write access to a read-only fs. */ - if (IS_RDONLY(inode) && + if ((IS_RDONLY(inode) || (nd && MNT_IS_RDONLY(nd->mnt))) && (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) return -EROFS; @@ -1397,7 +1397,9 @@ __reiserfs_permission (struct inode *inode, int mask, struct nameidata *nd, } #endif } else { +#ifdef CONFIG_REISERFS_FS_POSIX_ACL check_groups: +#endif if (in_group_p(inode->i_gid)) mode >>= 3; } @@ -1408,7 +1410,9 @@ check_groups: if (((mode & mask & (MAY_READ|MAY_WRITE|MAY_EXEC)) == mask)) return 0; +#ifdef CONFIG_REISERFS_FS_POSIX_ACL check_capabilities: +#endif /* * Read/write DACs are always overridable. * Executable DACs are overridable if at least one exec bit is set. diff --git a/include/linux/fs.h b/include/linux/fs.h index f2b93269d..e83d8e4dd 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -18,6 +18,7 @@ #include #include #include +#include #include struct iovec; @@ -164,7 +165,7 @@ extern int leases_enable, dir_notify_enable, lease_break_time; */ #define __IS_FLG(inode,flg) ((inode)->i_sb->s_flags & (flg)) -#define IS_RDONLY(inode) ((inode)->i_sb->s_flags & MS_RDONLY) +#define IS_RDONLY(inode) __IS_FLG(inode, MS_RDONLY) #define IS_SYNC(inode) (__IS_FLG(inode, MS_SYNCHRONOUS) || \ ((inode)->i_flags & S_SYNC)) #define IS_DIRSYNC(inode) (__IS_FLG(inode, MS_SYNCHRONOUS|MS_DIRSYNC) || \ @@ -993,8 +994,16 @@ static inline void mark_inode_dirty_sync(struct inode *inode) static inline void touch_atime(struct vfsmount *mnt, struct dentry *dentry) { - /* per-mountpoint checks will go here */ - update_atime(dentry->d_inode); + struct inode *inode = dentry->d_inode; + + if (MNT_IS_NOATIME(mnt)) + return; + if (S_ISDIR(inode->i_mode) && MNT_IS_NODIRATIME(mnt)) + return; + if (IS_RDONLY(inode) || MNT_IS_RDONLY(mnt)) + return; + + update_atime(inode); } static inline void file_accessed(struct file *file) @@ -1548,7 +1557,7 @@ extern ssize_t simple_read_from_buffer(void __user *, size_t, loff_t *, const vo extern int inode_change_ok(struct inode *, struct iattr *); extern int __must_check inode_setattr(struct inode *, struct iattr *); -extern void inode_update_time(struct inode *inode, int ctime_too); +extern void inode_update_time(struct inode *inode, struct vfsmount *mnt, int ctime_too); static inline ino_t parent_ino(struct dentry *dentry) { diff --git a/include/linux/mount.h b/include/linux/mount.h index 42e2c9460..c69739b2f 100644 --- a/include/linux/mount.h +++ b/include/linux/mount.h @@ -17,6 +17,9 @@ #define MNT_NOSUID 1 #define MNT_NODEV 2 #define MNT_NOEXEC 4 +#define MNT_RDONLY 8 +#define MNT_NOATIME 16 +#define MNT_NODIRATIME 32 struct vfsmount { @@ -36,6 +39,10 @@ struct vfsmount struct namespace *mnt_namespace; /* containing namespace */ }; +#define MNT_IS_RDONLY(m) ((m) && ((m)->mnt_flags & MNT_RDONLY)) +#define MNT_IS_NOATIME(m) ((m) && ((m)->mnt_flags & MNT_NOATIME)) +#define MNT_IS_NODIRATIME(m) ((m) && ((m)->mnt_flags & MNT_NODIRATIME)) + static inline struct vfsmount *mntget(struct vfsmount *mnt) { if (mnt) diff --git a/mm/filemap.c b/mm/filemap.c index a1d56dea2..c6d2f668e 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1887,7 +1887,7 @@ generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov, if (err) goto out; - inode_update_time(inode, 1); + inode_update_time(inode, file->f_vfsmnt, 1); /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */ if (unlikely(file->f_flags & O_DIRECT)) {