ceph: quota: report root dir quota usage in statfs
authorLuis Henriques <lhenriques@suse.com>
Wed, 31 Jan 2018 10:53:13 +0000 (10:53 +0000)
committerIlya Dryomov <idryomov@gmail.com>
Mon, 2 Apr 2018 09:17:53 +0000 (11:17 +0200)
This commit changes statfs default behaviour when reporting usage
statistics.  Instead of using the overall filesystem usage, statfs now
reports the quota for the filesystem root, if ceph.quota.max_bytes has
been set for this inode.  If quota hasn't been set, it falls back to the
old statfs behaviour.

A new mount option is also added ('noquotadf') to disable this behaviour.

Signed-off-by: Luis Henriques <lhenriques@suse.com>
Reviewed-by: "Yan, Zheng" <zyan@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Documentation/filesystems/ceph.txt
fs/ceph/quota.c
fs/ceph/super.c
fs/ceph/super.h

index 094772481263852df643546bc91bf9ca633eb968..d7f011ddc1500cdf8e705430c90ed60deb7a2ecc 100644 (file)
@@ -149,6 +149,10 @@ Mount Options
   noasyncreaddir
        Do not use the dcache as above for readdir.
 
+  noquotadf
+        Report overall filesystem usage in statfs instead of using the root
+        directory quota.
+
 More Information
 ================
 
index 588744b4665fe7a66b8a8be7695fe37a0017ec21..242bfa5c0539ba3ba49bcca9f17760a6346688ea 100644 (file)
@@ -18,6 +18,8 @@
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/statfs.h>
+
 #include "super.h"
 #include "mds_client.h"
 
@@ -303,3 +305,57 @@ bool ceph_quota_is_max_bytes_approaching(struct inode *inode, loff_t newsize)
        return check_quota_exceeded(inode, QUOTA_CHECK_MAX_BYTES_APPROACHING_OP,
                                    (newsize - size));
 }
+
+/*
+ * ceph_quota_update_statfs - if root has quota update statfs with quota status
+ * @fsc:       filesystem client instance
+ * @buf:       statfs to update
+ *
+ * If the mounted filesystem root has max_bytes quota set, update the filesystem
+ * statistics with the quota status.
+ *
+ * This function returns true if the stats have been updated, false otherwise.
+ */
+bool ceph_quota_update_statfs(struct ceph_fs_client *fsc, struct kstatfs *buf)
+{
+       struct ceph_mds_client *mdsc = fsc->mdsc;
+       struct ceph_inode_info *ci;
+       struct ceph_snap_realm *realm;
+       struct inode *in;
+       u64 total = 0, used, free;
+       bool is_updated = false;
+
+       down_read(&mdsc->snap_rwsem);
+       realm = get_quota_realm(mdsc, d_inode(fsc->sb->s_root));
+       up_read(&mdsc->snap_rwsem);
+       if (!realm)
+               return false;
+
+       spin_lock(&realm->inodes_with_caps_lock);
+       in = realm->inode ? igrab(realm->inode) : NULL;
+       spin_unlock(&realm->inodes_with_caps_lock);
+       if (in) {
+               ci = ceph_inode(in);
+               spin_lock(&ci->i_ceph_lock);
+               if (ci->i_max_bytes) {
+                       total = ci->i_max_bytes >> CEPH_BLOCK_SHIFT;
+                       used = ci->i_rbytes >> CEPH_BLOCK_SHIFT;
+                       /* It is possible for a quota to be exceeded.
+                        * Report 'zero' in that case
+                        */
+                       free = total > used ? total - used : 0;
+               }
+               spin_unlock(&ci->i_ceph_lock);
+               if (total) {
+                       buf->f_blocks = total;
+                       buf->f_bfree = free;
+                       buf->f_bavail = free;
+                       is_updated = true;
+               }
+               iput(in);
+       }
+       ceph_put_snap_realm(mdsc, realm);
+
+       return is_updated;
+}
+
index 0fc03c456c502a64a50f4b9bb2a54dff8c76eb4d..b33082e6878f1ca1ba8820716dafb1924d77855d 100644 (file)
@@ -76,9 +76,18 @@ static int ceph_statfs(struct dentry *dentry, struct kstatfs *buf)
         */
        buf->f_bsize = 1 << CEPH_BLOCK_SHIFT;
        buf->f_frsize = 1 << CEPH_BLOCK_SHIFT;
-       buf->f_blocks = le64_to_cpu(st.kb) >> (CEPH_BLOCK_SHIFT-10);
-       buf->f_bfree = le64_to_cpu(st.kb_avail) >> (CEPH_BLOCK_SHIFT-10);
-       buf->f_bavail = le64_to_cpu(st.kb_avail) >> (CEPH_BLOCK_SHIFT-10);
+
+       /*
+        * By default use root quota for stats; fallback to overall filesystem
+        * usage if using 'noquotadf' mount option or if the root dir doesn't
+        * have max_bytes quota set.
+        */
+       if (ceph_test_mount_opt(fsc, NOQUOTADF) ||
+           !ceph_quota_update_statfs(fsc, buf)) {
+               buf->f_blocks = le64_to_cpu(st.kb) >> (CEPH_BLOCK_SHIFT-10);
+               buf->f_bfree = le64_to_cpu(st.kb_avail) >> (CEPH_BLOCK_SHIFT-10);
+               buf->f_bavail = le64_to_cpu(st.kb_avail) >> (CEPH_BLOCK_SHIFT-10);
+       }
 
        buf->f_files = le64_to_cpu(st.num_objects);
        buf->f_ffree = -1;
@@ -151,6 +160,8 @@ enum {
        Opt_acl,
 #endif
        Opt_noacl,
+       Opt_quotadf,
+       Opt_noquotadf,
 };
 
 static match_table_t fsopt_tokens = {
@@ -187,6 +198,8 @@ static match_table_t fsopt_tokens = {
        {Opt_acl, "acl"},
 #endif
        {Opt_noacl, "noacl"},
+       {Opt_quotadf, "quotadf"},
+       {Opt_noquotadf, "noquotadf"},
        {-1, NULL}
 };
 
@@ -334,6 +347,12 @@ static int parse_fsopt_token(char *c, void *private)
        case Opt_norequire_active_mds:
                fsopt->flags |= CEPH_MOUNT_OPT_MOUNTWAIT;
                break;
+       case Opt_quotadf:
+               fsopt->flags &= ~CEPH_MOUNT_OPT_NOQUOTADF;
+               break;
+       case Opt_noquotadf:
+               fsopt->flags |= CEPH_MOUNT_OPT_NOQUOTADF;
+               break;
 #ifdef CONFIG_CEPH_FS_POSIX_ACL
        case Opt_acl:
                fsopt->sb_flags |= SB_POSIXACL;
@@ -520,6 +539,8 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root)
        }
        if (fsopt->flags & CEPH_MOUNT_OPT_NOPOOLPERM)
                seq_puts(m, ",nopoolperm");
+       if (fsopt->flags & CEPH_MOUNT_OPT_NOQUOTADF)
+               seq_puts(m, ",noquotadf");
 
 #ifdef CONFIG_CEPH_FS_POSIX_ACL
        if (fsopt->sb_flags & SB_POSIXACL)
index 1321a6749953cc16caea86a6403e698a73d211a2..a7077a0c989fb33cde837a41e6b4d8b9951d2c43 100644 (file)
@@ -39,6 +39,7 @@
 #define CEPH_MOUNT_OPT_FSCACHE         (1<<10) /* use fscache */
 #define CEPH_MOUNT_OPT_NOPOOLPERM      (1<<11) /* no pool permission check */
 #define CEPH_MOUNT_OPT_MOUNTWAIT       (1<<12) /* mount waits if no mds is up */
+#define CEPH_MOUNT_OPT_NOQUOTADF       (1<<13) /* no root dir quota in statfs */
 
 #define CEPH_MOUNT_OPT_DEFAULT    CEPH_MOUNT_OPT_DCACHE
 
@@ -1104,5 +1105,7 @@ 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);
 
 #endif /* _FS_CEPH_SUPER_H */