Commit ba6379f7 authored by Jan Kara's avatar Jan Kara

fs: Provide function to get superblock with exclusive s_umount

Quota code will need a variant of get_super_thawed() that returns
superblock with s_umount held in exclusive mode to serialize quota on
and quota off operations. Provide this functionality.
Signed-off-by: default avatarJan Kara <jack@suse.cz>
parent 9c763584
...@@ -558,6 +558,13 @@ void drop_super(struct super_block *sb) ...@@ -558,6 +558,13 @@ void drop_super(struct super_block *sb)
EXPORT_SYMBOL(drop_super); EXPORT_SYMBOL(drop_super);
void drop_super_exclusive(struct super_block *sb)
{
up_write(&sb->s_umount);
put_super(sb);
}
EXPORT_SYMBOL(drop_super_exclusive);
/** /**
* iterate_supers - call function for all active superblocks * iterate_supers - call function for all active superblocks
* @f: function to call * @f: function to call
...@@ -628,15 +635,7 @@ void iterate_supers_type(struct file_system_type *type, ...@@ -628,15 +635,7 @@ void iterate_supers_type(struct file_system_type *type,
EXPORT_SYMBOL(iterate_supers_type); EXPORT_SYMBOL(iterate_supers_type);
/** static struct super_block *__get_super(struct block_device *bdev, bool excl)
* get_super - get the superblock of a device
* @bdev: device to get the superblock for
*
* Scans the superblock list and finds the superblock of the file system
* mounted on the device given. %NULL is returned if no match is found.
*/
struct super_block *get_super(struct block_device *bdev)
{ {
struct super_block *sb; struct super_block *sb;
...@@ -651,11 +650,17 @@ struct super_block *get_super(struct block_device *bdev) ...@@ -651,11 +650,17 @@ struct super_block *get_super(struct block_device *bdev)
if (sb->s_bdev == bdev) { if (sb->s_bdev == bdev) {
sb->s_count++; sb->s_count++;
spin_unlock(&sb_lock); spin_unlock(&sb_lock);
down_read(&sb->s_umount); if (!excl)
down_read(&sb->s_umount);
else
down_write(&sb->s_umount);
/* still alive? */ /* still alive? */
if (sb->s_root && (sb->s_flags & MS_BORN)) if (sb->s_root && (sb->s_flags & MS_BORN))
return sb; return sb;
up_read(&sb->s_umount); if (!excl)
up_read(&sb->s_umount);
else
up_write(&sb->s_umount);
/* nope, got unmounted */ /* nope, got unmounted */
spin_lock(&sb_lock); spin_lock(&sb_lock);
__put_super(sb); __put_super(sb);
...@@ -666,31 +671,66 @@ struct super_block *get_super(struct block_device *bdev) ...@@ -666,31 +671,66 @@ struct super_block *get_super(struct block_device *bdev)
return NULL; return NULL;
} }
EXPORT_SYMBOL(get_super);
/** /**
* get_super_thawed - get thawed superblock of a device * get_super - get the superblock of a device
* @bdev: device to get the superblock for * @bdev: device to get the superblock for
* *
* Scans the superblock list and finds the superblock of the file system * Scans the superblock list and finds the superblock of the file system
* mounted on the device. The superblock is returned once it is thawed * mounted on the device given. %NULL is returned if no match is found.
* (or immediately if it was not frozen). %NULL is returned if no match
* is found.
*/ */
struct super_block *get_super_thawed(struct block_device *bdev) struct super_block *get_super(struct block_device *bdev)
{
return __get_super(bdev, false);
}
EXPORT_SYMBOL(get_super);
static struct super_block *__get_super_thawed(struct block_device *bdev,
bool excl)
{ {
while (1) { while (1) {
struct super_block *s = get_super(bdev); struct super_block *s = __get_super(bdev, excl);
if (!s || s->s_writers.frozen == SB_UNFROZEN) if (!s || s->s_writers.frozen == SB_UNFROZEN)
return s; return s;
up_read(&s->s_umount); if (!excl)
up_read(&s->s_umount);
else
up_write(&s->s_umount);
wait_event(s->s_writers.wait_unfrozen, wait_event(s->s_writers.wait_unfrozen,
s->s_writers.frozen == SB_UNFROZEN); s->s_writers.frozen == SB_UNFROZEN);
put_super(s); put_super(s);
} }
} }
/**
* get_super_thawed - get thawed superblock of a device
* @bdev: device to get the superblock for
*
* Scans the superblock list and finds the superblock of the file system
* mounted on the device. The superblock is returned once it is thawed
* (or immediately if it was not frozen). %NULL is returned if no match
* is found.
*/
struct super_block *get_super_thawed(struct block_device *bdev)
{
return __get_super_thawed(bdev, false);
}
EXPORT_SYMBOL(get_super_thawed); EXPORT_SYMBOL(get_super_thawed);
/**
* get_super_exclusive_thawed - get thawed superblock of a device
* @bdev: device to get the superblock for
*
* Scans the superblock list and finds the superblock of the file system
* mounted on the device. The superblock is returned once it is thawed
* (or immediately if it was not frozen) and s_umount semaphore is held
* in exclusive mode. %NULL is returned if no match is found.
*/
struct super_block *get_super_exclusive_thawed(struct block_device *bdev)
{
return __get_super_thawed(bdev, true);
}
EXPORT_SYMBOL(get_super_exclusive_thawed);
/** /**
* get_active_super - get an active reference to the superblock of a device * get_active_super - get an active reference to the superblock of a device
* @bdev: device to get the superblock for * @bdev: device to get the superblock for
......
...@@ -2949,8 +2949,10 @@ extern void put_filesystem(struct file_system_type *fs); ...@@ -2949,8 +2949,10 @@ extern void put_filesystem(struct file_system_type *fs);
extern struct file_system_type *get_fs_type(const char *name); extern struct file_system_type *get_fs_type(const char *name);
extern struct super_block *get_super(struct block_device *); extern struct super_block *get_super(struct block_device *);
extern struct super_block *get_super_thawed(struct block_device *); extern struct super_block *get_super_thawed(struct block_device *);
extern struct super_block *get_super_exclusive_thawed(struct block_device *bdev);
extern struct super_block *get_active_super(struct block_device *bdev); extern struct super_block *get_active_super(struct block_device *bdev);
extern void drop_super(struct super_block *sb); extern void drop_super(struct super_block *sb);
extern void drop_super_exclusive(struct super_block *sb);
extern void iterate_supers(void (*)(struct super_block *, void *), void *); extern void iterate_supers(void (*)(struct super_block *, void *), void *);
extern void iterate_supers_type(struct file_system_type *, extern void iterate_supers_type(struct file_system_type *,
void (*)(struct super_block *, void *), void *); void (*)(struct super_block *, void *), void *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment