]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
ceph: quota: update MDS when max_bytes is approaching
authorLuis Henriques <lhenriques@suse.com>
Fri, 5 Jan 2018 10:47:22 +0000 (10:47 +0000)
committerKleber Sacilotto de Souza <kleber.souza@canonical.com>
Tue, 2 Jul 2019 16:30:46 +0000 (18:30 +0200)
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 <lhenriques@suse.com>
Reviewed-by: "Yan, Zheng" <zyan@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
(cherry picked from commit 1ab302a0cb1455631646aa66b7fc02afd617ea4f)
Signed-off-by: Connor Kuehl <connor.kuehl@canonical.com>
Acked-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
Acked-by: Stefan Bader <stefan.bader@canonical.com>
Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
fs/ceph/file.c
fs/ceph/quota.c
fs/ceph/super.h

index a51098c0fc877eed3c0e6b4e373db5908788ed02..69c29f5489d718f3f83cdaa9643cafded90309ea 100644 (file)
@@ -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);
index e324593a97714136d25e127cad58665e5c2463b3..656c9fbba1aef8021c63f60a64d93c5292dccad0 100644 (file)
@@ -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));
+}
index fb1119147a688d16548849be8f3aeb65de00a229..35c2195e3e3db6e7e03897880fbd5b0609ed4ec4 100644 (file)
@@ -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 */