}
 
        if (!is_root) {
-               error = permission(dir, MAY_EXEC, NULL);
+               error = gfs2_permission(dir, MAY_EXEC);
                if (error)
                        goto out;
        }
 {
        int error;
 
-       error = permission(&dip->i_inode, MAY_WRITE | MAY_EXEC, NULL);
+       error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC);
        if (error)
                return error;
 
        if (IS_APPEND(&dip->i_inode))
                return -EPERM;
 
-       error = permission(&dip->i_inode, MAY_WRITE | MAY_EXEC, NULL);
+       error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC);
        if (error)
                return error;
 
 
                struct gfs2_inode *ip);
 int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name,
                   const struct gfs2_inode *ip);
+int gfs2_permission(struct inode *inode, int mask);
 int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to);
 int gfs2_readlinki(struct gfs2_inode *ip, char **buf, unsigned int *len);
 int gfs2_glock_nq_atime(struct gfs2_holder *gh);
 
 #include <linux/uio.h>
 #include <linux/blkdev.h>
 #include <linux/mm.h>
+#include <linux/mount.h>
 #include <linux/fs.h>
 #include <linux/gfs2_ondisk.h>
 #include <linux/ext2_fs.h>
        int error;
        u32 new_flags, flags;
 
-       error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
+       error = mnt_want_write(filp->f_path.mnt);
        if (error)
                return error;
 
+       error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
+       if (error)
+               goto out_drop_write;
+
        flags = ip->i_di.di_flags;
        new_flags = (flags & ~mask) | (reqflags & mask);
        if ((new_flags ^ flags) == 0)
            !capable(CAP_LINUX_IMMUTABLE))
                goto out;
        if (!IS_IMMUTABLE(inode)) {
-               error = permission(inode, MAY_WRITE, NULL);
+               error = gfs2_permission(inode, MAY_WRITE);
                if (error)
                        goto out;
        }
        gfs2_trans_end(sdp);
 out:
        gfs2_glock_dq_uninit(&gh);
+out_drop_write:
+       mnt_drop_write(filp->f_path.mnt);
        return error;
 }
 
 
        if (error)
                goto out;
 
-       error = permission(dir, MAY_WRITE | MAY_EXEC, NULL);
+       error = gfs2_permission(dir, MAY_WRITE | MAY_EXEC);
        if (error)
                goto out_gunlock;
 
                        }
                }
        } else {
-               error = permission(ndir, MAY_WRITE | MAY_EXEC, NULL);
+               error = gfs2_permission(ndir, MAY_WRITE | MAY_EXEC);
                if (error)
                        goto out_gunlock;
 
        /* Check out the dir to be renamed */
 
        if (dir_rename) {
-               error = permission(odentry->d_inode, MAY_WRITE, NULL);
+               error = gfs2_permission(odentry->d_inode, MAY_WRITE);
                if (error)
                        goto out_gunlock;
        }
  * Returns: errno
  */
 
-static int gfs2_permission(struct inode *inode, int mask, struct nameidata *nd)
+int gfs2_permission(struct inode *inode, int mask)
 {
        struct gfs2_inode *ip = GFS2_I(inode);
        struct gfs2_holder i_gh;
                unlock = 1;
        }
 
-       error = generic_permission(inode, mask, gfs2_check_acl);
+       if ((mask & MAY_WRITE) && IS_IMMUTABLE(inode))
+               error = -EACCES;
+       else
+               error = generic_permission(inode, mask, gfs2_check_acl);
        if (unlock)
                gfs2_glock_dq_uninit(&i_gh);
 
        return error;
 }
 
+static int gfs2_iop_permission(struct inode *inode, int mask,
+                              struct nameidata *nd)
+{
+       return gfs2_permission(inode, mask);
+}
+
 static int setattr_size(struct inode *inode, struct iattr *attr)
 {
        struct gfs2_inode *ip = GFS2_I(inode);
 }
 
 const struct inode_operations gfs2_file_iops = {
-       .permission = gfs2_permission,
+       .permission = gfs2_iop_permission,
        .setattr = gfs2_setattr,
        .getattr = gfs2_getattr,
        .setxattr = gfs2_setxattr,
        .rmdir = gfs2_rmdir,
        .mknod = gfs2_mknod,
        .rename = gfs2_rename,
-       .permission = gfs2_permission,
+       .permission = gfs2_iop_permission,
        .setattr = gfs2_setattr,
        .getattr = gfs2_getattr,
        .setxattr = gfs2_setxattr,
 const struct inode_operations gfs2_symlink_iops = {
        .readlink = gfs2_readlink,
        .follow_link = gfs2_follow_link,
-       .permission = gfs2_permission,
+       .permission = gfs2_iop_permission,
        .setattr = gfs2_setattr,
        .getattr = gfs2_getattr,
        .setxattr = gfs2_setxattr,