xref: /OK3568_Linux_fs/kernel/fs/dlm/user.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) 2006-2010 Red Hat, Inc.  All rights reserved.
4*4882a593Smuzhiyun  */
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun #include <linux/miscdevice.h>
7*4882a593Smuzhiyun #include <linux/init.h>
8*4882a593Smuzhiyun #include <linux/wait.h>
9*4882a593Smuzhiyun #include <linux/file.h>
10*4882a593Smuzhiyun #include <linux/fs.h>
11*4882a593Smuzhiyun #include <linux/poll.h>
12*4882a593Smuzhiyun #include <linux/signal.h>
13*4882a593Smuzhiyun #include <linux/spinlock.h>
14*4882a593Smuzhiyun #include <linux/dlm.h>
15*4882a593Smuzhiyun #include <linux/dlm_device.h>
16*4882a593Smuzhiyun #include <linux/slab.h>
17*4882a593Smuzhiyun #include <linux/sched/signal.h>
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #include "dlm_internal.h"
20*4882a593Smuzhiyun #include "lockspace.h"
21*4882a593Smuzhiyun #include "lock.h"
22*4882a593Smuzhiyun #include "lvb_table.h"
23*4882a593Smuzhiyun #include "user.h"
24*4882a593Smuzhiyun #include "ast.h"
25*4882a593Smuzhiyun #include "config.h"
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun static const char name_prefix[] = "dlm";
28*4882a593Smuzhiyun static const struct file_operations device_fops;
29*4882a593Smuzhiyun static atomic_t dlm_monitor_opened;
30*4882a593Smuzhiyun static int dlm_monitor_unused = 1;
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun struct dlm_lock_params32 {
35*4882a593Smuzhiyun 	__u8 mode;
36*4882a593Smuzhiyun 	__u8 namelen;
37*4882a593Smuzhiyun 	__u16 unused;
38*4882a593Smuzhiyun 	__u32 flags;
39*4882a593Smuzhiyun 	__u32 lkid;
40*4882a593Smuzhiyun 	__u32 parent;
41*4882a593Smuzhiyun 	__u64 xid;
42*4882a593Smuzhiyun 	__u64 timeout;
43*4882a593Smuzhiyun 	__u32 castparam;
44*4882a593Smuzhiyun 	__u32 castaddr;
45*4882a593Smuzhiyun 	__u32 bastparam;
46*4882a593Smuzhiyun 	__u32 bastaddr;
47*4882a593Smuzhiyun 	__u32 lksb;
48*4882a593Smuzhiyun 	char lvb[DLM_USER_LVB_LEN];
49*4882a593Smuzhiyun 	char name[];
50*4882a593Smuzhiyun };
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun struct dlm_write_request32 {
53*4882a593Smuzhiyun 	__u32 version[3];
54*4882a593Smuzhiyun 	__u8 cmd;
55*4882a593Smuzhiyun 	__u8 is64bit;
56*4882a593Smuzhiyun 	__u8 unused[2];
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	union  {
59*4882a593Smuzhiyun 		struct dlm_lock_params32 lock;
60*4882a593Smuzhiyun 		struct dlm_lspace_params lspace;
61*4882a593Smuzhiyun 		struct dlm_purge_params purge;
62*4882a593Smuzhiyun 	} i;
63*4882a593Smuzhiyun };
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun struct dlm_lksb32 {
66*4882a593Smuzhiyun 	__u32 sb_status;
67*4882a593Smuzhiyun 	__u32 sb_lkid;
68*4882a593Smuzhiyun 	__u8 sb_flags;
69*4882a593Smuzhiyun 	__u32 sb_lvbptr;
70*4882a593Smuzhiyun };
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun struct dlm_lock_result32 {
73*4882a593Smuzhiyun 	__u32 version[3];
74*4882a593Smuzhiyun 	__u32 length;
75*4882a593Smuzhiyun 	__u32 user_astaddr;
76*4882a593Smuzhiyun 	__u32 user_astparam;
77*4882a593Smuzhiyun 	__u32 user_lksb;
78*4882a593Smuzhiyun 	struct dlm_lksb32 lksb;
79*4882a593Smuzhiyun 	__u8 bast_mode;
80*4882a593Smuzhiyun 	__u8 unused[3];
81*4882a593Smuzhiyun 	/* Offsets may be zero if no data is present */
82*4882a593Smuzhiyun 	__u32 lvb_offset;
83*4882a593Smuzhiyun };
84*4882a593Smuzhiyun 
compat_input(struct dlm_write_request * kb,struct dlm_write_request32 * kb32,int namelen)85*4882a593Smuzhiyun static void compat_input(struct dlm_write_request *kb,
86*4882a593Smuzhiyun 			 struct dlm_write_request32 *kb32,
87*4882a593Smuzhiyun 			 int namelen)
88*4882a593Smuzhiyun {
89*4882a593Smuzhiyun 	kb->version[0] = kb32->version[0];
90*4882a593Smuzhiyun 	kb->version[1] = kb32->version[1];
91*4882a593Smuzhiyun 	kb->version[2] = kb32->version[2];
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	kb->cmd = kb32->cmd;
94*4882a593Smuzhiyun 	kb->is64bit = kb32->is64bit;
95*4882a593Smuzhiyun 	if (kb->cmd == DLM_USER_CREATE_LOCKSPACE ||
96*4882a593Smuzhiyun 	    kb->cmd == DLM_USER_REMOVE_LOCKSPACE) {
97*4882a593Smuzhiyun 		kb->i.lspace.flags = kb32->i.lspace.flags;
98*4882a593Smuzhiyun 		kb->i.lspace.minor = kb32->i.lspace.minor;
99*4882a593Smuzhiyun 		memcpy(kb->i.lspace.name, kb32->i.lspace.name, namelen);
100*4882a593Smuzhiyun 	} else if (kb->cmd == DLM_USER_PURGE) {
101*4882a593Smuzhiyun 		kb->i.purge.nodeid = kb32->i.purge.nodeid;
102*4882a593Smuzhiyun 		kb->i.purge.pid = kb32->i.purge.pid;
103*4882a593Smuzhiyun 	} else {
104*4882a593Smuzhiyun 		kb->i.lock.mode = kb32->i.lock.mode;
105*4882a593Smuzhiyun 		kb->i.lock.namelen = kb32->i.lock.namelen;
106*4882a593Smuzhiyun 		kb->i.lock.flags = kb32->i.lock.flags;
107*4882a593Smuzhiyun 		kb->i.lock.lkid = kb32->i.lock.lkid;
108*4882a593Smuzhiyun 		kb->i.lock.parent = kb32->i.lock.parent;
109*4882a593Smuzhiyun 		kb->i.lock.xid = kb32->i.lock.xid;
110*4882a593Smuzhiyun 		kb->i.lock.timeout = kb32->i.lock.timeout;
111*4882a593Smuzhiyun 		kb->i.lock.castparam = (void *)(long)kb32->i.lock.castparam;
112*4882a593Smuzhiyun 		kb->i.lock.castaddr = (void *)(long)kb32->i.lock.castaddr;
113*4882a593Smuzhiyun 		kb->i.lock.bastparam = (void *)(long)kb32->i.lock.bastparam;
114*4882a593Smuzhiyun 		kb->i.lock.bastaddr = (void *)(long)kb32->i.lock.bastaddr;
115*4882a593Smuzhiyun 		kb->i.lock.lksb = (void *)(long)kb32->i.lock.lksb;
116*4882a593Smuzhiyun 		memcpy(kb->i.lock.lvb, kb32->i.lock.lvb, DLM_USER_LVB_LEN);
117*4882a593Smuzhiyun 		memcpy(kb->i.lock.name, kb32->i.lock.name, namelen);
118*4882a593Smuzhiyun 	}
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun 
compat_output(struct dlm_lock_result * res,struct dlm_lock_result32 * res32)121*4882a593Smuzhiyun static void compat_output(struct dlm_lock_result *res,
122*4882a593Smuzhiyun 			  struct dlm_lock_result32 *res32)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun 	memset(res32, 0, sizeof(*res32));
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	res32->version[0] = res->version[0];
127*4882a593Smuzhiyun 	res32->version[1] = res->version[1];
128*4882a593Smuzhiyun 	res32->version[2] = res->version[2];
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	res32->user_astaddr = (__u32)(long)res->user_astaddr;
131*4882a593Smuzhiyun 	res32->user_astparam = (__u32)(long)res->user_astparam;
132*4882a593Smuzhiyun 	res32->user_lksb = (__u32)(long)res->user_lksb;
133*4882a593Smuzhiyun 	res32->bast_mode = res->bast_mode;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	res32->lvb_offset = res->lvb_offset;
136*4882a593Smuzhiyun 	res32->length = res->length;
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	res32->lksb.sb_status = res->lksb.sb_status;
139*4882a593Smuzhiyun 	res32->lksb.sb_flags = res->lksb.sb_flags;
140*4882a593Smuzhiyun 	res32->lksb.sb_lkid = res->lksb.sb_lkid;
141*4882a593Smuzhiyun 	res32->lksb.sb_lvbptr = (__u32)(long)res->lksb.sb_lvbptr;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun #endif
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun /* Figure out if this lock is at the end of its life and no longer
146*4882a593Smuzhiyun    available for the application to use.  The lkb still exists until
147*4882a593Smuzhiyun    the final ast is read.  A lock becomes EOL in three situations:
148*4882a593Smuzhiyun      1. a noqueue request fails with EAGAIN
149*4882a593Smuzhiyun      2. an unlock completes with EUNLOCK
150*4882a593Smuzhiyun      3. a cancel of a waiting request completes with ECANCEL/EDEADLK
151*4882a593Smuzhiyun    An EOL lock needs to be removed from the process's list of locks.
152*4882a593Smuzhiyun    And we can't allow any new operation on an EOL lock.  This is
153*4882a593Smuzhiyun    not related to the lifetime of the lkb struct which is managed
154*4882a593Smuzhiyun    entirely by refcount. */
155*4882a593Smuzhiyun 
lkb_is_endoflife(int mode,int status)156*4882a593Smuzhiyun static int lkb_is_endoflife(int mode, int status)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun 	switch (status) {
159*4882a593Smuzhiyun 	case -DLM_EUNLOCK:
160*4882a593Smuzhiyun 		return 1;
161*4882a593Smuzhiyun 	case -DLM_ECANCEL:
162*4882a593Smuzhiyun 	case -ETIMEDOUT:
163*4882a593Smuzhiyun 	case -EDEADLK:
164*4882a593Smuzhiyun 	case -EAGAIN:
165*4882a593Smuzhiyun 		if (mode == DLM_LOCK_IV)
166*4882a593Smuzhiyun 			return 1;
167*4882a593Smuzhiyun 		break;
168*4882a593Smuzhiyun 	}
169*4882a593Smuzhiyun 	return 0;
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun /* we could possibly check if the cancel of an orphan has resulted in the lkb
173*4882a593Smuzhiyun    being removed and then remove that lkb from the orphans list and free it */
174*4882a593Smuzhiyun 
dlm_user_add_ast(struct dlm_lkb * lkb,uint32_t flags,int mode,int status,uint32_t sbflags,uint64_t seq)175*4882a593Smuzhiyun void dlm_user_add_ast(struct dlm_lkb *lkb, uint32_t flags, int mode,
176*4882a593Smuzhiyun 		      int status, uint32_t sbflags, uint64_t seq)
177*4882a593Smuzhiyun {
178*4882a593Smuzhiyun 	struct dlm_ls *ls;
179*4882a593Smuzhiyun 	struct dlm_user_args *ua;
180*4882a593Smuzhiyun 	struct dlm_user_proc *proc;
181*4882a593Smuzhiyun 	int rv;
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 	if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD))
184*4882a593Smuzhiyun 		return;
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	ls = lkb->lkb_resource->res_ls;
187*4882a593Smuzhiyun 	mutex_lock(&ls->ls_clear_proc_locks);
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	/* If ORPHAN/DEAD flag is set, it means the process is dead so an ast
190*4882a593Smuzhiyun 	   can't be delivered.  For ORPHAN's, dlm_clear_proc_locks() freed
191*4882a593Smuzhiyun 	   lkb->ua so we can't try to use it.  This second check is necessary
192*4882a593Smuzhiyun 	   for cases where a completion ast is received for an operation that
193*4882a593Smuzhiyun 	   began before clear_proc_locks did its cancel/unlock. */
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD))
196*4882a593Smuzhiyun 		goto out;
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	DLM_ASSERT(lkb->lkb_ua, dlm_print_lkb(lkb););
199*4882a593Smuzhiyun 	ua = lkb->lkb_ua;
200*4882a593Smuzhiyun 	proc = ua->proc;
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	if ((flags & DLM_CB_BAST) && ua->bastaddr == NULL)
203*4882a593Smuzhiyun 		goto out;
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	if ((flags & DLM_CB_CAST) && lkb_is_endoflife(mode, status))
206*4882a593Smuzhiyun 		lkb->lkb_flags |= DLM_IFL_ENDOFLIFE;
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	spin_lock(&proc->asts_spin);
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	rv = dlm_add_lkb_callback(lkb, flags, mode, status, sbflags, seq);
211*4882a593Smuzhiyun 	if (rv < 0) {
212*4882a593Smuzhiyun 		spin_unlock(&proc->asts_spin);
213*4882a593Smuzhiyun 		goto out;
214*4882a593Smuzhiyun 	}
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	if (list_empty(&lkb->lkb_cb_list)) {
217*4882a593Smuzhiyun 		kref_get(&lkb->lkb_ref);
218*4882a593Smuzhiyun 		list_add_tail(&lkb->lkb_cb_list, &proc->asts);
219*4882a593Smuzhiyun 		wake_up_interruptible(&proc->wait);
220*4882a593Smuzhiyun 	}
221*4882a593Smuzhiyun 	spin_unlock(&proc->asts_spin);
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	if (lkb->lkb_flags & DLM_IFL_ENDOFLIFE) {
224*4882a593Smuzhiyun 		/* N.B. spin_lock locks_spin, not asts_spin */
225*4882a593Smuzhiyun 		spin_lock(&proc->locks_spin);
226*4882a593Smuzhiyun 		if (!list_empty(&lkb->lkb_ownqueue)) {
227*4882a593Smuzhiyun 			list_del_init(&lkb->lkb_ownqueue);
228*4882a593Smuzhiyun 			dlm_put_lkb(lkb);
229*4882a593Smuzhiyun 		}
230*4882a593Smuzhiyun 		spin_unlock(&proc->locks_spin);
231*4882a593Smuzhiyun 	}
232*4882a593Smuzhiyun  out:
233*4882a593Smuzhiyun 	mutex_unlock(&ls->ls_clear_proc_locks);
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun 
device_user_lock(struct dlm_user_proc * proc,struct dlm_lock_params * params)236*4882a593Smuzhiyun static int device_user_lock(struct dlm_user_proc *proc,
237*4882a593Smuzhiyun 			    struct dlm_lock_params *params)
238*4882a593Smuzhiyun {
239*4882a593Smuzhiyun 	struct dlm_ls *ls;
240*4882a593Smuzhiyun 	struct dlm_user_args *ua;
241*4882a593Smuzhiyun 	uint32_t lkid;
242*4882a593Smuzhiyun 	int error = -ENOMEM;
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 	ls = dlm_find_lockspace_local(proc->lockspace);
245*4882a593Smuzhiyun 	if (!ls)
246*4882a593Smuzhiyun 		return -ENOENT;
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	if (!params->castaddr || !params->lksb) {
249*4882a593Smuzhiyun 		error = -EINVAL;
250*4882a593Smuzhiyun 		goto out;
251*4882a593Smuzhiyun 	}
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	ua = kzalloc(sizeof(struct dlm_user_args), GFP_NOFS);
254*4882a593Smuzhiyun 	if (!ua)
255*4882a593Smuzhiyun 		goto out;
256*4882a593Smuzhiyun 	ua->proc = proc;
257*4882a593Smuzhiyun 	ua->user_lksb = params->lksb;
258*4882a593Smuzhiyun 	ua->castparam = params->castparam;
259*4882a593Smuzhiyun 	ua->castaddr = params->castaddr;
260*4882a593Smuzhiyun 	ua->bastparam = params->bastparam;
261*4882a593Smuzhiyun 	ua->bastaddr = params->bastaddr;
262*4882a593Smuzhiyun 	ua->xid = params->xid;
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	if (params->flags & DLM_LKF_CONVERT) {
265*4882a593Smuzhiyun 		error = dlm_user_convert(ls, ua,
266*4882a593Smuzhiyun 				         params->mode, params->flags,
267*4882a593Smuzhiyun 				         params->lkid, params->lvb,
268*4882a593Smuzhiyun 					 (unsigned long) params->timeout);
269*4882a593Smuzhiyun 	} else if (params->flags & DLM_LKF_ORPHAN) {
270*4882a593Smuzhiyun 		error = dlm_user_adopt_orphan(ls, ua,
271*4882a593Smuzhiyun 					 params->mode, params->flags,
272*4882a593Smuzhiyun 					 params->name, params->namelen,
273*4882a593Smuzhiyun 					 (unsigned long) params->timeout,
274*4882a593Smuzhiyun 					 &lkid);
275*4882a593Smuzhiyun 		if (!error)
276*4882a593Smuzhiyun 			error = lkid;
277*4882a593Smuzhiyun 	} else {
278*4882a593Smuzhiyun 		error = dlm_user_request(ls, ua,
279*4882a593Smuzhiyun 					 params->mode, params->flags,
280*4882a593Smuzhiyun 					 params->name, params->namelen,
281*4882a593Smuzhiyun 					 (unsigned long) params->timeout);
282*4882a593Smuzhiyun 		if (!error)
283*4882a593Smuzhiyun 			error = ua->lksb.sb_lkid;
284*4882a593Smuzhiyun 	}
285*4882a593Smuzhiyun  out:
286*4882a593Smuzhiyun 	dlm_put_lockspace(ls);
287*4882a593Smuzhiyun 	return error;
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun 
device_user_unlock(struct dlm_user_proc * proc,struct dlm_lock_params * params)290*4882a593Smuzhiyun static int device_user_unlock(struct dlm_user_proc *proc,
291*4882a593Smuzhiyun 			      struct dlm_lock_params *params)
292*4882a593Smuzhiyun {
293*4882a593Smuzhiyun 	struct dlm_ls *ls;
294*4882a593Smuzhiyun 	struct dlm_user_args *ua;
295*4882a593Smuzhiyun 	int error = -ENOMEM;
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	ls = dlm_find_lockspace_local(proc->lockspace);
298*4882a593Smuzhiyun 	if (!ls)
299*4882a593Smuzhiyun 		return -ENOENT;
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	ua = kzalloc(sizeof(struct dlm_user_args), GFP_NOFS);
302*4882a593Smuzhiyun 	if (!ua)
303*4882a593Smuzhiyun 		goto out;
304*4882a593Smuzhiyun 	ua->proc = proc;
305*4882a593Smuzhiyun 	ua->user_lksb = params->lksb;
306*4882a593Smuzhiyun 	ua->castparam = params->castparam;
307*4882a593Smuzhiyun 	ua->castaddr = params->castaddr;
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	if (params->flags & DLM_LKF_CANCEL)
310*4882a593Smuzhiyun 		error = dlm_user_cancel(ls, ua, params->flags, params->lkid);
311*4882a593Smuzhiyun 	else
312*4882a593Smuzhiyun 		error = dlm_user_unlock(ls, ua, params->flags, params->lkid,
313*4882a593Smuzhiyun 					params->lvb);
314*4882a593Smuzhiyun  out:
315*4882a593Smuzhiyun 	dlm_put_lockspace(ls);
316*4882a593Smuzhiyun 	return error;
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun 
device_user_deadlock(struct dlm_user_proc * proc,struct dlm_lock_params * params)319*4882a593Smuzhiyun static int device_user_deadlock(struct dlm_user_proc *proc,
320*4882a593Smuzhiyun 				struct dlm_lock_params *params)
321*4882a593Smuzhiyun {
322*4882a593Smuzhiyun 	struct dlm_ls *ls;
323*4882a593Smuzhiyun 	int error;
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun 	ls = dlm_find_lockspace_local(proc->lockspace);
326*4882a593Smuzhiyun 	if (!ls)
327*4882a593Smuzhiyun 		return -ENOENT;
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	error = dlm_user_deadlock(ls, params->flags, params->lkid);
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun 	dlm_put_lockspace(ls);
332*4882a593Smuzhiyun 	return error;
333*4882a593Smuzhiyun }
334*4882a593Smuzhiyun 
dlm_device_register(struct dlm_ls * ls,char * name)335*4882a593Smuzhiyun static int dlm_device_register(struct dlm_ls *ls, char *name)
336*4882a593Smuzhiyun {
337*4882a593Smuzhiyun 	int error, len;
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	/* The device is already registered.  This happens when the
340*4882a593Smuzhiyun 	   lockspace is created multiple times from userspace. */
341*4882a593Smuzhiyun 	if (ls->ls_device.name)
342*4882a593Smuzhiyun 		return 0;
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 	error = -ENOMEM;
345*4882a593Smuzhiyun 	len = strlen(name) + strlen(name_prefix) + 2;
346*4882a593Smuzhiyun 	ls->ls_device.name = kzalloc(len, GFP_NOFS);
347*4882a593Smuzhiyun 	if (!ls->ls_device.name)
348*4882a593Smuzhiyun 		goto fail;
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 	snprintf((char *)ls->ls_device.name, len, "%s_%s", name_prefix,
351*4882a593Smuzhiyun 		 name);
352*4882a593Smuzhiyun 	ls->ls_device.fops = &device_fops;
353*4882a593Smuzhiyun 	ls->ls_device.minor = MISC_DYNAMIC_MINOR;
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	error = misc_register(&ls->ls_device);
356*4882a593Smuzhiyun 	if (error) {
357*4882a593Smuzhiyun 		kfree(ls->ls_device.name);
358*4882a593Smuzhiyun 		/* this has to be set to NULL
359*4882a593Smuzhiyun 		 * to avoid a double-free in dlm_device_deregister
360*4882a593Smuzhiyun 		 */
361*4882a593Smuzhiyun 		ls->ls_device.name = NULL;
362*4882a593Smuzhiyun 	}
363*4882a593Smuzhiyun fail:
364*4882a593Smuzhiyun 	return error;
365*4882a593Smuzhiyun }
366*4882a593Smuzhiyun 
dlm_device_deregister(struct dlm_ls * ls)367*4882a593Smuzhiyun int dlm_device_deregister(struct dlm_ls *ls)
368*4882a593Smuzhiyun {
369*4882a593Smuzhiyun 	/* The device is not registered.  This happens when the lockspace
370*4882a593Smuzhiyun 	   was never used from userspace, or when device_create_lockspace()
371*4882a593Smuzhiyun 	   calls dlm_release_lockspace() after the register fails. */
372*4882a593Smuzhiyun 	if (!ls->ls_device.name)
373*4882a593Smuzhiyun 		return 0;
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	misc_deregister(&ls->ls_device);
376*4882a593Smuzhiyun 	kfree(ls->ls_device.name);
377*4882a593Smuzhiyun 	return 0;
378*4882a593Smuzhiyun }
379*4882a593Smuzhiyun 
device_user_purge(struct dlm_user_proc * proc,struct dlm_purge_params * params)380*4882a593Smuzhiyun static int device_user_purge(struct dlm_user_proc *proc,
381*4882a593Smuzhiyun 			     struct dlm_purge_params *params)
382*4882a593Smuzhiyun {
383*4882a593Smuzhiyun 	struct dlm_ls *ls;
384*4882a593Smuzhiyun 	int error;
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	ls = dlm_find_lockspace_local(proc->lockspace);
387*4882a593Smuzhiyun 	if (!ls)
388*4882a593Smuzhiyun 		return -ENOENT;
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 	error = dlm_user_purge(ls, proc, params->nodeid, params->pid);
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun 	dlm_put_lockspace(ls);
393*4882a593Smuzhiyun 	return error;
394*4882a593Smuzhiyun }
395*4882a593Smuzhiyun 
device_create_lockspace(struct dlm_lspace_params * params)396*4882a593Smuzhiyun static int device_create_lockspace(struct dlm_lspace_params *params)
397*4882a593Smuzhiyun {
398*4882a593Smuzhiyun 	dlm_lockspace_t *lockspace;
399*4882a593Smuzhiyun 	struct dlm_ls *ls;
400*4882a593Smuzhiyun 	int error;
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 	if (!capable(CAP_SYS_ADMIN))
403*4882a593Smuzhiyun 		return -EPERM;
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 	error = dlm_new_lockspace(params->name, dlm_config.ci_cluster_name, params->flags,
406*4882a593Smuzhiyun 				  DLM_USER_LVB_LEN, NULL, NULL, NULL,
407*4882a593Smuzhiyun 				  &lockspace);
408*4882a593Smuzhiyun 	if (error)
409*4882a593Smuzhiyun 		return error;
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 	ls = dlm_find_lockspace_local(lockspace);
412*4882a593Smuzhiyun 	if (!ls)
413*4882a593Smuzhiyun 		return -ENOENT;
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 	error = dlm_device_register(ls, params->name);
416*4882a593Smuzhiyun 	dlm_put_lockspace(ls);
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 	if (error)
419*4882a593Smuzhiyun 		dlm_release_lockspace(lockspace, 0);
420*4882a593Smuzhiyun 	else
421*4882a593Smuzhiyun 		error = ls->ls_device.minor;
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 	return error;
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun 
device_remove_lockspace(struct dlm_lspace_params * params)426*4882a593Smuzhiyun static int device_remove_lockspace(struct dlm_lspace_params *params)
427*4882a593Smuzhiyun {
428*4882a593Smuzhiyun 	dlm_lockspace_t *lockspace;
429*4882a593Smuzhiyun 	struct dlm_ls *ls;
430*4882a593Smuzhiyun 	int error, force = 0;
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 	if (!capable(CAP_SYS_ADMIN))
433*4882a593Smuzhiyun 		return -EPERM;
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun 	ls = dlm_find_lockspace_device(params->minor);
436*4882a593Smuzhiyun 	if (!ls)
437*4882a593Smuzhiyun 		return -ENOENT;
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 	if (params->flags & DLM_USER_LSFLG_FORCEFREE)
440*4882a593Smuzhiyun 		force = 2;
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 	lockspace = ls->ls_local_handle;
443*4882a593Smuzhiyun 	dlm_put_lockspace(ls);
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 	/* The final dlm_release_lockspace waits for references to go to
446*4882a593Smuzhiyun 	   zero, so all processes will need to close their device for the
447*4882a593Smuzhiyun 	   ls before the release will proceed.  release also calls the
448*4882a593Smuzhiyun 	   device_deregister above.  Converting a positive return value
449*4882a593Smuzhiyun 	   from release to zero means that userspace won't know when its
450*4882a593Smuzhiyun 	   release was the final one, but it shouldn't need to know. */
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 	error = dlm_release_lockspace(lockspace, force);
453*4882a593Smuzhiyun 	if (error > 0)
454*4882a593Smuzhiyun 		error = 0;
455*4882a593Smuzhiyun 	return error;
456*4882a593Smuzhiyun }
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun /* Check the user's version matches ours */
check_version(struct dlm_write_request * req)459*4882a593Smuzhiyun static int check_version(struct dlm_write_request *req)
460*4882a593Smuzhiyun {
461*4882a593Smuzhiyun 	if (req->version[0] != DLM_DEVICE_VERSION_MAJOR ||
462*4882a593Smuzhiyun 	    (req->version[0] == DLM_DEVICE_VERSION_MAJOR &&
463*4882a593Smuzhiyun 	     req->version[1] > DLM_DEVICE_VERSION_MINOR)) {
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 		printk(KERN_DEBUG "dlm: process %s (%d) version mismatch "
466*4882a593Smuzhiyun 		       "user (%d.%d.%d) kernel (%d.%d.%d)\n",
467*4882a593Smuzhiyun 		       current->comm,
468*4882a593Smuzhiyun 		       task_pid_nr(current),
469*4882a593Smuzhiyun 		       req->version[0],
470*4882a593Smuzhiyun 		       req->version[1],
471*4882a593Smuzhiyun 		       req->version[2],
472*4882a593Smuzhiyun 		       DLM_DEVICE_VERSION_MAJOR,
473*4882a593Smuzhiyun 		       DLM_DEVICE_VERSION_MINOR,
474*4882a593Smuzhiyun 		       DLM_DEVICE_VERSION_PATCH);
475*4882a593Smuzhiyun 		return -EINVAL;
476*4882a593Smuzhiyun 	}
477*4882a593Smuzhiyun 	return 0;
478*4882a593Smuzhiyun }
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun /*
481*4882a593Smuzhiyun  * device_write
482*4882a593Smuzhiyun  *
483*4882a593Smuzhiyun  *   device_user_lock
484*4882a593Smuzhiyun  *     dlm_user_request -> request_lock
485*4882a593Smuzhiyun  *     dlm_user_convert -> convert_lock
486*4882a593Smuzhiyun  *
487*4882a593Smuzhiyun  *   device_user_unlock
488*4882a593Smuzhiyun  *     dlm_user_unlock -> unlock_lock
489*4882a593Smuzhiyun  *     dlm_user_cancel -> cancel_lock
490*4882a593Smuzhiyun  *
491*4882a593Smuzhiyun  *   device_create_lockspace
492*4882a593Smuzhiyun  *     dlm_new_lockspace
493*4882a593Smuzhiyun  *
494*4882a593Smuzhiyun  *   device_remove_lockspace
495*4882a593Smuzhiyun  *     dlm_release_lockspace
496*4882a593Smuzhiyun  */
497*4882a593Smuzhiyun 
498*4882a593Smuzhiyun /* a write to a lockspace device is a lock or unlock request, a write
499*4882a593Smuzhiyun    to the control device is to create/remove a lockspace */
500*4882a593Smuzhiyun 
device_write(struct file * file,const char __user * buf,size_t count,loff_t * ppos)501*4882a593Smuzhiyun static ssize_t device_write(struct file *file, const char __user *buf,
502*4882a593Smuzhiyun 			    size_t count, loff_t *ppos)
503*4882a593Smuzhiyun {
504*4882a593Smuzhiyun 	struct dlm_user_proc *proc = file->private_data;
505*4882a593Smuzhiyun 	struct dlm_write_request *kbuf;
506*4882a593Smuzhiyun 	int error;
507*4882a593Smuzhiyun 
508*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
509*4882a593Smuzhiyun 	if (count < sizeof(struct dlm_write_request32))
510*4882a593Smuzhiyun #else
511*4882a593Smuzhiyun 	if (count < sizeof(struct dlm_write_request))
512*4882a593Smuzhiyun #endif
513*4882a593Smuzhiyun 		return -EINVAL;
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun 	/*
516*4882a593Smuzhiyun 	 * can't compare against COMPAT/dlm_write_request32 because
517*4882a593Smuzhiyun 	 * we don't yet know if is64bit is zero
518*4882a593Smuzhiyun 	 */
519*4882a593Smuzhiyun 	if (count > sizeof(struct dlm_write_request) + DLM_RESNAME_MAXLEN)
520*4882a593Smuzhiyun 		return -EINVAL;
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun 	kbuf = memdup_user_nul(buf, count);
523*4882a593Smuzhiyun 	if (IS_ERR(kbuf))
524*4882a593Smuzhiyun 		return PTR_ERR(kbuf);
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun 	if (check_version(kbuf)) {
527*4882a593Smuzhiyun 		error = -EBADE;
528*4882a593Smuzhiyun 		goto out_free;
529*4882a593Smuzhiyun 	}
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
532*4882a593Smuzhiyun 	if (!kbuf->is64bit) {
533*4882a593Smuzhiyun 		struct dlm_write_request32 *k32buf;
534*4882a593Smuzhiyun 		int namelen = 0;
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun 		if (count > sizeof(struct dlm_write_request32))
537*4882a593Smuzhiyun 			namelen = count - sizeof(struct dlm_write_request32);
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun 		k32buf = (struct dlm_write_request32 *)kbuf;
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun 		/* add 1 after namelen so that the name string is terminated */
542*4882a593Smuzhiyun 		kbuf = kzalloc(sizeof(struct dlm_write_request) + namelen + 1,
543*4882a593Smuzhiyun 			       GFP_NOFS);
544*4882a593Smuzhiyun 		if (!kbuf) {
545*4882a593Smuzhiyun 			kfree(k32buf);
546*4882a593Smuzhiyun 			return -ENOMEM;
547*4882a593Smuzhiyun 		}
548*4882a593Smuzhiyun 
549*4882a593Smuzhiyun 		if (proc)
550*4882a593Smuzhiyun 			set_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags);
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun 		compat_input(kbuf, k32buf, namelen);
553*4882a593Smuzhiyun 		kfree(k32buf);
554*4882a593Smuzhiyun 	}
555*4882a593Smuzhiyun #endif
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun 	/* do we really need this? can a write happen after a close? */
558*4882a593Smuzhiyun 	if ((kbuf->cmd == DLM_USER_LOCK || kbuf->cmd == DLM_USER_UNLOCK) &&
559*4882a593Smuzhiyun 	    (proc && test_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags))) {
560*4882a593Smuzhiyun 		error = -EINVAL;
561*4882a593Smuzhiyun 		goto out_free;
562*4882a593Smuzhiyun 	}
563*4882a593Smuzhiyun 
564*4882a593Smuzhiyun 	error = -EINVAL;
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun 	switch (kbuf->cmd)
567*4882a593Smuzhiyun 	{
568*4882a593Smuzhiyun 	case DLM_USER_LOCK:
569*4882a593Smuzhiyun 		if (!proc) {
570*4882a593Smuzhiyun 			log_print("no locking on control device");
571*4882a593Smuzhiyun 			goto out_free;
572*4882a593Smuzhiyun 		}
573*4882a593Smuzhiyun 		error = device_user_lock(proc, &kbuf->i.lock);
574*4882a593Smuzhiyun 		break;
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun 	case DLM_USER_UNLOCK:
577*4882a593Smuzhiyun 		if (!proc) {
578*4882a593Smuzhiyun 			log_print("no locking on control device");
579*4882a593Smuzhiyun 			goto out_free;
580*4882a593Smuzhiyun 		}
581*4882a593Smuzhiyun 		error = device_user_unlock(proc, &kbuf->i.lock);
582*4882a593Smuzhiyun 		break;
583*4882a593Smuzhiyun 
584*4882a593Smuzhiyun 	case DLM_USER_DEADLOCK:
585*4882a593Smuzhiyun 		if (!proc) {
586*4882a593Smuzhiyun 			log_print("no locking on control device");
587*4882a593Smuzhiyun 			goto out_free;
588*4882a593Smuzhiyun 		}
589*4882a593Smuzhiyun 		error = device_user_deadlock(proc, &kbuf->i.lock);
590*4882a593Smuzhiyun 		break;
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun 	case DLM_USER_CREATE_LOCKSPACE:
593*4882a593Smuzhiyun 		if (proc) {
594*4882a593Smuzhiyun 			log_print("create/remove only on control device");
595*4882a593Smuzhiyun 			goto out_free;
596*4882a593Smuzhiyun 		}
597*4882a593Smuzhiyun 		error = device_create_lockspace(&kbuf->i.lspace);
598*4882a593Smuzhiyun 		break;
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 	case DLM_USER_REMOVE_LOCKSPACE:
601*4882a593Smuzhiyun 		if (proc) {
602*4882a593Smuzhiyun 			log_print("create/remove only on control device");
603*4882a593Smuzhiyun 			goto out_free;
604*4882a593Smuzhiyun 		}
605*4882a593Smuzhiyun 		error = device_remove_lockspace(&kbuf->i.lspace);
606*4882a593Smuzhiyun 		break;
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun 	case DLM_USER_PURGE:
609*4882a593Smuzhiyun 		if (!proc) {
610*4882a593Smuzhiyun 			log_print("no locking on control device");
611*4882a593Smuzhiyun 			goto out_free;
612*4882a593Smuzhiyun 		}
613*4882a593Smuzhiyun 		error = device_user_purge(proc, &kbuf->i.purge);
614*4882a593Smuzhiyun 		break;
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun 	default:
617*4882a593Smuzhiyun 		log_print("Unknown command passed to DLM device : %d\n",
618*4882a593Smuzhiyun 			  kbuf->cmd);
619*4882a593Smuzhiyun 	}
620*4882a593Smuzhiyun 
621*4882a593Smuzhiyun  out_free:
622*4882a593Smuzhiyun 	kfree(kbuf);
623*4882a593Smuzhiyun 	return error;
624*4882a593Smuzhiyun }
625*4882a593Smuzhiyun 
626*4882a593Smuzhiyun /* Every process that opens the lockspace device has its own "proc" structure
627*4882a593Smuzhiyun    hanging off the open file that's used to keep track of locks owned by the
628*4882a593Smuzhiyun    process and asts that need to be delivered to the process. */
629*4882a593Smuzhiyun 
device_open(struct inode * inode,struct file * file)630*4882a593Smuzhiyun static int device_open(struct inode *inode, struct file *file)
631*4882a593Smuzhiyun {
632*4882a593Smuzhiyun 	struct dlm_user_proc *proc;
633*4882a593Smuzhiyun 	struct dlm_ls *ls;
634*4882a593Smuzhiyun 
635*4882a593Smuzhiyun 	ls = dlm_find_lockspace_device(iminor(inode));
636*4882a593Smuzhiyun 	if (!ls)
637*4882a593Smuzhiyun 		return -ENOENT;
638*4882a593Smuzhiyun 
639*4882a593Smuzhiyun 	proc = kzalloc(sizeof(struct dlm_user_proc), GFP_NOFS);
640*4882a593Smuzhiyun 	if (!proc) {
641*4882a593Smuzhiyun 		dlm_put_lockspace(ls);
642*4882a593Smuzhiyun 		return -ENOMEM;
643*4882a593Smuzhiyun 	}
644*4882a593Smuzhiyun 
645*4882a593Smuzhiyun 	proc->lockspace = ls->ls_local_handle;
646*4882a593Smuzhiyun 	INIT_LIST_HEAD(&proc->asts);
647*4882a593Smuzhiyun 	INIT_LIST_HEAD(&proc->locks);
648*4882a593Smuzhiyun 	INIT_LIST_HEAD(&proc->unlocking);
649*4882a593Smuzhiyun 	spin_lock_init(&proc->asts_spin);
650*4882a593Smuzhiyun 	spin_lock_init(&proc->locks_spin);
651*4882a593Smuzhiyun 	init_waitqueue_head(&proc->wait);
652*4882a593Smuzhiyun 	file->private_data = proc;
653*4882a593Smuzhiyun 
654*4882a593Smuzhiyun 	return 0;
655*4882a593Smuzhiyun }
656*4882a593Smuzhiyun 
device_close(struct inode * inode,struct file * file)657*4882a593Smuzhiyun static int device_close(struct inode *inode, struct file *file)
658*4882a593Smuzhiyun {
659*4882a593Smuzhiyun 	struct dlm_user_proc *proc = file->private_data;
660*4882a593Smuzhiyun 	struct dlm_ls *ls;
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun 	ls = dlm_find_lockspace_local(proc->lockspace);
663*4882a593Smuzhiyun 	if (!ls)
664*4882a593Smuzhiyun 		return -ENOENT;
665*4882a593Smuzhiyun 
666*4882a593Smuzhiyun 	set_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags);
667*4882a593Smuzhiyun 
668*4882a593Smuzhiyun 	dlm_clear_proc_locks(ls, proc);
669*4882a593Smuzhiyun 
670*4882a593Smuzhiyun 	/* at this point no more lkb's should exist for this lockspace,
671*4882a593Smuzhiyun 	   so there's no chance of dlm_user_add_ast() being called and
672*4882a593Smuzhiyun 	   looking for lkb->ua->proc */
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun 	kfree(proc);
675*4882a593Smuzhiyun 	file->private_data = NULL;
676*4882a593Smuzhiyun 
677*4882a593Smuzhiyun 	dlm_put_lockspace(ls);
678*4882a593Smuzhiyun 	dlm_put_lockspace(ls);  /* for the find in device_open() */
679*4882a593Smuzhiyun 
680*4882a593Smuzhiyun 	/* FIXME: AUTOFREE: if this ls is no longer used do
681*4882a593Smuzhiyun 	   device_remove_lockspace() */
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun 	return 0;
684*4882a593Smuzhiyun }
685*4882a593Smuzhiyun 
copy_result_to_user(struct dlm_user_args * ua,int compat,uint32_t flags,int mode,int copy_lvb,char __user * buf,size_t count)686*4882a593Smuzhiyun static int copy_result_to_user(struct dlm_user_args *ua, int compat,
687*4882a593Smuzhiyun 			       uint32_t flags, int mode, int copy_lvb,
688*4882a593Smuzhiyun 			       char __user *buf, size_t count)
689*4882a593Smuzhiyun {
690*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
691*4882a593Smuzhiyun 	struct dlm_lock_result32 result32;
692*4882a593Smuzhiyun #endif
693*4882a593Smuzhiyun 	struct dlm_lock_result result;
694*4882a593Smuzhiyun 	void *resultptr;
695*4882a593Smuzhiyun 	int error=0;
696*4882a593Smuzhiyun 	int len;
697*4882a593Smuzhiyun 	int struct_len;
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun 	memset(&result, 0, sizeof(struct dlm_lock_result));
700*4882a593Smuzhiyun 	result.version[0] = DLM_DEVICE_VERSION_MAJOR;
701*4882a593Smuzhiyun 	result.version[1] = DLM_DEVICE_VERSION_MINOR;
702*4882a593Smuzhiyun 	result.version[2] = DLM_DEVICE_VERSION_PATCH;
703*4882a593Smuzhiyun 	memcpy(&result.lksb, &ua->lksb, offsetof(struct dlm_lksb, sb_lvbptr));
704*4882a593Smuzhiyun 	result.user_lksb = ua->user_lksb;
705*4882a593Smuzhiyun 
706*4882a593Smuzhiyun 	/* FIXME: dlm1 provides for the user's bastparam/addr to not be updated
707*4882a593Smuzhiyun 	   in a conversion unless the conversion is successful.  See code
708*4882a593Smuzhiyun 	   in dlm_user_convert() for updating ua from ua_tmp.  OpenVMS, though,
709*4882a593Smuzhiyun 	   notes that a new blocking AST address and parameter are set even if
710*4882a593Smuzhiyun 	   the conversion fails, so maybe we should just do that. */
711*4882a593Smuzhiyun 
712*4882a593Smuzhiyun 	if (flags & DLM_CB_BAST) {
713*4882a593Smuzhiyun 		result.user_astaddr = ua->bastaddr;
714*4882a593Smuzhiyun 		result.user_astparam = ua->bastparam;
715*4882a593Smuzhiyun 		result.bast_mode = mode;
716*4882a593Smuzhiyun 	} else {
717*4882a593Smuzhiyun 		result.user_astaddr = ua->castaddr;
718*4882a593Smuzhiyun 		result.user_astparam = ua->castparam;
719*4882a593Smuzhiyun 	}
720*4882a593Smuzhiyun 
721*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
722*4882a593Smuzhiyun 	if (compat)
723*4882a593Smuzhiyun 		len = sizeof(struct dlm_lock_result32);
724*4882a593Smuzhiyun 	else
725*4882a593Smuzhiyun #endif
726*4882a593Smuzhiyun 		len = sizeof(struct dlm_lock_result);
727*4882a593Smuzhiyun 	struct_len = len;
728*4882a593Smuzhiyun 
729*4882a593Smuzhiyun 	/* copy lvb to userspace if there is one, it's been updated, and
730*4882a593Smuzhiyun 	   the user buffer has space for it */
731*4882a593Smuzhiyun 
732*4882a593Smuzhiyun 	if (copy_lvb && ua->lksb.sb_lvbptr && count >= len + DLM_USER_LVB_LEN) {
733*4882a593Smuzhiyun 		if (copy_to_user(buf+len, ua->lksb.sb_lvbptr,
734*4882a593Smuzhiyun 				 DLM_USER_LVB_LEN)) {
735*4882a593Smuzhiyun 			error = -EFAULT;
736*4882a593Smuzhiyun 			goto out;
737*4882a593Smuzhiyun 		}
738*4882a593Smuzhiyun 
739*4882a593Smuzhiyun 		result.lvb_offset = len;
740*4882a593Smuzhiyun 		len += DLM_USER_LVB_LEN;
741*4882a593Smuzhiyun 	}
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun 	result.length = len;
744*4882a593Smuzhiyun 	resultptr = &result;
745*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
746*4882a593Smuzhiyun 	if (compat) {
747*4882a593Smuzhiyun 		compat_output(&result, &result32);
748*4882a593Smuzhiyun 		resultptr = &result32;
749*4882a593Smuzhiyun 	}
750*4882a593Smuzhiyun #endif
751*4882a593Smuzhiyun 
752*4882a593Smuzhiyun 	if (copy_to_user(buf, resultptr, struct_len))
753*4882a593Smuzhiyun 		error = -EFAULT;
754*4882a593Smuzhiyun 	else
755*4882a593Smuzhiyun 		error = len;
756*4882a593Smuzhiyun  out:
757*4882a593Smuzhiyun 	return error;
758*4882a593Smuzhiyun }
759*4882a593Smuzhiyun 
copy_version_to_user(char __user * buf,size_t count)760*4882a593Smuzhiyun static int copy_version_to_user(char __user *buf, size_t count)
761*4882a593Smuzhiyun {
762*4882a593Smuzhiyun 	struct dlm_device_version ver;
763*4882a593Smuzhiyun 
764*4882a593Smuzhiyun 	memset(&ver, 0, sizeof(struct dlm_device_version));
765*4882a593Smuzhiyun 	ver.version[0] = DLM_DEVICE_VERSION_MAJOR;
766*4882a593Smuzhiyun 	ver.version[1] = DLM_DEVICE_VERSION_MINOR;
767*4882a593Smuzhiyun 	ver.version[2] = DLM_DEVICE_VERSION_PATCH;
768*4882a593Smuzhiyun 
769*4882a593Smuzhiyun 	if (copy_to_user(buf, &ver, sizeof(struct dlm_device_version)))
770*4882a593Smuzhiyun 		return -EFAULT;
771*4882a593Smuzhiyun 	return sizeof(struct dlm_device_version);
772*4882a593Smuzhiyun }
773*4882a593Smuzhiyun 
774*4882a593Smuzhiyun /* a read returns a single ast described in a struct dlm_lock_result */
775*4882a593Smuzhiyun 
device_read(struct file * file,char __user * buf,size_t count,loff_t * ppos)776*4882a593Smuzhiyun static ssize_t device_read(struct file *file, char __user *buf, size_t count,
777*4882a593Smuzhiyun 			   loff_t *ppos)
778*4882a593Smuzhiyun {
779*4882a593Smuzhiyun 	struct dlm_user_proc *proc = file->private_data;
780*4882a593Smuzhiyun 	struct dlm_lkb *lkb;
781*4882a593Smuzhiyun 	DECLARE_WAITQUEUE(wait, current);
782*4882a593Smuzhiyun 	struct dlm_callback cb;
783*4882a593Smuzhiyun 	int rv, resid, copy_lvb = 0;
784*4882a593Smuzhiyun 	int old_mode, new_mode;
785*4882a593Smuzhiyun 
786*4882a593Smuzhiyun 	if (count == sizeof(struct dlm_device_version)) {
787*4882a593Smuzhiyun 		rv = copy_version_to_user(buf, count);
788*4882a593Smuzhiyun 		return rv;
789*4882a593Smuzhiyun 	}
790*4882a593Smuzhiyun 
791*4882a593Smuzhiyun 	if (!proc) {
792*4882a593Smuzhiyun 		log_print("non-version read from control device %zu", count);
793*4882a593Smuzhiyun 		return -EINVAL;
794*4882a593Smuzhiyun 	}
795*4882a593Smuzhiyun 
796*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
797*4882a593Smuzhiyun 	if (count < sizeof(struct dlm_lock_result32))
798*4882a593Smuzhiyun #else
799*4882a593Smuzhiyun 	if (count < sizeof(struct dlm_lock_result))
800*4882a593Smuzhiyun #endif
801*4882a593Smuzhiyun 		return -EINVAL;
802*4882a593Smuzhiyun 
803*4882a593Smuzhiyun  try_another:
804*4882a593Smuzhiyun 
805*4882a593Smuzhiyun 	/* do we really need this? can a read happen after a close? */
806*4882a593Smuzhiyun 	if (test_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags))
807*4882a593Smuzhiyun 		return -EINVAL;
808*4882a593Smuzhiyun 
809*4882a593Smuzhiyun 	spin_lock(&proc->asts_spin);
810*4882a593Smuzhiyun 	if (list_empty(&proc->asts)) {
811*4882a593Smuzhiyun 		if (file->f_flags & O_NONBLOCK) {
812*4882a593Smuzhiyun 			spin_unlock(&proc->asts_spin);
813*4882a593Smuzhiyun 			return -EAGAIN;
814*4882a593Smuzhiyun 		}
815*4882a593Smuzhiyun 
816*4882a593Smuzhiyun 		add_wait_queue(&proc->wait, &wait);
817*4882a593Smuzhiyun 
818*4882a593Smuzhiyun 	repeat:
819*4882a593Smuzhiyun 		set_current_state(TASK_INTERRUPTIBLE);
820*4882a593Smuzhiyun 		if (list_empty(&proc->asts) && !signal_pending(current)) {
821*4882a593Smuzhiyun 			spin_unlock(&proc->asts_spin);
822*4882a593Smuzhiyun 			schedule();
823*4882a593Smuzhiyun 			spin_lock(&proc->asts_spin);
824*4882a593Smuzhiyun 			goto repeat;
825*4882a593Smuzhiyun 		}
826*4882a593Smuzhiyun 		set_current_state(TASK_RUNNING);
827*4882a593Smuzhiyun 		remove_wait_queue(&proc->wait, &wait);
828*4882a593Smuzhiyun 
829*4882a593Smuzhiyun 		if (signal_pending(current)) {
830*4882a593Smuzhiyun 			spin_unlock(&proc->asts_spin);
831*4882a593Smuzhiyun 			return -ERESTARTSYS;
832*4882a593Smuzhiyun 		}
833*4882a593Smuzhiyun 	}
834*4882a593Smuzhiyun 
835*4882a593Smuzhiyun 	/* if we empty lkb_callbacks, we don't want to unlock the spinlock
836*4882a593Smuzhiyun 	   without removing lkb_cb_list; so empty lkb_cb_list is always
837*4882a593Smuzhiyun 	   consistent with empty lkb_callbacks */
838*4882a593Smuzhiyun 
839*4882a593Smuzhiyun 	lkb = list_entry(proc->asts.next, struct dlm_lkb, lkb_cb_list);
840*4882a593Smuzhiyun 
841*4882a593Smuzhiyun 	/* rem_lkb_callback sets a new lkb_last_cast */
842*4882a593Smuzhiyun 	old_mode = lkb->lkb_last_cast.mode;
843*4882a593Smuzhiyun 
844*4882a593Smuzhiyun 	rv = dlm_rem_lkb_callback(lkb->lkb_resource->res_ls, lkb, &cb, &resid);
845*4882a593Smuzhiyun 	if (rv < 0) {
846*4882a593Smuzhiyun 		/* this shouldn't happen; lkb should have been removed from
847*4882a593Smuzhiyun 		   list when resid was zero */
848*4882a593Smuzhiyun 		log_print("dlm_rem_lkb_callback empty %x", lkb->lkb_id);
849*4882a593Smuzhiyun 		list_del_init(&lkb->lkb_cb_list);
850*4882a593Smuzhiyun 		spin_unlock(&proc->asts_spin);
851*4882a593Smuzhiyun 		/* removes ref for proc->asts, may cause lkb to be freed */
852*4882a593Smuzhiyun 		dlm_put_lkb(lkb);
853*4882a593Smuzhiyun 		goto try_another;
854*4882a593Smuzhiyun 	}
855*4882a593Smuzhiyun 	if (!resid)
856*4882a593Smuzhiyun 		list_del_init(&lkb->lkb_cb_list);
857*4882a593Smuzhiyun 	spin_unlock(&proc->asts_spin);
858*4882a593Smuzhiyun 
859*4882a593Smuzhiyun 	if (cb.flags & DLM_CB_SKIP) {
860*4882a593Smuzhiyun 		/* removes ref for proc->asts, may cause lkb to be freed */
861*4882a593Smuzhiyun 		if (!resid)
862*4882a593Smuzhiyun 			dlm_put_lkb(lkb);
863*4882a593Smuzhiyun 		goto try_another;
864*4882a593Smuzhiyun 	}
865*4882a593Smuzhiyun 
866*4882a593Smuzhiyun 	if (cb.flags & DLM_CB_CAST) {
867*4882a593Smuzhiyun 		new_mode = cb.mode;
868*4882a593Smuzhiyun 
869*4882a593Smuzhiyun 		if (!cb.sb_status && lkb->lkb_lksb->sb_lvbptr &&
870*4882a593Smuzhiyun 		    dlm_lvb_operations[old_mode + 1][new_mode + 1])
871*4882a593Smuzhiyun 			copy_lvb = 1;
872*4882a593Smuzhiyun 
873*4882a593Smuzhiyun 		lkb->lkb_lksb->sb_status = cb.sb_status;
874*4882a593Smuzhiyun 		lkb->lkb_lksb->sb_flags = cb.sb_flags;
875*4882a593Smuzhiyun 	}
876*4882a593Smuzhiyun 
877*4882a593Smuzhiyun 	rv = copy_result_to_user(lkb->lkb_ua,
878*4882a593Smuzhiyun 				 test_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags),
879*4882a593Smuzhiyun 				 cb.flags, cb.mode, copy_lvb, buf, count);
880*4882a593Smuzhiyun 
881*4882a593Smuzhiyun 	/* removes ref for proc->asts, may cause lkb to be freed */
882*4882a593Smuzhiyun 	if (!resid)
883*4882a593Smuzhiyun 		dlm_put_lkb(lkb);
884*4882a593Smuzhiyun 
885*4882a593Smuzhiyun 	return rv;
886*4882a593Smuzhiyun }
887*4882a593Smuzhiyun 
device_poll(struct file * file,poll_table * wait)888*4882a593Smuzhiyun static __poll_t device_poll(struct file *file, poll_table *wait)
889*4882a593Smuzhiyun {
890*4882a593Smuzhiyun 	struct dlm_user_proc *proc = file->private_data;
891*4882a593Smuzhiyun 
892*4882a593Smuzhiyun 	poll_wait(file, &proc->wait, wait);
893*4882a593Smuzhiyun 
894*4882a593Smuzhiyun 	spin_lock(&proc->asts_spin);
895*4882a593Smuzhiyun 	if (!list_empty(&proc->asts)) {
896*4882a593Smuzhiyun 		spin_unlock(&proc->asts_spin);
897*4882a593Smuzhiyun 		return EPOLLIN | EPOLLRDNORM;
898*4882a593Smuzhiyun 	}
899*4882a593Smuzhiyun 	spin_unlock(&proc->asts_spin);
900*4882a593Smuzhiyun 	return 0;
901*4882a593Smuzhiyun }
902*4882a593Smuzhiyun 
dlm_user_daemon_available(void)903*4882a593Smuzhiyun int dlm_user_daemon_available(void)
904*4882a593Smuzhiyun {
905*4882a593Smuzhiyun 	/* dlm_controld hasn't started (or, has started, but not
906*4882a593Smuzhiyun 	   properly populated configfs) */
907*4882a593Smuzhiyun 
908*4882a593Smuzhiyun 	if (!dlm_our_nodeid())
909*4882a593Smuzhiyun 		return 0;
910*4882a593Smuzhiyun 
911*4882a593Smuzhiyun 	/* This is to deal with versions of dlm_controld that don't
912*4882a593Smuzhiyun 	   know about the monitor device.  We assume that if the
913*4882a593Smuzhiyun 	   dlm_controld was started (above), but the monitor device
914*4882a593Smuzhiyun 	   was never opened, that it's an old version.  dlm_controld
915*4882a593Smuzhiyun 	   should open the monitor device before populating configfs. */
916*4882a593Smuzhiyun 
917*4882a593Smuzhiyun 	if (dlm_monitor_unused)
918*4882a593Smuzhiyun 		return 1;
919*4882a593Smuzhiyun 
920*4882a593Smuzhiyun 	return atomic_read(&dlm_monitor_opened) ? 1 : 0;
921*4882a593Smuzhiyun }
922*4882a593Smuzhiyun 
ctl_device_open(struct inode * inode,struct file * file)923*4882a593Smuzhiyun static int ctl_device_open(struct inode *inode, struct file *file)
924*4882a593Smuzhiyun {
925*4882a593Smuzhiyun 	file->private_data = NULL;
926*4882a593Smuzhiyun 	return 0;
927*4882a593Smuzhiyun }
928*4882a593Smuzhiyun 
ctl_device_close(struct inode * inode,struct file * file)929*4882a593Smuzhiyun static int ctl_device_close(struct inode *inode, struct file *file)
930*4882a593Smuzhiyun {
931*4882a593Smuzhiyun 	return 0;
932*4882a593Smuzhiyun }
933*4882a593Smuzhiyun 
monitor_device_open(struct inode * inode,struct file * file)934*4882a593Smuzhiyun static int monitor_device_open(struct inode *inode, struct file *file)
935*4882a593Smuzhiyun {
936*4882a593Smuzhiyun 	atomic_inc(&dlm_monitor_opened);
937*4882a593Smuzhiyun 	dlm_monitor_unused = 0;
938*4882a593Smuzhiyun 	return 0;
939*4882a593Smuzhiyun }
940*4882a593Smuzhiyun 
monitor_device_close(struct inode * inode,struct file * file)941*4882a593Smuzhiyun static int monitor_device_close(struct inode *inode, struct file *file)
942*4882a593Smuzhiyun {
943*4882a593Smuzhiyun 	if (atomic_dec_and_test(&dlm_monitor_opened))
944*4882a593Smuzhiyun 		dlm_stop_lockspaces();
945*4882a593Smuzhiyun 	return 0;
946*4882a593Smuzhiyun }
947*4882a593Smuzhiyun 
948*4882a593Smuzhiyun static const struct file_operations device_fops = {
949*4882a593Smuzhiyun 	.open    = device_open,
950*4882a593Smuzhiyun 	.release = device_close,
951*4882a593Smuzhiyun 	.read    = device_read,
952*4882a593Smuzhiyun 	.write   = device_write,
953*4882a593Smuzhiyun 	.poll    = device_poll,
954*4882a593Smuzhiyun 	.owner   = THIS_MODULE,
955*4882a593Smuzhiyun 	.llseek  = noop_llseek,
956*4882a593Smuzhiyun };
957*4882a593Smuzhiyun 
958*4882a593Smuzhiyun static const struct file_operations ctl_device_fops = {
959*4882a593Smuzhiyun 	.open    = ctl_device_open,
960*4882a593Smuzhiyun 	.release = ctl_device_close,
961*4882a593Smuzhiyun 	.read    = device_read,
962*4882a593Smuzhiyun 	.write   = device_write,
963*4882a593Smuzhiyun 	.owner   = THIS_MODULE,
964*4882a593Smuzhiyun 	.llseek  = noop_llseek,
965*4882a593Smuzhiyun };
966*4882a593Smuzhiyun 
967*4882a593Smuzhiyun static struct miscdevice ctl_device = {
968*4882a593Smuzhiyun 	.name  = "dlm-control",
969*4882a593Smuzhiyun 	.fops  = &ctl_device_fops,
970*4882a593Smuzhiyun 	.minor = MISC_DYNAMIC_MINOR,
971*4882a593Smuzhiyun };
972*4882a593Smuzhiyun 
973*4882a593Smuzhiyun static const struct file_operations monitor_device_fops = {
974*4882a593Smuzhiyun 	.open    = monitor_device_open,
975*4882a593Smuzhiyun 	.release = monitor_device_close,
976*4882a593Smuzhiyun 	.owner   = THIS_MODULE,
977*4882a593Smuzhiyun 	.llseek  = noop_llseek,
978*4882a593Smuzhiyun };
979*4882a593Smuzhiyun 
980*4882a593Smuzhiyun static struct miscdevice monitor_device = {
981*4882a593Smuzhiyun 	.name  = "dlm-monitor",
982*4882a593Smuzhiyun 	.fops  = &monitor_device_fops,
983*4882a593Smuzhiyun 	.minor = MISC_DYNAMIC_MINOR,
984*4882a593Smuzhiyun };
985*4882a593Smuzhiyun 
dlm_user_init(void)986*4882a593Smuzhiyun int __init dlm_user_init(void)
987*4882a593Smuzhiyun {
988*4882a593Smuzhiyun 	int error;
989*4882a593Smuzhiyun 
990*4882a593Smuzhiyun 	atomic_set(&dlm_monitor_opened, 0);
991*4882a593Smuzhiyun 
992*4882a593Smuzhiyun 	error = misc_register(&ctl_device);
993*4882a593Smuzhiyun 	if (error) {
994*4882a593Smuzhiyun 		log_print("misc_register failed for control device");
995*4882a593Smuzhiyun 		goto out;
996*4882a593Smuzhiyun 	}
997*4882a593Smuzhiyun 
998*4882a593Smuzhiyun 	error = misc_register(&monitor_device);
999*4882a593Smuzhiyun 	if (error) {
1000*4882a593Smuzhiyun 		log_print("misc_register failed for monitor device");
1001*4882a593Smuzhiyun 		misc_deregister(&ctl_device);
1002*4882a593Smuzhiyun 	}
1003*4882a593Smuzhiyun  out:
1004*4882a593Smuzhiyun 	return error;
1005*4882a593Smuzhiyun }
1006*4882a593Smuzhiyun 
dlm_user_exit(void)1007*4882a593Smuzhiyun void dlm_user_exit(void)
1008*4882a593Smuzhiyun {
1009*4882a593Smuzhiyun 	misc_deregister(&ctl_device);
1010*4882a593Smuzhiyun 	misc_deregister(&monitor_device);
1011*4882a593Smuzhiyun }
1012*4882a593Smuzhiyun 
1013