linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] ceph: only allow punch hole mode in fallocate
@ 2018-10-09 17:54 Luis Henriques
  2018-10-10  4:20 ` Yan, Zheng
  0 siblings, 1 reply; 5+ messages in thread
From: Luis Henriques @ 2018-10-09 17:54 UTC (permalink / raw)
  To: Yan, Zheng, Sage Weil, Ilya Dryomov
  Cc: ceph-devel, linux-kernel, Luis Henriques

Current implementation of cephfs fallocate isn't correct as it doesn't
really reserve the space in the cluster, which means that a subsequent
call to a write may actually fail due to lack of space.  In fact, it is
currently possible to fallocate an amount space that is larger than the
free space in the cluster.

Since there's no easy solution to fix this at the moment, this patch
simply removes support for all fallocate operations but
FALLOC_FL_PUNCH_HOLE (which implies FALLOC_FL_KEEP_SIZE).

Link: https://tracker.ceph.com/issues/36317
Cc: stable@vger.kernel.org
Fixes: ad7a60de882a ("ceph: punch hole support")
Signed-off-by: Luis Henriques <lhenriques@suse.com>
---
 fs/ceph/file.c | 45 +++++++++------------------------------------
 1 file changed, 9 insertions(+), 36 deletions(-)

diff --git a/fs/ceph/file.c b/fs/ceph/file.c
index 92ab20433682..91a7ad259bcf 100644
--- a/fs/ceph/file.c
+++ b/fs/ceph/file.c
@@ -1735,7 +1735,6 @@ static long ceph_fallocate(struct file *file, int mode,
 	struct ceph_file_info *fi = file->private_data;
 	struct inode *inode = file_inode(file);
 	struct ceph_inode_info *ci = ceph_inode(inode);
-	struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
 	struct ceph_cap_flush *prealloc_cf;
 	int want, got = 0;
 	int dirty;
@@ -1743,10 +1742,7 @@ static long ceph_fallocate(struct file *file, int mode,
 	loff_t endoff = 0;
 	loff_t size;
 
-	if ((offset + length) > max(i_size_read(inode), fsc->max_file_size))
-		return -EFBIG;
-
-	if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE))
+	if (mode != (FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE))
 		return -EOPNOTSUPP;
 
 	if (!S_ISREG(inode->i_mode))
@@ -1763,18 +1759,6 @@ static long ceph_fallocate(struct file *file, int mode,
 		goto unlock;
 	}
 
-	if (!(mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE)) &&
-	    ceph_quota_is_max_bytes_exceeded(inode, offset + length)) {
-		ret = -EDQUOT;
-		goto unlock;
-	}
-
-	if (ceph_osdmap_flag(&fsc->client->osdc, CEPH_OSDMAP_FULL) &&
-	    !(mode & FALLOC_FL_PUNCH_HOLE)) {
-		ret = -ENOSPC;
-		goto unlock;
-	}
-
 	if (ci->i_inline_version != CEPH_INLINE_NONE) {
 		ret = ceph_uninline_data(file, NULL);
 		if (ret < 0)
@@ -1782,12 +1766,12 @@ static long ceph_fallocate(struct file *file, int mode,
 	}
 
 	size = i_size_read(inode);
-	if (!(mode & FALLOC_FL_KEEP_SIZE)) {
-		endoff = offset + length;
-		ret = inode_newsize_ok(inode, endoff);
-		if (ret)
-			goto unlock;
-	}
+
+	/* Are we punching a hole beyond EOF? */
+	if (offset >= size)
+		goto unlock;
+	if ((offset + length) > size)
+		length = size - offset;
 
 	if (fi->fmode & CEPH_FILE_MODE_LAZY)
 		want = CEPH_CAP_FILE_BUFFER | CEPH_CAP_FILE_LAZYIO;
@@ -1798,16 +1782,8 @@ static long ceph_fallocate(struct file *file, int mode,
 	if (ret < 0)
 		goto unlock;
 
-	if (mode & FALLOC_FL_PUNCH_HOLE) {
-		if (offset < size)
-			ceph_zero_pagecache_range(inode, offset, length);
-		ret = ceph_zero_objects(inode, offset, length);
-	} else if (endoff > size) {
-		truncate_pagecache_range(inode, size, -1);
-		if (ceph_inode_set_size(inode, endoff))
-			ceph_check_caps(ceph_inode(inode),
-				CHECK_CAPS_AUTHONLY, NULL);
-	}
+	ceph_zero_pagecache_range(inode, offset, length);
+	ret = ceph_zero_objects(inode, offset, length);
 
 	if (!ret) {
 		spin_lock(&ci->i_ceph_lock);
@@ -1817,9 +1793,6 @@ 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);

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH] ceph: only allow punch hole mode in fallocate
  2018-10-09 17:54 [PATCH] ceph: only allow punch hole mode in fallocate Luis Henriques
@ 2018-10-10  4:20 ` Yan, Zheng
  2018-10-10 10:43   ` Ilya Dryomov
  0 siblings, 1 reply; 5+ messages in thread
From: Yan, Zheng @ 2018-10-10  4:20 UTC (permalink / raw)
  To: Luis Henriques
  Cc: Zheng Yan, Sage Weil, Ilya Dryomov, ceph-devel,
	Linux Kernel Mailing List

On Wed, Oct 10, 2018 at 1:54 AM Luis Henriques <lhenriques@suse.com> wrote:
>
> Current implementation of cephfs fallocate isn't correct as it doesn't
> really reserve the space in the cluster, which means that a subsequent
> call to a write may actually fail due to lack of space.  In fact, it is
> currently possible to fallocate an amount space that is larger than the
> free space in the cluster.
>
> Since there's no easy solution to fix this at the moment, this patch
> simply removes support for all fallocate operations but
> FALLOC_FL_PUNCH_HOLE (which implies FALLOC_FL_KEEP_SIZE).
>
> Link: https://tracker.ceph.com/issues/36317
> Cc: stable@vger.kernel.org
> Fixes: ad7a60de882a ("ceph: punch hole support")
> Signed-off-by: Luis Henriques <lhenriques@suse.com>
> ---
>  fs/ceph/file.c | 45 +++++++++------------------------------------
>  1 file changed, 9 insertions(+), 36 deletions(-)
>
> diff --git a/fs/ceph/file.c b/fs/ceph/file.c
> index 92ab20433682..91a7ad259bcf 100644
> --- a/fs/ceph/file.c
> +++ b/fs/ceph/file.c
> @@ -1735,7 +1735,6 @@ static long ceph_fallocate(struct file *file, int mode,
>         struct ceph_file_info *fi = file->private_data;
>         struct inode *inode = file_inode(file);
>         struct ceph_inode_info *ci = ceph_inode(inode);
> -       struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
>         struct ceph_cap_flush *prealloc_cf;
>         int want, got = 0;
>         int dirty;
> @@ -1743,10 +1742,7 @@ static long ceph_fallocate(struct file *file, int mode,
>         loff_t endoff = 0;
>         loff_t size;
>
> -       if ((offset + length) > max(i_size_read(inode), fsc->max_file_size))
> -               return -EFBIG;
> -
> -       if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE))
> +       if (mode != (FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE))
>                 return -EOPNOTSUPP;
>
>         if (!S_ISREG(inode->i_mode))
> @@ -1763,18 +1759,6 @@ static long ceph_fallocate(struct file *file, int mode,
>                 goto unlock;
>         }
>
> -       if (!(mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE)) &&
> -           ceph_quota_is_max_bytes_exceeded(inode, offset + length)) {
> -               ret = -EDQUOT;
> -               goto unlock;
> -       }
> -
> -       if (ceph_osdmap_flag(&fsc->client->osdc, CEPH_OSDMAP_FULL) &&
> -           !(mode & FALLOC_FL_PUNCH_HOLE)) {
> -               ret = -ENOSPC;
> -               goto unlock;
> -       }
> -
>         if (ci->i_inline_version != CEPH_INLINE_NONE) {
>                 ret = ceph_uninline_data(file, NULL);
>                 if (ret < 0)
> @@ -1782,12 +1766,12 @@ static long ceph_fallocate(struct file *file, int mode,
>         }
>
>         size = i_size_read(inode);
> -       if (!(mode & FALLOC_FL_KEEP_SIZE)) {
> -               endoff = offset + length;
> -               ret = inode_newsize_ok(inode, endoff);
> -               if (ret)
> -                       goto unlock;
> -       }
> +
> +       /* Are we punching a hole beyond EOF? */
> +       if (offset >= size)
> +               goto unlock;
> +       if ((offset + length) > size)
> +               length = size - offset;
>
>         if (fi->fmode & CEPH_FILE_MODE_LAZY)
>                 want = CEPH_CAP_FILE_BUFFER | CEPH_CAP_FILE_LAZYIO;
> @@ -1798,16 +1782,8 @@ static long ceph_fallocate(struct file *file, int mode,
>         if (ret < 0)
>                 goto unlock;
>
> -       if (mode & FALLOC_FL_PUNCH_HOLE) {
> -               if (offset < size)
> -                       ceph_zero_pagecache_range(inode, offset, length);
> -               ret = ceph_zero_objects(inode, offset, length);
> -       } else if (endoff > size) {
> -               truncate_pagecache_range(inode, size, -1);
> -               if (ceph_inode_set_size(inode, endoff))
> -                       ceph_check_caps(ceph_inode(inode),
> -                               CHECK_CAPS_AUTHONLY, NULL);
> -       }
> +       ceph_zero_pagecache_range(inode, offset, length);
> +       ret = ceph_zero_objects(inode, offset, length);
>
>         if (!ret) {
>                 spin_lock(&ci->i_ceph_lock);
> @@ -1817,9 +1793,6 @@ 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);

Applied, thanks

Yan, Zheng

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] ceph: only allow punch hole mode in fallocate
  2018-10-10  4:20 ` Yan, Zheng
@ 2018-10-10 10:43   ` Ilya Dryomov
  2018-10-10 11:20     ` Luis Henriques
  0 siblings, 1 reply; 5+ messages in thread
From: Ilya Dryomov @ 2018-10-10 10:43 UTC (permalink / raw)
  To: Yan, Zheng
  Cc: Luis Henriques, Yan, Zheng, Sage Weil, Ceph Development, linux-kernel

On Wed, Oct 10, 2018 at 6:21 AM Yan, Zheng <ukernel@gmail.com> wrote:
>
> On Wed, Oct 10, 2018 at 1:54 AM Luis Henriques <lhenriques@suse.com> wrote:
> >
> > Current implementation of cephfs fallocate isn't correct as it doesn't
> > really reserve the space in the cluster, which means that a subsequent
> > call to a write may actually fail due to lack of space.  In fact, it is
> > currently possible to fallocate an amount space that is larger than the
> > free space in the cluster.
> >
> > Since there's no easy solution to fix this at the moment, this patch
> > simply removes support for all fallocate operations but
> > FALLOC_FL_PUNCH_HOLE (which implies FALLOC_FL_KEEP_SIZE).
> >
> > Link: https://tracker.ceph.com/issues/36317
> > Cc: stable@vger.kernel.org
> > Fixes: ad7a60de882a ("ceph: punch hole support")
> > Signed-off-by: Luis Henriques <lhenriques@suse.com>
> > ---
> >  fs/ceph/file.c | 45 +++++++++------------------------------------
> >  1 file changed, 9 insertions(+), 36 deletions(-)
> >
> > diff --git a/fs/ceph/file.c b/fs/ceph/file.c
> > index 92ab20433682..91a7ad259bcf 100644
> > --- a/fs/ceph/file.c
> > +++ b/fs/ceph/file.c
> > @@ -1735,7 +1735,6 @@ static long ceph_fallocate(struct file *file, int mode,
> >         struct ceph_file_info *fi = file->private_data;
> >         struct inode *inode = file_inode(file);
> >         struct ceph_inode_info *ci = ceph_inode(inode);
> > -       struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
> >         struct ceph_cap_flush *prealloc_cf;
> >         int want, got = 0;
> >         int dirty;
> > @@ -1743,10 +1742,7 @@ static long ceph_fallocate(struct file *file, int mode,
> >         loff_t endoff = 0;
> >         loff_t size;
> >
> > -       if ((offset + length) > max(i_size_read(inode), fsc->max_file_size))
> > -               return -EFBIG;
> > -
> > -       if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE))
> > +       if (mode != (FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE))
> >                 return -EOPNOTSUPP;
> >
> >         if (!S_ISREG(inode->i_mode))
> > @@ -1763,18 +1759,6 @@ static long ceph_fallocate(struct file *file, int mode,
> >                 goto unlock;
> >         }
> >
> > -       if (!(mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE)) &&
> > -           ceph_quota_is_max_bytes_exceeded(inode, offset + length)) {
> > -               ret = -EDQUOT;
> > -               goto unlock;
> > -       }
> > -
> > -       if (ceph_osdmap_flag(&fsc->client->osdc, CEPH_OSDMAP_FULL) &&
> > -           !(mode & FALLOC_FL_PUNCH_HOLE)) {
> > -               ret = -ENOSPC;
> > -               goto unlock;
> > -       }
> > -
> >         if (ci->i_inline_version != CEPH_INLINE_NONE) {
> >                 ret = ceph_uninline_data(file, NULL);
> >                 if (ret < 0)
> > @@ -1782,12 +1766,12 @@ static long ceph_fallocate(struct file *file, int mode,
> >         }
> >
> >         size = i_size_read(inode);
> > -       if (!(mode & FALLOC_FL_KEEP_SIZE)) {
> > -               endoff = offset + length;
> > -               ret = inode_newsize_ok(inode, endoff);
> > -               if (ret)
> > -                       goto unlock;
> > -       }
> > +
> > +       /* Are we punching a hole beyond EOF? */
> > +       if (offset >= size)
> > +               goto unlock;
> > +       if ((offset + length) > size)
> > +               length = size - offset;
> >
> >         if (fi->fmode & CEPH_FILE_MODE_LAZY)
> >                 want = CEPH_CAP_FILE_BUFFER | CEPH_CAP_FILE_LAZYIO;
> > @@ -1798,16 +1782,8 @@ static long ceph_fallocate(struct file *file, int mode,
> >         if (ret < 0)
> >                 goto unlock;
> >
> > -       if (mode & FALLOC_FL_PUNCH_HOLE) {
> > -               if (offset < size)
> > -                       ceph_zero_pagecache_range(inode, offset, length);
> > -               ret = ceph_zero_objects(inode, offset, length);
> > -       } else if (endoff > size) {
> > -               truncate_pagecache_range(inode, size, -1);
> > -               if (ceph_inode_set_size(inode, endoff))
> > -                       ceph_check_caps(ceph_inode(inode),
> > -                               CHECK_CAPS_AUTHONLY, NULL);
> > -       }
> > +       ceph_zero_pagecache_range(inode, offset, length);
> > +       ret = ceph_zero_objects(inode, offset, length);
> >
> >         if (!ret) {
> >                 spin_lock(&ci->i_ceph_lock);
> > @@ -1817,9 +1793,6 @@ 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);
>
> Applied, thanks

I don't think it should go to stable kernels.  Strictly speaking it's
a behaviour change -- it's been this way for many years and, unless you
are close to ENOSPC, it's sort of appears to work.  I'll take off the
stable tag unless I hear objections.

Thanks,

                Ilya

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] ceph: only allow punch hole mode in fallocate
  2018-10-10 10:43   ` Ilya Dryomov
@ 2018-10-10 11:20     ` Luis Henriques
  2018-10-10 11:46       ` Ilya Dryomov
  0 siblings, 1 reply; 5+ messages in thread
From: Luis Henriques @ 2018-10-10 11:20 UTC (permalink / raw)
  To: Ilya Dryomov
  Cc: Yan, Zheng, Yan, Zheng, Sage Weil, Ceph Development, linux-kernel

Ilya Dryomov <idryomov@gmail.com> writes:

> On Wed, Oct 10, 2018 at 6:21 AM Yan, Zheng <ukernel@gmail.com> wrote:
>>
>> On Wed, Oct 10, 2018 at 1:54 AM Luis Henriques <lhenriques@suse.com> wrote:

<snip>

>> Applied, thanks
>
> I don't think it should go to stable kernels.  Strictly speaking it's
> a behaviour change -- it's been this way for many years and, unless you
> are close to ENOSPC, it's sort of appears to work.  I'll take off the
> stable tag unless I hear objections.

Right, it can in fact break applications that rely on the previous
(bogus) behaviour.  But it can also be claimed that it *will* break
applications anyway with an updated kernel, so backporting it to older
kernels will just allow a consistent behaviour.

Anyway, I'm OK either way.  But if you drop the stable tag make sure you
also remove the 'Fixes:' tag as I believe the stable folks will still
pick this patch if it includes a valid SHA1 in it.

Cheers,
-- 
Luis

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] ceph: only allow punch hole mode in fallocate
  2018-10-10 11:20     ` Luis Henriques
@ 2018-10-10 11:46       ` Ilya Dryomov
  0 siblings, 0 replies; 5+ messages in thread
From: Ilya Dryomov @ 2018-10-10 11:46 UTC (permalink / raw)
  To: Luis Henriques
  Cc: Yan, Zheng, Yan, Zheng, Sage Weil, Ceph Development, linux-kernel

On Wed, Oct 10, 2018 at 1:19 PM Luis Henriques <lhenriques@suse.com> wrote:
>
> Ilya Dryomov <idryomov@gmail.com> writes:
>
> > On Wed, Oct 10, 2018 at 6:21 AM Yan, Zheng <ukernel@gmail.com> wrote:
> >>
> >> On Wed, Oct 10, 2018 at 1:54 AM Luis Henriques <lhenriques@suse.com> wrote:
>
> <snip>
>
> >> Applied, thanks
> >
> > I don't think it should go to stable kernels.  Strictly speaking it's
> > a behaviour change -- it's been this way for many years and, unless you
> > are close to ENOSPC, it's sort of appears to work.  I'll take off the
> > stable tag unless I hear objections.
>
> Right, it can in fact break applications that rely on the previous
> (bogus) behaviour.  But it can also be claimed that it *will* break
> applications anyway with an updated kernel, so backporting it to older
> kernels will just allow a consistent behaviour.
>
> Anyway, I'm OK either way.  But if you drop the stable tag make sure you
> also remove the 'Fixes:' tag as I believe the stable folks will still
> pick this patch if it includes a valid SHA1 in it.

Yeah, we've run into this in the past.

Thanks,

                Ilya

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2018-10-10 11:47 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-10-09 17:54 [PATCH] ceph: only allow punch hole mode in fallocate Luis Henriques
2018-10-10  4:20 ` Yan, Zheng
2018-10-10 10:43   ` Ilya Dryomov
2018-10-10 11:20     ` Luis Henriques
2018-10-10 11:46       ` Ilya Dryomov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).