Remove DAEMON defines
[platform/upstream/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 "structs.h"
10 #include "structs_vec.h"
11 #include "waiter.h"
12 #include "devmapper.h"
13 #include "dmparser.h"
14 #include "config.h"
15 #include "propsel.h"
16 #include "sysfs.h"
17 #include "discovery.h"
18 #include "prio.h"
19
20 /*
21  * creates or updates mpp->paths reading mpp->pg
22  */
23 extern int
24 update_mpp_paths(struct multipath * mpp, vector pathvec)
25 {
26         struct pathgroup * pgp;
27         struct path * pp;
28         int i,j;
29
30         if (!mpp->pg)
31                 return 0;
32
33         if (!mpp->paths &&
34             !(mpp->paths = vector_alloc()))
35                 return 1;
36
37         vector_foreach_slot (mpp->pg, pgp, i) {
38                 vector_foreach_slot (pgp->paths, pp, j) {
39                         if (!find_path_by_devt(mpp->paths, pp->dev_t) &&
40                             (find_path_by_devt(pathvec, pp->dev_t)) &&
41                             store_path(mpp->paths, pp))
42                                 return 1;
43                 }
44         }
45         return 0;
46 }
47
48 extern int
49 adopt_paths (vector pathvec, struct multipath * mpp)
50 {
51         int i;
52         struct path * pp;
53
54         if (!mpp)
55                 return 0;
56
57         if (update_mpp_paths(mpp, pathvec))
58                 return 1;
59
60         vector_foreach_slot (pathvec, pp, i) {
61                 if (!strncmp(mpp->wwid, pp->wwid, WWID_SIZE)) {
62                         condlog(3, "%s: ownership set to %s",
63                                 pp->dev, mpp->alias);
64                         pp->mpp = mpp;
65
66                         if (!mpp->paths && !(mpp->paths = vector_alloc()))
67                                 return 1;
68
69                         if (!find_path_by_dev(mpp->paths, pp->dev) &&
70                             store_path(mpp->paths, pp))
71                                         return 1;
72                         pathinfo(pp, conf->hwtable, DI_PRIO | DI_CHECKER);
73                 }
74         }
75         return 0;
76 }
77
78 extern void
79 orphan_path (struct path * pp)
80 {
81         pp->mpp = NULL;
82         pp->dmstate = PSTATE_UNDEF;
83         pp->getuid = NULL;
84         pp->prio = NULL;
85         checker_put(&pp->checker);
86         if (pp->fd >= 0)
87                 close(pp->fd);
88         pp->fd = -1;
89 }
90
91 extern void
92 orphan_paths (vector pathvec, struct multipath * mpp)
93 {
94         int i;
95         struct path * pp;
96
97         vector_foreach_slot (pathvec, pp, i) {
98                 if (pp->mpp == mpp) {
99                         condlog(4, "%s: orphaned", pp->dev);
100                         orphan_path(pp);
101                 }
102         }
103 }
104
105 static void
106 set_multipath_wwid (struct multipath * mpp)
107 {
108         if (mpp->wwid)
109                 return;
110
111         dm_get_uuid(mpp->alias, mpp->wwid);
112 }
113
114 #define KEEP_WAITER 0
115 #define STOP_WAITER 1
116 #define PURGE_VEC 1
117
118 static void
119 _remove_map (struct multipath * mpp, struct vectors * vecs,
120             int stop_waiter, int purge_vec)
121 {
122         int i;
123
124         condlog(4, "%s: remove multipath map", mpp->alias);
125
126         /*
127          * stop the DM event waiter thread
128          */
129         if (stop_waiter)
130                 stop_waiter_thread(mpp, vecs);
131
132         /*
133          * clear references to this map
134          */
135         orphan_paths(vecs->pathvec, mpp);
136
137         if (purge_vec &&
138             (i = find_slot(vecs->mpvec, (void *)mpp)) != -1)
139                 vector_del_slot(vecs->mpvec, i);
140
141         /*
142          * final free
143          */
144         free_multipath(mpp, KEEP_PATHS);
145 }
146
147 extern void
148 remove_map (struct multipath * mpp, struct vectors * vecs, int purge_vec)
149 {
150         _remove_map(mpp, vecs, KEEP_WAITER, purge_vec);
151 }
152
153 extern void
154 remove_map_and_stop_waiter (struct multipath * mpp, struct vectors * vecs,
155                             int purge_vec)
156 {
157         _remove_map(mpp, vecs, STOP_WAITER, purge_vec);
158 }
159
160 static void
161 _remove_maps (struct vectors * vecs, int stop_waiter)
162 {
163         int i;
164         struct multipath * mpp;
165
166         vector_foreach_slot (vecs->mpvec, mpp, i) {
167                 _remove_map(mpp, vecs, stop_waiter, 1);
168                 i--;
169         }
170
171         vector_free(vecs->mpvec);
172         vecs->mpvec = NULL;
173 }
174
175 extern void
176 remove_maps (struct vectors * vecs)
177 {
178         _remove_maps(vecs, KEEP_WAITER);
179 }
180
181 extern void
182 remove_maps_and_stop_waiters (struct vectors * vecs)
183 {
184         _remove_maps(vecs, STOP_WAITER);
185 }
186
187 static struct hwentry *
188 extract_hwe_from_path(struct multipath * mpp)
189 {
190         struct path * pp;
191         struct pathgroup * pgp;
192
193         pgp = VECTOR_SLOT(mpp->pg, 0);
194         pp = VECTOR_SLOT(pgp->paths, 0);
195
196         return pp->hwe;
197 }
198
199 static int
200 update_multipath_table (struct multipath *mpp, vector pathvec)
201 {
202         if (!mpp)
203                 return 1;
204
205         if (dm_get_map(mpp->alias, &mpp->size, mpp->params))
206                 return 1;
207
208         if (disassemble_map(pathvec, mpp->params, mpp))
209                 return 1;
210
211         return 0;
212 }
213
214 static int
215 update_multipath_status (struct multipath *mpp)
216 {
217         if (!mpp)
218                 return 1;
219
220         if(dm_get_status(mpp->alias, mpp->status))
221                 return 1;
222
223         if (disassemble_status(mpp->status, mpp))
224                 return 1;
225
226         return 0;
227 }
228
229 extern int
230 update_multipath_strings (struct multipath *mpp, vector pathvec)
231 {
232         free_multipath_attributes(mpp);
233         free_pgvec(mpp->pg, KEEP_PATHS);
234         mpp->pg = NULL;
235
236         if (update_multipath_table(mpp, pathvec))
237                 return 1;
238
239         if (update_multipath_status(mpp))
240                 return 1;
241
242         return 0;
243 }
244
245 extern void
246 set_no_path_retry(struct multipath *mpp)
247 {
248         mpp->retry_tick = 0;
249         mpp->nr_active = pathcount(mpp, PATH_UP) + pathcount(mpp, PATH_GHOST);
250         select_no_path_retry(mpp);
251
252         switch (mpp->no_path_retry) {
253         case NO_PATH_RETRY_UNDEF:
254                 break;
255         case NO_PATH_RETRY_FAIL:
256                 dm_queue_if_no_path(mpp->alias, 0);
257                 break;
258         case NO_PATH_RETRY_QUEUE:
259                 dm_queue_if_no_path(mpp->alias, 1);
260                 break;
261         default:
262                 dm_queue_if_no_path(mpp->alias, 1);
263                 if (mpp->nr_active == 0) {
264                         /* Enter retry mode */
265                         mpp->retry_tick = mpp->no_path_retry * conf->checkint;
266                         condlog(1, "%s: Entering recovery mode: max_retries=%d",
267                                 mpp->alias, mpp->no_path_retry);
268                 }
269                 break;
270         }
271 }
272
273 extern int
274 setup_multipath (struct vectors * vecs, struct multipath * mpp)
275 {
276 retry:
277         if (dm_get_info(mpp->alias, &mpp->dmi)) {
278                 /* Error accessing table */
279                 condlog(3, "%s: cannot access table", mpp->alias); 
280                 goto out;
281         }
282
283         if (!dm_map_present(mpp->alias)) {
284                 /* Table has been removed */
285                 condlog(3, "%s: table does not exist", mpp->alias); 
286                 goto out;
287         }
288
289         set_multipath_wwid(mpp);
290         mpp->mpe = find_mpe(mpp->wwid);
291         condlog(3, "%s: discover", mpp->alias);
292
293         if (update_multipath_strings(mpp, vecs->pathvec)) {
294                 char new_alias[WWID_SIZE];
295
296                 /*
297                  * detect an external rename of the multipath device
298                  */
299                 if (dm_get_name(mpp->wwid, DEFAULT_TARGET, new_alias)) {
300                         condlog(3, "%s multipath mapped device name has "
301                                 "changed from %s to %s", mpp->wwid,
302                                 mpp->alias, new_alias);
303                         strcpy(mpp->alias, new_alias);
304
305                         if (mpp->waiter)
306                                 strncpy(((struct event_thread *)mpp->waiter)->mapname,
307                                         new_alias, WWID_SIZE);
308                         goto retry;
309                 }
310                 condlog(0, "%s: failed to setup multipath", mpp->alias);
311                 goto out;
312         }
313
314         //adopt_paths(vecs->pathvec, mpp);
315         mpp->hwe = extract_hwe_from_path(mpp);
316         select_rr_weight(mpp);
317         select_pgfailback(mpp);
318         set_no_path_retry(mpp);
319         select_pg_timeout(mpp);
320
321         return 0;
322 out:
323         remove_map(mpp, vecs, PURGE_VEC);
324         return 1;
325 }
326
327 extern struct multipath *
328 add_map_without_path (struct vectors * vecs,
329                       int minor, char * alias)
330 {
331         struct multipath * mpp = alloc_multipath();
332
333         if (!mpp)
334                 return NULL;
335
336         mpp->alias = alias;
337
338         if (setup_multipath(vecs, mpp))
339                 return NULL; /* mpp freed in setup_multipath */
340
341         if (adopt_paths(vecs->pathvec, mpp))
342                 goto out;
343
344         if (!vector_alloc_slot(vecs->mpvec))
345                 goto out;
346
347         vector_set_slot(vecs->mpvec, mpp);
348
349         if (start_waiter_thread(mpp, vecs))
350                 goto out;
351
352         return mpp;
353 out:
354         remove_map(mpp, vecs, PURGE_VEC);
355         return NULL;
356 }
357
358 extern struct multipath *
359 add_map_with_path (struct vectors * vecs,
360                    struct path * pp, int add_vec)
361 {
362         struct multipath * mpp;
363
364         if (!(mpp = alloc_multipath()))
365                 return NULL;
366
367         mpp->mpe = find_mpe(pp->wwid);
368         mpp->hwe = pp->hwe;
369
370         strcpy(mpp->wwid, pp->wwid);
371         select_alias(mpp);
372         mpp->size = pp->size;
373
374         if (adopt_paths(vecs->pathvec, mpp))
375                 goto out;
376
377         if (add_vec) {
378                 if (!vector_alloc_slot(vecs->mpvec))
379                         goto out;
380
381                 vector_set_slot(vecs->mpvec, mpp);
382         }
383
384         return mpp;
385
386 out:
387         remove_map(mpp, vecs, PURGE_VEC);
388         return NULL;
389 }
390
391 extern int
392 verify_paths(struct multipath * mpp, struct vectors * vecs, vector rpvec)
393 {
394         struct path * pp;
395         int count = 0;
396         int i, j;
397
398         vector_foreach_slot (mpp->paths, pp, i) {
399                 /*
400                  * see if path is in sysfs
401                  */
402                 if (!pp->sysdev || sysfs_get_dev(pp->sysdev,
403                                                  pp->dev_t, BLK_DEV_SIZE)) {
404                         condlog(0, "%s: failed to access path %s", mpp->alias,
405                                 pp->sysdev ? pp->sysdev->devpath : pp->dev_t);
406                         count++;
407                         vector_del_slot(mpp->paths, i);
408                         i--;
409
410                         if (rpvec)
411                                 store_path(rpvec, pp);
412                         else {
413                                 if ((j = find_slot(vecs->pathvec,
414                                                    (void *)pp)) != -1)
415                                         vector_del_slot(vecs->pathvec, j);
416                                 free_path(pp);
417                         }
418                 }
419         }
420         return count;
421 }
422
423 int update_multipath (struct vectors *vecs, char *mapname)
424 {
425         struct multipath *mpp;
426         struct pathgroup  *pgp;
427         struct path *pp;
428         int i, j;
429
430         mpp = find_mp_by_alias(vecs->mpvec, mapname);
431
432         if (!mpp) {
433                 condlog(3, "%s: multipath map not found\n", mapname);
434                 return 2;
435         }
436
437         free_pgvec(mpp->pg, KEEP_PATHS);
438         mpp->pg = NULL;
439
440         if (setup_multipath(vecs, mpp))
441                 return 1; /* mpp freed in setup_multipath */
442
443         /*
444          * compare checkers states with DM states
445          */
446         vector_foreach_slot (mpp->pg, pgp, i) {
447                 vector_foreach_slot (pgp->paths, pp, j) {
448                         if (pp->dmstate != PSTATE_FAILED)
449                                 continue;
450
451                         if (pp->state != PATH_DOWN) {
452                                 int oldstate = pp->state;
453                                 condlog(2, "%s: mark as failed", pp->dev_t);
454                                 mpp->stat_path_failures++;
455                                 pp->state = PATH_DOWN;
456                                 if (oldstate == PATH_UP ||
457                                     oldstate == PATH_GHOST)
458                                         update_queue_mode_del_path(mpp);
459
460                                 /*
461                                  * if opportune,
462                                  * schedule the next check earlier
463                                  */
464                                 if (pp->tick > conf->checkint)
465                                         pp->tick = conf->checkint;
466                         }
467                 }
468         }
469
470         return 0;
471 }
472
473 /*
474  * mpp->no_path_retry:
475  *   -2 (QUEUE) : queue_if_no_path enabled, never turned off
476  *   -1 (FAIL)  : fail_if_no_path
477  *    0 (UNDEF) : nothing
478  *   >0         : queue_if_no_path enabled, turned off after polling n times
479  */
480 void update_queue_mode_del_path(struct multipath *mpp)
481 {
482         if (--mpp->nr_active == 0 && mpp->no_path_retry > 0) {
483                 /*
484                  * Enter retry mode.
485                  * meaning of +1: retry_tick may be decremented in
486                  *                checkerloop before starting retry.
487                  */
488                 mpp->stat_queueing_timeouts++;
489                 mpp->retry_tick = mpp->no_path_retry * conf->checkint + 1;
490                 condlog(1, "%s: Entering recovery mode: max_retries=%d",
491                         mpp->alias, mpp->no_path_retry);
492         }
493         condlog(2, "%s: remaining active paths: %d", mpp->alias, mpp->nr_active);
494 }
495
496 void update_queue_mode_add_path(struct multipath *mpp)
497 {
498         if (mpp->nr_active++ == 0 && mpp->no_path_retry > 0) {
499                 /* come back to normal mode from retry mode */
500                 mpp->retry_tick = 0;
501                 dm_queue_if_no_path(mpp->alias, 1);
502                 condlog(2, "%s: queue_if_no_path enabled", mpp->alias);
503                 condlog(1, "%s: Recovered to normal mode", mpp->alias);
504         }
505         condlog(2, "%s: remaining active paths: %d", mpp->alias, mpp->nr_active);
506 }
507