@@ -5915,6 +5915,102 @@ static bool need_full_stripe(enum btrfs_map_op op)
59155915 return (op == BTRFS_MAP_WRITE || op == BTRFS_MAP_GET_READ_MIRRORS );
59165916}
59175917
5918+ /*
5919+ * btrfs_get_io_geometry - calculates the geomery of a particular (address, len)
5920+ * tuple. This information is used to calculate how big a
5921+ * particular bio can get before it straddles a stripe.
5922+ *
5923+ * @fs_info - the filesystem
5924+ * @logical - address that we want to figure out the geometry of
5925+ * @len - the length of IO we are going to perform, starting at @logical
5926+ * @op - type of operation - write or read
5927+ * @io_geom - pointer used to return values
5928+ *
5929+ * Returns < 0 in case a chunk for the given logical address cannot be found,
5930+ * usually shouldn't happen unless @logical is corrupted, 0 otherwise.
5931+ */
5932+ int btrfs_get_io_geometry (struct btrfs_fs_info * fs_info , enum btrfs_map_op op ,
5933+ u64 logical , u64 len , struct btrfs_io_geometry * io_geom )
5934+ {
5935+ struct extent_map * em ;
5936+ struct map_lookup * map ;
5937+ u64 offset ;
5938+ u64 stripe_offset ;
5939+ u64 stripe_nr ;
5940+ u64 stripe_len ;
5941+ u64 raid56_full_stripe_start = (u64 )- 1 ;
5942+ int data_stripes ;
5943+
5944+ ASSERT (op != BTRFS_MAP_DISCARD );
5945+
5946+ em = btrfs_get_chunk_map (fs_info , logical , len );
5947+ if (IS_ERR (em ))
5948+ return PTR_ERR (em );
5949+
5950+ map = em -> map_lookup ;
5951+ /* Offset of this logical address in the chunk */
5952+ offset = logical - em -> start ;
5953+ /* Len of a stripe in a chunk */
5954+ stripe_len = map -> stripe_len ;
5955+ /* Stripe wher this block falls in */
5956+ stripe_nr = div64_u64 (offset , stripe_len );
5957+ /* Offset of stripe in the chunk */
5958+ stripe_offset = stripe_nr * stripe_len ;
5959+ if (offset < stripe_offset ) {
5960+ btrfs_crit (fs_info ,
5961+ "stripe math has gone wrong, stripe_offset=%llu offset=%llu start=%llu logical=%llu stripe_len=%llu" ,
5962+ stripe_offset , offset , em -> start , logical , stripe_len );
5963+ free_extent_map (em );
5964+ return - EINVAL ;
5965+ }
5966+
5967+ /* stripe_offset is the offset of this block in its stripe */
5968+ stripe_offset = offset - stripe_offset ;
5969+ data_stripes = nr_data_stripes (map );
5970+
5971+ if (map -> type & BTRFS_BLOCK_GROUP_PROFILE_MASK ) {
5972+ u64 max_len = stripe_len - stripe_offset ;
5973+
5974+ /*
5975+ * In case of raid56, we need to know the stripe aligned start
5976+ */
5977+ if (map -> type & BTRFS_BLOCK_GROUP_RAID56_MASK ) {
5978+ unsigned long full_stripe_len = stripe_len * data_stripes ;
5979+ raid56_full_stripe_start = offset ;
5980+
5981+ /*
5982+ * Allow a write of a full stripe, but make sure we
5983+ * don't allow straddling of stripes
5984+ */
5985+ raid56_full_stripe_start = div64_u64 (raid56_full_stripe_start ,
5986+ full_stripe_len );
5987+ raid56_full_stripe_start *= full_stripe_len ;
5988+
5989+ /*
5990+ * For writes to RAID[56], allow a full stripeset across
5991+ * all disks. For other RAID types and for RAID[56]
5992+ * reads, just allow a single stripe (on a single disk).
5993+ */
5994+ if (op == BTRFS_MAP_WRITE ) {
5995+ max_len = stripe_len * data_stripes -
5996+ (offset - raid56_full_stripe_start );
5997+ }
5998+ }
5999+ len = min_t (u64 , em -> len - offset , max_len );
6000+ } else {
6001+ len = em -> len - offset ;
6002+ }
6003+
6004+ io_geom -> len = len ;
6005+ io_geom -> offset = offset ;
6006+ io_geom -> stripe_len = stripe_len ;
6007+ io_geom -> stripe_nr = stripe_nr ;
6008+ io_geom -> stripe_offset = stripe_offset ;
6009+ io_geom -> raid56_stripe_offset = raid56_full_stripe_start ;
6010+
6011+ return 0 ;
6012+ }
6013+
59186014static int __btrfs_map_block (struct btrfs_fs_info * fs_info ,
59196015 enum btrfs_map_op op ,
59206016 u64 logical , u64 * length ,
0 commit comments