multipathd: fix reservation_key check
[multipath-tools/.git] / libmultipath / structs_vec.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <unistd.h>
4
5 #include "checkers.h"
6 #include "vector.h"
7 #include "defaults.h"
8 #include "debug.h"
9 #include "config.h"
10 #include "structs.h"
11 #include "structs_vec.h"
12 #include "sysfs.h"
13 #include "devmapper.h"
14 #include "dmparser.h"
15 #include "propsel.h"
16 #include "discovery.h"
17 #include "prio.h"
18 #include "configure.h"
19 #include "libdevmapper.h"
20 #include "io_err_stat.h"
21
22 /*
23  * creates or updates mpp->paths reading mpp->pg
24  */
25 int update_mpp_paths(struct multipath *mpp, vector pathvec)
26 {
27         struct pathgroup * pgp;
28         struct path * pp;
29         int i,j;
30
31         if (!mpp || !mpp->pg)
32                 return 0;
33
34         if (!mpp->paths &&
35             !(mpp->paths = vector_alloc()))
36                 return 1;
37
38         vector_foreach_slot (mpp->pg, pgp, i) {
39                 vector_foreach_slot (pgp->paths, pp, j) {
40                         if (!find_path_by_devt(mpp->paths, pp->dev_t) &&
41                             (find_path_by_devt(pathvec, pp->dev_t)) &&
42                             store_path(mpp->paths, pp))
43                                 return 1;
44                 }
45         }
46         return 0;
47 }
48
49 int adopt_paths(vector pathvec, struct multipath *mpp)
50 {
51         int i, ret;
52         struct path * pp;
53         struct config *conf;
54
55         if (!mpp)
56                 return 0;
57
58         if (update_mpp_paths(mpp, pathvec))
59                 return 1;
60
61         vector_foreach_slot (pathvec, pp, i) {
62                 if (!strncmp(mpp->wwid, pp->wwid, WWID_SIZE)) {
63                         condlog(3, "%s: ownership set to %s",
64                                 pp->dev, mpp->alias);
65                         pp->mpp = mpp;
66
67                         if (!mpp->paths && !(mpp->paths = vector_alloc()))
68                                 return 1;
69
70                         if (!find_path_by_dev(mpp->paths, pp->dev) &&
71                             store_path(mpp->paths, pp))
72                                         return 1;
73                         conf = get_multipath_config();
74                         pthread_cleanup_push(put_multipath_config, conf);
75                         ret = pathinfo(pp, conf,
76                                        DI_PRIO | DI_CHECKER);
77                         pthread_cleanup_pop(1);
78                         if (ret)
79                                 return 1;
80                 }
81         }
82         return 0;
83 }
84
85 void orphan_path(struct path *pp, const char *reason)
86 {
87         condlog(3, "%s: orphan path, %s", pp->dev, reason);
88         pp->mpp = NULL;
89         pp->dmstate = PSTATE_UNDEF;
90         pp->uid_attribute = NULL;
91         pp->getuid = NULL;
92         prio_put(&pp->prio);
93         checker_put(&pp->checker);
94         if (pp->fd >= 0)
95                 close(pp->fd);
96         pp->fd = -1;
97 }
98
99 void orphan_paths(vector pathvec, struct multipath *mpp)
100 {
101         int i;
102         struct path * pp;
103
104         vector_foreach_slot (pathvec, pp, i) {
105                 if (pp->mpp == mpp) {
106                         orphan_path(pp, "map flushed");
107                 }
108         }
109 }
110
111 void
112 remove_map(struct multipath * mpp, struct vectors * vecs, int purge_vec)
113 {
114         int i;
115
116         condlog(4, "%s: remove multipath map", mpp->alias);
117
118         /*
119          * clear references to this map
120          */
121         orphan_paths(vecs->pathvec, mpp);
122
123         if (purge_vec &&
124             (i = find_slot(vecs->mpvec, (void *)mpp)) != -1)
125                 vector_del_slot(vecs->mpvec, i);
126
127         /*
128          * final free
129          */
130         free_multipath(mpp, KEEP_PATHS);
131 }
132
133 void
134 remove_map_by_alias(const char *alias, struct vectors * vecs, int purge_vec)
135 {
136         struct multipath * mpp = find_mp_by_alias(vecs->mpvec, alias);
137         if (mpp)
138                 remove_map(mpp, vecs, purge_vec);
139 }
140
141 void
142 remove_maps(struct vectors * vecs)
143 {
144         int i;
145         struct multipath * mpp;
146
147         if (!vecs)
148                 return;
149
150         vector_foreach_slot (vecs->mpvec, mpp, i) {
151                 remove_map(mpp, vecs, 1);
152                 i--;
153         }
154
155         vector_free(vecs->mpvec);
156         vecs->mpvec = NULL;
157 }
158
159 void
160 extract_hwe_from_path(struct multipath * mpp)
161 {
162         struct path * pp = NULL;
163         int i;
164
165         if (mpp->hwe || !mpp->paths)
166                 return;
167
168         condlog(3, "%s: searching paths for valid hwe", mpp->alias);
169         /* doing this in two passes seems like paranoia to me */
170         vector_foreach_slot(mpp->paths, pp, i) {
171                 if (pp->state != PATH_UP)
172                         continue;
173                 if (pp->hwe) {
174                         mpp->hwe = pp->hwe;
175                         return;
176                 }
177         }
178         vector_foreach_slot(mpp->paths, pp, i) {
179                 if (pp->state == PATH_UP)
180                         continue;
181                 if (pp->hwe) {
182                         mpp->hwe = pp->hwe;
183                         return;
184                 }
185         }
186 }
187
188 int
189 update_multipath_table (struct multipath *mpp, vector pathvec, int is_daemon)
190 {
191         char params[PARAMS_SIZE] = {0};
192
193         if (!mpp)
194                 return 1;
195
196         if (dm_get_map(mpp->alias, &mpp->size, params)) {
197                 condlog(3, "%s: cannot get map", mpp->alias);
198                 return 1;
199         }
200
201         if (disassemble_map(pathvec, params, mpp, is_daemon)) {
202                 condlog(3, "%s: cannot disassemble map", mpp->alias);
203                 return 1;
204         }
205
206         return 0;
207 }
208
209 int
210 update_multipath_status (struct multipath *mpp)
211 {
212         char status[PARAMS_SIZE] = {0};
213
214         if (!mpp)
215                 return 1;
216
217         if (dm_get_status(mpp->alias, status)) {
218                 condlog(3, "%s: cannot get status", mpp->alias);
219                 return 1;
220         }
221
222         if (disassemble_status(status, mpp)) {
223                 condlog(3, "%s: cannot disassemble status", mpp->alias);
224                 return 1;
225         }
226
227         return 0;
228 }
229
230 void sync_paths(struct multipath *mpp, vector pathvec)
231 {
232         struct path *pp;
233         struct pathgroup  *pgp;
234         int found, i, j;
235
236         vector_foreach_slot (mpp->paths, pp, i) {
237                 found = 0;
238                 vector_foreach_slot(mpp->pg, pgp, j) {
239                         if (find_slot(pgp->paths, (void *)pp) != -1) {
240                                 found = 1;
241                                 break;
242                         }
243                 }
244                 if (!found) {
245                         condlog(3, "%s dropped path %s", mpp->alias, pp->dev);
246                         vector_del_slot(mpp->paths, i--);
247                         orphan_path(pp, "path removed externally");
248                 }
249         }
250         update_mpp_paths(mpp, pathvec);
251         vector_foreach_slot (mpp->paths, pp, i)
252                 pp->mpp = mpp;
253 }
254
255 int
256 update_multipath_strings(struct multipath *mpp, vector pathvec, int is_daemon)
257 {
258         if (!mpp)
259                 return 1;
260
261         update_mpp_paths(mpp, pathvec);
262         condlog(4, "%s: %s", mpp->alias, __FUNCTION__);
263
264         free_multipath_attributes(mpp);
265         free_pgvec(mpp->pg, KEEP_PATHS);
266         mpp->pg = NULL;
267
268         if (update_multipath_table(mpp, pathvec, is_daemon))
269                 return 1;
270         sync_paths(mpp, pathvec);
271
272         if (update_multipath_status(mpp))
273                 return 1;
274
275         return 0;
276 }
277
278 void enter_recovery_mode(struct multipath *mpp)
279 {
280         int checkint;
281         struct config *conf = get_multipath_config();
282         checkint = conf->checkint;
283         put_multipath_config(conf);
284
285         /*
286          * Enter retry mode.
287          * meaning of +1: retry_tick may be decremented in checkerloop before
288          * starting retry.
289          */
290         mpp->stat_queueing_timeouts++;
291         mpp->retry_tick = mpp->no_path_retry * checkint + 1;
292         condlog(1, "%s: Entering recovery mode: max_retries=%d",
293                 mpp->alias, mpp->no_path_retry);
294 }
295
296 void
297 sync_map_state(struct multipath *mpp)
298 {
299         struct pathgroup *pgp;
300         struct path *pp;
301         unsigned int i, j;
302
303         if (!mpp->pg)
304                 return;
305
306         vector_foreach_slot (mpp->pg, pgp, i){
307                 vector_foreach_slot (pgp->paths, pp, j){
308                         if (pp->state == PATH_UNCHECKED ||
309                             pp->state == PATH_WILD ||
310                             pp->state == PATH_DELAYED)
311                                 continue;
312                         if (mpp->ghost_delay_tick > 0)
313                                 continue;
314                         if ((pp->dmstate == PSTATE_FAILED ||
315                              pp->dmstate == PSTATE_UNDEF) &&
316                             (pp->state == PATH_UP || pp->state == PATH_GHOST))
317                                 dm_reinstate_path(mpp->alias, pp->dev_t);
318                         else if ((pp->dmstate == PSTATE_ACTIVE ||
319                                   pp->dmstate == PSTATE_UNDEF) &&
320                                  (pp->state == PATH_DOWN ||
321                                   pp->state == PATH_SHAKY))
322                                 dm_fail_path(mpp->alias, pp->dev_t);
323                 }
324         }
325 }
326
327 static void
328 find_existing_alias (struct multipath * mpp,
329                      struct vectors *vecs)
330 {
331         struct multipath * mp;
332         int i;
333
334         vector_foreach_slot (vecs->mpvec, mp, i)
335                 if (strncmp(mp->wwid, mpp->wwid, WWID_SIZE - 1) == 0) {
336                         strncpy(mpp->alias_old, mp->alias, WWID_SIZE - 1);
337                         return;
338                 }
339 }
340
341 struct multipath *add_map_with_path(struct vectors *vecs, struct path *pp,
342                                     int add_vec)
343 {
344         struct multipath * mpp;
345         struct config *conf = NULL;
346
347         if (!strlen(pp->wwid))
348                 return NULL;
349
350         if (!(mpp = alloc_multipath()))
351                 return NULL;
352
353         conf = get_multipath_config();
354         mpp->mpe = find_mpe(conf->mptable, pp->wwid);
355         mpp->hwe = pp->hwe;
356         put_multipath_config(conf);
357
358         strcpy(mpp->wwid, pp->wwid);
359         find_existing_alias(mpp, vecs);
360         if (select_alias(conf, mpp))
361                 goto out;
362         mpp->size = pp->size;
363
364         if (adopt_paths(vecs->pathvec, mpp))
365                 goto out;
366
367         if (add_vec) {
368                 if (!vector_alloc_slot(vecs->mpvec))
369                         goto out;
370
371                 vector_set_slot(vecs->mpvec, mpp);
372         }
373
374         return mpp;
375
376 out:
377         remove_map(mpp, vecs, PURGE_VEC);
378         return NULL;
379 }
380
381 int verify_paths(struct multipath *mpp, struct vectors *vecs)
382 {
383         struct path * pp;
384         int count = 0;
385         int i, j;
386
387         if (!mpp)
388                 return 0;
389
390         vector_foreach_slot (mpp->paths, pp, i) {
391                 /*
392                  * see if path is in sysfs
393                  */
394                 if (sysfs_attr_get_value(pp->udev, "dev",
395                                          pp->dev_t, BLK_DEV_SIZE) < 0) {
396                         if (pp->state != PATH_DOWN) {
397                                 condlog(1, "%s: removing valid path %s in state %d",
398                                         mpp->alias, pp->dev, pp->state);
399                         } else {
400                                 condlog(3, "%s: failed to access path %s",
401                                         mpp->alias, pp->dev);
402                         }
403                         count++;
404                         vector_del_slot(mpp->paths, i);
405                         i--;
406
407                         if ((j = find_slot(vecs->pathvec,
408                                            (void *)pp)) != -1)
409                                 vector_del_slot(vecs->pathvec, j);
410                         free_path(pp);
411                 } else {
412                         condlog(4, "%s: verified path %s dev_t %s",
413                                 mpp->alias, pp->dev, pp->dev_t);
414                 }
415         }
416         return count;
417 }
418
419 /*
420  * mpp->no_path_retry:
421  *   -2 (QUEUE) : queue_if_no_path enabled, never turned off
422  *   -1 (FAIL)  : fail_if_no_path
423  *    0 (UNDEF) : nothing
424  *   >0         : queue_if_no_path enabled, turned off after polling n times
425  */
426 void update_queue_mode_del_path(struct multipath *mpp)
427 {
428         if (--mpp->nr_active == 0) {
429                 if (mpp->no_path_retry > 0)
430                         enter_recovery_mode(mpp);
431                 else if (mpp->no_path_retry != NO_PATH_RETRY_QUEUE)
432                         mpp->stat_map_failures++;
433         }
434         condlog(2, "%s: remaining active paths: %d", mpp->alias, mpp->nr_active);
435 }
436
437 void update_queue_mode_add_path(struct multipath *mpp)
438 {
439         if (mpp->nr_active++ == 0 && mpp->no_path_retry > 0) {
440                 /* come back to normal mode from retry mode */
441                 mpp->retry_tick = 0;
442                 dm_queue_if_no_path(mpp->alias, 1);
443                 condlog(2, "%s: queue_if_no_path enabled", mpp->alias);
444                 condlog(1, "%s: Recovered to normal mode", mpp->alias);
445         }
446         condlog(2, "%s: remaining active paths: %d", mpp->alias, mpp->nr_active);
447 }