@@ -2735,65 +2735,141 @@ xfs_rmap_has_records(
27352735 return xfs_btree_has_records (cur , & low , & high , & mask , outcome );
27362736}
27372737
2738- /*
2739- * Is there a record for this owner completely covering a given physical
2740- * extent? If so, *has_rmap will be set to true. If there is no record
2741- * or the record only covers part of the range, we set *has_rmap to false.
2742- * This function doesn't perform range lookups or offset checks, so it is
2743- * not suitable for checking data fork blocks.
2744- */
2745- int
2746- xfs_rmap_record_exists (
2747- struct xfs_btree_cur * cur ,
2738+ struct xfs_rmap_ownercount {
2739+ /* Owner that we're looking for. */
2740+ struct xfs_rmap_irec good ;
2741+
2742+ /* rmap search keys */
2743+ struct xfs_rmap_irec low ;
2744+ struct xfs_rmap_irec high ;
2745+
2746+ struct xfs_rmap_matches * results ;
2747+
2748+ /* Stop early if we find a nonmatch? */
2749+ bool stop_on_nonmatch ;
2750+ };
2751+
2752+ /* Does this rmap represent space that can have multiple owners? */
2753+ static inline bool
2754+ xfs_rmap_shareable (
2755+ struct xfs_mount * mp ,
2756+ const struct xfs_rmap_irec * rmap )
2757+ {
2758+ if (!xfs_has_reflink (mp ))
2759+ return false;
2760+ if (XFS_RMAP_NON_INODE_OWNER (rmap -> rm_owner ))
2761+ return false;
2762+ if (rmap -> rm_flags & (XFS_RMAP_ATTR_FORK |
2763+ XFS_RMAP_BMBT_BLOCK ))
2764+ return false;
2765+ return true;
2766+ }
2767+
2768+ static inline void
2769+ xfs_rmap_ownercount_init (
2770+ struct xfs_rmap_ownercount * roc ,
27482771 xfs_agblock_t bno ,
27492772 xfs_extlen_t len ,
27502773 const struct xfs_owner_info * oinfo ,
2751- bool * has_rmap )
2774+ struct xfs_rmap_matches * results )
27522775{
2753- uint64_t owner ;
2754- uint64_t offset ;
2755- unsigned int flags ;
2756- int has_record ;
2757- struct xfs_rmap_irec irec ;
2758- int error ;
2776+ memset (roc , 0 , sizeof (* roc ));
2777+ roc -> results = results ;
2778+
2779+ roc -> low .rm_startblock = bno ;
2780+ memset (& roc -> high , 0xFF , sizeof (roc -> high ));
2781+ roc -> high .rm_startblock = bno + len - 1 ;
2782+
2783+ memset (results , 0 , sizeof (* results ));
2784+ roc -> good .rm_startblock = bno ;
2785+ roc -> good .rm_blockcount = len ;
2786+ roc -> good .rm_owner = oinfo -> oi_owner ;
2787+ roc -> good .rm_offset = oinfo -> oi_offset ;
2788+ if (oinfo -> oi_flags & XFS_OWNER_INFO_ATTR_FORK )
2789+ roc -> good .rm_flags |= XFS_RMAP_ATTR_FORK ;
2790+ if (oinfo -> oi_flags & XFS_OWNER_INFO_BMBT_BLOCK )
2791+ roc -> good .rm_flags |= XFS_RMAP_BMBT_BLOCK ;
2792+ }
27592793
2760- xfs_owner_info_unpack (oinfo , & owner , & offset , & flags );
2761- ASSERT (XFS_RMAP_NON_INODE_OWNER (owner ) ||
2762- (flags & XFS_RMAP_BMBT_BLOCK ));
2794+ /* Figure out if this is a match for the owner. */
2795+ STATIC int
2796+ xfs_rmap_count_owners_helper (
2797+ struct xfs_btree_cur * cur ,
2798+ const struct xfs_rmap_irec * rec ,
2799+ void * priv )
2800+ {
2801+ struct xfs_rmap_ownercount * roc = priv ;
2802+ struct xfs_rmap_irec check = * rec ;
2803+ unsigned int keyflags ;
2804+ bool filedata ;
2805+ int64_t delta ;
2806+
2807+ filedata = !XFS_RMAP_NON_INODE_OWNER (check .rm_owner ) &&
2808+ !(check .rm_flags & XFS_RMAP_BMBT_BLOCK );
2809+
2810+ /* Trim the part of check that comes before the comparison range. */
2811+ delta = (int64_t )roc -> good .rm_startblock - check .rm_startblock ;
2812+ if (delta > 0 ) {
2813+ check .rm_startblock += delta ;
2814+ check .rm_blockcount -= delta ;
2815+ if (filedata )
2816+ check .rm_offset += delta ;
2817+ }
27632818
2764- error = xfs_rmap_lookup_le (cur , bno , owner , offset , flags , & irec ,
2765- & has_record );
2766- if (error )
2767- return error ;
2768- if (!has_record ) {
2769- * has_rmap = false;
2770- return 0 ;
2819+ /* Trim the part of check that comes after the comparison range. */
2820+ delta = (check .rm_startblock + check .rm_blockcount ) -
2821+ (roc -> good .rm_startblock + roc -> good .rm_blockcount );
2822+ if (delta > 0 )
2823+ check .rm_blockcount -= delta ;
2824+
2825+ /* Don't care about unwritten status for establishing ownership. */
2826+ keyflags = check .rm_flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK );
2827+
2828+ if (check .rm_startblock == roc -> good .rm_startblock &&
2829+ check .rm_blockcount == roc -> good .rm_blockcount &&
2830+ check .rm_owner == roc -> good .rm_owner &&
2831+ check .rm_offset == roc -> good .rm_offset &&
2832+ keyflags == roc -> good .rm_flags ) {
2833+ roc -> results -> matches ++ ;
2834+ } else {
2835+ roc -> results -> non_owner_matches ++ ;
2836+ if (xfs_rmap_shareable (cur -> bc_mp , & roc -> good ) ^
2837+ xfs_rmap_shareable (cur -> bc_mp , & check ))
2838+ roc -> results -> bad_non_owner_matches ++ ;
27712839 }
27722840
2773- * has_rmap = (irec .rm_owner == owner && irec .rm_startblock <= bno &&
2774- irec .rm_startblock + irec .rm_blockcount >= bno + len );
2841+ if (roc -> results -> non_owner_matches && roc -> stop_on_nonmatch )
2842+ return - ECANCELED ;
2843+
27752844 return 0 ;
27762845}
27772846
2778- struct xfs_rmap_key_state {
2779- uint64_t owner ;
2780- uint64_t offset ;
2781- unsigned int flags ;
2782- };
2783-
2784- /* For each rmap given, figure out if it doesn't match the key we want. */
2785- STATIC int
2786- xfs_rmap_has_other_keys_helper (
2847+ /* Count the number of owners and non-owners of this range of blocks. */
2848+ int
2849+ xfs_rmap_count_owners (
27872850 struct xfs_btree_cur * cur ,
2788- const struct xfs_rmap_irec * rec ,
2789- void * priv )
2851+ xfs_agblock_t bno ,
2852+ xfs_extlen_t len ,
2853+ const struct xfs_owner_info * oinfo ,
2854+ struct xfs_rmap_matches * results )
27902855{
2791- struct xfs_rmap_key_state * rks = priv ;
2856+ struct xfs_rmap_ownercount roc ;
2857+ int error ;
27922858
2793- if (rks -> owner == rec -> rm_owner && rks -> offset == rec -> rm_offset &&
2794- ((rks -> flags & rec -> rm_flags ) & XFS_RMAP_KEY_FLAGS ) == rks -> flags )
2795- return 0 ;
2796- return - ECANCELED ;
2859+ xfs_rmap_ownercount_init (& roc , bno , len , oinfo , results );
2860+ error = xfs_rmap_query_range (cur , & roc .low , & roc .high ,
2861+ xfs_rmap_count_owners_helper , & roc );
2862+ if (error )
2863+ return error ;
2864+
2865+ /*
2866+ * There can't be any non-owner rmaps that conflict with the given
2867+ * owner if we didn't find any rmaps matching the owner.
2868+ */
2869+ if (!results -> matches )
2870+ results -> bad_non_owner_matches = 0 ;
2871+
2872+ return 0 ;
27972873}
27982874
27992875/*
@@ -2806,28 +2882,26 @@ xfs_rmap_has_other_keys(
28062882 xfs_agblock_t bno ,
28072883 xfs_extlen_t len ,
28082884 const struct xfs_owner_info * oinfo ,
2809- bool * has_rmap )
2885+ bool * has_other )
28102886{
2811- struct xfs_rmap_irec low = {0 };
2812- struct xfs_rmap_irec high ;
2813- struct xfs_rmap_key_state rks ;
2887+ struct xfs_rmap_matches res ;
2888+ struct xfs_rmap_ownercount roc ;
28142889 int error ;
28152890
2816- xfs_owner_info_unpack (oinfo , & rks .owner , & rks .offset , & rks .flags );
2817- * has_rmap = false;
2818-
2819- low .rm_startblock = bno ;
2820- memset (& high , 0xFF , sizeof (high ));
2821- high .rm_startblock = bno + len - 1 ;
2891+ xfs_rmap_ownercount_init (& roc , bno , len , oinfo , & res );
2892+ roc .stop_on_nonmatch = true;
28222893
2823- error = xfs_rmap_query_range (cur , & low , & high ,
2824- xfs_rmap_has_other_keys_helper , & rks );
2894+ error = xfs_rmap_query_range (cur , & roc . low , & roc . high ,
2895+ xfs_rmap_count_owners_helper , & roc );
28252896 if (error == - ECANCELED ) {
2826- * has_rmap = true;
2897+ * has_other = true;
28272898 return 0 ;
28282899 }
2900+ if (error )
2901+ return error ;
28292902
2830- return error ;
2903+ * has_other = false;
2904+ return 0 ;
28312905}
28322906
28332907const struct xfs_owner_info XFS_RMAP_OINFO_SKIP_UPDATE = {
0 commit comments