blob: 0226d2a0a0faf8107fa5dcbc912c971545bd1048 [file] [log] [blame]
David Teiglande7fd4172006-01-18 09:30:29 +00001/******************************************************************************
2*******************************************************************************
3**
4** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
5**
6** This copyrighted material is made available to anyone wishing to use,
7** modify, copy, or redistribute it subject to the terms and conditions
8** of the GNU General Public License v.2.
9**
10*******************************************************************************
11******************************************************************************/
12
13#include "dlm_internal.h"
14#include "member.h"
15#include "lock.h"
16#include "dir.h"
17#include "config.h"
18#include "requestqueue.h"
19
20struct rq_entry {
21 struct list_head list;
22 int nodeid;
23 char request[1];
24};
25
26/*
27 * Requests received while the lockspace is in recovery get added to the
28 * request queue and processed when recovery is complete. This happens when
29 * the lockspace is suspended on some nodes before it is on others, or the
30 * lockspace is enabled on some while still suspended on others.
31 */
32
David Teiglandd4400152006-10-31 11:55:56 -060033int dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd)
David Teiglande7fd4172006-01-18 09:30:29 +000034{
35 struct rq_entry *e;
36 int length = hd->h_length;
David Teiglandd4400152006-10-31 11:55:56 -060037 int rv = 0;
David Teiglande7fd4172006-01-18 09:30:29 +000038
39 if (dlm_is_removed(ls, nodeid))
David Teiglandd4400152006-10-31 11:55:56 -060040 return 0;
David Teiglande7fd4172006-01-18 09:30:29 +000041
42 e = kmalloc(sizeof(struct rq_entry) + length, GFP_KERNEL);
43 if (!e) {
44 log_print("dlm_add_requestqueue: out of memory\n");
David Teiglandd4400152006-10-31 11:55:56 -060045 return 0;
David Teiglande7fd4172006-01-18 09:30:29 +000046 }
47
48 e->nodeid = nodeid;
49 memcpy(e->request, hd, length);
50
David Teiglandd4400152006-10-31 11:55:56 -060051 /* We need to check dlm_locking_stopped() after taking the mutex to
52 avoid a race where dlm_recoverd enables locking and runs
53 process_requestqueue between our earlier dlm_locking_stopped check
54 and this addition to the requestqueue. */
55
David Teigland90135922006-01-20 08:47:07 +000056 mutex_lock(&ls->ls_requestqueue_mutex);
David Teiglandd4400152006-10-31 11:55:56 -060057 if (dlm_locking_stopped(ls))
58 list_add_tail(&e->list, &ls->ls_requestqueue);
59 else {
60 log_debug(ls, "dlm_add_requestqueue skip from %d", nodeid);
61 kfree(e);
62 rv = -EAGAIN;
63 }
David Teigland90135922006-01-20 08:47:07 +000064 mutex_unlock(&ls->ls_requestqueue_mutex);
David Teiglandd4400152006-10-31 11:55:56 -060065 return rv;
David Teiglande7fd4172006-01-18 09:30:29 +000066}
67
68int dlm_process_requestqueue(struct dlm_ls *ls)
69{
70 struct rq_entry *e;
71 struct dlm_header *hd;
72 int error = 0;
73
David Teigland90135922006-01-20 08:47:07 +000074 mutex_lock(&ls->ls_requestqueue_mutex);
David Teiglande7fd4172006-01-18 09:30:29 +000075
76 for (;;) {
77 if (list_empty(&ls->ls_requestqueue)) {
David Teigland90135922006-01-20 08:47:07 +000078 mutex_unlock(&ls->ls_requestqueue_mutex);
David Teiglande7fd4172006-01-18 09:30:29 +000079 error = 0;
80 break;
81 }
82 e = list_entry(ls->ls_requestqueue.next, struct rq_entry, list);
David Teigland90135922006-01-20 08:47:07 +000083 mutex_unlock(&ls->ls_requestqueue_mutex);
David Teiglande7fd4172006-01-18 09:30:29 +000084
85 hd = (struct dlm_header *) e->request;
David Teigland90135922006-01-20 08:47:07 +000086 error = dlm_receive_message(hd, e->nodeid, 1);
David Teiglande7fd4172006-01-18 09:30:29 +000087
88 if (error == -EINTR) {
89 /* entry is left on requestqueue */
90 log_debug(ls, "process_requestqueue abort eintr");
91 break;
92 }
93
David Teigland90135922006-01-20 08:47:07 +000094 mutex_lock(&ls->ls_requestqueue_mutex);
David Teiglande7fd4172006-01-18 09:30:29 +000095 list_del(&e->list);
96 kfree(e);
97
98 if (dlm_locking_stopped(ls)) {
99 log_debug(ls, "process_requestqueue abort running");
David Teigland90135922006-01-20 08:47:07 +0000100 mutex_unlock(&ls->ls_requestqueue_mutex);
David Teiglande7fd4172006-01-18 09:30:29 +0000101 error = -EINTR;
102 break;
103 }
104 schedule();
105 }
106
107 return error;
108}
109
110/*
111 * After recovery is done, locking is resumed and dlm_recoverd takes all the
112 * saved requests and processes them as they would have been by dlm_recvd. At
113 * the same time, dlm_recvd will start receiving new requests from remote
114 * nodes. We want to delay dlm_recvd processing new requests until
115 * dlm_recoverd has finished processing the old saved requests.
116 */
117
118void dlm_wait_requestqueue(struct dlm_ls *ls)
119{
120 for (;;) {
David Teigland90135922006-01-20 08:47:07 +0000121 mutex_lock(&ls->ls_requestqueue_mutex);
David Teiglande7fd4172006-01-18 09:30:29 +0000122 if (list_empty(&ls->ls_requestqueue))
123 break;
124 if (dlm_locking_stopped(ls))
125 break;
David Teigland90135922006-01-20 08:47:07 +0000126 mutex_unlock(&ls->ls_requestqueue_mutex);
David Teiglande7fd4172006-01-18 09:30:29 +0000127 schedule();
128 }
David Teigland90135922006-01-20 08:47:07 +0000129 mutex_unlock(&ls->ls_requestqueue_mutex);
David Teiglande7fd4172006-01-18 09:30:29 +0000130}
131
132static int purge_request(struct dlm_ls *ls, struct dlm_message *ms, int nodeid)
133{
134 uint32_t type = ms->m_type;
135
136 if (dlm_is_removed(ls, nodeid))
137 return 1;
138
139 /* directory operations are always purged because the directory is
140 always rebuilt during recovery and the lookups resent */
141
142 if (type == DLM_MSG_REMOVE ||
143 type == DLM_MSG_LOOKUP ||
144 type == DLM_MSG_LOOKUP_REPLY)
145 return 1;
146
147 if (!dlm_no_directory(ls))
148 return 0;
149
150 /* with no directory, the master is likely to change as a part of
151 recovery; requests to/from the defunct master need to be purged */
152
153 switch (type) {
154 case DLM_MSG_REQUEST:
155 case DLM_MSG_CONVERT:
156 case DLM_MSG_UNLOCK:
157 case DLM_MSG_CANCEL:
158 /* we're no longer the master of this resource, the sender
159 will resend to the new master (see waiter_needs_recovery) */
160
161 if (dlm_hash2nodeid(ls, ms->m_hash) != dlm_our_nodeid())
162 return 1;
163 break;
164
165 case DLM_MSG_REQUEST_REPLY:
166 case DLM_MSG_CONVERT_REPLY:
167 case DLM_MSG_UNLOCK_REPLY:
168 case DLM_MSG_CANCEL_REPLY:
169 case DLM_MSG_GRANT:
170 /* this reply is from the former master of the resource,
171 we'll resend to the new master if needed */
172
173 if (dlm_hash2nodeid(ls, ms->m_hash) != nodeid)
174 return 1;
175 break;
176 }
177
178 return 0;
179}
180
181void dlm_purge_requestqueue(struct dlm_ls *ls)
182{
183 struct dlm_message *ms;
184 struct rq_entry *e, *safe;
185
David Teigland90135922006-01-20 08:47:07 +0000186 mutex_lock(&ls->ls_requestqueue_mutex);
David Teiglande7fd4172006-01-18 09:30:29 +0000187 list_for_each_entry_safe(e, safe, &ls->ls_requestqueue, list) {
188 ms = (struct dlm_message *) e->request;
189
190 if (purge_request(ls, ms, e->nodeid)) {
191 list_del(&e->list);
192 kfree(e);
193 }
194 }
David Teigland90135922006-01-20 08:47:07 +0000195 mutex_unlock(&ls->ls_requestqueue_mutex);
David Teiglande7fd4172006-01-18 09:30:29 +0000196}
197