From 763b0c3d5fb2e109fa64c3e6279053fc4989229a Mon Sep 17 00:00:00 2001 From: Luis Henriques Date: Fri, 5 Jan 2018 10:47:22 +0000 Subject: [PATCH] ceph: quota: update MDS when max_bytes is approaching BugLink: https://bugs.launchpad.net/bugs/1834235 When we're reaching the ceph.quota.max_bytes limit, i.e., when writing more than 1/16th of the space left in a quota realm, update the MDS with the new file size. This mirrors the fuse-client approach with commit 122c50315ed1 ("client: Inform mds file size when approaching quota limit"), in the ceph git tree. Signed-off-by: Luis Henriques Reviewed-by: "Yan, Zheng" Signed-off-by: Ilya Dryomov (cherry picked from commit 1ab302a0cb1455631646aa66b7fc02afd617ea4f) Signed-off-by: Connor Kuehl Acked-by: Kleber Sacilotto de Souza Acked-by: Stefan Bader Signed-off-by: Kleber Sacilotto de Souza --- fs/ceph/file.c | 6 ++++++ fs/ceph/quota.c | 38 +++++++++++++++++++++++++++++++++++++- fs/ceph/super.h | 2 ++ 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/fs/ceph/file.c b/fs/ceph/file.c index a51098c0fc87..69c29f5489d7 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -1426,6 +1426,7 @@ retry_snap: if (written >= 0) { int dirty; + spin_lock(&ci->i_ceph_lock); ci->i_inline_version = CEPH_INLINE_NONE; dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_FILE_WR, @@ -1433,6 +1434,8 @@ retry_snap: spin_unlock(&ci->i_ceph_lock); if (dirty) __mark_inode_dirty(inode, dirty); + if (ceph_quota_is_max_bytes_approaching(inode, iocb->ki_pos)) + ceph_check_caps(ci, CHECK_CAPS_NODELAY, NULL); } dout("aio_write %p %llx.%llx %llu~%u dropping cap refs on %s\n", @@ -1729,6 +1732,9 @@ static long ceph_fallocate(struct file *file, int mode, spin_unlock(&ci->i_ceph_lock); if (dirty) __mark_inode_dirty(inode, dirty); + if ((endoff > size) && + ceph_quota_is_max_bytes_approaching(inode, endoff)) + ceph_check_caps(ci, CHECK_CAPS_NODELAY, NULL); } ceph_put_cap_refs(ci, got); diff --git a/fs/ceph/quota.c b/fs/ceph/quota.c index e324593a9771..656c9fbba1ae 100644 --- a/fs/ceph/quota.c +++ b/fs/ceph/quota.c @@ -137,7 +137,9 @@ bool ceph_quota_is_same_realm(struct inode *old, struct inode *new) enum quota_check_op { QUOTA_CHECK_MAX_FILES_OP, /* check quota max_files limit */ - QUOTA_CHECK_MAX_BYTES_OP /* check quota max_files limit */ + QUOTA_CHECK_MAX_BYTES_OP, /* check quota max_files limit */ + QUOTA_CHECK_MAX_BYTES_APPROACHING_OP /* check if quota max_files + limit is approaching */ }; /* @@ -185,6 +187,20 @@ static bool check_quota_exceeded(struct inode *inode, enum quota_check_op op, case QUOTA_CHECK_MAX_BYTES_OP: exceeded = (max && (rvalue + delta > max)); break; + case QUOTA_CHECK_MAX_BYTES_APPROACHING_OP: + if (max) { + if (rvalue >= max) + exceeded = true; + else { + /* + * when we're writing more that 1/16th + * of the available space + */ + exceeded = + (((max - rvalue) >> 4) < delta); + } + } + break; default: /* Shouldn't happen */ pr_warn("Invalid quota check op (%d)\n", op); @@ -238,3 +254,23 @@ bool ceph_quota_is_max_bytes_exceeded(struct inode *inode, loff_t newsize) return check_quota_exceeded(inode, QUOTA_CHECK_MAX_BYTES_OP, (newsize - size)); } + +/* + * ceph_quota_is_max_bytes_approaching - check if we're reaching max_bytes + * @inode: inode being written + * @newsize: new size if write succeeds + * + * This function returns true if the new file size @newsize will be consuming + * more than 1/16th of the available quota space; it returns false otherwise. + */ +bool ceph_quota_is_max_bytes_approaching(struct inode *inode, loff_t newsize) +{ + loff_t size = ceph_inode(inode)->i_reported_size; + + /* return immediately if we're decreasing file size */ + if (newsize <= size) + return false; + + return check_quota_exceeded(inode, QUOTA_CHECK_MAX_BYTES_APPROACHING_OP, + (newsize - size)); +} diff --git a/fs/ceph/super.h b/fs/ceph/super.h index fb1119147a68..35c2195e3e3d 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -1082,5 +1082,7 @@ 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); #endif /* _FS_CEPH_SUPER_H */ -- 2.39.2