Skip to content

Commit 31634d7

Browse files
lxbszidryomov
authored andcommitted
ceph: force sending a cap update msg back to MDS for revoke op
If a client sends out a cap update dropping caps with the prior 'seq' just before an incoming cap revoke request, then the client may drop the revoke because it believes it's already released the requested capabilities. This causes the MDS to wait indefinitely for the client to respond to the revoke. It's therefore always a good idea to ack the cap revoke request with the bumped up 'seq'. Currently if the cap->issued equals to the newcaps the check_caps() will do nothing, we should force flush the caps. Cc: [email protected] Link: https://tracker.ceph.com/issues/61782 Signed-off-by: Xiubo Li <[email protected]> Reviewed-by: Venky Shankar <[email protected]> Signed-off-by: Ilya Dryomov <[email protected]>
1 parent 8400291 commit 31634d7

File tree

2 files changed

+28
-14
lines changed

2 files changed

+28
-14
lines changed

fs/ceph/caps.c

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2016,6 +2016,8 @@ bool __ceph_should_report_size(struct ceph_inode_info *ci)
20162016
* CHECK_CAPS_AUTHONLY - we should only check the auth cap
20172017
* CHECK_CAPS_FLUSH - we should flush any dirty caps immediately, without
20182018
* further delay.
2019+
* CHECK_CAPS_FLUSH_FORCE - we should flush any caps immediately, without
2020+
* further delay.
20192021
*/
20202022
void ceph_check_caps(struct ceph_inode_info *ci, int flags)
20212023
{
@@ -2097,15 +2099,16 @@ void ceph_check_caps(struct ceph_inode_info *ci, int flags)
20972099
}
20982100

20992101
doutc(cl, "%p %llx.%llx file_want %s used %s dirty %s "
2100-
"flushing %s issued %s revoking %s retain %s %s%s%s\n",
2102+
"flushing %s issued %s revoking %s retain %s %s%s%s%s\n",
21012103
inode, ceph_vinop(inode), ceph_cap_string(file_wanted),
21022104
ceph_cap_string(used), ceph_cap_string(ci->i_dirty_caps),
21032105
ceph_cap_string(ci->i_flushing_caps),
21042106
ceph_cap_string(issued), ceph_cap_string(revoking),
21052107
ceph_cap_string(retain),
21062108
(flags & CHECK_CAPS_AUTHONLY) ? " AUTHONLY" : "",
21072109
(flags & CHECK_CAPS_FLUSH) ? " FLUSH" : "",
2108-
(flags & CHECK_CAPS_NOINVAL) ? " NOINVAL" : "");
2110+
(flags & CHECK_CAPS_NOINVAL) ? " NOINVAL" : "",
2111+
(flags & CHECK_CAPS_FLUSH_FORCE) ? " FLUSH_FORCE" : "");
21092112

21102113
/*
21112114
* If we no longer need to hold onto old our caps, and we may
@@ -2180,6 +2183,11 @@ void ceph_check_caps(struct ceph_inode_info *ci, int flags)
21802183
queue_writeback = true;
21812184
}
21822185

2186+
if (flags & CHECK_CAPS_FLUSH_FORCE) {
2187+
doutc(cl, "force to flush caps\n");
2188+
goto ack;
2189+
}
2190+
21832191
if (cap == ci->i_auth_cap &&
21842192
(cap->issued & CEPH_CAP_FILE_WR)) {
21852193
/* request larger max_size from MDS? */
@@ -3510,6 +3518,8 @@ static void handle_cap_grant(struct inode *inode,
35103518
bool queue_invalidate = false;
35113519
bool deleted_inode = false;
35123520
bool fill_inline = false;
3521+
bool revoke_wait = false;
3522+
int flags = 0;
35133523

35143524
/*
35153525
* If there is at least one crypto block then we'll trust
@@ -3705,16 +3715,18 @@ static void handle_cap_grant(struct inode *inode,
37053715
ceph_cap_string(cap->issued), ceph_cap_string(newcaps),
37063716
ceph_cap_string(revoking));
37073717
if (S_ISREG(inode->i_mode) &&
3708-
(revoking & used & CEPH_CAP_FILE_BUFFER))
3718+
(revoking & used & CEPH_CAP_FILE_BUFFER)) {
37093719
writeback = true; /* initiate writeback; will delay ack */
3710-
else if (queue_invalidate &&
3720+
revoke_wait = true;
3721+
} else if (queue_invalidate &&
37113722
revoking == CEPH_CAP_FILE_CACHE &&
3712-
(newcaps & CEPH_CAP_FILE_LAZYIO) == 0)
3713-
; /* do nothing yet, invalidation will be queued */
3714-
else if (cap == ci->i_auth_cap)
3723+
(newcaps & CEPH_CAP_FILE_LAZYIO) == 0) {
3724+
revoke_wait = true; /* do nothing yet, invalidation will be queued */
3725+
} else if (cap == ci->i_auth_cap) {
37153726
check_caps = 1; /* check auth cap only */
3716-
else
3727+
} else {
37173728
check_caps = 2; /* check all caps */
3729+
}
37183730
/* If there is new caps, try to wake up the waiters */
37193731
if (~cap->issued & newcaps)
37203732
wake = true;
@@ -3741,8 +3753,9 @@ static void handle_cap_grant(struct inode *inode,
37413753
BUG_ON(cap->issued & ~cap->implemented);
37423754

37433755
/* don't let check_caps skip sending a response to MDS for revoke msgs */
3744-
if (le32_to_cpu(grant->op) == CEPH_CAP_OP_REVOKE) {
3756+
if (!revoke_wait && le32_to_cpu(grant->op) == CEPH_CAP_OP_REVOKE) {
37453757
cap->mds_wanted = 0;
3758+
flags |= CHECK_CAPS_FLUSH_FORCE;
37463759
if (cap == ci->i_auth_cap)
37473760
check_caps = 1; /* check auth cap only */
37483761
else
@@ -3798,9 +3811,9 @@ static void handle_cap_grant(struct inode *inode,
37983811

37993812
mutex_unlock(&session->s_mutex);
38003813
if (check_caps == 1)
3801-
ceph_check_caps(ci, CHECK_CAPS_AUTHONLY | CHECK_CAPS_NOINVAL);
3814+
ceph_check_caps(ci, flags | CHECK_CAPS_AUTHONLY | CHECK_CAPS_NOINVAL);
38023815
else if (check_caps == 2)
3803-
ceph_check_caps(ci, CHECK_CAPS_NOINVAL);
3816+
ceph_check_caps(ci, flags | CHECK_CAPS_NOINVAL);
38043817
}
38053818

38063819
/*

fs/ceph/super.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,9 +200,10 @@ struct ceph_cap {
200200
struct list_head caps_item;
201201
};
202202

203-
#define CHECK_CAPS_AUTHONLY 1 /* only check auth cap */
204-
#define CHECK_CAPS_FLUSH 2 /* flush any dirty caps */
205-
#define CHECK_CAPS_NOINVAL 4 /* don't invalidate pagecache */
203+
#define CHECK_CAPS_AUTHONLY 1 /* only check auth cap */
204+
#define CHECK_CAPS_FLUSH 2 /* flush any dirty caps */
205+
#define CHECK_CAPS_NOINVAL 4 /* don't invalidate pagecache */
206+
#define CHECK_CAPS_FLUSH_FORCE 8 /* force flush any caps */
206207

207208
struct ceph_cap_flush {
208209
u64 tid;

0 commit comments

Comments
 (0)