Commit 1c424629 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'ceph-for-6.11-rc2' of https://github.com/ceph/ceph-client

Pull ceph fix from Ilya Dryomov:
 "A fix for a potential hang in the MDS when cap revocation races with
  the client releasing the caps in question, marked for stable"

* tag 'ceph-for-6.11-rc2' of https://github.com/ceph/ceph-client:
  ceph: force sending a cap update msg back to MDS for revoke op
parents 725d410f 31634d75
Loading
Loading
Loading
Loading
+24 −11
Original line number Diff line number Diff line
@@ -2016,6 +2016,8 @@ bool __ceph_should_report_size(struct ceph_inode_info *ci)
 *  CHECK_CAPS_AUTHONLY - we should only check the auth cap
 *  CHECK_CAPS_FLUSH - we should flush any dirty caps immediately, without
 *    further delay.
 *  CHECK_CAPS_FLUSH_FORCE - we should flush any caps immediately, without
 *    further delay.
 */
void ceph_check_caps(struct ceph_inode_info *ci, int flags)
{
@@ -2097,7 +2099,7 @@ void ceph_check_caps(struct ceph_inode_info *ci, int flags)
	}

	doutc(cl, "%p %llx.%llx file_want %s used %s dirty %s "
	      "flushing %s issued %s revoking %s retain %s %s%s%s\n",
	      "flushing %s issued %s revoking %s retain %s %s%s%s%s\n",
	     inode, ceph_vinop(inode), ceph_cap_string(file_wanted),
	     ceph_cap_string(used), ceph_cap_string(ci->i_dirty_caps),
	     ceph_cap_string(ci->i_flushing_caps),
@@ -2105,7 +2107,8 @@ void ceph_check_caps(struct ceph_inode_info *ci, int flags)
	     ceph_cap_string(retain),
	     (flags & CHECK_CAPS_AUTHONLY) ? " AUTHONLY" : "",
	     (flags & CHECK_CAPS_FLUSH) ? " FLUSH" : "",
	     (flags & CHECK_CAPS_NOINVAL) ? " NOINVAL" : "");
	     (flags & CHECK_CAPS_NOINVAL) ? " NOINVAL" : "",
	     (flags & CHECK_CAPS_FLUSH_FORCE) ? " FLUSH_FORCE" : "");

	/*
	 * 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)
				queue_writeback = true;
		}

		if (flags & CHECK_CAPS_FLUSH_FORCE) {
			doutc(cl, "force to flush caps\n");
			goto ack;
		}

		if (cap == ci->i_auth_cap &&
		    (cap->issued & CEPH_CAP_FILE_WR)) {
			/* request larger max_size from MDS? */
@@ -3510,6 +3518,8 @@ static void handle_cap_grant(struct inode *inode,
	bool queue_invalidate = false;
	bool deleted_inode = false;
	bool fill_inline = false;
	bool revoke_wait = false;
	int flags = 0;

	/*
	 * If there is at least one crypto block then we'll trust
@@ -3705,16 +3715,18 @@ static void handle_cap_grant(struct inode *inode,
		      ceph_cap_string(cap->issued), ceph_cap_string(newcaps),
		      ceph_cap_string(revoking));
		if (S_ISREG(inode->i_mode) &&
		    (revoking & used & CEPH_CAP_FILE_BUFFER))
		    (revoking & used & CEPH_CAP_FILE_BUFFER)) {
			writeback = true;  /* initiate writeback; will delay ack */
		else if (queue_invalidate &&
			revoke_wait = true;
		} else if (queue_invalidate &&
			 revoking == CEPH_CAP_FILE_CACHE &&
			 (newcaps & CEPH_CAP_FILE_LAZYIO) == 0)
			; /* do nothing yet, invalidation will be queued */
		else if (cap == ci->i_auth_cap)
			 (newcaps & CEPH_CAP_FILE_LAZYIO) == 0) {
			revoke_wait = true; /* do nothing yet, invalidation will be queued */
		} else if (cap == ci->i_auth_cap) {
			check_caps = 1; /* check auth cap only */
		else
		} else {
			check_caps = 2; /* check all caps */
		}
		/* If there is new caps, try to wake up the waiters */
		if (~cap->issued & newcaps)
			wake = true;
@@ -3741,8 +3753,9 @@ static void handle_cap_grant(struct inode *inode,
	BUG_ON(cap->issued & ~cap->implemented);

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

	mutex_unlock(&session->s_mutex);
	if (check_caps == 1)
		ceph_check_caps(ci, CHECK_CAPS_AUTHONLY | CHECK_CAPS_NOINVAL);
		ceph_check_caps(ci, flags | CHECK_CAPS_AUTHONLY | CHECK_CAPS_NOINVAL);
	else if (check_caps == 2)
		ceph_check_caps(ci, CHECK_CAPS_NOINVAL);
		ceph_check_caps(ci, flags | CHECK_CAPS_NOINVAL);
}

/*
+4 −3
Original line number Diff line number Diff line
@@ -203,6 +203,7 @@ struct ceph_cap {
#define CHECK_CAPS_AUTHONLY     1  /* only check auth cap */
#define CHECK_CAPS_FLUSH        2  /* flush any dirty caps */
#define CHECK_CAPS_NOINVAL      4  /* don't invalidate pagecache */
#define CHECK_CAPS_FLUSH_FORCE  8  /* force flush any caps */

struct ceph_cap_flush {
	u64 tid;