diff options
author | David Teigland <teigland@redhat.com> | 2006-10-31 12:55:56 -0500 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2006-11-30 10:35:10 -0500 |
commit | d4400156d415540086c34a06e5d233122d6bf56a (patch) | |
tree | 747e4d270fb453d57926d6b6cab564664d9d2c0f /fs | |
parent | 435618b75b82b5ee511cc01fcdda9c44adb2f4bd (diff) |
[DLM] fix requestqueue race
Red Hat BZ 211914
There's a race between dlm_recoverd (1) enabling locking and (2) clearing
out the requestqueue, and dlm_recvd (1) checking if locking is enabled and
(2) adding a message to the requestqueue. An order of recoverd(1),
recvd(1), recvd(2), recoverd(2) will result in a message being left on the
requestqueue. The fix is to have dlm_recvd check if dlm_recoverd has
enabled locking after taking the mutex for the requestqueue and if it has
processing the message instead of queueing it.
Signed-off-by: David Teigland <teigland@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/dlm/lock.c | 15 | ||||
-rw-r--r-- | fs/dlm/requestqueue.c | 21 | ||||
-rw-r--r-- | fs/dlm/requestqueue.h | 2 |
3 files changed, 29 insertions, 9 deletions
diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index 3f2befa4797b..6088a16926bf 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c | |||
@@ -3028,10 +3028,17 @@ int dlm_receive_message(struct dlm_header *hd, int nodeid, int recovery) | |||
3028 | 3028 | ||
3029 | while (1) { | 3029 | while (1) { |
3030 | if (dlm_locking_stopped(ls)) { | 3030 | if (dlm_locking_stopped(ls)) { |
3031 | if (!recovery) | 3031 | if (recovery) { |
3032 | dlm_add_requestqueue(ls, nodeid, hd); | 3032 | error = -EINTR; |
3033 | error = -EINTR; | 3033 | goto out; |
3034 | goto out; | 3034 | } |
3035 | error = dlm_add_requestqueue(ls, nodeid, hd); | ||
3036 | if (error == -EAGAIN) | ||
3037 | continue; | ||
3038 | else { | ||
3039 | error = -EINTR; | ||
3040 | goto out; | ||
3041 | } | ||
3035 | } | 3042 | } |
3036 | 3043 | ||
3037 | if (lock_recovery_try(ls)) | 3044 | if (lock_recovery_try(ls)) |
diff --git a/fs/dlm/requestqueue.c b/fs/dlm/requestqueue.c index 7b2b089634a2..0226d2a0a0fa 100644 --- a/fs/dlm/requestqueue.c +++ b/fs/dlm/requestqueue.c | |||
@@ -30,26 +30,39 @@ struct rq_entry { | |||
30 | * lockspace is enabled on some while still suspended on others. | 30 | * lockspace is enabled on some while still suspended on others. |
31 | */ | 31 | */ |
32 | 32 | ||
33 | void dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd) | 33 | int dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd) |
34 | { | 34 | { |
35 | struct rq_entry *e; | 35 | struct rq_entry *e; |
36 | int length = hd->h_length; | 36 | int length = hd->h_length; |
37 | int rv = 0; | ||
37 | 38 | ||
38 | if (dlm_is_removed(ls, nodeid)) | 39 | if (dlm_is_removed(ls, nodeid)) |
39 | return; | 40 | return 0; |
40 | 41 | ||
41 | e = kmalloc(sizeof(struct rq_entry) + length, GFP_KERNEL); | 42 | e = kmalloc(sizeof(struct rq_entry) + length, GFP_KERNEL); |
42 | if (!e) { | 43 | if (!e) { |
43 | log_print("dlm_add_requestqueue: out of memory\n"); | 44 | log_print("dlm_add_requestqueue: out of memory\n"); |
44 | return; | 45 | return 0; |
45 | } | 46 | } |
46 | 47 | ||
47 | e->nodeid = nodeid; | 48 | e->nodeid = nodeid; |
48 | memcpy(e->request, hd, length); | 49 | memcpy(e->request, hd, length); |
49 | 50 | ||
51 | /* 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 | |||
50 | mutex_lock(&ls->ls_requestqueue_mutex); | 56 | mutex_lock(&ls->ls_requestqueue_mutex); |
51 | list_add_tail(&e->list, &ls->ls_requestqueue); | 57 | 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 | } | ||
52 | mutex_unlock(&ls->ls_requestqueue_mutex); | 64 | mutex_unlock(&ls->ls_requestqueue_mutex); |
65 | return rv; | ||
53 | } | 66 | } |
54 | 67 | ||
55 | int dlm_process_requestqueue(struct dlm_ls *ls) | 68 | int dlm_process_requestqueue(struct dlm_ls *ls) |
diff --git a/fs/dlm/requestqueue.h b/fs/dlm/requestqueue.h index 349f0d292d95..6a53ea03335d 100644 --- a/fs/dlm/requestqueue.h +++ b/fs/dlm/requestqueue.h | |||
@@ -13,7 +13,7 @@ | |||
13 | #ifndef __REQUESTQUEUE_DOT_H__ | 13 | #ifndef __REQUESTQUEUE_DOT_H__ |
14 | #define __REQUESTQUEUE_DOT_H__ | 14 | #define __REQUESTQUEUE_DOT_H__ |
15 | 15 | ||
16 | void dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd); | 16 | int dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd); |
17 | int dlm_process_requestqueue(struct dlm_ls *ls); | 17 | int dlm_process_requestqueue(struct dlm_ls *ls); |
18 | void dlm_wait_requestqueue(struct dlm_ls *ls); | 18 | void dlm_wait_requestqueue(struct dlm_ls *ls); |
19 | void dlm_purge_requestqueue(struct dlm_ls *ls); | 19 | void dlm_purge_requestqueue(struct dlm_ls *ls); |