Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

fs: Provide functions for handling mapping_metadata_bhs directly

As part of transition toward moving mapping_metadata_bhs to fs-private
part of the inode, provide functions for operations on this list
directly instead of going through the inode / mapping.

Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260326095354.16340-75-jack@suse.cz
Signed-off-by: Christian Brauner <brauner@kernel.org>

authored by

Jan Kara and committed by
Christian Brauner
a8c8122a 025c9af1

+87 -67
+51 -59
fs/buffer.c
··· 467 467 * a successful fsync(). For example, ext2 indirect blocks need to be 468 468 * written back and waited upon before fsync() returns. 469 469 * 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. 473 473 * 474 474 * The locking is a little subtle: The list of buffer heads is protected by 475 475 * the lock in mapping_metadata_bhs so functions coming from bdev mapping 476 476 * (such as try_to_free_buffers()) need to safely get to mapping_metadata_bhs 477 477 * using RCU, grab the lock, verify we didn't race with somebody detaching the 478 478 * 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. 493 479 */ 480 + 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); 494 488 495 489 static void __remove_assoc_queue(struct mapping_metadata_bhs *mmb, 496 490 struct buffer_head *bh) ··· 527 533 EXPORT_SYMBOL_GPL(mmb_has_buffers); 528 534 529 535 /** 530 - * sync_mapping_buffers - write out & wait upon a mapping's "associated" buffers 531 - * @mapping: the mapping which wants those buffers written 536 + * mmb_sync - write out & wait upon all buffers in a list 537 + * @mmb: the list of buffers to write 532 538 * 533 - * Starts I/O against the buffers at mapping->i_metadata_bhs and waits upon 534 - * that I/O. Basically, this is a convenience function for fsync(). @mapping 535 - * is a file or directory which needs those buffers to be written for a 539 + * Starts I/O against the buffers in the given list and waits upon 540 + * that I/O. Basically, this is a convenience function for fsync(). @mmb is 541 + * for a file or directory which needs those buffers to be written for a 536 542 * successful fsync(). 537 543 * 538 544 * We have conflicting pressures: we want to make sure that all ··· 547 553 * buffer stays on our list until IO completes (at which point it can be 548 554 * reaped). 549 555 */ 550 - int sync_mapping_buffers(struct address_space *mapping) 556 + int mmb_sync(struct mapping_metadata_bhs *mmb) 551 557 { 552 - struct mapping_metadata_bhs *mmb = &mapping->i_metadata_bhs; 553 558 struct buffer_head *bh; 554 559 int err = 0; 555 560 struct blk_plug plug; ··· 619 626 spin_unlock(&mmb->lock); 620 627 return err; 621 628 } 622 - EXPORT_SYMBOL(sync_mapping_buffers); 629 + EXPORT_SYMBOL(mmb_sync); 623 630 624 631 /** 625 - * generic_buffers_fsync_noflush - generic buffer fsync implementation 626 - * for simple filesystems with no inode lock 632 + * mmb_fsync_noflush - fsync implementation for simple filesystems with 633 + * metadata buffers list 627 634 * 628 635 * @file: file to synchronize 636 + * @mmb: list of metadata bhs to flush 629 637 * @start: start offset in bytes 630 638 * @end: end offset in bytes (inclusive) 631 639 * @datasync: only synchronize essential metadata if true 632 640 * 633 - * This is a generic implementation of the fsync method for simple 634 - * filesystems which track all non-inode metadata in the buffers list 635 - * hanging off the address_space structure. 641 + * This is an implementation of the fsync method for simple filesystems which 642 + * track all non-inode metadata in the buffers list hanging off the @mmb 643 + * structure. 636 644 */ 637 - int generic_buffers_fsync_noflush(struct file *file, loff_t start, loff_t end, 638 - bool datasync) 645 + int mmb_fsync_noflush(struct file *file, struct mapping_metadata_bhs *mmb, 646 + loff_t start, loff_t end, bool datasync) 639 647 { 640 648 struct inode *inode = file->f_mapping->host; 641 649 int err; 642 - int ret; 650 + int ret = 0; 643 651 644 652 err = file_write_and_wait_range(file, start, end); 645 653 if (err) 646 654 return err; 647 655 648 - ret = sync_mapping_buffers(inode->i_mapping); 656 + if (mmb) 657 + ret = mmb_sync(mmb); 649 658 if (!(inode_state_read_once(inode) & I_DIRTY_ALL)) 650 659 goto out; 651 660 if (datasync && !(inode_state_read_once(inode) & I_DIRTY_DATASYNC)) ··· 664 669 ret = err; 665 670 return ret; 666 671 } 667 - EXPORT_SYMBOL(generic_buffers_fsync_noflush); 672 + EXPORT_SYMBOL(mmb_fsync_noflush); 668 673 669 674 /** 670 - * generic_buffers_fsync - generic buffer fsync implementation 671 - * for simple filesystems with no inode lock 675 + * mmb_fsync - fsync implementation for simple filesystems with metadata 676 + * buffers list 672 677 * 673 678 * @file: file to synchronize 679 + * @mmb: list of metadata bhs to flush 674 680 * @start: start offset in bytes 675 681 * @end: end offset in bytes (inclusive) 676 682 * @datasync: only synchronize essential metadata if true 677 683 * 678 - * This is a generic implementation of the fsync method for simple 679 - * filesystems which track all non-inode metadata in the buffers list 680 - * hanging off the address_space structure. This also makes sure that 681 - * a device cache flush operation is called at the end. 684 + * This is an implementation of the fsync method for simple filesystems which 685 + * track all non-inode metadata in the buffers list hanging off the @mmb 686 + * structure. This also makes sure that a device cache flush operation is 687 + * called at the end. 682 688 */ 683 - int generic_buffers_fsync(struct file *file, loff_t start, loff_t end, 684 - bool datasync) 689 + int mmb_fsync(struct file *file, struct mapping_metadata_bhs *mmb, 690 + loff_t start, loff_t end, bool datasync) 685 691 { 686 692 struct inode *inode = file->f_mapping->host; 687 693 int ret; 688 694 689 - ret = generic_buffers_fsync_noflush(file, start, end, datasync); 695 + ret = mmb_fsync_noflush(file, mmb, start, end, datasync); 690 696 if (!ret) 691 697 ret = blkdev_issue_flush(inode->i_sb->s_bdev); 692 698 return ret; 693 699 } 694 - EXPORT_SYMBOL(generic_buffers_fsync); 700 + EXPORT_SYMBOL(mmb_fsync); 695 701 696 702 /* 697 703 * Called when we've recently written block `bblock', and it is known that ··· 713 717 } 714 718 } 715 719 716 - void mark_buffer_dirty_inode(struct buffer_head *bh, struct inode *inode) 720 + void mmb_mark_buffer_dirty(struct buffer_head *bh, 721 + struct mapping_metadata_bhs *mmb) 717 722 { 718 - struct address_space *mapping = inode->i_mapping; 719 - 720 723 mark_buffer_dirty(bh); 721 724 if (!bh->b_mmb) { 722 - spin_lock(&mapping->i_metadata_bhs.lock); 723 - list_move_tail(&bh->b_assoc_buffers, 724 - &mapping->i_metadata_bhs.list); 725 - bh->b_mmb = &mapping->i_metadata_bhs; 726 - spin_unlock(&mapping->i_metadata_bhs.lock); 725 + spin_lock(&mmb->lock); 726 + list_move_tail(&bh->b_assoc_buffers, &mmb->list); 727 + bh->b_mmb = mmb; 728 + spin_unlock(&mmb->lock); 727 729 } 728 730 } 729 - EXPORT_SYMBOL(mark_buffer_dirty_inode); 731 + EXPORT_SYMBOL(mmb_mark_buffer_dirty); 730 732 731 733 /** 732 734 * block_dirty_folio - Mark a folio as dirty. ··· 791 797 EXPORT_SYMBOL(block_dirty_folio); 792 798 793 799 /* 794 - * Invalidate any and all dirty buffers on a given inode. We are 800 + * Invalidate any and all dirty buffers on a given buffers list. We are 795 801 * probably unmounting the fs, but that doesn't mean we have already 796 802 * done a sync(). Just drop the buffers from the inode list. 797 803 */ 798 - void invalidate_inode_buffers(struct inode *inode) 804 + void mmb_invalidate(struct mapping_metadata_bhs *mmb) 799 805 { 800 - struct mapping_metadata_bhs *mmb = &inode->i_data.i_metadata_bhs; 801 - 802 806 if (mmb_has_buffers(mmb)) { 803 807 spin_lock(&mmb->lock); 804 808 while (!list_empty(&mmb->list)) ··· 804 812 spin_unlock(&mmb->lock); 805 813 } 806 814 } 807 - EXPORT_SYMBOL(invalidate_inode_buffers); 815 + EXPORT_SYMBOL(mmb_invalidate); 808 816 809 817 /* 810 818 * Create the appropriate buffers when given a folio for data area and
+36 -8
include/linux/buffer_head.h
··· 205 205 void end_buffer_read_sync(struct buffer_head *bh, int uptodate); 206 206 void end_buffer_write_sync(struct buffer_head *bh, int uptodate); 207 207 208 - /* Things to do with buffers at mapping->private_list */ 209 - void mark_buffer_dirty_inode(struct buffer_head *bh, struct inode *inode); 210 - int generic_buffers_fsync_noflush(struct file *file, loff_t start, loff_t end, 211 - bool datasync); 212 - int generic_buffers_fsync(struct file *file, loff_t start, loff_t end, 213 - bool datasync); 208 + /* Things to do with metadata buffers list */ 209 + void mmb_mark_buffer_dirty(struct buffer_head *bh, struct mapping_metadata_bhs *mmb); 210 + static inline void mark_buffer_dirty_inode(struct buffer_head *bh, 211 + struct inode *inode) 212 + { 213 + mmb_mark_buffer_dirty(bh, &inode->i_data.i_metadata_bhs); 214 + } 215 + int mmb_fsync_noflush(struct file *file, struct mapping_metadata_bhs *mmb, 216 + loff_t start, loff_t end, bool datasync); 217 + static inline int generic_buffers_fsync_noflush(struct file *file, 218 + loff_t start, loff_t end, 219 + bool datasync) 220 + { 221 + return mmb_fsync_noflush(file, &file->f_mapping->i_metadata_bhs, 222 + start, end, datasync); 223 + } 224 + int mmb_fsync(struct file *file, struct mapping_metadata_bhs *mmb, 225 + loff_t start, loff_t end, bool datasync); 226 + static inline int generic_buffers_fsync(struct file *file, 227 + loff_t start, loff_t end, bool datasync) 228 + { 229 + return mmb_fsync(file, &file->f_mapping->i_metadata_bhs, 230 + start, end, datasync); 231 + } 214 232 void clean_bdev_aliases(struct block_device *bdev, sector_t block, 215 233 sector_t len); 216 234 static inline void clean_bdev_bh_alias(struct buffer_head *bh) ··· 533 515 534 516 void buffer_init(void); 535 517 bool try_to_free_buffers(struct folio *folio); 518 + void mmb_init(struct mapping_metadata_bhs *mmb, struct address_space *mapping); 536 519 bool mmb_has_buffers(struct mapping_metadata_bhs *mmb); 537 - void invalidate_inode_buffers(struct inode *inode); 538 - int sync_mapping_buffers(struct address_space *mapping); 520 + void mmb_invalidate(struct mapping_metadata_bhs *mmb); 521 + int mmb_sync(struct mapping_metadata_bhs *mmb); 522 + static inline void invalidate_inode_buffers(struct inode *inode) 523 + { 524 + mmb_invalidate(&inode->i_data.i_metadata_bhs); 525 + } 526 + static inline int sync_mapping_buffers(struct address_space *mapping) 527 + { 528 + return mmb_sync(&mapping->i_metadata_bhs); 529 + } 539 530 void invalidate_bh_lrus(void); 540 531 void invalidate_bh_lrus_cpu(void); 541 532 bool has_bh_in_lru(int cpu, void *dummy); ··· 554 527 555 528 static inline void buffer_init(void) {} 556 529 static inline bool try_to_free_buffers(struct folio *folio) { return true; } 530 + static inline int mmb_sync(struct mapping_metadata_bhs *mmb) { return 0; } 557 531 static inline void invalidate_inode_buffers(struct inode *inode) {} 558 532 static inline int sync_mapping_buffers(struct address_space *mapping) { return 0; } 559 533 static inline void invalidate_bh_lrus(void) {}