]> Git Repo - linux.git/commitdiff
Merge tag 'xfs-5.13-merge-3' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
authorLinus Torvalds <[email protected]>
Thu, 29 Apr 2021 17:43:51 +0000 (10:43 -0700)
committerLinus Torvalds <[email protected]>
Thu, 29 Apr 2021 17:43:51 +0000 (10:43 -0700)
Pull xfs updates from Darrick Wong:
 "The notable user-visible addition this cycle is ability to remove
  space from the last AG in a filesystem. This is the first of many
  changes needed for full-fledged support for shrinking a filesystem.
  Still needed are (a) the ability to reorganize files and metadata away
  from the end of the fs; (b) the ability to remove entire allocation
  groups; (c) shrink support for realtime volumes; and (d) thorough
  testing of (a-c).

  There are a number of performance improvements in this code drop: Dave
  streamlined various parts of the buffer logging code and reduced the
  cost of various debugging checks, and added the ability to pre-create
  the xattr structures while creating files. Brian eliminated
  transaction reservations that were being held across writeback (thus
  reducing livelock potential.

  Other random pieces: Pavel fixed the repetitve warnings about
  deprecated mount options, I fixed online fsck to behave itself when a
  readonly remount comes in during scrub, and refactored various other
  parts of that code, Christoph contributed a lot of refactoring this
  cycle. The xfs_icdinode structure has been absorbed into the (incore)
  xfs_inode structure, and the format and flags handling around
  xfs_inode_fork structures has been simplified. Chandan provided a
  number of fixes for extent count overflow related problems that have
  been shaken out by debugging knobs added during 5.12.

  Summary:

   - Various minor fixes in online scrub.

   - Prevent metadata files from being automatically inactivated.

   - Validate btree heights by the computed per-btree limits.

   - Don't warn about remounting with deprecated mount options.

   - Initialize attr forks at create time if we suspect we're going to
     need to store them.

   - Reduce memory reallocation workouts in the logging code.

   - Fix some theoretical math calculation errors in logged buffers that
     span multiple discontig memory ranges but contiguous ondisk
     regions.

   - Speedups in dirty buffer bitmap handling.

   - Make type verifier functions more inline-happy to reduce overhead.

   - Reduce debug overhead in directory checking code.

   - Many many typo fixes.

   - Begin to handle the permanent loss of the very end of a filesystem.

   - Fold struct xfs_icdinode into xfs_inode.

   - Deprecate the long defunct BMV_IF_NO_DMAPI_READ from the bmapx
     ioctl.

   - Remove a broken directory block format check from online scrub.

   - Fix a bug where we could produce an unnecessarily tall data fork
     btree when creating an attr fork.

   - Fix scrub and readonly remounts racing.

   - Fix a writeback ioend log deadlock problem by dropping the behavior
     where we could preallocate a setfilesize transaction.

   - Fix some bugs in the new extent count checking code.

   - Fix some bugs in the attr fork preallocation code.

   - Refactor if_flags out of the incore inode fork data structure"

* tag 'xfs-5.13-merge-3' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux: (77 commits)
  xfs: remove xfs_quiesce_attr declaration
  xfs: remove XFS_IFEXTENTS
  xfs: remove XFS_IFINLINE
  xfs: remove XFS_IFBROOT
  xfs: only look at the fork format in xfs_idestroy_fork
  xfs: simplify xfs_attr_remove_args
  xfs: rename and simplify xfs_bmap_one_block
  xfs: move the XFS_IFEXTENTS check into xfs_iread_extents
  xfs: drop unnecessary setfilesize helper
  xfs: drop unused ioend private merge and setfilesize code
  xfs: open code ioend needs workqueue helper
  xfs: drop submit side trans alloc for append ioends
  xfs: fix return of uninitialized value in variable error
  xfs: get rid of the ip parameter to xchk_setup_*
  xfs: fix scrub and remount-ro protection when running scrub
  xfs: move the check for post-EOF mappings into xfs_can_free_eofblocks
  xfs: move the xfs_can_free_eofblocks call under the IOLOCK
  xfs: precalculate default inode attribute offset
  xfs: default attr fork size does not handle device inodes
  xfs: inode fork allocation depends on XFS_IFEXTENT flag
  ...

1  2 
fs/xfs/libxfs/xfs_fs.h
fs/xfs/xfs_inode.c
fs/xfs/xfs_ioctl.c
fs/xfs/xfs_iops.c
fs/xfs/xfs_symlink.c

diff --combined fs/xfs/libxfs/xfs_fs.h
index 6bf7d8b7d7435258e894c2e22720aa508feaeca1,bde2b4c64dbe30d13eef44f32005c35fe349ae1e..a83bdd0c47a846e2fa387818be20c6c2b6017521
@@@ -65,7 -65,7 +65,7 @@@ struct getbmapx 
  
  /*    bmv_iflags values - set by XFS_IOC_GETBMAPX caller.     */
  #define BMV_IF_ATTRFORK               0x1     /* return attr fork rather than data */
- #define BMV_IF_NO_DMAPI_READ  0x2     /* Do not generate DMAPI read event  */
+ #define BMV_IF_NO_DMAPI_READ  0x2     /* Deprecated */
  #define BMV_IF_PREALLOC               0x4     /* rtn status BMV_OF_PREALLOC if req */
  #define BMV_IF_DELALLOC               0x8     /* rtn status BMV_OF_DELALLOC if req */
  #define BMV_IF_NO_HOLES               0x10    /* Do not return holes */
@@@ -770,6 -770,8 +770,6 @@@ struct xfs_scrub_metadata 
  /*
   * ioctl commands that are used by Linux filesystems
   */
 -#define XFS_IOC_GETXFLAGS     FS_IOC_GETFLAGS
 -#define XFS_IOC_SETXFLAGS     FS_IOC_SETFLAGS
  #define XFS_IOC_GETVERSION    FS_IOC_GETVERSION
  
  /*
  #define XFS_IOC_ALLOCSP               _IOW ('X', 10, struct xfs_flock64)
  #define XFS_IOC_FREESP                _IOW ('X', 11, struct xfs_flock64)
  #define XFS_IOC_DIOINFO               _IOR ('X', 30, struct dioattr)
 -#define XFS_IOC_FSGETXATTR    FS_IOC_FSGETXATTR
 -#define XFS_IOC_FSSETXATTR    FS_IOC_FSSETXATTR
  #define XFS_IOC_ALLOCSP64     _IOW ('X', 36, struct xfs_flock64)
  #define XFS_IOC_FREESP64      _IOW ('X', 37, struct xfs_flock64)
  #define XFS_IOC_GETBMAP               _IOWR('X', 38, struct getbmap)
diff --combined fs/xfs/xfs_inode.c
index 2a8bdf33e6c46bad9ae37352023a1fdda7a6c6f0,17c2d8b18283c940c8e84494b4a7c40748ebb4b1..0369eb22c1bb0fd04e8b97f99703494a23bf69b5
@@@ -60,8 -60,8 +60,8 @@@ xfs_get_extsz_hint
         */
        if (xfs_is_always_cow_inode(ip))
                return 0;
-       if ((ip->i_d.di_flags & XFS_DIFLAG_EXTSIZE) && ip->i_d.di_extsize)
-               return ip->i_d.di_extsize;
+       if ((ip->i_diflags & XFS_DIFLAG_EXTSIZE) && ip->i_extsize)
+               return ip->i_extsize;
        if (XFS_IS_REALTIME_INODE(ip))
                return ip->i_mount->m_sb.sb_rextsize;
        return 0;
@@@ -80,8 -80,8 +80,8 @@@ xfs_get_cowextsz_hint
        xfs_extlen_t            a, b;
  
        a = 0;
-       if (ip->i_d.di_flags2 & XFS_DIFLAG2_COWEXTSIZE)
-               a = ip->i_d.di_cowextsize;
+       if (ip->i_diflags2 & XFS_DIFLAG2_COWEXTSIZE)
+               a = ip->i_cowextsize;
        b = xfs_get_extsz_hint(ip);
  
        a = max(a, b);
@@@ -111,8 -111,7 +111,7 @@@ xfs_ilock_data_map_shared
  {
        uint                    lock_mode = XFS_ILOCK_SHARED;
  
-       if (ip->i_df.if_format == XFS_DINODE_FMT_BTREE &&
-           (ip->i_df.if_flags & XFS_IFEXTENTS) == 0)
+       if (xfs_need_iread_extents(&ip->i_df))
                lock_mode = XFS_ILOCK_EXCL;
        xfs_ilock(ip, lock_mode);
        return lock_mode;
@@@ -124,9 -123,7 +123,7 @@@ xfs_ilock_attr_map_shared
  {
        uint                    lock_mode = XFS_ILOCK_SHARED;
  
-       if (ip->i_afp &&
-           ip->i_afp->if_format == XFS_DINODE_FMT_BTREE &&
-           (ip->i_afp->if_flags & XFS_IFEXTENTS) == 0)
+       if (ip->i_afp && xfs_need_iread_extents(ip->i_afp))
                lock_mode = XFS_ILOCK_EXCL;
        xfs_ilock(ip, lock_mode);
        return lock_mode;
@@@ -598,67 -595,55 +595,55 @@@ xfs_lock_two_inodes
        }
  }
  
- STATIC uint
- _xfs_dic2xflags(
-       uint16_t                di_flags,
-       uint64_t                di_flags2,
-       bool                    has_attr)
+ uint
+ xfs_ip2xflags(
+       struct xfs_inode        *ip)
  {
        uint                    flags = 0;
  
-       if (di_flags & XFS_DIFLAG_ANY) {
-               if (di_flags & XFS_DIFLAG_REALTIME)
+       if (ip->i_diflags & XFS_DIFLAG_ANY) {
+               if (ip->i_diflags & XFS_DIFLAG_REALTIME)
                        flags |= FS_XFLAG_REALTIME;
-               if (di_flags & XFS_DIFLAG_PREALLOC)
+               if (ip->i_diflags & XFS_DIFLAG_PREALLOC)
                        flags |= FS_XFLAG_PREALLOC;
-               if (di_flags & XFS_DIFLAG_IMMUTABLE)
+               if (ip->i_diflags & XFS_DIFLAG_IMMUTABLE)
                        flags |= FS_XFLAG_IMMUTABLE;
-               if (di_flags & XFS_DIFLAG_APPEND)
+               if (ip->i_diflags & XFS_DIFLAG_APPEND)
                        flags |= FS_XFLAG_APPEND;
-               if (di_flags & XFS_DIFLAG_SYNC)
+               if (ip->i_diflags & XFS_DIFLAG_SYNC)
                        flags |= FS_XFLAG_SYNC;
-               if (di_flags & XFS_DIFLAG_NOATIME)
+               if (ip->i_diflags & XFS_DIFLAG_NOATIME)
                        flags |= FS_XFLAG_NOATIME;
-               if (di_flags & XFS_DIFLAG_NODUMP)
+               if (ip->i_diflags & XFS_DIFLAG_NODUMP)
                        flags |= FS_XFLAG_NODUMP;
-               if (di_flags & XFS_DIFLAG_RTINHERIT)
+               if (ip->i_diflags & XFS_DIFLAG_RTINHERIT)
                        flags |= FS_XFLAG_RTINHERIT;
-               if (di_flags & XFS_DIFLAG_PROJINHERIT)
+               if (ip->i_diflags & XFS_DIFLAG_PROJINHERIT)
                        flags |= FS_XFLAG_PROJINHERIT;
-               if (di_flags & XFS_DIFLAG_NOSYMLINKS)
+               if (ip->i_diflags & XFS_DIFLAG_NOSYMLINKS)
                        flags |= FS_XFLAG_NOSYMLINKS;
-               if (di_flags & XFS_DIFLAG_EXTSIZE)
+               if (ip->i_diflags & XFS_DIFLAG_EXTSIZE)
                        flags |= FS_XFLAG_EXTSIZE;
-               if (di_flags & XFS_DIFLAG_EXTSZINHERIT)
+               if (ip->i_diflags & XFS_DIFLAG_EXTSZINHERIT)
                        flags |= FS_XFLAG_EXTSZINHERIT;
-               if (di_flags & XFS_DIFLAG_NODEFRAG)
+               if (ip->i_diflags & XFS_DIFLAG_NODEFRAG)
                        flags |= FS_XFLAG_NODEFRAG;
-               if (di_flags & XFS_DIFLAG_FILESTREAM)
+               if (ip->i_diflags & XFS_DIFLAG_FILESTREAM)
                        flags |= FS_XFLAG_FILESTREAM;
        }
  
-       if (di_flags2 & XFS_DIFLAG2_ANY) {
-               if (di_flags2 & XFS_DIFLAG2_DAX)
+       if (ip->i_diflags2 & XFS_DIFLAG2_ANY) {
+               if (ip->i_diflags2 & XFS_DIFLAG2_DAX)
                        flags |= FS_XFLAG_DAX;
-               if (di_flags2 & XFS_DIFLAG2_COWEXTSIZE)
+               if (ip->i_diflags2 & XFS_DIFLAG2_COWEXTSIZE)
                        flags |= FS_XFLAG_COWEXTSIZE;
        }
  
-       if (has_attr)
+       if (XFS_IFORK_Q(ip))
                flags |= FS_XFLAG_HASATTR;
        return flags;
  }
  
- uint
- xfs_ip2xflags(
-       struct xfs_inode        *ip)
- {
-       struct xfs_icdinode     *dic = &ip->i_d;
-       return _xfs_dic2xflags(dic->di_flags, dic->di_flags2, XFS_IFORK_Q(ip));
- }
  /*
   * Lookups up an inode from "name". If ci_name is not NULL, then a CI match
   * is allowed, otherwise it has to be an exact match. If a CI match is found,
@@@ -708,42 -693,42 +693,42 @@@ xfs_inode_inherit_flags
        umode_t                 mode = VFS_I(ip)->i_mode;
  
        if (S_ISDIR(mode)) {
-               if (pip->i_d.di_flags & XFS_DIFLAG_RTINHERIT)
+               if (pip->i_diflags & XFS_DIFLAG_RTINHERIT)
                        di_flags |= XFS_DIFLAG_RTINHERIT;
-               if (pip->i_d.di_flags & XFS_DIFLAG_EXTSZINHERIT) {
+               if (pip->i_diflags & XFS_DIFLAG_EXTSZINHERIT) {
                        di_flags |= XFS_DIFLAG_EXTSZINHERIT;
-                       ip->i_d.di_extsize = pip->i_d.di_extsize;
+                       ip->i_extsize = pip->i_extsize;
                }
-               if (pip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
+               if (pip->i_diflags & XFS_DIFLAG_PROJINHERIT)
                        di_flags |= XFS_DIFLAG_PROJINHERIT;
        } else if (S_ISREG(mode)) {
-               if ((pip->i_d.di_flags & XFS_DIFLAG_RTINHERIT) &&
+               if ((pip->i_diflags & XFS_DIFLAG_RTINHERIT) &&
                    xfs_sb_version_hasrealtime(&ip->i_mount->m_sb))
                        di_flags |= XFS_DIFLAG_REALTIME;
-               if (pip->i_d.di_flags & XFS_DIFLAG_EXTSZINHERIT) {
+               if (pip->i_diflags & XFS_DIFLAG_EXTSZINHERIT) {
                        di_flags |= XFS_DIFLAG_EXTSIZE;
-                       ip->i_d.di_extsize = pip->i_d.di_extsize;
+                       ip->i_extsize = pip->i_extsize;
                }
        }
-       if ((pip->i_d.di_flags & XFS_DIFLAG_NOATIME) &&
+       if ((pip->i_diflags & XFS_DIFLAG_NOATIME) &&
            xfs_inherit_noatime)
                di_flags |= XFS_DIFLAG_NOATIME;
-       if ((pip->i_d.di_flags & XFS_DIFLAG_NODUMP) &&
+       if ((pip->i_diflags & XFS_DIFLAG_NODUMP) &&
            xfs_inherit_nodump)
                di_flags |= XFS_DIFLAG_NODUMP;
-       if ((pip->i_d.di_flags & XFS_DIFLAG_SYNC) &&
+       if ((pip->i_diflags & XFS_DIFLAG_SYNC) &&
            xfs_inherit_sync)
                di_flags |= XFS_DIFLAG_SYNC;
-       if ((pip->i_d.di_flags & XFS_DIFLAG_NOSYMLINKS) &&
+       if ((pip->i_diflags & XFS_DIFLAG_NOSYMLINKS) &&
            xfs_inherit_nosymlinks)
                di_flags |= XFS_DIFLAG_NOSYMLINKS;
-       if ((pip->i_d.di_flags & XFS_DIFLAG_NODEFRAG) &&
+       if ((pip->i_diflags & XFS_DIFLAG_NODEFRAG) &&
            xfs_inherit_nodefrag)
                di_flags |= XFS_DIFLAG_NODEFRAG;
-       if (pip->i_d.di_flags & XFS_DIFLAG_FILESTREAM)
+       if (pip->i_diflags & XFS_DIFLAG_FILESTREAM)
                di_flags |= XFS_DIFLAG_FILESTREAM;
  
-       ip->i_d.di_flags |= di_flags;
+       ip->i_diflags |= di_flags;
  }
  
  /* Propagate di_flags2 from a parent inode to a child inode. */
@@@ -752,12 -737,12 +737,12 @@@ xfs_inode_inherit_flags2
        struct xfs_inode        *ip,
        const struct xfs_inode  *pip)
  {
-       if (pip->i_d.di_flags2 & XFS_DIFLAG2_COWEXTSIZE) {
-               ip->i_d.di_flags2 |= XFS_DIFLAG2_COWEXTSIZE;
-               ip->i_d.di_cowextsize = pip->i_d.di_cowextsize;
+       if (pip->i_diflags2 & XFS_DIFLAG2_COWEXTSIZE) {
+               ip->i_diflags2 |= XFS_DIFLAG2_COWEXTSIZE;
+               ip->i_cowextsize = pip->i_cowextsize;
        }
-       if (pip->i_d.di_flags2 & XFS_DIFLAG2_DAX)
-               ip->i_d.di_flags2 |= XFS_DIFLAG2_DAX;
+       if (pip->i_diflags2 & XFS_DIFLAG2_DAX)
+               ip->i_diflags2 |= XFS_DIFLAG2_DAX;
  }
  
  /*
@@@ -774,6 -759,7 +759,7 @@@ xfs_init_new_inode
        xfs_nlink_t             nlink,
        dev_t                   rdev,
        prid_t                  prid,
+       bool                    init_xattrs,
        struct xfs_inode        **ipp)
  {
        struct inode            *dir = pip ? VFS_I(pip) : NULL;
        inode = VFS_I(ip);
        set_nlink(inode, nlink);
        inode->i_rdev = rdev;
-       ip->i_d.di_projid = prid;
+       ip->i_projid = prid;
  
        if (dir && !(dir->i_mode & S_ISGID) &&
            (mp->m_flags & XFS_MOUNT_GRPID)) {
 -              inode->i_uid = fsuid_into_mnt(mnt_userns);
 +              inode_fsuid_set(inode, mnt_userns);
                inode->i_gid = dir->i_gid;
                inode->i_mode = mode;
        } else {
            !in_group_p(i_gid_into_mnt(mnt_userns, inode)))
                inode->i_mode &= ~S_ISGID;
  
-       ip->i_d.di_size = 0;
+       ip->i_disk_size = 0;
        ip->i_df.if_nextents = 0;
-       ASSERT(ip->i_d.di_nblocks == 0);
+       ASSERT(ip->i_nblocks == 0);
  
        tv = current_time(inode);
        inode->i_mtime = tv;
        inode->i_atime = tv;
        inode->i_ctime = tv;
  
-       ip->i_d.di_extsize = 0;
-       ip->i_d.di_dmevmask = 0;
-       ip->i_d.di_dmstate = 0;
-       ip->i_d.di_flags = 0;
+       ip->i_extsize = 0;
+       ip->i_diflags = 0;
  
        if (xfs_sb_version_has_v3inode(&mp->m_sb)) {
                inode_set_iversion(inode, 1);
-               ip->i_d.di_flags2 = mp->m_ino_geo.new_diflags2;
-               ip->i_d.di_cowextsize = 0;
-               ip->i_d.di_crtime = tv;
+               ip->i_cowextsize = 0;
+               ip->i_crtime = tv;
        }
  
        flags = XFS_ILOG_CORE;
        case S_IFBLK:
        case S_IFSOCK:
                ip->i_df.if_format = XFS_DINODE_FMT_DEV;
-               ip->i_df.if_flags = 0;
                flags |= XFS_ILOG_DEV;
                break;
        case S_IFREG:
        case S_IFDIR:
-               if (pip && (pip->i_d.di_flags & XFS_DIFLAG_ANY))
+               if (pip && (pip->i_diflags & XFS_DIFLAG_ANY))
                        xfs_inode_inherit_flags(ip, pip);
-               if (pip && (pip->i_d.di_flags2 & XFS_DIFLAG2_ANY))
+               if (pip && (pip->i_diflags2 & XFS_DIFLAG2_ANY))
                        xfs_inode_inherit_flags2(ip, pip);
                /* FALLTHROUGH */
        case S_IFLNK:
                ip->i_df.if_format = XFS_DINODE_FMT_EXTENTS;
-               ip->i_df.if_flags = XFS_IFEXTENTS;
                ip->i_df.if_bytes = 0;
                ip->i_df.if_u1.if_root = NULL;
                break;
                ASSERT(0);
        }
  
+       /*
+        * If we need to create attributes immediately after allocating the
+        * inode, initialise an empty attribute fork right now. We use the
+        * default fork offset for attributes here as we don't know exactly what
+        * size or how many attributes we might be adding. We can do this
+        * safely here because we know the data fork is completely empty and
+        * this saves us from needing to run a separate transaction to set the
+        * fork offset in the immediate future.
+        */
+       if (init_xattrs && xfs_sb_version_hasattr(&mp->m_sb)) {
+               ip->i_forkoff = xfs_default_attroffset(ip) >> 3;
+               ip->i_afp = xfs_ifork_alloc(XFS_DINODE_FMT_EXTENTS, 0);
+       }
        /*
         * Log the new values stuffed into the inode.
         */
@@@ -910,6 -905,7 +905,7 @@@ xfs_dir_ialloc
        xfs_nlink_t             nlink,
        dev_t                   rdev,
        prid_t                  prid,
+       bool                    init_xattrs,
        struct xfs_inode        **ipp)
  {
        struct xfs_buf          *agibp;
        ASSERT(ino != NULLFSINO);
  
        return xfs_init_new_inode(mnt_userns, *tpp, dp, ino, mode, nlink, rdev,
-                                 prid, ipp);
+                                 prid, init_xattrs, ipp);
  }
  
  /*
@@@ -982,6 -978,7 +978,7 @@@ xfs_create
        struct xfs_name         *name,
        umode_t                 mode,
        dev_t                   rdev,
+       bool                    init_xattrs,
        xfs_inode_t             **ipp)
  {
        int                     is_dir = S_ISDIR(mode);
        /*
         * Make sure that we have allocated dquot(s) on disk.
         */
 -      error = xfs_qm_vop_dqalloc(dp, fsuid_into_mnt(mnt_userns),
 -                      fsgid_into_mnt(mnt_userns), prid,
 +      error = xfs_qm_vop_dqalloc(dp, mapped_fsuid(mnt_userns),
 +                      mapped_fsgid(mnt_userns), prid,
                        XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT,
                        &udqp, &gdqp, &pdqp);
        if (error)
         * pointing to itself.
         */
        error = xfs_dir_ialloc(mnt_userns, &tp, dp, mode, is_dir ? 2 : 1, rdev,
-                              prid, &ip);
+                              prid, init_xattrs, &ip);
        if (error)
                goto out_trans_cancel;
  
@@@ -1158,8 -1155,8 +1155,8 @@@ xfs_create_tmpfile
        /*
         * Make sure that we have allocated dquot(s) on disk.
         */
 -      error = xfs_qm_vop_dqalloc(dp, fsuid_into_mnt(mnt_userns),
 -                      fsgid_into_mnt(mnt_userns), prid,
 +      error = xfs_qm_vop_dqalloc(dp, mapped_fsuid(mnt_userns),
 +                      mapped_fsgid(mnt_userns), prid,
                        XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT,
                        &udqp, &gdqp, &pdqp);
        if (error)
        if (error)
                goto out_release_dquots;
  
-       error = xfs_dir_ialloc(mnt_userns, &tp, dp, mode, 0, 0, prid, &ip);
+       error = xfs_dir_ialloc(mnt_userns, &tp, dp, mode, 0, 0, prid,
+                               false, &ip);
        if (error)
                goto out_trans_cancel;
  
@@@ -1272,8 -1270,8 +1270,8 @@@ xfs_link
         * creation in our tree when the project IDs are the same; else
         * the tree quota mechanism could be circumvented.
         */
-       if (unlikely((tdp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) &&
-                    tdp->i_d.di_projid != sip->i_d.di_projid)) {
+       if (unlikely((tdp->i_diflags & XFS_DIFLAG_PROJINHERIT) &&
+                    tdp->i_projid != sip->i_projid)) {
                error = -EXDEV;
                goto error_return;
        }
@@@ -1331,7 -1329,7 +1329,7 @@@ xfs_itruncate_clear_reflink_flags
        dfork = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
        cfork = XFS_IFORK_PTR(ip, XFS_COW_FORK);
        if (dfork->if_bytes == 0 && cfork->if_bytes == 0)
-               ip->i_d.di_flags2 &= ~XFS_DIFLAG2_REFLINK;
+               ip->i_diflags2 &= ~XFS_DIFLAG2_REFLINK;
        if (cfork->if_bytes == 0)
                xfs_inode_clear_cowblocks_tag(ip);
  }
@@@ -1442,7 -1440,7 +1440,7 @@@ xfs_release
        xfs_inode_t     *ip)
  {
        xfs_mount_t     *mp = ip->i_mount;
-       int             error;
+       int             error = 0;
  
        if (!S_ISREG(VFS_I(ip)->i_mode) || (VFS_I(ip)->i_mode == 0))
                return 0;
        if (VFS_I(ip)->i_nlink == 0)
                return 0;
  
-       if (xfs_can_free_eofblocks(ip, false)) {
+       /*
+        * If we can't get the iolock just skip truncating the blocks past EOF
+        * because we could deadlock with the mmap_lock otherwise. We'll get
+        * another chance to drop them once the last reference to the inode is
+        * dropped, so we'll never leak blocks permanently.
+        */
+       if (!xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL))
+               return 0;
  
+       if (xfs_can_free_eofblocks(ip, false)) {
                /*
                 * Check if the inode is being opened, written and closed
                 * frequently and we have delayed allocation blocks outstanding
                 * place.
                 */
                if (xfs_iflags_test(ip, XFS_IDIRTY_RELEASE))
-                       return 0;
-               /*
-                * If we can't get the iolock just skip truncating the blocks
-                * past EOF because we could deadlock with the mmap_lock
-                * otherwise. We'll get another chance to drop them once the
-                * last reference to the inode is dropped, so we'll never leak
-                * blocks permanently.
-                */
-               if (xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL)) {
-                       error = xfs_free_eofblocks(ip);
-                       xfs_iunlock(ip, XFS_IOLOCK_EXCL);
-                       if (error)
-                               return error;
-               }
+                       goto out_unlock;
+               error = xfs_free_eofblocks(ip);
+               if (error)
+                       goto out_unlock;
  
                /* delalloc blocks after truncation means it really is dirty */
                if (ip->i_delayed_blks)
                        xfs_iflags_set(ip, XFS_IDIRTY_RELEASE);
        }
-       return 0;
+ out_unlock:
+       xfs_iunlock(ip, XFS_IOLOCK_EXCL);
+       return error;
  }
  
  /*
@@@ -1543,7 -1543,7 +1543,7 @@@ xfs_inactive_truncate
         * of a system crash before the truncate completes. See the related
         * comment in xfs_vn_setattr_size() for details.
         */
-       ip->i_d.di_size = 0;
+       ip->i_disk_size = 0;
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
  
        error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, 0);
@@@ -1697,6 -1697,10 +1697,10 @@@ xfs_inactive
        if (mp->m_flags & XFS_MOUNT_RDONLY)
                return;
  
+       /* Metadata inodes require explicit resource cleanup. */
+       if (xfs_is_metadata_inode(ip))
+               return;
        /* Try to clean out the cow blocks if there are any. */
        if (xfs_inode_has_cow_data(ip))
                xfs_reflink_cancel_cow_range(ip, 0, NULLFILEOFF, true);
        }
  
        if (S_ISREG(VFS_I(ip)->i_mode) &&
-           (ip->i_d.di_size != 0 || XFS_ISIZE(ip) != 0 ||
+           (ip->i_disk_size != 0 || XFS_ISIZE(ip) != 0 ||
             ip->i_df.if_nextents > 0 || ip->i_delayed_blks > 0))
                truncate = 1;
  
        }
  
        ASSERT(!ip->i_afp);
-       ASSERT(ip->i_d.di_forkoff == 0);
+       ASSERT(ip->i_forkoff == 0);
  
        /*
         * Free the inode.
@@@ -2053,9 -2057,10 +2057,10 @@@ xfs_iunlink_update_inode
  
        ASSERT(xfs_verify_agino_or_null(mp, agno, next_agino));
  
-       error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &dip, &ibp, 0);
+       error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &ibp);
        if (error)
                return error;
+       dip = xfs_buf_offset(ibp, ip->i_imap.im_boffset);
  
        /* Make sure the old pointer isn't garbage. */
        old_value = be32_to_cpu(dip->di_next_unlinked);
@@@ -2180,13 -2185,14 +2185,14 @@@ xfs_iunlink_map_ino
                return error;
        }
  
-       error = xfs_imap_to_bp(mp, tp, imap, dipp, bpp, 0);
+       error = xfs_imap_to_bp(mp, tp, imap, bpp);
        if (error) {
                xfs_warn(mp, "%s: xfs_imap_to_bp returned error %d.",
                                __func__, error);
                return error;
        }
  
+       *dipp = xfs_buf_offset(*bpp, imap->im_boffset);
        return 0;
  }
  
@@@ -2564,8 -2570,8 +2570,8 @@@ xfs_ifree
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
        ASSERT(VFS_I(ip)->i_nlink == 0);
        ASSERT(ip->i_df.if_nextents == 0);
-       ASSERT(ip->i_d.di_size == 0 || !S_ISREG(VFS_I(ip)->i_mode));
-       ASSERT(ip->i_d.di_nblocks == 0);
+       ASSERT(ip->i_disk_size == 0 || !S_ISREG(VFS_I(ip)->i_mode));
+       ASSERT(ip->i_nblocks == 0);
  
        /*
         * Pull the on-disk inode from the AGI unlinked list.
        }
  
        VFS_I(ip)->i_mode = 0;          /* mark incore inode as free */
-       ip->i_d.di_flags = 0;
-       ip->i_d.di_flags2 = ip->i_mount->m_ino_geo.new_diflags2;
-       ip->i_d.di_dmevmask = 0;
-       ip->i_d.di_forkoff = 0;         /* mark the attr fork not in use */
+       ip->i_diflags = 0;
+       ip->i_diflags2 = ip->i_mount->m_ino_geo.new_diflags2;
+       ip->i_forkoff = 0;              /* mark the attr fork not in use */
        ip->i_df.if_format = XFS_DINODE_FMT_EXTENTS;
+       if (xfs_iflags_test(ip, XFS_IPRESERVE_DM_FIELDS))
+               xfs_iflags_clear(ip, XFS_IPRESERVE_DM_FIELDS);
  
        /* Don't attempt to replay owner changes for a deleted inode */
        spin_lock(&iip->ili_lock);
@@@ -2870,7 -2877,7 +2877,7 @@@ xfs_finish_rename
  /*
   * xfs_cross_rename()
   *
-  * responsible for handling RENAME_EXCHANGE flag in renameat2() sytemcall
+  * responsible for handling RENAME_EXCHANGE flag in renameat2() syscall
   */
  STATIC int
  xfs_cross_rename(
@@@ -3103,8 -3110,8 +3110,8 @@@ xfs_rename
         * into our tree when the project IDs are the same; else the
         * tree quota mechanism would be circumvented.
         */
-       if (unlikely((target_dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) &&
-                    target_dp->i_d.di_projid != src_ip->i_d.di_projid)) {
+       if (unlikely((target_dp->i_diflags & XFS_DIFLAG_PROJINHERIT) &&
+                    target_dp->i_projid != src_ip->i_projid)) {
                error = -EXDEV;
                goto out_trans_cancel;
        }
@@@ -3414,34 -3421,33 +3421,33 @@@ xfs_iflush
                }
        }
        if (XFS_TEST_ERROR(ip->i_df.if_nextents + xfs_ifork_nextents(ip->i_afp) >
-                               ip->i_d.di_nblocks, mp, XFS_ERRTAG_IFLUSH_5)) {
+                               ip->i_nblocks, mp, XFS_ERRTAG_IFLUSH_5)) {
                xfs_alert_tag(mp, XFS_PTAG_IFLUSH,
                        "%s: detected corrupt incore inode %Lu, "
                        "total extents = %d, nblocks = %Ld, ptr "PTR_FMT,
                        __func__, ip->i_ino,
                        ip->i_df.if_nextents + xfs_ifork_nextents(ip->i_afp),
-                       ip->i_d.di_nblocks, ip);
+                       ip->i_nblocks, ip);
                goto flush_out;
        }
-       if (XFS_TEST_ERROR(ip->i_d.di_forkoff > mp->m_sb.sb_inodesize,
+       if (XFS_TEST_ERROR(ip->i_forkoff > mp->m_sb.sb_inodesize,
                                mp, XFS_ERRTAG_IFLUSH_6)) {
                xfs_alert_tag(mp, XFS_PTAG_IFLUSH,
                        "%s: bad inode %Lu, forkoff 0x%x, ptr "PTR_FMT,
-                       __func__, ip->i_ino, ip->i_d.di_forkoff, ip);
+                       __func__, ip->i_ino, ip->i_forkoff, ip);
                goto flush_out;
        }
  
        /*
-        * Inode item log recovery for v2 inodes are dependent on the
-        * di_flushiter count for correct sequencing. We bump the flush
-        * iteration count so we can detect flushes which postdate a log record
-        * during recovery. This is redundant as we now log every change and
-        * hence this can't happen but we need to still do it to ensure
-        * backwards compatibility with old kernels that predate logging all
-        * inode changes.
+        * Inode item log recovery for v2 inodes are dependent on the flushiter
+        * count for correct sequencing.  We bump the flush iteration count so
+        * we can detect flushes which postdate a log record during recovery.
+        * This is redundant as we now log every change and hence this can't
+        * happen but we need to still do it to ensure backwards compatibility
+        * with old kernels that predate logging all inode changes.
         */
        if (!xfs_sb_version_has_v3inode(&mp->m_sb))
-               ip->i_d.di_flushiter++;
+               ip->i_flushiter++;
  
        /*
         * If there are inline format data / attr forks attached to this inode,
        xfs_inode_to_disk(ip, dip, iip->ili_item.li_lsn);
  
        /* Wrap, we never let the log put out DI_MAX_FLUSH */
-       if (ip->i_d.di_flushiter == DI_MAX_FLUSH)
-               ip->i_d.di_flushiter = 0;
+       if (!xfs_sb_version_has_v3inode(&mp->m_sb)) {
+               if (ip->i_flushiter == DI_MAX_FLUSH)
+                       ip->i_flushiter = 0;
+       }
  
        xfs_iflush_fork(ip, dip, iip, XFS_DATA_FORK);
        if (XFS_IFORK_Q(ip))
diff --combined fs/xfs/xfs_ioctl.c
index bbda105a2ce504b4c3e46137ecb329bf9871abe9,bf490bfae6cbb101d26e7ce8b5709b5176df88a7..3925bfcb236570bf75241e466b15d2aa70f30461
@@@ -40,7 -40,6 +40,7 @@@
  
  #include <linux/mount.h>
  #include <linux/namei.h>
 +#include <linux/fileattr.h>
  
  /*
   * xfs_find_handle maps from userspace xfs_fsop_handlereq structure to
@@@ -1054,53 -1053,99 +1054,55 @@@ xfs_ioc_ag_geometry
   * Linux extended inode flags interface.
   */
  
 -STATIC unsigned int
 -xfs_merge_ioc_xflags(
 -      unsigned int    flags,
 -      unsigned int    start)
 -{
 -      unsigned int    xflags = start;
 -
 -      if (flags & FS_IMMUTABLE_FL)
 -              xflags |= FS_XFLAG_IMMUTABLE;
 -      else
 -              xflags &= ~FS_XFLAG_IMMUTABLE;
 -      if (flags & FS_APPEND_FL)
 -              xflags |= FS_XFLAG_APPEND;
 -      else
 -              xflags &= ~FS_XFLAG_APPEND;
 -      if (flags & FS_SYNC_FL)
 -              xflags |= FS_XFLAG_SYNC;
 -      else
 -              xflags &= ~FS_XFLAG_SYNC;
 -      if (flags & FS_NOATIME_FL)
 -              xflags |= FS_XFLAG_NOATIME;
 -      else
 -              xflags &= ~FS_XFLAG_NOATIME;
 -      if (flags & FS_NODUMP_FL)
 -              xflags |= FS_XFLAG_NODUMP;
 -      else
 -              xflags &= ~FS_XFLAG_NODUMP;
 -      if (flags & FS_DAX_FL)
 -              xflags |= FS_XFLAG_DAX;
 -      else
 -              xflags &= ~FS_XFLAG_DAX;
 -
 -      return xflags;
 -}
 -
 -STATIC unsigned int
 -xfs_di2lxflags(
 -      uint16_t        di_flags,
 -      uint64_t        di_flags2)
 -{
 -      unsigned int    flags = 0;
 -
 -      if (di_flags & XFS_DIFLAG_IMMUTABLE)
 -              flags |= FS_IMMUTABLE_FL;
 -      if (di_flags & XFS_DIFLAG_APPEND)
 -              flags |= FS_APPEND_FL;
 -      if (di_flags & XFS_DIFLAG_SYNC)
 -              flags |= FS_SYNC_FL;
 -      if (di_flags & XFS_DIFLAG_NOATIME)
 -              flags |= FS_NOATIME_FL;
 -      if (di_flags & XFS_DIFLAG_NODUMP)
 -              flags |= FS_NODUMP_FL;
 -      if (di_flags2 & XFS_DIFLAG2_DAX) {
 -              flags |= FS_DAX_FL;
 -      }
 -      return flags;
 -}
 -
  static void
  xfs_fill_fsxattr(
        struct xfs_inode        *ip,
 -      bool                    attr,
 -      struct fsxattr          *fa)
 +      int                     whichfork,
 +      struct fileattr         *fa)
  {
 -      struct xfs_ifork        *ifp = attr ? ip->i_afp : &ip->i_df;
+       struct xfs_mount        *mp = ip->i_mount;
 +      struct xfs_ifork        *ifp = XFS_IFORK_PTR(ip, whichfork);
  
 -      simple_fill_fsxattr(fa, xfs_ip2xflags(ip));
 +      fileattr_fill_xflags(fa, xfs_ip2xflags(ip));
-       fa->fsx_extsize = ip->i_d.di_extsize << ip->i_mount->m_sb.sb_blocklog;
-       fa->fsx_cowextsize = ip->i_d.di_cowextsize <<
-                       ip->i_mount->m_sb.sb_blocklog;
-       fa->fsx_projid = ip->i_d.di_projid;
-       if (ifp && (ifp->if_flags & XFS_IFEXTENTS))
+       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;
+       if (ifp && !xfs_need_iread_extents(ifp))
                fa->fsx_nextents = xfs_iext_count(ifp);
        else
                fa->fsx_nextents = xfs_ifork_nextents(ifp);
  }
  
  STATIC int
 -xfs_ioc_fsgetxattr(
 +xfs_ioc_fsgetxattra(
        xfs_inode_t             *ip,
 -      int                     attr,
        void                    __user *arg)
  {
 -      struct fsxattr          fa;
 +      struct fileattr         fa;
  
        xfs_ilock(ip, XFS_ILOCK_SHARED);
 -      xfs_fill_fsxattr(ip, attr, &fa);
 +      xfs_fill_fsxattr(ip, XFS_ATTR_FORK, &fa);
 +      xfs_iunlock(ip, XFS_ILOCK_SHARED);
 +
 +      return copy_fsxattr_to_user(&fa, arg);
 +}
 +
 +int
 +xfs_fileattr_get(
 +      struct dentry           *dentry,
 +      struct fileattr         *fa)
 +{
 +      struct xfs_inode        *ip = XFS_I(d_inode(dentry));
 +
 +      if (d_is_special(dentry))
 +              return -ENOTTY;
 +
 +      xfs_ilock(ip, XFS_ILOCK_SHARED);
 +      xfs_fill_fsxattr(ip, XFS_DATA_FORK, fa);
        xfs_iunlock(ip, XFS_ILOCK_SHARED);
  
 -      if (copy_to_user(arg, &fa, sizeof(fa)))
 -              return -EFAULT;
        return 0;
  }
  
@@@ -1111,7 -1156,7 +1113,7 @@@ xfs_flags2diflags
  {
        /* can't set PREALLOC this way, just preserve it */
        uint16_t                di_flags =
-               (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC);
+               (ip->i_diflags & XFS_DIFLAG_PREALLOC);
  
        if (xflags & FS_XFLAG_IMMUTABLE)
                di_flags |= XFS_DIFLAG_IMMUTABLE;
@@@ -1152,8 -1197,8 +1154,8 @@@ xfs_flags2diflags2
        unsigned int            xflags)
  {
        uint64_t                di_flags2 =
-               (ip->i_d.di_flags2 & (XFS_DIFLAG2_REFLINK |
-                                     XFS_DIFLAG2_BIGTIME));
+               (ip->i_diflags2 & (XFS_DIFLAG2_REFLINK |
+                                  XFS_DIFLAG2_BIGTIME));
  
        if (xflags & FS_XFLAG_DAX)
                di_flags2 |= XFS_DIFLAG2_DAX;
@@@ -1167,10 -1212,10 +1169,10 @@@ static in
  xfs_ioctl_setattr_xflags(
        struct xfs_trans        *tp,
        struct xfs_inode        *ip,
 -      struct fsxattr          *fa)
 +      struct fileattr         *fa)
  {
        struct xfs_mount        *mp = ip->i_mount;
-       uint64_t                di_flags2;
+       uint64_t                i_flags2;
  
        /* Can't change realtime flag if any extents are allocated. */
        if ((ip->i_df.if_nextents || ip->i_delayed_blks) &&
        /* If realtime flag is set then must have realtime device */
        if (fa->fsx_xflags & FS_XFLAG_REALTIME) {
                if (mp->m_sb.sb_rblocks == 0 || mp->m_sb.sb_rextsize == 0 ||
-                   (ip->i_d.di_extsize % mp->m_sb.sb_rextsize))
+                   (ip->i_extsize % mp->m_sb.sb_rextsize))
                        return -EINVAL;
        }
  
        /* Clear reflink if we are actually able to set the rt flag. */
        if ((fa->fsx_xflags & FS_XFLAG_REALTIME) && xfs_is_reflink_inode(ip))
-               ip->i_d.di_flags2 &= ~XFS_DIFLAG2_REFLINK;
+               ip->i_diflags2 &= ~XFS_DIFLAG2_REFLINK;
  
        /* Don't allow us to set DAX mode for a reflinked file for now. */
        if ((fa->fsx_xflags & FS_XFLAG_DAX) && xfs_is_reflink_inode(ip))
                return -EINVAL;
  
        /* diflags2 only valid for v3 inodes. */
-       di_flags2 = xfs_flags2diflags2(ip, fa->fsx_xflags);
-       if (di_flags2 && !xfs_sb_version_has_v3inode(&mp->m_sb))
+       i_flags2 = xfs_flags2diflags2(ip, fa->fsx_xflags);
+       if (i_flags2 && !xfs_sb_version_has_v3inode(&mp->m_sb))
                return -EINVAL;
  
-       ip->i_d.di_flags = xfs_flags2diflags(ip, fa->fsx_xflags);
-       ip->i_d.di_flags2 = di_flags2;
+       ip->i_diflags = xfs_flags2diflags(ip, fa->fsx_xflags);
+       ip->i_diflags2 = i_flags2;
  
        xfs_diflags_to_iflags(ip, false);
        xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG);
  static void
  xfs_ioctl_setattr_prepare_dax(
        struct xfs_inode        *ip,
 -      struct fsxattr          *fa)
 +      struct fileattr         *fa)
  {
        struct xfs_mount        *mp = ip->i_mount;
        struct inode            *inode = VFS_I(ip);
                return;
  
        if (((fa->fsx_xflags & FS_XFLAG_DAX) &&
-           !(ip->i_d.di_flags2 & XFS_DIFLAG2_DAX)) ||
+           !(ip->i_diflags2 & XFS_DIFLAG2_DAX)) ||
            (!(fa->fsx_xflags & FS_XFLAG_DAX) &&
-            (ip->i_d.di_flags2 & XFS_DIFLAG2_DAX)))
+            (ip->i_diflags2 & XFS_DIFLAG2_DAX)))
                d_mark_dontcache(inode);
  }
  
   */
  static struct xfs_trans *
  xfs_ioctl_setattr_get_trans(
 -      struct file             *file,
 +      struct xfs_inode        *ip,
        struct xfs_dquot        *pdqp)
  {
 -      struct xfs_inode        *ip = XFS_I(file_inode(file));
        struct xfs_mount        *mp = ip->i_mount;
        struct xfs_trans        *tp;
        int                     error = -EROFS;
        if (error)
                goto out_error;
  
 -      /*
 -       * CAP_FOWNER overrides the following restrictions:
 -       *
 -       * The user ID of the calling process must be equal to the file owner
 -       * ID, except in cases where the CAP_FSETID capability is applicable.
 -       */
 -      if (!inode_owner_or_capable(file_mnt_user_ns(file), VFS_I(ip))) {
 -              error = -EPERM;
 -              goto out_cancel;
 -      }
 -
        if (mp->m_flags & XFS_MOUNT_WSYNC)
                xfs_trans_set_sync(tp);
  
        return tp;
  
 -out_cancel:
 -      xfs_trans_cancel(tp);
  out_error:
        return ERR_PTR(error);
  }
  static int
  xfs_ioctl_setattr_check_extsize(
        struct xfs_inode        *ip,
 -      struct fsxattr          *fa)
 +      struct fileattr         *fa)
  {
        struct xfs_mount        *mp = ip->i_mount;
        xfs_extlen_t            size;
        xfs_fsblock_t           extsize_fsb;
  
 +      if (!fa->fsx_valid)
 +              return 0;
 +
        if (S_ISREG(VFS_I(ip)->i_mode) && ip->i_df.if_nextents &&
-           ((ip->i_d.di_extsize << mp->m_sb.sb_blocklog) != fa->fsx_extsize))
+           ((ip->i_extsize << mp->m_sb.sb_blocklog) != fa->fsx_extsize))
                return -EINVAL;
  
        if (fa->fsx_extsize == 0)
  static int
  xfs_ioctl_setattr_check_cowextsize(
        struct xfs_inode        *ip,
 -      struct fsxattr          *fa)
 +      struct fileattr         *fa)
  {
        struct xfs_mount        *mp = ip->i_mount;
        xfs_extlen_t            size;
        xfs_fsblock_t           cowextsize_fsb;
  
 +      if (!fa->fsx_valid)
 +              return 0;
 +
        if (!(fa->fsx_xflags & FS_XFLAG_COWEXTSIZE))
                return 0;
  
  static int
  xfs_ioctl_setattr_check_projid(
        struct xfs_inode        *ip,
 -      struct fsxattr          *fa)
 +      struct fileattr         *fa)
  {
 +      if (!fa->fsx_valid)
 +              return 0;
 +
        /* Disallow 32bit project ids if projid32bit feature is not enabled. */
        if (fa->fsx_projid > (uint16_t)-1 &&
            !xfs_sb_version_hasprojid32bit(&ip->i_mount->m_sb))
        return 0;
  }
  
 -STATIC int
 -xfs_ioctl_setattr(
 -      struct file             *file,
 -      struct fsxattr          *fa)
 +int
 +xfs_fileattr_set(
 +      struct user_namespace   *mnt_userns,
 +      struct dentry           *dentry,
 +      struct fileattr         *fa)
  {
 -      struct user_namespace   *mnt_userns = file_mnt_user_ns(file);
 -      struct xfs_inode        *ip = XFS_I(file_inode(file));
 -      struct fsxattr          old_fa;
 +      struct xfs_inode        *ip = XFS_I(d_inode(dentry));
        struct xfs_mount        *mp = ip->i_mount;
        struct xfs_trans        *tp;
        struct xfs_dquot        *pdqp = NULL;
  
        trace_xfs_ioctl_setattr(ip);
  
 +      if (d_is_special(dentry))
 +              return -ENOTTY;
 +
 +      if (!fa->fsx_valid) {
 +              if (fa->flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL |
 +                                FS_NOATIME_FL | FS_NODUMP_FL |
 +                                FS_SYNC_FL | FS_DAX_FL | FS_PROJINHERIT_FL))
 +                      return -EOPNOTSUPP;
 +      }
 +
        error = xfs_ioctl_setattr_check_projid(ip, fa);
        if (error)
                return error;
         * If the IDs do change before we take the ilock, we're covered
         * because the i_*dquot fields will get updated anyway.
         */
 -      if (XFS_IS_QUOTA_ON(mp)) {
 +      if (fa->fsx_valid && XFS_IS_QUOTA_ON(mp)) {
                error = xfs_qm_vop_dqalloc(ip, VFS_I(ip)->i_uid,
                                VFS_I(ip)->i_gid, fa->fsx_projid,
                                XFS_QMOPT_PQUOTA, NULL, NULL, &pdqp);
  
        xfs_ioctl_setattr_prepare_dax(ip, fa);
  
 -      tp = xfs_ioctl_setattr_get_trans(file, pdqp);
 +      tp = xfs_ioctl_setattr_get_trans(ip, pdqp);
        if (IS_ERR(tp)) {
                error = PTR_ERR(tp);
                goto error_free_dquots;
        }
  
 -      xfs_fill_fsxattr(ip, false, &old_fa);
 -      error = vfs_ioc_fssetxattr_check(VFS_I(ip), &old_fa, fa);
 -      if (error)
 -              goto error_trans_cancel;
 -
        error = xfs_ioctl_setattr_check_extsize(ip, fa);
        if (error)
                goto error_trans_cancel;
        if (error)
                goto error_trans_cancel;
  
 +      if (!fa->fsx_valid)
 +              goto skip_xattr;
        /*
         * Change file ownership.  Must be the owner or privileged.  CAP_FSETID
         * overrides the following restrictions:
                VFS_I(ip)->i_mode &= ~(S_ISUID|S_ISGID);
  
        /* Change the ownerships and register project quota modifications */
-       if (ip->i_d.di_projid != fa->fsx_projid) {
+       if (ip->i_projid != fa->fsx_projid) {
                if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_PQUOTA_ON(mp)) {
                        olddquot = xfs_qm_vop_chown(tp, ip,
                                                &ip->i_pdquot, pdqp);
                }
-               ip->i_d.di_projid = fa->fsx_projid;
+               ip->i_projid = fa->fsx_projid;
        }
  
        /*
         * extent size hint should be set on the inode. If no extent size flags
         * are set on the inode then unconditionally clear the extent size hint.
         */
-       if (ip->i_d.di_flags & (XFS_DIFLAG_EXTSIZE | XFS_DIFLAG_EXTSZINHERIT))
-               ip->i_d.di_extsize = fa->fsx_extsize >> mp->m_sb.sb_blocklog;
-       else
-               ip->i_d.di_extsize = 0;
-       if (xfs_sb_version_has_v3inode(&mp->m_sb) &&
-           (ip->i_d.di_flags2 & XFS_DIFLAG2_COWEXTSIZE))
-               ip->i_d.di_cowextsize = fa->fsx_cowextsize >>
-                               mp->m_sb.sb_blocklog;
+       if (ip->i_diflags & (XFS_DIFLAG_EXTSIZE | XFS_DIFLAG_EXTSZINHERIT))
+               ip->i_extsize = XFS_B_TO_FSB(mp, fa->fsx_extsize);
        else
-               ip->i_d.di_cowextsize = 0;
+               ip->i_extsize = 0;
+       if (xfs_sb_version_has_v3inode(&mp->m_sb)) {
+               if (ip->i_diflags2 & XFS_DIFLAG2_COWEXTSIZE)
+                       ip->i_cowextsize = XFS_B_TO_FSB(mp, fa->fsx_cowextsize);
+               else
+                       ip->i_cowextsize = 0;
+       }
  
 +skip_xattr:
        error = xfs_trans_commit(tp);
  
        /*
@@@ -1505,6 -1549,91 +1508,6 @@@ error_free_dquots
        return error;
  }
  
 -STATIC int
 -xfs_ioc_fssetxattr(
 -      struct file             *filp,
 -      void                    __user *arg)
 -{
 -      struct fsxattr          fa;
 -      int error;
 -
 -      if (copy_from_user(&fa, arg, sizeof(fa)))
 -              return -EFAULT;
 -
 -      error = mnt_want_write_file(filp);
 -      if (error)
 -              return error;
 -      error = xfs_ioctl_setattr(filp, &fa);
 -      mnt_drop_write_file(filp);
 -      return error;
 -}
 -
 -STATIC int
 -xfs_ioc_getxflags(
 -      xfs_inode_t             *ip,
 -      void                    __user *arg)
 -{
 -      unsigned int            flags;
 -
 -      flags = xfs_di2lxflags(ip->i_diflags, ip->i_diflags2);
 -      if (copy_to_user(arg, &flags, sizeof(flags)))
 -              return -EFAULT;
 -      return 0;
 -}
 -
 -STATIC int
 -xfs_ioc_setxflags(
 -      struct xfs_inode        *ip,
 -      struct file             *filp,
 -      void                    __user *arg)
 -{
 -      struct xfs_trans        *tp;
 -      struct fsxattr          fa;
 -      struct fsxattr          old_fa;
 -      unsigned int            flags;
 -      int                     error;
 -
 -      if (copy_from_user(&flags, arg, sizeof(flags)))
 -              return -EFAULT;
 -
 -      if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \
 -                    FS_NOATIME_FL | FS_NODUMP_FL | \
 -                    FS_SYNC_FL | FS_DAX_FL))
 -              return -EOPNOTSUPP;
 -
 -      fa.fsx_xflags = xfs_merge_ioc_xflags(flags, xfs_ip2xflags(ip));
 -
 -      error = mnt_want_write_file(filp);
 -      if (error)
 -              return error;
 -
 -      xfs_ioctl_setattr_prepare_dax(ip, &fa);
 -
 -      tp = xfs_ioctl_setattr_get_trans(filp, NULL);
 -      if (IS_ERR(tp)) {
 -              error = PTR_ERR(tp);
 -              goto out_drop_write;
 -      }
 -
 -      xfs_fill_fsxattr(ip, false, &old_fa);
 -      error = vfs_ioc_fssetxattr_check(VFS_I(ip), &old_fa, &fa);
 -      if (error) {
 -              xfs_trans_cancel(tp);
 -              goto out_drop_write;
 -      }
 -
 -      error = xfs_ioctl_setattr_xflags(tp, ip, &fa);
 -      if (error) {
 -              xfs_trans_cancel(tp);
 -              goto out_drop_write;
 -      }
 -
 -      error = xfs_trans_commit(tp);
 -out_drop_write:
 -      mnt_drop_write_file(filp);
 -      return error;
 -}
 -
  static bool
  xfs_getbmap_format(
        struct kgetbmap         *p,
@@@ -1543,8 -1672,6 +1546,6 @@@ xfs_ioc_getbmap
                bmx.bmv_iflags = BMV_IF_ATTRFORK;
                /*FALLTHRU*/
        case XFS_IOC_GETBMAP:
-               if (file->f_mode & FMODE_NOCMTIME)
-                       bmx.bmv_iflags |= BMV_IF_NO_DMAPI_READ;
                /* struct getbmap is a strict subset of struct getbmapx. */
                recsize = sizeof(struct getbmap);
                break;
@@@ -1720,7 -1847,7 +1721,7 @@@ out_free
  
  STATIC int
  xfs_ioc_scrub_metadata(
-       struct xfs_inode                *ip,
+       struct file                     *file,
        void                            __user *arg)
  {
        struct xfs_scrub_metadata       scrub;
        if (copy_from_user(&scrub, arg, sizeof(scrub)))
                return -EFAULT;
  
-       error = xfs_scrub_metadata(ip, &scrub);
+       error = xfs_scrub_metadata(file, &scrub);
        if (error)
                return error;
  
@@@ -2011,8 -2138,16 +2012,8 @@@ xfs_file_ioctl
        case XFS_IOC_GETVERSION:
                return put_user(inode->i_generation, (int __user *)arg);
  
 -      case XFS_IOC_FSGETXATTR:
 -              return xfs_ioc_fsgetxattr(ip, 0, arg);
        case XFS_IOC_FSGETXATTRA:
 -              return xfs_ioc_fsgetxattr(ip, 1, arg);
 -      case XFS_IOC_FSSETXATTR:
 -              return xfs_ioc_fssetxattr(filp, arg);
 -      case XFS_IOC_GETXFLAGS:
 -              return xfs_ioc_getxflags(ip, arg);
 -      case XFS_IOC_SETXFLAGS:
 -              return xfs_ioc_setxflags(ip, filp, arg);
 +              return xfs_ioc_fsgetxattra(ip, arg);
  
        case XFS_IOC_GETBMAP:
        case XFS_IOC_GETBMAPA:
                return xfs_ioc_getfsmap(ip, arg);
  
        case XFS_IOC_SCRUB_METADATA:
-               return xfs_ioc_scrub_metadata(ip, arg);
+               return xfs_ioc_scrub_metadata(filp, arg);
  
        case XFS_IOC_FD_TO_HANDLE:
        case XFS_IOC_PATH_TO_HANDLE:
diff --combined fs/xfs/xfs_iops.c
index e1f749b711f86bf1a45b69e6ae74d072dcd3bb16,8f2f74a496bd24da8471660833f8e71c73cfcf7f..dfe24b7f26e5a3d1decceaf8850bec67c30da667
@@@ -21,7 -21,6 +21,7 @@@
  #include "xfs_dir2.h"
  #include "xfs_iomap.h"
  #include "xfs_error.h"
 +#include "xfs_ioctl.h"
  
  #include <linux/posix_acl.h>
  #include <linux/security.h>
@@@ -127,6 -126,37 +127,37 @@@ xfs_cleanup_inode
        xfs_remove(XFS_I(dir), &teardown, XFS_I(inode));
  }
  
+ /*
+  * Check to see if we are likely to need an extended attribute to be added to
+  * the inode we are about to allocate. This allows the attribute fork to be
+  * created during the inode allocation, reducing the number of transactions we
+  * need to do in this fast path.
+  *
+  * The security checks are optimistic, but not guaranteed. The two LSMs that
+  * require xattrs to be added here (selinux and smack) are also the only two
+  * LSMs that add a sb->s_security structure to the superblock. Hence if security
+  * is enabled and sb->s_security is set, we have a pretty good idea that we are
+  * going to be asked to add a security xattr immediately after allocating the
+  * xfs inode and instantiating the VFS inode.
+  */
+ static inline bool
+ xfs_create_need_xattr(
+       struct inode    *dir,
+       struct posix_acl *default_acl,
+       struct posix_acl *acl)
+ {
+       if (acl)
+               return true;
+       if (default_acl)
+               return true;
+ #if IS_ENABLED(CONFIG_SECURITY)
+       if (dir->i_sb->s_security)
+               return true;
+ #endif
+       return false;
+ }
  STATIC int
  xfs_generic_create(
        struct user_namespace   *mnt_userns,
  
        if (!tmpfile) {
                error = xfs_create(mnt_userns, XFS_I(dir), &name, mode, rdev,
-                                  &ip);
+                               xfs_create_need_xattr(dir, default_acl, acl),
+                               &ip);
        } else {
                error = xfs_create_tmpfile(mnt_userns, XFS_I(dir), mode, &ip);
        }
@@@ -488,7 -519,7 +520,7 @@@ xfs_vn_get_link_inline
        struct xfs_inode        *ip = XFS_I(inode);
        char                    *link;
  
-       ASSERT(ip->i_df.if_flags & XFS_IFINLINE);
+       ASSERT(ip->i_df.if_format == XFS_DINODE_FMT_LOCAL);
  
        /*
         * The VFS crashes on a NULL pointer, so return -EFSCORRUPTED if
@@@ -563,13 -594,12 +595,12 @@@ xfs_vn_getattr
        stat->atime = inode->i_atime;
        stat->mtime = inode->i_mtime;
        stat->ctime = inode->i_ctime;
-       stat->blocks =
-               XFS_FSB_TO_BB(mp, ip->i_d.di_nblocks + ip->i_delayed_blks);
+       stat->blocks = XFS_FSB_TO_BB(mp, ip->i_nblocks + ip->i_delayed_blks);
  
        if (xfs_sb_version_has_v3inode(&mp->m_sb)) {
                if (request_mask & STATX_BTIME) {
                        stat->result_mask |= STATX_BTIME;
-                       stat->btime = ip->i_d.di_crtime;
+                       stat->btime = ip->i_crtime;
                }
        }
  
         * Note: If you add another clause to set an attribute flag, please
         * update attributes_mask below.
         */
-       if (ip->i_d.di_flags & XFS_DIFLAG_IMMUTABLE)
+       if (ip->i_diflags & XFS_DIFLAG_IMMUTABLE)
                stat->attributes |= STATX_ATTR_IMMUTABLE;
-       if (ip->i_d.di_flags & XFS_DIFLAG_APPEND)
+       if (ip->i_diflags & XFS_DIFLAG_APPEND)
                stat->attributes |= STATX_ATTR_APPEND;
-       if (ip->i_d.di_flags & XFS_DIFLAG_NODUMP)
+       if (ip->i_diflags & XFS_DIFLAG_NODUMP)
                stat->attributes |= STATX_ATTR_NODUMP;
  
        stat->attributes_mask |= (STATX_ATTR_IMMUTABLE |
@@@ -706,7 -736,7 +737,7 @@@ xfs_setattr_nonsize
                 */
                ASSERT(udqp == NULL);
                ASSERT(gdqp == NULL);
-               error = xfs_qm_vop_dqalloc(ip, uid, gid, ip->i_d.di_projid,
+               error = xfs_qm_vop_dqalloc(ip, uid, gid, ip->i_projid,
                                           qflags, &udqp, &gdqp, NULL);
                if (error)
                        return error;
@@@ -918,8 -948,8 +949,8 @@@ xfs_setattr_size
         * operation.
         *
         * And we update in-core i_size and truncate page cache beyond newsize
-        * before writeback the [di_size, newsize] range, so we're guaranteed
-        * not to write stale data past the new EOF on truncate down.
+        * before writeback the [i_disk_size, newsize] range, so we're
+        * guaranteed not to write stale data past the new EOF on truncate down.
         */
        truncate_setsize(inode, newsize);
  
         * otherwise those blocks may not be zeroed after a crash.
         */
        if (did_zeroing ||
-           (newsize > ip->i_d.di_size && oldsize != ip->i_d.di_size)) {
+           (newsize > ip->i_disk_size && oldsize != ip->i_disk_size)) {
                error = filemap_write_and_wait_range(VFS_I(ip)->i_mapping,
-                                               ip->i_d.di_size, newsize - 1);
+                                               ip->i_disk_size, newsize - 1);
                if (error)
                        return error;
        }
         * permanent before actually freeing any blocks it doesn't matter if
         * they get written to.
         */
-       ip->i_d.di_size = newsize;
+       ip->i_disk_size = newsize;
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
  
        if (newsize <= oldsize) {
@@@ -1153,8 -1183,6 +1184,8 @@@ static const struct inode_operations xf
        .listxattr              = xfs_vn_listxattr,
        .fiemap                 = xfs_vn_fiemap,
        .update_time            = xfs_vn_update_time,
 +      .fileattr_get           = xfs_fileattr_get,
 +      .fileattr_set           = xfs_fileattr_set,
  };
  
  static const struct inode_operations xfs_dir_inode_operations = {
        .listxattr              = xfs_vn_listxattr,
        .update_time            = xfs_vn_update_time,
        .tmpfile                = xfs_vn_tmpfile,
 +      .fileattr_get           = xfs_fileattr_get,
 +      .fileattr_set           = xfs_fileattr_set,
  };
  
  static const struct inode_operations xfs_dir_ci_inode_operations = {
        .listxattr              = xfs_vn_listxattr,
        .update_time            = xfs_vn_update_time,
        .tmpfile                = xfs_vn_tmpfile,
 +      .fileattr_get           = xfs_fileattr_get,
 +      .fileattr_set           = xfs_fileattr_set,
  };
  
  static const struct inode_operations xfs_symlink_inode_operations = {
@@@ -1262,7 -1286,7 +1293,7 @@@ xfs_inode_should_enable_dax
                return false;
        if (ip->i_mount->m_flags & XFS_MOUNT_DAX_ALWAYS)
                return true;
-       if (ip->i_d.di_flags2 & XFS_DIFLAG2_DAX)
+       if (ip->i_diflags2 & XFS_DIFLAG2_DAX)
                return true;
        return false;
  }
@@@ -1319,7 -1343,7 +1350,7 @@@ xfs_setup_inode
        /* make the inode look hashed for the writeback code */
        inode_fake_hash(inode);
  
-       i_size_write(inode, ip->i_d.di_size);
+       i_size_write(inode, ip->i_disk_size);
        xfs_diflags_to_iflags(ip, true);
  
        if (S_ISDIR(inode->i_mode)) {
@@@ -1377,7 -1401,7 +1408,7 @@@ xfs_setup_iops
                inode->i_fop = &xfs_dir_file_operations;
                break;
        case S_IFLNK:
-               if (ip->i_df.if_flags & XFS_IFINLINE)
+               if (ip->i_df.if_format == XFS_DINODE_FMT_LOCAL)
                        inode->i_op = &xfs_inline_symlink_inode_operations;
                else
                        inode->i_op = &xfs_symlink_inode_operations;
diff --combined fs/xfs/xfs_symlink.c
index 63edb4dbed4abbc123084f4c629d6dedc3965c43,b4fa702823834b9f4c51abbc5f1ba1dddf017a29..99fbec32c10afe0084c35b0410be88a2f69fc45e
@@@ -33,7 -33,7 +33,7 @@@ xfs_readlink_bmap_ilocked
        struct xfs_buf          *bp;
        xfs_daddr_t             d;
        char                    *cur_chunk;
-       int                     pathlen = ip->i_d.di_size;
+       int                     pathlen = ip->i_disk_size;
        int                     nmaps = XFS_SYMLINK_MAPS;
        int                     byte_cnt;
        int                     n;
@@@ -86,7 -86,7 +86,7 @@@
        }
        ASSERT(pathlen == 0);
  
-       link[ip->i_d.di_size] = '\0';
+       link[ip->i_disk_size] = '\0';
        error = 0;
  
   out:
@@@ -104,14 -104,14 +104,14 @@@ xfs_readlink
  
        trace_xfs_readlink(ip);
  
-       ASSERT(!(ip->i_df.if_flags & XFS_IFINLINE));
+       ASSERT(ip->i_df.if_format != XFS_DINODE_FMT_LOCAL);
  
        if (XFS_FORCED_SHUTDOWN(mp))
                return -EIO;
  
        xfs_ilock(ip, XFS_ILOCK_SHARED);
  
-       pathlen = ip->i_d.di_size;
+       pathlen = ip->i_disk_size;
        if (!pathlen)
                goto out;
  
@@@ -182,8 -182,8 +182,8 @@@ xfs_symlink
        /*
         * Make sure that we have allocated dquot(s) on disk.
         */
 -      error = xfs_qm_vop_dqalloc(dp, fsuid_into_mnt(mnt_userns),
 -                      fsgid_into_mnt(mnt_userns), prid,
 +      error = xfs_qm_vop_dqalloc(dp, mapped_fsuid(mnt_userns),
 +                      mapped_fsgid(mnt_userns), prid,
                        XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT,
                        &udqp, &gdqp, &pdqp);
        if (error)
        /*
         * Check whether the directory allows new symlinks or not.
         */
-       if (dp->i_d.di_flags & XFS_DIFLAG_NOSYMLINKS) {
+       if (dp->i_diflags & XFS_DIFLAG_NOSYMLINKS) {
                error = -EPERM;
                goto out_trans_cancel;
        }
         * Allocate an inode for the symlink.
         */
        error = xfs_dir_ialloc(mnt_userns, &tp, dp, S_IFLNK | (mode & ~S_IFMT),
-                              1, 0, prid, &ip);
+                              1, 0, prid, false, &ip);
        if (error)
                goto out_trans_cancel;
  
        if (pathlen <= XFS_IFORK_DSIZE(ip)) {
                xfs_init_local_fork(ip, XFS_DATA_FORK, target_path, pathlen);
  
-               ip->i_d.di_size = pathlen;
+               ip->i_disk_size = pathlen;
                ip->i_df.if_format = XFS_DINODE_FMT_LOCAL;
                xfs_trans_log_inode(tp, ip, XFS_ILOG_DDATA | XFS_ILOG_CORE);
        } else {
                        goto out_trans_cancel;
  
                resblks -= fs_blocks;
-               ip->i_d.di_size = pathlen;
+               ip->i_disk_size = pathlen;
                xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
  
                cur_chunk = target_path;
                }
                ASSERT(pathlen == 0);
        }
-       i_size_write(VFS_I(ip), ip->i_d.di_size);
+       i_size_write(VFS_I(ip), ip->i_disk_size);
  
        /*
         * Create the directory entry for the symlink.
@@@ -377,7 -377,7 +377,7 @@@ xfs_inactive_symlink_rmt
        xfs_trans_t     *tp;
  
        mp = ip->i_mount;
-       ASSERT(ip->i_df.if_flags & XFS_IFEXTENTS);
+       ASSERT(!xfs_need_iread_extents(&ip->i_df));
        /*
         * We're freeing a symlink that has some
         * blocks allocated to it.  Free the
         * locked for the second transaction.  In the error paths we need it
         * held so the cancel won't rele it, see below.
         */
-       size = (int)ip->i_d.di_size;
-       ip->i_d.di_size = 0;
+       size = (int)ip->i_disk_size;
+       ip->i_disk_size = 0;
        VFS_I(ip)->i_mode = (VFS_I(ip)->i_mode & ~S_IFMT) | S_IFREG;
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
        /*
@@@ -477,7 -477,7 +477,7 @@@ xfs_inactive_symlink
                return -EIO;
  
        xfs_ilock(ip, XFS_ILOCK_EXCL);
-       pathlen = (int)ip->i_d.di_size;
+       pathlen = (int)ip->i_disk_size;
        ASSERT(pathlen);
  
        if (pathlen <= 0 || pathlen > XFS_SYMLINK_MAXLEN) {
         * Inline fork state gets removed by xfs_difree() so we have nothing to
         * do here in that case.
         */
-       if (ip->i_df.if_flags & XFS_IFINLINE) {
+       if (ip->i_df.if_format == XFS_DINODE_FMT_LOCAL) {
                xfs_iunlock(ip, XFS_ILOCK_EXCL);
                return 0;
        }
This page took 0.152386 seconds and 4 git commands to generate.