Skip to content

Commit 04b9407

Browse files
Daniil LunevMiklos Szeredi
authored andcommitted
vfs: function to prevent re-use of block-device-based superblocks
The function is to be called from filesystem-specific code to mark a superblock to be ignored by superblock test and thus never re-used. The function also unregisters bdi if the bdi is per-superblock to avoid collision if a new superblock is created to represent the filesystem. generic_shutdown_super() skips unregistering bdi for a retired superlock as it assumes retire function has already done it. This patch adds the functionality only for the block-device-based supers, since the primary use case of the feature is to gracefully handle force unmount of external devices, mounted with FUSE. This can be further extended to cover all superblocks, if the need arises. Signed-off-by: Daniil Lunev <dlunev@chromium.org> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
1 parent 73fb2c8 commit 04b9407

2 files changed

Lines changed: 33 additions & 2 deletions

File tree

fs/super.c

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,35 @@ bool trylock_super(struct super_block *sb)
422422
return false;
423423
}
424424

425+
/**
426+
* retire_super - prevents superblock from being reused
427+
* @sb: superblock to retire
428+
*
429+
* The function marks superblock to be ignored in superblock test, which
430+
* prevents it from being reused for any new mounts. If the superblock has
431+
* a private bdi, it also unregisters it, but doesn't reduce the refcount
432+
* of the superblock to prevent potential races. The refcount is reduced
433+
* by generic_shutdown_super(). The function can not be called
434+
* concurrently with generic_shutdown_super(). It is safe to call the
435+
* function multiple times, subsequent calls have no effect.
436+
*
437+
* The marker will affect the re-use only for block-device-based
438+
* superblocks. Other superblocks will still get marked if this function
439+
* is used, but that will not affect their reusability.
440+
*/
441+
void retire_super(struct super_block *sb)
442+
{
443+
WARN_ON(!sb->s_bdev);
444+
down_write(&sb->s_umount);
445+
if (sb->s_iflags & SB_I_PERSB_BDI) {
446+
bdi_unregister(sb->s_bdi);
447+
sb->s_iflags &= ~SB_I_PERSB_BDI;
448+
}
449+
sb->s_iflags |= SB_I_RETIRED;
450+
up_write(&sb->s_umount);
451+
}
452+
EXPORT_SYMBOL(retire_super);
453+
425454
/**
426455
* generic_shutdown_super - common helper for ->kill_sb()
427456
* @sb: superblock to kill
@@ -1216,7 +1245,7 @@ static int set_bdev_super_fc(struct super_block *s, struct fs_context *fc)
12161245

12171246
static int test_bdev_super_fc(struct super_block *s, struct fs_context *fc)
12181247
{
1219-
return s->s_bdev == fc->sget_key;
1248+
return !(s->s_iflags & SB_I_RETIRED) && s->s_bdev == fc->sget_key;
12201249
}
12211250

12221251
/**
@@ -1307,7 +1336,7 @@ EXPORT_SYMBOL(get_tree_bdev);
13071336

13081337
static int test_bdev_super(struct super_block *s, void *data)
13091338
{
1310-
return (void *)s->s_bdev == data;
1339+
return !(s->s_iflags & SB_I_RETIRED) && (void *)s->s_bdev == data;
13111340
}
13121341

13131342
struct dentry *mount_bdev(struct file_system_type *fs_type,

include/linux/fs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1412,6 +1412,7 @@ extern int send_sigurg(struct fown_struct *fown);
14121412
#define SB_I_SKIP_SYNC 0x00000100 /* Skip superblock at global sync */
14131413
#define SB_I_PERSB_BDI 0x00000200 /* has a per-sb bdi */
14141414
#define SB_I_TS_EXPIRY_WARNED 0x00000400 /* warned about timestamp range expiry */
1415+
#define SB_I_RETIRED 0x00000800 /* superblock shouldn't be reused */
14151416

14161417
/* Possible states of 'frozen' field */
14171418
enum {
@@ -2432,6 +2433,7 @@ extern struct dentry *mount_nodev(struct file_system_type *fs_type,
24322433
int flags, void *data,
24332434
int (*fill_super)(struct super_block *, void *, int));
24342435
extern struct dentry *mount_subtree(struct vfsmount *mnt, const char *path);
2436+
void retire_super(struct super_block *sb);
24352437
void generic_shutdown_super(struct super_block *sb);
24362438
void kill_block_super(struct super_block *sb);
24372439
void kill_anon_super(struct super_block *sb);

0 commit comments

Comments
 (0)