17336d0e6SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
22402211aSDavid Teigland /*
32402211aSDavid Teigland * Copyright (C) 2005-2008 Red Hat, Inc. All rights reserved.
42402211aSDavid Teigland */
52402211aSDavid Teigland
62402211aSDavid Teigland #include <linux/fs.h>
75970e15dSJeff Layton #include <linux/filelock.h>
82402211aSDavid Teigland #include <linux/miscdevice.h>
92402211aSDavid Teigland #include <linux/poll.h>
102402211aSDavid Teigland #include <linux/dlm.h>
112402211aSDavid Teigland #include <linux/dlm_plock.h>
125a0e3ad6STejun Heo #include <linux/slab.h>
132402211aSDavid Teigland
148c95006dSAlexander Aring #include <trace/events/dlm.h>
158c95006dSAlexander Aring
162402211aSDavid Teigland #include "dlm_internal.h"
172402211aSDavid Teigland #include "lockspace.h"
182402211aSDavid Teigland
19314a5540SAlexander Aring static DEFINE_SPINLOCK(ops_lock);
20314a5540SAlexander Aring static LIST_HEAD(send_list);
21314a5540SAlexander Aring static LIST_HEAD(recv_list);
22314a5540SAlexander Aring static DECLARE_WAIT_QUEUE_HEAD(send_wq);
23314a5540SAlexander Aring static DECLARE_WAIT_QUEUE_HEAD(recv_wq);
242402211aSDavid Teigland
25bcbb4ba6SAlexander Aring struct plock_async_data {
26bcbb4ba6SAlexander Aring void *fl;
27bcbb4ba6SAlexander Aring void *file;
28bcbb4ba6SAlexander Aring struct file_lock flc;
29bcbb4ba6SAlexander Aring int (*callback)(struct file_lock *fl, int result);
30bcbb4ba6SAlexander Aring };
31bcbb4ba6SAlexander Aring
322402211aSDavid Teigland struct plock_op {
332402211aSDavid Teigland struct list_head list;
342402211aSDavid Teigland int done;
352402211aSDavid Teigland struct dlm_plock_info info;
36bcbb4ba6SAlexander Aring /* if set indicates async handling */
37bcbb4ba6SAlexander Aring struct plock_async_data *data;
382402211aSDavid Teigland };
392402211aSDavid Teigland
set_version(struct dlm_plock_info * info)402402211aSDavid Teigland static inline void set_version(struct dlm_plock_info *info)
412402211aSDavid Teigland {
422402211aSDavid Teigland info->version[0] = DLM_PLOCK_VERSION_MAJOR;
432402211aSDavid Teigland info->version[1] = DLM_PLOCK_VERSION_MINOR;
442402211aSDavid Teigland info->version[2] = DLM_PLOCK_VERSION_PATCH;
452402211aSDavid Teigland }
462402211aSDavid Teigland
plock_lookup_waiter(const struct dlm_plock_info * info)47dc52cd2eSAlexander Aring static struct plock_op *plock_lookup_waiter(const struct dlm_plock_info *info)
48dc52cd2eSAlexander Aring {
49dc52cd2eSAlexander Aring struct plock_op *op = NULL, *iter;
50dc52cd2eSAlexander Aring
51dc52cd2eSAlexander Aring list_for_each_entry(iter, &recv_list, list) {
52dc52cd2eSAlexander Aring if (iter->info.fsid == info->fsid &&
53dc52cd2eSAlexander Aring iter->info.number == info->number &&
54dc52cd2eSAlexander Aring iter->info.owner == info->owner &&
55dc52cd2eSAlexander Aring iter->info.pid == info->pid &&
56dc52cd2eSAlexander Aring iter->info.start == info->start &&
57dc52cd2eSAlexander Aring iter->info.end == info->end &&
58dc52cd2eSAlexander Aring iter->info.ex == info->ex &&
59dc52cd2eSAlexander Aring iter->info.wait) {
60dc52cd2eSAlexander Aring op = iter;
61dc52cd2eSAlexander Aring break;
62dc52cd2eSAlexander Aring }
63dc52cd2eSAlexander Aring }
64dc52cd2eSAlexander Aring
65dc52cd2eSAlexander Aring return op;
66dc52cd2eSAlexander Aring }
67dc52cd2eSAlexander Aring
check_version(struct dlm_plock_info * info)682402211aSDavid Teigland static int check_version(struct dlm_plock_info *info)
692402211aSDavid Teigland {
702402211aSDavid Teigland if ((DLM_PLOCK_VERSION_MAJOR != info->version[0]) ||
712402211aSDavid Teigland (DLM_PLOCK_VERSION_MINOR < info->version[1])) {
722402211aSDavid Teigland log_print("plock device version mismatch: "
732402211aSDavid Teigland "kernel (%u.%u.%u), user (%u.%u.%u)",
742402211aSDavid Teigland DLM_PLOCK_VERSION_MAJOR,
752402211aSDavid Teigland DLM_PLOCK_VERSION_MINOR,
762402211aSDavid Teigland DLM_PLOCK_VERSION_PATCH,
772402211aSDavid Teigland info->version[0],
782402211aSDavid Teigland info->version[1],
792402211aSDavid Teigland info->version[2]);
802402211aSDavid Teigland return -EINVAL;
812402211aSDavid Teigland }
822402211aSDavid Teigland return 0;
832402211aSDavid Teigland }
842402211aSDavid Teigland
dlm_release_plock_op(struct plock_op * op)85bcbb4ba6SAlexander Aring static void dlm_release_plock_op(struct plock_op *op)
86bcbb4ba6SAlexander Aring {
87bcbb4ba6SAlexander Aring kfree(op->data);
88bcbb4ba6SAlexander Aring kfree(op);
89bcbb4ba6SAlexander Aring }
90bcbb4ba6SAlexander Aring
send_op(struct plock_op * op)912402211aSDavid Teigland static void send_op(struct plock_op *op)
922402211aSDavid Teigland {
932402211aSDavid Teigland set_version(&op->info);
942402211aSDavid Teigland spin_lock(&ops_lock);
952402211aSDavid Teigland list_add_tail(&op->list, &send_list);
962402211aSDavid Teigland spin_unlock(&ops_lock);
972402211aSDavid Teigland wake_up(&send_wq);
982402211aSDavid Teigland }
992402211aSDavid Teigland
do_lock_cancel(const struct dlm_plock_info * orig_info)100568f9156SAlexander Aring static int do_lock_cancel(const struct dlm_plock_info *orig_info)
101901025d2SDavid Teigland {
102901025d2SDavid Teigland struct plock_op *op;
103568f9156SAlexander Aring int rv;
104901025d2SDavid Teigland
105901025d2SDavid Teigland op = kzalloc(sizeof(*op), GFP_NOFS);
106901025d2SDavid Teigland if (!op)
107568f9156SAlexander Aring return -ENOMEM;
108901025d2SDavid Teigland
109568f9156SAlexander Aring op->info = *orig_info;
110568f9156SAlexander Aring op->info.optype = DLM_PLOCK_OP_CANCEL;
111568f9156SAlexander Aring op->info.wait = 0;
112901025d2SDavid Teigland
113901025d2SDavid Teigland send_op(op);
114568f9156SAlexander Aring wait_event(recv_wq, (op->done != 0));
115568f9156SAlexander Aring
116568f9156SAlexander Aring rv = op->info.rv;
117568f9156SAlexander Aring
118568f9156SAlexander Aring dlm_release_plock_op(op);
119568f9156SAlexander Aring return rv;
120901025d2SDavid Teigland }
121901025d2SDavid Teigland
dlm_posix_lock(dlm_lockspace_t * lockspace,u64 number,struct file * file,int cmd,struct file_lock * fl)1222402211aSDavid Teigland int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
1232402211aSDavid Teigland int cmd, struct file_lock *fl)
1242402211aSDavid Teigland {
125bcbb4ba6SAlexander Aring struct plock_async_data *op_data;
1262402211aSDavid Teigland struct dlm_ls *ls;
1272402211aSDavid Teigland struct plock_op *op;
1282402211aSDavid Teigland int rv;
1292402211aSDavid Teigland
1302402211aSDavid Teigland ls = dlm_find_lockspace_local(lockspace);
1312402211aSDavid Teigland if (!ls)
1322402211aSDavid Teigland return -EINVAL;
1332402211aSDavid Teigland
134bcbb4ba6SAlexander Aring op = kzalloc(sizeof(*op), GFP_NOFS);
135bcbb4ba6SAlexander Aring if (!op) {
1362402211aSDavid Teigland rv = -ENOMEM;
1372402211aSDavid Teigland goto out;
1382402211aSDavid Teigland }
1392402211aSDavid Teigland
1402402211aSDavid Teigland op->info.optype = DLM_PLOCK_OP_LOCK;
1412402211aSDavid Teigland op->info.pid = fl->fl_pid;
1422402211aSDavid Teigland op->info.ex = (fl->fl_type == F_WRLCK);
1432402211aSDavid Teigland op->info.wait = IS_SETLKW(cmd);
1442402211aSDavid Teigland op->info.fsid = ls->ls_global_id;
1452402211aSDavid Teigland op->info.number = number;
1462402211aSDavid Teigland op->info.start = fl->fl_start;
1472402211aSDavid Teigland op->info.end = fl->fl_end;
148bcbb4ba6SAlexander Aring /* async handling */
1498fb47a4fSJ. Bruce Fields if (fl->fl_lmops && fl->fl_lmops->lm_grant) {
150bcbb4ba6SAlexander Aring op_data = kzalloc(sizeof(*op_data), GFP_NOFS);
151bcbb4ba6SAlexander Aring if (!op_data) {
152bcbb4ba6SAlexander Aring dlm_release_plock_op(op);
153bcbb4ba6SAlexander Aring rv = -ENOMEM;
154bcbb4ba6SAlexander Aring goto out;
155bcbb4ba6SAlexander Aring }
156bcbb4ba6SAlexander Aring
1572402211aSDavid Teigland /* fl_owner is lockd which doesn't distinguish
1582402211aSDavid Teigland processes on the nfs client */
1592402211aSDavid Teigland op->info.owner = (__u64) fl->fl_pid;
160bcbb4ba6SAlexander Aring op_data->callback = fl->fl_lmops->lm_grant;
161bcbb4ba6SAlexander Aring locks_init_lock(&op_data->flc);
162bcbb4ba6SAlexander Aring locks_copy_lock(&op_data->flc, fl);
163bcbb4ba6SAlexander Aring op_data->fl = fl;
164bcbb4ba6SAlexander Aring op_data->file = file;
165bcbb4ba6SAlexander Aring
166bcbb4ba6SAlexander Aring op->data = op_data;
167a800ba77SAlexander Aring
168a800ba77SAlexander Aring send_op(op);
169a800ba77SAlexander Aring rv = FILE_LOCK_DEFERRED;
170a800ba77SAlexander Aring goto out;
1712402211aSDavid Teigland } else {
1722402211aSDavid Teigland op->info.owner = (__u64)(long) fl->fl_owner;
1732402211aSDavid Teigland }
1742402211aSDavid Teigland
1752402211aSDavid Teigland send_op(op);
1762402211aSDavid Teigland
1770f2b1cb8SAlexander Aring if (op->info.wait) {
178568f9156SAlexander Aring rv = wait_event_interruptible(recv_wq, (op->done != 0));
179901025d2SDavid Teigland if (rv == -ERESTARTSYS) {
180901025d2SDavid Teigland spin_lock(&ops_lock);
181b92a4e3fSAlexander Aring /* recheck under ops_lock if we got a done != 0,
182b92a4e3fSAlexander Aring * if so this interrupt case should be ignored
183b92a4e3fSAlexander Aring */
184b92a4e3fSAlexander Aring if (op->done != 0) {
185b92a4e3fSAlexander Aring spin_unlock(&ops_lock);
186b92a4e3fSAlexander Aring goto do_lock_wait;
187b92a4e3fSAlexander Aring }
188568f9156SAlexander Aring spin_unlock(&ops_lock);
189568f9156SAlexander Aring
190568f9156SAlexander Aring rv = do_lock_cancel(&op->info);
191568f9156SAlexander Aring switch (rv) {
192568f9156SAlexander Aring case 0:
193568f9156SAlexander Aring /* waiter was deleted in user space, answer will never come
194568f9156SAlexander Aring * remove original request. The original request must be
195568f9156SAlexander Aring * on recv_list because the answer of do_lock_cancel()
196568f9156SAlexander Aring * synchronized it.
197568f9156SAlexander Aring */
198568f9156SAlexander Aring spin_lock(&ops_lock);
199c847f4e2SAlexander Aring list_del(&op->list);
200901025d2SDavid Teigland spin_unlock(&ops_lock);
201568f9156SAlexander Aring rv = -EINTR;
202568f9156SAlexander Aring break;
203568f9156SAlexander Aring case -ENOENT:
204568f9156SAlexander Aring /* cancellation wasn't successful but op should be done */
205568f9156SAlexander Aring fallthrough;
206568f9156SAlexander Aring default:
207568f9156SAlexander Aring /* internal error doing cancel we need to wait */
208568f9156SAlexander Aring goto wait;
209568f9156SAlexander Aring }
210c847f4e2SAlexander Aring
211ea06d4caSAlexander Aring log_debug(ls, "%s: wait interrupted %x %llx pid %d",
212bcfad426SAlexander Aring __func__, ls->ls_global_id,
21319d7ca05SAlexander Aring (unsigned long long)number, op->info.pid);
214c847f4e2SAlexander Aring dlm_release_plock_op(op);
215901025d2SDavid Teigland goto out;
216901025d2SDavid Teigland }
2170f2b1cb8SAlexander Aring } else {
218568f9156SAlexander Aring wait:
2190f2b1cb8SAlexander Aring wait_event(recv_wq, (op->done != 0));
2200f2b1cb8SAlexander Aring }
2212402211aSDavid Teigland
222b92a4e3fSAlexander Aring do_lock_wait:
223b92a4e3fSAlexander Aring
224a559790cSAlexander Aring WARN_ON(!list_empty(&op->list));
2252402211aSDavid Teigland
2262402211aSDavid Teigland rv = op->info.rv;
2272402211aSDavid Teigland
2282402211aSDavid Teigland if (!rv) {
2294f656367SBenjamin Coddington if (locks_lock_file_wait(file, fl) < 0)
2302402211aSDavid Teigland log_error(ls, "dlm_posix_lock: vfs lock error %llx",
2312402211aSDavid Teigland (unsigned long long)number);
2322402211aSDavid Teigland }
2332402211aSDavid Teigland
234bcbb4ba6SAlexander Aring dlm_release_plock_op(op);
2352402211aSDavid Teigland out:
2362402211aSDavid Teigland dlm_put_lockspace(ls);
2372402211aSDavid Teigland return rv;
2382402211aSDavid Teigland }
2392402211aSDavid Teigland EXPORT_SYMBOL_GPL(dlm_posix_lock);
2402402211aSDavid Teigland
241af901ca1SAndré Goddard Rosa /* Returns failure iff a successful lock operation should be canceled */
dlm_plock_callback(struct plock_op * op)2422402211aSDavid Teigland static int dlm_plock_callback(struct plock_op *op)
2432402211aSDavid Teigland {
244bcbb4ba6SAlexander Aring struct plock_async_data *op_data = op->data;
2452402211aSDavid Teigland struct file *file;
2462402211aSDavid Teigland struct file_lock *fl;
2472402211aSDavid Teigland struct file_lock *flc;
248d0449b90SJoe Perches int (*notify)(struct file_lock *fl, int result) = NULL;
2492402211aSDavid Teigland int rv = 0;
2502402211aSDavid Teigland
251a559790cSAlexander Aring WARN_ON(!list_empty(&op->list));
2522402211aSDavid Teigland
2532402211aSDavid Teigland /* check if the following 2 are still valid or make a copy */
254bcbb4ba6SAlexander Aring file = op_data->file;
255bcbb4ba6SAlexander Aring flc = &op_data->flc;
256bcbb4ba6SAlexander Aring fl = op_data->fl;
257bcbb4ba6SAlexander Aring notify = op_data->callback;
2582402211aSDavid Teigland
2592402211aSDavid Teigland if (op->info.rv) {
260d0449b90SJoe Perches notify(fl, op->info.rv);
2612402211aSDavid Teigland goto out;
2622402211aSDavid Teigland }
2632402211aSDavid Teigland
2642402211aSDavid Teigland /* got fs lock; bookkeep locally as well: */
2652402211aSDavid Teigland flc->fl_flags &= ~FL_SLEEP;
2662402211aSDavid Teigland if (posix_lock_file(file, flc, NULL)) {
2672402211aSDavid Teigland /*
2682402211aSDavid Teigland * This can only happen in the case of kmalloc() failure.
2692402211aSDavid Teigland * The filesystem's own lock is the authoritative lock,
2702402211aSDavid Teigland * so a failure to get the lock locally is not a disaster.
2712402211aSDavid Teigland * As long as the fs cannot reliably cancel locks (especially
2722402211aSDavid Teigland * in a low-memory situation), we're better off ignoring
2732402211aSDavid Teigland * this failure than trying to recover.
2742402211aSDavid Teigland */
2752402211aSDavid Teigland log_print("dlm_plock_callback: vfs lock error %llx file %p fl %p",
2762402211aSDavid Teigland (unsigned long long)op->info.number, file, fl);
2772402211aSDavid Teigland }
2782402211aSDavid Teigland
279d0449b90SJoe Perches rv = notify(fl, 0);
2802402211aSDavid Teigland if (rv) {
2812402211aSDavid Teigland /* XXX: We need to cancel the fs lock here: */
28299c58d64SAlexander Aring log_print("%s: lock granted after lock request failed; dangling lock!",
28399c58d64SAlexander Aring __func__);
2842402211aSDavid Teigland goto out;
2852402211aSDavid Teigland }
2862402211aSDavid Teigland
2872402211aSDavid Teigland out:
288bcbb4ba6SAlexander Aring dlm_release_plock_op(op);
2892402211aSDavid Teigland return rv;
2902402211aSDavid Teigland }
2912402211aSDavid Teigland
dlm_posix_unlock(dlm_lockspace_t * lockspace,u64 number,struct file * file,struct file_lock * fl)2922402211aSDavid Teigland int dlm_posix_unlock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
2932402211aSDavid Teigland struct file_lock *fl)
2942402211aSDavid Teigland {
2952402211aSDavid Teigland struct dlm_ls *ls;
2962402211aSDavid Teigland struct plock_op *op;
2972402211aSDavid Teigland int rv;
29890008318SDavid Teigland unsigned char fl_flags = fl->fl_flags;
2992402211aSDavid Teigland
3002402211aSDavid Teigland ls = dlm_find_lockspace_local(lockspace);
3012402211aSDavid Teigland if (!ls)
3022402211aSDavid Teigland return -EINVAL;
3032402211aSDavid Teigland
304573c24c4SDavid Teigland op = kzalloc(sizeof(*op), GFP_NOFS);
3052402211aSDavid Teigland if (!op) {
3062402211aSDavid Teigland rv = -ENOMEM;
3072402211aSDavid Teigland goto out;
3082402211aSDavid Teigland }
3092402211aSDavid Teigland
31090008318SDavid Teigland /* cause the vfs unlock to return ENOENT if lock is not found */
31190008318SDavid Teigland fl->fl_flags |= FL_EXISTS;
31290008318SDavid Teigland
3134f656367SBenjamin Coddington rv = locks_lock_file_wait(file, fl);
31490008318SDavid Teigland if (rv == -ENOENT) {
31590008318SDavid Teigland rv = 0;
31690008318SDavid Teigland goto out_free;
31790008318SDavid Teigland }
31890008318SDavid Teigland if (rv < 0) {
31990008318SDavid Teigland log_error(ls, "dlm_posix_unlock: vfs unlock error %d %llx",
32090008318SDavid Teigland rv, (unsigned long long)number);
32190008318SDavid Teigland }
3222402211aSDavid Teigland
3232402211aSDavid Teigland op->info.optype = DLM_PLOCK_OP_UNLOCK;
3242402211aSDavid Teigland op->info.pid = fl->fl_pid;
3252402211aSDavid Teigland op->info.fsid = ls->ls_global_id;
3262402211aSDavid Teigland op->info.number = number;
3272402211aSDavid Teigland op->info.start = fl->fl_start;
3282402211aSDavid Teigland op->info.end = fl->fl_end;
3298fb47a4fSJ. Bruce Fields if (fl->fl_lmops && fl->fl_lmops->lm_grant)
3302402211aSDavid Teigland op->info.owner = (__u64) fl->fl_pid;
3312402211aSDavid Teigland else
3322402211aSDavid Teigland op->info.owner = (__u64)(long) fl->fl_owner;
3332402211aSDavid Teigland
334901025d2SDavid Teigland if (fl->fl_flags & FL_CLOSE) {
335901025d2SDavid Teigland op->info.flags |= DLM_PLOCK_FL_CLOSE;
336901025d2SDavid Teigland send_op(op);
337901025d2SDavid Teigland rv = 0;
338901025d2SDavid Teigland goto out;
339901025d2SDavid Teigland }
340901025d2SDavid Teigland
3412402211aSDavid Teigland send_op(op);
3422402211aSDavid Teigland wait_event(recv_wq, (op->done != 0));
3432402211aSDavid Teigland
344a559790cSAlexander Aring WARN_ON(!list_empty(&op->list));
3452402211aSDavid Teigland
3462402211aSDavid Teigland rv = op->info.rv;
3472402211aSDavid Teigland
3482402211aSDavid Teigland if (rv == -ENOENT)
3492402211aSDavid Teigland rv = 0;
3502402211aSDavid Teigland
35190008318SDavid Teigland out_free:
352bcbb4ba6SAlexander Aring dlm_release_plock_op(op);
3532402211aSDavid Teigland out:
3542402211aSDavid Teigland dlm_put_lockspace(ls);
35590008318SDavid Teigland fl->fl_flags = fl_flags;
3562402211aSDavid Teigland return rv;
3572402211aSDavid Teigland }
3582402211aSDavid Teigland EXPORT_SYMBOL_GPL(dlm_posix_unlock);
3592402211aSDavid Teigland
360dc52cd2eSAlexander Aring /*
361dc52cd2eSAlexander Aring * NOTE: This implementation can only handle async lock requests as nfs
362dc52cd2eSAlexander Aring * do it. It cannot handle cancellation of a pending lock request sitting
363dc52cd2eSAlexander Aring * in wait_event(), but for now only nfs is the only user local kernel
364dc52cd2eSAlexander Aring * user.
365dc52cd2eSAlexander Aring */
dlm_posix_cancel(dlm_lockspace_t * lockspace,u64 number,struct file * file,struct file_lock * fl)366dc52cd2eSAlexander Aring int dlm_posix_cancel(dlm_lockspace_t *lockspace, u64 number, struct file *file,
367dc52cd2eSAlexander Aring struct file_lock *fl)
368dc52cd2eSAlexander Aring {
369dc52cd2eSAlexander Aring struct dlm_plock_info info;
370dc52cd2eSAlexander Aring struct plock_op *op;
371dc52cd2eSAlexander Aring struct dlm_ls *ls;
372dc52cd2eSAlexander Aring int rv;
373dc52cd2eSAlexander Aring
374dc52cd2eSAlexander Aring /* this only works for async request for now and nfs is the only
375dc52cd2eSAlexander Aring * kernel user right now.
376dc52cd2eSAlexander Aring */
377dc52cd2eSAlexander Aring if (WARN_ON_ONCE(!fl->fl_lmops || !fl->fl_lmops->lm_grant))
378dc52cd2eSAlexander Aring return -EOPNOTSUPP;
379dc52cd2eSAlexander Aring
380dc52cd2eSAlexander Aring ls = dlm_find_lockspace_local(lockspace);
381dc52cd2eSAlexander Aring if (!ls)
382dc52cd2eSAlexander Aring return -EINVAL;
383dc52cd2eSAlexander Aring
384dc52cd2eSAlexander Aring memset(&info, 0, sizeof(info));
385dc52cd2eSAlexander Aring info.pid = fl->fl_pid;
386dc52cd2eSAlexander Aring info.ex = (fl->fl_type == F_WRLCK);
387dc52cd2eSAlexander Aring info.fsid = ls->ls_global_id;
388dc52cd2eSAlexander Aring dlm_put_lockspace(ls);
389dc52cd2eSAlexander Aring info.number = number;
390dc52cd2eSAlexander Aring info.start = fl->fl_start;
391dc52cd2eSAlexander Aring info.end = fl->fl_end;
392dc52cd2eSAlexander Aring info.owner = (__u64)fl->fl_pid;
393dc52cd2eSAlexander Aring
394dc52cd2eSAlexander Aring rv = do_lock_cancel(&info);
395dc52cd2eSAlexander Aring switch (rv) {
396dc52cd2eSAlexander Aring case 0:
397dc52cd2eSAlexander Aring spin_lock(&ops_lock);
398dc52cd2eSAlexander Aring /* lock request to cancel must be on recv_list because
399dc52cd2eSAlexander Aring * do_lock_cancel() synchronizes it.
400dc52cd2eSAlexander Aring */
401dc52cd2eSAlexander Aring op = plock_lookup_waiter(&info);
402dc52cd2eSAlexander Aring if (WARN_ON_ONCE(!op)) {
403e717f2e8SAlexander Aring spin_unlock(&ops_lock);
404dc52cd2eSAlexander Aring rv = -ENOLCK;
405dc52cd2eSAlexander Aring break;
406dc52cd2eSAlexander Aring }
407dc52cd2eSAlexander Aring
408dc52cd2eSAlexander Aring list_del(&op->list);
409dc52cd2eSAlexander Aring spin_unlock(&ops_lock);
410dc52cd2eSAlexander Aring WARN_ON(op->info.optype != DLM_PLOCK_OP_LOCK);
411dc52cd2eSAlexander Aring op->data->callback(op->data->fl, -EINTR);
412dc52cd2eSAlexander Aring dlm_release_plock_op(op);
413dc52cd2eSAlexander Aring rv = -EINTR;
414dc52cd2eSAlexander Aring break;
415dc52cd2eSAlexander Aring case -ENOENT:
416dc52cd2eSAlexander Aring /* if cancel wasn't successful we probably were to late
417dc52cd2eSAlexander Aring * or it was a non-blocking lock request, so just unlock it.
418dc52cd2eSAlexander Aring */
419dc52cd2eSAlexander Aring rv = dlm_posix_unlock(lockspace, number, file, fl);
420dc52cd2eSAlexander Aring break;
421dc52cd2eSAlexander Aring default:
422dc52cd2eSAlexander Aring break;
423dc52cd2eSAlexander Aring }
424dc52cd2eSAlexander Aring
425dc52cd2eSAlexander Aring return rv;
426dc52cd2eSAlexander Aring }
427dc52cd2eSAlexander Aring EXPORT_SYMBOL_GPL(dlm_posix_cancel);
428dc52cd2eSAlexander Aring
dlm_posix_get(dlm_lockspace_t * lockspace,u64 number,struct file * file,struct file_lock * fl)4292402211aSDavid Teigland int dlm_posix_get(dlm_lockspace_t *lockspace, u64 number, struct file *file,
4302402211aSDavid Teigland struct file_lock *fl)
4312402211aSDavid Teigland {
4322402211aSDavid Teigland struct dlm_ls *ls;
4332402211aSDavid Teigland struct plock_op *op;
4342402211aSDavid Teigland int rv;
4352402211aSDavid Teigland
4362402211aSDavid Teigland ls = dlm_find_lockspace_local(lockspace);
4372402211aSDavid Teigland if (!ls)
4382402211aSDavid Teigland return -EINVAL;
4392402211aSDavid Teigland
440573c24c4SDavid Teigland op = kzalloc(sizeof(*op), GFP_NOFS);
4412402211aSDavid Teigland if (!op) {
4422402211aSDavid Teigland rv = -ENOMEM;
4432402211aSDavid Teigland goto out;
4442402211aSDavid Teigland }
4452402211aSDavid Teigland
4462402211aSDavid Teigland op->info.optype = DLM_PLOCK_OP_GET;
4472402211aSDavid Teigland op->info.pid = fl->fl_pid;
4482402211aSDavid Teigland op->info.ex = (fl->fl_type == F_WRLCK);
4492402211aSDavid Teigland op->info.fsid = ls->ls_global_id;
4502402211aSDavid Teigland op->info.number = number;
4512402211aSDavid Teigland op->info.start = fl->fl_start;
4522402211aSDavid Teigland op->info.end = fl->fl_end;
4538fb47a4fSJ. Bruce Fields if (fl->fl_lmops && fl->fl_lmops->lm_grant)
4542402211aSDavid Teigland op->info.owner = (__u64) fl->fl_pid;
4552402211aSDavid Teigland else
4562402211aSDavid Teigland op->info.owner = (__u64)(long) fl->fl_owner;
4572402211aSDavid Teigland
4582402211aSDavid Teigland send_op(op);
4592402211aSDavid Teigland wait_event(recv_wq, (op->done != 0));
4602402211aSDavid Teigland
461a559790cSAlexander Aring WARN_ON(!list_empty(&op->list));
4622402211aSDavid Teigland
4632402211aSDavid Teigland /* info.rv from userspace is 1 for conflict, 0 for no-conflict,
4642402211aSDavid Teigland -ENOENT if there are no locks on the file */
4652402211aSDavid Teigland
4662402211aSDavid Teigland rv = op->info.rv;
4672402211aSDavid Teigland
4682402211aSDavid Teigland fl->fl_type = F_UNLCK;
4692402211aSDavid Teigland if (rv == -ENOENT)
4702402211aSDavid Teigland rv = 0;
4712402211aSDavid Teigland else if (rv > 0) {
47220d5a399SJeff Layton locks_init_lock(fl);
4732402211aSDavid Teigland fl->fl_type = (op->info.ex) ? F_WRLCK : F_RDLCK;
47420d5a399SJeff Layton fl->fl_flags = FL_POSIX;
47592655fbdSAlexander Aring fl->fl_pid = op->info.pid;
47692655fbdSAlexander Aring if (op->info.nodeid != dlm_our_nodeid())
47792655fbdSAlexander Aring fl->fl_pid = -fl->fl_pid;
4782402211aSDavid Teigland fl->fl_start = op->info.start;
4792402211aSDavid Teigland fl->fl_end = op->info.end;
4802402211aSDavid Teigland rv = 0;
4812402211aSDavid Teigland }
4822402211aSDavid Teigland
483bcbb4ba6SAlexander Aring dlm_release_plock_op(op);
4842402211aSDavid Teigland out:
4852402211aSDavid Teigland dlm_put_lockspace(ls);
4862402211aSDavid Teigland return rv;
4872402211aSDavid Teigland }
4882402211aSDavid Teigland EXPORT_SYMBOL_GPL(dlm_posix_get);
4892402211aSDavid Teigland
4902402211aSDavid Teigland /* a read copies out one plock request from the send list */
dev_read(struct file * file,char __user * u,size_t count,loff_t * ppos)4912402211aSDavid Teigland static ssize_t dev_read(struct file *file, char __user *u, size_t count,
4922402211aSDavid Teigland loff_t *ppos)
4932402211aSDavid Teigland {
4942402211aSDavid Teigland struct dlm_plock_info info;
4952402211aSDavid Teigland struct plock_op *op = NULL;
4962402211aSDavid Teigland
4972402211aSDavid Teigland if (count < sizeof(info))
4982402211aSDavid Teigland return -EINVAL;
4992402211aSDavid Teigland
5002402211aSDavid Teigland spin_lock(&ops_lock);
5012402211aSDavid Teigland if (!list_empty(&send_list)) {
502976a0624SAlexander Aring op = list_first_entry(&send_list, struct plock_op, list);
503901025d2SDavid Teigland if (op->info.flags & DLM_PLOCK_FL_CLOSE)
504901025d2SDavid Teigland list_del(&op->list);
505901025d2SDavid Teigland else
50657e2c2f2SAlexander Aring list_move_tail(&op->list, &recv_list);
5072402211aSDavid Teigland memcpy(&info, &op->info, sizeof(info));
5082402211aSDavid Teigland }
5092402211aSDavid Teigland spin_unlock(&ops_lock);
5102402211aSDavid Teigland
5112402211aSDavid Teigland if (!op)
5122402211aSDavid Teigland return -EAGAIN;
5132402211aSDavid Teigland
5148c95006dSAlexander Aring trace_dlm_plock_read(&info);
5158c95006dSAlexander Aring
516901025d2SDavid Teigland /* there is no need to get a reply from userspace for unlocks
517901025d2SDavid Teigland that were generated by the vfs cleaning up for a close
518901025d2SDavid Teigland (the process did not make an unlock call). */
519901025d2SDavid Teigland
520901025d2SDavid Teigland if (op->info.flags & DLM_PLOCK_FL_CLOSE)
521bcbb4ba6SAlexander Aring dlm_release_plock_op(op);
522901025d2SDavid Teigland
5232402211aSDavid Teigland if (copy_to_user(u, &info, sizeof(info)))
5242402211aSDavid Teigland return -EFAULT;
5252402211aSDavid Teigland return sizeof(info);
5262402211aSDavid Teigland }
5272402211aSDavid Teigland
5282402211aSDavid Teigland /* a write copies in one plock result that should match a plock_op
5292402211aSDavid Teigland on the recv list */
dev_write(struct file * file,const char __user * u,size_t count,loff_t * ppos)5302402211aSDavid Teigland static ssize_t dev_write(struct file *file, const char __user *u, size_t count,
5312402211aSDavid Teigland loff_t *ppos)
5322402211aSDavid Teigland {
533dc1acd5cSJakob Koschel struct plock_op *op = NULL, *iter;
5342402211aSDavid Teigland struct dlm_plock_info info;
535dc1acd5cSJakob Koschel int do_callback = 0;
5362402211aSDavid Teigland
5372402211aSDavid Teigland if (count != sizeof(info))
5382402211aSDavid Teigland return -EINVAL;
5392402211aSDavid Teigland
5402402211aSDavid Teigland if (copy_from_user(&info, u, sizeof(info)))
5412402211aSDavid Teigland return -EFAULT;
5422402211aSDavid Teigland
5438c95006dSAlexander Aring trace_dlm_plock_write(&info);
5448c95006dSAlexander Aring
5452402211aSDavid Teigland if (check_version(&info))
5462402211aSDavid Teigland return -EINVAL;
5472402211aSDavid Teigland
54857e2c2f2SAlexander Aring /*
54957e2c2f2SAlexander Aring * The results for waiting ops (SETLKW) can be returned in any
55057e2c2f2SAlexander Aring * order, so match all fields to find the op. The results for
55157e2c2f2SAlexander Aring * non-waiting ops are returned in the order that they were sent
55257e2c2f2SAlexander Aring * to userspace, so match the result with the first non-waiting op.
55357e2c2f2SAlexander Aring */
5542402211aSDavid Teigland spin_lock(&ops_lock);
55557e2c2f2SAlexander Aring if (info.wait) {
556dc52cd2eSAlexander Aring op = plock_lookup_waiter(&info);
55757e2c2f2SAlexander Aring } else {
55857e2c2f2SAlexander Aring list_for_each_entry(iter, &recv_list, list) {
559*7c53e847SAlexander Aring if (!iter->info.wait &&
560*7c53e847SAlexander Aring iter->info.fsid == info.fsid) {
56157e2c2f2SAlexander Aring op = iter;
56257e2c2f2SAlexander Aring break;
56357e2c2f2SAlexander Aring }
56457e2c2f2SAlexander Aring }
56557e2c2f2SAlexander Aring }
56657e2c2f2SAlexander Aring
56757e2c2f2SAlexander Aring if (op) {
56857e2c2f2SAlexander Aring /* Sanity check that op and info match. */
56957e2c2f2SAlexander Aring if (info.wait)
57057e2c2f2SAlexander Aring WARN_ON(op->info.optype != DLM_PLOCK_OP_LOCK);
57157e2c2f2SAlexander Aring else
572*7c53e847SAlexander Aring WARN_ON(op->info.number != info.number ||
57357e2c2f2SAlexander Aring op->info.owner != info.owner ||
57457e2c2f2SAlexander Aring op->info.optype != info.optype);
57557e2c2f2SAlexander Aring
57657e2c2f2SAlexander Aring list_del_init(&op->list);
57757e2c2f2SAlexander Aring memcpy(&op->info, &info, sizeof(info));
57857e2c2f2SAlexander Aring if (op->data)
57957e2c2f2SAlexander Aring do_callback = 1;
58057e2c2f2SAlexander Aring else
58157e2c2f2SAlexander Aring op->done = 1;
58257e2c2f2SAlexander Aring }
5832402211aSDavid Teigland spin_unlock(&ops_lock);
5842402211aSDavid Teigland
585dc1acd5cSJakob Koschel if (op) {
586c78a87d0SDavid Teigland if (do_callback)
587817d10baSDavid Teigland dlm_plock_callback(op);
5882402211aSDavid Teigland else
5892402211aSDavid Teigland wake_up(&recv_wq);
5902402211aSDavid Teigland } else
591c847f4e2SAlexander Aring pr_debug("%s: no op %x %llx", __func__,
592bcfad426SAlexander Aring info.fsid, (unsigned long long)info.number);
5932402211aSDavid Teigland return count;
5942402211aSDavid Teigland }
5952402211aSDavid Teigland
dev_poll(struct file * file,poll_table * wait)596076ccb76SAl Viro static __poll_t dev_poll(struct file *file, poll_table *wait)
5972402211aSDavid Teigland {
598076ccb76SAl Viro __poll_t mask = 0;
5992402211aSDavid Teigland
6002402211aSDavid Teigland poll_wait(file, &send_wq, wait);
6012402211aSDavid Teigland
6022402211aSDavid Teigland spin_lock(&ops_lock);
6032402211aSDavid Teigland if (!list_empty(&send_list))
604a9a08845SLinus Torvalds mask = EPOLLIN | EPOLLRDNORM;
6052402211aSDavid Teigland spin_unlock(&ops_lock);
6062402211aSDavid Teigland
6072402211aSDavid Teigland return mask;
6082402211aSDavid Teigland }
6092402211aSDavid Teigland
6102402211aSDavid Teigland static const struct file_operations dev_fops = {
6112402211aSDavid Teigland .read = dev_read,
6122402211aSDavid Teigland .write = dev_write,
6132402211aSDavid Teigland .poll = dev_poll,
6146038f373SArnd Bergmann .owner = THIS_MODULE,
6156038f373SArnd Bergmann .llseek = noop_llseek,
6162402211aSDavid Teigland };
6172402211aSDavid Teigland
6182402211aSDavid Teigland static struct miscdevice plock_dev_misc = {
6192402211aSDavid Teigland .minor = MISC_DYNAMIC_MINOR,
6202402211aSDavid Teigland .name = DLM_PLOCK_MISC_NAME,
6212402211aSDavid Teigland .fops = &dev_fops
6222402211aSDavid Teigland };
6232402211aSDavid Teigland
dlm_plock_init(void)6242402211aSDavid Teigland int dlm_plock_init(void)
6252402211aSDavid Teigland {
6262402211aSDavid Teigland int rv;
6272402211aSDavid Teigland
6282402211aSDavid Teigland rv = misc_register(&plock_dev_misc);
6292402211aSDavid Teigland if (rv)
6302402211aSDavid Teigland log_print("dlm_plock_init: misc_register failed %d", rv);
6312402211aSDavid Teigland return rv;
6322402211aSDavid Teigland }
6332402211aSDavid Teigland
dlm_plock_exit(void)6342402211aSDavid Teigland void dlm_plock_exit(void)
6352402211aSDavid Teigland {
636f368ed60SGreg Kroah-Hartman misc_deregister(&plock_dev_misc);
63767b5da9aSAlexander Aring WARN_ON(!list_empty(&send_list));
63867b5da9aSAlexander Aring WARN_ON(!list_empty(&recv_list));
6392402211aSDavid Teigland }
6402402211aSDavid Teigland
641