@@ -791,6 +791,16 @@ static struct super_block *quotactl_block(const char __user *special, int cmd)
struct block_device *bdev;
struct super_block *sb;
struct filename *tmp = getname(special);
+ bool thawed = false, exclusive;
+ int ret;
+
+ if (quotactl_cmd_onoff(cmd)) {
+ thawed = true;
+ exclusive = true;
+ } else if (quotactl_cmd_write(cmd)) {
+ thawed = true;
+ exclusive = false;
+ }
if (IS_ERR(tmp))
return ERR_CAST(tmp);
@@ -798,16 +808,24 @@ static struct super_block *quotactl_block(const char __user *special, int cmd)
putname(tmp);
if (IS_ERR(bdev))
return ERR_CAST(bdev);
- if (quotactl_cmd_onoff(cmd))
- sb = get_super_exclusive_thawed(bdev);
- else if (quotactl_cmd_write(cmd))
- sb = get_super_thawed(bdev);
- else
- sb = get_super(bdev);
+
bdput(bdev);
+
+ sb = get_super(bdev);
if (!sb)
return ERR_PTR(-ENODEV);
+ if (thawed) {
+ ret = wait_super_thawed(sb, exclusive);
+ if (ret) {
+ if (exclusive)
+ drop_super_exclusive(sb);
+ else
+ drop_super(sb);
+ return ERR_PTR(ret);
+ }
+ }
+
return sb;
#else
return ERR_PTR(-ENODEV);
@@ -783,61 +783,41 @@ struct super_block *get_super(struct block_device *bdev)
}
EXPORT_SYMBOL(get_super);
-static struct super_block *__get_super_thawed(struct block_device *bdev,
- bool excl)
+/**
+ * wait_super_thawed - wait for a superblock being thawed
+ * @sb: superblock to wait for
+ * @excl: if true, get s_umount semaphore exclusively
+ *
+ * Wait until the superblock is thawed. s_umount semaphore must be released on
+ * entry and will be held when returning.
+ */
+int wait_super_thawed(struct super_block *sb, bool excl)
{
- struct super_block *s = __get_super(bdev, excl);
- if (!s)
- return NULL;
+ up_read(&sb->s_umount);
while (1) {
- if (s->s_writers.frozen == SB_UNFROZEN)
- return s;
-
- if (!excl)
- up_read(&s->s_umount);
+ if (excl)
+ down_write(&sb->s_umount);
else
- up_write(&s->s_umount);
+ down_read(&sb->s_umount);
- wait_event(s->s_writers.wait_unfrozen,
- s->s_writers.frozen == SB_UNFROZEN);
+ /* still alive? */
+ if (!sb->s_root || !(sb->s_flags & SB_BORN))
+ return -ENODEV;
- if (!excl)
- down_read(&sb->s_umount);
- else
- down_write(&sb->s_umount);
- }
-}
+ if (sb->s_writers.frozen == SB_UNFROZEN)
+ return 0;
-/**
- * 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);
+ if (excl)
+ up_write(&sb->s_umount);
+ else
+ up_read(&sb->s_umount);
-/**
- * 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);
+ wait_event(sb->s_writers.wait_unfrozen,
+ sb->s_writers.frozen == SB_UNFROZEN);
+ }
}
-EXPORT_SYMBOL(get_super_exclusive_thawed);
+EXPORT_SYMBOL(wait_super_thawed);
/**
* get_active_super - get an active reference to the superblock of a device
@@ -3220,9 +3220,9 @@ extern struct file_system_type *get_filesystem(struct file_system_type *fs);
extern void put_filesystem(struct file_system_type *fs);
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_thawed(struct block_device *);
-extern struct super_block *get_super_exclusive_thawed(struct block_device *bdev);
+extern int wait_super_thawed(struct super_block *sb, bool excl);
extern struct super_block *get_active_super(struct block_device *bdev);
+extern int super_wait_thawed(struct super_block *sb, bool excl);
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 *);
quota uses three different functions to get a superblock from a block_device. Instead, retrieve the superblock always with get_super() and introduce wait_super_thawed() which is then used to wait until the superblock is thawed. This way the code can better be shared with the code introduced in the next step: We want to add quota support for filesystems without a block_device, so here functions around a block_device can't be used. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> --- fs/quota/quota.c | 30 +++++++++++++++---- fs/super.c | 72 +++++++++++++++++----------------------------- include/linux/fs.h | 4 +-- 3 files changed, 52 insertions(+), 54 deletions(-)