if (projid_eq(kprojid, EXT4_I(inode)->i_projid))
                return 0;
 
-       err = mnt_want_write_file(filp);
-       if (err)
-               return err;
-
        err = -EPERM;
-       inode_lock(inode);
        /* Is it quota file? Do not allow user to mess with it */
        if (ext4_is_quota_file(inode))
-               goto out_unlock;
+               return err;
 
        err = ext4_get_inode_loc(inode, &iloc);
        if (err)
-               goto out_unlock;
+               return err;
 
        raw_inode = ext4_raw_inode(&iloc);
        if (!EXT4_FITS_IN_INODE(raw_inode, ei, i_projid)) {
                                              EXT4_SB(sb)->s_want_extra_isize,
                                              &iloc);
                if (err)
-                       goto out_unlock;
+                       return err;
        } else {
                brelse(iloc.bh);
        }
        handle = ext4_journal_start(inode, EXT4_HT_QUOTA,
                EXT4_QUOTA_INIT_BLOCKS(sb) +
                EXT4_QUOTA_DEL_BLOCKS(sb) + 3);
-       if (IS_ERR(handle)) {
-               err = PTR_ERR(handle);
-               goto out_unlock;
-       }
+       if (IS_ERR(handle))
+               return PTR_ERR(handle);
 
        err = ext4_reserve_inode_write(handle, inode, &iloc);
        if (err)
                err = rc;
 out_stop:
        ext4_journal_stop(handle);
-out_unlock:
-       inode_unlock(inode);
-       mnt_drop_write_file(filp);
        return err;
 }
 #else
        return err;
 }
 
+static int ext4_ioctl_check_project(struct inode *inode, struct fsxattr *fa)
+{
+       /*
+        * Project Quota ID state is only allowed to change from within the init
+        * namespace. Enforce that restriction only if we are trying to change
+        * the quota ID state. Everything else is allowed in user namespaces.
+        */
+       if (current_user_ns() == &init_user_ns)
+               return 0;
+
+       if (__kprojid_val(EXT4_I(inode)->i_projid) != fa->fsx_projid)
+               return -EINVAL;
+
+       if (ext4_test_inode_flag(inode, EXT4_INODE_PROJINHERIT)) {
+               if (!(fa->fsx_xflags & FS_XFLAG_PROJINHERIT))
+                       return -EINVAL;
+       } else {
+               if (fa->fsx_xflags & FS_XFLAG_PROJINHERIT)
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
 long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
        struct inode *inode = file_inode(filp);
                        return err;
 
                inode_lock(inode);
+               err = ext4_ioctl_check_project(inode, &fa);
+               if (err)
+                       goto out;
                flags = (ei->i_flags & ~EXT4_FL_XFLAG_VISIBLE) |
                         (flags & EXT4_FL_XFLAG_VISIBLE);
                err = ext4_ioctl_setflags(inode, flags);
-               inode_unlock(inode);
-               mnt_drop_write_file(filp);
                if (err)
-                       return err;
-
+                       goto out;
                err = ext4_ioctl_setproject(filp, fa.fsx_projid);
-               if (err)
-                       return err;
-
-               return 0;
+out:
+               inode_unlock(inode);
+               mnt_drop_write_file(filp);
+               return err;
        }
        case EXT4_IOC_SHUTDOWN:
                return ext4_shutdown(sb, arg);