~cyphermox/ubuntu/trusty/multipath-tools/usb+local

« back to all changes in this revision

Viewing changes to .pc/0011-libmultipath-update-waiter-handling.patch/libmultipath/waiter.c

  • Committer: Package Import Robot
  • Author(s): Rafael David Tinoco
  • Date: 2014-08-07 16:15:25 UTC
  • Revision ID: package-import@ubuntu.com-20140807161525-whfb9ggygzcwuawa
Tags: 0.4.9-3ubuntu7.1
* Added 0011-libmultipath-update-waiter-handling.patch (LP: #1354114)
* Added 0012-Race-condition-when-calling-stop_waiter_thread.patch (LP: #1354114)
* Added 0013-multipath-clean-up-code-for-stopping-the-waiter-thre.patch (LP: #1354114)
* Added 0014-Fix-race-condition-in-stop_waiter_thread.patch (LP: #1354114)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2004, 2005 Christophe Varoqui
 
3
 * Copyright (c) 2005 Kiyoshi Ueda, NEC
 
4
 * Copyright (c) 2005 Benjamin Marzinski, Redhat
 
5
 * Copyright (c) 2005 Edward Goggin, EMC
 
6
 */
 
7
#include <unistd.h>
 
8
#include <libdevmapper.h>
 
9
#include <sys/mman.h>
 
10
#include <pthread.h>
 
11
#include <signal.h>
 
12
 
 
13
#include "vector.h"
 
14
#include "memory.h"
 
15
#include "checkers.h"
 
16
#include "structs.h"
 
17
#include "structs_vec.h"
 
18
#include "devmapper.h"
 
19
#include "debug.h"
 
20
#include "lock.h"
 
21
#include "waiter.h"
 
22
 
 
23
pthread_attr_t waiter_attr;
 
24
 
 
25
struct event_thread *alloc_waiter (void)
 
26
{
 
27
 
 
28
        struct event_thread *wp;
 
29
 
 
30
        wp = (struct event_thread *)MALLOC(sizeof(struct event_thread));
 
31
 
 
32
        return wp;
 
33
}
 
34
 
 
35
void free_waiter (void *data)
 
36
{
 
37
        sigset_t old;
 
38
        struct event_thread *wp = (struct event_thread *)data;
 
39
 
 
40
        /*
 
41
         * indicate in mpp that the wp is already freed storage
 
42
         */
 
43
        block_signal(SIGHUP, &old);
 
44
        lock(wp->vecs->lock);
 
45
 
 
46
        if (wp->mpp)
 
47
                /*
 
48
                 * be careful, mpp may already be freed -- null if so
 
49
                 */
 
50
                wp->mpp->waiter = NULL;
 
51
        else
 
52
                /*
 
53
                * This is OK condition during shutdown.
 
54
                */
 
55
                condlog(3, "free_waiter, mpp freed before wp=%p (%s).", wp, wp->mapname);
 
56
 
 
57
        unlock(wp->vecs->lock);
 
58
        pthread_sigmask(SIG_SETMASK, &old, NULL);
 
59
 
 
60
        if (wp->dmt)
 
61
                dm_task_destroy(wp->dmt);
 
62
 
 
63
        FREE(wp);
 
64
}
 
65
 
 
66
void stop_waiter_thread (struct multipath *mpp, struct vectors *vecs)
 
67
{
 
68
        struct event_thread *wp = (struct event_thread *)mpp->waiter;
 
69
        pthread_t thread;
 
70
 
 
71
        if (!wp) {
 
72
                condlog(3, "%s: no waiter thread", mpp->alias);
 
73
                return;
 
74
        }
 
75
        thread = wp->thread;
 
76
        condlog(2, "%s: stop event checker thread (%lu)", wp->mapname, thread);
 
77
 
 
78
        pthread_kill(thread, SIGUSR1);
 
79
}
 
80
 
 
81
static sigset_t unblock_signals(void)
 
82
{
 
83
        sigset_t set, old;
 
84
 
 
85
        sigemptyset(&set);
 
86
        sigaddset(&set, SIGHUP);
 
87
        sigaddset(&set, SIGUSR1);
 
88
        pthread_sigmask(SIG_UNBLOCK, &set, &old);
 
89
        return old;
 
90
}
 
91
 
 
92
/*
 
93
 * returns the reschedule delay
 
94
 * negative means *stop*
 
95
 */
 
96
int waiteventloop (struct event_thread *waiter)
 
97
{
 
98
        sigset_t set;
 
99
        int event_nr;
 
100
        int r;
 
101
 
 
102
        if (!waiter->event_nr)
 
103
                waiter->event_nr = dm_geteventnr(waiter->mapname);
 
104
 
 
105
        if (!(waiter->dmt = dm_task_create(DM_DEVICE_WAITEVENT))) {
 
106
                condlog(0, "%s: devmap event #%i dm_task_create error",
 
107
                                waiter->mapname, waiter->event_nr);
 
108
                return 1;
 
109
        }
 
110
 
 
111
        if (!dm_task_set_name(waiter->dmt, waiter->mapname)) {
 
112
                condlog(0, "%s: devmap event #%i dm_task_set_name error",
 
113
                                waiter->mapname, waiter->event_nr);
 
114
                dm_task_destroy(waiter->dmt);
 
115
                return 1;
 
116
        }
 
117
 
 
118
        if (waiter->event_nr && !dm_task_set_event_nr(waiter->dmt,
 
119
                                                      waiter->event_nr)) {
 
120
                condlog(0, "%s: devmap event #%i dm_task_set_event_nr error",
 
121
                                waiter->mapname, waiter->event_nr);
 
122
                dm_task_destroy(waiter->dmt);
 
123
                return 1;
 
124
        }
 
125
 
 
126
        dm_task_no_open_count(waiter->dmt);
 
127
 
 
128
        /* accept wait interruption */
 
129
        set = unblock_signals();
 
130
 
 
131
        /* wait */
 
132
        r = dm_task_run(waiter->dmt);
 
133
 
 
134
        /* wait is over : event or interrupt */
 
135
        pthread_sigmask(SIG_SETMASK, &set, NULL);
 
136
 
 
137
        if (!r) /* wait interrupted by signal */
 
138
                return -1;
 
139
 
 
140
        dm_task_destroy(waiter->dmt);
 
141
        waiter->dmt = NULL;
 
142
        waiter->event_nr++;
 
143
 
 
144
        /*
 
145
         * upon event ...
 
146
         */
 
147
        while (1) {
 
148
                condlog(3, "%s: devmap event #%i",
 
149
                                waiter->mapname, waiter->event_nr);
 
150
 
 
151
                /*
 
152
                 * event might be :
 
153
                 *
 
154
                 * 1) a table reload, which means our mpp structure is
 
155
                 *    obsolete : refresh it through update_multipath()
 
156
                 * 2) a path failed by DM : mark as such through
 
157
                 *    update_multipath()
 
158
                 * 3) map has gone away : stop the thread.
 
159
                 * 4) a path reinstate : nothing to do
 
160
                 * 5) a switch group : nothing to do
 
161
                 */
 
162
                pthread_cleanup_push(cleanup_lock, &waiter->vecs->lock);
 
163
                lock(waiter->vecs->lock);
 
164
                r = update_multipath(waiter->vecs, waiter->mapname);
 
165
                lock_cleanup_pop(waiter->vecs->lock);
 
166
 
 
167
                if (r) {
 
168
                        condlog(2, "%s: event checker exit",
 
169
                                waiter->mapname);
 
170
                        return -1; /* stop the thread */
 
171
                }
 
172
 
 
173
                event_nr = dm_geteventnr(waiter->mapname);
 
174
 
 
175
                if (waiter->event_nr == event_nr)
 
176
                        return 1; /* upon problem reschedule 1s later */
 
177
 
 
178
                waiter->event_nr = event_nr;
 
179
        }
 
180
        return -1; /* never reach there */
 
181
}
 
182
 
 
183
void *waitevent (void *et)
 
184
{
 
185
        int r;
 
186
        struct event_thread *waiter;
 
187
 
 
188
        mlockall(MCL_CURRENT | MCL_FUTURE);
 
189
 
 
190
        waiter = (struct event_thread *)et;
 
191
        pthread_cleanup_push(free_waiter, et);
 
192
 
 
193
        block_signal(SIGUSR1, NULL);
 
194
        block_signal(SIGHUP, NULL);
 
195
        while (1) {
 
196
                r = waiteventloop(waiter);
 
197
 
 
198
                if (r < 0)
 
199
                        break;
 
200
 
 
201
                sleep(r);
 
202
        }
 
203
 
 
204
        pthread_cleanup_pop(1);
 
205
        return NULL;
 
206
}
 
207
 
 
208
int start_waiter_thread (struct multipath *mpp, struct vectors *vecs)
 
209
{
 
210
        struct event_thread *wp;
 
211
 
 
212
        if (!mpp)
 
213
                return 0;
 
214
 
 
215
        wp = alloc_waiter();
 
216
 
 
217
        if (!wp)
 
218
                goto out;
 
219
 
 
220
        mpp->waiter = (void *)wp;
 
221
        strncpy(wp->mapname, mpp->alias, WWID_SIZE);
 
222
        wp->vecs = vecs;
 
223
        wp->mpp = mpp;
 
224
 
 
225
        if (pthread_create(&wp->thread, &waiter_attr, waitevent, wp)) {
 
226
                condlog(0, "%s: cannot create event checker", wp->mapname);
 
227
                goto out1;
 
228
        }
 
229
        condlog(2, "%s: event checker started", wp->mapname);
 
230
 
 
231
        return 0;
 
232
out1:
 
233
        free_waiter(wp);
 
234
        mpp->waiter = NULL;
 
235
out:
 
236
        condlog(0, "failed to start waiter thread");
 
237
        return 1;
 
238
}
 
239