diff options
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 | } |
