multipathd: fix reservation_key check
[multipath-tools/.git] / libmultipath / prio.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <stddef.h>
4 #include <dlfcn.h>
5 #include <sys/stat.h>
6
7 #include "debug.h"
8 #include "prio.h"
9
10 static LIST_HEAD(prioritizers);
11
12 unsigned int get_prio_timeout(unsigned int checker_timeout,
13                               unsigned int default_timeout)
14 {
15         if (checker_timeout)
16                 return checker_timeout * 1000;
17         return default_timeout;
18 }
19
20 int init_prio (char *multipath_dir)
21 {
22         if (!add_prio(multipath_dir, DEFAULT_PRIO))
23                 return 1;
24         return 0;
25 }
26
27 static struct prio * alloc_prio (void)
28 {
29         struct prio *p;
30
31         p = MALLOC(sizeof(struct prio));
32         if (p) {
33                 INIT_LIST_HEAD(&p->node);
34                 p->refcount = 1;
35         }
36         return p;
37 }
38
39 void free_prio (struct prio * p)
40 {
41         if (!p)
42                 return;
43         p->refcount--;
44         if (p->refcount) {
45                 condlog(3, "%s prioritizer refcount %d",
46                         p->name, p->refcount);
47                 return;
48         }
49         condlog(3, "unloading %s prioritizer", p->name);
50         list_del(&p->node);
51         if (p->handle) {
52                 if (dlclose(p->handle) != 0) {
53                         condlog(0, "Cannot unload prioritizer %s: %s",
54                                 p->name, dlerror());
55                 }
56         }
57         FREE(p);
58 }
59
60 void cleanup_prio(void)
61 {
62         struct prio * prio_loop;
63         struct prio * prio_temp;
64
65         list_for_each_entry_safe(prio_loop, prio_temp, &prioritizers, node) {
66                 free_prio(prio_loop);
67         }
68 }
69
70 static struct prio * prio_lookup (char * name)
71 {
72         struct prio * p;
73
74         if (!name || !strlen(name))
75                 return NULL;
76
77         list_for_each_entry(p, &prioritizers, node) {
78                 if (!strncmp(name, p->name, PRIO_NAME_LEN))
79                         return p;
80         }
81         return NULL;
82 }
83
84 int prio_set_args (struct prio * p, char * args)
85 {
86         return snprintf(p->args, PRIO_ARGS_LEN, "%s", args);
87 }
88
89 struct prio * add_prio (char *multipath_dir, char * name)
90 {
91         char libname[LIB_PRIO_NAMELEN];
92         struct stat stbuf;
93         struct prio * p;
94         char *errstr;
95
96         p = alloc_prio();
97         if (!p)
98                 return NULL;
99         snprintf(p->name, PRIO_NAME_LEN, "%s", name);
100         snprintf(libname, LIB_PRIO_NAMELEN, "%s/libprio%s.so",
101                  multipath_dir, name);
102         if (stat(libname,&stbuf) < 0) {
103                 condlog(0,"Prioritizer '%s' not found in %s",
104                         name, multipath_dir);
105                 goto out;
106         }
107         condlog(3, "loading %s prioritizer", libname);
108         p->handle = dlopen(libname, RTLD_NOW);
109         if (!p->handle) {
110                 if ((errstr = dlerror()) != NULL)
111                         condlog(0, "A dynamic linking error occurred: (%s)",
112                                 errstr);
113                 goto out;
114         }
115         p->getprio = (int (*)(struct path *, char *, unsigned int)) dlsym(p->handle, "getprio");
116         errstr = dlerror();
117         if (errstr != NULL)
118                 condlog(0, "A dynamic linking error occurred: (%s)", errstr);
119         if (!p->getprio)
120                 goto out;
121         list_add(&p->node, &prioritizers);
122         return p;
123 out:
124         free_prio(p);
125         return NULL;
126 }
127
128 int prio_getprio (struct prio * p, struct path * pp, unsigned int timeout)
129 {
130         return p->getprio(pp, p->args, timeout);
131 }
132
133 int prio_selected (struct prio * p)
134 {
135         if (!p)
136                 return 0;
137         return (p->getprio) ? 1 : 0;
138 }
139
140 char * prio_name (struct prio * p)
141 {
142         return p->name;
143 }
144
145 char * prio_args (struct prio * p)
146 {
147         return p->args;
148 }
149
150 void prio_get (char *multipath_dir, struct prio * dst, char * name, char * args)
151 {
152         struct prio * src = NULL;
153
154         if (!dst)
155                 return;
156
157         if (name && strlen(name)) {
158                 src = prio_lookup(name);
159                 if (!src)
160                         src = add_prio(multipath_dir, name);
161         }
162         if (!src) {
163                 dst->getprio = NULL;
164                 return;
165         }
166
167         strncpy(dst->name, src->name, PRIO_NAME_LEN);
168         if (args)
169                 strncpy(dst->args, args, PRIO_ARGS_LEN - 1);
170         dst->getprio = src->getprio;
171         dst->handle = NULL;
172
173         src->refcount++;
174 }
175
176 void prio_put (struct prio * dst)
177 {
178         struct prio * src;
179
180         if (!dst || !dst->getprio)
181                 return;
182
183         src = prio_lookup(dst->name);
184         memset(dst, 0x0, sizeof(struct prio));
185         free_prio(src);
186 }