diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-22 16:44:23 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-22 16:44:23 -0400 |
commit | 03b883840c630c7b571690577809754739ac773f (patch) | |
tree | aeec0581accf5e19360205e21dd25a220b4a0e54 /fs/dlm | |
parent | 0d07a15bdb5a4ea6271b6e874d307c48151ef546 (diff) | |
parent | c1c76743e98346eb052b707f0e054377a09441d1 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/teigland/dlm
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/teigland/dlm:
dlm: linux/{dlm,dlm_device}.h: cleanup for userspace
dlm: common max length definitions
dlm: move plock code from gfs2
dlm: recover nodes that are removed and re-added
dlm: save master info after failed no-queue request
dlm: make dlm_print_rsb() static
dlm: match signedness between dlm_config_info and cluster_set
Diffstat (limited to 'fs/dlm')
-rw-r--r-- | fs/dlm/Makefile | 1 | ||||
-rw-r--r-- | fs/dlm/config.c | 50 | ||||
-rw-r--r-- | fs/dlm/config.h | 3 | ||||
-rw-r--r-- | fs/dlm/dlm_internal.h | 8 | ||||
-rw-r--r-- | fs/dlm/lock.c | 5 | ||||
-rw-r--r-- | fs/dlm/lock.h | 1 | ||||
-rw-r--r-- | fs/dlm/main.c | 7 | ||||
-rw-r--r-- | fs/dlm/member.c | 34 | ||||
-rw-r--r-- | fs/dlm/plock.c | 439 | ||||
-rw-r--r-- | fs/dlm/recoverd.c | 1 |
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 | ||
116 | static ssize_t cluster_set(struct cluster *cl, unsigned int *cl_field, | 116 | static 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 | ||
289 | static struct configfs_group_operations clusters_ops = { | 290 | static 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 */ |
808 | int dlm_nodeid_list(char *lsname, int **ids_out) | 810 | int 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; | |||
35 | int dlm_config_init(void); | 35 | int dlm_config_init(void); |
36 | void dlm_config_exit(void); | 36 | void dlm_config_exit(void); |
37 | int dlm_node_weight(char *lsname, int nodeid); | 37 | int dlm_node_weight(char *lsname, int nodeid); |
38 | int dlm_nodeid_list(char *lsname, int **ids_out); | 38 | int dlm_nodeid_list(char *lsname, int **ids_out, int *ids_count_out, |
39 | int **new_out, int *new_count_out); | ||
39 | int dlm_nodeid_to_addr(int nodeid, struct sockaddr_storage *addr); | 40 | int dlm_nodeid_to_addr(int nodeid, struct sockaddr_storage *addr); |
40 | int dlm_addr_to_nodeid(struct sockaddr_storage *addr, int *nodeid); | 41 | int dlm_addr_to_nodeid(struct sockaddr_storage *addr, int *nodeid); |
41 | int dlm_our_nodeid(void); | 42 | int 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 | ||
133 | struct dlm_recover { | 131 | struct 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) | |||
579 | int dlm_netlink_init(void); | 579 | int dlm_netlink_init(void); |
580 | void dlm_netlink_exit(void); | 580 | void dlm_netlink_exit(void); |
581 | void dlm_timeout_warn(struct dlm_lkb *lkb); | 581 | void dlm_timeout_warn(struct dlm_lkb *lkb); |
582 | int dlm_plock_init(void); | ||
583 | void dlm_plock_exit(void); | ||
582 | 584 | ||
583 | #ifdef CONFIG_DLM_DEBUG | 585 | #ifdef CONFIG_DLM_DEBUG |
584 | int dlm_register_debugfs(void); | 586 | int 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 | ||
168 | void dlm_print_rsb(struct dlm_rsb *r) | 168 | static 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 | ||
16 | void dlm_print_rsb(struct dlm_rsb *r); | ||
17 | void dlm_dump_rsb(struct dlm_rsb *r); | 16 | void dlm_dump_rsb(struct dlm_rsb *r); |
18 | void dlm_print_lkb(struct dlm_lkb *lkb); | 17 | void dlm_print_lkb(struct dlm_lkb *lkb); |
19 | void dlm_receive_message_saved(struct dlm_ls *ls, struct dlm_message *ms); | 18 | void 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 | ||
67 | static void __exit exit_dlm(void) | 73 | static 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) | |||
314 | int dlm_ls_start(struct dlm_ls *ls) | 331 | int 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 | |||
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; | ||
23 | |||
24 | struct plock_op { | ||
25 | struct list_head list; | ||
26 | int done; | ||
27 | struct dlm_plock_info info; | ||
28 | }; | ||
29 | |||
30 | struct plock_xop { | ||
31 | struct plock_op xop; | ||
32 | void *callback; | ||
33 | void *fl; | ||
34 | void *file; | ||
35 | struct file_lock flc; | ||
36 | }; | ||
37 | |||
38 | |||
39 | static 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 | |||
46 | static 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 | |||
63 | static 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 | |||
73 | int 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); | ||
140 | out: | ||
141 | dlm_put_lockspace(ls); | ||
142 | return rv; | ||
143 | } | ||
144 | EXPORT_SYMBOL_GPL(dlm_posix_lock); | ||
145 | |||
146 | /* Returns failure iff a succesful lock operation should be canceled */ | ||
147 | static 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 | |||
198 | out: | ||
199 | kfree(xop); | ||
200 | return rv; | ||
201 | } | ||
202 | |||
203 | int 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); | ||
252 | out: | ||
253 | dlm_put_lockspace(ls); | ||
254 | return rv; | ||
255 | } | ||
256 | EXPORT_SYMBOL_GPL(dlm_posix_unlock); | ||
257 | |||
258 | int 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); | ||
315 | out: | ||
316 | dlm_put_lockspace(ls); | ||
317 | return rv; | ||
318 | } | ||
319 | EXPORT_SYMBOL_GPL(dlm_posix_get); | ||
320 | |||
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, | ||
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 */ | ||
349 | static 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 | |||
391 | static 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 | |||
405 | static const struct file_operations dev_fops = { | ||
406 | .read = dev_read, | ||
407 | .write = dev_write, | ||
408 | .poll = dev_poll, | ||
409 | .owner = THIS_MODULE | ||
410 | }; | ||
411 | |||
412 | static struct miscdevice plock_dev_misc = { | ||
413 | .minor = MISC_DYNAMIC_MINOR, | ||
414 | .name = DLM_PLOCK_MISC_NAME, | ||
415 | .fops = &dev_fops | ||
416 | }; | ||
417 | |||
418 | int 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 | |||
434 | void 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 | } |