All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] ceph: quota: client optimizations
@ 2018-01-12 17:19 Luis Henriques
  2018-01-12 17:19 ` [PATCH 1/2] ceph: quota: cache inode pointer in ceph_snap_realm Luis Henriques
  2018-01-12 17:19 ` [PATCH 2/2] ceph: quota: add counter for snaprealms with quota Luis Henriques
  0 siblings, 2 replies; 3+ messages in thread
From: Luis Henriques @ 2018-01-12 17:19 UTC (permalink / raw)
  To: ceph-devel; +Cc: Yan, Zheng, Jan Fajerski, Luis Henriques

Following this email I'm sending two patches that contain optimizations
for the quota implementation.  They were both suggested by Zheng Yan.

The first patch modifies the snaprealm structure to include an extra
field that will cache an inode pointer (but doesn't keep a ref to it).
This will remove the need for extra ceph_find_inode() calls while
walking through the snaprealm hierarchy.

The 2nd patch keeps a counter of inodes that have quota set.  By keeping
this counter, it is possible to short-circuit quota checks if we don't
have any inode with quotas on the filesystem.

NOTE: these 2 patches are based on the current ceph-client testing
branch, not on mainline kernel.

Luis Henriques (2):
  ceph: quota: cache inode pointer in ceph_snap_realm
  ceph: quota: add counter for snaprealms with quota

 fs/ceph/inode.c      |  3 +--
 fs/ceph/mds_client.c |  1 +
 fs/ceph/mds_client.h |  2 ++
 fs/ceph/quota.c      | 60 ++++++++++++++++++++++++++++++++++------------------
 fs/ceph/snap.c       |  9 ++++++++
 fs/ceph/super.h      |  4 ++++
 6 files changed, 57 insertions(+), 22 deletions(-)


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

* [PATCH 1/2] ceph: quota: cache inode pointer in ceph_snap_realm
  2018-01-12 17:19 [PATCH 0/2] ceph: quota: client optimizations Luis Henriques
@ 2018-01-12 17:19 ` Luis Henriques
  2018-01-12 17:19 ` [PATCH 2/2] ceph: quota: add counter for snaprealms with quota Luis Henriques
  1 sibling, 0 replies; 3+ messages in thread
From: Luis Henriques @ 2018-01-12 17:19 UTC (permalink / raw)
  To: ceph-devel; +Cc: Yan, Zheng, Jan Fajerski, Luis Henriques

Keep a pointer to the inode in struct ceph_snap_realm.  This allows to
optimize functions that walk the realms hierarchy (e.g. in quotas).

Signed-off-by: Luis Henriques <lhenriques@suse.com>
---
 fs/ceph/quota.c | 22 ++++------------------
 fs/ceph/snap.c  |  9 +++++++++
 fs/ceph/super.h |  1 +
 3 files changed, 14 insertions(+), 18 deletions(-)

diff --git a/fs/ceph/quota.c b/fs/ceph/quota.c
index 121819baeb58..d8bd6d346324 100644
--- a/fs/ceph/quota.c
+++ b/fs/ceph/quota.c
@@ -83,7 +83,6 @@ static struct ceph_snap_realm *get_quota_realm(struct ceph_mds_client *mdsc,
 {
 	struct ceph_inode_info *ci = NULL;
 	struct ceph_snap_realm *realm, *next;
-	struct ceph_vino vino;
 	struct inode *in;
 	bool has_quota;
 
@@ -96,14 +95,8 @@ static struct ceph_snap_realm *get_quota_realm(struct ceph_mds_client *mdsc,
 	else
 		pr_err_ratelimited("get_quota_realm: ino (%llx.%llx) "
 				   "null i_snap_realm\n", ceph_vinop(inode));
-	while (realm) {
-		vino.ino = realm->ino;
-		vino.snap = CEPH_NOSNAP;
-		in = ceph_find_inode(inode->i_sb, vino);
-		if (!in) {
-			pr_warn("Failed to find inode for %llu\n", vino.ino);
-			break;
-		}
+	while (realm && realm->inode) {
+		in = igrab(realm->inode);
 		ci = ceph_inode(in);
 		has_quota = ceph_has_quota(ci);
 		iput(in);
@@ -161,7 +154,6 @@ static bool check_quota_exceeded(struct inode *inode, enum quota_check_op op,
 	struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
 	struct ceph_inode_info *ci;
 	struct ceph_snap_realm *realm, *next;
-	struct ceph_vino vino;
 	struct inode *in;
 	u64 max, rvalue;
 	bool exceeded = false;
@@ -176,14 +168,8 @@ static bool check_quota_exceeded(struct inode *inode, enum quota_check_op op,
 	else
 		pr_err_ratelimited("check_quota_exceeded: ino (%llx.%llx) "
 				   "null i_snap_realm\n", ceph_vinop(inode));
-	while (realm) {
-		vino.ino = realm->ino;
-		vino.snap = CEPH_NOSNAP;
-		in = ceph_find_inode(inode->i_sb, vino);
-		if (!in) {
-			pr_warn("Failed to find inode for %llu\n", vino.ino);
-			break;
-		}
+	while (realm && realm->inode) {
+		in = igrab(realm->inode);
 		ci = ceph_inode(in);
 		spin_lock(&ci->i_ceph_lock);
 		if (op == QUOTA_CHECK_MAX_FILES_OP) {
diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c
index 41858604c2db..e4bbd2c03c1b 100644
--- a/fs/ceph/snap.c
+++ b/fs/ceph/snap.c
@@ -110,6 +110,7 @@ static struct ceph_snap_realm *ceph_create_snap_realm(
 	u64 ino)
 {
 	struct ceph_snap_realm *realm;
+	struct ceph_vino vino;
 
 	realm = kzalloc(sizeof(*realm), GFP_NOFS);
 	if (!realm)
@@ -117,6 +118,14 @@ static struct ceph_snap_realm *ceph_create_snap_realm(
 
 	atomic_set(&realm->nref, 1);    /* for caller */
 	realm->ino = ino;
+
+	/* cache a pointer to inode */
+	vino.ino = realm->ino;
+	vino.snap = CEPH_NOSNAP;
+	realm->inode = ceph_find_inode(mdsc->fsc->sb, vino);
+	if (realm->inode)
+		/* drop ref */
+		iput(realm->inode);
 	INIT_LIST_HEAD(&realm->children);
 	INIT_LIST_HEAD(&realm->child_item);
 	INIT_LIST_HEAD(&realm->empty_item);
diff --git a/fs/ceph/super.h b/fs/ceph/super.h
index 3e0741a47cb4..5f788350cd75 100644
--- a/fs/ceph/super.h
+++ b/fs/ceph/super.h
@@ -754,6 +754,7 @@ struct ceph_readdir_cache_control {
  */
 struct ceph_snap_realm {
 	u64 ino;
+	struct inode *inode;
 	atomic_t nref;
 	struct rb_node node;
 

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

* [PATCH 2/2] ceph: quota: add counter for snaprealms with quota
  2018-01-12 17:19 [PATCH 0/2] ceph: quota: client optimizations Luis Henriques
  2018-01-12 17:19 ` [PATCH 1/2] ceph: quota: cache inode pointer in ceph_snap_realm Luis Henriques
@ 2018-01-12 17:19 ` Luis Henriques
  1 sibling, 0 replies; 3+ messages in thread
From: Luis Henriques @ 2018-01-12 17:19 UTC (permalink / raw)
  To: ceph-devel; +Cc: Yan, Zheng, Jan Fajerski, Luis Henriques

By keeping a counter with the number of snaprealms that have quota set
allows to optimize the functions that need to walk throught the realms
hierarchy looking for quotas.  Thus, if this counter is zero it's safe to
assume that there are no realms with quota.

Signed-off-by: Luis Henriques <lhenriques@suse.com>
---
 fs/ceph/inode.c      |  3 +--
 fs/ceph/mds_client.c |  1 +
 fs/ceph/mds_client.h |  2 ++
 fs/ceph/quota.c      | 38 ++++++++++++++++++++++++++++++++++++--
 fs/ceph/super.h      |  3 +++
 5 files changed, 43 insertions(+), 4 deletions(-)

diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
index 6563543692b2..7dfd17bec963 100644
--- a/fs/ceph/inode.c
+++ b/fs/ceph/inode.c
@@ -801,8 +801,7 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
 	inode->i_rdev = le32_to_cpu(info->rdev);
 	inode->i_blkbits = fls(le32_to_cpu(info->layout.fl_stripe_unit)) - 1;
 
-	ci->i_max_bytes = iinfo->max_bytes;
-	ci->i_max_files = iinfo->max_files;
+	ceph_quota_update_inode(mdsc, ci, iinfo->max_bytes, iinfo->max_files);
 
 	if ((new_version || (new_issued & CEPH_CAP_AUTH_SHARED)) &&
 	    (issued & CEPH_CAP_AUTH_EXCL) == 0) {
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index 6e4640d41446..ed8cb5c3be3f 100644
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -3599,6 +3599,7 @@ int ceph_mdsc_init(struct ceph_fs_client *fsc)
 	atomic_set(&mdsc->num_sessions, 0);
 	mdsc->max_sessions = 0;
 	mdsc->stopping = 0;
+	atomic64_set(&mdsc->quotarealms_count, 0);
 	mdsc->last_snap_seq = 0;
 	init_rwsem(&mdsc->snap_rwsem);
 	mdsc->snap_realms = RB_ROOT;
diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h
index 1dd013f49f8d..8c5657b78da1 100644
--- a/fs/ceph/mds_client.h
+++ b/fs/ceph/mds_client.h
@@ -323,6 +323,8 @@ struct ceph_mds_client {
 	int                     max_sessions;  /* len of s_mds_sessions */
 	int                     stopping;      /* true if shutting down */
 
+	atomic64_t		quotarealms_count; /* # realms with quota */
+
 	/*
 	 * snap_rwsem will cover cap linkage into snaprealms, and
 	 * realm snap contexts.  (later, we can do per-realm snap
diff --git a/fs/ceph/quota.c b/fs/ceph/quota.c
index d8bd6d346324..c1f8d5ae15fb 100644
--- a/fs/ceph/quota.c
+++ b/fs/ceph/quota.c
@@ -26,6 +26,31 @@ static inline bool ceph_has_quota(struct ceph_inode_info *ci)
 	return (ci && (ci->i_max_files || ci->i_max_bytes));
 }
 
+static inline bool ceph_has_realms_with_quotas(struct inode *inode)
+{
+	struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
+
+	return (atomic64_read(&mdsc->quotarealms_count) != 0);
+}
+
+void ceph_quota_update_inode(struct ceph_mds_client *mdsc, struct
+			     ceph_inode_info *ci,
+			     u64 max_bytes, u64 max_files)
+{
+	bool had_quota, has_quota;
+
+	had_quota = ceph_has_quota(ci);
+	ci->i_max_bytes = max_bytes;
+	ci->i_max_files = max_files;
+	has_quota = ceph_has_quota(ci);
+
+	/* Update number of realms that have quotas */
+	if (has_quota && !had_quota)
+		atomic64_inc(&mdsc->quotarealms_count);
+	else if (!has_quota && had_quota)
+		atomic64_dec(&mdsc->quotarealms_count);
+}
+
 void ceph_handle_quota(struct ceph_mds_client *mdsc,
 		       struct ceph_mds_session *session,
 		       struct ceph_msg *msg)
@@ -62,8 +87,8 @@ void ceph_handle_quota(struct ceph_mds_client *mdsc,
 	ci->i_rbytes = le64_to_cpu(h->rbytes);
 	ci->i_rfiles = le64_to_cpu(h->rfiles);
 	ci->i_rsubdirs = le64_to_cpu(h->rsubdirs);
-	ci->i_max_bytes = le64_to_cpu(h->max_bytes);
-	ci->i_max_files = le64_to_cpu(h->max_files);
+	ceph_quota_update_inode(mdsc, ci, le64_to_cpu(h->max_bytes),
+				le64_to_cpu(h->max_files));
 	spin_unlock(&ci->i_ceph_lock);
 
 	iput(inode);
@@ -231,6 +256,9 @@ static bool check_quota_exceeded(struct inode *inode, enum quota_check_op op,
  */
 bool ceph_quota_is_max_files_exceeded(struct inode *inode)
 {
+	if (!ceph_has_realms_with_quotas(inode))
+		return false;
+
 	WARN_ON(!S_ISDIR(inode->i_mode));
 
 	return check_quota_exceeded(inode, QUOTA_CHECK_MAX_FILES_OP, 0);
@@ -248,6 +276,9 @@ bool ceph_quota_is_max_bytes_exceeded(struct inode *inode, loff_t newsize)
 {
 	loff_t size = i_size_read(inode);
 
+	if (!ceph_has_realms_with_quotas(inode))
+		return false;
+
 	/* return immediately if we're decreasing file size */
 	if (newsize <= size)
 		return false;
@@ -267,6 +298,9 @@ bool ceph_quota_is_max_bytes_approaching(struct inode *inode, loff_t newsize)
 {
 	loff_t size = ceph_inode(inode)->i_reported_size;
 
+	if (!ceph_has_realms_with_quotas(inode))
+		return false;
+
 	/* return immediately if we're decreasing file size */
 	if (newsize <= size)
 		return false;
diff --git a/fs/ceph/super.h b/fs/ceph/super.h
index 5f788350cd75..cc6c4d6d45d6 100644
--- a/fs/ceph/super.h
+++ b/fs/ceph/super.h
@@ -1082,6 +1082,9 @@ extern int ceph_fs_debugfs_init(struct ceph_fs_client *client);
 extern void ceph_fs_debugfs_cleanup(struct ceph_fs_client *client);
 
 /* quota.c */
+extern void ceph_quota_update_inode(struct ceph_mds_client *mdsc,
+				    struct ceph_inode_info *ci,
+				    u64 max_bytes, u64 max_files);
 extern void ceph_handle_quota(struct ceph_mds_client *mdsc,
 			      struct ceph_mds_session *session,
 			      struct ceph_msg *msg);

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

end of thread, other threads:[~2018-01-12 17:19 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-01-12 17:19 [PATCH 0/2] ceph: quota: client optimizations Luis Henriques
2018-01-12 17:19 ` [PATCH 1/2] ceph: quota: cache inode pointer in ceph_snap_realm Luis Henriques
2018-01-12 17:19 ` [PATCH 2/2] ceph: quota: add counter for snaprealms with quota Luis Henriques

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.