Commit 5bd76b8d authored by Xiubo Li's avatar Xiubo Li Committed by Ilya Dryomov
Browse files

ceph: fix NULL pointer dereference for req->r_session

The request's r_session maybe changed when it was forwarded or
resent. Both the forwarding and resending cases the requests will
be protected by the mdsc->mutex.

Cc: stable@vger.kernel.org
Link: https://bugzilla.redhat.com/show_bug.cgi?id=2137955


Signed-off-by: default avatarXiubo Li <xiubli@redhat.com>
Reviewed-by: default avatarIlya Dryomov <idryomov@gmail.com>
Signed-off-by: default avatarIlya Dryomov <idryomov@gmail.com>
parent 51884d15
Loading
Loading
Loading
Loading
+12 −36
Original line number Diff line number Diff line
@@ -2248,7 +2248,6 @@ static int flush_mdlog_and_wait_inode_unsafe_requests(struct inode *inode)
	struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
	struct ceph_inode_info *ci = ceph_inode(inode);
	struct ceph_mds_request *req1 = NULL, *req2 = NULL;
	unsigned int max_sessions;
	int ret, err = 0;

	spin_lock(&ci->i_unsafe_lock);
@@ -2266,28 +2265,24 @@ static int flush_mdlog_and_wait_inode_unsafe_requests(struct inode *inode)
	}
	spin_unlock(&ci->i_unsafe_lock);

	/*
	 * The mdsc->max_sessions is unlikely to be changed
	 * mostly, here we will retry it by reallocating the
	 * sessions array memory to get rid of the mdsc->mutex
	 * lock.
	 */
retry:
	max_sessions = mdsc->max_sessions;

	/*
	 * Trigger to flush the journal logs in all the relevant MDSes
	 * manually, or in the worst case we must wait at most 5 seconds
	 * to wait the journal logs to be flushed by the MDSes periodically.
	 */
	if ((req1 || req2) && likely(max_sessions)) {
		struct ceph_mds_session **sessions = NULL;
		struct ceph_mds_session *s;
	if (req1 || req2) {
		struct ceph_mds_request *req;
		struct ceph_mds_session **sessions;
		struct ceph_mds_session *s;
		unsigned int max_sessions;
		int i;

		mutex_lock(&mdsc->mutex);
		max_sessions = mdsc->max_sessions;

		sessions = kcalloc(max_sessions, sizeof(s), GFP_KERNEL);
		if (!sessions) {
			mutex_unlock(&mdsc->mutex);
			err = -ENOMEM;
			goto out;
		}
@@ -2299,16 +2294,6 @@ static int flush_mdlog_and_wait_inode_unsafe_requests(struct inode *inode)
				s = req->r_session;
				if (!s)
					continue;
				if (unlikely(s->s_mds >= max_sessions)) {
					spin_unlock(&ci->i_unsafe_lock);
					for (i = 0; i < max_sessions; i++) {
						s = sessions[i];
						if (s)
							ceph_put_mds_session(s);
					}
					kfree(sessions);
					goto retry;
				}
				if (!sessions[s->s_mds]) {
					s = ceph_get_mds_session(s);
					sessions[s->s_mds] = s;
@@ -2321,16 +2306,6 @@ static int flush_mdlog_and_wait_inode_unsafe_requests(struct inode *inode)
				s = req->r_session;
				if (!s)
					continue;
				if (unlikely(s->s_mds >= max_sessions)) {
					spin_unlock(&ci->i_unsafe_lock);
					for (i = 0; i < max_sessions; i++) {
						s = sessions[i];
						if (s)
							ceph_put_mds_session(s);
					}
					kfree(sessions);
					goto retry;
				}
				if (!sessions[s->s_mds]) {
					s = ceph_get_mds_session(s);
					sessions[s->s_mds] = s;
@@ -2347,6 +2322,7 @@ static int flush_mdlog_and_wait_inode_unsafe_requests(struct inode *inode)
				sessions[s->s_mds] = ceph_get_mds_session(s);
		}
		spin_unlock(&ci->i_ceph_lock);
		mutex_unlock(&mdsc->mutex);

		/* send flush mdlog request to MDSes */
		for (i = 0; i < max_sessions; i++) {