[04/11] fs, quota: introduce wait_super_thawed() to wait until a superblock is thawed
diff mbox series

Message ID 20190814121834.13983-5-s.hauer@pengutronix.de
State Changes Requested
Headers show
Series
  • Add quota support to UBIFS
Related show

Commit Message

Sascha Hauer Aug. 14, 2019, 12:18 p.m. UTC
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(-)

Comments

Al Viro Aug. 14, 2019, 11:35 p.m. UTC | #1
On Wed, Aug 14, 2019 at 02:18:27PM +0200, Sascha Hauer wrote:
> 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.

> + *	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.
> + */

Never expose anything like that - if locking rules depend upon the flags,
it MUST NOT be anything beyond a static helper.  I'm serious - that kind
of stuff ends up with trouble again and again.  Just don't.

Patch
diff mbox series

diff --git a/fs/quota/quota.c b/fs/quota/quota.c
index cb13fb76dbee..64a212576a72 100644
--- a/fs/quota/quota.c
+++ b/fs/quota/quota.c
@@ -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);
diff --git a/fs/super.c b/fs/super.c
index f85d1ea194ae..13380ffcbd8d 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -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
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 997a530ff4e9..59d9ea62942a 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -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 *);