From d82ab84cfd5499eb704906c7dcecc2b4aa9f3651 Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Fri, 3 Feb 2023 09:58:29 +0800 Subject: [PATCH] [DO NOT MERGE] ceph: BUG if MDS changed truncate_seq with client caps still outstanding We need to trigger to crash the kernel and fail the qa tests to get more infomation about the bug. URL: https://tracker.ceph.com/issues/56693 Signed-off-by: Xiubo Li --- fs/ceph/caps.c | 5 +++-- fs/ceph/inode.c | 21 ++++++++++++++++----- fs/ceph/super.h | 3 ++- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 5e7c9bd4dfa2c..8d49df60f442d 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -3656,7 +3656,7 @@ static void handle_cap_grant(struct inode *inode, queue_trunc = ceph_fill_file_size(inode, extra_info->issued, le32_to_cpu(grant->truncate_seq), le64_to_cpu(grant->truncate_size), - size); + size, newcaps); } if (ci->i_auth_cap == cap && (newcaps & CEPH_CAP_ANY_FILE_WR)) { @@ -4056,7 +4056,8 @@ static bool handle_cap_trunc(struct inode *inode, doutc(cl, "%p %llx.%llx mds%d seq %d to %lld truncate seq %d\n", inode, ceph_vinop(inode), mds, seq, truncate_size, truncate_seq); queue_trunc = ceph_fill_file_size(inode, issued, - truncate_seq, truncate_size, size); + truncate_seq, truncate_size, + size, 0); return queue_trunc; } diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index c46fa6ed11c19..130bb3d66be66 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "super.h" #include "mds_client.h" @@ -756,7 +757,8 @@ static inline blkcnt_t calc_inode_blocks(u64 size) * truncate() increments the corresponding _seq values.) */ int ceph_fill_file_size(struct inode *inode, int issued, - u32 truncate_seq, u64 truncate_size, u64 size) + u32 truncate_seq, u64 truncate_size, + u64 size, int newcaps) { struct ceph_client *cl = ceph_inode_to_client(inode); struct ceph_inode_info *ci = ceph_inode(inode); @@ -780,13 +782,22 @@ int ceph_fill_file_size(struct inode *inode, int issued, ceph_fscache_update(inode); ci->i_reported_size = size; if (truncate_seq != ci->i_truncate_seq) { + /* the MDS should have revoked these caps */ + if (issued & (CEPH_CAP_FILE_RD | + CEPH_CAP_FILE_LAZYIO)) { + pr_err_client(cl, "%p ino %llx.%llx already issued %s, newcaps %s\n", + inode, ceph_vinop(inode), + ceph_cap_string(issued), + ceph_cap_string(newcaps)); + pr_err_client(cl, " truncate_seq %u -> %u\n", + ci->i_truncate_seq, truncate_seq); + pr_err_client(cl, " size %lld -> %llu\n", isize, size); + WARN_ON(1); + } doutc(cl, "truncate_seq %u -> %u\n", ci->i_truncate_seq, truncate_seq); ci->i_truncate_seq = truncate_seq; - /* the MDS should have revoked these caps */ - WARN_ON_ONCE(issued & (CEPH_CAP_FILE_RD | - CEPH_CAP_FILE_LAZYIO)); /* * If we hold relevant caps, or in the case where we're * not the only client referencing this file and we @@ -1127,7 +1138,7 @@ int ceph_fill_inode(struct inode *inode, struct page *locked_page, queue_trunc = ceph_fill_file_size(inode, issued, le32_to_cpu(info->truncate_seq), le64_to_cpu(info->truncate_size), - size); + size, info_caps); /* only update max_size on auth cap */ if ((info->cap.flags & CEPH_CAP_FLAG_AUTH) && ci->i_max_size != le64_to_cpu(info->max_size)) { diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 4a54fc273ec1d..0dfe5557de91a 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -1042,7 +1042,8 @@ extern struct inode *ceph_get_inode(struct super_block *sb, struct inode *newino); extern struct inode *ceph_get_snapdir(struct inode *parent); extern int ceph_fill_file_size(struct inode *inode, int issued, - u32 truncate_seq, u64 truncate_size, u64 size); + u32 truncate_seq, u64 truncate_size, + u64 size, int newcaps); extern void ceph_fill_file_time(struct inode *inode, int issued, u64 time_warp_seq, struct timespec64 *ctime, struct timespec64 *mtime, -- 2.39.5