@@ -467,31 +467,25 @@ EXPORT_SYMBOL(mark_buffer_async_write);
467467 * a successful fsync(). For example, ext2 indirect blocks need to be
468468 * written back and waited upon before fsync() returns.
469469 *
470- * The functions mark_buffer_dirty_inode (), fsync_inode_buffers (),
471- * mmb_has_buffers() and invalidate_inode_buffers () are provided for the
472- * management of a list of dependent buffers in mapping_metadata_bhs struct.
470+ * The functions mmb_mark_buffer_dirty (), mmb_sync (), mmb_has_buffers()
471+ * and mmb_invalidate () are provided for the management of a list of dependent
472+ * buffers in mapping_metadata_bhs struct.
473473 *
474474 * The locking is a little subtle: The list of buffer heads is protected by
475475 * the lock in mapping_metadata_bhs so functions coming from bdev mapping
476476 * (such as try_to_free_buffers()) need to safely get to mapping_metadata_bhs
477477 * using RCU, grab the lock, verify we didn't race with somebody detaching the
478478 * bh / moving it to different inode and only then proceeding.
479- *
480- * FIXME: mark_buffer_dirty_inode() is a data-plane operation. It should
481- * take an address_space, not an inode. And it should be called
482- * mark_buffer_dirty_fsync() to clearly define why those buffers are being
483- * queued up.
484- *
485- * FIXME: mark_buffer_dirty_inode() doesn't need to add the buffer to the
486- * list if it is already on a list. Because if the buffer is on a list,
487- * it *must* already be on the right one. If not, the filesystem is being
488- * silly. This will save a ton of locking. But first we have to ensure
489- * that buffers are taken *off* the old inode's list when they are freed
490- * (presumably in truncate). That requires careful auditing of all
491- * filesystems (do it inside bforget()). It could also be done by bringing
492- * b_inode back.
493479 */
494480
481+ void mmb_init (struct mapping_metadata_bhs * mmb , struct address_space * mapping )
482+ {
483+ spin_lock_init (& mmb -> lock );
484+ INIT_LIST_HEAD (& mmb -> list );
485+ mmb -> mapping = mapping ;
486+ }
487+ EXPORT_SYMBOL (mmb_init );
488+
495489static void __remove_assoc_queue (struct mapping_metadata_bhs * mmb ,
496490 struct buffer_head * bh )
497491{
@@ -533,12 +527,12 @@ bool mmb_has_buffers(struct mapping_metadata_bhs *mmb)
533527EXPORT_SYMBOL_GPL (mmb_has_buffers );
534528
535529/**
536- * sync_mapping_buffers - write out & wait upon a mapping's "associated" buffers
537- * @mapping : the mapping which wants those buffers written
530+ * mmb_sync - write out & wait upon all buffers in a list
531+ * @mmb : the list of buffers to write
538532 *
539- * Starts I/O against the buffers at mapping->i_metadata_bhs and waits upon
540- * that I/O. Basically, this is a convenience function for fsync(). @mapping
541- * is a file or directory which needs those buffers to be written for a
533+ * Starts I/O against the buffers in the given list and waits upon
534+ * that I/O. Basically, this is a convenience function for fsync(). @mmb is
535+ * for a file or directory which needs those buffers to be written for a
542536 * successful fsync().
543537 *
544538 * We have conflicting pressures: we want to make sure that all
@@ -553,9 +547,8 @@ EXPORT_SYMBOL_GPL(mmb_has_buffers);
553547 * buffer stays on our list until IO completes (at which point it can be
554548 * reaped).
555549 */
556- int sync_mapping_buffers (struct address_space * mapping )
550+ int mmb_sync (struct mapping_metadata_bhs * mmb )
557551{
558- struct mapping_metadata_bhs * mmb = & mapping -> i_metadata_bhs ;
559552 struct buffer_head * bh ;
560553 int err = 0 ;
561554 struct blk_plug plug ;
@@ -626,33 +619,35 @@ int sync_mapping_buffers(struct address_space *mapping)
626619 spin_unlock (& mmb -> lock );
627620 return err ;
628621}
629- EXPORT_SYMBOL (sync_mapping_buffers );
622+ EXPORT_SYMBOL (mmb_sync );
630623
631624/**
632- * generic_buffers_fsync_noflush - generic buffer fsync implementation
633- * for simple filesystems with no inode lock
625+ * mmb_fsync_noflush - fsync implementation for simple filesystems with
626+ * metadata buffers list
634627 *
635628 * @file: file to synchronize
629+ * @mmb: list of metadata bhs to flush
636630 * @start: start offset in bytes
637631 * @end: end offset in bytes (inclusive)
638632 * @datasync: only synchronize essential metadata if true
639633 *
640- * This is a generic implementation of the fsync method for simple
641- * filesystems which track all non-inode metadata in the buffers list
642- * hanging off the address_space structure.
634+ * This is an implementation of the fsync method for simple filesystems which
635+ * track all non-inode metadata in the buffers list hanging off the @mmb
636+ * structure.
643637 */
644- int generic_buffers_fsync_noflush (struct file * file , loff_t start , loff_t end ,
645- bool datasync )
638+ int mmb_fsync_noflush (struct file * file , struct mapping_metadata_bhs * mmb ,
639+ loff_t start , loff_t end , bool datasync )
646640{
647641 struct inode * inode = file -> f_mapping -> host ;
648642 int err ;
649- int ret ;
643+ int ret = 0 ;
650644
651645 err = file_write_and_wait_range (file , start , end );
652646 if (err )
653647 return err ;
654648
655- ret = sync_mapping_buffers (inode -> i_mapping );
649+ if (mmb )
650+ ret = mmb_sync (mmb );
656651 if (!(inode_state_read_once (inode ) & I_DIRTY_ALL ))
657652 goto out ;
658653 if (datasync && !(inode_state_read_once (inode ) & I_DIRTY_DATASYNC ))
@@ -669,34 +664,35 @@ int generic_buffers_fsync_noflush(struct file *file, loff_t start, loff_t end,
669664 ret = err ;
670665 return ret ;
671666}
672- EXPORT_SYMBOL (generic_buffers_fsync_noflush );
667+ EXPORT_SYMBOL (mmb_fsync_noflush );
673668
674669/**
675- * generic_buffers_fsync - generic buffer fsync implementation
676- * for simple filesystems with no inode lock
670+ * mmb_fsync - fsync implementation for simple filesystems with metadata
671+ * buffers list
677672 *
678673 * @file: file to synchronize
674+ * @mmb: list of metadata bhs to flush
679675 * @start: start offset in bytes
680676 * @end: end offset in bytes (inclusive)
681677 * @datasync: only synchronize essential metadata if true
682678 *
683- * This is a generic implementation of the fsync method for simple
684- * filesystems which track all non-inode metadata in the buffers list
685- * hanging off the address_space structure. This also makes sure that
686- * a device cache flush operation is called at the end.
679+ * This is an implementation of the fsync method for simple filesystems which
680+ * track all non-inode metadata in the buffers list hanging off the @mmb
681+ * structure. This also makes sure that a device cache flush operation is
682+ * called at the end.
687683 */
688- int generic_buffers_fsync (struct file * file , loff_t start , loff_t end ,
689- bool datasync )
684+ int mmb_fsync (struct file * file , struct mapping_metadata_bhs * mmb ,
685+ loff_t start , loff_t end , bool datasync )
690686{
691687 struct inode * inode = file -> f_mapping -> host ;
692688 int ret ;
693689
694- ret = generic_buffers_fsync_noflush (file , start , end , datasync );
690+ ret = mmb_fsync_noflush (file , mmb , start , end , datasync );
695691 if (!ret )
696692 ret = blkdev_issue_flush (inode -> i_sb -> s_bdev );
697693 return ret ;
698694}
699- EXPORT_SYMBOL (generic_buffers_fsync );
695+ EXPORT_SYMBOL (mmb_fsync );
700696
701697/*
702698 * Called when we've recently written block `bblock', and it is known that
@@ -717,20 +713,18 @@ void write_boundary_block(struct block_device *bdev,
717713 }
718714}
719715
720- void mark_buffer_dirty_inode (struct buffer_head * bh , struct inode * inode )
716+ void mmb_mark_buffer_dirty (struct buffer_head * bh ,
717+ struct mapping_metadata_bhs * mmb )
721718{
722- struct address_space * mapping = inode -> i_mapping ;
723-
724719 mark_buffer_dirty (bh );
725720 if (!bh -> b_mmb ) {
726- spin_lock (& mapping -> i_metadata_bhs .lock );
727- list_move_tail (& bh -> b_assoc_buffers ,
728- & mapping -> i_metadata_bhs .list );
729- bh -> b_mmb = & mapping -> i_metadata_bhs ;
730- spin_unlock (& mapping -> i_metadata_bhs .lock );
721+ spin_lock (& mmb -> lock );
722+ list_move_tail (& bh -> b_assoc_buffers , & mmb -> list );
723+ bh -> b_mmb = mmb ;
724+ spin_unlock (& mmb -> lock );
731725 }
732726}
733- EXPORT_SYMBOL (mark_buffer_dirty_inode );
727+ EXPORT_SYMBOL (mmb_mark_buffer_dirty );
734728
735729/**
736730 * block_dirty_folio - Mark a folio as dirty.
@@ -797,22 +791,20 @@ bool block_dirty_folio(struct address_space *mapping, struct folio *folio)
797791EXPORT_SYMBOL (block_dirty_folio );
798792
799793/*
800- * Invalidate any and all dirty buffers on a given inode . We are
794+ * Invalidate any and all dirty buffers on a given buffers list . We are
801795 * probably unmounting the fs, but that doesn't mean we have already
802796 * done a sync(). Just drop the buffers from the inode list.
803797 */
804- void invalidate_inode_buffers (struct inode * inode )
798+ void mmb_invalidate (struct mapping_metadata_bhs * mmb )
805799{
806- struct mapping_metadata_bhs * mmb = & inode -> i_data .i_metadata_bhs ;
807-
808800 if (mmb_has_buffers (mmb )) {
809801 spin_lock (& mmb -> lock );
810802 while (!list_empty (& mmb -> list ))
811803 __remove_assoc_queue (mmb , BH_ENTRY (mmb -> list .next ));
812804 spin_unlock (& mmb -> lock );
813805 }
814806}
815- EXPORT_SYMBOL (invalidate_inode_buffers );
807+ EXPORT_SYMBOL (mmb_invalidate );
816808
817809/*
818810 * Create the appropriate buffers when given a folio for data area and
0 commit comments