@@ -3876,6 +3876,63 @@ xfs_bmap_btalloc(
3876
3876
return 0 ;
3877
3877
}
3878
3878
3879
+ /*
3880
+ * For a remap operation, just "allocate" an extent at the address that the
3881
+ * caller passed in, and ensure that the AGFL is the right size. The caller
3882
+ * will then map the "allocated" extent into the file somewhere.
3883
+ */
3884
+ STATIC int
3885
+ xfs_bmap_remap_alloc (
3886
+ struct xfs_bmalloca * ap )
3887
+ {
3888
+ struct xfs_trans * tp = ap -> tp ;
3889
+ struct xfs_mount * mp = tp -> t_mountp ;
3890
+ xfs_agblock_t bno ;
3891
+ struct xfs_alloc_arg args ;
3892
+ int error ;
3893
+
3894
+ /*
3895
+ * validate that the block number is legal - the enables us to detect
3896
+ * and handle a silent filesystem corruption rather than crashing.
3897
+ */
3898
+ memset (& args , 0 , sizeof (struct xfs_alloc_arg ));
3899
+ args .tp = ap -> tp ;
3900
+ args .mp = ap -> tp -> t_mountp ;
3901
+ bno = * ap -> firstblock ;
3902
+ args .agno = XFS_FSB_TO_AGNO (mp , bno );
3903
+ args .agbno = XFS_FSB_TO_AGBNO (mp , bno );
3904
+ if (args .agno >= mp -> m_sb .sb_agcount ||
3905
+ args .agbno >= mp -> m_sb .sb_agblocks )
3906
+ return - EFSCORRUPTED ;
3907
+
3908
+ /* "Allocate" the extent from the range we passed in. */
3909
+ trace_xfs_bmap_remap_alloc (ap -> ip , * ap -> firstblock , ap -> length );
3910
+ ap -> blkno = bno ;
3911
+ ap -> ip -> i_d .di_nblocks += ap -> length ;
3912
+ xfs_trans_log_inode (ap -> tp , ap -> ip , XFS_ILOG_CORE );
3913
+
3914
+ /* Fix the freelist, like a real allocator does. */
3915
+ args .datatype = ap -> datatype ;
3916
+ args .pag = xfs_perag_get (args .mp , args .agno );
3917
+ ASSERT (args .pag );
3918
+
3919
+ /*
3920
+ * The freelist fixing code will decline the allocation if
3921
+ * the size and shape of the free space doesn't allow for
3922
+ * allocating the extent and updating all the metadata that
3923
+ * happens during an allocation. We're remapping, not
3924
+ * allocating, so skip that check by pretending to be freeing.
3925
+ */
3926
+ error = xfs_alloc_fix_freelist (& args , XFS_ALLOC_FLAG_FREEING );
3927
+ if (error )
3928
+ goto error0 ;
3929
+ error0 :
3930
+ xfs_perag_put (args .pag );
3931
+ if (error )
3932
+ trace_xfs_bmap_remap_alloc_error (ap -> ip , error , _RET_IP_ );
3933
+ return error ;
3934
+ }
3935
+
3879
3936
/*
3880
3937
* xfs_bmap_alloc is called by xfs_bmapi to allocate an extent for a file.
3881
3938
* It figures out where to ask the underlying allocator to put the new extent.
@@ -3884,6 +3941,8 @@ STATIC int
3884
3941
xfs_bmap_alloc (
3885
3942
struct xfs_bmalloca * ap ) /* bmap alloc argument struct */
3886
3943
{
3944
+ if (ap -> flags & XFS_BMAPI_REMAP )
3945
+ return xfs_bmap_remap_alloc (ap );
3887
3946
if (XFS_IS_REALTIME_INODE (ap -> ip ) &&
3888
3947
xfs_alloc_is_userdata (ap -> datatype ))
3889
3948
return xfs_bmap_rtalloc (ap );
@@ -4442,6 +4501,9 @@ xfs_bmapi_write(
4442
4501
ASSERT (len > 0 );
4443
4502
ASSERT (XFS_IFORK_FORMAT (ip , whichfork ) != XFS_DINODE_FMT_LOCAL );
4444
4503
ASSERT (xfs_isilocked (ip , XFS_ILOCK_EXCL ));
4504
+ ASSERT (!(flags & XFS_BMAPI_REMAP ) || whichfork == XFS_DATA_FORK );
4505
+ ASSERT (!(flags & XFS_BMAPI_PREALLOC ) || !(flags & XFS_BMAPI_REMAP ));
4506
+ ASSERT (!(flags & XFS_BMAPI_CONVERT ) || !(flags & XFS_BMAPI_REMAP ));
4445
4507
4446
4508
/* zeroing is for currently only for data extents, not metadata */
4447
4509
ASSERT ((flags & (XFS_BMAPI_METADATA | XFS_BMAPI_ZERO )) !=
@@ -4502,6 +4564,12 @@ xfs_bmapi_write(
4502
4564
inhole = eof || bma .got .br_startoff > bno ;
4503
4565
wasdelay = !inhole && isnullstartblock (bma .got .br_startblock );
4504
4566
4567
+ /*
4568
+ * Make sure we only reflink into a hole.
4569
+ */
4570
+ if (flags & XFS_BMAPI_REMAP )
4571
+ ASSERT (inhole );
4572
+
4505
4573
/*
4506
4574
* First, deal with the hole before the allocated space
4507
4575
* that we found, if any.
0 commit comments