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 v.2.
9 #include <linux/miscdevice.h>
10 #include <linux/lock_dlm_plock.h>
15 static spinlock_t ops_lock
;
16 static struct list_head send_list
;
17 static struct list_head recv_list
;
18 static wait_queue_head_t send_wq
;
19 static wait_queue_head_t recv_wq
;
22 struct list_head list
;
24 struct gdlm_plock_info info
;
27 static inline void set_version(struct gdlm_plock_info
*info
)
29 info
->version
[0] = GDLM_PLOCK_VERSION_MAJOR
;
30 info
->version
[1] = GDLM_PLOCK_VERSION_MINOR
;
31 info
->version
[2] = GDLM_PLOCK_VERSION_PATCH
;
34 static int check_version(struct gdlm_plock_info
*info
)
36 if ((GDLM_PLOCK_VERSION_MAJOR
!= info
->version
[0]) ||
37 (GDLM_PLOCK_VERSION_MINOR
< info
->version
[1])) {
38 log_error("plock device version mismatch: "
39 "kernel (%u.%u.%u), user (%u.%u.%u)",
40 GDLM_PLOCK_VERSION_MAJOR
,
41 GDLM_PLOCK_VERSION_MINOR
,
42 GDLM_PLOCK_VERSION_PATCH
,
51 static void send_op(struct plock_op
*op
)
53 set_version(&op
->info
);
54 INIT_LIST_HEAD(&op
->list
);
56 list_add_tail(&op
->list
, &send_list
);
57 spin_unlock(&ops_lock
);
61 int gdlm_plock(lm_lockspace_t
*lockspace
, struct lm_lockname
*name
,
62 struct file
*file
, int cmd
, struct file_lock
*fl
)
64 struct gdlm_ls
*ls
= (struct gdlm_ls
*) lockspace
;
68 op
= kzalloc(sizeof(*op
), GFP_KERNEL
);
72 op
->info
.optype
= GDLM_PLOCK_OP_LOCK
;
73 op
->info
.pid
= (uint32_t) fl
->fl_owner
;
74 op
->info
.ex
= (fl
->fl_type
== F_WRLCK
);
75 op
->info
.wait
= IS_SETLKW(cmd
);
76 op
->info
.fsid
= ls
->id
;
77 op
->info
.number
= name
->ln_number
;
78 op
->info
.start
= fl
->fl_start
;
79 op
->info
.end
= fl
->fl_end
;
82 wait_event(recv_wq
, (op
->done
!= 0));
85 if (!list_empty(&op
->list
)) {
86 printk("plock op on list\n");
89 spin_unlock(&ops_lock
);
94 if (posix_lock_file_wait(file
, fl
) < 0)
95 log_error("gdlm_plock: vfs lock error %x,%llx",
96 name
->ln_type
, name
->ln_number
);
103 int gdlm_punlock(lm_lockspace_t
*lockspace
, struct lm_lockname
*name
,
104 struct file
*file
, struct file_lock
*fl
)
106 struct gdlm_ls
*ls
= (struct gdlm_ls
*) lockspace
;
110 op
= kzalloc(sizeof(*op
), GFP_KERNEL
);
114 if (posix_lock_file_wait(file
, fl
) < 0)
115 log_error("gdlm_punlock: vfs unlock error %x,%llx",
116 name
->ln_type
, name
->ln_number
);
118 op
->info
.optype
= GDLM_PLOCK_OP_UNLOCK
;
119 op
->info
.pid
= (uint32_t) fl
->fl_owner
;
120 op
->info
.fsid
= ls
->id
;
121 op
->info
.number
= name
->ln_number
;
122 op
->info
.start
= fl
->fl_start
;
123 op
->info
.end
= fl
->fl_end
;
126 wait_event(recv_wq
, (op
->done
!= 0));
128 spin_lock(&ops_lock
);
129 if (!list_empty(&op
->list
)) {
130 printk("punlock op on list\n");
133 spin_unlock(&ops_lock
);
141 int gdlm_plock_get(lm_lockspace_t
*lockspace
, struct lm_lockname
*name
,
142 struct file
*file
, struct file_lock
*fl
)
144 struct gdlm_ls
*ls
= (struct gdlm_ls
*) lockspace
;
148 op
= kzalloc(sizeof(*op
), GFP_KERNEL
);
152 op
->info
.optype
= GDLM_PLOCK_OP_GET
;
153 op
->info
.pid
= (uint32_t) fl
->fl_owner
;
154 op
->info
.ex
= (fl
->fl_type
== F_WRLCK
);
155 op
->info
.fsid
= ls
->id
;
156 op
->info
.number
= name
->ln_number
;
157 op
->info
.start
= fl
->fl_start
;
158 op
->info
.end
= fl
->fl_end
;
161 wait_event(recv_wq
, (op
->done
!= 0));
163 spin_lock(&ops_lock
);
164 if (!list_empty(&op
->list
)) {
165 printk("plock_get op on list\n");
168 spin_unlock(&ops_lock
);
173 fl
->fl_type
= F_UNLCK
;
175 fl
->fl_type
= (op
->info
.ex
) ? F_WRLCK
: F_RDLCK
;
176 fl
->fl_pid
= op
->info
.pid
;
177 fl
->fl_start
= op
->info
.start
;
178 fl
->fl_end
= op
->info
.end
;
185 /* a read copies out one plock request from the send list */
186 static ssize_t
dev_read(struct file
*file
, char __user
*u
, size_t count
,
189 struct gdlm_plock_info info
;
190 struct plock_op
*op
= NULL
;
192 if (count
< sizeof(info
))
195 spin_lock(&ops_lock
);
196 if (!list_empty(&send_list
)) {
197 op
= list_entry(send_list
.next
, struct plock_op
, list
);
198 list_move(&op
->list
, &recv_list
);
199 memcpy(&info
, &op
->info
, sizeof(info
));
201 spin_unlock(&ops_lock
);
206 if (copy_to_user(u
, &info
, sizeof(info
)))
211 /* a write copies in one plock result that should match a plock_op
213 static ssize_t
dev_write(struct file
*file
, const char __user
*u
, size_t count
,
216 struct gdlm_plock_info info
;
220 if (count
!= sizeof(info
))
223 if (copy_from_user(&info
, u
, sizeof(info
)))
226 if (check_version(&info
))
229 spin_lock(&ops_lock
);
230 list_for_each_entry(op
, &recv_list
, list
) {
231 if (op
->info
.fsid
== info
.fsid
&&
232 op
->info
.number
== info
.number
) {
233 list_del_init(&op
->list
);
236 memcpy(&op
->info
, &info
, sizeof(info
));
240 spin_unlock(&ops_lock
);
245 printk("gdlm dev_write no op %x %llx\n", info
.fsid
,
250 static unsigned int dev_poll(struct file
*file
, poll_table
*wait
)
252 poll_wait(file
, &send_wq
, wait
);
254 spin_lock(&ops_lock
);
255 if (!list_empty(&send_list
)) {
256 spin_unlock(&ops_lock
);
257 return POLLIN
| POLLRDNORM
;
259 spin_unlock(&ops_lock
);
263 static struct file_operations dev_fops
= {
270 static struct miscdevice plock_dev_misc
= {
271 .minor
= MISC_DYNAMIC_MINOR
,
272 .name
= GDLM_PLOCK_MISC_NAME
,
276 int gdlm_plock_init(void)
280 spin_lock_init(&ops_lock
);
281 INIT_LIST_HEAD(&send_list
);
282 INIT_LIST_HEAD(&recv_list
);
283 init_waitqueue_head(&send_wq
);
284 init_waitqueue_head(&recv_wq
);
286 rv
= misc_register(&plock_dev_misc
);
288 printk("gdlm_plock_init: misc_register failed %d", rv
);
292 void gdlm_plock_exit(void)
294 if (misc_deregister(&plock_dev_misc
) < 0)
295 printk("gdlm_plock_exit: misc_deregister failed");