block: consolidate __invalidate_device and fsync_bdev
authorChristoph Hellwig <hch@lst.de>
Fri, 11 Aug 2023 10:08:24 +0000 (12:08 +0200)
committerChristian Brauner <brauner@kernel.org>
Mon, 21 Aug 2023 12:35:31 +0000 (14:35 +0200)
We currently have two interfaces that take a block_devices and the find
a mounted file systems to flush or invaldidate data on it.  Both are a
bit problematic because they only work for the "main" block devices
that is used as s_dev for the super_block, and because they don't call
into the file system at all.

Merge the two into a new bdev_mark_dead helper that does both the
syncing and invalidation and which is properly documented.  This is
in preparation of merging the functionality into the ->mark_dead
holder operation so that it will work on additional block devices
used by a file systems and give us a single entry point for invalidation
of dead devices or media.

Note that a single standalone fsync_bdev call for an obscure ioctl
remains for now, but that one will also be deal with in a bit.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Josef Bacik <josef@toxicpanda.com>
Message-Id: <20230811100828.1897174-14-hch@lst.de>
Signed-off-by: Christian Brauner <brauner@kernel.org>
block/bdev.c
block/disk-events.c
block/genhd.c
block/partitions/core.c
drivers/s390/block/dasd.c
fs/super.c
include/linux/blkdev.h

index 979e28a..074a9ff 100644 (file)
@@ -221,7 +221,6 @@ int fsync_bdev(struct block_device *bdev)
        }
        return sync_blockdev(bdev);
 }
-EXPORT_SYMBOL(fsync_bdev);
 
 /**
  * freeze_bdev - lock a filesystem and force it into a consistent state
@@ -960,12 +959,27 @@ out_path_put:
 }
 EXPORT_SYMBOL(lookup_bdev);
 
-int __invalidate_device(struct block_device *bdev, bool kill_dirty)
+/**
+ * bdev_mark_dead - mark a block device as dead
+ * @bdev: block device to operate on
+ * @surprise: indicate a surprise removal
+ *
+ * Tell the file system that this devices or media is dead.  If @surprise is set
+ * to %true the device or media is already gone, if not we are preparing for an
+ * orderly removal.
+ *
+ * This syncs out all dirty data and writes back inodes and then invalidates any
+ * cached data in the inodes on the file system, the inodes themselves and the
+ * block device mapping.
+ */
+void bdev_mark_dead(struct block_device *bdev, bool surprise)
 {
        struct super_block *sb = get_super(bdev);
        int res = 0;
 
        if (sb) {
+               if (!surprise)
+                       sync_filesystem(sb);
                /*
                 * no need to lock the super, get_super holds the
                 * read mutex so the filesystem cannot go away
@@ -973,13 +987,22 @@ int __invalidate_device(struct block_device *bdev, bool kill_dirty)
                 * hold).
                 */
                shrink_dcache_sb(sb);
-               res = invalidate_inodes(sb, kill_dirty);
+               res = invalidate_inodes(sb, true);
                drop_super(sb);
+       } else {
+               if (!surprise)
+                       sync_blockdev(bdev);
        }
        invalidate_bdev(bdev);
-       return res;
 }
-EXPORT_SYMBOL(__invalidate_device);
+#ifdef CONFIG_DASD_MODULE
+/*
+ * Drivers should not use this directly, but the DASD driver has historically
+ * had a shutdown to offline mode that doesn't actually remove the gendisk
+ * that otherwise looks a lot like a safe device removal.
+ */
+EXPORT_SYMBOL_GPL(bdev_mark_dead);
+#endif
 
 void sync_bdevs(bool wait)
 {
index 6b858d3..422db82 100644 (file)
@@ -281,7 +281,7 @@ bool disk_check_media_change(struct gendisk *disk)
        if (!(events & DISK_EVENT_MEDIA_CHANGE))
                return false;
 
-       __invalidate_device(disk->part0, true);
+       bdev_mark_dead(disk->part0, true);
        set_bit(GD_NEED_PART_SCAN, &disk->state);
        return true;
 }
@@ -300,7 +300,7 @@ void disk_force_media_change(struct gendisk *disk)
 {
        disk_event_uevent(disk, DISK_EVENT_MEDIA_CHANGE);
        inc_diskseq(disk);
-       __invalidate_device(disk->part0, true);
+       bdev_mark_dead(disk->part0, true);
        set_bit(GD_NEED_PART_SCAN, &disk->state);
 }
 EXPORT_SYMBOL_GPL(disk_force_media_change);
index 3d287b3..afc2cb0 100644 (file)
@@ -647,8 +647,7 @@ void del_gendisk(struct gendisk *disk)
        mutex_lock(&disk->open_mutex);
        xa_for_each(&disk->part_tbl, idx, part) {
                remove_inode_hash(part->bd_inode);
-               fsync_bdev(part);
-               __invalidate_device(part, true);
+               bdev_mark_dead(part, false);
        }
        mutex_unlock(&disk->open_mutex);
 
index 13a7341..e137a87 100644 (file)
@@ -281,10 +281,7 @@ static void delete_partition(struct block_device *part)
         * looked up any more even when openers still hold references.
         */
        remove_inode_hash(part->bd_inode);
-
-       fsync_bdev(part);
-       __invalidate_device(part, true);
-
+       bdev_mark_dead(part, false);
        drop_partition(part);
 }
 
index 675b38a..1f642be 100644 (file)
@@ -3626,10 +3626,8 @@ int dasd_generic_set_offline(struct ccw_device *cdev)
                 * so sync bdev first and then wait for our queues to become
                 * empty
                 */
-               if (device->block) {
-                       fsync_bdev(device->block->bdev);
-                       __invalidate_device(device->block->bdev, true);
-               }
+               if (device->block)
+                       bdev_mark_dead(device->block->bdev, false);
                dasd_schedule_device_bh(device);
                rc = wait_event_interruptible(shutdown_waitq,
                                              _wait_for_empty_queues(device));
index f72a111..9b2188e 100644 (file)
@@ -1359,7 +1359,7 @@ int get_tree_bdev(struct fs_context *fc,
                /*
                 * We drop s_umount here because we need to open the bdev and
                 * bdev->open_mutex ranks above s_umount (blkdev_put() ->
-                * __invalidate_device()). It is safe because we have active sb
+                * bdev_mark_dead()). It is safe because we have active sb
                 * reference and SB_BORN is not set yet.
                 */
                up_write(&s->s_umount);
@@ -1411,7 +1411,7 @@ struct dentry *mount_bdev(struct file_system_type *fs_type,
                /*
                 * We drop s_umount here because we need to open the bdev and
                 * bdev->open_mutex ranks above s_umount (blkdev_put() ->
-                * __invalidate_device()). It is safe because we have active sb
+                * bdev_mark_dead()). It is safe because we have active sb
                 * reference and SB_BORN is not set yet.
                 */
                up_write(&s->s_umount);
index c8eab6e..6721595 100644 (file)
@@ -751,6 +751,7 @@ static inline int bdev_read_only(struct block_device *bdev)
 
 bool set_capacity_and_notify(struct gendisk *disk, sector_t size);
 void disk_force_media_change(struct gendisk *disk);
+void bdev_mark_dead(struct block_device *bdev, bool surprise);
 
 void add_disk_randomness(struct gendisk *disk) __latent_entropy;
 void rand_initialize_disk(struct gendisk *disk);
@@ -809,7 +810,6 @@ int __register_blkdev(unsigned int major, const char *name,
 void unregister_blkdev(unsigned int major, const char *name);
 
 bool disk_check_media_change(struct gendisk *disk);
-int __invalidate_device(struct block_device *bdev, bool kill_dirty);
 void set_capacity(struct gendisk *disk, sector_t size);
 
 #ifdef CONFIG_BLOCK_HOLDER_DEPRECATED