diff -ruN linux-2.6.16.9/arch/sparc64/solaris/fs.c linux-2.6.16.9-fixed/arch/sparc64/solaris/fs.c --- linux-2.6.16.9/arch/sparc64/solaris/fs.c 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.9-fixed/arch/sparc64/solaris/fs.c 2006-05-07 15:50:51.004542750 +0200 @@ -363,7 +363,7 @@ 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; @@ -399,7 +399,7 @@ 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 -ruN linux-2.6.16.9/fs/ext2/ioctl.c linux-2.6.16.9-fixed/fs/ext2/ioctl.c --- linux-2.6.16.9/fs/ext2/ioctl.c 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.9-fixed/fs/ext2/ioctl.c 2006-05-08 23:27:18.276906500 +0200 @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -30,7 +31,8 @@ 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)) @@ -69,7 +71,8 @@ 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 -ruN linux-2.6.16.9/fs/ext3/ioctl.c linux-2.6.16.9-fixed/fs/ext3/ioctl.c --- linux-2.6.16.9/fs/ext3/ioctl.c 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.9-fixed/fs/ext3/ioctl.c 2006-05-08 23:27:30.985700750 +0200 @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -36,7 +37,8 @@ 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)) @@ -112,7 +114,8 @@ 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; @@ -166,7 +169,8 @@ if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode)) return -ENOTTY; - 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)) @@ -201,7 +205,8 @@ if (!capable(CAP_SYS_RESOURCE)) return -EPERM; - if (IS_RDONLY(inode)) + if (IS_RDONLY(inode) || + (filp && MNT_IS_RDONLY(filp->f_vfsmnt))) return -EROFS; if (get_user(n_blocks_count, (__u32 __user *)arg)) @@ -222,7 +227,8 @@ if (!capable(CAP_SYS_RESOURCE)) return -EPERM; - if (IS_RDONLY(inode)) + if (IS_RDONLY(inode) || + (filp && MNT_IS_RDONLY(filp->f_vfsmnt))) return -EROFS; if (copy_from_user(&input, (struct ext3_new_group_input __user *)arg, diff -ruN linux-2.6.16.9/fs/hfsplus/ioctl.c linux-2.6.16.9-fixed/fs/hfsplus/ioctl.c --- linux-2.6.16.9/fs/hfsplus/ioctl.c 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.9-fixed/fs/hfsplus/ioctl.c 2006-05-07 15:50:51.004542750 +0200 @@ -35,7 +35,8 @@ 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 -ruN linux-2.6.16.9/fs/inode.c linux-2.6.16.9-fixed/fs/inode.c --- linux-2.6.16.9/fs/inode.c 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.9-fixed/fs/inode.c 2006-05-08 22:47:54.877203250 +0200 @@ -1203,7 +1203,8 @@ */ if (mnt && ((mnt->mnt_flags & MNT_NOATIME) || - ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode)))) + ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode)) || + (MNT_IS_RDONLY(mnt)))) return; now = current_fs_time(inode->i_sb); diff -ruN linux-2.6.16.9/fs/namei.c linux-2.6.16.9-fixed/fs/namei.c --- linux-2.6.16.9/fs/namei.c 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.9-fixed/fs/namei.c 2006-05-08 23:03:59.801507250 +0200 @@ -235,7 +235,7 @@ /* * 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; @@ -998,6 +998,24 @@ return link_path_walk(name, 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_IS_RDONLY(mnt)) + 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_IS_RDONLY(mnt)) + return -EROFS; + return 0; +} + /* * SMP-safe: Returns 1 and nd will have valid dentry and mnt, if * everything is done. Returns 0 and drops input nd, if lookup failed; @@ -1507,7 +1525,8 @@ 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. @@ -1738,15 +1757,17 @@ */ struct dentry *lookup_create(struct nameidata *nd, int is_dir) { - struct dentry *dentry = ERR_PTR(-EEXIST); - + struct dentry *dentry; + int error; + mutex_lock(&nd->dentry->d_inode->i_mutex); /* * Yucky last component or no last component at all? * (foo/., foo/.., /////) */ + error = -EEXIST; if (nd->last_type != LAST_NORM) - goto fail; + goto out; nd->flags &= ~LOOKUP_PARENT; /* @@ -1754,6 +1775,10 @@ */ dentry = lookup_hash(nd); if (IS_ERR(dentry)) + goto ret; + + error = mnt_may_create(nd->mnt, nd->dentry->d_inode, dentry); + if (error) goto fail; /* @@ -1762,14 +1787,15 @@ * all is fine. Let's be bastards - you had / on the end, you've * been asking for (non-existent) directory. -ENOENT for you. */ + 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); } EXPORT_SYMBOL_GPL(lookup_create); @@ -2001,7 +2027,11 @@ dentry = lookup_hash(&nd); 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); } mutex_unlock(&nd.dentry->d_inode->i_mutex); @@ -2078,6 +2108,9 @@ /* 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); @@ -2468,6 +2501,9 @@ error = -EINVAL; if (old_dentry == trap) goto exit4; + error = -EROFS; + if (MNT_IS_RDONLY(newnd.mnt)) + goto exit4; new_dentry = lookup_hash(&newnd); error = PTR_ERR(new_dentry); if (IS_ERR(new_dentry)) diff -ruN linux-2.6.16.9/fs/namespace.c linux-2.6.16.9-fixed/fs/namespace.c --- linux-2.6.16.9/fs/namespace.c 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.9-fixed/fs/namespace.c 2006-05-08 22:26:35.781264750 +0200 @@ -354,37 +354,40 @@ 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" }, - { 0, NULL } + { MS_RDONLY, MNT_RDONLY, "ro", "rw" }, + { MS_SYNCHRONOUS, 0, ",sync", NULL }, + { MS_DIRSYNC, 0, ",dirsync", NULL }, + { MS_MANDLOCK, 0, ",mand", NULL }, + { 0, MNT_NOSUID, ",nosuid", NULL }, + { 0, MNT_NODEV, ",nodev", NULL }, + { 0, MNT_NOEXEC, ",noexec", NULL }, + { 0, MNT_NOATIME, ",noatime", NULL }, + { 0, MNT_NODIRATIME, ",nodiratime", NULL }, + { 0, 0, NULL, NULL } }; - static struct proc_fs_info mnt_info[] = { - { MNT_NOSUID, ",nosuid" }, - { MNT_NODEV, ",nodev" }, - { MNT_NOEXEC, ",noexec" }, - { MNT_NOATIME, ",noatime" }, - { MNT_NODIRATIME, ",nodiratime" }, - { 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; mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none"); seq_putc(m, ' '); 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); @@ -861,11 +864,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) @@ -899,6 +904,7 @@ spin_unlock(&vfsmount_lock); release_mounts(&umount_list); } + mnt->mnt_flags = mnt_flags; out: up_write(&namespace_sem); @@ -1285,6 +1291,8 @@ ((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) @@ -1312,7 +1320,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_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE)) retval = do_change_type(&nd, flags); else if (flags & MS_MOVE) diff -ruN linux-2.6.16.9/fs/nfs/dir.c linux-2.6.16.9-fixed/fs/nfs/dir.c --- linux-2.6.16.9/fs/nfs/dir.c 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.9-fixed/fs/nfs/dir.c 2006-05-07 15:50:51.008543000 +0200 @@ -902,7 +902,8 @@ 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; } diff -ruN linux-2.6.16.9/fs/nfsd/vfs.c linux-2.6.16.9-fixed/fs/nfsd/vfs.c --- linux-2.6.16.9/fs/nfsd/vfs.c 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.9-fixed/fs/nfsd/vfs.c 2006-05-07 15:50:51.012543250 +0200 @@ -1781,7 +1781,8 @@ */ 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 -ruN linux-2.6.16.9/fs/open.c linux-2.6.16.9-fixed/fs/open.c --- linux-2.6.16.9/fs/open.c 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.9-fixed/fs/open.c 2006-05-08 23:01:47.473237250 +0200 @@ -248,7 +248,7 @@ 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; @@ -372,7 +372,7 @@ 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() */ @@ -429,7 +429,7 @@ 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() */ @@ -516,7 +516,8 @@ if (!res) { res = vfs_permission(&nd, mode); /* 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); @@ -627,7 +628,7 @@ 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)) @@ -660,7 +661,7 @@ 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; @@ -686,7 +687,8 @@ return sys_fchmodat(AT_FDCWD, filename, mode); } -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; @@ -698,7 +700,7 @@ 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)) @@ -728,7 +730,7 @@ 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; @@ -747,7 +749,7 @@ follow = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW; error = __user_walk_fd(dfd, filename, follow, &nd); if (!error) { - error = chown_common(nd.dentry, user, group); + error = chown_common(nd.dentry, nd.mnt, user, group); path_release(&nd); } out: @@ -761,7 +763,7 @@ 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; @@ -775,7 +777,7 @@ 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 -ruN linux-2.6.16.9/fs/pipe.c linux-2.6.16.9-fixed/fs/pipe.c --- linux-2.6.16.9/fs/pipe.c 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.9-fixed/fs/pipe.c 2006-05-08 22:36:00.240541250 +0200 @@ -346,7 +346,7 @@ wake_up_interruptible(PIPE_WAIT(*inode)); kill_fasync(PIPE_FASYNC_READERS(*inode), SIGIO, POLL_IN); } - if (ret > 0) + if ((ret > 0) && !MNT_IS_RDONLY(filp->f_vfsmnt)) file_update_time(filp); return ret; } diff -ruN linux-2.6.16.9/fs/reiserfs/ioctl.c linux-2.6.16.9-fixed/fs/reiserfs/ioctl.c --- linux-2.6.16.9/fs/reiserfs/ioctl.c 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.9-fixed/fs/reiserfs/ioctl.c 2006-05-07 15:53:46.011480000 +0200 @@ -47,7 +47,8 @@ if (!reiserfs_attrs(inode->i_sb)) return -ENOTTY; - if (IS_RDONLY(inode)) + if (IS_RDONLY(inode) || + (filp && MNT_IS_RDONLY(filp->f_vfsmnt))) return -EROFS; if ((current->fsuid != inode->i_uid) @@ -82,7 +83,8 @@ 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 -ruN linux-2.6.16.9/fs/xattr.c linux-2.6.16.9-fixed/fs/xattr.c --- linux-2.6.16.9/fs/xattr.c 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.9-fixed/fs/xattr.c 2006-05-08 23:26:42.634679000 +0200 @@ -17,6 +17,7 @@ #include #include #include +#include #include @@ -63,7 +64,7 @@ int vfs_setxattr(struct dentry *dentry, char *name, void *value, - size_t size, int flags) + size_t size, int flags, struct vfsmount *mnt) { struct inode *inode = dentry->d_inode; int error; @@ -76,6 +77,9 @@ error = security_inode_setxattr(dentry, name, value, size, flags); if (error) goto out; + error = -EROFS; + if (MNT_IS_RDONLY(mnt)) + goto out; error = -EOPNOTSUPP; if (inode->i_op->setxattr) { error = inode->i_op->setxattr(dentry, name, value, size, flags); @@ -135,7 +139,7 @@ EXPORT_SYMBOL_GPL(vfs_getxattr); int -vfs_removexattr(struct dentry *dentry, char *name) +vfs_removexattr(struct dentry *dentry, char *name, struct vfsmount *mnt) { struct inode *inode = dentry->d_inode; int error; @@ -151,6 +155,10 @@ if (error) return error; + error = -EROFS; + if (MNT_IS_RDONLY(mnt)) + return error; + mutex_lock(&inode->i_mutex); error = inode->i_op->removexattr(dentry, name); mutex_unlock(&inode->i_mutex); @@ -167,7 +175,7 @@ */ static long setxattr(struct dentry *d, char __user *name, void __user *value, - size_t size, int flags) + size_t size, int flags, struct vfsmount *mnt) { int error; void *kvalue = NULL; @@ -194,7 +202,7 @@ } } - error = vfs_setxattr(d, kname, kvalue, size, flags); + error = vfs_setxattr(d, kname, kvalue, size, flags, mnt); kfree(kvalue); return error; } @@ -209,7 +217,7 @@ error = user_path_walk(path, &nd); if (error) return error; - error = setxattr(nd.dentry, name, value, size, flags); + error = setxattr(nd.dentry, name, value, size, flags, nd.mnt); path_release(&nd); return error; } @@ -224,7 +232,7 @@ error = user_path_walk_link(path, &nd); if (error) return error; - error = setxattr(nd.dentry, name, value, size, flags); + error = setxattr(nd.dentry, name, value, size, flags, nd.mnt); path_release(&nd); return error; } @@ -239,7 +247,7 @@ f = fget(fd); if (!f) return error; - error = setxattr(f->f_dentry, name, value, size, flags); + error = setxattr(f->f_dentry, name, value, size, flags, f->f_vfsmnt); fput(f); return error; } @@ -412,7 +420,7 @@ * Extended attribute REMOVE operations */ static long -removexattr(struct dentry *d, char __user *name) +removexattr(struct dentry *d, char __user *name, struct vfsmount *mnt) { int error; char kname[XATTR_NAME_MAX + 1]; @@ -423,7 +431,7 @@ if (error < 0) return error; - return vfs_removexattr(d, kname); + return vfs_removexattr(d, kname, mnt); } asmlinkage long @@ -435,7 +443,7 @@ error = user_path_walk(path, &nd); if (error) return error; - error = removexattr(nd.dentry, name); + error = removexattr(nd.dentry, name, nd.mnt); path_release(&nd); return error; } @@ -449,7 +457,7 @@ error = user_path_walk_link(path, &nd); if (error) return error; - error = removexattr(nd.dentry, name); + error = removexattr(nd.dentry, name, nd.mnt); path_release(&nd); return error; } @@ -463,7 +471,7 @@ f = fget(fd); if (!f) return error; - error = removexattr(f->f_dentry, name); + error = removexattr(f->f_dentry, name, f->f_vfsmnt); fput(f); return error; } diff -ruN linux-2.6.16.9/include/linux/fs.h linux-2.6.16.9-fixed/include/linux/fs.h --- linux-2.6.16.9/include/linux/fs.h 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.9-fixed/include/linux/fs.h 2006-05-08 22:48:48.836575500 +0200 @@ -151,7 +151,7 @@ */ #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) || \ diff -ruN linux-2.6.16.9/include/linux/mount.h linux-2.6.16.9-fixed/include/linux/mount.h --- linux-2.6.16.9/include/linux/mount.h 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.9-fixed/include/linux/mount.h 2006-05-08 22:49:57.616874000 +0200 @@ -20,8 +20,9 @@ #define MNT_NOSUID 0x01 #define MNT_NODEV 0x02 #define MNT_NOEXEC 0x04 -#define MNT_NOATIME 0x08 -#define MNT_NODIRATIME 0x10 +#define MNT_RDONLY 0x08 +#define MNT_NOATIME 0x10 +#define MNT_NODIRATIME 0x20 #define MNT_SHARED 0x1000 /* if the vfsmount is a shared mount */ #define MNT_UNBINDABLE 0x2000 /* if the vfsmount is a unbindable mount */ @@ -49,6 +50,10 @@ int mnt_pinned; }; +#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 -ruN linux-2.6.16.9/include/linux/xattr.h linux-2.6.16.9-fixed/include/linux/xattr.h --- linux-2.6.16.9/include/linux/xattr.h 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.9-fixed/include/linux/xattr.h 2006-05-08 23:25:45.707121250 +0200 @@ -41,8 +41,8 @@ }; ssize_t vfs_getxattr(struct dentry *, char *, void *, size_t); -int vfs_setxattr(struct dentry *, char *, void *, size_t, int); -int vfs_removexattr(struct dentry *, char *); +int vfs_setxattr(struct dentry *, char *, void *, size_t, int, struct vfsmount *); +int vfs_removexattr(struct dentry *, char *, struct vfsmount *); ssize_t generic_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size); ssize_t generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size); diff -ruN linux-2.6.16.9/mm/filemap.c linux-2.6.16.9-fixed/mm/filemap.c --- linux-2.6.16.9/mm/filemap.c 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16.9-fixed/mm/filemap.c 2006-05-08 22:59:49.397858000 +0200 @@ -29,6 +29,7 @@ #include #include #include +#include #include "filemap.h" /* * FIXME: remove all knowledge of the buffer layer from the core VM @@ -1804,6 +1805,8 @@ return -EINVAL; if (!isblk) { + if (MNT_IS_RDONLY(file->f_vfsmnt)) + return -EROFS; /* FIXME: this is for backwards compatibility with 2.4 */ if (file->f_flags & O_APPEND) *pos = i_size_read(inode);