Loading fs/xfs/xfs_ioctl.c +98 −7 Original line number Diff line number Diff line Loading @@ -1059,24 +1059,87 @@ xfs_ioctl_setattr_xflags( return 0; } /* * If we are changing DAX flags, we have to ensure the file is clean and any * cached objects in the address space are invalidated and removed. This * requires us to lock out other IO and page faults similar to a truncate * operation. The locks need to be held until the transaction has been committed * so that the cache invalidation is atomic with respect to the DAX flag * manipulation. */ static int xfs_ioctl_setattr_dax_invalidate( struct xfs_inode *ip, struct fsxattr *fa, int *join_flags) { struct inode *inode = VFS_I(ip); int error; *join_flags = 0; /* * It is only valid to set the DAX flag on regular files and * directories on filesystems where the block size is equal to the page * size. On directories it serves as an inherit hint. */ if (fa->fsx_xflags & FS_XFLAG_DAX) { if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) return -EINVAL; if (ip->i_mount->m_sb.sb_blocksize != PAGE_SIZE) return -EINVAL; } /* If the DAX state is not changing, we have nothing to do here. */ if ((fa->fsx_xflags & FS_XFLAG_DAX) && IS_DAX(inode)) return 0; if (!(fa->fsx_xflags & FS_XFLAG_DAX) && !IS_DAX(inode)) return 0; /* lock, flush and invalidate mapping in preparation for flag change */ xfs_ilock(ip, XFS_MMAPLOCK_EXCL | XFS_IOLOCK_EXCL); error = filemap_write_and_wait(inode->i_mapping); if (error) goto out_unlock; error = invalidate_inode_pages2(inode->i_mapping); if (error) goto out_unlock; *join_flags = XFS_MMAPLOCK_EXCL | XFS_IOLOCK_EXCL; return 0; out_unlock: xfs_iunlock(ip, XFS_MMAPLOCK_EXCL | XFS_IOLOCK_EXCL); return error; } /* * Set up the transaction structure for the setattr operation, checking that we * have permission to do so. On success, return a clean transaction and the * inode locked exclusively ready for further operation specific checks. On * failure, return an error without modifying or locking the inode. * * The inode might already be IO locked on call. If this is the case, it is * indicated in @join_flags and we take full responsibility for ensuring they * are unlocked from now on. Hence if we have an error here, we still have to * unlock them. Otherwise, once they are joined to the transaction, they will * be unlocked on commit/cancel. */ static struct xfs_trans * xfs_ioctl_setattr_get_trans( struct xfs_inode *ip) struct xfs_inode *ip, int join_flags) { struct xfs_mount *mp = ip->i_mount; struct xfs_trans *tp; int error; int error = -EROFS; if (mp->m_flags & XFS_MOUNT_RDONLY) return ERR_PTR(-EROFS); goto out_unlock; error = -EIO; if (XFS_FORCED_SHUTDOWN(mp)) return ERR_PTR(-EIO); goto out_unlock; tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE); error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0); Loading @@ -1084,7 +1147,8 @@ xfs_ioctl_setattr_get_trans( goto out_cancel; xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | join_flags); join_flags = 0; /* * CAP_FOWNER overrides the following restrictions: Loading @@ -1104,6 +1168,9 @@ xfs_ioctl_setattr_get_trans( out_cancel: xfs_trans_cancel(tp); out_unlock: if (join_flags) xfs_iunlock(ip, join_flags); return ERR_PTR(error); } Loading Loading @@ -1202,6 +1269,7 @@ xfs_ioctl_setattr( struct xfs_dquot *pdqp = NULL; struct xfs_dquot *olddquot = NULL; int code; int join_flags = 0; trace_xfs_ioctl_setattr(ip); Loading @@ -1225,7 +1293,18 @@ xfs_ioctl_setattr( return code; } tp = xfs_ioctl_setattr_get_trans(ip); /* * Changing DAX config may require inode locking for mapping * invalidation. These need to be held all the way to transaction commit * or cancel time, so need to be passed through to * xfs_ioctl_setattr_get_trans() so it can apply them to the join call * appropriately. */ code = xfs_ioctl_setattr_dax_invalidate(ip, fa, &join_flags); if (code) goto error_free_dquots; tp = xfs_ioctl_setattr_get_trans(ip, join_flags); if (IS_ERR(tp)) { code = PTR_ERR(tp); goto error_free_dquots; Loading Loading @@ -1341,6 +1420,7 @@ xfs_ioc_setxflags( struct xfs_trans *tp; struct fsxattr fa; unsigned int flags; int join_flags = 0; int error; if (copy_from_user(&flags, arg, sizeof(flags))) Loading @@ -1357,7 +1437,18 @@ xfs_ioc_setxflags( if (error) return error; tp = xfs_ioctl_setattr_get_trans(ip); /* * Changing DAX config may require inode locking for mapping * invalidation. These need to be held all the way to transaction commit * or cancel time, so need to be passed through to * xfs_ioctl_setattr_get_trans() so it can apply them to the join call * appropriately. */ error = xfs_ioctl_setattr_dax_invalidate(ip, &fa, &join_flags); if (error) goto out_drop_write; tp = xfs_ioctl_setattr_get_trans(ip, join_flags); if (IS_ERR(tp)) { error = PTR_ERR(tp); goto out_drop_write; Loading fs/xfs/xfs_iops.c +4 −2 Original line number Diff line number Diff line Loading @@ -1185,8 +1185,10 @@ xfs_diflags_to_iflags( inode->i_flags |= S_SYNC; if (flags & XFS_DIFLAG_NOATIME) inode->i_flags |= S_NOATIME; if (ip->i_mount->m_flags & XFS_MOUNT_DAX || ip->i_d.di_flags2 & XFS_DIFLAG2_DAX) if (S_ISREG(inode->i_mode) && ip->i_mount->m_sb.sb_blocksize == PAGE_SIZE && (ip->i_mount->m_flags & XFS_MOUNT_DAX || ip->i_d.di_flags2 & XFS_DIFLAG2_DAX)) inode->i_flags |= S_DAX; } Loading Loading
fs/xfs/xfs_ioctl.c +98 −7 Original line number Diff line number Diff line Loading @@ -1059,24 +1059,87 @@ xfs_ioctl_setattr_xflags( return 0; } /* * If we are changing DAX flags, we have to ensure the file is clean and any * cached objects in the address space are invalidated and removed. This * requires us to lock out other IO and page faults similar to a truncate * operation. The locks need to be held until the transaction has been committed * so that the cache invalidation is atomic with respect to the DAX flag * manipulation. */ static int xfs_ioctl_setattr_dax_invalidate( struct xfs_inode *ip, struct fsxattr *fa, int *join_flags) { struct inode *inode = VFS_I(ip); int error; *join_flags = 0; /* * It is only valid to set the DAX flag on regular files and * directories on filesystems where the block size is equal to the page * size. On directories it serves as an inherit hint. */ if (fa->fsx_xflags & FS_XFLAG_DAX) { if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) return -EINVAL; if (ip->i_mount->m_sb.sb_blocksize != PAGE_SIZE) return -EINVAL; } /* If the DAX state is not changing, we have nothing to do here. */ if ((fa->fsx_xflags & FS_XFLAG_DAX) && IS_DAX(inode)) return 0; if (!(fa->fsx_xflags & FS_XFLAG_DAX) && !IS_DAX(inode)) return 0; /* lock, flush and invalidate mapping in preparation for flag change */ xfs_ilock(ip, XFS_MMAPLOCK_EXCL | XFS_IOLOCK_EXCL); error = filemap_write_and_wait(inode->i_mapping); if (error) goto out_unlock; error = invalidate_inode_pages2(inode->i_mapping); if (error) goto out_unlock; *join_flags = XFS_MMAPLOCK_EXCL | XFS_IOLOCK_EXCL; return 0; out_unlock: xfs_iunlock(ip, XFS_MMAPLOCK_EXCL | XFS_IOLOCK_EXCL); return error; } /* * Set up the transaction structure for the setattr operation, checking that we * have permission to do so. On success, return a clean transaction and the * inode locked exclusively ready for further operation specific checks. On * failure, return an error without modifying or locking the inode. * * The inode might already be IO locked on call. If this is the case, it is * indicated in @join_flags and we take full responsibility for ensuring they * are unlocked from now on. Hence if we have an error here, we still have to * unlock them. Otherwise, once they are joined to the transaction, they will * be unlocked on commit/cancel. */ static struct xfs_trans * xfs_ioctl_setattr_get_trans( struct xfs_inode *ip) struct xfs_inode *ip, int join_flags) { struct xfs_mount *mp = ip->i_mount; struct xfs_trans *tp; int error; int error = -EROFS; if (mp->m_flags & XFS_MOUNT_RDONLY) return ERR_PTR(-EROFS); goto out_unlock; error = -EIO; if (XFS_FORCED_SHUTDOWN(mp)) return ERR_PTR(-EIO); goto out_unlock; tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE); error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0); Loading @@ -1084,7 +1147,8 @@ xfs_ioctl_setattr_get_trans( goto out_cancel; xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | join_flags); join_flags = 0; /* * CAP_FOWNER overrides the following restrictions: Loading @@ -1104,6 +1168,9 @@ xfs_ioctl_setattr_get_trans( out_cancel: xfs_trans_cancel(tp); out_unlock: if (join_flags) xfs_iunlock(ip, join_flags); return ERR_PTR(error); } Loading Loading @@ -1202,6 +1269,7 @@ xfs_ioctl_setattr( struct xfs_dquot *pdqp = NULL; struct xfs_dquot *olddquot = NULL; int code; int join_flags = 0; trace_xfs_ioctl_setattr(ip); Loading @@ -1225,7 +1293,18 @@ xfs_ioctl_setattr( return code; } tp = xfs_ioctl_setattr_get_trans(ip); /* * Changing DAX config may require inode locking for mapping * invalidation. These need to be held all the way to transaction commit * or cancel time, so need to be passed through to * xfs_ioctl_setattr_get_trans() so it can apply them to the join call * appropriately. */ code = xfs_ioctl_setattr_dax_invalidate(ip, fa, &join_flags); if (code) goto error_free_dquots; tp = xfs_ioctl_setattr_get_trans(ip, join_flags); if (IS_ERR(tp)) { code = PTR_ERR(tp); goto error_free_dquots; Loading Loading @@ -1341,6 +1420,7 @@ xfs_ioc_setxflags( struct xfs_trans *tp; struct fsxattr fa; unsigned int flags; int join_flags = 0; int error; if (copy_from_user(&flags, arg, sizeof(flags))) Loading @@ -1357,7 +1437,18 @@ xfs_ioc_setxflags( if (error) return error; tp = xfs_ioctl_setattr_get_trans(ip); /* * Changing DAX config may require inode locking for mapping * invalidation. These need to be held all the way to transaction commit * or cancel time, so need to be passed through to * xfs_ioctl_setattr_get_trans() so it can apply them to the join call * appropriately. */ error = xfs_ioctl_setattr_dax_invalidate(ip, &fa, &join_flags); if (error) goto out_drop_write; tp = xfs_ioctl_setattr_get_trans(ip, join_flags); if (IS_ERR(tp)) { error = PTR_ERR(tp); goto out_drop_write; Loading
fs/xfs/xfs_iops.c +4 −2 Original line number Diff line number Diff line Loading @@ -1185,8 +1185,10 @@ xfs_diflags_to_iflags( inode->i_flags |= S_SYNC; if (flags & XFS_DIFLAG_NOATIME) inode->i_flags |= S_NOATIME; if (ip->i_mount->m_flags & XFS_MOUNT_DAX || ip->i_d.di_flags2 & XFS_DIFLAG2_DAX) if (S_ISREG(inode->i_mode) && ip->i_mount->m_sb.sb_blocksize == PAGE_SIZE && (ip->i_mount->m_flags & XFS_MOUNT_DAX || ip->i_d.di_flags2 & XFS_DIFLAG2_DAX)) inode->i_flags |= S_DAX; } Loading