summaryrefslogtreecommitdiffstats
path: root/fs/quota/quota.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/quota/quota.c')
-rw-r--r--fs/quota/quota.c40
1 files changed, 28 insertions, 12 deletions
diff --git a/fs/quota/quota.c b/fs/quota/quota.c
index 9af95c7a0bbe..6d16b2be5ac4 100644
--- a/fs/quota/quota.c
+++ b/fs/quota/quota.c
@@ -20,6 +20,7 @@
#include <linux/writeback.h>
#include <linux/nospec.h>
#include "compat.h"
+#include "../internal.h"
static int check_quotactl_permission(struct super_block *sb, int type, int cmd,
qid_t id)
@@ -865,27 +866,42 @@ static bool quotactl_cmd_onoff(int cmd)
static struct super_block *quotactl_block(const char __user *special, int cmd)
{
#ifdef CONFIG_BLOCK
- struct block_device *bdev;
struct super_block *sb;
struct filename *tmp = getname(special);
+ bool excl = false, thawed = false;
+ int error;
+ dev_t dev;
if (IS_ERR(tmp))
return ERR_CAST(tmp);
- bdev = lookup_bdev(tmp->name);
+ error = lookup_bdev(tmp->name, &dev);
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);
+ if (error)
+ return ERR_PTR(error);
+
+ if (quotactl_cmd_onoff(cmd)) {
+ excl = true;
+ thawed = true;
+ } else if (quotactl_cmd_write(cmd)) {
+ thawed = true;
+ }
+
+retry:
+ sb = user_get_super(dev, excl);
if (!sb)
return ERR_PTR(-ENODEV);
-
+ if (thawed && sb->s_writers.frozen != SB_UNFROZEN) {
+ if (excl)
+ up_write(&sb->s_umount);
+ else
+ up_read(&sb->s_umount);
+ wait_event(sb->s_writers.wait_unfrozen,
+ sb->s_writers.frozen == SB_UNFROZEN);
+ put_super(sb);
+ goto retry;
+ }
return sb;
+
#else
return ERR_PTR(-ENODEV);
#endif