diff --git a/fs/ext4/super.c b/fs/ext4/super.c index c10b56ab3eea..c28c5d0efa56 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -72,6 +72,7 @@ static void ext4_mark_recovery_complete(struct super_block *sb, static void ext4_clear_journal_err(struct super_block *sb, struct ext4_super_block *es); static int ext4_sync_fs(struct super_block *sb, int wait); +static void ext4_umount_end(struct super_block *sb, int flags); static int ext4_remount(struct super_block *sb, int *flags, char *data); static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf); static int ext4_unfreeze(struct super_block *sb); @@ -1275,6 +1276,7 @@ static const struct super_operations ext4_sops = { .freeze_fs = ext4_freeze, .unfreeze_fs = ext4_unfreeze, .statfs = ext4_statfs, + .umount_end = ext4_umount_end, .remount_fs = ext4_remount, .show_options = ext4_show_options, #ifdef CONFIG_QUOTA @@ -4976,6 +4978,25 @@ struct ext4_mount_options { #endif }; +static void ext4_umount_end(struct super_block *sb, int flags) +{ + /* + * this is called at the end of umount(2). If there is an unclosed + * namespace, ext4 won't do put_super() which triggers fsck in the + * next boot. + */ + if ((flags & MNT_FORCE) || atomic_read(&sb->s_active) > 1) { + ext4_msg(sb, KERN_ERR, + "errors=remount-ro for active namespaces on umount %x", + flags); + clear_opt(sb, ERRORS_PANIC); + set_opt(sb, ERRORS_RO); + /* to write the latest s_kbytes_written */ + if (!(sb->s_flags & MS_RDONLY)) + ext4_commit_super(sb, 1); + } +} + static int ext4_remount(struct super_block *sb, int *flags, char *data) { struct ext4_super_block *es; diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index fa4948e12df8..68d0277fb46f 100755 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1040,6 +1040,24 @@ static void destroy_device_list(struct f2fs_sb_info *sbi) kvfree(sbi->devs); } +static void f2fs_umount_end(struct super_block *sb, int flags) +{ + /* + * this is called at the end of umount(2). If there is an unclosed + * namespace, f2fs won't do put_super() which triggers fsck in the + * next boot. + */ + if ((flags & MNT_FORCE) || atomic_read(&sb->s_active) > 1) { + /* to write the latest kbytes_written */ + if (!(sb->s_flags & MS_RDONLY)) { + struct cp_control cpc = { + .reason = CP_UMOUNT, + }; + f2fs_write_checkpoint(F2FS_SB(sb), &cpc); + } + } +} + static void f2fs_put_super(struct super_block *sb) { struct f2fs_sb_info *sbi = F2FS_SB(sb); @@ -2218,6 +2236,7 @@ static const struct super_operations f2fs_sops = { #endif .evict_inode = f2fs_evict_inode, .put_super = f2fs_put_super, + .umount_end = f2fs_umount_end, .sync_fs = f2fs_sync_fs, .freeze_fs = f2fs_freeze, .unfreeze_fs = f2fs_unfreeze, diff --git a/fs/file_table.c b/fs/file_table.c index 747bb386b446..251d54ee7ef7 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -261,6 +261,12 @@ void flush_delayed_fput(void) static DECLARE_DELAYED_WORK(delayed_fput_work, delayed_fput); +void flush_delayed_fput_wait(void) +{ + delayed_fput(NULL); + flush_delayed_work(&delayed_fput_work); +} + void fput_many(struct file *file, unsigned int refs) { if (atomic_long_sub_and_test(refs, &file->f_count)) { diff --git a/fs/namespace.c b/fs/namespace.c index 8f4ce6c56e74..66333a390ff7 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -20,6 +20,7 @@ #include /* get_fs_root et.al. */ #include /* fsnotify_vfsmount_delete */ #include +#include #include #include #include @@ -1163,6 +1164,12 @@ static void delayed_mntput(struct work_struct *unused) } static DECLARE_DELAYED_WORK(delayed_mntput_work, delayed_mntput); +void flush_delayed_mntput_wait(void) +{ + delayed_mntput(NULL); + flush_delayed_work(&delayed_mntput_work); +} + static void mntput_no_expire(struct mount *mnt) { rcu_read_lock(); @@ -1718,6 +1725,7 @@ SYSCALL_DEFINE2(umount, char __user *, name, int, flags) struct mount *mnt; int retval; int lookup_flags = 0; + bool user_request = !(current->flags & PF_KTHREAD); if (flags & ~(MNT_FORCE | MNT_DETACH | MNT_EXPIRE | UMOUNT_NOFOLLOW)) return -EINVAL; @@ -1743,11 +1751,35 @@ SYSCALL_DEFINE2(umount, char __user *, name, int, flags) if (flags & MNT_FORCE && !capable(CAP_SYS_ADMIN)) goto dput_and_out; + /* flush delayed_fput to put mnt_count */ + if (user_request) + flush_delayed_fput_wait(); + retval = do_umount(mnt, flags); dput_and_out: /* we mustn't call path_put() as that would clear mnt_expiry_mark */ dput(path.dentry); mntput_no_expire(mnt); + + if (!user_request) + goto out; + + if (!retval) { + /* + * If the last delayed_fput() is called during do_umount() + * and makes mnt_count zero, we need to guarantee to register + * delayed_mntput by waiting for delayed_fput work again. + */ + flush_delayed_fput_wait(); + + /* flush delayed_mntput_work to put sb->s_active */ + flush_delayed_mntput_wait(); + } + if (!retval || (flags & MNT_FORCE)) { + /* filesystem needs to handle unclosed namespaces */ + if (mnt->mnt.mnt_sb->s_op->umount_end) + mnt->mnt.mnt_sb->s_op->umount_end(mnt->mnt.mnt_sb, flags); + } out: return retval; } diff --git a/include/linux/file.h b/include/linux/file.h index d5baf7194fb0..8723759dbd36 100644 --- a/include/linux/file.h +++ b/include/linux/file.h @@ -86,6 +86,7 @@ extern void put_unused_fd(unsigned int fd); extern void fd_install(unsigned int fd, struct file *file); extern void flush_delayed_fput(void); +extern void flush_delayed_fput_wait(void); extern void __fput_sync(struct file *); #endif /* __LINUX_FILE_H */ diff --git a/include/linux/fs.h b/include/linux/fs.h index 68c4f71cbe52..7a7bc091ae13 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1850,6 +1850,7 @@ struct super_operations { void *(*clone_mnt_data) (void *); void (*copy_mnt_data) (void *, void *); void (*umount_begin) (struct super_block *); + void (*umount_end) (struct super_block *, int); int (*show_options)(struct seq_file *, struct dentry *); int (*show_options2)(struct vfsmount *,struct seq_file *, struct dentry *);