Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7b57fc3f authored by Alexander Aring's avatar Alexander Aring Committed by Greg Kroah-Hartman
Browse files

fs: dlm: fix mismatch of plock results from userspace



[ Upstream commit 57e2c2f2d94cfd551af91cedfa1af6d972487197 ]

When a waiting plock request (F_SETLKW) is sent to userspace
for processing (dlm_controld), the result is returned at a
later time. That result could be incorrectly matched to a
different waiting request in cases where the owner field is
the same (e.g. different threads in a process.) This is fixed
by comparing all the properties in the request and reply.

The results for non-waiting plock requests are now matched
based on list order because the results are returned in the
same order they were sent.

Cc: stable@vger.kernel.org
Signed-off-by: default avatarAlexander Aring <aahringo@redhat.com>
Signed-off-by: default avatarDavid Teigland <teigland@redhat.com>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 721d5b51
Loading
Loading
Loading
Loading
+45 −13
Original line number Diff line number Diff line
@@ -405,7 +405,7 @@ static ssize_t dev_read(struct file *file, char __user *u, size_t count,
		if (op->info.flags & DLM_PLOCK_FL_CLOSE)
			list_del(&op->list);
		else
			list_move(&op->list, &recv_list);
			list_move_tail(&op->list, &recv_list);
		memcpy(&info, &op->info, sizeof(info));
	}
	spin_unlock(&ops_lock);
@@ -443,21 +443,53 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count,
	if (check_version(&info))
		return -EINVAL;

	/*
	 * The results for waiting ops (SETLKW) can be returned in any
	 * order, so match all fields to find the op.  The results for
	 * non-waiting ops are returned in the order that they were sent
	 * to userspace, so match the result with the first non-waiting op.
	 */
	spin_lock(&ops_lock);
	if (info.wait) {
		list_for_each_entry(iter, &recv_list, list) {
			if (iter->info.fsid == info.fsid &&
			    iter->info.number == info.number &&
		    iter->info.owner == info.owner) {
			list_del_init(&iter->list);
			memcpy(&iter->info, &info, sizeof(info));
			if (iter->data)
				do_callback = 1;
			else
				iter->done = 1;
			    iter->info.owner == info.owner &&
			    iter->info.pid == info.pid &&
			    iter->info.start == info.start &&
			    iter->info.end == info.end &&
			    iter->info.ex == info.ex &&
			    iter->info.wait) {
				op = iter;
				break;
			}
		}
	} else {
		list_for_each_entry(iter, &recv_list, list) {
			if (!iter->info.wait) {
				op = iter;
				break;
			}
		}
	}

	if (op) {
		/* Sanity check that op and info match. */
		if (info.wait)
			WARN_ON(op->info.optype != DLM_PLOCK_OP_LOCK);
		else
			WARN_ON(op->info.fsid != info.fsid ||
				op->info.number != info.number ||
				op->info.owner != info.owner ||
				op->info.optype != info.optype);

		list_del_init(&op->list);
		memcpy(&op->info, &info, sizeof(info));
		if (op->data)
			do_callback = 1;
		else
			op->done = 1;
	}
	spin_unlock(&ops_lock);

	if (op) {