xref: /linux/fs/dlm/plock.c (revision 12d5fc96ebbb3b948861805b32a4c3a96105ccd9)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2005-2008 Red Hat, Inc.  All rights reserved.
4  */
5 
6 #include <linux/fs.h>
7 #include <linux/capability.h>
8 #include <linux/filelock.h>
9 #include <linux/miscdevice.h>
10 #include <linux/poll.h>
11 #include <linux/dlm.h>
12 #include <linux/dlm_plock.h>
13 #include <linux/slab.h>
14 
15 #include <trace/events/dlm.h>
16 
17 #include "dlm_internal.h"
18 #include "lockspace.h"
19 
20 static DEFINE_SPINLOCK(ops_lock);
21 static LIST_HEAD(send_list);
22 static LIST_HEAD(recv_list);
23 static DECLARE_WAIT_QUEUE_HEAD(send_wq);
24 static DECLARE_WAIT_QUEUE_HEAD(recv_wq);
25 
26 struct plock_async_data {
27 	void *fl;
28 	void *file;
29 	struct file_lock flc;
30 	int (*callback)(struct file_lock *fl, int result);
31 };
32 
33 struct plock_op {
34 	struct list_head list;
35 	int done;
36 	struct dlm_plock_info info;
37 	/* if set indicates async handling */
38 	struct plock_async_data *data;
39 };
40 
41 static inline void set_version(struct dlm_plock_info *info)
42 {
43 	info->version[0] = DLM_PLOCK_VERSION_MAJOR;
44 	info->version[1] = DLM_PLOCK_VERSION_MINOR;
45 	info->version[2] = DLM_PLOCK_VERSION_PATCH;
46 }
47 
48 static struct plock_op *plock_lookup_waiter(const struct dlm_plock_info *info)
49 {
50 	struct plock_op *op = NULL, *iter;
51 
52 	list_for_each_entry(iter, &recv_list, list) {
53 		if (iter->info.fsid == info->fsid &&
54 		    iter->info.number == info->number &&
55 		    iter->info.owner == info->owner &&
56 		    iter->info.pid == info->pid &&
57 		    iter->info.start == info->start &&
58 		    iter->info.end == info->end &&
59 		    iter->info.ex == info->ex &&
60 		    iter->info.wait) {
61 			op = iter;
62 			break;
63 		}
64 	}
65 
66 	return op;
67 }
68 
69 static int check_version(struct dlm_plock_info *info)
70 {
71 	if ((DLM_PLOCK_VERSION_MAJOR != info->version[0]) ||
72 	    (DLM_PLOCK_VERSION_MINOR < info->version[1])) {
73 		log_print("plock device version mismatch: "
74 			  "kernel (%u.%u.%u), user (%u.%u.%u)",
75 			  DLM_PLOCK_VERSION_MAJOR,
76 			  DLM_PLOCK_VERSION_MINOR,
77 			  DLM_PLOCK_VERSION_PATCH,
78 			  info->version[0],
79 			  info->version[1],
80 			  info->version[2]);
81 		return -EINVAL;
82 	}
83 	return 0;
84 }
85 
86 static void dlm_release_plock_op(struct plock_op *op)
87 {
88 	kfree(op->data);
89 	kfree(op);
90 }
91 
92 static void send_op(struct plock_op *op)
93 {
94 	set_version(&op->info);
95 	spin_lock(&ops_lock);
96 	list_add_tail(&op->list, &send_list);
97 	spin_unlock(&ops_lock);
98 	wake_up(&send_wq);
99 }
100 
101 static int do_lock_cancel(const struct dlm_plock_info *orig_info)
102 {
103 	struct plock_op *op;
104 	int rv;
105 
106 	op = kzalloc_obj(*op, GFP_NOFS);
107 	if (!op)
108 		return -ENOMEM;
109 
110 	op->info = *orig_info;
111 	op->info.optype = DLM_PLOCK_OP_CANCEL;
112 	op->info.wait = 0;
113 
114 	send_op(op);
115 	wait_event(recv_wq, (op->done != 0));
116 
117 	rv = op->info.rv;
118 
119 	dlm_release_plock_op(op);
120 	return rv;
121 }
122 
123 int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
124 		   int cmd, struct file_lock *fl)
125 {
126 	struct plock_async_data *op_data;
127 	struct dlm_ls *ls;
128 	struct plock_op *op;
129 	int rv;
130 
131 	ls = dlm_find_lockspace_local(lockspace);
132 	if (!ls)
133 		return -EINVAL;
134 
135 	op = kzalloc_obj(*op, GFP_NOFS);
136 	if (!op) {
137 		rv = -ENOMEM;
138 		goto out;
139 	}
140 
141 	op->info.optype		= DLM_PLOCK_OP_LOCK;
142 	op->info.pid		= fl->c.flc_pid;
143 	op->info.ex		= lock_is_write(fl);
144 	op->info.wait		= !!(fl->c.flc_flags & FL_SLEEP);
145 	op->info.fsid		= ls->ls_global_id;
146 	op->info.number		= number;
147 	op->info.start		= fl->fl_start;
148 	op->info.end		= fl->fl_end;
149 	op->info.owner = (__u64)(long) fl->c.flc_owner;
150 	/* async handling */
151 	if (fl->fl_lmops && fl->fl_lmops->lm_grant) {
152 		op_data = kzalloc_obj(*op_data, GFP_NOFS);
153 		if (!op_data) {
154 			dlm_release_plock_op(op);
155 			rv = -ENOMEM;
156 			goto out;
157 		}
158 
159 		op_data->callback = fl->fl_lmops->lm_grant;
160 		locks_init_lock(&op_data->flc);
161 		locks_copy_lock(&op_data->flc, fl);
162 		op_data->fl		= fl;
163 		op_data->file	= file;
164 
165 		op->data = op_data;
166 
167 		send_op(op);
168 		rv = FILE_LOCK_DEFERRED;
169 		goto out;
170 	}
171 
172 	send_op(op);
173 
174 	if (op->info.wait) {
175 		rv = wait_event_interruptible(recv_wq, (op->done != 0));
176 		if (rv == -ERESTARTSYS) {
177 			spin_lock(&ops_lock);
178 			/* recheck under ops_lock if we got a done != 0,
179 			 * if so this interrupt case should be ignored
180 			 */
181 			if (op->done != 0) {
182 				spin_unlock(&ops_lock);
183 				goto do_lock_wait;
184 			}
185 			spin_unlock(&ops_lock);
186 
187 			rv = do_lock_cancel(&op->info);
188 			switch (rv) {
189 			case 0:
190 				/* waiter was deleted in user space, answer will never come
191 				 * remove original request. The original request must be
192 				 * on recv_list because the answer of do_lock_cancel()
193 				 * synchronized it.
194 				 */
195 				spin_lock(&ops_lock);
196 				list_del(&op->list);
197 				spin_unlock(&ops_lock);
198 				rv = -EINTR;
199 				break;
200 			case -ENOENT:
201 				/* cancellation wasn't successful but op should be done */
202 				fallthrough;
203 			default:
204 				/* internal error doing cancel we need to wait */
205 				goto wait;
206 			}
207 
208 			log_debug(ls, "%s: wait interrupted %x %llx pid %d",
209 				  __func__, ls->ls_global_id,
210 				  (unsigned long long)number, op->info.pid);
211 			dlm_release_plock_op(op);
212 			goto out;
213 		}
214 	} else {
215 wait:
216 		wait_event(recv_wq, (op->done != 0));
217 	}
218 
219 do_lock_wait:
220 
221 	WARN_ON(!list_empty(&op->list));
222 
223 	rv = op->info.rv;
224 
225 	if (!rv) {
226 		if (locks_lock_file_wait(file, fl) < 0)
227 			log_error(ls, "dlm_posix_lock: vfs lock error %llx",
228 				  (unsigned long long)number);
229 	}
230 
231 	dlm_release_plock_op(op);
232 out:
233 	dlm_put_lockspace(ls);
234 	return rv;
235 }
236 EXPORT_SYMBOL_GPL(dlm_posix_lock);
237 
238 /* Returns failure iff a successful lock operation should be canceled */
239 static int dlm_plock_callback(struct plock_op *op)
240 {
241 	struct plock_async_data *op_data = op->data;
242 	struct file *file;
243 	struct file_lock *fl;
244 	struct file_lock *flc;
245 	int (*notify)(struct file_lock *fl, int result) = NULL;
246 	int rv = 0;
247 
248 	WARN_ON(!list_empty(&op->list));
249 
250 	/* check if the following 2 are still valid or make a copy */
251 	file = op_data->file;
252 	flc = &op_data->flc;
253 	fl = op_data->fl;
254 	notify = op_data->callback;
255 
256 	if (op->info.rv) {
257 		notify(fl, op->info.rv);
258 		goto out;
259 	}
260 
261 	/* got fs lock; bookkeep locally as well: */
262 	flc->c.flc_flags &= ~FL_SLEEP;
263 	if (posix_lock_file(file, flc, NULL)) {
264 		/*
265 		 * This can only happen in the case of kmalloc() failure.
266 		 * The filesystem's own lock is the authoritative lock,
267 		 * so a failure to get the lock locally is not a disaster.
268 		 * As long as the fs cannot reliably cancel locks (especially
269 		 * in a low-memory situation), we're better off ignoring
270 		 * this failure than trying to recover.
271 		 */
272 		log_print("dlm_plock_callback: vfs lock error %llx file %p fl %p",
273 			  (unsigned long long)op->info.number, file, fl);
274 	}
275 
276 	rv = notify(fl, 0);
277 	if (rv) {
278 		/* XXX: We need to cancel the fs lock here: */
279 		log_print("%s: lock granted after lock request failed; dangling lock!",
280 			  __func__);
281 		goto out;
282 	}
283 
284 out:
285 	dlm_release_plock_op(op);
286 	return rv;
287 }
288 
289 int dlm_posix_unlock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
290 		     struct file_lock *fl)
291 {
292 	struct dlm_ls *ls;
293 	struct plock_op *op;
294 	int rv;
295 	unsigned char saved_flags = fl->c.flc_flags;
296 
297 	ls = dlm_find_lockspace_local(lockspace);
298 	if (!ls)
299 		return -EINVAL;
300 
301 	op = kzalloc_obj(*op, GFP_NOFS);
302 	if (!op) {
303 		rv = -ENOMEM;
304 		goto out;
305 	}
306 
307 	/* cause the vfs unlock to return ENOENT if lock is not found */
308 	fl->c.flc_flags |= FL_EXISTS;
309 
310 	rv = locks_lock_file_wait(file, fl);
311 	if (rv == -ENOENT) {
312 		rv = 0;
313 		goto out_free;
314 	}
315 	if (rv < 0) {
316 		log_error(ls, "dlm_posix_unlock: vfs unlock error %d %llx",
317 			  rv, (unsigned long long)number);
318 	}
319 
320 	op->info.optype		= DLM_PLOCK_OP_UNLOCK;
321 	op->info.pid		= fl->c.flc_pid;
322 	op->info.fsid		= ls->ls_global_id;
323 	op->info.number		= number;
324 	op->info.start		= fl->fl_start;
325 	op->info.end		= fl->fl_end;
326 	op->info.owner = (__u64)(long) fl->c.flc_owner;
327 
328 	if (fl->c.flc_flags & FL_CLOSE) {
329 		op->info.flags |= DLM_PLOCK_FL_CLOSE;
330 		send_op(op);
331 		rv = 0;
332 		goto out;
333 	}
334 
335 	send_op(op);
336 	wait_event(recv_wq, (op->done != 0));
337 
338 	WARN_ON(!list_empty(&op->list));
339 
340 	rv = op->info.rv;
341 
342 	if (rv == -ENOENT)
343 		rv = 0;
344 
345 out_free:
346 	dlm_release_plock_op(op);
347 out:
348 	dlm_put_lockspace(ls);
349 	fl->c.flc_flags = saved_flags;
350 	return rv;
351 }
352 EXPORT_SYMBOL_GPL(dlm_posix_unlock);
353 
354 /*
355  * NOTE: This implementation can only handle async lock requests as nfs
356  * do it. It cannot handle cancellation of a pending lock request sitting
357  * in wait_event(), but for now only nfs is the only user local kernel
358  * user.
359  */
360 int dlm_posix_cancel(dlm_lockspace_t *lockspace, u64 number, struct file *file,
361 		     struct file_lock *fl)
362 {
363 	struct dlm_plock_info info;
364 	struct plock_op *op;
365 	struct dlm_ls *ls;
366 	int rv;
367 
368 	/* this only works for async request for now and nfs is the only
369 	 * kernel user right now.
370 	 */
371 	if (WARN_ON_ONCE(!fl->fl_lmops || !fl->fl_lmops->lm_grant))
372 		return -EOPNOTSUPP;
373 
374 	ls = dlm_find_lockspace_local(lockspace);
375 	if (!ls)
376 		return -EINVAL;
377 
378 	memset(&info, 0, sizeof(info));
379 	info.pid = fl->c.flc_pid;
380 	info.ex = lock_is_write(fl);
381 	info.fsid = ls->ls_global_id;
382 	dlm_put_lockspace(ls);
383 	info.number = number;
384 	info.start = fl->fl_start;
385 	info.end = fl->fl_end;
386 	info.owner = (__u64)(long) fl->c.flc_owner;
387 
388 	rv = do_lock_cancel(&info);
389 	switch (rv) {
390 	case 0:
391 		spin_lock(&ops_lock);
392 		/* lock request to cancel must be on recv_list because
393 		 * do_lock_cancel() synchronizes it.
394 		 */
395 		op = plock_lookup_waiter(&info);
396 		if (WARN_ON_ONCE(!op)) {
397 			spin_unlock(&ops_lock);
398 			rv = -ENOLCK;
399 			break;
400 		}
401 
402 		list_del(&op->list);
403 		spin_unlock(&ops_lock);
404 		WARN_ON(op->info.optype != DLM_PLOCK_OP_LOCK);
405 		op->data->callback(op->data->fl, -EINTR);
406 		dlm_release_plock_op(op);
407 		rv = -EINTR;
408 		break;
409 	case -ENOENT:
410 		/* if cancel wasn't successful we probably were to late
411 		 * or it was a non-blocking lock request, so just unlock it.
412 		 */
413 		rv = dlm_posix_unlock(lockspace, number, file, fl);
414 		break;
415 	default:
416 		break;
417 	}
418 
419 	return rv;
420 }
421 EXPORT_SYMBOL_GPL(dlm_posix_cancel);
422 
423 int dlm_posix_get(dlm_lockspace_t *lockspace, u64 number, struct file *file,
424 		  struct file_lock *fl)
425 {
426 	struct dlm_ls *ls;
427 	struct plock_op *op;
428 	int rv;
429 
430 	ls = dlm_find_lockspace_local(lockspace);
431 	if (!ls)
432 		return -EINVAL;
433 
434 	op = kzalloc_obj(*op, GFP_NOFS);
435 	if (!op) {
436 		rv = -ENOMEM;
437 		goto out;
438 	}
439 
440 	op->info.optype		= DLM_PLOCK_OP_GET;
441 	op->info.pid		= fl->c.flc_pid;
442 	op->info.ex		= lock_is_write(fl);
443 	op->info.fsid		= ls->ls_global_id;
444 	op->info.number		= number;
445 	op->info.start		= fl->fl_start;
446 	op->info.end		= fl->fl_end;
447 	op->info.owner = (__u64)(long) fl->c.flc_owner;
448 
449 	send_op(op);
450 	wait_event(recv_wq, (op->done != 0));
451 
452 	WARN_ON(!list_empty(&op->list));
453 
454 	/* info.rv from userspace is 1 for conflict, 0 for no-conflict,
455 	   -ENOENT if there are no locks on the file */
456 
457 	rv = op->info.rv;
458 
459 	fl->c.flc_type = F_UNLCK;
460 	if (rv == -ENOENT)
461 		rv = 0;
462 	else if (rv > 0) {
463 		locks_init_lock(fl);
464 		fl->c.flc_type = (op->info.ex) ? F_WRLCK : F_RDLCK;
465 		fl->c.flc_flags = FL_POSIX;
466 		fl->c.flc_pid = op->info.pid;
467 		if (op->info.nodeid != dlm_our_nodeid())
468 			fl->c.flc_pid = -fl->c.flc_pid;
469 		fl->fl_start = op->info.start;
470 		fl->fl_end = op->info.end;
471 		rv = 0;
472 	}
473 
474 	dlm_release_plock_op(op);
475 out:
476 	dlm_put_lockspace(ls);
477 	return rv;
478 }
479 EXPORT_SYMBOL_GPL(dlm_posix_get);
480 
481 static int dev_open(struct inode *inode, struct file *file)
482 {
483 	/* Userspace plock daemon is a privileged cluster component. */
484 	if (!capable(CAP_SYS_ADMIN))
485 		return -EPERM;
486 
487 	return 0;
488 }
489 
490 /* a read copies out one plock request from the send list */
491 static ssize_t dev_read(struct file *file, char __user *u, size_t count,
492 			loff_t *ppos)
493 {
494 	struct dlm_plock_info info;
495 	struct plock_op *op = NULL;
496 
497 	if (count < sizeof(info))
498 		return -EINVAL;
499 
500 	spin_lock(&ops_lock);
501 	if (!list_empty(&send_list)) {
502 		op = list_first_entry(&send_list, struct plock_op, list);
503 		if (op->info.flags & DLM_PLOCK_FL_CLOSE)
504 			list_del(&op->list);
505 		else
506 			list_move_tail(&op->list, &recv_list);
507 		memcpy(&info, &op->info, sizeof(info));
508 	}
509 	spin_unlock(&ops_lock);
510 
511 	if (!op)
512 		return -EAGAIN;
513 
514 	trace_dlm_plock_read(&info);
515 
516 	/* there is no need to get a reply from userspace for unlocks
517 	   that were generated by the vfs cleaning up for a close
518 	   (the process did not make an unlock call). */
519 
520 	if (op->info.flags & DLM_PLOCK_FL_CLOSE)
521 		dlm_release_plock_op(op);
522 
523 	if (copy_to_user(u, &info, sizeof(info)))
524 		return -EFAULT;
525 	return sizeof(info);
526 }
527 
528 /* a write copies in one plock result that should match a plock_op
529    on the recv list */
530 static ssize_t dev_write(struct file *file, const char __user *u, size_t count,
531 			 loff_t *ppos)
532 {
533 	struct plock_op *op = NULL, *iter;
534 	struct dlm_plock_info info;
535 	int do_callback = 0;
536 
537 	if (count != sizeof(info))
538 		return -EINVAL;
539 
540 	if (copy_from_user(&info, u, sizeof(info)))
541 		return -EFAULT;
542 
543 	trace_dlm_plock_write(&info);
544 
545 	if (check_version(&info))
546 		return -EINVAL;
547 
548 	/*
549 	 * The results for waiting ops (SETLKW) can be returned in any
550 	 * order, so match all fields to find the op.  The results for
551 	 * non-waiting ops are returned in the order that they were sent
552 	 * to userspace, so match the result with the first non-waiting op.
553 	 */
554 	spin_lock(&ops_lock);
555 	if (info.wait) {
556 		op = plock_lookup_waiter(&info);
557 	} else {
558 		list_for_each_entry(iter, &recv_list, list) {
559 			if (!iter->info.wait &&
560 			    iter->info.fsid == info.fsid) {
561 				op = iter;
562 				break;
563 			}
564 		}
565 	}
566 
567 	if (op) {
568 		/* Sanity check that op and info match. */
569 		if (info.wait)
570 			WARN_ON(op->info.optype != DLM_PLOCK_OP_LOCK);
571 		else
572 			WARN_ON(op->info.number != info.number ||
573 				op->info.owner != info.owner ||
574 				op->info.optype != info.optype);
575 
576 		list_del_init(&op->list);
577 		memcpy(&op->info, &info, sizeof(info));
578 		if (op->data)
579 			do_callback = 1;
580 		else
581 			op->done = 1;
582 	}
583 	spin_unlock(&ops_lock);
584 
585 	if (op) {
586 		if (do_callback)
587 			dlm_plock_callback(op);
588 		else
589 			wake_up(&recv_wq);
590 	} else
591 		pr_debug("%s: no op %x %llx", __func__,
592 			 info.fsid, (unsigned long long)info.number);
593 	return count;
594 }
595 
596 static __poll_t dev_poll(struct file *file, poll_table *wait)
597 {
598 	__poll_t mask = 0;
599 
600 	poll_wait(file, &send_wq, wait);
601 
602 	spin_lock(&ops_lock);
603 	if (!list_empty(&send_list))
604 		mask = EPOLLIN | EPOLLRDNORM;
605 	spin_unlock(&ops_lock);
606 
607 	return mask;
608 }
609 
610 static const struct file_operations dev_fops = {
611 	.open    = dev_open,
612 	.read    = dev_read,
613 	.write   = dev_write,
614 	.poll    = dev_poll,
615 	.owner   = THIS_MODULE,
616 	.llseek  = noop_llseek,
617 };
618 
619 static struct miscdevice plock_dev_misc = {
620 	.minor = MISC_DYNAMIC_MINOR,
621 	.name = DLM_PLOCK_MISC_NAME,
622 	.fops = &dev_fops,
623 	.mode = 0600,
624 };
625 
626 int dlm_plock_init(void)
627 {
628 	int rv;
629 
630 	rv = misc_register(&plock_dev_misc);
631 	if (rv)
632 		log_print("dlm_plock_init: misc_register failed %d", rv);
633 	return rv;
634 }
635 
636 void dlm_plock_exit(void)
637 {
638 	misc_deregister(&plock_dev_misc);
639 	WARN_ON(!list_empty(&send_list));
640 	WARN_ON(!list_empty(&recv_list));
641 }
642 
643