ceph: quota: add counter for snaprealms with quota
authorLuis Henriques <lhenriques@suse.com>
Fri, 12 Jan 2018 17:19:29 +0000 (17:19 +0000)
committerIlya Dryomov <idryomov@gmail.com>
Mon, 2 Apr 2018 09:17:53 +0000 (11:17 +0200)
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>
Reviewed-by: "Yan, Zheng" <zyan@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
fs/ceph/inode.c
fs/ceph/mds_client.c
fs/ceph/mds_client.h
fs/ceph/quota.c
fs/ceph/super.h

index 8ea11b1a2e23334dc2caaa6b428a032b1f6fd645..8bf60250309e359ffd6a34f89c75991b3a1c3c48 100644 (file)
@@ -539,6 +539,9 @@ void ceph_destroy_inode(struct inode *inode)
 
        ceph_queue_caps_release(inode);
 
+       if (__ceph_has_any_quota(ci))
+               ceph_adjust_quota_realms_count(inode, false);
+
        /*
         * we may still have a snap_realm reference if there are stray
         * caps in i_snap_caps.
@@ -796,8 +799,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_update_quota(ci, iinfo->max_bytes, iinfo->max_files);
 
        if ((new_version || (new_issued & CEPH_CAP_AUTH_SHARED)) &&
            (issued & CEPH_CAP_AUTH_EXCL) == 0) {
index 1c9877c1149fb2d3d95696383bc93dd32d208ab4..5ece2e6ad1548e0893ee9734132a64bb66ffc89e 100644 (file)
@@ -3609,6 +3609,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;
index 2a67c8b01ae642d43fb56d4f7ac91c2db81f4ad9..2ec3b5b350671a1fa1e574ae67d6a67567762dd8 100644 (file)
@@ -314,6 +314,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
index c561a85ea8b1c2bec1bc4ac087b3e633d15d9b91..588744b4665fe7a66b8a8be7695fe37a0017ec21 100644 (file)
 #include "super.h"
 #include "mds_client.h"
 
-static inline bool ceph_has_quota(struct ceph_inode_info *ci)
+void ceph_adjust_quota_realms_count(struct inode *inode, bool inc)
 {
-       return (ci && (ci->i_max_files || ci->i_max_bytes));
+       struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
+       if (inc)
+               atomic64_inc(&mdsc->quotarealms_count);
+       else
+               atomic64_dec(&mdsc->quotarealms_count);
+}
+
+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_handle_quota(struct ceph_mds_client *mdsc,
@@ -62,8 +72,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_update_quota(ci, le64_to_cpu(h->max_bytes),
+                           le64_to_cpu(h->max_files));
        spin_unlock(&ci->i_ceph_lock);
 
        iput(inode);
@@ -103,7 +113,7 @@ static struct ceph_snap_realm *get_quota_realm(struct ceph_mds_client *mdsc,
                        break;
 
                ci = ceph_inode(in);
-               has_quota = ceph_has_quota(ci);
+               has_quota = __ceph_has_any_quota(ci);
                iput(in);
 
                next = realm->parent;
@@ -241,6 +251,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);
@@ -258,6 +271,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;
@@ -277,6 +293,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;
index 8217abf461821d338bd2dcc3dac2cb4c2f5dae6c..1321a6749953cc16caea86a6403e698a73d211a2 100644 (file)
@@ -1075,6 +1075,26 @@ extern int ceph_fs_debugfs_init(struct ceph_fs_client *client);
 extern void ceph_fs_debugfs_cleanup(struct ceph_fs_client *client);
 
 /* quota.c */
+static inline bool __ceph_has_any_quota(struct ceph_inode_info *ci)
+{
+       return ci->i_max_files || ci->i_max_bytes;
+}
+
+extern void ceph_adjust_quota_realms_count(struct inode *inode, bool inc);
+
+static inline void __ceph_update_quota(struct ceph_inode_info *ci,
+                                      u64 max_bytes, u64 max_files)
+{
+       bool had_quota, has_quota;
+       had_quota = __ceph_has_any_quota(ci);
+       ci->i_max_bytes = max_bytes;
+       ci->i_max_files = max_files;
+       has_quota = __ceph_has_any_quota(ci);
+
+       if (had_quota != has_quota)
+               ceph_adjust_quota_realms_count(&ci->vfs_inode, has_quota);
+}
+
 extern void ceph_handle_quota(struct ceph_mds_client *mdsc,
                              struct ceph_mds_session *session,
                              struct ceph_msg *msg);