aboutsummaryrefslogtreecommitdiffstats
path: root/fs/dlm
diff options
context:
space:
mode:
Diffstat (limited to 'fs/dlm')
-rw-r--r--fs/dlm/Makefile1
-rw-r--r--fs/dlm/config.c50
-rw-r--r--fs/dlm/config.h3
-rw-r--r--fs/dlm/dlm_internal.h8
-rw-r--r--fs/dlm/lock.c5
-rw-r--r--fs/dlm/lock.h1
-rw-r--r--fs/dlm/main.c7
-rw-r--r--fs/dlm/member.c34
-rw-r--r--fs/dlm/plock.c439
-rw-r--r--fs/dlm/recoverd.c1
10 files changed, 526 insertions, 23 deletions
diff --git a/fs/dlm/Makefile b/fs/dlm/Makefile
index d248e60951ba..ca1c9124c8ce 100644
--- a/fs/dlm/Makefile
+++ b/fs/dlm/Makefile
@@ -10,6 +10,7 @@ dlm-y := ast.o \
10 midcomms.o \ 10 midcomms.o \
11 netlink.o \ 11 netlink.o \
12 lowcomms.o \ 12 lowcomms.o \
13 plock.o \
13 rcom.o \ 14 rcom.o \
14 recover.o \ 15 recover.o \
15 recoverd.o \ 16 recoverd.o \
diff --git a/fs/dlm/config.c b/fs/dlm/config.c
index c3ad1dff3b25..eac23bd288b2 100644
--- a/fs/dlm/config.c
+++ b/fs/dlm/config.c
@@ -114,7 +114,7 @@ struct cluster_attribute {
114}; 114};
115 115
116static ssize_t cluster_set(struct cluster *cl, unsigned int *cl_field, 116static ssize_t cluster_set(struct cluster *cl, unsigned int *cl_field,
117 unsigned int *info_field, int check_zero, 117 int *info_field, int check_zero,
118 const char *buf, size_t len) 118 const char *buf, size_t len)
119{ 119{
120 unsigned int x; 120 unsigned int x;
@@ -284,6 +284,7 @@ struct node {
284 struct list_head list; /* space->members */ 284 struct list_head list; /* space->members */
285 int nodeid; 285 int nodeid;
286 int weight; 286 int weight;
287 int new;
287}; 288};
288 289
289static struct configfs_group_operations clusters_ops = { 290static struct configfs_group_operations clusters_ops = {
@@ -565,6 +566,7 @@ static struct config_item *make_node(struct config_group *g, const char *name)
565 config_item_init_type_name(&nd->item, name, &node_type); 566 config_item_init_type_name(&nd->item, name, &node_type);
566 nd->nodeid = -1; 567 nd->nodeid = -1;
567 nd->weight = 1; /* default weight of 1 if none is set */ 568 nd->weight = 1; /* default weight of 1 if none is set */
569 nd->new = 1; /* set to 0 once it's been read by dlm_nodeid_list() */
568 570
569 mutex_lock(&sp->members_lock); 571 mutex_lock(&sp->members_lock);
570 list_add(&nd->list, &sp->members); 572 list_add(&nd->list, &sp->members);
@@ -805,12 +807,13 @@ static void put_comm(struct comm *cm)
805} 807}
806 808
807/* caller must free mem */ 809/* caller must free mem */
808int dlm_nodeid_list(char *lsname, int **ids_out) 810int dlm_nodeid_list(char *lsname, int **ids_out, int *ids_count_out,
811 int **new_out, int *new_count_out)
809{ 812{
810 struct space *sp; 813 struct space *sp;
811 struct node *nd; 814 struct node *nd;
812 int i = 0, rv = 0; 815 int i = 0, rv = 0, ids_count = 0, new_count = 0;
813 int *ids; 816 int *ids, *new;
814 817
815 sp = get_space(lsname); 818 sp = get_space(lsname);
816 if (!sp) 819 if (!sp)
@@ -818,23 +821,50 @@ int dlm_nodeid_list(char *lsname, int **ids_out)
818 821
819 mutex_lock(&sp->members_lock); 822 mutex_lock(&sp->members_lock);
820 if (!sp->members_count) { 823 if (!sp->members_count) {
821 rv = 0; 824 rv = -EINVAL;
825 printk(KERN_ERR "dlm: zero members_count\n");
822 goto out; 826 goto out;
823 } 827 }
824 828
825 ids = kcalloc(sp->members_count, sizeof(int), GFP_KERNEL); 829 ids_count = sp->members_count;
830
831 ids = kcalloc(ids_count, sizeof(int), GFP_KERNEL);
826 if (!ids) { 832 if (!ids) {
827 rv = -ENOMEM; 833 rv = -ENOMEM;
828 goto out; 834 goto out;
829 } 835 }
830 836
831 rv = sp->members_count; 837 list_for_each_entry(nd, &sp->members, list) {
832 list_for_each_entry(nd, &sp->members, list)
833 ids[i++] = nd->nodeid; 838 ids[i++] = nd->nodeid;
839 if (nd->new)
840 new_count++;
841 }
842
843 if (ids_count != i)
844 printk(KERN_ERR "dlm: bad nodeid count %d %d\n", ids_count, i);
845
846 if (!new_count)
847 goto out_ids;
848
849 new = kcalloc(new_count, sizeof(int), GFP_KERNEL);
850 if (!new) {
851 kfree(ids);
852 rv = -ENOMEM;
853 goto out;
854 }
834 855
835 if (rv != i) 856 i = 0;
836 printk("bad nodeid count %d %d\n", rv, i); 857 list_for_each_entry(nd, &sp->members, list) {
858 if (nd->new) {
859 new[i++] = nd->nodeid;
860 nd->new = 0;
861 }
862 }
863 *new_count_out = new_count;
864 *new_out = new;
837 865
866 out_ids:
867 *ids_count_out = ids_count;
838 *ids_out = ids; 868 *ids_out = ids;
839 out: 869 out:
840 mutex_unlock(&sp->members_lock); 870 mutex_unlock(&sp->members_lock);
diff --git a/fs/dlm/config.h b/fs/dlm/config.h
index a3170fe22090..4f1d6fce58c5 100644
--- a/fs/dlm/config.h
+++ b/fs/dlm/config.h
@@ -35,7 +35,8 @@ extern struct dlm_config_info dlm_config;
35int dlm_config_init(void); 35int dlm_config_init(void);
36void dlm_config_exit(void); 36void dlm_config_exit(void);
37int dlm_node_weight(char *lsname, int nodeid); 37int dlm_node_weight(char *lsname, int nodeid);
38int dlm_nodeid_list(char *lsname, int **ids_out); 38int dlm_nodeid_list(char *lsname, int **ids_out, int *ids_count_out,
39 int **new_out, int *new_count_out);
39int dlm_nodeid_to_addr(int nodeid, struct sockaddr_storage *addr); 40int dlm_nodeid_to_addr(int nodeid, struct sockaddr_storage *addr);
40int dlm_addr_to_nodeid(struct sockaddr_storage *addr, int *nodeid); 41int dlm_addr_to_nodeid(struct sockaddr_storage *addr, int *nodeid);
41int dlm_our_nodeid(void); 42int dlm_our_nodeid(void);
diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h
index 7a8824f475f2..5a7ac33b629c 100644
--- a/fs/dlm/dlm_internal.h
+++ b/fs/dlm/dlm_internal.h
@@ -42,8 +42,6 @@
42#include <linux/dlm.h> 42#include <linux/dlm.h>
43#include "config.h" 43#include "config.h"
44 44
45#define DLM_LOCKSPACE_LEN 64
46
47/* Size of the temp buffer midcomms allocates on the stack. 45/* Size of the temp buffer midcomms allocates on the stack.
48 We try to make this large enough so most messages fit. 46 We try to make this large enough so most messages fit.
49 FIXME: should sctp make this unnecessary? */ 47 FIXME: should sctp make this unnecessary? */
@@ -132,8 +130,10 @@ struct dlm_member {
132 130
133struct dlm_recover { 131struct dlm_recover {
134 struct list_head list; 132 struct list_head list;
135 int *nodeids; 133 int *nodeids; /* nodeids of all members */
136 int node_count; 134 int node_count;
135 int *new; /* nodeids of new members */
136 int new_count;
137 uint64_t seq; 137 uint64_t seq;
138}; 138};
139 139
@@ -579,6 +579,8 @@ static inline int dlm_no_directory(struct dlm_ls *ls)
579int dlm_netlink_init(void); 579int dlm_netlink_init(void);
580void dlm_netlink_exit(void); 580void dlm_netlink_exit(void);
581void dlm_timeout_warn(struct dlm_lkb *lkb); 581void dlm_timeout_warn(struct dlm_lkb *lkb);
582int dlm_plock_init(void);
583void dlm_plock_exit(void);
582 584
583#ifdef CONFIG_DLM_DEBUG 585#ifdef CONFIG_DLM_DEBUG
584int dlm_register_debugfs(void); 586int dlm_register_debugfs(void);
diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c
index 8f250ac8b928..2d3d1027ce2b 100644
--- a/fs/dlm/lock.c
+++ b/fs/dlm/lock.c
@@ -165,7 +165,7 @@ void dlm_print_lkb(struct dlm_lkb *lkb)
165 lkb->lkb_grmode, lkb->lkb_wait_type, lkb->lkb_ast_type); 165 lkb->lkb_grmode, lkb->lkb_wait_type, lkb->lkb_ast_type);
166} 166}
167 167
168void dlm_print_rsb(struct dlm_rsb *r) 168static void dlm_print_rsb(struct dlm_rsb *r)
169{ 169{
170 printk(KERN_ERR "rsb: nodeid %d flags %lx first %x rlc %d name %s\n", 170 printk(KERN_ERR "rsb: nodeid %d flags %lx first %x rlc %d name %s\n",
171 r->res_nodeid, r->res_flags, r->res_first_lkid, 171 r->res_nodeid, r->res_flags, r->res_first_lkid,
@@ -1956,8 +1956,7 @@ static void confirm_master(struct dlm_rsb *r, int error)
1956 list_del_init(&lkb->lkb_rsb_lookup); 1956 list_del_init(&lkb->lkb_rsb_lookup);
1957 r->res_first_lkid = lkb->lkb_id; 1957 r->res_first_lkid = lkb->lkb_id;
1958 _request_lock(r, lkb); 1958 _request_lock(r, lkb);
1959 } else 1959 }
1960 r->res_nodeid = -1;
1961 break; 1960 break;
1962 1961
1963 default: 1962 default:
diff --git a/fs/dlm/lock.h b/fs/dlm/lock.h
index 05d9c82e646b..88e93c80cc22 100644
--- a/fs/dlm/lock.h
+++ b/fs/dlm/lock.h
@@ -13,7 +13,6 @@
13#ifndef __LOCK_DOT_H__ 13#ifndef __LOCK_DOT_H__
14#define __LOCK_DOT_H__ 14#define __LOCK_DOT_H__
15 15
16void dlm_print_rsb(struct dlm_rsb *r);
17void dlm_dump_rsb(struct dlm_rsb *r); 16void dlm_dump_rsb(struct dlm_rsb *r);
18void dlm_print_lkb(struct dlm_lkb *lkb); 17void dlm_print_lkb(struct dlm_lkb *lkb);
19void dlm_receive_message_saved(struct dlm_ls *ls, struct dlm_message *ms); 18void dlm_receive_message_saved(struct dlm_ls *ls, struct dlm_message *ms);
diff --git a/fs/dlm/main.c b/fs/dlm/main.c
index 58487fb95a4c..b80e0aa3cfa5 100644
--- a/fs/dlm/main.c
+++ b/fs/dlm/main.c
@@ -46,10 +46,16 @@ static int __init init_dlm(void)
46 if (error) 46 if (error)
47 goto out_user; 47 goto out_user;
48 48
49 error = dlm_plock_init();
50 if (error)
51 goto out_netlink;
52
49 printk("DLM (built %s %s) installed\n", __DATE__, __TIME__); 53 printk("DLM (built %s %s) installed\n", __DATE__, __TIME__);
50 54
51 return 0; 55 return 0;
52 56
57 out_netlink:
58 dlm_netlink_exit();
53 out_user: 59 out_user:
54 dlm_user_exit(); 60 dlm_user_exit();
55 out_debug: 61 out_debug:
@@ -66,6 +72,7 @@ static int __init init_dlm(void)
66 72
67static void __exit exit_dlm(void) 73static void __exit exit_dlm(void)
68{ 74{
75 dlm_plock_exit();
69 dlm_netlink_exit(); 76 dlm_netlink_exit();
70 dlm_user_exit(); 77 dlm_user_exit();
71 dlm_config_exit(); 78 dlm_config_exit();
diff --git a/fs/dlm/member.c b/fs/dlm/member.c
index fa17f5a27883..26133f05ae3a 100644
--- a/fs/dlm/member.c
+++ b/fs/dlm/member.c
@@ -210,6 +210,23 @@ int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out)
210 } 210 }
211 } 211 }
212 212
213 /* Add an entry to ls_nodes_gone for members that were removed and
214 then added again, so that previous state for these nodes will be
215 cleared during recovery. */
216
217 for (i = 0; i < rv->new_count; i++) {
218 if (!dlm_is_member(ls, rv->new[i]))
219 continue;
220 log_debug(ls, "new nodeid %d is a re-added member", rv->new[i]);
221
222 memb = kzalloc(sizeof(struct dlm_member), GFP_KERNEL);
223 if (!memb)
224 return -ENOMEM;
225 memb->nodeid = rv->new[i];
226 list_add_tail(&memb->list, &ls->ls_nodes_gone);
227 neg++;
228 }
229
213 /* add new members to ls_nodes */ 230 /* add new members to ls_nodes */
214 231
215 for (i = 0; i < rv->node_count; i++) { 232 for (i = 0; i < rv->node_count; i++) {
@@ -314,15 +331,16 @@ int dlm_ls_stop(struct dlm_ls *ls)
314int dlm_ls_start(struct dlm_ls *ls) 331int dlm_ls_start(struct dlm_ls *ls)
315{ 332{
316 struct dlm_recover *rv = NULL, *rv_old; 333 struct dlm_recover *rv = NULL, *rv_old;
317 int *ids = NULL; 334 int *ids = NULL, *new = NULL;
318 int error, count; 335 int error, ids_count = 0, new_count = 0;
319 336
320 rv = kzalloc(sizeof(struct dlm_recover), GFP_KERNEL); 337 rv = kzalloc(sizeof(struct dlm_recover), GFP_KERNEL);
321 if (!rv) 338 if (!rv)
322 return -ENOMEM; 339 return -ENOMEM;
323 340
324 error = count = dlm_nodeid_list(ls->ls_name, &ids); 341 error = dlm_nodeid_list(ls->ls_name, &ids, &ids_count,
325 if (error <= 0) 342 &new, &new_count);
343 if (error < 0)
326 goto fail; 344 goto fail;
327 345
328 spin_lock(&ls->ls_recover_lock); 346 spin_lock(&ls->ls_recover_lock);
@@ -337,14 +355,19 @@ int dlm_ls_start(struct dlm_ls *ls)
337 } 355 }
338 356
339 rv->nodeids = ids; 357 rv->nodeids = ids;
340 rv->node_count = count; 358 rv->node_count = ids_count;
359 rv->new = new;
360 rv->new_count = new_count;
341 rv->seq = ++ls->ls_recover_seq; 361 rv->seq = ++ls->ls_recover_seq;
342 rv_old = ls->ls_recover_args; 362 rv_old = ls->ls_recover_args;
343 ls->ls_recover_args = rv; 363 ls->ls_recover_args = rv;
344 spin_unlock(&ls->ls_recover_lock); 364 spin_unlock(&ls->ls_recover_lock);
345 365
346 if (rv_old) { 366 if (rv_old) {
367 log_error(ls, "unused recovery %llx %d",
368 (unsigned long long)rv_old->seq, rv_old->node_count);
347 kfree(rv_old->nodeids); 369 kfree(rv_old->nodeids);
370 kfree(rv_old->new);
348 kfree(rv_old); 371 kfree(rv_old);
349 } 372 }
350 373
@@ -354,6 +377,7 @@ int dlm_ls_start(struct dlm_ls *ls)
354 fail: 377 fail:
355 kfree(rv); 378 kfree(rv);
356 kfree(ids); 379 kfree(ids);
380 kfree(new);
357 return error; 381 return error;
358} 382}
359 383
diff --git a/fs/dlm/plock.c b/fs/dlm/plock.c
new file mode 100644
index 000000000000..d6d6e370f89c
--- /dev/null
+++ b/fs/dlm/plock.c
@@ -0,0 +1,439 @@
1/*
2 * Copyright (C) 2005-2008 Red Hat, Inc. All rights reserved.
3 *
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.
7 */
8
9#include <linux/fs.h>
10#include <linux/miscdevice.h>
11#include <linux/poll.h>
12#include <linux/dlm.h>
13#include <linux/dlm_plock.h>
14
15#include "dlm_internal.h"
16#include "lockspace.h"
17
18static spinlock_t ops_lock;
19static struct list_head send_list;
20static struct list_head recv_list;
21static wait_queue_head_t send_wq;
22static wait_queue_head_t recv_wq;
23
24struct plock_op {
25 struct list_head list;
26 int done;
27 struct dlm_plock_info info;
28};
29
30struct plock_xop {
31 struct plock_op xop;
32 void *callback;
33 void *fl;
34 void *file;
35 struct file_lock flc;
36};
37
38
39static inline void set_version(struct dlm_plock_info *info)
40{
41 info->version[0] = DLM_PLOCK_VERSION_MAJOR;
42 info->version[1] = DLM_PLOCK_VERSION_MINOR;
43 info->version[2] = DLM_PLOCK_VERSION_PATCH;
44}
45
46static int check_version(struct dlm_plock_info *info)
47{
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,
55 info->version[0],
56 info->version[1],
57 info->version[2]);
58 return -EINVAL;
59 }
60 return 0;
61}
62
63static void send_op(struct plock_op *op)
64{
65 set_version(&op->info);
66 INIT_LIST_HEAD(&op->list);
67 spin_lock(&ops_lock);
68 list_add_tail(&op->list, &send_list);
69 spin_unlock(&ops_lock);
70 wake_up(&send_wq);
71}
72
73int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
74 int cmd, struct file_lock *fl)
75{
76 struct dlm_ls *ls;
77 struct plock_op *op;
78 struct plock_xop *xop;
79 int rv;
80
81 ls = dlm_find_lockspace_local(lockspace);
82 if (!ls)
83 return -EINVAL;
84
85 xop = kzalloc(sizeof(*xop), GFP_KERNEL);
86 if (!xop) {
87 rv = -ENOMEM;
88 goto out;
89 }
90
91 op = &xop->xop;
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);
107 xop->fl = fl;
108 xop->file = file;
109 } else {
110 op->info.owner = (__u64)(long) fl->fl_owner;
111 xop->callback = NULL;
112 }
113
114 send_op(op);
115
116 if (xop->callback == NULL)
117 wait_event(recv_wq, (op->done != 0));
118 else {
119 rv = -EINPROGRESS;
120 goto out;
121 }
122
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);
127 list_del(&op->list);
128 }
129 spin_unlock(&ops_lock);
130
131 rv = op->info.rv;
132
133 if (!rv) {
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);
137 }
138
139 kfree(xop);
140out:
141 dlm_put_lockspace(ls);
142 return rv;
143}
144EXPORT_SYMBOL_GPL(dlm_posix_lock);
145
146/* Returns failure iff a succesful lock operation should be canceled */
147static int dlm_plock_callback(struct plock_op *op)
148{
149 struct file *file;
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;
154 int rv = 0;
155
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);
160 list_del(&op->list);
161 }
162 spin_unlock(&ops_lock);
163
164 /* check if the following 2 are still valid or make a copy */
165 file = xop->file;
166 flc = &xop->flc;
167 fl = xop->fl;
168 notify = xop->callback;
169
170 if (op->info.rv) {
171 notify(flc, NULL, op->info.rv);
172 goto out;
173 }
174
175 /* got fs lock; bookkeep locally as well: */
176 flc->fl_flags &= ~FL_SLEEP;
177 if (posix_lock_file(file, flc, NULL)) {
178 /*
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.
185 */
186 log_print("dlm_plock_callback: vfs lock error %llx file %p fl %p",
187 (unsigned long long)op->info.number, file, fl);
188 }
189
190 rv = notify(flc, NULL, 0);
191 if (rv) {
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");
195 goto out;
196 }
197
198out:
199 kfree(xop);
200 return rv;
201}
202
203int dlm_posix_unlock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
204 struct file_lock *fl)
205{
206 struct dlm_ls *ls;
207 struct plock_op *op;
208 int rv;
209
210 ls = dlm_find_lockspace_local(lockspace);
211 if (!ls)
212 return -EINVAL;
213
214 op = kzalloc(sizeof(*op), GFP_KERNEL);
215 if (!op) {
216 rv = -ENOMEM;
217 goto out;
218 }
219
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);
223
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;
232 else
233 op->info.owner = (__u64)(long) fl->fl_owner;
234
235 send_op(op);
236 wait_event(recv_wq, (op->done != 0));
237
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);
242 list_del(&op->list);
243 }
244 spin_unlock(&ops_lock);
245
246 rv = op->info.rv;
247
248 if (rv == -ENOENT)
249 rv = 0;
250
251 kfree(op);
252out:
253 dlm_put_lockspace(ls);
254 return rv;
255}
256EXPORT_SYMBOL_GPL(dlm_posix_unlock);
257
258int dlm_posix_get(dlm_lockspace_t *lockspace, u64 number, struct file *file,
259 struct file_lock *fl)
260{
261 struct dlm_ls *ls;
262 struct plock_op *op;
263 int rv;
264
265 ls = dlm_find_lockspace_local(lockspace);
266 if (!ls)
267 return -EINVAL;
268
269 op = kzalloc(sizeof(*op), GFP_KERNEL);
270 if (!op) {
271 rv = -ENOMEM;
272 goto out;
273 }
274
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;
284 else
285 op->info.owner = (__u64)(long) fl->fl_owner;
286
287 send_op(op);
288 wait_event(recv_wq, (op->done != 0));
289
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);
294 list_del(&op->list);
295 }
296 spin_unlock(&ops_lock);
297
298 /* info.rv from userspace is 1 for conflict, 0 for no-conflict,
299 -ENOENT if there are no locks on the file */
300
301 rv = op->info.rv;
302
303 fl->fl_type = F_UNLCK;
304 if (rv == -ENOENT)
305 rv = 0;
306 else if (rv > 0) {
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;
311 rv = 0;
312 }
313
314 kfree(op);
315out:
316 dlm_put_lockspace(ls);
317 return rv;
318}
319EXPORT_SYMBOL_GPL(dlm_posix_get);
320
321/* a read copies out one plock request from the send list */
322static ssize_t dev_read(struct file *file, char __user *u, size_t count,
323 loff_t *ppos)
324{
325 struct dlm_plock_info info;
326 struct plock_op *op = NULL;
327
328 if (count < sizeof(info))
329 return -EINVAL;
330
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));
336 }
337 spin_unlock(&ops_lock);
338
339 if (!op)
340 return -EAGAIN;
341
342 if (copy_to_user(u, &info, sizeof(info)))
343 return -EFAULT;
344 return sizeof(info);
345}
346
347/* a write copies in one plock result that should match a plock_op
348 on the recv list */
349static ssize_t dev_write(struct file *file, const char __user *u, size_t count,
350 loff_t *ppos)
351{
352 struct dlm_plock_info info;
353 struct plock_op *op;
354 int found = 0;
355
356 if (count != sizeof(info))
357 return -EINVAL;
358
359 if (copy_from_user(&info, u, sizeof(info)))
360 return -EFAULT;
361
362 if (check_version(&info))
363 return -EINVAL;
364
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);
370 found = 1;
371 op->done = 1;
372 memcpy(&op->info, &info, sizeof(info));
373 break;
374 }
375 }
376 spin_unlock(&ops_lock);
377
378 if (found) {
379 struct plock_xop *xop;
380 xop = (struct plock_xop *)op;
381 if (xop->callback)
382 count = dlm_plock_callback(op);
383 else
384 wake_up(&recv_wq);
385 } else
386 log_print("dev_write no op %x %llx", info.fsid,
387 (unsigned long long)info.number);
388 return count;
389}
390
391static unsigned int dev_poll(struct file *file, poll_table *wait)
392{
393 unsigned int mask = 0;
394
395 poll_wait(file, &send_wq, wait);
396
397 spin_lock(&ops_lock);
398 if (!list_empty(&send_list))
399 mask = POLLIN | POLLRDNORM;
400 spin_unlock(&ops_lock);
401
402 return mask;
403}
404
405static const struct file_operations dev_fops = {
406 .read = dev_read,
407 .write = dev_write,
408 .poll = dev_poll,
409 .owner = THIS_MODULE
410};
411
412static struct miscdevice plock_dev_misc = {
413 .minor = MISC_DYNAMIC_MINOR,
414 .name = DLM_PLOCK_MISC_NAME,
415 .fops = &dev_fops
416};
417
418int dlm_plock_init(void)
419{
420 int rv;
421
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);
427
428 rv = misc_register(&plock_dev_misc);
429 if (rv)
430 log_print("dlm_plock_init: misc_register failed %d", rv);
431 return rv;
432}
433
434void dlm_plock_exit(void)
435{
436 if (misc_deregister(&plock_dev_misc) < 0)
437 log_print("dlm_plock_exit: misc_deregister failed");
438}
439
diff --git a/fs/dlm/recoverd.c b/fs/dlm/recoverd.c
index 997f9531d594..fd677c8c3d3b 100644
--- a/fs/dlm/recoverd.c
+++ b/fs/dlm/recoverd.c
@@ -257,6 +257,7 @@ static void do_ls_recovery(struct dlm_ls *ls)
257 if (rv) { 257 if (rv) {
258 ls_recover(ls, rv); 258 ls_recover(ls, rv);
259 kfree(rv->nodeids); 259 kfree(rv->nodeids);
260 kfree(rv->new);
260 kfree(rv); 261 kfree(rv);
261 } 262 }
262} 263}