COW improvements and always_cow support
Hi all,
this series adds the always_cow mode support after improving our COW write support a little bit first.
The always_cow mode stresses the COW path a lot, but with a few xfstests fixups it generall looks good, except for:
- a few tests that complain about fragmentation, which is rather inherent in this mode
- generic/208 crashing a lot (and generic/095 with 1k block similarly) because a COW fork extent has changed under writeback. As far as I can tell this is because nothing prevents another thread from moving a COW fork extent to the data fork while we are under writeback. I'm currently fully root causing this and looking into a potential fix
- xfs/017 crashes occasionally in log recovery because we can't find a refcount tree record that we try to free.
I haven't really fully understood this one yet.
PATCH 1/3 xfs: don't use delalloc extents for COW on files with extsize hints
While using delalloc for extsize hints is generally a good idea, the current code that does so only for COW doesn't help us much and creates a lot of special cases. Switch it to use real allocations like we do for direct I/O.
--- fs/xfs/xfs_iomap.c | 28 +++++++++++++++++----------- fs/xfs/xfs_reflink.c | 5 ++++- fs/xfs/xfs_reflink.h | 5 ++--- 3 files changed, 23 insertions(+), 15 deletions(-)
fs/xfs/xfs_iomap.c +17 -11
@@ -1082,22 +1082,28 @@ xfs_file_iomap_begin(* been done up front, so we don't need to do them here. */ if (xfs_is_reflink_inode (ip)) { +struct xfs_bmbt_irec orig = imap; +/* if zeroing doesn't need COW allocation, then we are done. */ if ((flags &IOMAP_ZERO ) && !needs_cow_for_zeroing (&imap, nimaps)) goto out_found; -if (flags &IOMAP_DIRECT ) { -/* may drop and re-acquire the ilock */ - error =xfs_reflink_allocate_cow (ip, &imap, &shared, - &lockmode); -if (error) - goto out_unlock; - }else { - error =xfs_reflink_reserve_cow (ip, &imap); -if (error) - goto out_unlock; - } + error =xfs_reflink_allocate_cow (ip, &imap, &shared, &lockmode, + flags); +if (error) + goto out_unlock; + +/* +* For buffered writes we need to report the address of the +* previous block (if there was any) so that the higher level +* write code can perform read-modify-write operations. For +* direct I/O code, which must be block aligned we need to +* report the newly allocated address. +*/ +if (!(flags &IOMAP_DIRECT ) && + orig.br_startblock !=HOLESTARTBLOCK ) + imap = orig; end_fsb = imap.br_startoff + imap.br_blockcount; length =XFS_FSB_TO_B (mp, end_fsb) - offset;
fs/xfs/xfs_reflink.c +4 -1
@@ -396,7 +396,8 @@ xfs_reflink_allocate_cow(struct xfs_inode *ip, struct xfs_bmbt_irec *imap, bool *shared, - uint *lockmode) + uint *lockmode, + unsigned flags) { struct xfs_mount *mp = ip->i_mount;xfs_fileoff_t offset_fsb = imap->br_startoff;
@@ -470,6 +471,8 @@ xfs_reflink_allocate_cow(if (nimaps ==0 )return -ENOSPC ; convert: +if (!(flags &IOMAP_DIRECT )) +return 0 ;return xfs_reflink_convert_cow_extent (ip, imap, offset_fsb, count_fsb); out_unreserve:
fs/xfs/xfs_reflink.h +2 -3
@@ -12,10 +12,9 @@ extern int xfs_reflink_find_shared(struct xfs_mount *mp, struct xfs_trans *tp,extern int xfs_reflink_trim_around_shared (struct xfs_inode *ip,struct xfs_bmbt_irec *irec,bool *shared); -extern int xfs_reflink_reserve_cow (struct xfs_inode *ip, -struct xfs_bmbt_irec *imap);extern int xfs_reflink_allocate_cow (struct xfs_inode *ip, -struct xfs_bmbt_irec *imap,bool *shared,uint *lockmode); +struct xfs_bmbt_irec *imap,bool *shared,uint *lockmode, +unsigned flags);extern int xfs_reflink_convert_cow (struct xfs_inode *ip,xfs_off_t offset,xfs_off_t count);
Signature · 1 line
2.19.1
PATCH 2/3 xfs: merge COW handling into xfs_file_iomap_begin_delay
In reply to Christoph HellwigBesides simplifying the code a bit this allows to actually implement the behavior of using COW preallocation for non-COW data mentioned in the current comments.
Note that this breaks the current version of xfs/420, but that is because the test is broken. A separate fix will be sent for it.
--- fs/xfs/xfs_iomap.c | 135 +++++++++++++++++++++++++++++-------------- fs/xfs/xfs_reflink.c | 66 --------------------- 2 files changed, 92 insertions(+), 109 deletions(-)
fs/xfs/xfs_iomap.c +92 -43
@@ -522,15 +522,16 @@ xfs_file_iomap_begin_delay( {struct xfs_inode *ip =XFS_I (inode);struct xfs_mount *mp = ip->i_mount; -struct xfs_ifork *ifp =XFS_IFORK_PTR (ip,XFS_DATA_FORK );xfs_fileoff_t offset_fsb =XFS_B_TO_FSBT (mp, offset);xfs_fileoff_t maxbytes_fsb =XFS_B_TO_FSB (mp, mp->m_super->s_maxbytes);xfs_fileoff_t end_fsb; -int error =0 , eof =0 ; -struct xfs_bmbt_irec got; -struct xfs_iext_cursor icur; +struct xfs_bmbt_irec imap, cmap; +struct xfs_iext_cursor icur, ccur;xfs_fsblock_t prealloc_blocks =0 ; +bool eof = false, cow_eof = false, shared; +int whichfork =XFS_DATA_FORK ; +int error =0 ;ASSERT (!XFS_IS_REALTIME_INODE (ip));ASSERT (!xfs_get_extsz_hint (ip));
@@ -548,7 +549,7 @@ xfs_file_iomap_begin_delay(XFS_STATS_INC (mp, xs_blk_mapw); -if (!(ifp->if_flags &XFS_IFEXTENTS )) { +if (!(ip->i_df.if_flags &XFS_IFEXTENTS )) { error =xfs_iread_extents (NULL , ip,XFS_DATA_FORK );if (error) goto out_unlock;
@@ -556,51 +557,97 @@ xfs_file_iomap_begin_delay( end_fsb =min (XFS_B_TO_FSB (mp, offset + count), maxbytes_fsb); - eof = !xfs_iext_lookup_extent (ip, ifp, offset_fsb, &icur, &got); +/* +* Search the data fork fork first to look up our source mapping. We +* always need the data fork map, as we have to return it to the +* iomap code so that the higher level write code can read data in to +* perform read-modify-write cycles for unaligned writes. +*/ + eof = !xfs_iext_lookup_extent (ip, &ip->i_df, offset_fsb, &icur, &imap);if (eof) - got.br_startoff = end_fsb;/* fake hole until the end */ + imap.br_startoff = end_fsb;/* fake hole until the end */ -if (got.br_startoff <= offset_fsb) { +/* We never need to allocate blocks for zeroing a hole. */ +if ((flags &IOMAP_ZERO ) && imap.br_startoff > offset_fsb) { +xfs_hole_to_iomap (ip, iomap, offset_fsb, imap.br_startoff); + goto out_unlock; + } + +/* +* Search the COW fork extent list even if we did not find a data fork +* extent. This serves two purposes: first this implements the +* speculative preallocation using cowextisze, so that we also unshare +* block adjacent to shared blocks instead of just the shared blocks +* themselves. Second the lookup in the extent list is generally faster +* than going out to the shared extent tree. +*/ +if (xfs_is_reflink_inode (ip)) { + cow_eof = !xfs_iext_lookup_extent (ip, ip->i_cowfp, offset_fsb, + &ccur, &cmap); +if (!cow_eof && cmap.br_startoff <= offset_fsb) { +if (imap.br_startoff <= offset_fsb) { +xfs_trim_extent (&imap, cmap.br_startoff, + cmap.br_blockcount); + }else { +xfs_trim_extent (&cmap, offset_fsb, + imap.br_startoff - offset_fsb); + imap = cmap; + } +trace_xfs_reflink_cow_found (ip, &imap); + goto done; + } + } + +if (imap.br_startoff <= offset_fsb) {/* * For reflink files we may need a delalloc reservation when * overwriting shared extents. This includes zeroing of * existing extents that contain data. */ -if (xfs_is_reflink_inode (ip) && - ((flags &IOMAP_WRITE ) || - got.br_state !=XFS_EXT_UNWRITTEN )) { -xfs_trim_extent (&got, offset_fsb, end_fsb - offset_fsb); - error =xfs_reflink_reserve_cow (ip, &got); -if (error) - goto out_unlock; +if (!xfs_is_reflink_inode (ip) || + ((flags &IOMAP_ZERO ) && imap.br_state !=XFS_EXT_NORM )) { +trace_xfs_iomap_found (ip, offset, count,0 , &imap); + goto done; } -trace_xfs_iomap_found (ip, offset, count,0 , &got); - goto done; - } +xfs_trim_extent (&imap, offset_fsb, end_fsb - offset_fsb); -if (flags &IOMAP_ZERO ) { -xfs_hole_to_iomap (ip, iomap, offset_fsb, got.br_startoff); - goto out_unlock; +/* Trim the mapping to the nearest shared extent boundary. */ + error =xfs_reflink_trim_around_shared (ip, &imap, &shared); +if (error) + goto out_unlock; + +/* Not shared? Just report the (potentially capped) extent. */ +if (!shared) { +trace_xfs_iomap_found (ip, offset, count,0 , &imap); + goto done; + } + +/* +* Fork all the shared blocks from our write offset until the +* end of the extent. +*/ + whichfork =XFS_COW_FORK ; + end_fsb = imap.br_startoff + imap.br_blockcount; + }else { +/* +* We cap the maximum length we map here to MAX_WRITEBACK_PAGES +* pages to keep the chunks of work done where somewhat +* symmetric with the work writeback does. This is a completely +* arbitrary number pulled out of thin air. +* +* Note that the values needs to be less than 32-bits wide until +* the lower level functions are updated. +*/ + count =min_t (loff_t, count,1024 *PAGE_SIZE ); + end_fsb =min (XFS_B_TO_FSB (mp, offset + count), maxbytes_fsb); } error =xfs_qm_dqattach_locked (ip, false);if (error) goto out_unlock; -/* -* We cap the maximum length we map here to MAX_WRITEBACK_PAGES pages -* to keep the chunks of work done where somewhat symmetric with the -* work writeback does. This is a completely arbitrary number pulled -* out of thin air as a best guess for initial testing. -* -* Note that the values needs to be less than 32-bits wide until -* the lower level functions are updated. -*/ - count =min_t (loff_t, count,1024 *PAGE_SIZE ); - end_fsb =min (XFS_B_TO_FSB (mp, offset + count), maxbytes_fsb); - -if (eof) { +if (eof && whichfork ==XFS_DATA_FORK ) { prealloc_blocks =xfs_iomap_prealloc_size (ip, offset, count, &icur);if (prealloc_blocks) {
@@ -623,9 +670,11 @@ xfs_file_iomap_begin_delay( } retry: - error =xfs_bmapi_reserve_delalloc (ip,XFS_DATA_FORK , offset_fsb, - end_fsb - offset_fsb, prealloc_blocks, &got, &icur, - eof); + error =xfs_bmapi_reserve_delalloc (ip, whichfork, offset_fsb, + end_fsb - offset_fsb, prealloc_blocks, + whichfork ==XFS_DATA_FORK ? &imap : &cmap, + whichfork ==XFS_DATA_FORK ? &icur : &ccur, + whichfork ==XFS_DATA_FORK ? eof : cow_eof);switch (error) {case 0 :break ;
@@ -647,18 +696,18 @@ xfs_file_iomap_begin_delay(* them out if the write happens to fail. */ iomap->flags |=IOMAP_F_NEW ; -trace_xfs_iomap_alloc (ip, offset, count,0 , &got); +trace_xfs_iomap_alloc (ip, offset, count,0 , &imap); done: -if (isnullstartblock (got.br_startblock)) - got.br_startblock =DELAYSTARTBLOCK ; +if (isnullstartblock (imap.br_startblock)) + imap.br_startblock =DELAYSTARTBLOCK ; -if (!got.br_startblock) { - error =xfs_alert_fsblock_zero (ip, &got); +if (!imap.br_startblock) { + error =xfs_alert_fsblock_zero (ip, &imap);if (error) goto out_unlock; } -xfs_bmbt_to_iomap (ip, iomap, &got); +xfs_bmbt_to_iomap (ip, iomap, &imap); out_unlock:xfs_iunlock (ip,XFS_ILOCK_EXCL );
fs/xfs/xfs_reflink.c +0 -66
72 lines not on this page · raw message
Signature · 1 line
2.19.1
PATCH 3/3 xfs: introduce an always_cow mode
In reply to Christoph HellwigAdd a mode where XFS never overwrites existing blocks in place. This is to aid debugging our COW code, and also put infatructure in place for things like possible future support for zoned block devices, which can't support overwrites.
This mode is enabled globally by doing a:
echo 1 > /sys/fs/xfs/debug/always_cow
Note that the parameter is global to allow running all tests in xfstests easily in this mode, which would not easily be possible with a per-fs sysfs file.
--- fs/xfs/xfs_aops.c | 2 +- fs/xfs/xfs_file.c | 7 ++++++- fs/xfs/xfs_iomap.c | 16 ++++++++++------ fs/xfs/xfs_reflink.c | 28 ++++++++++++++++++++++++---- fs/xfs/xfs_reflink.h | 13 +++++++++++++ fs/xfs/xfs_super.c | 13 +++++++++---- fs/xfs/xfs_sysctl.h | 1 + fs/xfs/xfs_sysfs.c | 24 ++++++++++++++++++++++++ 8 files changed, 88 insertions(+), 16 deletions(-)
fs/xfs/xfs_aops.c +1 -1
@@ -981,7 +981,7 @@ xfs_vm_bmap(* Since we don't pass back blockdev info, we can't return bmap * information for rt files either. */ -if (xfs_is_reflink_inode (ip) ||XFS_IS_REALTIME_INODE (ip)) +if (xfs_is_cow_inode (ip) ||XFS_IS_REALTIME_INODE (ip))return 0 ;return iomap_bmap (mapping, block, &xfs_iomap_ops); }
fs/xfs/xfs_file.c +6 -1
@@ -507,7 +507,7 @@ xfs_file_dio_aio_write(* We can't properly handle unaligned direct I/O to reflink * files yet, as we can't unshare a partial block. */ -if (xfs_is_reflink_inode (ip)) { +if (xfs_is_cow_inode (ip)) {trace_xfs_reflink_bounce_dio_write (ip, iocb->ki_pos, count);return -EREMCHG ; }
@@ -806,6 +806,11 @@ xfs_file_fallocate(return -EOPNOTSUPP ;xfs_ilock (ip, iolock); +if (xfs_is_always_cow_inode (ip) && mode !=FALLOC_FL_PUNCH_HOLE ) { + error = -EOPNOTSUPP ; + goto out_unlock; + } + error =xfs_break_layouts (inode, &iolock,BREAK_UNMAP );if (error) goto out_unlock;
fs/xfs/xfs_iomap.c +10 -6
@@ -581,7 +581,11 @@ xfs_file_iomap_begin_delay(* themselves. Second the lookup in the extent list is generally faster * than going out to the shared extent tree. */ -if (xfs_is_reflink_inode (ip)) { +if (xfs_is_cow_inode (ip)) { +if (!ip->i_cowfp) { +ASSERT (!xfs_is_reflink_inode (ip)); +xfs_ifork_init_cow (ip); + } cow_eof = !xfs_iext_lookup_extent (ip, ip->i_cowfp, offset_fsb, &ccur, &cmap);if (!cow_eof && cmap.br_startoff <= offset_fsb) {
@@ -604,7 +608,7 @@ xfs_file_iomap_begin_delay(* overwriting shared extents. This includes zeroing of * existing extents that contain data. */ -if (!xfs_is_reflink_inode (ip) || +if (!xfs_is_cow_inode (ip) || ((flags &IOMAP_ZERO ) && imap.br_state !=XFS_EXT_NORM )) {trace_xfs_iomap_found (ip, offset, count,0 , &imap); goto done;
@@ -613,7 +617,7 @@ xfs_file_iomap_begin_delay(xfs_trim_extent (&imap, offset_fsb, end_fsb - offset_fsb);/* Trim the mapping to the nearest shared extent boundary. */ - error =xfs_reflink_trim_around_shared (ip, &imap, &shared); + error =xfs_inode_need_cow (ip, &imap, &shared);if (error) goto out_unlock;
@@ -1024,7 +1028,7 @@ xfs_ilock_for_iomap(* COW writes may allocate delalloc space or convert unwritten COW * extents, so we need to make sure to take the lock exclusively here. */ -if (xfs_is_reflink_inode (ip) && is_write) { +if (xfs_is_cow_inode (ip) && is_write) {/* * FIXME: It could still overwrite on unshared extents and not * need allocation.
@@ -1058,7 +1062,7 @@ xfs_ilock_for_iomap(* check, so if we got ILOCK_SHARED for a write and but we're now a * reflink inode we have to switch to ILOCK_EXCL and relock. */ -if (mode ==XFS_ILOCK_SHARED && is_write &&xfs_is_reflink_inode (ip)) { +if (mode ==XFS_ILOCK_SHARED && is_write &&xfs_is_cow_inode (ip)) {xfs_iunlock (ip, mode); mode =XFS_ILOCK_EXCL ; goto relock;
@@ -1130,7 +1134,7 @@ xfs_file_iomap_begin(* Break shared extents if necessary. Checks for non-blocking IO have * been done up front, so we don't need to do them here. */ -if (xfs_is_reflink_inode (ip)) { +if (xfs_is_cow_inode (ip)) {struct xfs_bmbt_irec orig = imap;/* if zeroing doesn't need COW allocation, then we are done. */
fs/xfs/xfs_reflink.c +24 -4
@@ -192,7 +192,7 @@ xfs_reflink_trim_around_shared(int error =0 ;/* Holes, unwritten, and delalloc extents cannot be shared */ -if (!xfs_is_reflink_inode (ip) || !xfs_bmap_is_real_extent (irec)) { +if (!xfs_is_cow_inode (ip) || !xfs_bmap_is_real_extent (irec)) { *shared = false;return 0 ; }
@@ -234,6 +234,23 @@ xfs_reflink_trim_around_shared( } } +bool +xfs_inode_need_cow ( +struct xfs_inode *ip, +struct xfs_bmbt_irec *imap, +bool *shared) +{ +/* We can't update any real extents in always COW mode. */ +if (xfs_is_always_cow_inode (ip) && + !isnullstartblock (imap->br_startblock)) { + *shared = true; +return 0 ; + } + +/* Trim the mapping to the nearest shared extent boundary. */ +return xfs_reflink_trim_around_shared (ip, imap, shared); +} +/* Convert part of an unwritten CoW extent to a real one. */ STATIC int xfs_reflink_convert_cow_extent(
@@ -308,7 +325,7 @@ xfs_find_trim_cow_extent(if (got.br_startoff > offset_fsb) {xfs_trim_extent (imap, imap->br_startoff, got.br_startoff - imap->br_startoff); -return xfs_reflink_trim_around_shared (ip, imap, shared); +return xfs_inode_need_cow (ip, imap, shared); } *shared = true;
@@ -343,7 +360,10 @@ xfs_reflink_allocate_cow(xfs_extlen_t resblks =0 ;ASSERT (xfs_isilocked (ip,XFS_ILOCK_EXCL )); -ASSERT (xfs_is_reflink_inode (ip)); +if (!ip->i_cowfp) { +ASSERT (!xfs_is_reflink_inode (ip)); +xfs_ifork_init_cow (ip); + } error =xfs_find_trim_cow_extent (ip, imap, shared, &found);if (error || !*shared)
@@ -522,7 +542,7 @@ xfs_reflink_cancel_cow_range(int error;trace_xfs_reflink_cancel_cow_range (ip, offset, count); -ASSERT (xfs_is_reflink_inode (ip)); +ASSERT (ip->i_cowfp); offset_fsb =XFS_B_TO_FSBT (ip->i_mount, offset);if (count ==NULLFILEOFF )
fs/xfs/xfs_reflink.h +13 -0
@@ -6,11 +6,24 @@#ifndef __XFS_REFLINK_H#define __XFS_REFLINK_H 1 +static inline bool xfs_is_always_cow_inode (struct xfs_inode *ip) +{ +return xfs_globals.always_cow && +xfs_sb_version_hasreflink (&ip->i_mount->m_sb); +} + +static inline bool xfs_is_cow_inode (struct xfs_inode *ip) +{ +return xfs_is_reflink_inode (ip) ||xfs_is_always_cow_inode (ip); +} +extern int xfs_reflink_find_shared (struct xfs_mount *mp,struct xfs_trans *tp,xfs_agnumber_t agno,xfs_agblock_t agbno,xfs_extlen_t aglen,xfs_agblock_t *fbno,xfs_extlen_t *flen,bool find_maximal);extern int xfs_reflink_trim_around_shared (struct xfs_inode *ip,struct xfs_bmbt_irec *irec,bool *shared); +bool xfs_inode_need_cow (struct xfs_inode *ip,struct xfs_bmbt_irec *imap, +bool *shared); extern int xfs_reflink_allocate_cow(struct xfs_inode *ip, struct xfs_bmbt_irec *imap, bool *shared, uint *lockmode,
fs/xfs/xfs_super.c +9 -4
@@ -1728,11 +1728,16 @@ xfs_fs_fill_super( } } -if (xfs_sb_version_hasreflink (&mp->m_sb) && mp->m_sb.sb_rblocks) { -xfs_alert (mp, +if (xfs_sb_version_hasreflink (&mp->m_sb)) { +if (mp->m_sb.sb_rblocks) { +xfs_alert (mp,"reflink not compatible with realtime device!" ); - error = -EINVAL ; - goto out_filestream_unmount; + error = -EINVAL ; + goto out_filestream_unmount; + } + +if (xfs_globals.always_cow) +xfs_info (mp,"using DEBUG-only always_cow mode." ); }if (xfs_sb_version_hasrmapbt (&mp->m_sb) && mp->m_sb.sb_rblocks) {
fs/xfs/xfs_sysctl.h +1 -0
@@ -85,6 +85,7 @@ struct xfs_globals {int log_recovery_delay;/* log recovery delay (secs) */ int mount_delay;/* mount setup delay (secs) */ bool bug_on_assert;/* BUG() the kernel on assert failure */ +bool always_cow;/* use COW fork for all overwrites */ };extern struct xfs_globals xfs_globals;
fs/xfs/xfs_sysfs.c +24 -0
@@ -183,10 +183,34 @@ mount_delay_show( }XFS_SYSFS_ATTR_RW (mount_delay); +static ssize_t +always_cow_store ( +struct kobject *kobject, +const char *buf, +size_t count) +{ +ssize_t ret; + + ret =kstrtobool (buf, &xfs_globals.always_cow); +if (ret <0 ) +return ret; +return count; +} + +static ssize_t +always_cow_show ( +struct kobject *kobject, +char *buf) +{ +return snprintf (buf,PAGE_SIZE ,"%d\n" , xfs_globals.always_cow); +} +XFS_SYSFS_ATTR_RW (always_cow); +static struct attribute *xfs_dbg_attrs[] = {ATTR_LIST (bug_on_assert),ATTR_LIST (log_recovery_delay),ATTR_LIST (mount_delay), +ATTR_LIST (always_cow),NULL , };
Signature · 1 line
2.19.1
Re: [PATCH 3/3] xfs: introduce an always_cow mode
Quoted 52 lines · Christoph Hellwig
Add a mode where XFS never overwrites existing blocks in place. This is to aid debugging our COW code, and also put infatructure in place for things like possible future support for zoned block devices, which can't support overwrites.
This mode is enabled globally by doing a:
echo 1 >
/sys/fs/xfs/debug/always_cowNote that the parameter is global to allow running all tests in xfstests easily in this mode, which would not easily be possible with a per-fs sysfs file.
Signed-off-by Christoph Hellwig <[email protected]>--- fs/xfs/xfs_aops.c | 2 +- fs/xfs/xfs_file.c | 7 ++++++- fs/xfs/xfs_iomap.c | 16 ++++++++++------ fs/xfs/xfs_reflink.c | 28 ++++++++++++++++++++++++---- fs/xfs/xfs_reflink.h | 13 +++++++++++++ fs/xfs/xfs_super.c | 13 +++++++++---- fs/xfs/xfs_sysctl.h | 1 + fs/xfs/xfs_sysfs.c | 24 ++++++++++++++++++++++++ 8 files changed, 88 insertions(+), 16 deletions(-)fs/xfs/xfs_aops.c +1
-1@@ -981,7 +981,7 @@ xfs_vm_bmap(* Since we don't pass back blockdev info, we can't return bmap * information for rt files either. */ -if (xfs_is_reflink_inode (ip) ||XFS_IS_REALTIME_INODE (ip)) +if (xfs_is_cow_inode (ip) ||XFS_IS_REALTIME_INODE (ip))return 0 ;return iomap_bmap (mapping, block, &xfs_iomap_ops); }fs/xfs/xfs_file.c +1
-1@@ -507,7 +507,7 @@ xfs_file_dio_aio_write(* We can't properly handle unaligned direct I/O to reflink * files yet, as we can't unshare a partial block. */ -if (xfs_is_reflink_inode (ip)) { +if (xfs_is_cow_inode (ip)) {trace_xfs_reflink_bounce_dio_write (ip, iocb->ki_pos, count);return -EREMCHG ; }
fs/xfs/xfs_file.c xfs_file_fallocate( · line 811
Quoted 6 lines
fs/xfs/xfs_file.c +3
-0@@ -806,6 +806,11 @@ xfs_file_fallocate(return -EOPNOTSUPP ;xfs_ilock (ip, iolock); +if (xfs_is_always_cow_inode (ip) && mode !=FALLOC_FL_PUNCH_HOLE ) { + error = -EOPNOTSUPP ; + goto out_unlock;
It's the weekend, so I'm only doing a quick scan of patches:
Why can't we support collapse range, insert range, zero range, or unshare in always_cow mode?
--D
Quoted 242 lines
fs/xfs/xfs_file.c +2
-0+ } + error =xfs_break_layouts (inode, &iolock,BREAK_UNMAP );if (error) goto out_unlock;fs/xfs/xfs_iomap.c +10
-6@@ -581,7 +581,11 @@ xfs_file_iomap_begin_delay(* themselves. Second the lookup in the extent list is generally faster * than going out to the shared extent tree. */ -if (xfs_is_reflink_inode (ip)) { +if (xfs_is_cow_inode (ip)) { +if (!ip->i_cowfp) { +ASSERT (!xfs_is_reflink_inode (ip)); +xfs_ifork_init_cow (ip); + } cow_eof = !xfs_iext_lookup_extent (ip, ip->i_cowfp, offset_fsb, &ccur, &cmap);if (!cow_eof && cmap.br_startoff <= offset_fsb) {@@ -604,7 +608,7 @@ xfs_file_iomap_begin_delay(* overwriting shared extents. This includes zeroing of * existing extents that contain data. */ -if (!xfs_is_reflink_inode (ip) || +if (!xfs_is_cow_inode (ip) || ((flags &IOMAP_ZERO ) && imap.br_state !=XFS_EXT_NORM )) {trace_xfs_iomap_found (ip, offset, count,0 , &imap); goto done;@@ -613,7 +617,7 @@ xfs_file_iomap_begin_delay(xfs_trim_extent (&imap, offset_fsb, end_fsb - offset_fsb);/* Trim the mapping to the nearest shared extent boundary. */ - error =xfs_reflink_trim_around_shared (ip, &imap, &shared); + error =xfs_inode_need_cow (ip, &imap, &shared);if (error) goto out_unlock;@@ -1024,7 +1028,7 @@ xfs_ilock_for_iomap(* COW writes may allocate delalloc space or convert unwritten COW * extents, so we need to make sure to take the lock exclusively here. */ -if (xfs_is_reflink_inode (ip) && is_write) { +if (xfs_is_cow_inode (ip) && is_write) {/* * FIXME: It could still overwrite on unshared extents and not * need allocation. @@ -1058,7 +1062,7 @@ xfs_ilock_for_iomap(* check, so if we got ILOCK_SHARED for a write and but we're now a * reflink inode we have to switch to ILOCK_EXCL and relock. */ -if (mode ==XFS_ILOCK_SHARED && is_write &&xfs_is_reflink_inode (ip)) { +if (mode ==XFS_ILOCK_SHARED && is_write &&xfs_is_cow_inode (ip)) {xfs_iunlock (ip, mode); mode =XFS_ILOCK_EXCL ; goto relock;@@ -1130,7 +1134,7 @@ xfs_file_iomap_begin(* Break shared extents if necessary. Checks for non-blocking IO have * been done up front, so we don't need to do them here. */ -if (xfs_is_reflink_inode (ip)) { +if (xfs_is_cow_inode (ip)) {struct xfs_bmbt_irec orig = imap;/* if zeroing doesn't need COW allocation, then we are done. */ fs/xfs/xfs_reflink.c +24
-4@@ -192,7 +192,7 @@ xfs_reflink_trim_around_shared(int error =0 ;/* Holes, unwritten, and delalloc extents cannot be shared */ -if (!xfs_is_reflink_inode (ip) || !xfs_bmap_is_real_extent (irec)) { +if (!xfs_is_cow_inode (ip) || !xfs_bmap_is_real_extent (irec)) { *shared = false;return 0 ; }@@ -234,6 +234,23 @@ xfs_reflink_trim_around_shared( } } +bool +xfs_inode_need_cow ( +struct xfs_inode *ip, +struct xfs_bmbt_irec *imap, +bool *shared) +{ +/* We can't update any real extents in always COW mode. */ +if (xfs_is_always_cow_inode (ip) && + !isnullstartblock (imap->br_startblock)) { + *shared = true; +return 0 ; + } + +/* Trim the mapping to the nearest shared extent boundary. */ +return xfs_reflink_trim_around_shared (ip, imap, shared); +} +/* Convert part of an unwritten CoW extent to a real one. */ STATIC int xfs_reflink_convert_cow_extent(@@ -308,7 +325,7 @@ xfs_find_trim_cow_extent(if (got.br_startoff > offset_fsb) {xfs_trim_extent (imap, imap->br_startoff, got.br_startoff - imap->br_startoff); -return xfs_reflink_trim_around_shared (ip, imap, shared); +return xfs_inode_need_cow (ip, imap, shared); } *shared = true;@@ -343,7 +360,10 @@ xfs_reflink_allocate_cow(xfs_extlen_t resblks =0 ;ASSERT (xfs_isilocked (ip,XFS_ILOCK_EXCL )); -ASSERT (xfs_is_reflink_inode (ip)); +if (!ip->i_cowfp) { +ASSERT (!xfs_is_reflink_inode (ip)); +xfs_ifork_init_cow (ip); + } error =xfs_find_trim_cow_extent (ip, imap, shared, &found);if (error || !*shared)@@ -522,7 +542,7 @@ xfs_reflink_cancel_cow_range(int error;trace_xfs_reflink_cancel_cow_range (ip, offset, count); -ASSERT (xfs_is_reflink_inode (ip)); +ASSERT (ip->i_cowfp); offset_fsb =XFS_B_TO_FSBT (ip->i_mount, offset);if (count ==NULLFILEOFF )fs/xfs/xfs_reflink.h +13
-0@@ -6,11 +6,24 @@#ifndef __XFS_REFLINK_H#define __XFS_REFLINK_H 1 +static inline bool xfs_is_always_cow_inode (struct xfs_inode *ip) +{ +return xfs_globals.always_cow && +xfs_sb_version_hasreflink (&ip->i_mount->m_sb); +} + +static inline bool xfs_is_cow_inode (struct xfs_inode *ip) +{ +return xfs_is_reflink_inode (ip) ||xfs_is_always_cow_inode (ip); +} +extern int xfs_reflink_find_shared (struct xfs_mount *mp,struct xfs_trans *tp,xfs_agnumber_t agno,xfs_agblock_t agbno,xfs_extlen_t aglen,xfs_agblock_t *fbno,xfs_extlen_t *flen,bool find_maximal);extern int xfs_reflink_trim_around_shared (struct xfs_inode *ip,struct xfs_bmbt_irec *irec,bool *shared); +bool xfs_inode_need_cow (struct xfs_inode *ip,struct xfs_bmbt_irec *imap, +bool *shared); extern int xfs_reflink_allocate_cow(struct xfs_inode *ip, struct xfs_bmbt_irec *imap, bool *shared, uint *lockmode,fs/xfs/xfs_super.c +9
-4@@ -1728,11 +1728,16 @@ xfs_fs_fill_super( } } -if (xfs_sb_version_hasreflink (&mp->m_sb) && mp->m_sb.sb_rblocks) { -xfs_alert (mp, +if (xfs_sb_version_hasreflink (&mp->m_sb)) { +if (mp->m_sb.sb_rblocks) { +xfs_alert (mp,"reflink not compatible with realtime device!" ); - error = -EINVAL ; - goto out_filestream_unmount; + error = -EINVAL ; + goto out_filestream_unmount; + } + +if (xfs_globals.always_cow) +xfs_info (mp,"using DEBUG-only always_cow mode." ); }if (xfs_sb_version_hasrmapbt (&mp->m_sb) && mp->m_sb.sb_rblocks) {fs/xfs/xfs_sysctl.h +1
-0@@ -85,6 +85,7 @@ struct xfs_globals {int log_recovery_delay;/* log recovery delay (secs) */ int mount_delay;/* mount setup delay (secs) */ bool bug_on_assert;/* BUG() the kernel on assert failure */ +bool always_cow;/* use COW fork for all overwrites */ };extern struct xfs_globals xfs_globals;fs/xfs/xfs_sysfs.c +24
-0@@ -183,10 +183,34 @@ mount_delay_show( }XFS_SYSFS_ATTR_RW (mount_delay); +static ssize_t +always_cow_store ( +struct kobject *kobject, +const char *buf, +size_t count) +{ +ssize_t ret; + + ret =kstrtobool (buf, &xfs_globals.always_cow); +if (ret <0 ) +return ret; +return count; +} + +static ssize_t +always_cow_show ( +struct kobject *kobject, +char *buf) +{ +return snprintf (buf,PAGE_SIZE ,"%d\n" , xfs_globals.always_cow); +} +XFS_SYSFS_ATTR_RW (always_cow); +static struct attribute *xfs_dbg_attrs[] = {ATTR_LIST (bug_on_assert),ATTR_LIST (log_recovery_delay),ATTR_LIST (mount_delay), +ATTR_LIST (always_cow),NULL , };Signature · 1 line
2.19.1
Re: [PATCH 3/3] xfs: introduce an always_cow mode
Quoted 9 lines · Darrick J. Wong
fs/xfs/xfs_file.c xfs_file_fallocate( · line 811
Quoted 4 lines
fs/xfs/xfs_file.c +3
-0xfs_ilock (ip, iolock); +if (xfs_is_always_cow_inode (ip) && mode !=FALLOC_FL_PUNCH_HOLE ) { + error = -EOPNOTSUPP ; + goto out_unlock;It's the weekend, so I'm only doing a quick scan of patches:
Why can't we support collapse range, insert range, zero range, or unshare in
always_cowmode?
Yes, this a little agressive. I think we should be fine just skipping modes zero and keep size (ugg, the fallocate flags scheme is horrible..). I'll do that for the next version.
Re: [PATCH 3/3] xfs: introduce an always_cow mode
Quoted 3 lines · Christoph Hellwig
Yes, this a little agressive. I think we should be fine just skipping modes zero and keep size (ugg, the fallocate flags scheme is horrible..). I'll do that for the next version.
Enabling all these seems to work, I see two additional test failures, one of them is an missing explicit preallocation support check, similar to the various I just fixed up in my xfstests series, but otherwise it seems to do fine:
---
Quoted 1 line
From
58fc931499fc90ea7a08a73b798d495af2a9ff81Mon Sep 17 00:00:00 2001
From: Christoph Hellwig <[email protected]>
Date: Mon, 22 Oct 2018 12:39:42 +0100
Subject: xfs: introduce an always_cow mode
Add a mode where XFS never overwrites existing blocks in place. This is to aid debugging our COW code, and also put infatructure in place for things like possible future support for zoned block devices, which can't support overwrites.
This mode is enabled globally by doing a:
echo 1 > /sys/fs/xfs/debug/always_cow
Note that the parameter is global to allow running all tests in xfstests easily in this mode, which would not easily be possible with a per-fs sysfs file.
--- fs/xfs/xfs_aops.c | 2 +- fs/xfs/xfs_file.c | 11 ++++++++++- fs/xfs/xfs_iomap.c | 16 ++++++++++------ fs/xfs/xfs_reflink.c | 28 ++++++++++++++++++++++++---- fs/xfs/xfs_reflink.h | 13 +++++++++++++ fs/xfs/xfs_super.c | 13 +++++++++---- fs/xfs/xfs_sysctl.h | 1 + fs/xfs/xfs_sysfs.c | 24 ++++++++++++++++++++++++ 8 files changed, 92 insertions(+), 16 deletions(-)
fs/xfs/xfs_aops.c +1 -1
@@ -981,7 +981,7 @@ xfs_vm_bmap(* Since we don't pass back blockdev info, we can't return bmap * information for rt files either. */ -if (xfs_is_reflink_inode (ip) ||XFS_IS_REALTIME_INODE (ip)) +if (xfs_is_cow_inode (ip) ||XFS_IS_REALTIME_INODE (ip))return 0 ;return iomap_bmap (mapping, block, &xfs_iomap_ops); }
fs/xfs/xfs_file.c +10 -1
@@ -507,7 +507,7 @@ xfs_file_dio_aio_write(* We can't properly handle unaligned direct I/O to reflink * files yet, as we can't unshare a partial block. */ -if (xfs_is_reflink_inode (ip)) { +if (xfs_is_cow_inode (ip)) {trace_xfs_reflink_bounce_dio_write (ip, iocb->ki_pos, count);return -EREMCHG ; }
@@ -806,6 +806,15 @@ xfs_file_fallocate(return -EOPNOTSUPP ;xfs_ilock (ip, iolock); +/* +* If always_cow mode we can't use preallocation and thus should not +* allow creating them. +*/ +if (xfs_is_always_cow_inode (ip) && (mode & ~FALLOC_FL_KEEP_SIZE ) ==0 ) { + error = -EOPNOTSUPP ; + goto out_unlock; + } + error =xfs_break_layouts (inode, &iolock,BREAK_UNMAP );if (error) goto out_unlock;
fs/xfs/xfs_iomap.c +10 -6
@@ -581,7 +581,11 @@ xfs_file_iomap_begin_delay(* themselves. Second the lookup in the extent list is generally faster * than going out to the shared extent tree. */ -if (xfs_is_reflink_inode (ip)) { +if (xfs_is_cow_inode (ip)) { +if (!ip->i_cowfp) { +ASSERT (!xfs_is_reflink_inode (ip)); +xfs_ifork_init_cow (ip); + } cow_eof = !xfs_iext_lookup_extent (ip, ip->i_cowfp, offset_fsb, &ccur, &cmap);if (!cow_eof && cmap.br_startoff <= offset_fsb) {
@@ -604,7 +608,7 @@ xfs_file_iomap_begin_delay(* overwriting shared extents. This includes zeroing of * existing extents that contain data. */ -if (!xfs_is_reflink_inode (ip) || +if (!xfs_is_cow_inode (ip) || ((flags &IOMAP_ZERO ) && imap.br_state !=XFS_EXT_NORM )) {trace_xfs_iomap_found (ip, offset, count,0 , &imap); goto done;
@@ -613,7 +617,7 @@ xfs_file_iomap_begin_delay(xfs_trim_extent (&imap, offset_fsb, end_fsb - offset_fsb);/* Trim the mapping to the nearest shared extent boundary. */ - error =xfs_reflink_trim_around_shared (ip, &imap, &shared); + error =xfs_inode_need_cow (ip, &imap, &shared);if (error) goto out_unlock;
@@ -1024,7 +1028,7 @@ xfs_ilock_for_iomap(* COW writes may allocate delalloc space or convert unwritten COW * extents, so we need to make sure to take the lock exclusively here. */ -if (xfs_is_reflink_inode (ip) && is_write) { +if (xfs_is_cow_inode (ip) && is_write) {/* * FIXME: It could still overwrite on unshared extents and not * need allocation.
@@ -1058,7 +1062,7 @@ xfs_ilock_for_iomap(* check, so if we got ILOCK_SHARED for a write and but we're now a * reflink inode we have to switch to ILOCK_EXCL and relock. */ -if (mode ==XFS_ILOCK_SHARED && is_write &&xfs_is_reflink_inode (ip)) { +if (mode ==XFS_ILOCK_SHARED && is_write &&xfs_is_cow_inode (ip)) {xfs_iunlock (ip, mode); mode =XFS_ILOCK_EXCL ; goto relock;
@@ -1130,7 +1134,7 @@ xfs_file_iomap_begin(* Break shared extents if necessary. Checks for non-blocking IO have * been done up front, so we don't need to do them here. */ -if (xfs_is_reflink_inode (ip)) { +if (xfs_is_cow_inode (ip)) {struct xfs_bmbt_irec orig = imap;/* if zeroing doesn't need COW allocation, then we are done. */
fs/xfs/xfs_reflink.c +24 -4
@@ -192,7 +192,7 @@ xfs_reflink_trim_around_shared(int error =0 ;/* Holes, unwritten, and delalloc extents cannot be shared */ -if (!xfs_is_reflink_inode (ip) || !xfs_bmap_is_real_extent (irec)) { +if (!xfs_is_cow_inode (ip) || !xfs_bmap_is_real_extent (irec)) { *shared = false;return 0 ; }
@@ -234,6 +234,23 @@ xfs_reflink_trim_around_shared( } } +bool +xfs_inode_need_cow ( +struct xfs_inode *ip, +struct xfs_bmbt_irec *imap, +bool *shared) +{ +/* We can't update any real extents in always COW mode. */ +if (xfs_is_always_cow_inode (ip) && + !isnullstartblock (imap->br_startblock)) { + *shared = true; +return 0 ; + } + +/* Trim the mapping to the nearest shared extent boundary. */ +return xfs_reflink_trim_around_shared (ip, imap, shared); +} +/* Convert part of an unwritten CoW extent to a real one. */ STATIC int xfs_reflink_convert_cow_extent(
@@ -308,7 +325,7 @@ xfs_find_trim_cow_extent(if (got.br_startoff > offset_fsb) {xfs_trim_extent (imap, imap->br_startoff, got.br_startoff - imap->br_startoff); -return xfs_reflink_trim_around_shared (ip, imap, shared); +return xfs_inode_need_cow (ip, imap, shared); } *shared = true;
@@ -343,7 +360,10 @@ xfs_reflink_allocate_cow(xfs_extlen_t resblks =0 ;ASSERT (xfs_isilocked (ip,XFS_ILOCK_EXCL )); -ASSERT (xfs_is_reflink_inode (ip)); +if (!ip->i_cowfp) { +ASSERT (!xfs_is_reflink_inode (ip)); +xfs_ifork_init_cow (ip); + } error =xfs_find_trim_cow_extent (ip, imap, shared, &found);if (error || !*shared)
@@ -522,7 +542,7 @@ xfs_reflink_cancel_cow_range(int error;trace_xfs_reflink_cancel_cow_range (ip, offset, count); -ASSERT (xfs_is_reflink_inode (ip)); +ASSERT (ip->i_cowfp); offset_fsb =XFS_B_TO_FSBT (ip->i_mount, offset);if (count ==NULLFILEOFF )
fs/xfs/xfs_reflink.h +13 -0
@@ -6,11 +6,24 @@#ifndef __XFS_REFLINK_H#define __XFS_REFLINK_H 1 +static inline bool xfs_is_always_cow_inode (struct xfs_inode *ip) +{ +return xfs_globals.always_cow && +xfs_sb_version_hasreflink (&ip->i_mount->m_sb); +} + +static inline bool xfs_is_cow_inode (struct xfs_inode *ip) +{ +return xfs_is_reflink_inode (ip) ||xfs_is_always_cow_inode (ip); +} +extern int xfs_reflink_find_shared (struct xfs_mount *mp,struct xfs_trans *tp,xfs_agnumber_t agno,xfs_agblock_t agbno,xfs_extlen_t aglen,xfs_agblock_t *fbno,xfs_extlen_t *flen,bool find_maximal);extern int xfs_reflink_trim_around_shared (struct xfs_inode *ip,struct xfs_bmbt_irec *irec,bool *shared); +bool xfs_inode_need_cow (struct xfs_inode *ip,struct xfs_bmbt_irec *imap, +bool *shared); extern int xfs_reflink_allocate_cow(struct xfs_inode *ip, struct xfs_bmbt_irec *imap, bool *shared, uint *lockmode,
fs/xfs/xfs_super.c +9 -4
@@ -1728,11 +1728,16 @@ xfs_fs_fill_super( } } -if (xfs_sb_version_hasreflink (&mp->m_sb) && mp->m_sb.sb_rblocks) { -xfs_alert (mp, +if (xfs_sb_version_hasreflink (&mp->m_sb)) { +if (mp->m_sb.sb_rblocks) { +xfs_alert (mp,"reflink not compatible with realtime device!" ); - error = -EINVAL ; - goto out_filestream_unmount; + error = -EINVAL ; + goto out_filestream_unmount; + } + +if (xfs_globals.always_cow) +xfs_info (mp,"using DEBUG-only always_cow mode." ); }if (xfs_sb_version_hasrmapbt (&mp->m_sb) && mp->m_sb.sb_rblocks) {
fs/xfs/xfs_sysctl.h +1 -0
@@ -85,6 +85,7 @@ struct xfs_globals {int log_recovery_delay;/* log recovery delay (secs) */ int mount_delay;/* mount setup delay (secs) */ bool bug_on_assert;/* BUG() the kernel on assert failure */ +bool always_cow;/* use COW fork for all overwrites */ };extern struct xfs_globals xfs_globals;
fs/xfs/xfs_sysfs.c +24 -0
@@ -183,10 +183,34 @@ mount_delay_show( }XFS_SYSFS_ATTR_RW (mount_delay); +static ssize_t +always_cow_store ( +struct kobject *kobject, +const char *buf, +size_t count) +{ +ssize_t ret; + + ret =kstrtobool (buf, &xfs_globals.always_cow); +if (ret <0 ) +return ret; +return count; +} + +static ssize_t +always_cow_show ( +struct kobject *kobject, +char *buf) +{ +return snprintf (buf,PAGE_SIZE ,"%d\n" , xfs_globals.always_cow); +} +XFS_SYSFS_ATTR_RW (always_cow); +static struct attribute *xfs_dbg_attrs[] = {ATTR_LIST (bug_on_assert),ATTR_LIST (log_recovery_delay),ATTR_LIST (mount_delay), +ATTR_LIST (always_cow),NULL , };
Signature · 1 line
2.19.1
[PATCH 4/3] xfs: make COW fork unwritten extent conversions more robust
In reply to Christoph HellwigIf we have racing buffered and direct I/O COW fork extents under writeback can have been moved to the data fork by the time we call xfs_reflink_convert_cow from xfs_submit_ioend. This would be mostly harmless as the block numbers don't change by this move, except for the fact that xfs_bmapi_write will crash or trigger asserts when not finding existing extents, even despite trying to paper over this with the XFS_BMAPI_CONVERT_ONLY flag.
Instead of special casing non-transaction conversions in the already way too complicated xfs_bmapi_write just add a new helper for the much simpler non-transactional COW fork case, which simplify ignores not found extents.
--- fs/xfs/libxfs/xfs_bmap.c | 12 ++------ fs/xfs/libxfs/xfs_bmap.h | 8 +++--- fs/xfs/xfs_reflink.c | 61 +++++++++++++++++++++++++--------------- 3 files changed, 45 insertions(+), 36 deletions(-)
fs/xfs/libxfs/xfs_bmap.c +3 -9
@@ -2026,7 +2026,7 @@ xfs_bmap_add_extent_delay_real(/* * Convert an unwritten allocation to a real allocation or vice versa. */ -STATIC int /* error */ +int /* error */ xfs_bmap_add_extent_unwritten_real( struct xfs_trans *tp, xfs_inode_t *ip, /* incore inode pointer */
@@ -4244,9 +4244,7 @@ xfs_bmapi_write(ASSERT (*nmap >=1 );ASSERT (*nmap <=XFS_BMAP_MAX_NMAP ); -ASSERT (tp !=NULL || - (flags & (XFS_BMAPI_CONVERT |XFS_BMAPI_COWFORK )) == - (XFS_BMAPI_CONVERT |XFS_BMAPI_COWFORK )); +ASSERT (tp !=NULL );ASSERT (len >0 );ASSERT (XFS_IFORK_FORMAT (ip, whichfork) !=XFS_DINODE_FMT_LOCAL );ASSERT (xfs_isilocked (ip,XFS_ILOCK_EXCL ));
@@ -4317,9 +4315,6 @@ xfs_bmapi_write(* holes. There should always be something for us * to work on. */ -ASSERT (!((flags &XFS_BMAPI_CONVERT ) && - (flags &XFS_BMAPI_COWFORK ))); -if (flags &XFS_BMAPI_DELALLOC ) {/* * For the COW fork we can reasonably get a
@@ -4348,8 +4343,7 @@ xfs_bmapi_write(* First, deal with the hole before the allocated space * that we found, if any. */ -if ((need_alloc || wasdelay) && - !(flags &XFS_BMAPI_CONVERT_ONLY )) { +if (need_alloc || wasdelay) { bma.eof = eof; bma.conv = !!(flags &XFS_BMAPI_CONVERT ); bma.wasdel = wasdelay;
fs/xfs/libxfs/xfs_bmap.h +4 -4
@@ -98,9 +98,6 @@ struct xfs_extent_free_item/* Only convert delalloc space, don't allocate entirely new extents */ #define XFS_BMAPI_DELALLOC 0x400 -/* Only convert unwritten extents, don't allocate new blocks */ -#define XFS_BMAPI_CONVERT_ONLY 0x800 -/* Skip online discard of freed extents */ #define XFS_BMAPI_NODISCARD 0x1000
@@ -118,7 +115,6 @@ struct xfs_extent_free_item { XFS_BMAPI_REMAP, "REMAP" }, \ { XFS_BMAPI_COWFORK, "COWFORK" }, \ { XFS_BMAPI_DELALLOC, "DELALLOC" }, \ - { XFS_BMAPI_CONVERT_ONLY, "CONVERT_ONLY" }, \ { XFS_BMAPI_NODISCARD, "NODISCARD" }, \ { XFS_BMAPI_NORMAP, "NORMAP" }
@@ -228,6 +224,10 @@ int xfs_bmapi_reserve_delalloc(struct xfs_inode *ip, int whichfork, xfs_fileoff_t off, xfs_filblks_t len, xfs_filblks_t prealloc, struct xfs_bmbt_irec *got, struct xfs_iext_cursor *cur, int eof); +int xfs_bmap_add_extent_unwritten_real (struct xfs_trans *tp, +struct xfs_inode *ip,int whichfork, +struct xfs_iext_cursor *icur,struct xfs_btree_cur **curp, +struct xfs_bmbt_irec *new,int *logflagsp);static inline void xfs_bmap_add_free(
fs/xfs/xfs_reflink.c +38 -23
88 lines not on this page · raw message
Signature · 1 line
2.19.1