[v2,5/5] ceph: handle inlined files in copy_file_range
diff mbox series

Message ID 20190711184136.19779-6-jlayton@kernel.org
State New
Headers show
Series
  • ceph: fix races when uninlining data
Related show

Commit Message

Jeff Layton July 11, 2019, 6:41 p.m. UTC
If the src is inlined, then just bail out. Have it attempt to uninline
the dst file however.

Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
 fs/ceph/file.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

Comments

Yan, Zheng July 12, 2019, 2:46 a.m. UTC | #1
On Fri, Jul 12, 2019 at 3:17 AM Jeff Layton <jlayton@kernel.org> wrote:
>
> If the src is inlined, then just bail out. Have it attempt to uninline
> the dst file however.
>
> Signed-off-by: Jeff Layton <jlayton@kernel.org>
> ---
>  fs/ceph/file.c | 13 ++++++++++++-
>  1 file changed, 12 insertions(+), 1 deletion(-)
>
> diff --git a/fs/ceph/file.c b/fs/ceph/file.c
> index 252aac44b8ce..774f51b0b63d 100644
> --- a/fs/ceph/file.c
> +++ b/fs/ceph/file.c
> @@ -1934,6 +1934,10 @@ static ssize_t ceph_copy_file_range(struct file *src_file, loff_t src_off,
>         if (len < src_ci->i_layout.object_size)
>                 return -EOPNOTSUPP; /* no remote copy will be done */
>
> +       /* Fall back if src file is inlined */
> +       if (READ_ONCE(src_ci->i_inline_version) != CEPH_INLINE_NONE)
> +               return -EOPNOTSUPP;
> +
>         prealloc_cf = ceph_alloc_cap_flush();
>         if (!prealloc_cf)
>                 return -ENOMEM;
> @@ -1967,6 +1971,13 @@ static ssize_t ceph_copy_file_range(struct file *src_file, loff_t src_off,
>         if (ret < 0)
>                 goto out_caps;
>
> +       /* uninline the dst inode */
> +       dirty = ceph_uninline_data(dst_inode, NULL);
> +       if (dirty < 0) {
> +               ret = dirty;
> +               goto out_caps;
> +       }
> +
>         size = i_size_read(dst_inode);
>         endoff = dst_off + len;
>
> @@ -2080,7 +2091,7 @@ static ssize_t ceph_copy_file_range(struct file *src_file, loff_t src_off,
>         /* Mark Fw dirty */
>         spin_lock(&dst_ci->i_ceph_lock);
>         dst_ci->i_inline_version = CEPH_INLINE_NONE;
remove this line

> -       dirty = __ceph_mark_dirty_caps(dst_ci, CEPH_CAP_FILE_WR, &prealloc_cf);
> +       dirty |= __ceph_mark_dirty_caps(dst_ci, CEPH_CAP_FILE_WR, &prealloc_cf);
>         spin_unlock(&dst_ci->i_ceph_lock);
>         if (dirty)
>                 __mark_inode_dirty(dst_inode, dirty);
> --
> 2.21.0
>
Jeff Layton July 12, 2019, 10:19 a.m. UTC | #2
On Fri, 2019-07-12 at 10:46 +0800, Yan, Zheng wrote:
> On Fri, Jul 12, 2019 at 3:17 AM Jeff Layton <jlayton@kernel.org> wrote:
> > If the src is inlined, then just bail out. Have it attempt to uninline
> > the dst file however.
> > 
> > Signed-off-by: Jeff Layton <jlayton@kernel.org>
> > ---
> >  fs/ceph/file.c | 13 ++++++++++++-
> >  1 file changed, 12 insertions(+), 1 deletion(-)
> > 
> > diff --git a/fs/ceph/file.c b/fs/ceph/file.c
> > index 252aac44b8ce..774f51b0b63d 100644
> > --- a/fs/ceph/file.c
> > +++ b/fs/ceph/file.c
> > @@ -1934,6 +1934,10 @@ static ssize_t ceph_copy_file_range(struct file *src_file, loff_t src_off,
> >         if (len < src_ci->i_layout.object_size)
> >                 return -EOPNOTSUPP; /* no remote copy will be done */
> > 
> > +       /* Fall back if src file is inlined */
> > +       if (READ_ONCE(src_ci->i_inline_version) != CEPH_INLINE_NONE)
> > +               return -EOPNOTSUPP;
> > +
> >         prealloc_cf = ceph_alloc_cap_flush();
> >         if (!prealloc_cf)
> >                 return -ENOMEM;
> > @@ -1967,6 +1971,13 @@ static ssize_t ceph_copy_file_range(struct file *src_file, loff_t src_off,
> >         if (ret < 0)
> >                 goto out_caps;
> > 
> > +       /* uninline the dst inode */
> > +       dirty = ceph_uninline_data(dst_inode, NULL);
> > +       if (dirty < 0) {
> > +               ret = dirty;
> > +               goto out_caps;
> > +       }
> > +
> >         size = i_size_read(dst_inode);
> >         endoff = dst_off + len;
> > 
> > @@ -2080,7 +2091,7 @@ static ssize_t ceph_copy_file_range(struct file *src_file, loff_t src_off,
> >         /* Mark Fw dirty */
> >         spin_lock(&dst_ci->i_ceph_lock);
> >         dst_ci->i_inline_version = CEPH_INLINE_NONE;
> remove this line
> 

Good catch. Looks like I left another one too in ceph_aio_complete. I'll
remove that one as well.

> > -       dirty = __ceph_mark_dirty_caps(dst_ci, CEPH_CAP_FILE_WR, &prealloc_cf);
> > +       dirty |= __ceph_mark_dirty_caps(dst_ci, CEPH_CAP_FILE_WR, &prealloc_cf);
> >         spin_unlock(&dst_ci->i_ceph_lock);
> >         if (dirty)
> >                 __mark_inode_dirty(dst_inode, dirty);
> > --
> > 2.21.0
> >

Patch
diff mbox series

diff --git a/fs/ceph/file.c b/fs/ceph/file.c
index 252aac44b8ce..774f51b0b63d 100644
--- a/fs/ceph/file.c
+++ b/fs/ceph/file.c
@@ -1934,6 +1934,10 @@  static ssize_t ceph_copy_file_range(struct file *src_file, loff_t src_off,
 	if (len < src_ci->i_layout.object_size)
 		return -EOPNOTSUPP; /* no remote copy will be done */
 
+	/* Fall back if src file is inlined */
+	if (READ_ONCE(src_ci->i_inline_version) != CEPH_INLINE_NONE)
+		return -EOPNOTSUPP;
+
 	prealloc_cf = ceph_alloc_cap_flush();
 	if (!prealloc_cf)
 		return -ENOMEM;
@@ -1967,6 +1971,13 @@  static ssize_t ceph_copy_file_range(struct file *src_file, loff_t src_off,
 	if (ret < 0)
 		goto out_caps;
 
+	/* uninline the dst inode */
+	dirty = ceph_uninline_data(dst_inode, NULL);
+	if (dirty < 0) {
+		ret = dirty;
+		goto out_caps;
+	}
+
 	size = i_size_read(dst_inode);
 	endoff = dst_off + len;
 
@@ -2080,7 +2091,7 @@  static ssize_t ceph_copy_file_range(struct file *src_file, loff_t src_off,
 	/* Mark Fw dirty */
 	spin_lock(&dst_ci->i_ceph_lock);
 	dst_ci->i_inline_version = CEPH_INLINE_NONE;
-	dirty = __ceph_mark_dirty_caps(dst_ci, CEPH_CAP_FILE_WR, &prealloc_cf);
+	dirty |= __ceph_mark_dirty_caps(dst_ci, CEPH_CAP_FILE_WR, &prealloc_cf);
 	spin_unlock(&dst_ci->i_ceph_lock);
 	if (dirty)
 		__mark_inode_dirty(dst_inode, dirty);