Merge tag 'mips-fixes_5.14_1' of git://git.kernel.org/pub/scm/linux/kernel/git/mips...
[linux-2.6-microblaze.git] / fs / xfs / xfs_ioctl.c
index 7b1796c..16039ea 100644 (file)
@@ -1065,7 +1065,24 @@ xfs_fill_fsxattr(
 
        fileattr_fill_xflags(fa, xfs_ip2xflags(ip));
 
-       fa->fsx_extsize = XFS_FSB_TO_B(mp, ip->i_extsize);
+       if (ip->i_diflags & XFS_DIFLAG_EXTSIZE) {
+               fa->fsx_extsize = XFS_FSB_TO_B(mp, ip->i_extsize);
+       } else if (ip->i_diflags & XFS_DIFLAG_EXTSZINHERIT) {
+               /*
+                * Don't let a misaligned extent size hint on a directory
+                * escape to userspace if it won't pass the setattr checks
+                * later.
+                */
+               if ((ip->i_diflags & XFS_DIFLAG_RTINHERIT) &&
+                   ip->i_extsize % mp->m_sb.sb_rextsize > 0) {
+                       fa->fsx_xflags &= ~(FS_XFLAG_EXTSIZE |
+                                           FS_XFLAG_EXTSZINHERIT);
+                       fa->fsx_extsize = 0;
+               } else {
+                       fa->fsx_extsize = XFS_FSB_TO_B(mp, ip->i_extsize);
+               }
+       }
+
        if (ip->i_diflags2 & XFS_DIFLAG2_COWEXTSIZE)
                fa->fsx_cowextsize = XFS_FSB_TO_B(mp, ip->i_cowextsize);
        fa->fsx_projid = ip->i_projid;
@@ -1292,10 +1309,10 @@ xfs_ioctl_setattr_check_extsize(
        new_diflags = xfs_flags2diflags(ip, fa->fsx_xflags);
 
        /*
-        * Inode verifiers on older kernels don't check that the extent size
-        * hint is an integer multiple of the rt extent size on a directory
-        * with both rtinherit and extszinherit flags set.  Don't let sysadmins
-        * misconfigure directories.
+        * Inode verifiers do not check that the extent size hint is an integer
+        * multiple of the rt extent size on a directory with both rtinherit
+        * and extszinherit flags set.  Don't let sysadmins misconfigure
+        * directories.
         */
        if ((new_diflags & XFS_DIFLAG_RTINHERIT) &&
            (new_diflags & XFS_DIFLAG_EXTSZINHERIT)) {
@@ -1875,7 +1892,7 @@ out:
 static inline int
 xfs_fs_eofblocks_from_user(
        struct xfs_fs_eofblocks         *src,
-       struct xfs_eofblocks            *dst)
+       struct xfs_icwalk               *dst)
 {
        if (src->eof_version != XFS_EOFBLOCKS_VERSION)
                return -EINVAL;
@@ -1887,21 +1904,32 @@ xfs_fs_eofblocks_from_user(
            memchr_inv(src->pad64, 0, sizeof(src->pad64)))
                return -EINVAL;
 
-       dst->eof_flags = src->eof_flags;
-       dst->eof_prid = src->eof_prid;
-       dst->eof_min_file_size = src->eof_min_file_size;
-
-       dst->eof_uid = INVALID_UID;
+       dst->icw_flags = 0;
+       if (src->eof_flags & XFS_EOF_FLAGS_SYNC)
+               dst->icw_flags |= XFS_ICWALK_FLAG_SYNC;
+       if (src->eof_flags & XFS_EOF_FLAGS_UID)
+               dst->icw_flags |= XFS_ICWALK_FLAG_UID;
+       if (src->eof_flags & XFS_EOF_FLAGS_GID)
+               dst->icw_flags |= XFS_ICWALK_FLAG_GID;
+       if (src->eof_flags & XFS_EOF_FLAGS_PRID)
+               dst->icw_flags |= XFS_ICWALK_FLAG_PRID;
+       if (src->eof_flags & XFS_EOF_FLAGS_MINFILESIZE)
+               dst->icw_flags |= XFS_ICWALK_FLAG_MINFILESIZE;
+
+       dst->icw_prid = src->eof_prid;
+       dst->icw_min_file_size = src->eof_min_file_size;
+
+       dst->icw_uid = INVALID_UID;
        if (src->eof_flags & XFS_EOF_FLAGS_UID) {
-               dst->eof_uid = make_kuid(current_user_ns(), src->eof_uid);
-               if (!uid_valid(dst->eof_uid))
+               dst->icw_uid = make_kuid(current_user_ns(), src->eof_uid);
+               if (!uid_valid(dst->icw_uid))
                        return -EINVAL;
        }
 
-       dst->eof_gid = INVALID_GID;
+       dst->icw_gid = INVALID_GID;
        if (src->eof_flags & XFS_EOF_FLAGS_GID) {
-               dst->eof_gid = make_kgid(current_user_ns(), src->eof_gid);
-               if (!gid_valid(dst->eof_gid))
+               dst->icw_gid = make_kgid(current_user_ns(), src->eof_gid);
+               if (!gid_valid(dst->icw_gid))
                        return -EINVAL;
        }
        return 0;
@@ -2164,8 +2192,8 @@ xfs_file_ioctl(
                return xfs_errortag_clearall(mp);
 
        case XFS_IOC_FREE_EOFBLOCKS: {
-               struct xfs_fs_eofblocks eofb;
-               struct xfs_eofblocks keofb;
+               struct xfs_fs_eofblocks eofb;
+               struct xfs_icwalk       icw;
 
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
@@ -2176,14 +2204,14 @@ xfs_file_ioctl(
                if (copy_from_user(&eofb, arg, sizeof(eofb)))
                        return -EFAULT;
 
-               error = xfs_fs_eofblocks_from_user(&eofb, &keofb);
+               error = xfs_fs_eofblocks_from_user(&eofb, &icw);
                if (error)
                        return error;
 
-               trace_xfs_ioc_free_eofblocks(mp, &keofb, _RET_IP_);
+               trace_xfs_ioc_free_eofblocks(mp, &icw, _RET_IP_);
 
                sb_start_write(mp->m_super);
-               error = xfs_blockgc_free_space(mp, &keofb);
+               error = xfs_blockgc_free_space(mp, &icw);
                sb_end_write(mp->m_super);
                return error;
        }