Linux-Fsdevel Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH 0/7] quota: Allow quota support without quota files
@ 2019-11-04 10:51 Jan Kara
  2019-11-04 10:51 ` [PATCH 1/7] quota: Factor out setup of quota inode Jan Kara
                   ` (7 more replies)
  0 siblings, 8 replies; 10+ messages in thread
From: Jan Kara @ 2019-11-04 10:51 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: Sascha Hauer, Jan Kara

Hello,

this patch series refactors quota enabling / disabling code and allows
filesystems to implement quota support without providing quota files (ubifs
wants to do this).

Patches have passed testing with fstests, review is welcome.

								Honza

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/7] quota: Factor out setup of quota inode
  2019-11-04 10:51 [PATCH 0/7] quota: Allow quota support without quota files Jan Kara
@ 2019-11-04 10:51 ` Jan Kara
  2019-11-04 10:51 ` [PATCH 2/7] quota: Simplify dquot_resume() Jan Kara
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Jan Kara @ 2019-11-04 10:51 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: Sascha Hauer, Jan Kara

Factor out setting up of quota inode and eventual error cleanup from
vfs_load_quota_inode(). This will simplify situation for filesystems
that don't have any quota inodes.

Signed-off-by: Jan Kara <jack@suse.cz>
---
 fs/quota/dquot.c         | 108 +++++++++++++++++++++++++++++------------------
 include/linux/quotaops.h |   2 +
 2 files changed, 69 insertions(+), 41 deletions(-)

diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 6e826b454082..9e8eb6e71675 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -2299,28 +2299,60 @@ EXPORT_SYMBOL(dquot_quota_off);
  *	Turn quotas on on a device
  */
 
-/*
- * Helper function to turn quotas on when we already have the inode of
- * quota file and no quota information is loaded.
- */
-static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
+static int vfs_setup_quota_inode(struct inode *inode, int type)
+{
+	struct super_block *sb = inode->i_sb;
+	struct quota_info *dqopt = sb_dqopt(sb);
+
+	if (!S_ISREG(inode->i_mode))
+		return -EACCES;
+	if (IS_RDONLY(inode))
+		return -EROFS;
+	if (sb_has_quota_loaded(sb, type))
+		return -EBUSY;
+
+	dqopt->files[type] = igrab(inode);
+	if (!dqopt->files[type])
+		return -EIO;
+	if (!(dqopt->flags & DQUOT_QUOTA_SYS_FILE)) {
+		/* We don't want quota and atime on quota files (deadlocks
+		 * possible) Also nobody should write to the file - we use
+		 * special IO operations which ignore the immutable bit. */
+		inode_lock(inode);
+		inode->i_flags |= S_NOQUOTA;
+		inode_unlock(inode);
+		/*
+		 * When S_NOQUOTA is set, remove dquot references as no more
+		 * references can be added
+		 */
+		__dquot_drop(inode);
+	}
+	return 0;
+}
+
+static void vfs_cleanup_quota_inode(struct super_block *sb, int type)
+{
+	struct quota_info *dqopt = sb_dqopt(sb);
+	struct inode *inode = dqopt->files[type];
+
+	if (!(dqopt->flags & DQUOT_QUOTA_SYS_FILE)) {
+		inode_lock(inode);
+		inode->i_flags &= ~S_NOQUOTA;
+		inode_unlock(inode);
+	}
+	dqopt->files[type] = NULL;
+	iput(inode);
+}
+
+int dquot_load_quota_sb(struct super_block *sb, int type, int format_id,
 	unsigned int flags)
 {
 	struct quota_format_type *fmt = find_quota_format(format_id);
-	struct super_block *sb = inode->i_sb;
 	struct quota_info *dqopt = sb_dqopt(sb);
 	int error;
 
 	if (!fmt)
 		return -ESRCH;
-	if (!S_ISREG(inode->i_mode)) {
-		error = -EACCES;
-		goto out_fmt;
-	}
-	if (IS_RDONLY(inode)) {
-		error = -EROFS;
-		goto out_fmt;
-	}
 	if (!sb->s_op->quota_write || !sb->s_op->quota_read ||
 	    (type == PRJQUOTA && sb->dq_op->get_projid == NULL)) {
 		error = -EINVAL;
@@ -2352,27 +2384,9 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
 		invalidate_bdev(sb->s_bdev);
 	}
 
-	if (!(dqopt->flags & DQUOT_QUOTA_SYS_FILE)) {
-		/* We don't want quota and atime on quota files (deadlocks
-		 * possible) Also nobody should write to the file - we use
-		 * special IO operations which ignore the immutable bit. */
-		inode_lock(inode);
-		inode->i_flags |= S_NOQUOTA;
-		inode_unlock(inode);
-		/*
-		 * When S_NOQUOTA is set, remove dquot references as no more
-		 * references can be added
-		 */
-		__dquot_drop(inode);
-	}
-
-	error = -EIO;
-	dqopt->files[type] = igrab(inode);
-	if (!dqopt->files[type])
-		goto out_file_flags;
 	error = -EINVAL;
 	if (!fmt->qf_ops->check_quota_file(sb, type))
-		goto out_file_init;
+		goto out_fmt;
 
 	dqopt->ops[type] = fmt->qf_ops;
 	dqopt->info[type].dqi_format = fmt;
@@ -2380,7 +2394,7 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
 	INIT_LIST_HEAD(&dqopt->info[type].dqi_dirty_list);
 	error = dqopt->ops[type]->read_file_info(sb, type);
 	if (error < 0)
-		goto out_file_init;
+		goto out_fmt;
 	if (dqopt->flags & DQUOT_QUOTA_SYS_FILE) {
 		spin_lock(&dq_data_lock);
 		dqopt->info[type].dqi_flags |= DQF_SYS_FILE;
@@ -2395,18 +2409,30 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
 		dquot_disable(sb, type, flags);
 
 	return error;
-out_file_init:
-	dqopt->files[type] = NULL;
-	iput(inode);
-out_file_flags:
-	inode_lock(inode);
-	inode->i_flags &= ~S_NOQUOTA;
-	inode_unlock(inode);
 out_fmt:
 	put_quota_format(fmt);
 
 	return error;
 }
+EXPORT_SYMBOL(dquot_load_quota_sb);
+
+/*
+ * Helper function to turn quotas on when we already have the inode of
+ * quota file and no quota information is loaded.
+ */
+static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
+	unsigned int flags)
+{
+	int err;
+
+	err = vfs_setup_quota_inode(inode, type);
+	if (err < 0)
+		return err;
+	err = dquot_load_quota_sb(inode->i_sb, type, format_id, flags);
+	if (err < 0)
+		vfs_cleanup_quota_inode(inode->i_sb, type);
+	return err;
+}
 
 /* Reenable quotas on remount RW */
 int dquot_resume(struct super_block *sb, int type)
diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h
index 185d94829701..2625766bcfe7 100644
--- a/include/linux/quotaops.h
+++ b/include/linux/quotaops.h
@@ -89,6 +89,8 @@ int dquot_file_open(struct inode *inode, struct file *file);
 
 int dquot_enable(struct inode *inode, int type, int format_id,
 	unsigned int flags);
+int dquot_load_quota_sb(struct super_block *sb, int type, int format_id,
+	unsigned int flags);
 int dquot_quota_on(struct super_block *sb, int type, int format_id,
 	const struct path *path);
 int dquot_quota_on_mount(struct super_block *sb, char *qf_name,
-- 
2.16.4


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 2/7] quota: Simplify dquot_resume()
  2019-11-04 10:51 [PATCH 0/7] quota: Allow quota support without quota files Jan Kara
  2019-11-04 10:51 ` [PATCH 1/7] quota: Factor out setup of quota inode Jan Kara
@ 2019-11-04 10:51 ` Jan Kara
  2019-11-04 10:51 ` [PATCH 3/7] quota: Rename vfs_load_quota_inode() to dquot_load_quota_inode() Jan Kara
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Jan Kara @ 2019-11-04 10:51 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: Sascha Hauer, Jan Kara

We already have quota inode loaded when resuming quotas. Use
vfs_load_quota() to avoid some pointless churn with the quota inode.

Signed-off-by: Jan Kara <jack@suse.cz>
---
 fs/quota/dquot.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 9e8eb6e71675..ecdae91029ed 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -2438,7 +2438,6 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
 int dquot_resume(struct super_block *sb, int type)
 {
 	struct quota_info *dqopt = sb_dqopt(sb);
-	struct inode *inode;
 	int ret = 0, cnt;
 	unsigned int flags;
 
@@ -2452,8 +2451,6 @@ int dquot_resume(struct super_block *sb, int type)
 		if (!sb_has_quota_suspended(sb, cnt))
 			continue;
 
-		inode = dqopt->files[cnt];
-		dqopt->files[cnt] = NULL;
 		spin_lock(&dq_state_lock);
 		flags = dqopt->flags & dquot_state_flag(DQUOT_USAGE_ENABLED |
 							DQUOT_LIMITS_ENABLED,
@@ -2462,9 +2459,10 @@ int dquot_resume(struct super_block *sb, int type)
 		spin_unlock(&dq_state_lock);
 
 		flags = dquot_generic_flag(flags, cnt);
-		ret = vfs_load_quota_inode(inode, cnt,
-				dqopt->info[cnt].dqi_fmt_id, flags);
-		iput(inode);
+		ret = dquot_load_quota_sb(sb, cnt, dqopt->info[cnt].dqi_fmt_id,
+					  flags);
+		if (ret < 0)
+			vfs_cleanup_quota_inode(sb, type);
 	}
 
 	return ret;
-- 
2.16.4


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 3/7] quota: Rename vfs_load_quota_inode() to dquot_load_quota_inode()
  2019-11-04 10:51 [PATCH 0/7] quota: Allow quota support without quota files Jan Kara
  2019-11-04 10:51 ` [PATCH 1/7] quota: Factor out setup of quota inode Jan Kara
  2019-11-04 10:51 ` [PATCH 2/7] quota: Simplify dquot_resume() Jan Kara
@ 2019-11-04 10:51 ` Jan Kara
  2019-11-04 10:51 ` [PATCH 4/7] fs: Use dquot_load_quota_inode() from filesystems Jan Kara
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Jan Kara @ 2019-11-04 10:51 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: Sascha Hauer, Jan Kara

Rename vfs_load_quota_inode() to dquot_load_quota_inode() to be
consistent with naming of other functions used for enabling quota
accounting from filesystems. Also export the function and add some
sanity checks to assure filesystems are calling the function properly.

Signed-off-by: Jan Kara <jack@suse.cz>
---
 fs/quota/dquot.c         | 19 +++++++++++++------
 include/linux/quotaops.h |  2 ++
 2 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index ecdae91029ed..0ddcbce596f8 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -2351,6 +2351,12 @@ int dquot_load_quota_sb(struct super_block *sb, int type, int format_id,
 	struct quota_info *dqopt = sb_dqopt(sb);
 	int error;
 
+	/* Just unsuspend quotas? */
+	BUG_ON(flags & DQUOT_SUSPENDED);
+	/* s_umount should be held in exclusive mode */
+	if (WARN_ON_ONCE(down_read_trylock(&sb->s_umount)))
+		up_read(&sb->s_umount);
+
 	if (!fmt)
 		return -ESRCH;
 	if (!sb->s_op->quota_write || !sb->s_op->quota_read ||
@@ -2417,10 +2423,10 @@ int dquot_load_quota_sb(struct super_block *sb, int type, int format_id,
 EXPORT_SYMBOL(dquot_load_quota_sb);
 
 /*
- * Helper function to turn quotas on when we already have the inode of
- * quota file and no quota information is loaded.
+ * More powerful function for turning on quotas on given quota inode allowing
+ * setting of individual quota flags
  */
-static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
+int dquot_load_quota_inode(struct inode *inode, int type, int format_id,
 	unsigned int flags)
 {
 	int err;
@@ -2433,6 +2439,7 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
 		vfs_cleanup_quota_inode(inode->i_sb, type);
 	return err;
 }
+EXPORT_SYMBOL(dquot_load_quota_inode);
 
 /* Reenable quotas on remount RW */
 int dquot_resume(struct super_block *sb, int type)
@@ -2479,7 +2486,7 @@ int dquot_quota_on(struct super_block *sb, int type, int format_id,
 	if (path->dentry->d_sb != sb)
 		error = -EXDEV;
 	else
-		error = vfs_load_quota_inode(d_inode(path->dentry), type,
+		error = dquot_load_quota_inode(d_inode(path->dentry), type,
 					     format_id, DQUOT_USAGE_ENABLED |
 					     DQUOT_LIMITS_ENABLED);
 	return error;
@@ -2517,7 +2524,7 @@ int dquot_enable(struct inode *inode, int type, int format_id,
 		return 0;
 	}
 
-	return vfs_load_quota_inode(inode, type, format_id, flags);
+	return dquot_load_quota_inode(inode, type, format_id, flags);
 }
 EXPORT_SYMBOL(dquot_enable);
 
@@ -2542,7 +2549,7 @@ int dquot_quota_on_mount(struct super_block *sb, char *qf_name,
 
 	error = security_quota_on(dentry);
 	if (!error)
-		error = vfs_load_quota_inode(d_inode(dentry), type, format_id,
+		error = dquot_load_quota_inode(d_inode(dentry), type, format_id,
 				DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED);
 
 out:
diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h
index 2625766bcfe7..0ce9da5a1a93 100644
--- a/include/linux/quotaops.h
+++ b/include/linux/quotaops.h
@@ -91,6 +91,8 @@ int dquot_enable(struct inode *inode, int type, int format_id,
 	unsigned int flags);
 int dquot_load_quota_sb(struct super_block *sb, int type, int format_id,
 	unsigned int flags);
+int dquot_load_quota_inode(struct inode *inode, int type, int format_id,
+	unsigned int flags);
 int dquot_quota_on(struct super_block *sb, int type, int format_id,
 	const struct path *path);
 int dquot_quota_on_mount(struct super_block *sb, char *qf_name,
-- 
2.16.4


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 4/7] fs: Use dquot_load_quota_inode() from filesystems
  2019-11-04 10:51 [PATCH 0/7] quota: Allow quota support without quota files Jan Kara
                   ` (2 preceding siblings ...)
  2019-11-04 10:51 ` [PATCH 3/7] quota: Rename vfs_load_quota_inode() to dquot_load_quota_inode() Jan Kara
@ 2019-11-04 10:51 ` Jan Kara
  2019-11-04 10:51 ` [PATCH 5/7] quota: Drop dquot_enable() Jan Kara
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Jan Kara @ 2019-11-04 10:51 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: Sascha Hauer, Jan Kara

Use dquot_load_quota_inode from filesystems instead of dquot_enable().
In all three cases we want to load quota inode and never use the
function to update quota flags.

Signed-off-by: Jan Kara <jack@suse.cz>
---
 fs/ext4/super.c  | 2 +-
 fs/f2fs/super.c  | 2 +-
 fs/ocfs2/super.c | 4 ++--
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index dd654e53ba3d..1b947c95eff2 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -5835,7 +5835,7 @@ static int ext4_quota_enable(struct super_block *sb, int type, int format_id,
 	/* Don't account quota for quota files to avoid recursion */
 	qf_inode->i_flags |= S_NOQUOTA;
 	lockdep_set_quota_inode(qf_inode, I_DATA_SEM_QUOTA);
-	err = dquot_enable(qf_inode, type, format_id, flags);
+	err = dquot_load_quota_inode(qf_inode, type, format_id, flags);
 	if (err)
 		lockdep_set_quota_inode(qf_inode, I_DATA_SEM_NORMAL);
 	iput(qf_inode);
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 1443cee15863..91745d5b718d 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -1932,7 +1932,7 @@ static int f2fs_quota_enable(struct super_block *sb, int type, int format_id,
 
 	/* Don't account quota for quota files to avoid recursion */
 	qf_inode->i_flags |= S_NOQUOTA;
-	err = dquot_enable(qf_inode, type, format_id, flags);
+	err = dquot_load_quota_inode(qf_inode, type, format_id, flags);
 	iput(qf_inode);
 	return err;
 }
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index c81e86c62380..05dd68ade293 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -926,8 +926,8 @@ static int ocfs2_enable_quotas(struct ocfs2_super *osb)
 			status = -ENOENT;
 			goto out_quota_off;
 		}
-		status = dquot_enable(inode[type], type, QFMT_OCFS2,
-				      DQUOT_USAGE_ENABLED);
+		status = dquot_load_quota_inode(inode[type], type, QFMT_OCFS2,
+						DQUOT_USAGE_ENABLED);
 		if (status < 0)
 			goto out_quota_off;
 	}
-- 
2.16.4


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 5/7] quota: Drop dquot_enable()
  2019-11-04 10:51 [PATCH 0/7] quota: Allow quota support without quota files Jan Kara
                   ` (3 preceding siblings ...)
  2019-11-04 10:51 ` [PATCH 4/7] fs: Use dquot_load_quota_inode() from filesystems Jan Kara
@ 2019-11-04 10:51 ` Jan Kara
  2019-11-04 10:51 ` [PATCH 6/7] quota: Make dquot_disable() work without quota inodes Jan Kara
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Jan Kara @ 2019-11-04 10:51 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: Sascha Hauer, Jan Kara

Now dquot_enable() has only two internal callers and both of them just
need to update quota flags and don't need most of checks. Just drop
dquot_enable() and fold necessary functionality into the two calling
places.

Signed-off-by: Jan Kara <jack@suse.cz>
---
 fs/quota/dquot.c         | 61 +++++++++++++-----------------------------------
 include/linux/quotaops.h |  2 --
 2 files changed, 16 insertions(+), 47 deletions(-)

diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 0ddcbce596f8..3e4cf0d10955 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -2493,41 +2493,6 @@ int dquot_quota_on(struct super_block *sb, int type, int format_id,
 }
 EXPORT_SYMBOL(dquot_quota_on);
 
-/*
- * More powerful function for turning on quotas allowing setting
- * of individual quota flags
- */
-int dquot_enable(struct inode *inode, int type, int format_id,
-		 unsigned int flags)
-{
-	struct super_block *sb = inode->i_sb;
-
-	/* Just unsuspend quotas? */
-	BUG_ON(flags & DQUOT_SUSPENDED);
-	/* s_umount should be held in exclusive mode */
-	if (WARN_ON_ONCE(down_read_trylock(&sb->s_umount)))
-		up_read(&sb->s_umount);
-
-	if (!flags)
-		return 0;
-	/* Just updating flags needed? */
-	if (sb_has_quota_loaded(sb, type)) {
-		if (flags & DQUOT_USAGE_ENABLED &&
-		    sb_has_quota_usage_enabled(sb, type))
-			return -EBUSY;
-		if (flags & DQUOT_LIMITS_ENABLED &&
-		    sb_has_quota_limits_enabled(sb, type))
-			return -EBUSY;
-		spin_lock(&dq_state_lock);
-		sb_dqopt(sb)->flags |= dquot_state_flag(flags, type);
-		spin_unlock(&dq_state_lock);
-		return 0;
-	}
-
-	return dquot_load_quota_inode(inode, type, format_id, flags);
-}
-EXPORT_SYMBOL(dquot_enable);
-
 /*
  * This function is used when filesystem needs to initialize quotas
  * during mount time.
@@ -2574,13 +2539,17 @@ static int dquot_quota_enable(struct super_block *sb, unsigned int flags)
 		if (!(flags & qtype_enforce_flag(type)))
 			continue;
 		/* Can't enforce without accounting */
-		if (!sb_has_quota_usage_enabled(sb, type))
-			return -EINVAL;
-		ret = dquot_enable(dqopt->files[type], type,
-				   dqopt->info[type].dqi_fmt_id,
-				   DQUOT_LIMITS_ENABLED);
-		if (ret < 0)
+		if (!sb_has_quota_usage_enabled(sb, type)) {
+			ret = -EINVAL;
+			goto out_err;
+		}
+		if (sb_has_quota_limits_enabled(sb, type)) {
+			ret = -EBUSY;
 			goto out_err;
+		}
+		spin_lock(&dq_state_lock);
+		dqopt->flags |= dquot_state_flag(DQUOT_LIMITS_ENABLED, type);
+		spin_unlock(&dq_state_lock);
 	}
 	return 0;
 out_err:
@@ -2630,10 +2599,12 @@ static int dquot_quota_disable(struct super_block *sb, unsigned int flags)
 out_err:
 	/* Backout enforcement disabling we already did */
 	for (type--; type >= 0; type--)  {
-		if (flags & qtype_enforce_flag(type))
-			dquot_enable(dqopt->files[type], type,
-				     dqopt->info[type].dqi_fmt_id,
-				     DQUOT_LIMITS_ENABLED);
+		if (flags & qtype_enforce_flag(type)) {
+			spin_lock(&dq_state_lock);
+			dqopt->flags |=
+				dquot_state_flag(DQUOT_LIMITS_ENABLED, type);
+			spin_unlock(&dq_state_lock);
+		}
 	}
 	return ret;
 }
diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h
index 0ce9da5a1a93..6b8ebc8d715e 100644
--- a/include/linux/quotaops.h
+++ b/include/linux/quotaops.h
@@ -87,8 +87,6 @@ int dquot_mark_dquot_dirty(struct dquot *dquot);
 
 int dquot_file_open(struct inode *inode, struct file *file);
 
-int dquot_enable(struct inode *inode, int type, int format_id,
-	unsigned int flags);
 int dquot_load_quota_sb(struct super_block *sb, int type, int format_id,
 	unsigned int flags);
 int dquot_load_quota_inode(struct inode *inode, int type, int format_id,
-- 
2.16.4


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 6/7] quota: Make dquot_disable() work without quota inodes
  2019-11-04 10:51 [PATCH 0/7] quota: Allow quota support without quota files Jan Kara
                   ` (4 preceding siblings ...)
  2019-11-04 10:51 ` [PATCH 5/7] quota: Drop dquot_enable() Jan Kara
@ 2019-11-04 10:51 ` Jan Kara
  2019-11-04 10:51 ` [PATCH 7/7] quota: Handle quotas without quota inodes in dquot_get_state() Jan Kara
  2019-11-06  8:17 ` [PATCH 0/7] quota: Allow quota support without quota files Sascha Hauer
  7 siblings, 0 replies; 10+ messages in thread
From: Jan Kara @ 2019-11-04 10:51 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: Sascha Hauer, Jan Kara

Quota on and quota off are protected by s_umount semaphore held in
exclusive mode since commit 7d6cd73d33b6 "quota: Hold s_umount in
exclusive mode when enabling / disabling quotas". This makes it
impossible for dquot_disable() to race with other enabling or disabling
of quotas. Simplify the cleanup done by dquot_disable() based on this
fact and also remove some stale comments. As a bonus this cleanup makes
dquot_disable() properly handle a case when there are no quota inodes.

Signed-off-by: Jan Kara <jack@suse.cz>
---
 fs/quota/dquot.c | 73 ++++++++++++++++++++++----------------------------------
 1 file changed, 29 insertions(+), 44 deletions(-)

diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 3e4cf0d10955..4c3da4ea31bc 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -2162,14 +2162,29 @@ int dquot_file_open(struct inode *inode, struct file *file)
 }
 EXPORT_SYMBOL(dquot_file_open);
 
+static void vfs_cleanup_quota_inode(struct super_block *sb, int type)
+{
+	struct quota_info *dqopt = sb_dqopt(sb);
+	struct inode *inode = dqopt->files[type];
+
+	if (!inode)
+		return;
+	if (!(dqopt->flags & DQUOT_QUOTA_SYS_FILE)) {
+		inode_lock(inode);
+		inode->i_flags &= ~S_NOQUOTA;
+		inode_unlock(inode);
+	}
+	dqopt->files[type] = NULL;
+	iput(inode);
+}
+
 /*
  * Turn quota off on a device. type == -1 ==> quotaoff for all types (umount)
  */
 int dquot_disable(struct super_block *sb, int type, unsigned int flags)
 {
-	int cnt, ret = 0;
+	int cnt;
 	struct quota_info *dqopt = sb_dqopt(sb);
-	struct inode *toputinode[MAXQUOTAS];
 
 	/* s_umount should be held in exclusive mode */
 	if (WARN_ON_ONCE(down_read_trylock(&sb->s_umount)))
@@ -2191,7 +2206,6 @@ int dquot_disable(struct super_block *sb, int type, unsigned int flags)
 		return 0;
 
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-		toputinode[cnt] = NULL;
 		if (type != -1 && cnt != type)
 			continue;
 		if (!sb_has_quota_loaded(sb, cnt))
@@ -2211,8 +2225,7 @@ int dquot_disable(struct super_block *sb, int type, unsigned int flags)
 				dqopt->flags &=	~dquot_state_flag(
 							DQUOT_SUSPENDED, cnt);
 				spin_unlock(&dq_state_lock);
-				iput(dqopt->files[cnt]);
-				dqopt->files[cnt] = NULL;
+				vfs_cleanup_quota_inode(sb, cnt);
 				continue;
 			}
 			spin_unlock(&dq_state_lock);
@@ -2234,10 +2247,6 @@ int dquot_disable(struct super_block *sb, int type, unsigned int flags)
 		if (dqopt->ops[cnt]->free_file_info)
 			dqopt->ops[cnt]->free_file_info(sb, cnt);
 		put_quota_format(dqopt->info[cnt].dqi_format);
-
-		toputinode[cnt] = dqopt->files[cnt];
-		if (!sb_has_quota_loaded(sb, cnt))
-			dqopt->files[cnt] = NULL;
 		dqopt->info[cnt].dqi_flags = 0;
 		dqopt->info[cnt].dqi_igrace = 0;
 		dqopt->info[cnt].dqi_bgrace = 0;
@@ -2259,32 +2268,22 @@ int dquot_disable(struct super_block *sb, int type, unsigned int flags)
 	 * must also discard the blockdev buffers so that we see the
 	 * changes done by userspace on the next quotaon() */
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
-		/* This can happen when suspending quotas on remount-ro... */
-		if (toputinode[cnt] && !sb_has_quota_loaded(sb, cnt)) {
-			inode_lock(toputinode[cnt]);
-			toputinode[cnt]->i_flags &= ~S_NOQUOTA;
-			truncate_inode_pages(&toputinode[cnt]->i_data, 0);
-			inode_unlock(toputinode[cnt]);
-			mark_inode_dirty_sync(toputinode[cnt]);
+		if (!sb_has_quota_loaded(sb, cnt) && dqopt->files[cnt]) {
+			inode_lock(dqopt->files[cnt]);
+			truncate_inode_pages(&dqopt->files[cnt]->i_data, 0);
+			inode_unlock(dqopt->files[cnt]);
 		}
 	if (sb->s_bdev)
 		invalidate_bdev(sb->s_bdev);
 put_inodes:
+	/* We are done when suspending quotas */
+	if (flags & DQUOT_SUSPENDED)
+		return 0;
+
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
-		if (toputinode[cnt]) {
-			/* On remount RO, we keep the inode pointer so that we
-			 * can reenable quota on the subsequent remount RW. We
-			 * have to check 'flags' variable and not use sb_has_
-			 * function because another quotaon / quotaoff could
-			 * change global state before we got here. We refuse
-			 * to suspend quotas when there is pending delete on
-			 * the quota file... */
-			if (!(flags & DQUOT_SUSPENDED))
-				iput(toputinode[cnt]);
-			else if (!toputinode[cnt]->i_nlink)
-				ret = -EBUSY;
-		}
-	return ret;
+		if (!sb_has_quota_loaded(sb, cnt))
+			vfs_cleanup_quota_inode(sb, cnt);
+	return 0;
 }
 EXPORT_SYMBOL(dquot_disable);
 
@@ -2330,20 +2329,6 @@ static int vfs_setup_quota_inode(struct inode *inode, int type)
 	return 0;
 }
 
-static void vfs_cleanup_quota_inode(struct super_block *sb, int type)
-{
-	struct quota_info *dqopt = sb_dqopt(sb);
-	struct inode *inode = dqopt->files[type];
-
-	if (!(dqopt->flags & DQUOT_QUOTA_SYS_FILE)) {
-		inode_lock(inode);
-		inode->i_flags &= ~S_NOQUOTA;
-		inode_unlock(inode);
-	}
-	dqopt->files[type] = NULL;
-	iput(inode);
-}
-
 int dquot_load_quota_sb(struct super_block *sb, int type, int format_id,
 	unsigned int flags)
 {
-- 
2.16.4


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 7/7] quota: Handle quotas without quota inodes in dquot_get_state()
  2019-11-04 10:51 [PATCH 0/7] quota: Allow quota support without quota files Jan Kara
                   ` (5 preceding siblings ...)
  2019-11-04 10:51 ` [PATCH 6/7] quota: Make dquot_disable() work without quota inodes Jan Kara
@ 2019-11-04 10:51 ` Jan Kara
  2019-11-06  8:17 ` [PATCH 0/7] quota: Allow quota support without quota files Sascha Hauer
  7 siblings, 0 replies; 10+ messages in thread
From: Jan Kara @ 2019-11-04 10:51 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: Sascha Hauer, Jan Kara

Make dquot_get_state() gracefully handle a situation when there are no
quota files present even though quotas are enabled.

Signed-off-by: Jan Kara <jack@suse.cz>
---
 fs/quota/dquot.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 4c3da4ea31bc..a69a657209a6 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -2787,8 +2787,10 @@ int dquot_get_state(struct super_block *sb, struct qc_state *state)
 			tstate->flags |= QCI_LIMITS_ENFORCED;
 		tstate->spc_timelimit = mi->dqi_bgrace;
 		tstate->ino_timelimit = mi->dqi_igrace;
-		tstate->ino = dqopt->files[type]->i_ino;
-		tstate->blocks = dqopt->files[type]->i_blocks;
+		if (dqopt->files[type]) {
+			tstate->ino = dqopt->files[type]->i_ino;
+			tstate->blocks = dqopt->files[type]->i_blocks;
+		}
 		tstate->nextents = 1;	/* We don't know... */
 		spin_unlock(&dq_data_lock);
 	}
-- 
2.16.4


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 0/7] quota: Allow quota support without quota files
  2019-11-04 10:51 [PATCH 0/7] quota: Allow quota support without quota files Jan Kara
                   ` (6 preceding siblings ...)
  2019-11-04 10:51 ` [PATCH 7/7] quota: Handle quotas without quota inodes in dquot_get_state() Jan Kara
@ 2019-11-06  8:17 ` Sascha Hauer
  2019-11-06  9:59   ` Jan Kara
  7 siblings, 1 reply; 10+ messages in thread
From: Sascha Hauer @ 2019-11-06  8:17 UTC (permalink / raw)
  To: Jan Kara; +Cc: linux-fsdevel

Hi Jan,

On Mon, Nov 04, 2019 at 11:51:48AM +0100, Jan Kara wrote:
> Hello,
> 
> this patch series refactors quota enabling / disabling code and allows
> filesystems to implement quota support without providing quota files (ubifs
> wants to do this).
> 
> Patches have passed testing with fstests, review is welcome.

Thank you for creating this series. I can confirm my UBIFS quota patches
are working fine on top of this series. I'll send an updated UBIFS quota
series shortly.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 0/7] quota: Allow quota support without quota files
  2019-11-06  8:17 ` [PATCH 0/7] quota: Allow quota support without quota files Sascha Hauer
@ 2019-11-06  9:59   ` Jan Kara
  0 siblings, 0 replies; 10+ messages in thread
From: Jan Kara @ 2019-11-06  9:59 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: Jan Kara, linux-fsdevel

On Wed 06-11-19 09:17:52, Sascha Hauer wrote:
> Hi Jan,
> 
> On Mon, Nov 04, 2019 at 11:51:48AM +0100, Jan Kara wrote:
> > Hello,
> > 
> > this patch series refactors quota enabling / disabling code and allows
> > filesystems to implement quota support without providing quota files (ubifs
> > wants to do this).
> > 
> > Patches have passed testing with fstests, review is welcome.
> 
> Thank you for creating this series. I can confirm my UBIFS quota patches
> are working fine on top of this series. I'll send an updated UBIFS quota
> series shortly.

Thanks for testing! I've pushed the series to linux-next so that it gets
wider exposure and will send it to Linus in the next maintenance window.

								Honza
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, back to index

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-04 10:51 [PATCH 0/7] quota: Allow quota support without quota files Jan Kara
2019-11-04 10:51 ` [PATCH 1/7] quota: Factor out setup of quota inode Jan Kara
2019-11-04 10:51 ` [PATCH 2/7] quota: Simplify dquot_resume() Jan Kara
2019-11-04 10:51 ` [PATCH 3/7] quota: Rename vfs_load_quota_inode() to dquot_load_quota_inode() Jan Kara
2019-11-04 10:51 ` [PATCH 4/7] fs: Use dquot_load_quota_inode() from filesystems Jan Kara
2019-11-04 10:51 ` [PATCH 5/7] quota: Drop dquot_enable() Jan Kara
2019-11-04 10:51 ` [PATCH 6/7] quota: Make dquot_disable() work without quota inodes Jan Kara
2019-11-04 10:51 ` [PATCH 7/7] quota: Handle quotas without quota inodes in dquot_get_state() Jan Kara
2019-11-06  8:17 ` [PATCH 0/7] quota: Allow quota support without quota files Sascha Hauer
2019-11-06  9:59   ` Jan Kara

Linux-Fsdevel Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-fsdevel/0 linux-fsdevel/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-fsdevel linux-fsdevel/ https://lore.kernel.org/linux-fsdevel \
		linux-fsdevel@vger.kernel.org
	public-inbox-index linux-fsdevel

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-fsdevel


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git