Skip to content

Commit 57e2c2f

Browse files
Alexander Aringteigland
authored andcommitted
fs: dlm: fix mismatch of plock results from userspace
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: Alexander Aring <aahringo@redhat.com> Signed-off-by: David Teigland <teigland@redhat.com>
1 parent 0f2b1cb commit 57e2c2f

1 file changed

Lines changed: 45 additions & 13 deletions

File tree

fs/dlm/plock.c

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ static ssize_t dev_read(struct file *file, char __user *u, size_t count,
395395
if (op->info.flags & DLM_PLOCK_FL_CLOSE)
396396
list_del(&op->list);
397397
else
398-
list_move(&op->list, &recv_list);
398+
list_move_tail(&op->list, &recv_list);
399399
memcpy(&info, &op->info, sizeof(info));
400400
}
401401
spin_unlock(&ops_lock);
@@ -433,20 +433,52 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count,
433433
if (check_version(&info))
434434
return -EINVAL;
435435

436+
/*
437+
* The results for waiting ops (SETLKW) can be returned in any
438+
* order, so match all fields to find the op. The results for
439+
* non-waiting ops are returned in the order that they were sent
440+
* to userspace, so match the result with the first non-waiting op.
441+
*/
436442
spin_lock(&ops_lock);
437-
list_for_each_entry(iter, &recv_list, list) {
438-
if (iter->info.fsid == info.fsid &&
439-
iter->info.number == info.number &&
440-
iter->info.owner == info.owner) {
441-
list_del_init(&iter->list);
442-
memcpy(&iter->info, &info, sizeof(info));
443-
if (iter->data)
444-
do_callback = 1;
445-
else
446-
iter->done = 1;
447-
op = iter;
448-
break;
443+
if (info.wait) {
444+
list_for_each_entry(iter, &recv_list, list) {
445+
if (iter->info.fsid == info.fsid &&
446+
iter->info.number == info.number &&
447+
iter->info.owner == info.owner &&
448+
iter->info.pid == info.pid &&
449+
iter->info.start == info.start &&
450+
iter->info.end == info.end &&
451+
iter->info.ex == info.ex &&
452+
iter->info.wait) {
453+
op = iter;
454+
break;
455+
}
449456
}
457+
} else {
458+
list_for_each_entry(iter, &recv_list, list) {
459+
if (!iter->info.wait) {
460+
op = iter;
461+
break;
462+
}
463+
}
464+
}
465+
466+
if (op) {
467+
/* Sanity check that op and info match. */
468+
if (info.wait)
469+
WARN_ON(op->info.optype != DLM_PLOCK_OP_LOCK);
470+
else
471+
WARN_ON(op->info.fsid != info.fsid ||
472+
op->info.number != info.number ||
473+
op->info.owner != info.owner ||
474+
op->info.optype != info.optype);
475+
476+
list_del_init(&op->list);
477+
memcpy(&op->info, &info, sizeof(info));
478+
if (op->data)
479+
do_callback = 1;
480+
else
481+
op->done = 1;
450482
}
451483
spin_unlock(&ops_lock);
452484

0 commit comments

Comments
 (0)