2 * Copyright (C) 2005-2008 Red Hat, Inc. All rights reserved.
4 * This copyrighted material is made available to anyone wishing to use,
5 * modify, copy, or redistribute it subject to the terms and conditions
6 * of the GNU General Public License version 2.
10 #include <linux/miscdevice.h>
11 #include <linux/poll.h>
12 #include <linux/dlm.h>
13 #include <linux/dlm_plock.h>
14 #include <linux/slab.h>
16 #include "dlm_internal.h"
17 #include "lockspace.h"
19 static spinlock_t ops_lock
;
20 static struct list_head send_list
;
21 static struct list_head recv_list
;
22 static wait_queue_head_t send_wq
;
23 static wait_queue_head_t recv_wq
;
26 struct list_head list
;
28 struct dlm_plock_info info
;
40 static inline void set_version(struct dlm_plock_info
*info
)
42 info
->version
[0] = DLM_PLOCK_VERSION_MAJOR
;
43 info
->version
[1] = DLM_PLOCK_VERSION_MINOR
;
44 info
->version
[2] = DLM_PLOCK_VERSION_PATCH
;
47 static int check_version(struct dlm_plock_info
*info
)
49 if ((DLM_PLOCK_VERSION_MAJOR
!= info
->version
[0]) ||
50 (DLM_PLOCK_VERSION_MINOR
< info
->version
[1])) {
51 log_print("plock device version mismatch: "
52 "kernel (%u.%u.%u), user (%u.%u.%u)",
53 DLM_PLOCK_VERSION_MAJOR
,
54 DLM_PLOCK_VERSION_MINOR
,
55 DLM_PLOCK_VERSION_PATCH
,
64 static void send_op(struct plock_op
*op
)
66 set_version(&op
->info
);
67 INIT_LIST_HEAD(&op
->list
);
69 list_add_tail(&op
->list
, &send_list
);
70 spin_unlock(&ops_lock
);
74 int dlm_posix_lock(dlm_lockspace_t
*lockspace
, u64 number
, struct file
*file
,
75 int cmd
, struct file_lock
*fl
)
79 struct plock_xop
*xop
;
82 ls
= dlm_find_lockspace_local(lockspace
);
86 xop
= kzalloc(sizeof(*xop
), GFP_NOFS
);
93 op
->info
.optype
= DLM_PLOCK_OP_LOCK
;
94 op
->info
.pid
= fl
->fl_pid
;
95 op
->info
.ex
= (fl
->fl_type
== F_WRLCK
);
96 op
->info
.wait
= IS_SETLKW(cmd
);
97 op
->info
.fsid
= ls
->ls_global_id
;
98 op
->info
.number
= number
;
99 op
->info
.start
= fl
->fl_start
;
100 op
->info
.end
= fl
->fl_end
;
101 if (fl
->fl_lmops
&& fl
->fl_lmops
->fl_grant
) {
102 /* fl_owner is lockd which doesn't distinguish
103 processes on the nfs client */
104 op
->info
.owner
= (__u64
) fl
->fl_pid
;
105 xop
->callback
= fl
->fl_lmops
->fl_grant
;
106 locks_init_lock(&xop
->flc
);
107 locks_copy_lock(&xop
->flc
, fl
);
111 op
->info
.owner
= (__u64
)(long) fl
->fl_owner
;
112 xop
->callback
= NULL
;
117 if (xop
->callback
== NULL
)
118 wait_event(recv_wq
, (op
->done
!= 0));
120 rv
= FILE_LOCK_DEFERRED
;
124 spin_lock(&ops_lock
);
125 if (!list_empty(&op
->list
)) {
126 log_error(ls
, "dlm_posix_lock: op on list %llx",
127 (unsigned long long)number
);
130 spin_unlock(&ops_lock
);
135 if (posix_lock_file_wait(file
, fl
) < 0)
136 log_error(ls
, "dlm_posix_lock: vfs lock error %llx",
137 (unsigned long long)number
);
142 dlm_put_lockspace(ls
);
145 EXPORT_SYMBOL_GPL(dlm_posix_lock
);
147 /* Returns failure iff a successful lock operation should be canceled */
148 static int dlm_plock_callback(struct plock_op
*op
)
151 struct file_lock
*fl
;
152 struct file_lock
*flc
;
153 int (*notify
)(void *, void *, int) = NULL
;
154 struct plock_xop
*xop
= (struct plock_xop
*)op
;
157 spin_lock(&ops_lock
);
158 if (!list_empty(&op
->list
)) {
159 log_print("dlm_plock_callback: op on list %llx",
160 (unsigned long long)op
->info
.number
);
163 spin_unlock(&ops_lock
);
165 /* check if the following 2 are still valid or make a copy */
169 notify
= xop
->callback
;
172 notify(fl
, NULL
, op
->info
.rv
);
176 /* got fs lock; bookkeep locally as well: */
177 flc
->fl_flags
&= ~FL_SLEEP
;
178 if (posix_lock_file(file
, flc
, NULL
)) {
180 * This can only happen in the case of kmalloc() failure.
181 * The filesystem's own lock is the authoritative lock,
182 * so a failure to get the lock locally is not a disaster.
183 * As long as the fs cannot reliably cancel locks (especially
184 * in a low-memory situation), we're better off ignoring
185 * this failure than trying to recover.
187 log_print("dlm_plock_callback: vfs lock error %llx file %p fl %p",
188 (unsigned long long)op
->info
.number
, file
, fl
);
191 rv
= notify(fl
, NULL
, 0);
193 /* XXX: We need to cancel the fs lock here: */
194 log_print("dlm_plock_callback: lock granted after lock request "
195 "failed; dangling lock!\n");
204 int dlm_posix_unlock(dlm_lockspace_t
*lockspace
, u64 number
, struct file
*file
,
205 struct file_lock
*fl
)
211 ls
= dlm_find_lockspace_local(lockspace
);
215 op
= kzalloc(sizeof(*op
), GFP_NOFS
);
221 if (posix_lock_file_wait(file
, fl
) < 0)
222 log_error(ls
, "dlm_posix_unlock: vfs unlock error %llx",
223 (unsigned long long)number
);
225 op
->info
.optype
= DLM_PLOCK_OP_UNLOCK
;
226 op
->info
.pid
= fl
->fl_pid
;
227 op
->info
.fsid
= ls
->ls_global_id
;
228 op
->info
.number
= number
;
229 op
->info
.start
= fl
->fl_start
;
230 op
->info
.end
= fl
->fl_end
;
231 if (fl
->fl_lmops
&& fl
->fl_lmops
->fl_grant
)
232 op
->info
.owner
= (__u64
) fl
->fl_pid
;
234 op
->info
.owner
= (__u64
)(long) fl
->fl_owner
;
237 wait_event(recv_wq
, (op
->done
!= 0));
239 spin_lock(&ops_lock
);
240 if (!list_empty(&op
->list
)) {
241 log_error(ls
, "dlm_posix_unlock: op on list %llx",
242 (unsigned long long)number
);
245 spin_unlock(&ops_lock
);
254 dlm_put_lockspace(ls
);
257 EXPORT_SYMBOL_GPL(dlm_posix_unlock
);
259 int dlm_posix_get(dlm_lockspace_t
*lockspace
, u64 number
, struct file
*file
,
260 struct file_lock
*fl
)
266 ls
= dlm_find_lockspace_local(lockspace
);
270 op
= kzalloc(sizeof(*op
), GFP_NOFS
);
276 op
->info
.optype
= DLM_PLOCK_OP_GET
;
277 op
->info
.pid
= fl
->fl_pid
;
278 op
->info
.ex
= (fl
->fl_type
== F_WRLCK
);
279 op
->info
.fsid
= ls
->ls_global_id
;
280 op
->info
.number
= number
;
281 op
->info
.start
= fl
->fl_start
;
282 op
->info
.end
= fl
->fl_end
;
283 if (fl
->fl_lmops
&& fl
->fl_lmops
->fl_grant
)
284 op
->info
.owner
= (__u64
) fl
->fl_pid
;
286 op
->info
.owner
= (__u64
)(long) fl
->fl_owner
;
289 wait_event(recv_wq
, (op
->done
!= 0));
291 spin_lock(&ops_lock
);
292 if (!list_empty(&op
->list
)) {
293 log_error(ls
, "dlm_posix_get: op on list %llx",
294 (unsigned long long)number
);
297 spin_unlock(&ops_lock
);
299 /* info.rv from userspace is 1 for conflict, 0 for no-conflict,
300 -ENOENT if there are no locks on the file */
304 fl
->fl_type
= F_UNLCK
;
309 fl
->fl_type
= (op
->info
.ex
) ? F_WRLCK
: F_RDLCK
;
310 fl
->fl_flags
= FL_POSIX
;
311 fl
->fl_pid
= op
->info
.pid
;
312 fl
->fl_start
= op
->info
.start
;
313 fl
->fl_end
= op
->info
.end
;
319 dlm_put_lockspace(ls
);
322 EXPORT_SYMBOL_GPL(dlm_posix_get
);
324 /* a read copies out one plock request from the send list */
325 static ssize_t
dev_read(struct file
*file
, char __user
*u
, size_t count
,
328 struct dlm_plock_info info
;
329 struct plock_op
*op
= NULL
;
331 if (count
< sizeof(info
))
334 spin_lock(&ops_lock
);
335 if (!list_empty(&send_list
)) {
336 op
= list_entry(send_list
.next
, struct plock_op
, list
);
337 list_move(&op
->list
, &recv_list
);
338 memcpy(&info
, &op
->info
, sizeof(info
));
340 spin_unlock(&ops_lock
);
345 if (copy_to_user(u
, &info
, sizeof(info
)))
350 /* a write copies in one plock result that should match a plock_op
352 static ssize_t
dev_write(struct file
*file
, const char __user
*u
, size_t count
,
355 struct dlm_plock_info info
;
357 int found
= 0, do_callback
= 0;
359 if (count
!= sizeof(info
))
362 if (copy_from_user(&info
, u
, sizeof(info
)))
365 if (check_version(&info
))
368 spin_lock(&ops_lock
);
369 list_for_each_entry(op
, &recv_list
, list
) {
370 if (op
->info
.fsid
== info
.fsid
&&
371 op
->info
.number
== info
.number
&&
372 op
->info
.owner
== info
.owner
) {
373 struct plock_xop
*xop
= (struct plock_xop
*)op
;
374 list_del_init(&op
->list
);
375 memcpy(&op
->info
, &info
, sizeof(info
));
384 spin_unlock(&ops_lock
);
388 dlm_plock_callback(op
);
392 log_print("dev_write no op %x %llx", info
.fsid
,
393 (unsigned long long)info
.number
);
397 static unsigned int dev_poll(struct file
*file
, poll_table
*wait
)
399 unsigned int mask
= 0;
401 poll_wait(file
, &send_wq
, wait
);
403 spin_lock(&ops_lock
);
404 if (!list_empty(&send_list
))
405 mask
= POLLIN
| POLLRDNORM
;
406 spin_unlock(&ops_lock
);
411 static const struct file_operations dev_fops
= {
415 .owner
= THIS_MODULE
,
416 .llseek
= noop_llseek
,
419 static struct miscdevice plock_dev_misc
= {
420 .minor
= MISC_DYNAMIC_MINOR
,
421 .name
= DLM_PLOCK_MISC_NAME
,
425 int dlm_plock_init(void)
429 spin_lock_init(&ops_lock
);
430 INIT_LIST_HEAD(&send_list
);
431 INIT_LIST_HEAD(&recv_list
);
432 init_waitqueue_head(&send_wq
);
433 init_waitqueue_head(&recv_wq
);
435 rv
= misc_register(&plock_dev_misc
);
437 log_print("dlm_plock_init: misc_register failed %d", rv
);
441 void dlm_plock_exit(void)
443 if (misc_deregister(&plock_dev_misc
) < 0)
444 log_print("dlm_plock_exit: misc_deregister failed");