aboutsummaryrefslogtreecommitdiffstats
path: root/fs/dlm
diff options
context:
space:
mode:
authorDavid Teigland <teigland@redhat.com>2007-05-18 09:59:31 -0400
committerSteven Whitehouse <swhiteho@redhat.com>2007-07-09 03:22:33 -0400
commit3ae1acf93a21512512f8a78430fcde5992dd208e (patch)
tree878ed3c619530c6acf862ecf663063f66fc47a06 /fs/dlm
parent85e86edf951a8a39954c0ba1edbe4a58827dcd5c (diff)
[DLM] add lock timeouts and warnings [2/6]
New features: lock timeouts and time warnings. If the DLM_LKF_TIMEOUT flag is set, then the request/conversion will be canceled after waiting the specified number of centiseconds (specified per lock). This feature is only available for locks requested through libdlm (can be enabled for kernel dlm users if there's a use for it.) If the new DLM_LSFL_TIMEWARN flag is set when creating the lockspace, then a warning message will be sent to userspace (using genetlink) after a request/conversion has been waiting for a given number of centiseconds (configurable per node). The time warnings will be used in the future to do deadlock detection in userspace. Signed-off-by: David Teigland <teigland@redhat.com> Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/dlm')
-rw-r--r--fs/dlm/Makefile1
-rw-r--r--fs/dlm/config.c8
-rw-r--r--fs/dlm/config.h1
-rw-r--r--fs/dlm/dlm_internal.h10
-rw-r--r--fs/dlm/lock.c146
-rw-r--r--fs/dlm/lock.h4
-rw-r--r--fs/dlm/lockspace.c10
-rw-r--r--fs/dlm/main.c11
-rw-r--r--fs/dlm/member.c5
-rw-r--r--fs/dlm/netlink.c155
-rw-r--r--fs/dlm/recoverd.c4
-rw-r--r--fs/dlm/user.c2
12 files changed, 348 insertions, 9 deletions
diff --git a/fs/dlm/Makefile b/fs/dlm/Makefile
index 604cf7dc5f39..d248e60951ba 100644
--- a/fs/dlm/Makefile
+++ b/fs/dlm/Makefile
@@ -8,6 +8,7 @@ dlm-y := ast.o \
8 member.o \ 8 member.o \
9 memory.o \ 9 memory.o \
10 midcomms.o \ 10 midcomms.o \
11 netlink.o \
11 lowcomms.o \ 12 lowcomms.o \
12 rcom.o \ 13 rcom.o \
13 recover.o \ 14 recover.o \
diff --git a/fs/dlm/config.c b/fs/dlm/config.c
index 5a3d390cc826..2909abf1bbc3 100644
--- a/fs/dlm/config.c
+++ b/fs/dlm/config.c
@@ -90,6 +90,7 @@ struct cluster {
90 unsigned int cl_scan_secs; 90 unsigned int cl_scan_secs;
91 unsigned int cl_log_debug; 91 unsigned int cl_log_debug;
92 unsigned int cl_protocol; 92 unsigned int cl_protocol;
93 unsigned int cl_timewarn_cs;
93}; 94};
94 95
95enum { 96enum {
@@ -103,6 +104,7 @@ enum {
103 CLUSTER_ATTR_SCAN_SECS, 104 CLUSTER_ATTR_SCAN_SECS,
104 CLUSTER_ATTR_LOG_DEBUG, 105 CLUSTER_ATTR_LOG_DEBUG,
105 CLUSTER_ATTR_PROTOCOL, 106 CLUSTER_ATTR_PROTOCOL,
107 CLUSTER_ATTR_TIMEWARN_CS,
106}; 108};
107 109
108struct cluster_attribute { 110struct cluster_attribute {
@@ -162,6 +164,7 @@ CLUSTER_ATTR(toss_secs, 1);
162CLUSTER_ATTR(scan_secs, 1); 164CLUSTER_ATTR(scan_secs, 1);
163CLUSTER_ATTR(log_debug, 0); 165CLUSTER_ATTR(log_debug, 0);
164CLUSTER_ATTR(protocol, 0); 166CLUSTER_ATTR(protocol, 0);
167CLUSTER_ATTR(timewarn_cs, 1);
165 168
166static struct configfs_attribute *cluster_attrs[] = { 169static struct configfs_attribute *cluster_attrs[] = {
167 [CLUSTER_ATTR_TCP_PORT] = &cluster_attr_tcp_port.attr, 170 [CLUSTER_ATTR_TCP_PORT] = &cluster_attr_tcp_port.attr,
@@ -174,6 +177,7 @@ static struct configfs_attribute *cluster_attrs[] = {
174 [CLUSTER_ATTR_SCAN_SECS] = &cluster_attr_scan_secs.attr, 177 [CLUSTER_ATTR_SCAN_SECS] = &cluster_attr_scan_secs.attr,
175 [CLUSTER_ATTR_LOG_DEBUG] = &cluster_attr_log_debug.attr, 178 [CLUSTER_ATTR_LOG_DEBUG] = &cluster_attr_log_debug.attr,
176 [CLUSTER_ATTR_PROTOCOL] = &cluster_attr_protocol.attr, 179 [CLUSTER_ATTR_PROTOCOL] = &cluster_attr_protocol.attr,
180 [CLUSTER_ATTR_TIMEWARN_CS] = &cluster_attr_timewarn_cs.attr,
177 NULL, 181 NULL,
178}; 182};
179 183
@@ -916,6 +920,7 @@ int dlm_our_addr(struct sockaddr_storage *addr, int num)
916#define DEFAULT_SCAN_SECS 5 920#define DEFAULT_SCAN_SECS 5
917#define DEFAULT_LOG_DEBUG 0 921#define DEFAULT_LOG_DEBUG 0
918#define DEFAULT_PROTOCOL 0 922#define DEFAULT_PROTOCOL 0
923#define DEFAULT_TIMEWARN_CS 500 /* 5 sec = 500 centiseconds */
919 924
920struct dlm_config_info dlm_config = { 925struct dlm_config_info dlm_config = {
921 .ci_tcp_port = DEFAULT_TCP_PORT, 926 .ci_tcp_port = DEFAULT_TCP_PORT,
@@ -927,6 +932,7 @@ struct dlm_config_info dlm_config = {
927 .ci_toss_secs = DEFAULT_TOSS_SECS, 932 .ci_toss_secs = DEFAULT_TOSS_SECS,
928 .ci_scan_secs = DEFAULT_SCAN_SECS, 933 .ci_scan_secs = DEFAULT_SCAN_SECS,
929 .ci_log_debug = DEFAULT_LOG_DEBUG, 934 .ci_log_debug = DEFAULT_LOG_DEBUG,
930 .ci_protocol = DEFAULT_PROTOCOL 935 .ci_protocol = DEFAULT_PROTOCOL,
936 .ci_timewarn_cs = DEFAULT_TIMEWARN_CS
931}; 937};
932 938
diff --git a/fs/dlm/config.h b/fs/dlm/config.h
index 967cc3d72e5e..a3170fe22090 100644
--- a/fs/dlm/config.h
+++ b/fs/dlm/config.h
@@ -27,6 +27,7 @@ struct dlm_config_info {
27 int ci_scan_secs; 27 int ci_scan_secs;
28 int ci_log_debug; 28 int ci_log_debug;
29 int ci_protocol; 29 int ci_protocol;
30 int ci_timewarn_cs;
30}; 31};
31 32
32extern struct dlm_config_info dlm_config; 33extern struct dlm_config_info dlm_config;
diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h
index 30994d68f6a0..65a5fc076b8a 100644
--- a/fs/dlm/dlm_internal.h
+++ b/fs/dlm/dlm_internal.h
@@ -213,8 +213,10 @@ struct dlm_args {
213#define DLM_IFL_OVERLAP_UNLOCK 0x00080000 213#define DLM_IFL_OVERLAP_UNLOCK 0x00080000
214#define DLM_IFL_OVERLAP_CANCEL 0x00100000 214#define DLM_IFL_OVERLAP_CANCEL 0x00100000
215#define DLM_IFL_ENDOFLIFE 0x00200000 215#define DLM_IFL_ENDOFLIFE 0x00200000
216#define DLM_IFL_WATCH_TIMEWARN 0x00400000
216#define DLM_IFL_USER 0x00000001 217#define DLM_IFL_USER 0x00000001
217#define DLM_IFL_ORPHAN 0x00000002 218#define DLM_IFL_ORPHAN 0x00000002
219#define DLM_IFL_TIMEOUT_CANCEL 0x00000004
218 220
219struct dlm_lkb { 221struct dlm_lkb {
220 struct dlm_rsb *lkb_resource; /* the rsb */ 222 struct dlm_rsb *lkb_resource; /* the rsb */
@@ -243,6 +245,9 @@ struct dlm_lkb {
243 struct list_head lkb_wait_reply; /* waiting for remote reply */ 245 struct list_head lkb_wait_reply; /* waiting for remote reply */
244 struct list_head lkb_astqueue; /* need ast to be sent */ 246 struct list_head lkb_astqueue; /* need ast to be sent */
245 struct list_head lkb_ownqueue; /* list of locks for a process */ 247 struct list_head lkb_ownqueue; /* list of locks for a process */
248 struct list_head lkb_time_list;
249 unsigned long lkb_timestamp;
250 unsigned long lkb_timeout_cs;
246 251
247 char *lkb_lvbptr; 252 char *lkb_lvbptr;
248 struct dlm_lksb *lkb_lksb; /* caller's status block */ 253 struct dlm_lksb *lkb_lksb; /* caller's status block */
@@ -447,6 +452,9 @@ struct dlm_ls {
447 struct mutex ls_orphans_mutex; 452 struct mutex ls_orphans_mutex;
448 struct list_head ls_orphans; 453 struct list_head ls_orphans;
449 454
455 struct mutex ls_timeout_mutex;
456 struct list_head ls_timeout;
457
450 struct list_head ls_nodes; /* current nodes in ls */ 458 struct list_head ls_nodes; /* current nodes in ls */
451 struct list_head ls_nodes_gone; /* dead node list, recovery */ 459 struct list_head ls_nodes_gone; /* dead node list, recovery */
452 int ls_num_nodes; /* number of nodes in ls */ 460 int ls_num_nodes; /* number of nodes in ls */
@@ -472,6 +480,7 @@ struct dlm_ls {
472 struct task_struct *ls_recoverd_task; 480 struct task_struct *ls_recoverd_task;
473 struct mutex ls_recoverd_active; 481 struct mutex ls_recoverd_active;
474 spinlock_t ls_recover_lock; 482 spinlock_t ls_recover_lock;
483 unsigned long ls_recover_begin; /* jiffies timestamp */
475 uint32_t ls_recover_status; /* DLM_RS_ */ 484 uint32_t ls_recover_status; /* DLM_RS_ */
476 uint64_t ls_recover_seq; 485 uint64_t ls_recover_seq;
477 struct dlm_recover *ls_recover_args; 486 struct dlm_recover *ls_recover_args;
@@ -501,6 +510,7 @@ struct dlm_ls {
501#define LSFL_RCOM_READY 3 510#define LSFL_RCOM_READY 3
502#define LSFL_RCOM_WAIT 4 511#define LSFL_RCOM_WAIT 4
503#define LSFL_UEVENT_WAIT 5 512#define LSFL_UEVENT_WAIT 5
513#define LSFL_TIMEWARN 6
504 514
505/* much of this is just saving user space pointers associated with the 515/* much of this is just saving user space pointers associated with the
506 lock that we pass back to the user lib with an ast */ 516 lock that we pass back to the user lib with an ast */
diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c
index 09668ec2e279..ab986dfbe6d3 100644
--- a/fs/dlm/lock.c
+++ b/fs/dlm/lock.c
@@ -82,10 +82,13 @@ static int send_bast(struct dlm_rsb *r, struct dlm_lkb *lkb, int mode);
82static int send_lookup(struct dlm_rsb *r, struct dlm_lkb *lkb); 82static int send_lookup(struct dlm_rsb *r, struct dlm_lkb *lkb);
83static int send_remove(struct dlm_rsb *r); 83static int send_remove(struct dlm_rsb *r);
84static int _request_lock(struct dlm_rsb *r, struct dlm_lkb *lkb); 84static int _request_lock(struct dlm_rsb *r, struct dlm_lkb *lkb);
85static int _cancel_lock(struct dlm_rsb *r, struct dlm_lkb *lkb);
85static void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, 86static void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb,
86 struct dlm_message *ms); 87 struct dlm_message *ms);
87static int receive_extralen(struct dlm_message *ms); 88static int receive_extralen(struct dlm_message *ms);
88static void do_purge(struct dlm_ls *ls, int nodeid, int pid); 89static void do_purge(struct dlm_ls *ls, int nodeid, int pid);
90static void del_timeout(struct dlm_lkb *lkb);
91void dlm_timeout_warn(struct dlm_lkb *lkb);
89 92
90/* 93/*
91 * Lock compatibilty matrix - thanks Steve 94 * Lock compatibilty matrix - thanks Steve
@@ -286,8 +289,17 @@ static void queue_cast(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)
286 if (is_master_copy(lkb)) 289 if (is_master_copy(lkb))
287 return; 290 return;
288 291
292 del_timeout(lkb);
293
289 DLM_ASSERT(lkb->lkb_lksb, dlm_print_lkb(lkb);); 294 DLM_ASSERT(lkb->lkb_lksb, dlm_print_lkb(lkb););
290 295
296 /* if the operation was a cancel, then return -DLM_ECANCEL, if a
297 timeout caused the cancel then return -ETIMEDOUT */
298 if (rv == -DLM_ECANCEL && (lkb->lkb_flags & DLM_IFL_TIMEOUT_CANCEL)) {
299 lkb->lkb_flags &= ~DLM_IFL_TIMEOUT_CANCEL;
300 rv = -ETIMEDOUT;
301 }
302
291 lkb->lkb_lksb->sb_status = rv; 303 lkb->lkb_lksb->sb_status = rv;
292 lkb->lkb_lksb->sb_flags = lkb->lkb_sbflags; 304 lkb->lkb_lksb->sb_flags = lkb->lkb_sbflags;
293 305
@@ -581,6 +593,7 @@ static int create_lkb(struct dlm_ls *ls, struct dlm_lkb **lkb_ret)
581 kref_init(&lkb->lkb_ref); 593 kref_init(&lkb->lkb_ref);
582 INIT_LIST_HEAD(&lkb->lkb_ownqueue); 594 INIT_LIST_HEAD(&lkb->lkb_ownqueue);
583 INIT_LIST_HEAD(&lkb->lkb_rsb_lookup); 595 INIT_LIST_HEAD(&lkb->lkb_rsb_lookup);
596 INIT_LIST_HEAD(&lkb->lkb_time_list);
584 597
585 get_random_bytes(&bucket, sizeof(bucket)); 598 get_random_bytes(&bucket, sizeof(bucket));
586 bucket &= (ls->ls_lkbtbl_size - 1); 599 bucket &= (ls->ls_lkbtbl_size - 1);
@@ -993,6 +1006,125 @@ void dlm_scan_rsbs(struct dlm_ls *ls)
993 } 1006 }
994} 1007}
995 1008
1009static void add_timeout(struct dlm_lkb *lkb)
1010{
1011 struct dlm_ls *ls = lkb->lkb_resource->res_ls;
1012
1013 if (is_master_copy(lkb))
1014 return;
1015
1016 if (lkb->lkb_exflags & DLM_LKF_TIMEOUT)
1017 goto add_it;
1018
1019 if (test_bit(LSFL_TIMEWARN, &ls->ls_flags) &&
1020 !(lkb->lkb_exflags & DLM_LKF_NODLCKWT)) {
1021 lkb->lkb_flags |= DLM_IFL_WATCH_TIMEWARN;
1022 goto add_it;
1023 }
1024 return;
1025
1026 add_it:
1027 DLM_ASSERT(list_empty(&lkb->lkb_time_list), dlm_print_lkb(lkb););
1028 mutex_lock(&ls->ls_timeout_mutex);
1029 hold_lkb(lkb);
1030 lkb->lkb_timestamp = jiffies;
1031 list_add_tail(&lkb->lkb_time_list, &ls->ls_timeout);
1032 mutex_unlock(&ls->ls_timeout_mutex);
1033}
1034
1035static void del_timeout(struct dlm_lkb *lkb)
1036{
1037 struct dlm_ls *ls = lkb->lkb_resource->res_ls;
1038
1039 mutex_lock(&ls->ls_timeout_mutex);
1040 if (!list_empty(&lkb->lkb_time_list)) {
1041 list_del_init(&lkb->lkb_time_list);
1042 unhold_lkb(lkb);
1043 }
1044 mutex_unlock(&ls->ls_timeout_mutex);
1045}
1046
1047/* FIXME: is it safe to look at lkb_exflags, lkb_flags, lkb_timestamp, and
1048 lkb_lksb_timeout without lock_rsb? Note: we can't lock timeout_mutex
1049 and then lock rsb because of lock ordering in add_timeout. We may need
1050 to specify some special timeout-related bits in the lkb that are just to
1051 be accessed under the timeout_mutex. */
1052
1053void dlm_scan_timeout(struct dlm_ls *ls)
1054{
1055 struct dlm_rsb *r;
1056 struct dlm_lkb *lkb;
1057 int do_cancel, do_warn;
1058
1059 for (;;) {
1060 if (dlm_locking_stopped(ls))
1061 break;
1062
1063 do_cancel = 0;
1064 do_warn = 0;
1065 mutex_lock(&ls->ls_timeout_mutex);
1066 list_for_each_entry(lkb, &ls->ls_timeout, lkb_time_list) {
1067
1068 if ((lkb->lkb_exflags & DLM_LKF_TIMEOUT) &&
1069 time_after_eq(jiffies, lkb->lkb_timestamp +
1070 lkb->lkb_timeout_cs * HZ/100))
1071 do_cancel = 1;
1072
1073 if ((lkb->lkb_flags & DLM_IFL_WATCH_TIMEWARN) &&
1074 time_after_eq(jiffies, lkb->lkb_timestamp +
1075 dlm_config.ci_timewarn_cs * HZ/100))
1076 do_warn = 1;
1077
1078 if (!do_cancel && !do_warn)
1079 continue;
1080 hold_lkb(lkb);
1081 break;
1082 }
1083 mutex_unlock(&ls->ls_timeout_mutex);
1084
1085 if (!do_cancel && !do_warn)
1086 break;
1087
1088 r = lkb->lkb_resource;
1089 hold_rsb(r);
1090 lock_rsb(r);
1091
1092 if (do_warn) {
1093 /* clear flag so we only warn once */
1094 lkb->lkb_flags &= ~DLM_IFL_WATCH_TIMEWARN;
1095 if (!(lkb->lkb_exflags & DLM_LKF_TIMEOUT))
1096 del_timeout(lkb);
1097 dlm_timeout_warn(lkb);
1098 }
1099
1100 if (do_cancel) {
1101 lkb->lkb_flags &= ~DLM_IFL_WATCH_TIMEWARN;
1102 lkb->lkb_flags |= DLM_IFL_TIMEOUT_CANCEL;
1103 del_timeout(lkb);
1104 _cancel_lock(r, lkb);
1105 }
1106
1107 unlock_rsb(r);
1108 unhold_rsb(r);
1109 dlm_put_lkb(lkb);
1110 }
1111}
1112
1113/* This is only called by dlm_recoverd, and we rely on dlm_ls_stop() stopping
1114 dlm_recoverd before checking/setting ls_recover_begin. */
1115
1116void dlm_adjust_timeouts(struct dlm_ls *ls)
1117{
1118 struct dlm_lkb *lkb;
1119 long adj = jiffies - ls->ls_recover_begin;
1120
1121 ls->ls_recover_begin = 0;
1122 mutex_lock(&ls->ls_timeout_mutex);
1123 list_for_each_entry(lkb, &ls->ls_timeout, lkb_time_list)
1124 lkb->lkb_timestamp += adj;
1125 mutex_unlock(&ls->ls_timeout_mutex);
1126}
1127
996/* lkb is master or local copy */ 1128/* lkb is master or local copy */
997 1129
998static void set_lvb_lock(struct dlm_rsb *r, struct dlm_lkb *lkb) 1130static void set_lvb_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
@@ -1902,6 +2034,9 @@ static int validate_unlock_args(struct dlm_lkb *lkb, struct dlm_args *args)
1902 if (is_overlap(lkb)) 2034 if (is_overlap(lkb))
1903 goto out; 2035 goto out;
1904 2036
2037 /* don't let scand try to do a cancel */
2038 del_timeout(lkb);
2039
1905 if (lkb->lkb_flags & DLM_IFL_RESEND) { 2040 if (lkb->lkb_flags & DLM_IFL_RESEND) {
1906 lkb->lkb_flags |= DLM_IFL_OVERLAP_CANCEL; 2041 lkb->lkb_flags |= DLM_IFL_OVERLAP_CANCEL;
1907 rv = -EBUSY; 2042 rv = -EBUSY;
@@ -1933,6 +2068,9 @@ static int validate_unlock_args(struct dlm_lkb *lkb, struct dlm_args *args)
1933 if (is_overlap_unlock(lkb)) 2068 if (is_overlap_unlock(lkb))
1934 goto out; 2069 goto out;
1935 2070
2071 /* don't let scand try to do a cancel */
2072 del_timeout(lkb);
2073
1936 if (lkb->lkb_flags & DLM_IFL_RESEND) { 2074 if (lkb->lkb_flags & DLM_IFL_RESEND) {
1937 lkb->lkb_flags |= DLM_IFL_OVERLAP_UNLOCK; 2075 lkb->lkb_flags |= DLM_IFL_OVERLAP_UNLOCK;
1938 rv = -EBUSY; 2076 rv = -EBUSY;
@@ -1993,6 +2131,7 @@ static int do_request(struct dlm_rsb *r, struct dlm_lkb *lkb)
1993 error = -EINPROGRESS; 2131 error = -EINPROGRESS;
1994 add_lkb(r, lkb, DLM_LKSTS_WAITING); 2132 add_lkb(r, lkb, DLM_LKSTS_WAITING);
1995 send_blocking_asts(r, lkb); 2133 send_blocking_asts(r, lkb);
2134 add_timeout(lkb);
1996 goto out; 2135 goto out;
1997 } 2136 }
1998 2137
@@ -2040,6 +2179,7 @@ static int do_convert(struct dlm_rsb *r, struct dlm_lkb *lkb)
2040 del_lkb(r, lkb); 2179 del_lkb(r, lkb);
2041 add_lkb(r, lkb, DLM_LKSTS_CONVERT); 2180 add_lkb(r, lkb, DLM_LKSTS_CONVERT);
2042 send_blocking_asts(r, lkb); 2181 send_blocking_asts(r, lkb);
2182 add_timeout(lkb);
2043 goto out; 2183 goto out;
2044 } 2184 }
2045 2185
@@ -3110,9 +3250,10 @@ static void receive_request_reply(struct dlm_ls *ls, struct dlm_message *ms)
3110 lkb->lkb_remid = ms->m_lkid; 3250 lkb->lkb_remid = ms->m_lkid;
3111 if (is_altmode(lkb)) 3251 if (is_altmode(lkb))
3112 munge_altmode(lkb, ms); 3252 munge_altmode(lkb, ms);
3113 if (result) 3253 if (result) {
3114 add_lkb(r, lkb, DLM_LKSTS_WAITING); 3254 add_lkb(r, lkb, DLM_LKSTS_WAITING);
3115 else { 3255 add_timeout(lkb);
3256 } else {
3116 grant_lock_pc(r, lkb, ms); 3257 grant_lock_pc(r, lkb, ms);
3117 queue_cast(r, lkb, 0); 3258 queue_cast(r, lkb, 0);
3118 } 3259 }
@@ -3178,6 +3319,7 @@ static void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb,
3178 munge_demoted(lkb, ms); 3319 munge_demoted(lkb, ms);
3179 del_lkb(r, lkb); 3320 del_lkb(r, lkb);
3180 add_lkb(r, lkb, DLM_LKSTS_CONVERT); 3321 add_lkb(r, lkb, DLM_LKSTS_CONVERT);
3322 add_timeout(lkb);
3181 break; 3323 break;
3182 3324
3183 case 0: 3325 case 0:
diff --git a/fs/dlm/lock.h b/fs/dlm/lock.h
index 19403aa08739..6b5b71f0e9dd 100644
--- a/fs/dlm/lock.h
+++ b/fs/dlm/lock.h
@@ -1,7 +1,7 @@
1/****************************************************************************** 1/******************************************************************************
2******************************************************************************* 2*******************************************************************************
3** 3**
4** Copyright (C) 2005 Red Hat, Inc. All rights reserved. 4** Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved.
5** 5**
6** This copyrighted material is made available to anyone wishing to use, 6** This copyrighted material is made available to anyone wishing to use,
7** modify, copy, or redistribute it subject to the terms and conditions 7** modify, copy, or redistribute it subject to the terms and conditions
@@ -26,6 +26,8 @@ int dlm_put_lkb(struct dlm_lkb *lkb);
26void dlm_scan_rsbs(struct dlm_ls *ls); 26void dlm_scan_rsbs(struct dlm_ls *ls);
27int dlm_lock_recovery_try(struct dlm_ls *ls); 27int dlm_lock_recovery_try(struct dlm_ls *ls);
28void dlm_unlock_recovery(struct dlm_ls *ls); 28void dlm_unlock_recovery(struct dlm_ls *ls);
29void dlm_scan_timeout(struct dlm_ls *ls);
30void dlm_adjust_timeouts(struct dlm_ls *ls);
29 31
30int dlm_purge_locks(struct dlm_ls *ls); 32int dlm_purge_locks(struct dlm_ls *ls);
31void dlm_purge_mstcpy_locks(struct dlm_rsb *r); 33void dlm_purge_mstcpy_locks(struct dlm_rsb *r);
diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c
index 414a108df934..339a204d7479 100644
--- a/fs/dlm/lockspace.c
+++ b/fs/dlm/lockspace.c
@@ -237,6 +237,7 @@ static int dlm_scand(void *data)
237 list_for_each_entry(ls, &lslist, ls_list) { 237 list_for_each_entry(ls, &lslist, ls_list) {
238 if (dlm_lock_recovery_try(ls)) { 238 if (dlm_lock_recovery_try(ls)) {
239 dlm_scan_rsbs(ls); 239 dlm_scan_rsbs(ls);
240 dlm_scan_timeout(ls);
240 dlm_unlock_recovery(ls); 241 dlm_unlock_recovery(ls);
241 } 242 }
242 } 243 }
@@ -421,11 +422,16 @@ static int new_lockspace(char *name, int namelen, void **lockspace,
421 goto out; 422 goto out;
422 memcpy(ls->ls_name, name, namelen); 423 memcpy(ls->ls_name, name, namelen);
423 ls->ls_namelen = namelen; 424 ls->ls_namelen = namelen;
424 ls->ls_exflags = flags;
425 ls->ls_lvblen = lvblen; 425 ls->ls_lvblen = lvblen;
426 ls->ls_count = 0; 426 ls->ls_count = 0;
427 ls->ls_flags = 0; 427 ls->ls_flags = 0;
428 428
429 /* ls_exflags are forced to match among nodes, and we don't
430 need to require all nodes to have TIMEWARN active */
431 if (flags & DLM_LSFL_TIMEWARN)
432 set_bit(LSFL_TIMEWARN, &ls->ls_flags);
433 ls->ls_exflags = (flags & ~DLM_LSFL_TIMEWARN);
434
429 size = dlm_config.ci_rsbtbl_size; 435 size = dlm_config.ci_rsbtbl_size;
430 ls->ls_rsbtbl_size = size; 436 ls->ls_rsbtbl_size = size;
431 437
@@ -465,6 +471,8 @@ static int new_lockspace(char *name, int namelen, void **lockspace,
465 mutex_init(&ls->ls_waiters_mutex); 471 mutex_init(&ls->ls_waiters_mutex);
466 INIT_LIST_HEAD(&ls->ls_orphans); 472 INIT_LIST_HEAD(&ls->ls_orphans);
467 mutex_init(&ls->ls_orphans_mutex); 473 mutex_init(&ls->ls_orphans_mutex);
474 INIT_LIST_HEAD(&ls->ls_timeout);
475 mutex_init(&ls->ls_timeout_mutex);
468 476
469 INIT_LIST_HEAD(&ls->ls_nodes); 477 INIT_LIST_HEAD(&ls->ls_nodes);
470 INIT_LIST_HEAD(&ls->ls_nodes_gone); 478 INIT_LIST_HEAD(&ls->ls_nodes_gone);
diff --git a/fs/dlm/main.c b/fs/dlm/main.c
index 162fbae58fe5..eca2907f2386 100644
--- a/fs/dlm/main.c
+++ b/fs/dlm/main.c
@@ -2,7 +2,7 @@
2******************************************************************************* 2*******************************************************************************
3** 3**
4** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. 4** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
5** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. 5** Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
6** 6**
7** This copyrighted material is made available to anyone wishing to use, 7** This copyrighted material is made available to anyone wishing to use,
8** modify, copy, or redistribute it subject to the terms and conditions 8** modify, copy, or redistribute it subject to the terms and conditions
@@ -25,6 +25,8 @@ void dlm_unregister_debugfs(void);
25static inline int dlm_register_debugfs(void) { return 0; } 25static inline int dlm_register_debugfs(void) { return 0; }
26static inline void dlm_unregister_debugfs(void) { } 26static inline void dlm_unregister_debugfs(void) { }
27#endif 27#endif
28int dlm_netlink_init(void);
29void dlm_netlink_exit(void);
28 30
29static int __init init_dlm(void) 31static int __init init_dlm(void)
30{ 32{
@@ -50,10 +52,16 @@ static int __init init_dlm(void)
50 if (error) 52 if (error)
51 goto out_debug; 53 goto out_debug;
52 54
55 error = dlm_netlink_init();
56 if (error)
57 goto out_user;
58
53 printk("DLM (built %s %s) installed\n", __DATE__, __TIME__); 59 printk("DLM (built %s %s) installed\n", __DATE__, __TIME__);
54 60
55 return 0; 61 return 0;
56 62
63 out_user:
64 dlm_user_exit();
57 out_debug: 65 out_debug:
58 dlm_unregister_debugfs(); 66 dlm_unregister_debugfs();
59 out_config: 67 out_config:
@@ -68,6 +76,7 @@ static int __init init_dlm(void)
68 76
69static void __exit exit_dlm(void) 77static void __exit exit_dlm(void)
70{ 78{
79 dlm_netlink_exit();
71 dlm_user_exit(); 80 dlm_user_exit();
72 dlm_config_exit(); 81 dlm_config_exit();
73 dlm_memory_exit(); 82 dlm_memory_exit();
diff --git a/fs/dlm/member.c b/fs/dlm/member.c
index 85e2897bd740..f08faec3d854 100644
--- a/fs/dlm/member.c
+++ b/fs/dlm/member.c
@@ -1,7 +1,7 @@
1/****************************************************************************** 1/******************************************************************************
2******************************************************************************* 2*******************************************************************************
3** 3**
4** Copyright (C) 2005 Red Hat, Inc. All rights reserved. 4** Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved.
5** 5**
6** This copyrighted material is made available to anyone wishing to use, 6** This copyrighted material is made available to anyone wishing to use,
7** modify, copy, or redistribute it subject to the terms and conditions 7** modify, copy, or redistribute it subject to the terms and conditions
@@ -284,6 +284,9 @@ int dlm_ls_stop(struct dlm_ls *ls)
284 dlm_recoverd_suspend(ls); 284 dlm_recoverd_suspend(ls);
285 ls->ls_recover_status = 0; 285 ls->ls_recover_status = 0;
286 dlm_recoverd_resume(ls); 286 dlm_recoverd_resume(ls);
287
288 if (!ls->ls_recover_begin)
289 ls->ls_recover_begin = jiffies;
287 return 0; 290 return 0;
288} 291}
289 292
diff --git a/fs/dlm/netlink.c b/fs/dlm/netlink.c
new file mode 100644
index 000000000000..804b32cd22c1
--- /dev/null
+++ b/fs/dlm/netlink.c
@@ -0,0 +1,155 @@
1/*
2 * Copyright (C) 2007 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 v.2.
7 */
8
9#include <net/genetlink.h>
10#include <linux/dlm.h>
11#include <linux/dlm_netlink.h>
12
13#include "dlm_internal.h"
14
15static uint32_t dlm_nl_seqnum;
16static uint32_t listener_nlpid;
17
18static struct genl_family family = {
19 .id = GENL_ID_GENERATE,
20 .name = DLM_GENL_NAME,
21 .version = DLM_GENL_VERSION,
22};
23
24static int prepare_data(u8 cmd, struct sk_buff **skbp, size_t size)
25{
26 struct sk_buff *skb;
27 void *data;
28
29 skb = genlmsg_new(size, GFP_KERNEL);
30 if (!skb)
31 return -ENOMEM;
32
33 /* add the message headers */
34 data = genlmsg_put(skb, 0, dlm_nl_seqnum++, &family, 0, cmd);
35 if (!data) {
36 nlmsg_free(skb);
37 return -EINVAL;
38 }
39
40 *skbp = skb;
41 return 0;
42}
43
44static struct dlm_lock_data *mk_data(struct sk_buff *skb)
45{
46 struct nlattr *ret;
47
48 ret = nla_reserve(skb, DLM_TYPE_LOCK, sizeof(struct dlm_lock_data));
49 if (!ret)
50 return NULL;
51 return nla_data(ret);
52}
53
54static int send_data(struct sk_buff *skb)
55{
56 struct genlmsghdr *genlhdr = nlmsg_data((struct nlmsghdr *)skb->data);
57 void *data = genlmsg_data(genlhdr);
58 int rv;
59
60 rv = genlmsg_end(skb, data);
61 if (rv < 0) {
62 nlmsg_free(skb);
63 return rv;
64 }
65
66 return genlmsg_unicast(skb, listener_nlpid);
67}
68
69static int user_cmd(struct sk_buff *skb, struct genl_info *info)
70{
71 listener_nlpid = info->snd_pid;
72 printk("user_cmd nlpid %u\n", listener_nlpid);
73 return 0;
74}
75
76static struct genl_ops dlm_nl_ops = {
77 .cmd = DLM_CMD_HELLO,
78 .doit = user_cmd,
79};
80
81int dlm_netlink_init(void)
82{
83 int rv;
84
85 rv = genl_register_family(&family);
86 if (rv)
87 return rv;
88
89 rv = genl_register_ops(&family, &dlm_nl_ops);
90 if (rv < 0)
91 goto err;
92 return 0;
93 err:
94 genl_unregister_family(&family);
95 return rv;
96}
97
98void dlm_netlink_exit(void)
99{
100 genl_unregister_ops(&family, &dlm_nl_ops);
101 genl_unregister_family(&family);
102}
103
104static void fill_data(struct dlm_lock_data *data, struct dlm_lkb *lkb)
105{
106 struct dlm_rsb *r = lkb->lkb_resource;
107 struct dlm_user_args *ua = (struct dlm_user_args *) lkb->lkb_astparam;
108
109 memset(data, 0, sizeof(struct dlm_lock_data));
110
111 data->version = DLM_LOCK_DATA_VERSION;
112 data->nodeid = lkb->lkb_nodeid;
113 data->ownpid = lkb->lkb_ownpid;
114 data->id = lkb->lkb_id;
115 data->remid = lkb->lkb_remid;
116 data->status = lkb->lkb_status;
117 data->grmode = lkb->lkb_grmode;
118 data->rqmode = lkb->lkb_rqmode;
119 data->timestamp = lkb->lkb_timestamp;
120 if (ua)
121 data->xid = ua->xid;
122 if (r) {
123 data->lockspace_id = r->res_ls->ls_global_id;
124 data->resource_namelen = r->res_length;
125 memcpy(data->resource_name, r->res_name, r->res_length);
126 }
127}
128
129void dlm_timeout_warn(struct dlm_lkb *lkb)
130{
131 struct dlm_lock_data *data;
132 struct sk_buff *send_skb;
133 size_t size;
134 int rv;
135
136 log_debug(lkb->lkb_resource->res_ls, "timeout_warn %x", lkb->lkb_id);
137
138 size = nla_total_size(sizeof(struct dlm_lock_data)) +
139 nla_total_size(0); /* why this? */
140
141 rv = prepare_data(DLM_CMD_TIMEOUT, &send_skb, size);
142 if (rv < 0)
143 return;
144
145 data = mk_data(send_skb);
146 if (!data) {
147 nlmsg_free(send_skb);
148 return;
149 }
150
151 fill_data(data, lkb);
152
153 send_data(send_skb);
154}
155
diff --git a/fs/dlm/recoverd.c b/fs/dlm/recoverd.c
index 3cb636d60249..66575997861c 100644
--- a/fs/dlm/recoverd.c
+++ b/fs/dlm/recoverd.c
@@ -2,7 +2,7 @@
2******************************************************************************* 2*******************************************************************************
3** 3**
4** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. 4** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
5** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. 5** Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
6** 6**
7** This copyrighted material is made available to anyone wishing to use, 7** This copyrighted material is made available to anyone wishing to use,
8** modify, copy, or redistribute it subject to the terms and conditions 8** modify, copy, or redistribute it subject to the terms and conditions
@@ -190,6 +190,8 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
190 190
191 dlm_clear_members_gone(ls); 191 dlm_clear_members_gone(ls);
192 192
193 dlm_adjust_timeouts(ls);
194
193 error = enable_locking(ls, rv->seq); 195 error = enable_locking(ls, rv->seq);
194 if (error) { 196 if (error) {
195 log_debug(ls, "enable_locking failed %d", error); 197 log_debug(ls, "enable_locking failed %d", error);
diff --git a/fs/dlm/user.c b/fs/dlm/user.c
index b0201ec325a7..c7612da5b617 100644
--- a/fs/dlm/user.c
+++ b/fs/dlm/user.c
@@ -348,7 +348,7 @@ static int device_create_lockspace(struct dlm_lspace_params *params)
348 return -EPERM; 348 return -EPERM;
349 349
350 error = dlm_new_lockspace(params->name, strlen(params->name), 350 error = dlm_new_lockspace(params->name, strlen(params->name),
351 &lockspace, 0, DLM_USER_LVB_LEN); 351 &lockspace, params->flags, DLM_USER_LVB_LEN);
352 if (error) 352 if (error)
353 return error; 353 return error;
354 354