2 * Copyright (C) 2005 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.
9 #include <linux/miscdevice.h>
10 #include <linux/lock_dlm_plock.h>
11 #include <linux/poll.h>
16 static spinlock_t ops_lock
;
17 static struct list_head send_list
;
18 static struct list_head recv_list
;
19 static wait_queue_head_t send_wq
;
20 static wait_queue_head_t recv_wq
;
23 struct list_head list
;
25 struct gdlm_plock_info info
;
28 static inline void set_version(struct gdlm_plock_info
*info
)
30 info
->version
[0] = GDLM_PLOCK_VERSION_MAJOR
;
31 info
->version
[1] = GDLM_PLOCK_VERSION_MINOR
;
32 info
->version
[2] = GDLM_PLOCK_VERSION_PATCH
;
35 static int check_version(struct gdlm_plock_info
*info
)
37 if ((GDLM_PLOCK_VERSION_MAJOR
!= info
->version
[0]) ||
38 (GDLM_PLOCK_VERSION_MINOR
< info
->version
[1])) {
39 log_error("plock device version mismatch: "
40 "kernel (%u.%u.%u), user (%u.%u.%u)",
41 GDLM_PLOCK_VERSION_MAJOR
,
42 GDLM_PLOCK_VERSION_MINOR
,
43 GDLM_PLOCK_VERSION_PATCH
,
52 static void send_op(struct plock_op
*op
)
54 set_version(&op
->info
);
55 INIT_LIST_HEAD(&op
->list
);
57 list_add_tail(&op
->list
, &send_list
);
58 spin_unlock(&ops_lock
);
62 int gdlm_plock(void *lockspace
, struct lm_lockname
*name
,
63 struct file
*file
, int cmd
, struct file_lock
*fl
)
65 struct gdlm_ls
*ls
= lockspace
;
69 op
= kzalloc(sizeof(*op
), GFP_KERNEL
);
73 op
->info
.optype
= GDLM_PLOCK_OP_LOCK
;
74 op
->info
.pid
= fl
->fl_pid
;
75 op
->info
.ex
= (fl
->fl_type
== F_WRLCK
);
76 op
->info
.wait
= IS_SETLKW(cmd
);
77 op
->info
.fsid
= ls
->id
;
78 op
->info
.number
= name
->ln_number
;
79 op
->info
.start
= fl
->fl_start
;
80 op
->info
.end
= fl
->fl_end
;
81 op
->info
.owner
= (__u64
)(long) fl
->fl_owner
;
84 wait_event(recv_wq
, (op
->done
!= 0));
87 if (!list_empty(&op
->list
)) {
88 printk(KERN_INFO
"plock op on list\n");
91 spin_unlock(&ops_lock
);
96 if (posix_lock_file_wait(file
, fl
) < 0)
97 log_error("gdlm_plock: vfs lock error %x,%llx",
99 (unsigned long long)name
->ln_number
);
106 int gdlm_punlock(void *lockspace
, struct lm_lockname
*name
,
107 struct file
*file
, struct file_lock
*fl
)
109 struct gdlm_ls
*ls
= lockspace
;
113 op
= kzalloc(sizeof(*op
), GFP_KERNEL
);
117 if (posix_lock_file_wait(file
, fl
) < 0)
118 log_error("gdlm_punlock: vfs unlock error %x,%llx",
119 name
->ln_type
, (unsigned long long)name
->ln_number
);
121 op
->info
.optype
= GDLM_PLOCK_OP_UNLOCK
;
122 op
->info
.pid
= fl
->fl_pid
;
123 op
->info
.fsid
= ls
->id
;
124 op
->info
.number
= name
->ln_number
;
125 op
->info
.start
= fl
->fl_start
;
126 op
->info
.end
= fl
->fl_end
;
127 op
->info
.owner
= (__u64
)(long) fl
->fl_owner
;
130 wait_event(recv_wq
, (op
->done
!= 0));
132 spin_lock(&ops_lock
);
133 if (!list_empty(&op
->list
)) {
134 printk(KERN_INFO
"punlock op on list\n");
137 spin_unlock(&ops_lock
);
145 int gdlm_plock_get(void *lockspace
, struct lm_lockname
*name
,
146 struct file
*file
, struct file_lock
*fl
)
148 struct gdlm_ls
*ls
= lockspace
;
152 op
= kzalloc(sizeof(*op
), GFP_KERNEL
);
156 op
->info
.optype
= GDLM_PLOCK_OP_GET
;
157 op
->info
.pid
= fl
->fl_pid
;
158 op
->info
.ex
= (fl
->fl_type
== F_WRLCK
);
159 op
->info
.fsid
= ls
->id
;
160 op
->info
.number
= name
->ln_number
;
161 op
->info
.start
= fl
->fl_start
;
162 op
->info
.end
= fl
->fl_end
;
165 wait_event(recv_wq
, (op
->done
!= 0));
167 spin_lock(&ops_lock
);
168 if (!list_empty(&op
->list
)) {
169 printk(KERN_INFO
"plock_get op on list\n");
172 spin_unlock(&ops_lock
);
177 fl
->fl_type
= F_UNLCK
;
179 fl
->fl_type
= (op
->info
.ex
) ? F_WRLCK
: F_RDLCK
;
180 fl
->fl_pid
= op
->info
.pid
;
181 fl
->fl_start
= op
->info
.start
;
182 fl
->fl_end
= op
->info
.end
;
189 /* a read copies out one plock request from the send list */
190 static ssize_t
dev_read(struct file
*file
, char __user
*u
, size_t count
,
193 struct gdlm_plock_info info
;
194 struct plock_op
*op
= NULL
;
196 if (count
< sizeof(info
))
199 spin_lock(&ops_lock
);
200 if (!list_empty(&send_list
)) {
201 op
= list_entry(send_list
.next
, struct plock_op
, list
);
202 list_move(&op
->list
, &recv_list
);
203 memcpy(&info
, &op
->info
, sizeof(info
));
205 spin_unlock(&ops_lock
);
210 if (copy_to_user(u
, &info
, sizeof(info
)))
215 /* a write copies in one plock result that should match a plock_op
217 static ssize_t
dev_write(struct file
*file
, const char __user
*u
, size_t count
,
220 struct gdlm_plock_info info
;
224 if (count
!= sizeof(info
))
227 if (copy_from_user(&info
, u
, sizeof(info
)))
230 if (check_version(&info
))
233 spin_lock(&ops_lock
);
234 list_for_each_entry(op
, &recv_list
, list
) {
235 if (op
->info
.fsid
== info
.fsid
&& op
->info
.number
== info
.number
&&
236 op
->info
.owner
== info
.owner
) {
237 list_del_init(&op
->list
);
240 memcpy(&op
->info
, &info
, sizeof(info
));
244 spin_unlock(&ops_lock
);
249 printk(KERN_INFO
"gdlm dev_write no op %x %llx\n", info
.fsid
,
250 (unsigned long long)info
.number
);
254 static unsigned int dev_poll(struct file
*file
, poll_table
*wait
)
256 poll_wait(file
, &send_wq
, wait
);
258 spin_lock(&ops_lock
);
259 if (!list_empty(&send_list
)) {
260 spin_unlock(&ops_lock
);
261 return POLLIN
| POLLRDNORM
;
263 spin_unlock(&ops_lock
);
267 static const struct file_operations dev_fops
= {
274 static struct miscdevice plock_dev_misc
= {
275 .minor
= MISC_DYNAMIC_MINOR
,
276 .name
= GDLM_PLOCK_MISC_NAME
,
280 int gdlm_plock_init(void)
284 spin_lock_init(&ops_lock
);
285 INIT_LIST_HEAD(&send_list
);
286 INIT_LIST_HEAD(&recv_list
);
287 init_waitqueue_head(&send_wq
);
288 init_waitqueue_head(&recv_wq
);
290 rv
= misc_register(&plock_dev_misc
);
292 printk(KERN_INFO
"gdlm_plock_init: misc_register failed %d",
297 void gdlm_plock_exit(void)
299 if (misc_deregister(&plock_dev_misc
) < 0)
300 printk(KERN_INFO
"gdlm_plock_exit: misc_deregister failed");