Message ID | 20201124132751.3747337-5-hch@lst.de (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [01/45] blk-cgroup: fix a hd_struct leak in blkcg_fill_root_iostats | expand |
On 2020/11/24 21:27, Christoph Hellwig wrote: > Store the frozen superblock in struct block_device to avoid the awkward > interface that can return a sb only used a cookie, an ERR_PTR or NULL. > > Signed-off-by: Christoph Hellwig<hch@lst.de> > --- > drivers/md/dm-core.h | 5 ----- > drivers/md/dm.c | 20 ++++++-------------- > fs/block_dev.c | 39 ++++++++++++++++----------------------- > fs/buffer.c | 2 +- > fs/ext4/ioctl.c | 2 +- > fs/f2fs/file.c | 14 +++++--------- For f2fs part, Acked-by: Chao Yu <yuchao0@huawei.com> Thanks, > fs/xfs/xfs_fsops.c | 7 ++----- > include/linux/blk_types.h | 1 + > include/linux/blkdev.h | 4 ++-- > 9 files changed, 34 insertions(+), 60 deletions(-)
On Tue 24-11-20 14:27:10, Christoph Hellwig wrote: > Store the frozen superblock in struct block_device to avoid the awkward > interface that can return a sb only used a cookie, an ERR_PTR or NULL. > > Signed-off-by: Christoph Hellwig <hch@lst.de> Some comments below... > diff --git a/fs/block_dev.c b/fs/block_dev.c > index d8664f5c1ff669..60492620d51866 100644 > --- a/fs/block_dev.c > +++ b/fs/block_dev.c > @@ -548,55 +548,47 @@ EXPORT_SYMBOL(fsync_bdev); > * count down in thaw_bdev(). When it becomes 0, thaw_bdev() will unfreeze > * actually. > */ > -struct super_block *freeze_bdev(struct block_device *bdev) > +int freeze_bdev(struct block_device *bdev) > { > struct super_block *sb; > int error = 0; > > mutex_lock(&bdev->bd_fsfreeze_mutex); > - if (++bdev->bd_fsfreeze_count > 1) { > - /* > - * We don't even need to grab a reference - the first call > - * to freeze_bdev grab an active reference and only the last > - * thaw_bdev drops it. > - */ > - sb = get_super(bdev); > - if (sb) > - drop_super(sb); > - mutex_unlock(&bdev->bd_fsfreeze_mutex); > - return sb; > - } > + if (++bdev->bd_fsfreeze_count > 1) > + goto done; > > sb = get_active_super(bdev); > if (!sb) > - goto out; > + goto sync; > if (sb->s_op->freeze_super) > error = sb->s_op->freeze_super(sb); > else > error = freeze_super(sb); > + deactivate_super(sb); > + > if (error) { > - deactivate_super(sb); > bdev->bd_fsfreeze_count--; > - mutex_unlock(&bdev->bd_fsfreeze_mutex); > - return ERR_PTR(error); > + goto done; > } > - deactivate_super(sb); > - out: > + bdev->bd_fsfreeze_sb = sb; > + > +sync: > sync_blockdev(bdev); > +done: > mutex_unlock(&bdev->bd_fsfreeze_mutex); > - return sb; /* thaw_bdev releases s->s_umount */ > + return error; /* thaw_bdev releases s->s_umount */ The comment about thaw_bdev() seems to be stale? At least I don't see what it's speaking about... > } > EXPORT_SYMBOL(freeze_bdev); > > /** > * thaw_bdev -- unlock filesystem > * @bdev: blockdevice to unlock > - * @sb: associated superblock > * > * Unlocks the filesystem and marks it writeable again after freeze_bdev(). > */ > -int thaw_bdev(struct block_device *bdev, struct super_block *sb) > +int thaw_bdev(struct block_device *bdev) > { > + struct super_block *sb; > int error = -EINVAL; > > mutex_lock(&bdev->bd_fsfreeze_mutex); > @@ -607,6 +599,7 @@ int thaw_bdev(struct block_device *bdev, struct super_block *sb) > if (--bdev->bd_fsfreeze_count > 0) > goto out; > > + sb = bdev->bd_fsfreeze_sb; > if (!sb) > goto out; > > @@ -618,7 +611,7 @@ int thaw_bdev(struct block_device *bdev, struct super_block *sb) > bdev->bd_fsfreeze_count++; > out: > mutex_unlock(&bdev->bd_fsfreeze_mutex); > - return error; > + return 0; But we now won't return -EINVAL if this gets called e.g. with bd_fsfreeze_count == 0, right? Honza
On Wed, Nov 25, 2020 at 01:29:53PM +0100, Jan Kara wrote: > > mutex_unlock(&bdev->bd_fsfreeze_mutex); > > - return sb; /* thaw_bdev releases s->s_umount */ > > + return error; /* thaw_bdev releases s->s_umount */ > > The comment about thaw_bdev() seems to be stale? At least I don't see what > it's speaking about... Yes, this comment seems long stale. I think in the very early days we held s_umount on frozen file system, which caused all kinds of problems. > > mutex_unlock(&bdev->bd_fsfreeze_mutex); > > - return error; > > + return 0; > > But we now won't return -EINVAL if this gets called e.g. with > bd_fsfreeze_count == 0, right? Yes. I had tried to drop the return value as all the freeze_bdev calls ignored it. But I had missed the unpaired emergency thaw and put it back and messed this up..
diff --git a/drivers/md/dm-core.h b/drivers/md/dm-core.h index d522093cb39dda..aace147effcacb 100644 --- a/drivers/md/dm-core.h +++ b/drivers/md/dm-core.h @@ -96,11 +96,6 @@ struct mapped_device { */ struct workqueue_struct *wq; - /* - * freeze/thaw support require holding onto a super block - */ - struct super_block *frozen_sb; - /* forced geometry settings */ struct hd_geometry geometry; diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 54739f1b579bc8..50541d336c719b 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -2392,27 +2392,19 @@ static int lock_fs(struct mapped_device *md) { int r; - WARN_ON(md->frozen_sb); + WARN_ON(test_bit(DMF_FROZEN, &md->flags)); - md->frozen_sb = freeze_bdev(md->bdev); - if (IS_ERR(md->frozen_sb)) { - r = PTR_ERR(md->frozen_sb); - md->frozen_sb = NULL; - return r; - } - - set_bit(DMF_FROZEN, &md->flags); - - return 0; + r = freeze_bdev(md->bdev); + if (!r) + set_bit(DMF_FROZEN, &md->flags); + return r; } static void unlock_fs(struct mapped_device *md) { if (!test_bit(DMF_FROZEN, &md->flags)) return; - - thaw_bdev(md->bdev, md->frozen_sb); - md->frozen_sb = NULL; + thaw_bdev(md->bdev); clear_bit(DMF_FROZEN, &md->flags); } diff --git a/fs/block_dev.c b/fs/block_dev.c index d8664f5c1ff669..60492620d51866 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -548,55 +548,47 @@ EXPORT_SYMBOL(fsync_bdev); * count down in thaw_bdev(). When it becomes 0, thaw_bdev() will unfreeze * actually. */ -struct super_block *freeze_bdev(struct block_device *bdev) +int freeze_bdev(struct block_device *bdev) { struct super_block *sb; int error = 0; mutex_lock(&bdev->bd_fsfreeze_mutex); - if (++bdev->bd_fsfreeze_count > 1) { - /* - * We don't even need to grab a reference - the first call - * to freeze_bdev grab an active reference and only the last - * thaw_bdev drops it. - */ - sb = get_super(bdev); - if (sb) - drop_super(sb); - mutex_unlock(&bdev->bd_fsfreeze_mutex); - return sb; - } + if (++bdev->bd_fsfreeze_count > 1) + goto done; sb = get_active_super(bdev); if (!sb) - goto out; + goto sync; if (sb->s_op->freeze_super) error = sb->s_op->freeze_super(sb); else error = freeze_super(sb); + deactivate_super(sb); + if (error) { - deactivate_super(sb); bdev->bd_fsfreeze_count--; - mutex_unlock(&bdev->bd_fsfreeze_mutex); - return ERR_PTR(error); + goto done; } - deactivate_super(sb); - out: + bdev->bd_fsfreeze_sb = sb; + +sync: sync_blockdev(bdev); +done: mutex_unlock(&bdev->bd_fsfreeze_mutex); - return sb; /* thaw_bdev releases s->s_umount */ + return error; /* thaw_bdev releases s->s_umount */ } EXPORT_SYMBOL(freeze_bdev); /** * thaw_bdev -- unlock filesystem * @bdev: blockdevice to unlock - * @sb: associated superblock * * Unlocks the filesystem and marks it writeable again after freeze_bdev(). */ -int thaw_bdev(struct block_device *bdev, struct super_block *sb) +int thaw_bdev(struct block_device *bdev) { + struct super_block *sb; int error = -EINVAL; mutex_lock(&bdev->bd_fsfreeze_mutex); @@ -607,6 +599,7 @@ int thaw_bdev(struct block_device *bdev, struct super_block *sb) if (--bdev->bd_fsfreeze_count > 0) goto out; + sb = bdev->bd_fsfreeze_sb; if (!sb) goto out; @@ -618,7 +611,7 @@ int thaw_bdev(struct block_device *bdev, struct super_block *sb) bdev->bd_fsfreeze_count++; out: mutex_unlock(&bdev->bd_fsfreeze_mutex); - return error; + return 0; } EXPORT_SYMBOL(thaw_bdev); diff --git a/fs/buffer.c b/fs/buffer.c index 23f645657488ba..a7595ada9400ff 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -523,7 +523,7 @@ static int osync_buffers_list(spinlock_t *lock, struct list_head *list) void emergency_thaw_bdev(struct super_block *sb) { - while (sb->s_bdev && !thaw_bdev(sb->s_bdev, sb)) + while (sb->s_bdev && !thaw_bdev(sb->s_bdev)) printk(KERN_WARNING "Emergency Thaw on %pg\n", sb->s_bdev); } diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index f0381876a7e5b0..524e134324475e 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -624,7 +624,7 @@ static int ext4_shutdown(struct super_block *sb, unsigned long arg) case EXT4_GOING_FLAGS_DEFAULT: freeze_bdev(sb->s_bdev); set_bit(EXT4_FLAGS_SHUTDOWN, &sbi->s_ext4_flags); - thaw_bdev(sb->s_bdev, sb); + thaw_bdev(sb->s_bdev); break; case EXT4_GOING_FLAGS_LOGFLUSH: set_bit(EXT4_FLAGS_SHUTDOWN, &sbi->s_ext4_flags); diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index ee861c6d9ff026..a9fc482a0e60a5 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -2230,16 +2230,12 @@ static int f2fs_ioc_shutdown(struct file *filp, unsigned long arg) switch (in) { case F2FS_GOING_DOWN_FULLSYNC: - sb = freeze_bdev(sb->s_bdev); - if (IS_ERR(sb)) { - ret = PTR_ERR(sb); + ret = freeze_bdev(sb->s_bdev); + if (ret) goto out; - } - if (sb) { - f2fs_stop_checkpoint(sbi, false); - set_sbi_flag(sbi, SBI_IS_SHUTDOWN); - thaw_bdev(sb->s_bdev, sb); - } + f2fs_stop_checkpoint(sbi, false); + set_sbi_flag(sbi, SBI_IS_SHUTDOWN); + thaw_bdev(sb->s_bdev); break; case F2FS_GOING_DOWN_METASYNC: /* do checkpoint only */ diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index ef1d5bb88b93ab..b7c5783a031c69 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c @@ -433,13 +433,10 @@ xfs_fs_goingdown( { switch (inflags) { case XFS_FSOP_GOING_FLAGS_DEFAULT: { - struct super_block *sb = freeze_bdev(mp->m_super->s_bdev); - - if (sb && !IS_ERR(sb)) { + if (!freeze_bdev(mp->m_super->s_bdev)) { xfs_force_shutdown(mp, SHUTDOWN_FORCE_UMOUNT); - thaw_bdev(sb->s_bdev, sb); + thaw_bdev(mp->m_super->s_bdev); } - break; } case XFS_FSOP_GOING_FLAGS_LOGFLUSH: diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index d9b69bbde5cc54..ebfb4e7c1fd125 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -46,6 +46,7 @@ struct block_device { int bd_fsfreeze_count; /* Mutex for freeze */ struct mutex bd_fsfreeze_mutex; + struct super_block *bd_fsfreeze_sb; } __randomize_layout; /* diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 05b346a68c2eee..12810a19edebc4 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -2020,7 +2020,7 @@ static inline int sync_blockdev(struct block_device *bdev) #endif int fsync_bdev(struct block_device *bdev); -struct super_block *freeze_bdev(struct block_device *bdev); -int thaw_bdev(struct block_device *bdev, struct super_block *sb); +int freeze_bdev(struct block_device *bdev); +int thaw_bdev(struct block_device *bdev); #endif /* _LINUX_BLKDEV_H */
Store the frozen superblock in struct block_device to avoid the awkward interface that can return a sb only used a cookie, an ERR_PTR or NULL. Signed-off-by: Christoph Hellwig <hch@lst.de> --- drivers/md/dm-core.h | 5 ----- drivers/md/dm.c | 20 ++++++-------------- fs/block_dev.c | 39 ++++++++++++++++----------------------- fs/buffer.c | 2 +- fs/ext4/ioctl.c | 2 +- fs/f2fs/file.c | 14 +++++--------- fs/xfs/xfs_fsops.c | 7 ++----- include/linux/blk_types.h | 1 + include/linux/blkdev.h | 4 ++-- 9 files changed, 34 insertions(+), 60 deletions(-)