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>
15 #include "dlm_internal.h"
16 #include "lockspace.h"
18 static spinlock_t ops_lock
;
19 static struct list_head send_list
;
20 static struct list_head recv_list
;
21 static wait_queue_head_t send_wq
;
22 static wait_queue_head_t recv_wq
;
25 struct list_head list
;
27 struct dlm_plock_info info
;
39 static inline void set_version(struct dlm_plock_info
*info
)
41 info
->version
[0] = DLM_PLOCK_VERSION_MAJOR
;
42 info
->version
[1] = DLM_PLOCK_VERSION_MINOR
;
43 info
->version
[2] = DLM_PLOCK_VERSION_PATCH
;
46 static int check_version(struct dlm_plock_info
*info
)
48 if ((DLM_PLOCK_VERSION_MAJOR
!= info
->version
[0]) ||
49 (DLM_PLOCK_VERSION_MINOR
< info
->version
[1])) {
50 log_print("plock device version mismatch: "
51 "kernel (%u.%u.%u), user (%u.%u.%u)",
52 DLM_PLOCK_VERSION_MAJOR
,
53 DLM_PLOCK_VERSION_MINOR
,
54 DLM_PLOCK_VERSION_PATCH
,
63 static void send_op(struct plock_op
*op
)
65 set_version(&op
->info
);
66 INIT_LIST_HEAD(&op
->list
);
68 list_add_tail(&op
->list
, &send_list
);
69 spin_unlock(&ops_lock
);
73 int dlm_posix_lock(dlm_lockspace_t
*lockspace
, u64 number
, struct file
*file
,
74 int cmd
, struct file_lock
*fl
)
78 struct plock_xop
*xop
;
81 ls
= dlm_find_lockspace_local(lockspace
);
85 xop
= kzalloc(sizeof(*xop
), GFP_KERNEL
);
92 op
->info
.optype
= DLM_PLOCK_OP_LOCK
;
93 op
->info
.pid
= fl
->fl_pid
;
94 op
->info
.ex
= (fl
->fl_type
== F_WRLCK
);
95 op
->info
.wait
= IS_SETLKW(cmd
);
96 op
->info
.fsid
= ls
->ls_global_id
;
97 op
->info
.number
= number
;
98 op
->info
.start
= fl
->fl_start
;
99 op
->info
.end
= fl
->fl_end
;
100 if (fl
->fl_lmops
&& fl
->fl_lmops
->fl_grant
) {
101 /* fl_owner is lockd which doesn't distinguish
102 processes on the nfs client */
103 op
->info
.owner
= (__u64
) fl
->fl_pid
;
104 xop
->callback
= fl
->fl_lmops
->fl_grant
;
105 locks_init_lock(&xop
->flc
);
106 locks_copy_lock(&xop
->flc
, fl
);
110 op
->info
.owner
= (__u64
)(long) fl
->fl_owner
;
111 xop
->callback
= NULL
;
116 if (xop
->callback
== NULL
)
117 wait_event(recv_wq
, (op
->done
!= 0));
119 rv
= FILE_LOCK_DEFERRED
;
123 spin_lock(&ops_lock
);
124 if (!list_empty(&op
->list
)) {
125 log_error(ls
, "dlm_posix_lock: op on list %llx",
126 (unsigned long long)number
);
129 spin_unlock(&ops_lock
);
134 if (posix_lock_file_wait(file
, fl
) < 0)
135 log_error(ls
, "dlm_posix_lock: vfs lock error %llx",
136 (unsigned long long)number
);
141 dlm_put_lockspace(ls
);
144 EXPORT_SYMBOL_GPL(dlm_posix_lock
);
146 /* Returns failure iff a succesful lock operation should be canceled */
147 static int dlm_plock_callback(struct plock_op
*op
)
150 struct file_lock
*fl
;
151 struct file_lock
*flc
;
152 int (*notify
)(void *, void *, int) = NULL
;
153 struct plock_xop
*xop
= (struct plock_xop
*)op
;
156 spin_lock(&ops_lock
);
157 if (!list_empty(&op
->list
)) {
158 log_print("dlm_plock_callback: op on list %llx",
159 (unsigned long long)op
->info
.number
);
162 spin_unlock(&ops_lock
);
164 /* check if the following 2 are still valid or make a copy */
168 notify
= xop
->callback
;
171 notify(flc
, NULL
, op
->info
.rv
);
175 /* got fs lock; bookkeep locally as well: */
176 flc
->fl_flags
&= ~FL_SLEEP
;
177 if (posix_lock_file(file
, flc
, NULL
)) {
179 * This can only happen in the case of kmalloc() failure.
180 * The filesystem's own lock is the authoritative lock,
181 * so a failure to get the lock locally is not a disaster.
182 * As long as the fs cannot reliably cancel locks (especially
183 * in a low-memory situation), we're better off ignoring
184 * this failure than trying to recover.
186 log_print("dlm_plock_callback: vfs lock error %llx file %p fl %p",
187 (unsigned long long)op
->info
.number
, file
, fl
);
190 rv
= notify(flc
, NULL
, 0);
192 /* XXX: We need to cancel the fs lock here: */
193 log_print("dlm_plock_callback: lock granted after lock request "
194 "failed; dangling lock!\n");
203 int dlm_posix_unlock(dlm_lockspace_t
*lockspace
, u64 number
, struct file
*file
,
204 struct file_lock
*fl
)
210 ls
= dlm_find_lockspace_local(lockspace
);
214 op
= kzalloc(sizeof(*op
), GFP_KERNEL
);
220 if (posix_lock_file_wait(file
, fl
) < 0)
221 log_error(ls
, "dlm_posix_unlock: vfs unlock error %llx",
222 (unsigned long long)number
);
224 op
->info
.optype
= DLM_PLOCK_OP_UNLOCK
;
225 op
->info
.pid
= fl
->fl_pid
;
226 op
->info
.fsid
= ls
->ls_global_id
;
227 op
->info
.number
= number
;
228 op
->info
.start
= fl
->fl_start
;
229 op
->info
.end
= fl
->fl_end
;
230 if (fl
->fl_lmops
&& fl
->fl_lmops
->fl_grant
)
231 op
->info
.owner
= (__u64
) fl
->fl_pid
;
233 op
->info
.owner
= (__u64
)(long) fl
->fl_owner
;
236 wait_event(recv_wq
, (op
->done
!= 0));
238 spin_lock(&ops_lock
);
239 if (!list_empty(&op
->list
)) {
240 log_error(ls
, "dlm_posix_unlock: op on list %llx",
241 (unsigned long long)number
);
244 spin_unlock(&ops_lock
);
253 dlm_put_lockspace(ls
);
256 EXPORT_SYMBOL_GPL(dlm_posix_unlock
);
258 int dlm_posix_get(dlm_lockspace_t
*lockspace
, u64 number
, struct file
*file
,
259 struct file_lock
*fl
)
265 ls
= dlm_find_lockspace_local(lockspace
);
269 op
= kzalloc(sizeof(*op
), GFP_KERNEL
);
275 op
->info
.optype
= DLM_PLOCK_OP_GET
;
276 op
->info
.pid
= fl
->fl_pid
;
277 op
->info
.ex
= (fl
->fl_type
== F_WRLCK
);
278 op
->info
.fsid
= ls
->ls_global_id
;
279 op
->info
.number
= number
;
280 op
->info
.start
= fl
->fl_start
;
281 op
->info
.end
= fl
->fl_end
;
282 if (fl
->fl_lmops
&& fl
->fl_lmops
->fl_grant
)
283 op
->info
.owner
= (__u64
) fl
->fl_pid
;
285 op
->info
.owner
= (__u64
)(long) fl
->fl_owner
;
288 wait_event(recv_wq
, (op
->done
!= 0));
290 spin_lock(&ops_lock
);
291 if (!list_empty(&op
->list
)) {
292 log_error(ls
, "dlm_posix_get: op on list %llx",
293 (unsigned long long)number
);
296 spin_unlock(&ops_lock
);
298 /* info.rv from userspace is 1 for conflict, 0 for no-conflict,
299 -ENOENT if there are no locks on the file */
303 fl
->fl_type
= F_UNLCK
;
307 fl
->fl_type
= (op
->info
.ex
) ? F_WRLCK
: F_RDLCK
;
308 fl
->fl_pid
= op
->info
.pid
;
309 fl
->fl_start
= op
->info
.start
;
310 fl
->fl_end
= op
->info
.end
;
316 dlm_put_lockspace(ls
);
319 EXPORT_SYMBOL_GPL(dlm_posix_get
);
321 /* a read copies out one plock request from the send list */
322 static ssize_t
dev_read(struct file
*file
, char __user
*u
, size_t count
,
325 struct dlm_plock_info info
;
326 struct plock_op
*op
= NULL
;
328 if (count
< sizeof(info
))
331 spin_lock(&ops_lock
);
332 if (!list_empty(&send_list
)) {
333 op
= list_entry(send_list
.next
, struct plock_op
, list
);
334 list_move(&op
->list
, &recv_list
);
335 memcpy(&info
, &op
->info
, sizeof(info
));
337 spin_unlock(&ops_lock
);
342 if (copy_to_user(u
, &info
, sizeof(info
)))
347 /* a write copies in one plock result that should match a plock_op
349 static ssize_t
dev_write(struct file
*file
, const char __user
*u
, size_t count
,
352 struct dlm_plock_info info
;
356 if (count
!= sizeof(info
))
359 if (copy_from_user(&info
, u
, sizeof(info
)))
362 if (check_version(&info
))
365 spin_lock(&ops_lock
);
366 list_for_each_entry(op
, &recv_list
, list
) {
367 if (op
->info
.fsid
== info
.fsid
&& op
->info
.number
== info
.number
&&
368 op
->info
.owner
== info
.owner
) {
369 list_del_init(&op
->list
);
372 memcpy(&op
->info
, &info
, sizeof(info
));
376 spin_unlock(&ops_lock
);
379 struct plock_xop
*xop
;
380 xop
= (struct plock_xop
*)op
;
382 dlm_plock_callback(op
);
386 log_print("dev_write no op %x %llx", info
.fsid
,
387 (unsigned long long)info
.number
);
391 static unsigned int dev_poll(struct file
*file
, poll_table
*wait
)
393 unsigned int mask
= 0;
395 poll_wait(file
, &send_wq
, wait
);
397 spin_lock(&ops_lock
);
398 if (!list_empty(&send_list
))
399 mask
= POLLIN
| POLLRDNORM
;
400 spin_unlock(&ops_lock
);
405 static const struct file_operations dev_fops
= {
412 static struct miscdevice plock_dev_misc
= {
413 .minor
= MISC_DYNAMIC_MINOR
,
414 .name
= DLM_PLOCK_MISC_NAME
,
418 int dlm_plock_init(void)
422 spin_lock_init(&ops_lock
);
423 INIT_LIST_HEAD(&send_list
);
424 INIT_LIST_HEAD(&recv_list
);
425 init_waitqueue_head(&send_wq
);
426 init_waitqueue_head(&recv_wq
);
428 rv
= misc_register(&plock_dev_misc
);
430 log_print("dlm_plock_init: misc_register failed %d", rv
);
434 void dlm_plock_exit(void)
436 if (misc_deregister(&plock_dev_misc
) < 0)
437 log_print("dlm_plock_exit: misc_deregister failed");