@@ -111,6 +111,9 @@ void btrfs_init_subpage_info(struct btrfs_subpage_info *subpage_info, u32 sector
111111 subpage_info -> checked_offset = cur ;
112112 cur += nr_bits ;
113113
114+ subpage_info -> locked_offset = cur ;
115+ cur += nr_bits ;
116+
114117 subpage_info -> total_nr_bits = cur ;
115118}
116119
@@ -237,28 +240,58 @@ static void btrfs_subpage_assert(const struct btrfs_fs_info *fs_info,
237240 start + len <= folio_pos (folio ) + PAGE_SIZE );
238241}
239242
243+ #define subpage_calc_start_bit (fs_info , folio , name , start , len ) \
244+ ({ \
245+ unsigned int start_bit; \
246+ \
247+ btrfs_subpage_assert(fs_info, folio, start, len); \
248+ start_bit = offset_in_page(start) >> fs_info->sectorsize_bits; \
249+ start_bit += fs_info->subpage_info->name##_offset; \
250+ start_bit; \
251+ })
252+
240253void btrfs_subpage_start_reader (const struct btrfs_fs_info * fs_info ,
241254 struct folio * folio , u64 start , u32 len )
242255{
243256 struct btrfs_subpage * subpage = folio_get_private (folio );
257+ const int start_bit = subpage_calc_start_bit (fs_info , folio , locked , start , len );
244258 const int nbits = len >> fs_info -> sectorsize_bits ;
259+ unsigned long flags ;
260+
245261
246262 btrfs_subpage_assert (fs_info , folio , start , len );
247263
264+ spin_lock_irqsave (& subpage -> lock , flags );
265+ /*
266+ * Even though it's just for reading the page, no one should have
267+ * locked the subpage range.
268+ */
269+ ASSERT (bitmap_test_range_all_zero (subpage -> bitmaps , start_bit , nbits ));
270+ bitmap_set (subpage -> bitmaps , start_bit , nbits );
248271 atomic_add (nbits , & subpage -> readers );
272+ spin_unlock_irqrestore (& subpage -> lock , flags );
249273}
250274
251275void btrfs_subpage_end_reader (const struct btrfs_fs_info * fs_info ,
252276 struct folio * folio , u64 start , u32 len )
253277{
254278 struct btrfs_subpage * subpage = folio_get_private (folio );
279+ const int start_bit = subpage_calc_start_bit (fs_info , folio , locked , start , len );
255280 const int nbits = len >> fs_info -> sectorsize_bits ;
281+ unsigned long flags ;
256282 bool is_data ;
257283 bool last ;
258284
259285 btrfs_subpage_assert (fs_info , folio , start , len );
260286 is_data = is_data_inode (folio -> mapping -> host );
287+
288+ spin_lock_irqsave (& subpage -> lock , flags );
289+
290+ /* The range should have already been locked. */
291+ ASSERT (bitmap_test_range_all_set (subpage -> bitmaps , start_bit , nbits ));
261292 ASSERT (atomic_read (& subpage -> readers ) >= nbits );
293+
294+ bitmap_clear (subpage -> bitmaps , start_bit , nbits );
262295 last = atomic_sub_and_test (nbits , & subpage -> readers );
263296
264297 /*
@@ -270,6 +303,7 @@ void btrfs_subpage_end_reader(const struct btrfs_fs_info *fs_info,
270303 */
271304 if (is_data && last )
272305 folio_unlock (folio );
306+ spin_unlock_irqrestore (& subpage -> lock , flags );
273307}
274308
275309static void btrfs_subpage_clamp_range (struct folio * folio , u64 * start , u32 * len )
@@ -365,16 +399,6 @@ void btrfs_folio_end_writer_lock(const struct btrfs_fs_info *fs_info,
365399 folio_unlock (folio );
366400}
367401
368- #define subpage_calc_start_bit (fs_info , folio , name , start , len ) \
369- ({ \
370- unsigned int start_bit; \
371- \
372- btrfs_subpage_assert(fs_info, folio, start, len); \
373- start_bit = offset_in_page(start) >> fs_info->sectorsize_bits; \
374- start_bit += fs_info->subpage_info->name##_offset; \
375- start_bit; \
376- })
377-
378402#define subpage_test_bitmap_all_set (fs_info , subpage , name ) \
379403 bitmap_test_range_all_set(subpage->bitmaps, \
380404 fs_info->subpage_info->name##_offset, \
@@ -751,6 +775,7 @@ void __cold btrfs_subpage_dump_bitmap(const struct btrfs_fs_info *fs_info,
751775 GET_SUBPAGE_BITMAP (subpage , subpage_info , writeback , & writeback_bitmap );
752776 GET_SUBPAGE_BITMAP (subpage , subpage_info , ordered , & ordered_bitmap );
753777 GET_SUBPAGE_BITMAP (subpage , subpage_info , checked , & checked_bitmap );
778+ GET_SUBPAGE_BITMAP (subpage , subpage_info , locked , & checked_bitmap );
754779 spin_unlock_irqrestore (& subpage -> lock , flags );
755780
756781 dump_page (folio_page (folio , 0 ), "btrfs subpage dump" );
0 commit comments