ceph: Fix incorrect statfs report for small quota
authorKotresh HR <khiremat@redhat.com>
Wed, 10 Nov 2021 18:00:21 +0000 (23:30 +0530)
committerIlya Dryomov <idryomov@gmail.com>
Thu, 13 Jan 2022 12:40:06 +0000 (13:40 +0100)
Problem:
The statfs reports incorrect free/available space for quota less then
CEPH_BLOCK size (4M).

Solution:
For quota less than CEPH_BLOCK size, smaller block size of 4K is used.
But if quota is less than 4K, it is decided to go with binary use/free
of 4K block. For quota size less than 4K size, report the
total=used=4K,free=0 when quota is full and total=free=4K,used=0
otherwise.

Signed-off-by: Kotresh HR <khiremat@redhat.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
fs/ceph/quota.c
fs/ceph/super.h

index 620c691..24ae13e 100644 (file)
@@ -494,10 +494,24 @@ bool ceph_quota_update_statfs(struct ceph_fs_client *fsc, struct kstatfs *buf)
                if (ci->i_max_bytes) {
                        total = ci->i_max_bytes >> CEPH_BLOCK_SHIFT;
                        used = ci->i_rbytes >> CEPH_BLOCK_SHIFT;
+                       /* For quota size less than 4MB, use 4KB block size */
+                       if (!total) {
+                               total = ci->i_max_bytes >> CEPH_4K_BLOCK_SHIFT;
+                               used = ci->i_rbytes >> CEPH_4K_BLOCK_SHIFT;
+                               buf->f_frsize = 1 << CEPH_4K_BLOCK_SHIFT;
+                       }
                        /* It is possible for a quota to be exceeded.
                         * Report 'zero' in that case
                         */
                        free = total > used ? total - used : 0;
+                       /* For quota size less than 4KB, report the
+                        * total=used=4KB,free=0 when quota is full
+                        * and total=free=4KB, used=0 otherwise */
+                       if (!total) {
+                               total = 1;
+                               free = ci->i_max_bytes > ci->i_rbytes ? 1 : 0;
+                               buf->f_frsize = 1 << CEPH_4K_BLOCK_SHIFT;
+                       }
                }
                spin_unlock(&ci->i_ceph_lock);
                if (total) {
index ec6b221..533189b 100644 (file)
@@ -32,6 +32,7 @@
  * large volume sizes on 32-bit machines. */
 #define CEPH_BLOCK_SHIFT   22  /* 4 MB */
 #define CEPH_BLOCK         (1 << CEPH_BLOCK_SHIFT)
+#define CEPH_4K_BLOCK_SHIFT 12  /* 4 KB */
 
 #define CEPH_MOUNT_OPT_CLEANRECOVER    (1<<1) /* auto reonnect (clean mode) after blocklisted */
 #define CEPH_MOUNT_OPT_DIRSTAT         (1<<4) /* `cat dirname` for stats */