In order to have a file that is accessed through the same inode have
different permissions, VFS functions must pass the mount structure.

Signed-off-by: Sam Vilain <[EMAIL PROTECTED]>
---

 arch/sparc64/solaris/fs.c |    4 +--
 fs/ext2/ioctl.c           |    7 +++--
 fs/ext3/ioctl.c           |   16 +++++++---
 fs/hfsplus/ioctl.c        |    3 +-
 fs/namei.c                |   69 +++++++++++++++++++++++++++------------------
 fs/nfs/dir.c              |    3 +-
 fs/nfsd/nfs4recover.c     |    6 ++--
 fs/nfsd/vfs.c             |   19 +++++++-----
 fs/open.c                 |   25 ++++++++--------
 fs/reiserfs/ioctl.c       |    7 +++--
 fs/reiserfs/xattr.c       |    3 +-
 fs/xattr.c                |   23 ++++++++++-----
 include/linux/fs.h        |   12 ++++----
 ipc/mqueue.c              |    2 +
 net/unix/af_unix.c        |    2 +
 15 files changed, 121 insertions(+), 80 deletions(-)

diff --git a/arch/sparc64/solaris/fs.c b/arch/sparc64/solaris/fs.c
index 4885ca6..612477d 100644
--- a/arch/sparc64/solaris/fs.c
+++ b/arch/sparc64/solaris/fs.c
@@ -363,7 +363,7 @@ static int report_statvfs(struct vfsmoun
                int j = strlen (p);
                
                if (j > 15) j = 15;
-               if (IS_RDONLY(inode)) i = 1;
+               if (IS_RDONLY(inode) || 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 @@ static int report_statvfs64(struct vfsmo
                int j = strlen (p);
                
                if (j > 15) j = 15;
-               if (IS_RDONLY(inode)) i = 1;
+               if (IS_RDONLY(inode) || 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/ioctl.c b/fs/ext2/ioctl.c
index 3ca9afd..8f1c64a 100644
--- a/fs/ext2/ioctl.c
+++ b/fs/ext2/ioctl.c
@@ -11,6 +11,7 @@
 #include <linux/capability.h>
 #include <linux/time.h>
 #include <linux/sched.h>
+#include <linux/mount.h>
 #include <asm/current.h>
 #include <asm/uaccess.h>
 
@@ -30,7 +31,8 @@ int ext2_ioctl (struct inode * inode, st
        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 @@ int ext2_ioctl (struct inode * inode, st
        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/ioctl.c b/fs/ext3/ioctl.c
index 556cd55..2b83f7e 100644
--- a/fs/ext3/ioctl.c
+++ b/fs/ext3/ioctl.c
@@ -8,6 +8,7 @@
  */
 
 #include <linux/fs.h>
+#include <linux/mount.h>
 #include <linux/jbd.h>
 #include <linux/capability.h>
 #include <linux/ext3_fs.h>
@@ -36,7 +37,8 @@ int ext3_ioctl (struct inode * inode, st
                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 @@ 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;
@@ -166,7 +169,8 @@ flags_err:
                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 @@ flags_err:
                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 @@ flags_err:
                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 --git a/fs/hfsplus/ioctl.c b/fs/hfsplus/ioctl.c
index 13cf848..73cc849 100644
--- a/fs/hfsplus/ioctl.c
+++ b/fs/hfsplus/ioctl.c
@@ -35,7 +35,8 @@ int hfsplus_ioctl(struct inode *inode, s
                        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/namei.c b/fs/namei.c
index e28de84..46d31cc 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -235,7 +235,7 @@ int permission(struct inode *inode, int 
                /*
                 * 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;
 
@@ -702,7 +702,8 @@ static __always_inline void follow_dotdo
                if (nd->dentry == current->fs->root &&
                    nd->mnt == current->fs->rootmnt) {
                         read_unlock(&current->fs->lock);
-                       break;
+                       /* for sane '/' avoid follow_mount() */
+                       return;
                }
                 read_unlock(&current->fs->lock);
                spin_lock(&dcache_lock);
@@ -1345,7 +1346,8 @@ static inline int check_sticky(struct in
  * 10. We don't allow removal of NFS sillyrenamed files; it's handled by
  *     nfs_async_unlink().
  */
-static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
+static int may_delete(struct inode *dir, struct dentry *victim,
+       int isdir, struct nameidata *nd)
 {
        int error;
 
@@ -1354,7 +1356,7 @@ static int may_delete(struct inode *dir,
 
        BUG_ON(victim->d_parent->d_inode != dir);
 
-       error = permission(dir,MAY_WRITE | MAY_EXEC, NULL);
+       error = permission(dir,MAY_WRITE | MAY_EXEC, nd);
        if (error)
                return error;
        if (IS_APPEND(dir))
@@ -1507,7 +1509,8 @@ int may_open(struct nameidata *nd, int a
                        return -EACCES;
 
                flag &= ~O_TRUNC;
-       } else if (IS_RDONLY(inode) && (flag & FMODE_WRITE))
+       } else if ((IS_RDONLY(inode) || MNT_IS_RDONLY(nd->mnt))
+               && (flag & FMODE_WRITE))
                return -EROFS;
        /*
         * An append-only file must be opened in append mode for writing.
@@ -1773,9 +1776,10 @@ fail:
 }
 EXPORT_SYMBOL_GPL(lookup_create);
 
-int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
+int vfs_mknod(struct inode *dir, struct dentry *dentry,
+       int mode, dev_t dev, struct nameidata *nd)
 {
-       int error = may_create(dir, dentry, NULL);
+       int error = may_create(dir, dentry, nd);
 
        if (error)
                return error;
@@ -1825,11 +1829,12 @@ asmlinkage long sys_mknodat(int dfd, con
                        error = vfs_create(nd.dentry->d_inode,dentry,mode,&nd);
                        break;
                case S_IFCHR: case S_IFBLK:
-                       error = vfs_mknod(nd.dentry->d_inode,dentry,mode,
-                                       new_decode_dev(dev));
+                       error = vfs_mknod(nd.dentry->d_inode, dentry, mode,
+                                       new_decode_dev(dev), &nd);
                        break;
                case S_IFIFO: case S_IFSOCK:
-                       error = vfs_mknod(nd.dentry->d_inode,dentry,mode,0);
+                       error = vfs_mknod(nd.dentry->d_inode, dentry, mode,
+                                       0, &nd);
                        break;
                case S_IFDIR:
                        error = -EPERM;
@@ -1852,9 +1857,9 @@ asmlinkage long sys_mknod(const char __u
        return sys_mknodat(AT_FDCWD, filename, mode, dev);
 }
 
-int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode, struct 
nameidata *nd)
 {
-       int error = may_create(dir, dentry, NULL);
+       int error = may_create(dir, dentry, nd);
 
        if (error)
                return error;
@@ -1893,7 +1898,8 @@ asmlinkage long sys_mkdirat(int dfd, con
                if (!IS_ERR(dentry)) {
                        if (!IS_POSIXACL(nd.dentry->d_inode))
                                mode &= ~current->fs->umask;
-                       error = vfs_mkdir(nd.dentry->d_inode, dentry, mode);
+                       error = vfs_mkdir(nd.dentry->d_inode, dentry,
+                               mode, &nd);
                        dput(dentry);
                }
                mutex_unlock(&nd.dentry->d_inode->i_mutex);
@@ -1938,9 +1944,10 @@ void dentry_unhash(struct dentry *dentry
        spin_unlock(&dcache_lock);
 }
 
-int vfs_rmdir(struct inode *dir, struct dentry *dentry)
+int vfs_rmdir(struct inode *dir, struct dentry *dentry,
+       struct nameidata *nd)
 {
-       int error = may_delete(dir, dentry, 1);
+       int error = may_delete(dir, dentry, 1, nd);
 
        if (error)
                return error;
@@ -2001,7 +2008,7 @@ static long do_rmdir(int dfd, const char
        dentry = lookup_hash(&nd);
        error = PTR_ERR(dentry);
        if (!IS_ERR(dentry)) {
-               error = vfs_rmdir(nd.dentry->d_inode, dentry);
+               error = vfs_rmdir(nd.dentry->d_inode, dentry, &nd);
                dput(dentry);
        }
        mutex_unlock(&nd.dentry->d_inode->i_mutex);
@@ -2017,9 +2024,9 @@ asmlinkage long sys_rmdir(const char __u
        return do_rmdir(AT_FDCWD, pathname);
 }
 
-int vfs_unlink(struct inode *dir, struct dentry *dentry)
+int vfs_unlink(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
 {
-       int error = may_delete(dir, dentry, 0);
+       int error = may_delete(dir, dentry, 0, nd);
 
        if (error)
                return error;
@@ -2081,7 +2088,7 @@ static long do_unlinkat(int dfd, const c
                inode = dentry->d_inode;
                if (inode)
                        atomic_inc(&inode->i_count);
-               error = vfs_unlink(nd.dentry->d_inode, dentry);
+               error = vfs_unlink(nd.dentry->d_inode, dentry, &nd);
        exit2:
                dput(dentry);
        }
@@ -2116,9 +2123,9 @@ asmlinkage long sys_unlink(const char __
        return do_unlinkat(AT_FDCWD, pathname);
 }
 
-int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname, 
int mode)
+int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname, 
int mode, struct nameidata *nd)
 {
-       int error = may_create(dir, dentry, NULL);
+       int error = may_create(dir, dentry, nd);
 
        if (error)
                return error;
@@ -2159,7 +2166,8 @@ asmlinkage long sys_symlinkat(const char
                dentry = lookup_create(&nd, 0);
                error = PTR_ERR(dentry);
                if (!IS_ERR(dentry)) {
-                       error = vfs_symlink(nd.dentry->d_inode, dentry, from, 
S_IALLUGO);
+                       error = vfs_symlink(nd.dentry->d_inode, dentry,
+                               from, S_IALLUGO, &nd);
                        dput(dentry);
                }
                mutex_unlock(&nd.dentry->d_inode->i_mutex);
@@ -2176,7 +2184,7 @@ asmlinkage long sys_symlink(const char _
        return sys_symlinkat(oldname, AT_FDCWD, newname);
 }
 
-int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry 
*new_dentry)
+int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry 
*new_dentry, struct nameidata *nd)
 {
        struct inode *inode = old_dentry->d_inode;
        int error;
@@ -2184,7 +2192,7 @@ int vfs_link(struct dentry *old_dentry, 
        if (!inode)
                return -ENOENT;
 
-       error = may_create(dir, new_dentry, NULL);
+       error = may_create(dir, new_dentry, nd);
        if (error)
                return error;
 
@@ -2247,7 +2255,8 @@ asmlinkage long sys_linkat(int olddfd, c
        new_dentry = lookup_create(&nd, 0);
        error = PTR_ERR(new_dentry);
        if (!IS_ERR(new_dentry)) {
-               error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry);
+               error = vfs_link(old_nd.dentry, nd.dentry->d_inode,
+                       new_dentry, &nd);
                dput(new_dentry);
        }
        mutex_unlock(&nd.dentry->d_inode->i_mutex);
@@ -2379,14 +2388,14 @@ int vfs_rename(struct inode *old_dir, st
        if (old_dentry->d_inode == new_dentry->d_inode)
                return 0;
  
-       error = may_delete(old_dir, old_dentry, is_dir);
+       error = may_delete(old_dir, old_dentry, is_dir, NULL);
        if (error)
                return error;
 
        if (!new_dentry->d_inode)
                error = may_create(new_dir, new_dentry, NULL);
        else
-               error = may_delete(new_dir, new_dentry, is_dir);
+               error = may_delete(new_dir, new_dentry, is_dir, NULL);
        if (error)
                return error;
 
@@ -2464,6 +2473,12 @@ static int do_rename(int olddfd, const c
        error = -EINVAL;
        if (old_dentry == trap)
                goto exit4;
+       error = -EROFS;
+       if (MNT_IS_RDONLY(newnd.mnt))
+               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 --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index a1554be..e78b606 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -902,7 +902,8 @@ static int is_atomic_open(struct inode *
        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) || MNT_IS_RDONLY(nd->mnt)) &&
+               (nd->intent.open.flags & (O_CREAT|O_TRUNC|FMODE_WRITE)))
                return 0;
        return 1;
 }
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index 06da750..a725cd1 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -155,7 +155,7 @@ nfsd4_create_clid_dir(struct nfs4_client
                dprintk("NFSD: nfsd4_create_clid_dir: DIRECTORY EXISTS\n");
                goto out_put;
        }
-       status = vfs_mkdir(rec_dir.dentry->d_inode, dentry, S_IRWXU);
+       status = vfs_mkdir(rec_dir.dentry->d_inode, dentry, S_IRWXU, NULL);
 out_put:
        dput(dentry);
 out_unlock:
@@ -259,7 +259,7 @@ nfsd4_remove_clid_file(struct dentry *di
                return -EINVAL;
        }
        mutex_lock(&dir->d_inode->i_mutex);
-       status = vfs_unlink(dir->d_inode, dentry);
+       status = vfs_unlink(dir->d_inode, dentry, NULL);
        mutex_unlock(&dir->d_inode->i_mutex);
        return status;
 }
@@ -274,7 +274,7 @@ nfsd4_clear_clid_dir(struct dentry *dir,
         * a kernel from the future.... */
        nfsd4_list_rec_dir(dentry, nfsd4_remove_clid_file);
        mutex_lock(&dir->d_inode->i_mutex);
-       status = vfs_rmdir(dir->d_inode, dentry);
+       status = vfs_rmdir(dir->d_inode, dentry, NULL);
        mutex_unlock(&dir->d_inode->i_mutex);
        return status;
 }
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 5320e5a..c9a49da 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -1160,13 +1160,13 @@ nfsd_create(struct svc_rqst *rqstp, stru
                err = vfs_create(dirp, dchild, iap->ia_mode, NULL);
                break;
        case S_IFDIR:
-               err = vfs_mkdir(dirp, dchild, iap->ia_mode);
+               err = vfs_mkdir(dirp, dchild, iap->ia_mode, NULL);
                break;
        case S_IFCHR:
        case S_IFBLK:
        case S_IFIFO:
        case S_IFSOCK:
-               err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
+               err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev, NULL);
                break;
        default:
                printk("nfsd: bad file type %o in nfsd_create\n", type);
@@ -1446,11 +1446,13 @@ nfsd_symlink(struct svc_rqst *rqstp, str
                else {
                        strncpy(path_alloced, path, plen);
                        path_alloced[plen] = 0;
-                       err = vfs_symlink(dentry->d_inode, dnew, path_alloced, 
mode);
+                       err = vfs_symlink(dentry->d_inode, dnew,
+                               path_alloced, mode, NULL);
                        kfree(path_alloced);
                }
        } else
-               err = vfs_symlink(dentry->d_inode, dnew, path, mode);
+               err = vfs_symlink(dentry->d_inode, dnew,
+                       path, mode, NULL);
 
        if (!err)
                if (EX_ISSYNC(fhp->fh_export))
@@ -1508,7 +1510,7 @@ nfsd_link(struct svc_rqst *rqstp, struct
        dold = tfhp->fh_dentry;
        dest = dold->d_inode;
 
-       err = vfs_link(dold, dirp, dnew);
+       err = vfs_link(dold, dirp, dnew, NULL);
        if (!err) {
                if (EX_ISSYNC(ffhp->fh_export)) {
                        err = nfserrno(nfsd_sync_dir(ddir));
@@ -1670,9 +1672,9 @@ nfsd_unlink(struct svc_rqst *rqstp, stru
                        err = -EPERM;
                } else
 #endif
-               err = vfs_unlink(dirp, rdentry);
+               err = vfs_unlink(dirp, rdentry, NULL);
        } else { /* It's RMDIR */
-               err = vfs_rmdir(dirp, rdentry);
+               err = vfs_rmdir(dirp, rdentry, NULL);
        }
 
        dput(rdentry);
@@ -1781,7 +1783,8 @@ nfsd_permission(struct svc_export *exp, 
         */
        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)
+                               || 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 70e0230..0abd398 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -248,7 +248,7 @@ static long do_sys_truncate(const char _
                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 @@ asmlinkage long sys_utime(char __user * 
        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 @@ long do_utimes(int dfd, char __user *fil
        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 @@ asmlinkage long sys_faccessat(int dfd, c
        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 @@ asmlinkage long sys_fchmod(unsigned int 
        inode = dentry->d_inode;
 
        err = -EROFS;
-       if (IS_RDONLY(inode))
+       if (IS_RDONLY(inode) || MNT_IS_RDONLY(file->f_vfsmnt))
                goto out_putf;
        err = -EPERM;
        if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
@@ -660,7 +661,7 @@ asmlinkage long sys_fchmodat(int dfd, co
        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,7 @@ asmlinkage long sys_chmod(const char __u
        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 +699,7 @@ static int chown_common(struct dentry * 
                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 +729,7 @@ asmlinkage long sys_chown(const char __u
 
        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 +748,7 @@ asmlinkage long sys_fchownat(int dfd, co
        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 +762,7 @@ asmlinkage long sys_lchown(const char __
 
        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 +776,7 @@ asmlinkage long sys_fchown(unsigned int 
 
        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/reiserfs/ioctl.c b/fs/reiserfs/ioctl.c
index 745c881..cd5b6e8 100644
--- a/fs/reiserfs/ioctl.c
+++ b/fs/reiserfs/ioctl.c
@@ -4,6 +4,7 @@
 
 #include <linux/capability.h>
 #include <linux/fs.h>
+#include <linux/mount.h>
 #include <linux/reiserfs_fs.h>
 #include <linux/time.h>
 #include <asm/uaccess.h>
@@ -47,7 +48,8 @@ int reiserfs_ioctl(struct inode *inode, 
                        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 +84,8 @@ int reiserfs_ioctl(struct inode *inode, 
        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 ffb79c4..b99819a 100644
--- a/fs/reiserfs/xattr.c
+++ b/fs/reiserfs/xattr.c
@@ -35,6 +35,7 @@
 #include <linux/namei.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
+#include <linux/mount.h>
 #include <linux/file.h>
 #include <linux/pagemap.h>
 #include <linux/xattr.h>
@@ -824,7 +825,7 @@ int reiserfs_delete_xattrs(struct inode 
        if (dir->d_inode->i_nlink <= 2) {
                root = get_xa_root(inode->i_sb);
                reiserfs_write_lock_xattrs(inode->i_sb);
-               err = vfs_rmdir(root->d_inode, dir);
+               err = vfs_rmdir(root->d_inode, dir, NULL);
                reiserfs_write_unlock_xattrs(inode->i_sb);
                dput(root);
        } else {
diff --git a/fs/xattr.c b/fs/xattr.c
index 80eca7d..ad83a51 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -17,6 +17,7 @@
 #include <linux/syscalls.h>
 #include <linux/module.h>
 #include <linux/fsnotify.h>
+#include <linux/mount.h>
 #include <asm/uaccess.h>
 
 
@@ -167,7 +168,7 @@ EXPORT_SYMBOL_GPL(vfs_removexattr);
  */
 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,6 +195,9 @@ setxattr(struct dentry *d, char __user *
                }
        }
 
+       if (MNT_IS_RDONLY(mnt))
+               return -EROFS;
+
        error = vfs_setxattr(d, kname, kvalue, size, flags);
        kfree(kvalue);
        return error;
@@ -209,7 +213,7 @@ sys_setxattr(char __user *path, char __u
        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 +228,7 @@ sys_lsetxattr(char __user *path, char __
        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 +243,7 @@ sys_fsetxattr(int fd, char __user *name,
        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 +416,7 @@ sys_flistxattr(int fd, char __user *list
  * 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,6 +427,9 @@ removexattr(struct dentry *d, char __use
        if (error < 0)
                return error;
 
+       if (MNT_IS_RDONLY(mnt))
+               return -EROFS;
+
        return vfs_removexattr(d, kname);
 }
 
@@ -435,7 +442,7 @@ sys_removexattr(char __user *path, char 
        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 +456,7 @@ sys_lremovexattr(char __user *path, char
        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 +470,7 @@ sys_fremovexattr(int fd, char __user *na
        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 --git a/include/linux/fs.h b/include/linux/fs.h
index e059da9..250b002 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -903,12 +903,12 @@ static inline void unlock_super(struct s
  */
 extern int vfs_permission(struct nameidata *, int);
 extern int vfs_create(struct inode *, struct dentry *, int, struct nameidata 
*);
-extern int vfs_mkdir(struct inode *, struct dentry *, int);
-extern int vfs_mknod(struct inode *, struct dentry *, int, dev_t);
-extern int vfs_symlink(struct inode *, struct dentry *, const char *, int);
-extern int vfs_link(struct dentry *, struct inode *, struct dentry *);
-extern int vfs_rmdir(struct inode *, struct dentry *);
-extern int vfs_unlink(struct inode *, struct dentry *);
+extern int vfs_mkdir(struct inode *, struct dentry *, int, struct nameidata *);
+extern int vfs_mknod(struct inode *, struct dentry *, int, dev_t, struct 
nameidata *);
+extern int vfs_symlink(struct inode *, struct dentry *, const char *, int, 
struct nameidata *);
+extern int vfs_link(struct dentry *, struct inode *, struct dentry *, struct 
nameidata *);
+extern int vfs_rmdir(struct inode *, struct dentry *, struct nameidata *);
+extern int vfs_unlink(struct inode *, struct dentry *, struct nameidata *);
 extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct 
dentry *);
 
 /*
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index fd2e26b..57391b7 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -738,7 +738,7 @@ asmlinkage long sys_mq_unlink(const char
        if (inode)
                atomic_inc(&inode->i_count);
 
-       err = vfs_unlink(dentry->d_parent->d_inode, dentry);
+       err = vfs_unlink(dentry->d_parent->d_inode, dentry, NULL);
 out_err:
        dput(dentry);
 
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 1b5989b..10b3375 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -781,7 +781,7 @@ static int unix_bind(struct socket *sock
                 */
                mode = S_IFSOCK |
                       (SOCK_INODE(sock)->i_mode & ~current->fs->umask);
-               err = vfs_mknod(nd.dentry->d_inode, dentry, mode, 0);
+               err = vfs_mknod(nd.dentry->d_inode, dentry, mode, 0, NULL);
                if (err)
                        goto out_mknod_dput;
                mutex_unlock(&nd.dentry->d_inode->i_mutex);

_______________________________________________
Vserver mailing list
[email protected]
http://list.linux-vserver.org/mailman/listinfo/vserver

Reply via email to