Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

New helper: deactivate_locked_super()

Does equivalent of up_write(&s->s_umount); deactivate_super(s);
However, it does not does not unlock it until it's all over.
As the result, it's safe to use to dispose of new superblock on ->get_sb()
failure exits - nobody will see the sucker until it's all over.
Equivalent using up_write/deactivate_super is safe for that purpose
if superblock is either safe to use or has NULL ->s_root when we unlock.
Normally filesystems take the required precautions, but
a) we do have bugs in that area in some of them.
b) up_write/deactivate_super sequence is extremely common,
so the helper makes sense anyway.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

Al Viro 74dbbdd7 677c9b2e

+35 -12
+34 -12
fs/super.c
··· 208 208 EXPORT_SYMBOL(deactivate_super); 209 209 210 210 /** 211 + * deactivate_locked_super - drop an active reference to superblock 212 + * @s: superblock to deactivate 213 + * 214 + * Equivalent of up_write(&s->s_umount); deactivate_super(s);, except that 215 + * it does not unlock it until it's all over. As the result, it's safe to 216 + * use to dispose of new superblock on ->get_sb() failure exits - nobody 217 + * will see the sucker until it's all over. Equivalent using up_write + 218 + * deactivate_super is safe for that purpose only if superblock is either 219 + * safe to use or has NULL ->s_root when we unlock. 220 + */ 221 + void deactivate_locked_super(struct super_block *s) 222 + { 223 + struct file_system_type *fs = s->s_type; 224 + if (atomic_dec_and_lock(&s->s_active, &sb_lock)) { 225 + s->s_count -= S_BIAS-1; 226 + spin_unlock(&sb_lock); 227 + vfs_dq_off(s, 0); 228 + fs->kill_sb(s); 229 + put_filesystem(fs); 230 + put_super(s); 231 + } else { 232 + up_write(&s->s_umount); 233 + } 234 + } 235 + 236 + EXPORT_SYMBOL(deactivate_locked_super); 237 + 238 + /** 211 239 * grab_super - acquire an active reference 212 240 * @s: reference we are trying to make active 213 241 * ··· 825 797 sb->s_flags = flags; 826 798 err = fill_super(sb, data, flags & MS_SILENT ? 1 : 0); 827 799 if (err) { 828 - up_write(&sb->s_umount); 829 - deactivate_super(sb); 800 + deactivate_locked_super(sb); 830 801 return err; 831 802 } 832 803 ··· 881 854 882 855 if (s->s_root) { 883 856 if ((flags ^ s->s_flags) & MS_RDONLY) { 884 - up_write(&s->s_umount); 885 - deactivate_super(s); 857 + deactivate_locked_super(s); 886 858 error = -EBUSY; 887 859 goto error_bdev; 888 860 } ··· 896 870 sb_set_blocksize(s, block_size(bdev)); 897 871 error = fill_super(s, data, flags & MS_SILENT ? 1 : 0); 898 872 if (error) { 899 - up_write(&s->s_umount); 900 - deactivate_super(s); 873 + deactivate_locked_super(s); 901 874 goto error; 902 875 } 903 876 ··· 946 921 947 922 error = fill_super(s, data, flags & MS_SILENT ? 1 : 0); 948 923 if (error) { 949 - up_write(&s->s_umount); 950 - deactivate_super(s); 924 + deactivate_locked_super(s); 951 925 return error; 952 926 } 953 927 s->s_flags |= MS_ACTIVE; ··· 976 952 s->s_flags = flags; 977 953 error = fill_super(s, data, flags & MS_SILENT ? 1 : 0); 978 954 if (error) { 979 - up_write(&s->s_umount); 980 - deactivate_super(s); 955 + deactivate_locked_super(s); 981 956 return error; 982 957 } 983 958 s->s_flags |= MS_ACTIVE; ··· 1029 1006 return mnt; 1030 1007 out_sb: 1031 1008 dput(mnt->mnt_root); 1032 - up_write(&mnt->mnt_sb->s_umount); 1033 - deactivate_super(mnt->mnt_sb); 1009 + deactivate_locked_super(mnt->mnt_sb); 1034 1010 out_free_secdata: 1035 1011 free_secdata(secdata); 1036 1012 out_mnt:
+1
include/linux/fs.h
··· 1775 1775 void kill_anon_super(struct super_block *sb); 1776 1776 void kill_litter_super(struct super_block *sb); 1777 1777 void deactivate_super(struct super_block *sb); 1778 + void deactivate_locked_super(struct super_block *sb); 1778 1779 int set_anon_super(struct super_block *s, void *data); 1779 1780 struct super_block *sget(struct file_system_type *type, 1780 1781 int (*test)(struct super_block *,void *),