Merge tag 'acpi-5.20-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael...
[linux-2.6-microblaze.git] / fs / super.c
index 4fca665..734ed58 100644 (file)
@@ -422,6 +422,35 @@ bool trylock_super(struct super_block *sb)
        return false;
 }
 
+/**
+ *     retire_super    -       prevents superblock from being reused
+ *     @sb: superblock to retire
+ *
+ *     The function marks superblock to be ignored in superblock test, which
+ *     prevents it from being reused for any new mounts.  If the superblock has
+ *     a private bdi, it also unregisters it, but doesn't reduce the refcount
+ *     of the superblock to prevent potential races.  The refcount is reduced
+ *     by generic_shutdown_super().  The function can not be called
+ *     concurrently with generic_shutdown_super().  It is safe to call the
+ *     function multiple times, subsequent calls have no effect.
+ *
+ *     The marker will affect the re-use only for block-device-based
+ *     superblocks.  Other superblocks will still get marked if this function
+ *     is used, but that will not affect their reusability.
+ */
+void retire_super(struct super_block *sb)
+{
+       WARN_ON(!sb->s_bdev);
+       down_write(&sb->s_umount);
+       if (sb->s_iflags & SB_I_PERSB_BDI) {
+               bdi_unregister(sb->s_bdi);
+               sb->s_iflags &= ~SB_I_PERSB_BDI;
+       }
+       sb->s_iflags |= SB_I_RETIRED;
+       up_write(&sb->s_umount);
+}
+EXPORT_SYMBOL(retire_super);
+
 /**
  *     generic_shutdown_super  -       common helper for ->kill_sb()
  *     @sb: superblock to kill
@@ -1216,7 +1245,7 @@ static int set_bdev_super_fc(struct super_block *s, struct fs_context *fc)
 
 static int test_bdev_super_fc(struct super_block *s, struct fs_context *fc)
 {
-       return s->s_bdev == fc->sget_key;
+       return !(s->s_iflags & SB_I_RETIRED) && s->s_bdev == fc->sget_key;
 }
 
 /**
@@ -1309,7 +1338,7 @@ EXPORT_SYMBOL(get_tree_bdev);
 
 static int test_bdev_super(struct super_block *s, void *data)
 {
-       return (void *)s->s_bdev == data;
+       return !(s->s_iflags & SB_I_RETIRED) && (void *)s->s_bdev == data;
 }
 
 struct dentry *mount_bdev(struct file_system_type *fs_type,