Loading fs/xfs/libxfs/xfs_sb.c +20 −4 Original line number Diff line number Diff line Loading @@ -386,10 +386,11 @@ xfs_sb_quota_from_disk(struct xfs_sb *sbp) } } void xfs_sb_from_disk( static void __xfs_sb_from_disk( struct xfs_sb *to, xfs_dsb_t *from) xfs_dsb_t *from, bool convert_xquota) { to->sb_magicnum = be32_to_cpu(from->sb_magicnum); to->sb_blocksize = be32_to_cpu(from->sb_blocksize); Loading Loading @@ -445,6 +446,17 @@ xfs_sb_from_disk( to->sb_pad = 0; to->sb_pquotino = be64_to_cpu(from->sb_pquotino); to->sb_lsn = be64_to_cpu(from->sb_lsn); /* Convert on-disk flags to in-memory flags? */ if (convert_xquota) xfs_sb_quota_from_disk(to); } void xfs_sb_from_disk( struct xfs_sb *to, xfs_dsb_t *from) { __xfs_sb_from_disk(to, from, true); } static inline void Loading Loading @@ -577,7 +589,11 @@ xfs_sb_verify( struct xfs_mount *mp = bp->b_target->bt_mount; struct xfs_sb sb; xfs_sb_from_disk(&sb, XFS_BUF_TO_SBP(bp)); /* * Use call variant which doesn't convert quota flags from disk * format, because xfs_mount_validate_sb checks the on-disk flags. */ __xfs_sb_from_disk(&sb, XFS_BUF_TO_SBP(bp), false); /* * Only check the in progress field for the primary superblock as Loading fs/xfs/xfs_bmap_util.c +48 −52 Original line number Diff line number Diff line Loading @@ -809,7 +809,7 @@ xfs_can_free_eofblocks(struct xfs_inode *ip, bool force) * have speculative prealloc/delalloc blocks to remove. */ if (VFS_I(ip)->i_size == 0 && VN_CACHED(VFS_I(ip)) == 0 && VFS_I(ip)->i_mapping->nrpages == 0 && ip->i_delayed_blks == 0) return false; Loading Loading @@ -1618,6 +1618,30 @@ xfs_swap_extents_check_format( return 0; } int xfs_swap_extent_flush( struct xfs_inode *ip) { int error; error = filemap_write_and_wait(VFS_I(ip)->i_mapping); if (error) return error; truncate_pagecache_range(VFS_I(ip), 0, -1); /* Verify O_DIRECT for ftmp */ if (VFS_I(ip)->i_mapping->nrpages) return -EINVAL; /* * Don't try to swap extents on mmap()d files because we can't lock * out races against page faults safely. */ if (mapping_mapped(VFS_I(ip)->i_mapping)) return -EBUSY; return 0; } int xfs_swap_extents( xfs_inode_t *ip, /* target inode */ Loading @@ -1633,6 +1657,7 @@ xfs_swap_extents( int aforkblks = 0; int taforkblks = 0; __uint64_t tmp; int lock_flags; tempifp = kmem_alloc(sizeof(xfs_ifork_t), KM_MAYFAIL); if (!tempifp) { Loading @@ -1641,13 +1666,13 @@ xfs_swap_extents( } /* * we have to do two separate lock calls here to keep lockdep * happy. If we try to get all the locks in one call, lock will * report false positives when we drop the ILOCK and regain them * below. * Lock up the inodes against other IO and truncate to begin with. * Then we can ensure the inodes are flushed and have no page cache * safely. Once we have done this we can take the ilocks and do the rest * of the checks. */ lock_flags = XFS_IOLOCK_EXCL; xfs_lock_two_inodes(ip, tip, XFS_IOLOCK_EXCL); xfs_lock_two_inodes(ip, tip, XFS_ILOCK_EXCL); /* Verify that both files have the same format */ if ((ip->i_d.di_mode & S_IFMT) != (tip->i_d.di_mode & S_IFMT)) { Loading @@ -1661,23 +1686,28 @@ xfs_swap_extents( goto out_unlock; } error = filemap_write_and_wait(VFS_I(tip)->i_mapping); error = xfs_swap_extent_flush(ip); if (error) goto out_unlock; error = xfs_swap_extent_flush(tip); if (error) goto out_unlock; truncate_pagecache_range(VFS_I(tip), 0, -1); /* Verify O_DIRECT for ftmp */ if (VN_CACHED(VFS_I(tip)) != 0) { error = -EINVAL; tp = xfs_trans_alloc(mp, XFS_TRANS_SWAPEXT); error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0); if (error) { xfs_trans_cancel(tp, 0); goto out_unlock; } xfs_lock_two_inodes(ip, tip, XFS_ILOCK_EXCL); lock_flags |= XFS_ILOCK_EXCL; /* Verify all data are being swapped */ if (sxp->sx_offset != 0 || sxp->sx_length != ip->i_d.di_size || sxp->sx_length != tip->i_d.di_size) { error = -EFAULT; goto out_unlock; goto out_trans_cancel; } trace_xfs_swap_extent_before(ip, 0); Loading @@ -1689,7 +1719,7 @@ xfs_swap_extents( xfs_notice(mp, "%s: inode 0x%llx format is incompatible for exchanging.", __func__, ip->i_ino); goto out_unlock; goto out_trans_cancel; } /* Loading @@ -1704,42 +1734,8 @@ xfs_swap_extents( (sbp->bs_mtime.tv_sec != VFS_I(ip)->i_mtime.tv_sec) || (sbp->bs_mtime.tv_nsec != VFS_I(ip)->i_mtime.tv_nsec)) { error = -EBUSY; goto out_unlock; } /* We need to fail if the file is memory mapped. Once we have tossed * all existing pages, the page fault will have no option * but to go to the filesystem for pages. By making the page fault call * vop_read (or write in the case of autogrow) they block on the iolock * until we have switched the extents. */ if (VN_MAPPED(VFS_I(ip))) { error = -EBUSY; goto out_unlock; } xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_iunlock(tip, XFS_ILOCK_EXCL); /* * There is a race condition here since we gave up the * ilock. However, the data fork will not change since * we have the iolock (locked for truncation too) so we * are safe. We don't really care if non-io related * fields change. */ truncate_pagecache_range(VFS_I(ip), 0, -1); tp = xfs_trans_alloc(mp, XFS_TRANS_SWAPEXT); error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0); if (error) { xfs_iunlock(ip, XFS_IOLOCK_EXCL); xfs_iunlock(tip, XFS_IOLOCK_EXCL); xfs_trans_cancel(tp, 0); goto out; goto out_trans_cancel; } xfs_lock_two_inodes(ip, tip, XFS_ILOCK_EXCL); /* * Count the number of extended attribute blocks */ Loading @@ -1757,8 +1753,8 @@ xfs_swap_extents( goto out_trans_cancel; } xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); xfs_trans_ijoin(tp, tip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); xfs_trans_ijoin(tp, ip, lock_flags); xfs_trans_ijoin(tp, tip, lock_flags); /* * Before we've swapped the forks, lets set the owners of the forks Loading Loading @@ -1887,8 +1883,8 @@ xfs_swap_extents( return error; out_unlock: xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); xfs_iunlock(tip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); xfs_iunlock(ip, lock_flags); xfs_iunlock(tip, lock_flags); goto out; out_trans_cancel: Loading fs/xfs/xfs_buf.c +14 −0 Original line number Diff line number Diff line Loading @@ -1330,6 +1330,20 @@ _xfs_buf_ioapply( SHUTDOWN_CORRUPT_INCORE); return; } } else if (bp->b_bn != XFS_BUF_DADDR_NULL) { struct xfs_mount *mp = bp->b_target->bt_mount; /* * non-crc filesystems don't attach verifiers during * log recovery, so don't warn for such filesystems. */ if (xfs_sb_version_hascrc(&mp->m_sb)) { xfs_warn(mp, "%s: no ops on block 0x%llx/0x%x", __func__, bp->b_bn, bp->b_length); xfs_hex_dump(bp->b_addr, 64); dump_stack(); } } } else if (bp->b_flags & XBF_READ_AHEAD) { rw = READA; Loading fs/xfs/xfs_dquot.c +2 −1 Original line number Diff line number Diff line Loading @@ -974,7 +974,8 @@ xfs_qm_dqflush( * Get the buffer containing the on-disk dquot */ error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, dqp->q_blkno, mp->m_quotainfo->qi_dqchunklen, 0, &bp, NULL); mp->m_quotainfo->qi_dqchunklen, 0, &bp, &xfs_dquot_buf_ops); if (error) goto out_unlock; Loading fs/xfs/xfs_file.c +5 −5 Original line number Diff line number Diff line Loading @@ -247,11 +247,11 @@ xfs_file_read_iter( XFS_STATS_INC(xs_read_calls); if (unlikely(file->f_flags & O_DIRECT)) ioflags |= IO_ISDIRECT; ioflags |= XFS_IO_ISDIRECT; if (file->f_mode & FMODE_NOCMTIME) ioflags |= IO_INVIS; ioflags |= XFS_IO_INVIS; if (unlikely(ioflags & IO_ISDIRECT)) { if (unlikely(ioflags & XFS_IO_ISDIRECT)) { xfs_buftarg_t *target = XFS_IS_REALTIME_INODE(ip) ? mp->m_rtdev_targp : mp->m_ddev_targp; Loading Loading @@ -284,7 +284,7 @@ xfs_file_read_iter( * proceeed concurrently without serialisation. */ xfs_rw_ilock(ip, XFS_IOLOCK_SHARED); if ((ioflags & IO_ISDIRECT) && inode->i_mapping->nrpages) { if ((ioflags & XFS_IO_ISDIRECT) && inode->i_mapping->nrpages) { xfs_rw_iunlock(ip, XFS_IOLOCK_SHARED); xfs_rw_ilock(ip, XFS_IOLOCK_EXCL); Loading Loading @@ -326,7 +326,7 @@ xfs_file_splice_read( XFS_STATS_INC(xs_read_calls); if (infilp->f_mode & FMODE_NOCMTIME) ioflags |= IO_INVIS; ioflags |= XFS_IO_INVIS; if (XFS_FORCED_SHUTDOWN(ip->i_mount)) return -EIO; Loading Loading
fs/xfs/libxfs/xfs_sb.c +20 −4 Original line number Diff line number Diff line Loading @@ -386,10 +386,11 @@ xfs_sb_quota_from_disk(struct xfs_sb *sbp) } } void xfs_sb_from_disk( static void __xfs_sb_from_disk( struct xfs_sb *to, xfs_dsb_t *from) xfs_dsb_t *from, bool convert_xquota) { to->sb_magicnum = be32_to_cpu(from->sb_magicnum); to->sb_blocksize = be32_to_cpu(from->sb_blocksize); Loading Loading @@ -445,6 +446,17 @@ xfs_sb_from_disk( to->sb_pad = 0; to->sb_pquotino = be64_to_cpu(from->sb_pquotino); to->sb_lsn = be64_to_cpu(from->sb_lsn); /* Convert on-disk flags to in-memory flags? */ if (convert_xquota) xfs_sb_quota_from_disk(to); } void xfs_sb_from_disk( struct xfs_sb *to, xfs_dsb_t *from) { __xfs_sb_from_disk(to, from, true); } static inline void Loading Loading @@ -577,7 +589,11 @@ xfs_sb_verify( struct xfs_mount *mp = bp->b_target->bt_mount; struct xfs_sb sb; xfs_sb_from_disk(&sb, XFS_BUF_TO_SBP(bp)); /* * Use call variant which doesn't convert quota flags from disk * format, because xfs_mount_validate_sb checks the on-disk flags. */ __xfs_sb_from_disk(&sb, XFS_BUF_TO_SBP(bp), false); /* * Only check the in progress field for the primary superblock as Loading
fs/xfs/xfs_bmap_util.c +48 −52 Original line number Diff line number Diff line Loading @@ -809,7 +809,7 @@ xfs_can_free_eofblocks(struct xfs_inode *ip, bool force) * have speculative prealloc/delalloc blocks to remove. */ if (VFS_I(ip)->i_size == 0 && VN_CACHED(VFS_I(ip)) == 0 && VFS_I(ip)->i_mapping->nrpages == 0 && ip->i_delayed_blks == 0) return false; Loading Loading @@ -1618,6 +1618,30 @@ xfs_swap_extents_check_format( return 0; } int xfs_swap_extent_flush( struct xfs_inode *ip) { int error; error = filemap_write_and_wait(VFS_I(ip)->i_mapping); if (error) return error; truncate_pagecache_range(VFS_I(ip), 0, -1); /* Verify O_DIRECT for ftmp */ if (VFS_I(ip)->i_mapping->nrpages) return -EINVAL; /* * Don't try to swap extents on mmap()d files because we can't lock * out races against page faults safely. */ if (mapping_mapped(VFS_I(ip)->i_mapping)) return -EBUSY; return 0; } int xfs_swap_extents( xfs_inode_t *ip, /* target inode */ Loading @@ -1633,6 +1657,7 @@ xfs_swap_extents( int aforkblks = 0; int taforkblks = 0; __uint64_t tmp; int lock_flags; tempifp = kmem_alloc(sizeof(xfs_ifork_t), KM_MAYFAIL); if (!tempifp) { Loading @@ -1641,13 +1666,13 @@ xfs_swap_extents( } /* * we have to do two separate lock calls here to keep lockdep * happy. If we try to get all the locks in one call, lock will * report false positives when we drop the ILOCK and regain them * below. * Lock up the inodes against other IO and truncate to begin with. * Then we can ensure the inodes are flushed and have no page cache * safely. Once we have done this we can take the ilocks and do the rest * of the checks. */ lock_flags = XFS_IOLOCK_EXCL; xfs_lock_two_inodes(ip, tip, XFS_IOLOCK_EXCL); xfs_lock_two_inodes(ip, tip, XFS_ILOCK_EXCL); /* Verify that both files have the same format */ if ((ip->i_d.di_mode & S_IFMT) != (tip->i_d.di_mode & S_IFMT)) { Loading @@ -1661,23 +1686,28 @@ xfs_swap_extents( goto out_unlock; } error = filemap_write_and_wait(VFS_I(tip)->i_mapping); error = xfs_swap_extent_flush(ip); if (error) goto out_unlock; error = xfs_swap_extent_flush(tip); if (error) goto out_unlock; truncate_pagecache_range(VFS_I(tip), 0, -1); /* Verify O_DIRECT for ftmp */ if (VN_CACHED(VFS_I(tip)) != 0) { error = -EINVAL; tp = xfs_trans_alloc(mp, XFS_TRANS_SWAPEXT); error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0); if (error) { xfs_trans_cancel(tp, 0); goto out_unlock; } xfs_lock_two_inodes(ip, tip, XFS_ILOCK_EXCL); lock_flags |= XFS_ILOCK_EXCL; /* Verify all data are being swapped */ if (sxp->sx_offset != 0 || sxp->sx_length != ip->i_d.di_size || sxp->sx_length != tip->i_d.di_size) { error = -EFAULT; goto out_unlock; goto out_trans_cancel; } trace_xfs_swap_extent_before(ip, 0); Loading @@ -1689,7 +1719,7 @@ xfs_swap_extents( xfs_notice(mp, "%s: inode 0x%llx format is incompatible for exchanging.", __func__, ip->i_ino); goto out_unlock; goto out_trans_cancel; } /* Loading @@ -1704,42 +1734,8 @@ xfs_swap_extents( (sbp->bs_mtime.tv_sec != VFS_I(ip)->i_mtime.tv_sec) || (sbp->bs_mtime.tv_nsec != VFS_I(ip)->i_mtime.tv_nsec)) { error = -EBUSY; goto out_unlock; } /* We need to fail if the file is memory mapped. Once we have tossed * all existing pages, the page fault will have no option * but to go to the filesystem for pages. By making the page fault call * vop_read (or write in the case of autogrow) they block on the iolock * until we have switched the extents. */ if (VN_MAPPED(VFS_I(ip))) { error = -EBUSY; goto out_unlock; } xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_iunlock(tip, XFS_ILOCK_EXCL); /* * There is a race condition here since we gave up the * ilock. However, the data fork will not change since * we have the iolock (locked for truncation too) so we * are safe. We don't really care if non-io related * fields change. */ truncate_pagecache_range(VFS_I(ip), 0, -1); tp = xfs_trans_alloc(mp, XFS_TRANS_SWAPEXT); error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0); if (error) { xfs_iunlock(ip, XFS_IOLOCK_EXCL); xfs_iunlock(tip, XFS_IOLOCK_EXCL); xfs_trans_cancel(tp, 0); goto out; goto out_trans_cancel; } xfs_lock_two_inodes(ip, tip, XFS_ILOCK_EXCL); /* * Count the number of extended attribute blocks */ Loading @@ -1757,8 +1753,8 @@ xfs_swap_extents( goto out_trans_cancel; } xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); xfs_trans_ijoin(tp, tip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); xfs_trans_ijoin(tp, ip, lock_flags); xfs_trans_ijoin(tp, tip, lock_flags); /* * Before we've swapped the forks, lets set the owners of the forks Loading Loading @@ -1887,8 +1883,8 @@ xfs_swap_extents( return error; out_unlock: xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); xfs_iunlock(tip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); xfs_iunlock(ip, lock_flags); xfs_iunlock(tip, lock_flags); goto out; out_trans_cancel: Loading
fs/xfs/xfs_buf.c +14 −0 Original line number Diff line number Diff line Loading @@ -1330,6 +1330,20 @@ _xfs_buf_ioapply( SHUTDOWN_CORRUPT_INCORE); return; } } else if (bp->b_bn != XFS_BUF_DADDR_NULL) { struct xfs_mount *mp = bp->b_target->bt_mount; /* * non-crc filesystems don't attach verifiers during * log recovery, so don't warn for such filesystems. */ if (xfs_sb_version_hascrc(&mp->m_sb)) { xfs_warn(mp, "%s: no ops on block 0x%llx/0x%x", __func__, bp->b_bn, bp->b_length); xfs_hex_dump(bp->b_addr, 64); dump_stack(); } } } else if (bp->b_flags & XBF_READ_AHEAD) { rw = READA; Loading
fs/xfs/xfs_dquot.c +2 −1 Original line number Diff line number Diff line Loading @@ -974,7 +974,8 @@ xfs_qm_dqflush( * Get the buffer containing the on-disk dquot */ error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, dqp->q_blkno, mp->m_quotainfo->qi_dqchunklen, 0, &bp, NULL); mp->m_quotainfo->qi_dqchunklen, 0, &bp, &xfs_dquot_buf_ops); if (error) goto out_unlock; Loading
fs/xfs/xfs_file.c +5 −5 Original line number Diff line number Diff line Loading @@ -247,11 +247,11 @@ xfs_file_read_iter( XFS_STATS_INC(xs_read_calls); if (unlikely(file->f_flags & O_DIRECT)) ioflags |= IO_ISDIRECT; ioflags |= XFS_IO_ISDIRECT; if (file->f_mode & FMODE_NOCMTIME) ioflags |= IO_INVIS; ioflags |= XFS_IO_INVIS; if (unlikely(ioflags & IO_ISDIRECT)) { if (unlikely(ioflags & XFS_IO_ISDIRECT)) { xfs_buftarg_t *target = XFS_IS_REALTIME_INODE(ip) ? mp->m_rtdev_targp : mp->m_ddev_targp; Loading Loading @@ -284,7 +284,7 @@ xfs_file_read_iter( * proceeed concurrently without serialisation. */ xfs_rw_ilock(ip, XFS_IOLOCK_SHARED); if ((ioflags & IO_ISDIRECT) && inode->i_mapping->nrpages) { if ((ioflags & XFS_IO_ISDIRECT) && inode->i_mapping->nrpages) { xfs_rw_iunlock(ip, XFS_IOLOCK_SHARED); xfs_rw_ilock(ip, XFS_IOLOCK_EXCL); Loading Loading @@ -326,7 +326,7 @@ xfs_file_splice_read( XFS_STATS_INC(xs_read_calls); if (infilp->f_mode & FMODE_NOCMTIME) ioflags |= IO_INVIS; ioflags |= XFS_IO_INVIS; if (XFS_FORCED_SHUTDOWN(ip->i_mount)) return -EIO; Loading