From 2527fd38772fea30c1d1cbf94839a0bbf4122133 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 11 Aug 2023 12:08:22 +0200 Subject: dasd: also call __invalidate_device when setting the device offline Don't just write out the data, but also invalidate all caches when setting the device offline. Stop canceling the offlining when writeback fails as there is no way to recover from that anyway. Signed-off-by: Christoph Hellwig Reviewed-by: Josef Bacik Message-Id: <20230811100828.1897174-12-hch@lst.de> Signed-off-by: Christian Brauner --- drivers/s390/block/dasd.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/s390/block') diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index edcbf77852c3..675b38ad00dc 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -3627,9 +3627,8 @@ int dasd_generic_set_offline(struct ccw_device *cdev) * empty */ if (device->block) { - rc = fsync_bdev(device->block->bdev); - if (rc != 0) - goto interrupted; + fsync_bdev(device->block->bdev); + __invalidate_device(device->block->bdev, true); } dasd_schedule_device_bh(device); rc = wait_event_interruptible(shutdown_waitq, -- cgit v1.2.3 From 560e20e4bf6484a0c12f9f3c7a1aa55056948e1e Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 11 Aug 2023 12:08:24 +0200 Subject: block: consolidate __invalidate_device and fsync_bdev 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 Reviewed-by: Josef Bacik Message-Id: <20230811100828.1897174-14-hch@lst.de> Signed-off-by: Christian Brauner --- block/bdev.c | 33 ++++++++++++++++++++++++++++----- block/disk-events.c | 4 ++-- block/genhd.c | 3 +-- block/partitions/core.c | 5 +---- drivers/s390/block/dasd.c | 6 ++---- fs/super.c | 4 ++-- include/linux/blkdev.h | 2 +- 7 files changed, 37 insertions(+), 20 deletions(-) (limited to 'drivers/s390/block') diff --git a/block/bdev.c b/block/bdev.c index 979e28a46b98..074a9ffa9d8b 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -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) { diff --git a/block/disk-events.c b/block/disk-events.c index 6b858d350477..422db8292d09 100644 --- a/block/disk-events.c +++ b/block/disk-events.c @@ -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); diff --git a/block/genhd.c b/block/genhd.c index 3d287b32d50d..afc2cb09eb94 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -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); diff --git a/block/partitions/core.c b/block/partitions/core.c index 13a7341299a9..e137a87f4db0 100644 --- a/block/partitions/core.c +++ b/block/partitions/core.c @@ -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); } diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 675b38ad00dc..1f642be840c3 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -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)); diff --git a/fs/super.c b/fs/super.c index f72a1112a31b..9b2188e08bcc 100644 --- a/fs/super.c +++ b/fs/super.c @@ -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); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index c8eab6effc22..6721595b9f97 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -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 -- cgit v1.2.3