mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v2 0/2] ceph: support cross-quota-tree renames
@ 2020-04-07 10:30 Luis Henriques
  2020-04-07 10:30 ` [PATCH v2 1/2] ceph: normalize 'delta' parameter usage in check_quota_exceeded Luis Henriques
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Luis Henriques @ 2020-04-07 10:30 UTC (permalink / raw)
  To: Jeff Layton, Sage Weil, Ilya Dryomov, Gregory Farnum, Zheng Yan
  Cc: Frank Schilder, ceph-devel, linux-kernel, Luis Henriques

Hi!

The following patches will make the cephfs kernel client behave the same
way as the fuse client when doing renames across different quota realms.

Changes since v1:

- Dropped 'old == new' check in ceph_quota_check_rename() and added back
  optimization in ceph_rename(), to only check realms if old_dir and
  new_dir are different.

Luis Henriques (2):
  ceph: normalize 'delta' parameter usage in check_quota_exceeded
  ceph: allow rename operation under different quota realms

 fs/ceph/dir.c   |  9 +++----
 fs/ceph/quota.c | 62 +++++++++++++++++++++++++++++++++++++++++++++----
 fs/ceph/super.h |  3 ++-
 3 files changed, 65 insertions(+), 9 deletions(-)


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

* [PATCH v2 1/2] ceph: normalize 'delta' parameter usage in check_quota_exceeded
  2020-04-07 10:30 [PATCH v2 0/2] ceph: support cross-quota-tree renames Luis Henriques
@ 2020-04-07 10:30 ` Luis Henriques
  2020-04-07 10:30 ` [PATCH v2 2/2] ceph: allow rename operation under different quota realms Luis Henriques
  2020-04-08 14:31 ` [PATCH v2 0/2] ceph: support cross-quota-tree renames Jeff Layton
  2 siblings, 0 replies; 6+ messages in thread
From: Luis Henriques @ 2020-04-07 10:30 UTC (permalink / raw)
  To: Jeff Layton, Sage Weil, Ilya Dryomov, Gregory Farnum, Zheng Yan
  Cc: Frank Schilder, ceph-devel, linux-kernel, Luis Henriques

Function check_quota_exceeded() uses delta parameter only for the
QUOTA_CHECK_MAX_BYTES_OP operation.  Using this parameter also for
MAX_FILES will makes the code cleaner and will be required to support
cross-quota-tree renames.

Signed-off-by: Luis Henriques <lhenriques@suse.com>
---
 fs/ceph/quota.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/fs/ceph/quota.c b/fs/ceph/quota.c
index de56dee60540..c5c8050f0f99 100644
--- a/fs/ceph/quota.c
+++ b/fs/ceph/quota.c
@@ -361,8 +361,6 @@ static bool check_quota_exceeded(struct inode *inode, enum quota_check_op op,
 		spin_unlock(&ci->i_ceph_lock);
 		switch (op) {
 		case QUOTA_CHECK_MAX_FILES_OP:
-			exceeded = (max && (rvalue >= max));
-			break;
 		case QUOTA_CHECK_MAX_BYTES_OP:
 			exceeded = (max && (rvalue + delta > max));
 			break;
@@ -417,7 +415,7 @@ bool ceph_quota_is_max_files_exceeded(struct inode *inode)
 
 	WARN_ON(!S_ISDIR(inode->i_mode));
 
-	return check_quota_exceeded(inode, QUOTA_CHECK_MAX_FILES_OP, 0);
+	return check_quota_exceeded(inode, QUOTA_CHECK_MAX_FILES_OP, 1);
 }
 
 /*

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

* [PATCH v2 2/2] ceph: allow rename operation under different quota realms
  2020-04-07 10:30 [PATCH v2 0/2] ceph: support cross-quota-tree renames Luis Henriques
  2020-04-07 10:30 ` [PATCH v2 1/2] ceph: normalize 'delta' parameter usage in check_quota_exceeded Luis Henriques
@ 2020-04-07 10:30 ` Luis Henriques
  2020-04-07 22:57   ` Jeff Layton
  2020-04-08 14:31 ` [PATCH v2 0/2] ceph: support cross-quota-tree renames Jeff Layton
  2 siblings, 1 reply; 6+ messages in thread
From: Luis Henriques @ 2020-04-07 10:30 UTC (permalink / raw)
  To: Jeff Layton, Sage Weil, Ilya Dryomov, Gregory Farnum, Zheng Yan
  Cc: Frank Schilder, ceph-devel, linux-kernel, Luis Henriques

Returning -EXDEV when trying to 'mv' files/directories from different
quota realms results in copy+unlink operations instead of the faster
CEPH_MDS_OP_RENAME.  This will occur even when there aren't any quotas
set in the destination directory, or if there's enough space left for
the new file(s).

This patch adds a new helper function to be called on rename operations
which will allow these operations if they can be executed.  This patch
mimics userland fuse client commit b8954e5734b3 ("client:
optimize rename operation under different quota root").

Since ceph_quota_is_same_realm() is now called only from this new
helper, make it static.

URL: https://tracker.ceph.com/issues/44791
Signed-off-by: Luis Henriques <lhenriques@suse.com>
---
 fs/ceph/dir.c   |  9 ++++----
 fs/ceph/quota.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++-
 fs/ceph/super.h |  3 ++-
 3 files changed, 64 insertions(+), 6 deletions(-)

diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
index d0cd0aba5843..23f0345611a3 100644
--- a/fs/ceph/dir.c
+++ b/fs/ceph/dir.c
@@ -1099,11 +1099,12 @@ static int ceph_rename(struct inode *old_dir, struct dentry *old_dentry,
 			op = CEPH_MDS_OP_RENAMESNAP;
 		else
 			return -EROFS;
+	} else if (old_dir != new_dir) {
+		err = ceph_quota_check_rename(mdsc, d_inode(old_dentry),
+					      new_dir);
+		if (err)
+			return err;
 	}
-	/* don't allow cross-quota renames */
-	if ((old_dir != new_dir) &&
-	    (!ceph_quota_is_same_realm(old_dir, new_dir)))
-		return -EXDEV;
 
 	dout("rename dir %p dentry %p to dir %p dentry %p\n",
 	     old_dir, old_dentry, new_dir, new_dentry);
diff --git a/fs/ceph/quota.c b/fs/ceph/quota.c
index c5c8050f0f99..9e82704a9f7b 100644
--- a/fs/ceph/quota.c
+++ b/fs/ceph/quota.c
@@ -264,7 +264,7 @@ static struct ceph_snap_realm *get_quota_realm(struct ceph_mds_client *mdsc,
 	return NULL;
 }
 
-bool ceph_quota_is_same_realm(struct inode *old, struct inode *new)
+static bool ceph_quota_is_same_realm(struct inode *old, struct inode *new)
 {
 	struct ceph_mds_client *mdsc = ceph_inode_to_client(old)->mdsc;
 	struct ceph_snap_realm *old_realm, *new_realm;
@@ -516,3 +516,59 @@ bool ceph_quota_update_statfs(struct ceph_fs_client *fsc, struct kstatfs *buf)
 	return is_updated;
 }
 
+/*
+ * ceph_quota_check_rename - check if a rename can be executed
+ * @mdsc:	MDS client instance
+ * @old:	inode to be copied
+ * @new:	destination inode (directory)
+ *
+ * This function verifies if a rename (e.g. moving a file or directory) can be
+ * executed.  It forces an rstat update in the @new target directory (and in the
+ * source @old as well, if it's a directory).  The actual check is done both for
+ * max_files and max_bytes.
+ *
+ * This function returns 0 if it's OK to do the rename, or, if quotas are
+ * exceeded, -EXDEV (if @old is a directory) or -EDQUOT.
+ */
+int ceph_quota_check_rename(struct ceph_mds_client *mdsc,
+			    struct inode *old, struct inode *new)
+{
+	struct ceph_inode_info *ci_old = ceph_inode(old);
+	int ret = 0;
+
+	if (ceph_quota_is_same_realm(old, new))
+		return 0;
+
+	/*
+	 * Get the latest rstat for target directory (and for source, if a
+	 * directory)
+	 */
+	ret = ceph_do_getattr(new, CEPH_STAT_RSTAT, false);
+	if (ret)
+		return ret;
+
+	if (S_ISDIR(old->i_mode)) {
+		ret = ceph_do_getattr(old, CEPH_STAT_RSTAT, false);
+		if (ret)
+			return ret;
+		ret = check_quota_exceeded(new, QUOTA_CHECK_MAX_BYTES_OP,
+					   ci_old->i_rbytes);
+		if (!ret)
+			ret = check_quota_exceeded(new,
+						   QUOTA_CHECK_MAX_FILES_OP,
+						   ci_old->i_rfiles +
+						   ci_old->i_rsubdirs);
+		if (ret)
+			ret = -EXDEV;
+	} else {
+		ret = check_quota_exceeded(new, QUOTA_CHECK_MAX_BYTES_OP,
+					   i_size_read(old));
+		if (!ret)
+			ret = check_quota_exceeded(new,
+						   QUOTA_CHECK_MAX_FILES_OP, 1);
+		if (ret)
+			ret = -EDQUOT;
+	}
+
+	return ret;
+}
diff --git a/fs/ceph/super.h b/fs/ceph/super.h
index 037cdfb2ad4f..d5853831a6b5 100644
--- a/fs/ceph/super.h
+++ b/fs/ceph/super.h
@@ -1175,13 +1175,14 @@ extern void ceph_handle_quota(struct ceph_mds_client *mdsc,
 			      struct ceph_mds_session *session,
 			      struct ceph_msg *msg);
 extern bool ceph_quota_is_max_files_exceeded(struct inode *inode);
-extern bool ceph_quota_is_same_realm(struct inode *old, struct inode *new);
 extern bool ceph_quota_is_max_bytes_exceeded(struct inode *inode,
 					     loff_t newlen);
 extern bool ceph_quota_is_max_bytes_approaching(struct inode *inode,
 						loff_t newlen);
 extern bool ceph_quota_update_statfs(struct ceph_fs_client *fsc,
 				     struct kstatfs *buf);
+extern int ceph_quota_check_rename(struct ceph_mds_client *mdsc,
+				   struct inode *old, struct inode *new);
 extern void ceph_cleanup_quotarealms_inodes(struct ceph_mds_client *mdsc);
 
 #endif /* _FS_CEPH_SUPER_H */

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

* Re: [PATCH v2 2/2] ceph: allow rename operation under different quota realms
  2020-04-07 10:30 ` [PATCH v2 2/2] ceph: allow rename operation under different quota realms Luis Henriques
@ 2020-04-07 22:57   ` Jeff Layton
  2020-04-08  3:10     ` Yan, Zheng
  0 siblings, 1 reply; 6+ messages in thread
From: Jeff Layton @ 2020-04-07 22:57 UTC (permalink / raw)
  To: Luis Henriques, Sage Weil, Ilya Dryomov, Gregory Farnum, Zheng Yan
  Cc: Frank Schilder, ceph-devel, linux-kernel

On Tue, 2020-04-07 at 11:30 +0100, Luis Henriques wrote:
> Returning -EXDEV when trying to 'mv' files/directories from different
> quota realms results in copy+unlink operations instead of the faster
> CEPH_MDS_OP_RENAME.  This will occur even when there aren't any quotas
> set in the destination directory, or if there's enough space left for
> the new file(s).
> 
> This patch adds a new helper function to be called on rename operations
> which will allow these operations if they can be executed.  This patch
> mimics userland fuse client commit b8954e5734b3 ("client:
> optimize rename operation under different quota root").
> 
> Since ceph_quota_is_same_realm() is now called only from this new
> helper, make it static.
> 
> URL: https://tracker.ceph.com/issues/44791
> Signed-off-by: Luis Henriques <lhenriques@suse.com>
> ---
>  fs/ceph/dir.c   |  9 ++++----
>  fs/ceph/quota.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++-
>  fs/ceph/super.h |  3 ++-
>  3 files changed, 64 insertions(+), 6 deletions(-)
> 
> diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
> index d0cd0aba5843..23f0345611a3 100644
> --- a/fs/ceph/dir.c
> +++ b/fs/ceph/dir.c
> @@ -1099,11 +1099,12 @@ static int ceph_rename(struct inode *old_dir, struct dentry *old_dentry,
>  			op = CEPH_MDS_OP_RENAMESNAP;
>  		else
>  			return -EROFS;
> +	} else if (old_dir != new_dir) {
> +		err = ceph_quota_check_rename(mdsc, d_inode(old_dentry),
> +					      new_dir);
> +		if (err)
> +			return err;
>  	}
> -	/* don't allow cross-quota renames */
> -	if ((old_dir != new_dir) &&
> -	    (!ceph_quota_is_same_realm(old_dir, new_dir)))
> -		return -EXDEV;
>  
>  	dout("rename dir %p dentry %p to dir %p dentry %p\n",
>  	     old_dir, old_dentry, new_dir, new_dentry);
> diff --git a/fs/ceph/quota.c b/fs/ceph/quota.c
> index c5c8050f0f99..9e82704a9f7b 100644
> --- a/fs/ceph/quota.c
> +++ b/fs/ceph/quota.c
> @@ -264,7 +264,7 @@ static struct ceph_snap_realm *get_quota_realm(struct ceph_mds_client *mdsc,
>  	return NULL;
>  }
>  
> -bool ceph_quota_is_same_realm(struct inode *old, struct inode *new)
> +static bool ceph_quota_is_same_realm(struct inode *old, struct inode *new)
>  {
>  	struct ceph_mds_client *mdsc = ceph_inode_to_client(old)->mdsc;
>  	struct ceph_snap_realm *old_realm, *new_realm;
> @@ -516,3 +516,59 @@ bool ceph_quota_update_statfs(struct ceph_fs_client *fsc, struct kstatfs *buf)
>  	return is_updated;
>  }
>  
> +/*
> + * ceph_quota_check_rename - check if a rename can be executed
> + * @mdsc:	MDS client instance
> + * @old:	inode to be copied
> + * @new:	destination inode (directory)
> + *
> + * This function verifies if a rename (e.g. moving a file or directory) can be
> + * executed.  It forces an rstat update in the @new target directory (and in the
> + * source @old as well, if it's a directory).  The actual check is done both for
> + * max_files and max_bytes.
> + *
> + * This function returns 0 if it's OK to do the rename, or, if quotas are
> + * exceeded, -EXDEV (if @old is a directory) or -EDQUOT.
> + */
> +int ceph_quota_check_rename(struct ceph_mds_client *mdsc,
> +			    struct inode *old, struct inode *new)
> +{
> +	struct ceph_inode_info *ci_old = ceph_inode(old);
> +	int ret = 0;
> +
> +	if (ceph_quota_is_same_realm(old, new))
> +		return 0;
> +
> +	/*
> +	 * Get the latest rstat for target directory (and for source, if a
> +	 * directory)
> +	 */
> +	ret = ceph_do_getattr(new, CEPH_STAT_RSTAT, false);
> +	if (ret)
> +		return ret;
> +
> +	if (S_ISDIR(old->i_mode)) {
> +		ret = ceph_do_getattr(old, CEPH_STAT_RSTAT, false);
> +		if (ret)
> +			return ret;
> +		ret = check_quota_exceeded(new, QUOTA_CHECK_MAX_BYTES_OP,
> +					   ci_old->i_rbytes);
> +		if (!ret)
> +			ret = check_quota_exceeded(new,
> +						   QUOTA_CHECK_MAX_FILES_OP,
> +						   ci_old->i_rfiles +
> +						   ci_old->i_rsubdirs);

Somewhat idle curiosity, but what happens with hardlinked files where
one dentry is in one quota domain and another is in a different one?
Does it stay in the old quotarealm?

In any case, this is likely fine as non-hardlinked files are the
pessimal case anyway.

> +		if (ret)
> +			ret = -EXDEV;
> +	} else {
> +		ret = check_quota_exceeded(new, QUOTA_CHECK_MAX_BYTES_OP,
> +					   i_size_read(old));
> +		if (!ret)
> +			ret = check_quota_exceeded(new,
> +						   QUOTA_CHECK_MAX_FILES_OP, 1);
> +		if (ret)
> +			ret = -EDQUOT;
> +	}
> +
> +	return ret;
> +}
> diff --git a/fs/ceph/super.h b/fs/ceph/super.h
> index 037cdfb2ad4f..d5853831a6b5 100644
> --- a/fs/ceph/super.h
> +++ b/fs/ceph/super.h
> @@ -1175,13 +1175,14 @@ extern void ceph_handle_quota(struct ceph_mds_client *mdsc,
>  			      struct ceph_mds_session *session,
>  			      struct ceph_msg *msg);
>  extern bool ceph_quota_is_max_files_exceeded(struct inode *inode);
> -extern bool ceph_quota_is_same_realm(struct inode *old, struct inode *new);
>  extern bool ceph_quota_is_max_bytes_exceeded(struct inode *inode,
>  					     loff_t newlen);
>  extern bool ceph_quota_is_max_bytes_approaching(struct inode *inode,
>  						loff_t newlen);
>  extern bool ceph_quota_update_statfs(struct ceph_fs_client *fsc,
>  				     struct kstatfs *buf);
> +extern int ceph_quota_check_rename(struct ceph_mds_client *mdsc,
> +				   struct inode *old, struct inode *new);
>  extern void ceph_cleanup_quotarealms_inodes(struct ceph_mds_client *mdsc);
>  
>  #endif /* _FS_CEPH_SUPER_H */

-- 
Jeff Layton <jlayton@kernel.org>


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

* Re: [PATCH v2 2/2] ceph: allow rename operation under different quota realms
  2020-04-07 22:57   ` Jeff Layton
@ 2020-04-08  3:10     ` Yan, Zheng
  0 siblings, 0 replies; 6+ messages in thread
From: Yan, Zheng @ 2020-04-08  3:10 UTC (permalink / raw)
  To: Jeff Layton
  Cc: Luis Henriques, Sage Weil, Ilya Dryomov, Gregory Farnum,
	Zheng Yan, Frank Schilder, ceph-devel, Linux Kernel Mailing List

On Wed, Apr 8, 2020 at 7:00 AM Jeff Layton <jlayton@kernel.org> wrote:

>
> Somewhat idle curiosity, but what happens with hardlinked files where
> one dentry is in one quota domain and another is in a different one?
> Does it stay in the old quotarealm?
>
> In any case, this is likely fine as non-hardlinked files are the
> pessimal case anyway.

rstat only tracks primary dentry.  inode is in the quota realm where
its primary linkage is in.

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

* Re: [PATCH v2 0/2] ceph: support cross-quota-tree renames
  2020-04-07 10:30 [PATCH v2 0/2] ceph: support cross-quota-tree renames Luis Henriques
  2020-04-07 10:30 ` [PATCH v2 1/2] ceph: normalize 'delta' parameter usage in check_quota_exceeded Luis Henriques
  2020-04-07 10:30 ` [PATCH v2 2/2] ceph: allow rename operation under different quota realms Luis Henriques
@ 2020-04-08 14:31 ` Jeff Layton
  2 siblings, 0 replies; 6+ messages in thread
From: Jeff Layton @ 2020-04-08 14:31 UTC (permalink / raw)
  To: Luis Henriques, Sage Weil, Ilya Dryomov, Gregory Farnum, Zheng Yan
  Cc: Frank Schilder, ceph-devel, linux-kernel

On Tue, 2020-04-07 at 11:30 +0100, Luis Henriques wrote:
> Hi!
> 
> The following patches will make the cephfs kernel client behave the same
> way as the fuse client when doing renames across different quota realms.
> 
> Changes since v1:
> 
> - Dropped 'old == new' check in ceph_quota_check_rename() and added back
>   optimization in ceph_rename(), to only check realms if old_dir and
>   new_dir are different.
> 
> Luis Henriques (2):
>   ceph: normalize 'delta' parameter usage in check_quota_exceeded
>   ceph: allow rename operation under different quota realms
> 
>  fs/ceph/dir.c   |  9 +++----
>  fs/ceph/quota.c | 62 +++++++++++++++++++++++++++++++++++++++++++++----
>  fs/ceph/super.h |  3 ++-
>  3 files changed, 65 insertions(+), 9 deletions(-)
> 

Looks good. Merged into ceph-client/testing.

Thanks!
-- 
Jeff Layton <jlayton@kernel.org>


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

end of thread, other threads:[~2020-04-08 14:31 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-04-07 10:30 [PATCH v2 0/2] ceph: support cross-quota-tree renames Luis Henriques
2020-04-07 10:30 ` [PATCH v2 1/2] ceph: normalize 'delta' parameter usage in check_quota_exceeded Luis Henriques
2020-04-07 10:30 ` [PATCH v2 2/2] ceph: allow rename operation under different quota realms Luis Henriques
2020-04-07 22:57   ` Jeff Layton
2020-04-08  3:10     ` Yan, Zheng
2020-04-08 14:31 ` [PATCH v2 0/2] ceph: support cross-quota-tree renames Jeff Layton

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®