diff mbox series

[v2,1/1] ceph: Fix incorrect statfs report for small quota

Message ID 20211110180021.20876-2-khiremat@redhat.com (mailing list archive)
State New, archived
Headers show
Series ceph: Fix incorrect statfs report | expand

Commit Message

Kotresh Hiremath Ravishankar Nov. 10, 2021, 6 p.m. UTC
From: Kotresh HR <khiremat@redhat.com>

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>
---
 fs/ceph/quota.c | 14 ++++++++++++++
 fs/ceph/super.h |  1 +
 2 files changed, 15 insertions(+)

Comments

Jeff Layton Nov. 10, 2021, 7:18 p.m. UTC | #1
On Wed, 2021-11-10 at 23:30 +0530, khiremat@redhat.com wrote:
> From: Kotresh HR <khiremat@redhat.com>
> 
> 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>
> ---
>  fs/ceph/quota.c | 14 ++++++++++++++
>  fs/ceph/super.h |  1 +
>  2 files changed, 15 insertions(+)
> 
> diff --git a/fs/ceph/quota.c b/fs/ceph/quota.c
> index 620c691af40e..24ae13ea2241 100644
> --- a/fs/ceph/quota.c
> +++ b/fs/ceph/quota.c
> @@ -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;
> +			}

We really ought to have the MDS establish a floor for the quota size.
<4k quota seems ridiculous.

>  		}
>  		spin_unlock(&ci->i_ceph_lock);
>  		if (total) {
> diff --git a/fs/ceph/super.h b/fs/ceph/super.h
> index ed51e04739c4..387ee33894db 100644
> --- a/fs/ceph/super.h
> +++ b/fs/ceph/super.h
> @@ -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 */

This looks good, Kotresh. Nice work. I'll plan to merge this into
testing in the near term.

Before we merge this into mainline though, it would be good to have a
testcase that ensures that this works like we expect with these small
quotas.

Could you write something for teuthology?

Thanks,
Kotresh Hiremath Ravishankar Nov. 11, 2021, 7:02 a.m. UTC | #2
On Thu, Nov 11, 2021 at 12:48 AM Jeff Layton <jlayton@kernel.org> wrote:
>
> On Wed, 2021-11-10 at 23:30 +0530, khiremat@redhat.com wrote:
> > From: Kotresh HR <khiremat@redhat.com>
> >
> > 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>
> > ---
> >  fs/ceph/quota.c | 14 ++++++++++++++
> >  fs/ceph/super.h |  1 +
> >  2 files changed, 15 insertions(+)
> >
> > diff --git a/fs/ceph/quota.c b/fs/ceph/quota.c
> > index 620c691af40e..24ae13ea2241 100644
> > --- a/fs/ceph/quota.c
> > +++ b/fs/ceph/quota.c
> > @@ -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;
> > +                     }
>
> We really ought to have the MDS establish a floor for the quota size.
> <4k quota seems ridiculous.

Yes, I have opened a tracker for the same.
https://tracker.ceph.com/issues/53228
>
>
> >               }
> >               spin_unlock(&ci->i_ceph_lock);
> >               if (total) {
> > diff --git a/fs/ceph/super.h b/fs/ceph/super.h
> > index ed51e04739c4..387ee33894db 100644
> > --- a/fs/ceph/super.h
> > +++ b/fs/ceph/super.h
> > @@ -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 */
>
> This looks good, Kotresh. Nice work. I'll plan to merge this into
> testing in the near term.
>
> Before we merge this into mainline though, it would be good to have a
> testcase that ensures that this works like we expect with these small
> quotas.
>
> Could you write something for teuthology?

Sure, I will add a teuthology test for this.
>
>
> Thanks,
> --
> Jeff Layton <jlayton@kernel.org>
>
--
Thanks,
Kotresh HR
Xiubo Li Nov. 15, 2021, 2:53 a.m. UTC | #3
On 11/11/21 2:00 AM, khiremat@redhat.com wrote:
> From: Kotresh HR <khiremat@redhat.com>
>
> Problem:
> The statfs reports incorrect free/available space
> for quota less then CEPH_BLOCK size (4M).

s/then/than/


> 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>
> ---
>   fs/ceph/quota.c | 14 ++++++++++++++
>   fs/ceph/super.h |  1 +
>   2 files changed, 15 insertions(+)
>
> diff --git a/fs/ceph/quota.c b/fs/ceph/quota.c
> index 620c691af40e..24ae13ea2241 100644
> --- a/fs/ceph/quota.c
> +++ b/fs/ceph/quota.c
> @@ -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;

The 'buf->f_frsize' has already been assigned above, this could be removed.

Thanks

-- Xiubo

> +			}
>   		}
>   		spin_unlock(&ci->i_ceph_lock);
>   		if (total) {
> diff --git a/fs/ceph/super.h b/fs/ceph/super.h
> index ed51e04739c4..387ee33894db 100644
> --- a/fs/ceph/super.h
> +++ b/fs/ceph/super.h
> @@ -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 */
Kotresh Hiremath Ravishankar Nov. 15, 2021, 5:30 a.m. UTC | #4
On Mon, Nov 15, 2021 at 8:24 AM Xiubo Li <xiubli@redhat.com> wrote:
>
>
> On 11/11/21 2:00 AM, khiremat@redhat.com wrote:
> > From: Kotresh HR <khiremat@redhat.com>
> >
> > Problem:
> > The statfs reports incorrect free/available space
> > for quota less then CEPH_BLOCK size (4M).
>
> s/then/than/
>
>
> > 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>
> > ---
> >   fs/ceph/quota.c | 14 ++++++++++++++
> >   fs/ceph/super.h |  1 +
> >   2 files changed, 15 insertions(+)
> >
> > diff --git a/fs/ceph/quota.c b/fs/ceph/quota.c
> > index 620c691af40e..24ae13ea2241 100644
> > --- a/fs/ceph/quota.c
> > +++ b/fs/ceph/quota.c
> > @@ -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;
>
> The 'buf->f_frsize' has already been assigned above, this could be removed.
>
If the quota size is less than 4KB, the above assignment is not hit.
This is required.

> Thanks
>
> -- Xiubo
>
> > +                     }
> >               }
> >               spin_unlock(&ci->i_ceph_lock);
> >               if (total) {
> > diff --git a/fs/ceph/super.h b/fs/ceph/super.h
> > index ed51e04739c4..387ee33894db 100644
> > --- a/fs/ceph/super.h
> > +++ b/fs/ceph/super.h
> > @@ -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 */
>
Xiubo Li Nov. 15, 2021, 5:42 a.m. UTC | #5
On 11/15/21 1:30 PM, Kotresh Hiremath Ravishankar wrote:
> On Mon, Nov 15, 2021 at 8:24 AM Xiubo Li <xiubli@redhat.com> wrote:
>>
>> On 11/11/21 2:00 AM, khiremat@redhat.com wrote:
>>> From: Kotresh HR <khiremat@redhat.com>
>>>
>>> Problem:
>>> The statfs reports incorrect free/available space
>>> for quota less then CEPH_BLOCK size (4M).
>> s/then/than/
>>
>>
>>> 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>
>>> ---
>>>    fs/ceph/quota.c | 14 ++++++++++++++
>>>    fs/ceph/super.h |  1 +
>>>    2 files changed, 15 insertions(+)
>>>
>>> diff --git a/fs/ceph/quota.c b/fs/ceph/quota.c
>>> index 620c691af40e..24ae13ea2241 100644
>>> --- a/fs/ceph/quota.c
>>> +++ b/fs/ceph/quota.c
>>> @@ -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;

If the quota size is less than 4MB, the 'buf->f_frsize' will always be 
set here, including less than 4KB.


>>> +                     }
>>>                        /* 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;
>> The 'buf->f_frsize' has already been assigned above, this could be removed.
>>
> If the quota size is less than 4KB, the above assignment is not hit.
> This is required.
>
>> Thanks
>>
>> -- Xiubo
>>
>>> +                     }
>>>                }
>>>                spin_unlock(&ci->i_ceph_lock);
>>>                if (total) {
>>> diff --git a/fs/ceph/super.h b/fs/ceph/super.h
>>> index ed51e04739c4..387ee33894db 100644
>>> --- a/fs/ceph/super.h
>>> +++ b/fs/ceph/super.h
>>> @@ -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 */
>
Kotresh Hiremath Ravishankar Nov. 15, 2021, 6:31 a.m. UTC | #6
On Mon, Nov 15, 2021 at 11:12 AM Xiubo Li <xiubli@redhat.com> wrote:
>
>
> On 11/15/21 1:30 PM, Kotresh Hiremath Ravishankar wrote:
> > On Mon, Nov 15, 2021 at 8:24 AM Xiubo Li <xiubli@redhat.com> wrote:
> >>
> >> On 11/11/21 2:00 AM, khiremat@redhat.com wrote:
> >>> From: Kotresh HR <khiremat@redhat.com>
> >>>
> >>> Problem:
> >>> The statfs reports incorrect free/available space
> >>> for quota less then CEPH_BLOCK size (4M).
> >> s/then/than/
> >>
> >>
> >>> 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>
> >>> ---
> >>>    fs/ceph/quota.c | 14 ++++++++++++++
> >>>    fs/ceph/super.h |  1 +
> >>>    2 files changed, 15 insertions(+)
> >>>
> >>> diff --git a/fs/ceph/quota.c b/fs/ceph/quota.c
> >>> index 620c691af40e..24ae13ea2241 100644
> >>> --- a/fs/ceph/quota.c
> >>> +++ b/fs/ceph/quota.c
> >>> @@ -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;
>
> If the quota size is less than 4MB, the 'buf->f_frsize' will always be
> set here, including less than 4KB.
Yes, sorry for the confusion. I will address this.
>
>
> >>> +                     }
> >>>                        /* 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;
> >> The 'buf->f_frsize' has already been assigned above, this could be removed.
> >>
> > If the quota size is less than 4KB, the above assignment is not hit.
> > This is required.
> >
> >> Thanks
> >>
> >> -- Xiubo
> >>
> >>> +                     }
> >>>                }
> >>>                spin_unlock(&ci->i_ceph_lock);
> >>>                if (total) {
> >>> diff --git a/fs/ceph/super.h b/fs/ceph/super.h
> >>> index ed51e04739c4..387ee33894db 100644
> >>> --- a/fs/ceph/super.h
> >>> +++ b/fs/ceph/super.h
> >>> @@ -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 */
> >
>
diff mbox series

Patch

diff --git a/fs/ceph/quota.c b/fs/ceph/quota.c
index 620c691af40e..24ae13ea2241 100644
--- a/fs/ceph/quota.c
+++ b/fs/ceph/quota.c
@@ -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) {
diff --git a/fs/ceph/super.h b/fs/ceph/super.h
index ed51e04739c4..387ee33894db 100644
--- a/fs/ceph/super.h
+++ b/fs/ceph/super.h
@@ -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 */