@@ -1800,7 +1800,8 @@ void btrfs_reclaim_bgs_work(struct work_struct *work)
if (!btrfs_should_reclaim(fs_info))
return;
- sb_start_write(fs_info->sb);
+ if (sb_start_write(fs_info->sb) < 0)
+ return;
if (!btrfs_exclop_start(fs_info, BTRFS_EXCLOP_BALANCE)) {
sb_end_write(fs_info->sb);
@@ -274,7 +274,11 @@ static int __btrfs_run_defrag_inode(struct btrfs_fs_info *fs_info,
range.start = cur;
range.extent_thresh = defrag->extent_thresh;
- sb_start_write(fs_info->sb);
+ ret = sb_start_write(fs_info->sb);
+ if (ret < 0) {
+ iput(inode);
+ goto cleanup;
+ }
ret = btrfs_defrag_file(inode, NULL, &range, defrag->transid,
BTRFS_DEFRAG_BATCH);
sb_end_write(fs_info->sb);
@@ -4589,9 +4589,11 @@ int btrfs_balance(struct btrfs_fs_info *fs_info,
static int balance_kthread(void *data)
{
struct btrfs_fs_info *fs_info = data;
- int ret = 0;
+ int ret;
- sb_start_write(fs_info->sb);
+ ret = sb_start_write(fs_info->sb);
+ if (ret < 0)
+ return ret;
mutex_lock(&fs_info->balance_mutex);
if (fs_info->balance_ctl)
ret = btrfs_balance(fs_info, fs_info->balance_ctl, NULL);
@@ -8231,12 +8233,15 @@ static int relocating_repair_kthread(void *data)
struct btrfs_block_group *cache = data;
struct btrfs_fs_info *fs_info = cache->fs_info;
u64 target;
- int ret = 0;
+ int ret;
target = cache->start;
btrfs_put_block_group(cache);
- sb_start_write(fs_info->sb);
+ ret = sb_start_write(fs_info->sb);
+ if (ret < 0)
+ return ret;
+
if (!btrfs_exclop_start(fs_info, BTRFS_EXCLOP_BALANCE)) {
btrfs_info(fs_info,
"zoned: skip relocating block group %llu to repair: EBUSY",
@@ -63,7 +63,9 @@ static int write_mmp_block(struct super_block *sb, struct buffer_head *bh)
* We protect against freezing so that we don't create dirty buffers
* on frozen filesystem.
*/
- sb_start_write(sb);
+ err = sb_start_write(sb);
+ if (err < 0)
+ return err;
err = write_mmp_block_thawed(sb, bh);
sb_end_write(sb);
return err;
@@ -512,7 +512,9 @@ int mnt_want_write(struct vfsmount *m)
{
int ret;
- sb_start_write(m->mnt_sb);
+ ret = sb_start_write(m->mnt_sb);
+ if (ret)
+ return ret;
ret = mnt_get_write_access(m);
if (ret)
sb_end_write(m->mnt_sb);
@@ -556,7 +558,9 @@ int mnt_want_write_file(struct file *file)
{
int ret;
- sb_start_write(file_inode(file)->i_sb);
+ ret = sb_start_write(file_inode(file)->i_sb);
+ if (ret)
+ return ret;
ret = mnt_get_write_access_file(file);
if (ret)
sb_end_write(file_inode(file)->i_sb);
@@ -175,7 +175,9 @@ long do_ftruncate(struct file *file, loff_t length, int small)
/* Check IS_APPEND on real upper inode */
if (IS_APPEND(file_inode(file)))
return -EPERM;
- sb_start_write(inode->i_sb);
+ error = sb_start_write(inode->i_sb);
+ if (error)
+ return error;
error = security_file_truncate(file);
if (!error)
error = do_truncate(file_mnt_idmap(file), dentry, length,
@@ -28,8 +28,7 @@ int ovl_get_write_access(struct dentry *dentry)
int __must_check ovl_start_write(struct dentry *dentry)
{
struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
- sb_start_write(ovl_upper_mnt(ofs)->mnt_sb);
- return 0;
+ return sb_start_write(ovl_upper_mnt(ofs)->mnt_sb);
}
int ovl_want_write(struct dentry *dentry)
@@ -896,8 +896,8 @@ static struct super_block *quotactl_block(const char __user *special, int cmd)
else
up_read(&sb->s_umount);
/* Wait for sb to unfreeze */
- sb_start_write(sb);
- sb_end_write(sb);
+ if (sb_start_write(sb) == 0)
+ sb_end_write(sb);
put_super(sb);
goto retry;
}
@@ -1499,7 +1499,9 @@ xfs_file_ioctl(
trace_xfs_ioc_free_eofblocks(mp, &icw, _RET_IP_);
- sb_start_write(mp->m_super);
+ error = sb_start_write(mp->m_super);
+ if (error)
+ return error;
error = xfs_blockgc_free_space(mp, &icw);
sb_end_write(mp->m_super);
return error;
@@ -1190,6 +1190,9 @@ enum {
SB_I_TS_EXPIRY_WARNED, /* warned about timestamp range expiry */
SB_I_RETIRED, /* superblock shouldn't be reused */
SB_I_NOUMASK, /* VFS does not apply umask */
+ SB_I_SHUTDOWN, /* The filesystem has shutdown. Refuse
+ * modification attempts with error as they are
+ * a futile exercise. */
};
/* Possible states of 'frozen' field */
@@ -1823,9 +1826,12 @@ static inline void sb_end_intwrite(struct super_block *sb)
* -> i_mutex (write path, truncate, directory ops, ...)
* -> s_umount (freeze_super, thaw_super)
*/
-static inline void sb_start_write(struct super_block *sb)
+static inline int __must_check sb_start_write(struct super_block *sb)
{
+ if (sb_test_iflag(sb, SB_I_SHUTDOWN))
+ return -EROFS;
__sb_start_write(sb, SB_FREEZE_WRITE);
+ return 0;
}
static inline bool __must_check sb_start_write_trylock(struct super_block *sb)
@@ -2891,8 +2897,7 @@ static inline int __must_check file_start_write(struct file *file)
{
if (!S_ISREG(file_inode(file)->i_mode))
return 0;
- sb_start_write(file_inode(file)->i_sb);
- return 0;
+ return sb_start_write(file_inode(file)->i_sb);
}
static inline bool __must_check file_start_write_trylock(struct file *file)
@@ -2925,8 +2930,11 @@ static inline void file_end_write(struct file *file)
static inline int __must_check kiocb_start_write(struct kiocb *iocb)
{
struct inode *inode = file_inode(iocb->ki_filp);
+ int err;
- sb_start_write(inode->i_sb);
+ err = sb_start_write(inode->i_sb);
+ if (err)
+ return err;
/*
* Fool lockdep by telling it the lock got released so that it
* doesn't complain about the held lock when we return to userspace.
Introduce new SB_I_SHUTDOWN flag that a filesystem can set when it is forcefully shutting down (usually due to errors). Make sb_start_write() return errors for such superblocks to avoid modifications to it which reduces noise in the error logs and generally makes life somewhat easier for filesystems. We teach all sb_start_write() callers to handle the error. Signed-off-by: Jan Kara <jack@suse.cz> --- fs/btrfs/block-group.c | 3 ++- fs/btrfs/defrag.c | 6 +++++- fs/btrfs/volumes.c | 13 +++++++++---- fs/ext4/mmp.c | 4 +++- fs/namespace.c | 8 ++++++-- fs/open.c | 4 +++- fs/overlayfs/util.c | 3 +-- fs/quota/quota.c | 4 ++-- fs/xfs/xfs_ioctl.c | 4 +++- include/linux/fs.h | 16 ++++++++++++---- 10 files changed, 46 insertions(+), 19 deletions(-)