| From fa60ee4c50be3d6bfd05824790fd8a83976361af Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Wed, 11 Aug 2021 06:40:42 -0400 |
| Subject: ceph: request Fw caps before updating the mtime in ceph_write_iter |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| From: Jeff Layton <jlayton@kernel.org> |
| |
| [ Upstream commit b11ed50346683a749632ea664959b28d524d7395 ] |
| |
| The current code will update the mtime and then try to get caps to |
| handle the write. If we end up having to request caps from the MDS, then |
| the mtime in the cap grant will clobber the updated mtime and it'll be |
| lost. |
| |
| This is most noticable when two clients are alternately writing to the |
| same file. Fw caps are continually being granted and revoked, and the |
| mtime ends up stuck because the updated mtimes are always being |
| overwritten with the old one. |
| |
| Fix this by changing the order of operations in ceph_write_iter to get |
| the caps before updating the times. Also, make sure we check the pool |
| full conditions before even getting any caps or uninlining. |
| |
| URL: https://tracker.ceph.com/issues/46574 |
| Reported-by: Jozef Kováč <kovac@firma.zoznam.sk> |
| Signed-off-by: Jeff Layton <jlayton@kernel.org> |
| Reviewed-by: Xiubo Li <xiubli@redhat.com> |
| Reviewed-by: Luis Henriques <lhenriques@suse.de> |
| Signed-off-by: Ilya Dryomov <idryomov@gmail.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| fs/ceph/file.c | 32 +++++++++++++++++--------------- |
| 1 file changed, 17 insertions(+), 15 deletions(-) |
| |
| diff --git a/fs/ceph/file.c b/fs/ceph/file.c |
| index d1755ac1d964..3daebfaec8c6 100644 |
| --- a/fs/ceph/file.c |
| +++ b/fs/ceph/file.c |
| @@ -1722,32 +1722,26 @@ retry_snap: |
| goto out; |
| } |
| |
| - err = file_remove_privs(file); |
| - if (err) |
| + down_read(&osdc->lock); |
| + map_flags = osdc->osdmap->flags; |
| + pool_flags = ceph_pg_pool_flags(osdc->osdmap, ci->i_layout.pool_id); |
| + up_read(&osdc->lock); |
| + if ((map_flags & CEPH_OSDMAP_FULL) || |
| + (pool_flags & CEPH_POOL_FLAG_FULL)) { |
| + err = -ENOSPC; |
| goto out; |
| + } |
| |
| - err = file_update_time(file); |
| + err = file_remove_privs(file); |
| if (err) |
| goto out; |
| |
| - inode_inc_iversion_raw(inode); |
| - |
| if (ci->i_inline_version != CEPH_INLINE_NONE) { |
| err = ceph_uninline_data(file, NULL); |
| if (err < 0) |
| goto out; |
| } |
| |
| - down_read(&osdc->lock); |
| - map_flags = osdc->osdmap->flags; |
| - pool_flags = ceph_pg_pool_flags(osdc->osdmap, ci->i_layout.pool_id); |
| - up_read(&osdc->lock); |
| - if ((map_flags & CEPH_OSDMAP_FULL) || |
| - (pool_flags & CEPH_POOL_FLAG_FULL)) { |
| - err = -ENOSPC; |
| - goto out; |
| - } |
| - |
| dout("aio_write %p %llx.%llx %llu~%zd getting caps. i_size %llu\n", |
| inode, ceph_vinop(inode), pos, count, i_size_read(inode)); |
| if (fi->fmode & CEPH_FILE_MODE_LAZY) |
| @@ -1759,6 +1753,12 @@ retry_snap: |
| if (err < 0) |
| goto out; |
| |
| + err = file_update_time(file); |
| + if (err) |
| + goto out_caps; |
| + |
| + inode_inc_iversion_raw(inode); |
| + |
| dout("aio_write %p %llx.%llx %llu~%zd got cap refs on %s\n", |
| inode, ceph_vinop(inode), pos, count, ceph_cap_string(got)); |
| |
| @@ -1842,6 +1842,8 @@ retry_snap: |
| } |
| |
| goto out_unlocked; |
| +out_caps: |
| + ceph_put_cap_refs(ci, got); |
| out: |
| if (direct_lock) |
| ceph_end_io_direct(inode); |
| -- |
| 2.33.0 |
| |