pohmelfs: Use current logging styles.
[pohmelfs.git] / fs / pohmelfs / route.c
blobc6a47557049d42a689d763c86d8a57d645a8b4fb
1 /*
2 * Copyright (C) 2011+ Evgeniy Polyakov <zbr@ioremap.net>
3 */
5 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
7 #include <linux/slab.h>
8 #include <linux/workqueue.h>
10 #include "pohmelfs.h"
13 static inline int pohmelfs_route_cmp_raw(const struct pohmelfs_route *rt, const struct dnet_raw_id *raw, int group_id)
15 if (rt->group_id < group_id)
16 return -1;
17 if (rt->group_id > group_id)
18 return 1;
20 return dnet_id_cmp_str(rt->id.id, raw->id);
23 static inline int pohmelfs_route_cmp(const struct pohmelfs_route *id1, const struct pohmelfs_route *id2)
25 return pohmelfs_route_cmp_raw(id1, &id2->id, id2->group_id);
28 static int pohmelfs_route_insert(struct pohmelfs_connection *conn, struct pohmelfs_route *rt)
30 struct rb_node **n = &conn->route_root.rb_node, *parent = NULL;
31 struct pohmelfs_route *tmp;
32 int cmp, err = 0;
34 spin_lock(&conn->state_lock);
35 while (*n) {
36 parent = *n;
38 tmp = rb_entry(parent, struct pohmelfs_route, node);
40 cmp = pohmelfs_route_cmp(tmp, rt);
41 if (cmp < 0)
42 n = &parent->rb_left;
43 else if (cmp > 0)
44 n = &parent->rb_right;
45 else {
46 err = -EEXIST;
47 goto err_out_unlock;
51 rb_link_node(&rt->node, parent, n);
52 rb_insert_color(&rt->node, &conn->route_root);
54 err_out_unlock:
55 spin_unlock(&conn->state_lock);
56 return err;
60 static int pohmelfs_route_add(struct pohmelfs_state *st, struct dnet_raw_id *id, int group_id)
62 struct pohmelfs_connection *conn = st->conn;
63 struct pohmelfs_route *rt;
64 int err;
66 rt = kmem_cache_zalloc(pohmelfs_route_cache, GFP_NOIO);
67 if (!rt) {
68 err = -ENOMEM;
69 goto err_out_exit;
72 memcpy(&rt->id, id, sizeof(struct dnet_raw_id));
73 rt->group_id = group_id;
74 rt->st = st;
76 pohmelfs_state_get(st);
78 err = pohmelfs_route_insert(conn, rt);
79 if (err)
80 goto err_out_put;
82 rt->st->routes++;
83 return 0;
85 err_out_put:
86 pohmelfs_state_put(st);
87 kmem_cache_free(pohmelfs_route_cache, rt);
88 err_out_exit:
89 return err;
92 static struct pohmelfs_state *pohmelfs_state_lookup_connection(struct pohmelfs_connection *conn, struct dnet_raw_id *id, int group_id)
94 struct rb_node *n = conn->route_root.rb_node;
95 struct pohmelfs_route *rt;
96 struct pohmelfs_state *st = NULL;
97 int cmp;
99 spin_lock(&conn->state_lock);
100 while (n) {
101 rt = rb_entry(n, struct pohmelfs_route, node);
103 cmp = pohmelfs_route_cmp_raw(rt, id, group_id);
105 if (!st && (rt->group_id == group_id)) {
106 st = rt->st;
109 if (cmp < 0) {
110 n = n->rb_left;
112 if (rt->group_id == group_id) {
113 st = rt->st;
115 } else if (cmp > 0)
116 n = n->rb_right;
117 else {
118 st = rt->st;
119 break;
122 if (st)
123 pohmelfs_state_get(st);
125 spin_unlock(&conn->state_lock);
127 return st;
130 struct pohmelfs_state *pohmelfs_state_lookup(struct pohmelfs_sb *psb, struct dnet_raw_id *id, int group_id, ssize_t size)
132 struct pohmelfs_state *st;
133 struct pohmelfs_connection *c;
134 int idx;
136 mutex_lock(&psb->conn_lock);
137 if ((size > PAGE_SIZE) || (size < 0)) {
138 idx = psb->bulk_idx;
139 if (++psb->bulk_idx >= psb->bulk_num)
140 psb->bulk_idx = 0;
141 } else {
142 /* meta connections are placed after bulk */
143 idx = psb->meta_idx + psb->bulk_num;
144 if (++psb->meta_idx >= psb->meta_num)
145 psb->meta_idx = 0;
148 pr_debug("%s: selected connection: %d, group: %d, size: %zd\n",
149 pohmelfs_dump_id(id->id), idx, group_id, size);
151 c = &psb->conn[idx];
152 st = pohmelfs_state_lookup_connection(c, id, group_id);
153 mutex_unlock(&psb->conn_lock);
155 return st;
158 int pohmelfs_grab_states(struct pohmelfs_sb *psb, struct pohmelfs_state ***stp)
160 struct pohmelfs_state **states, *st;
161 struct pohmelfs_connection *c;
162 int err;
163 int num = 0, pos = 0;
165 mutex_lock(&psb->conn_lock);
166 c = &psb->conn[0];
168 spin_lock(&c->state_lock);
169 list_for_each_entry(st, &c->state_list, state_entry) {
170 ++num;
172 spin_unlock(&c->state_lock);
173 mutex_unlock(&psb->conn_lock);
175 if (!num) {
176 err = -ENOENT;
177 goto err_out_exit;
180 states = kzalloc(sizeof(struct pohmelfs_state *) * num, GFP_NOIO);
181 if (!states) {
182 err = -ENOMEM;
183 goto err_out_exit;
186 mutex_lock(&psb->conn_lock);
187 c = &psb->conn[0];
189 spin_lock(&c->state_lock);
190 list_for_each_entry(st, &c->state_list, state_entry) {
191 pohmelfs_state_get(st);
192 states[pos] = st;
193 ++pos;
195 spin_unlock(&c->state_lock);
196 mutex_unlock(&psb->conn_lock);
198 *stp = states;
199 return pos;
201 err_out_exit:
202 return err;
205 static void pohmelfs_route_remove_nolock(struct pohmelfs_connection *conn, struct pohmelfs_route *rt)
207 rt->st->routes--;
208 rb_erase(&rt->node, &conn->route_root);
209 pohmelfs_state_put(rt->st);
210 kmem_cache_free(pohmelfs_route_cache, rt);
213 void pohmelfs_route_remove_all(struct pohmelfs_state *st)
215 struct pohmelfs_connection *conn = st->conn;
216 struct pohmelfs_route *rt;
217 struct rb_node *n;
218 int again = 1;
220 while (again) {
221 spin_lock(&conn->state_lock);
223 n = rb_first(&conn->route_root);
224 if (!n) {
225 spin_unlock(&conn->state_lock);
226 break;
229 again = 0;
230 while (n) {
231 rt = rb_entry(n, struct pohmelfs_route, node);
233 if (rt->st == st) {
234 pohmelfs_route_remove_nolock(conn, rt);
235 again = 1;
236 break;
239 n = rb_next(n);
241 spin_unlock(&conn->state_lock);
243 cond_resched();
247 static int pohmelfs_route_request_complete(struct pohmelfs_trans *t, struct pohmelfs_state *recv)
249 struct pohmelfs_sb *psb = pohmelfs_sb(t->inode->i_sb);
250 struct dnet_cmd *cmd = &recv->cmd;
251 struct pohmelfs_state *st;
252 struct dnet_attr *attr;
253 struct dnet_addr_attr *a;
254 struct dnet_raw_id *ids;
255 int err = 0;
257 if (!t->io_offset)
258 goto err_out_exit;
260 attr = t->recv_data;
261 dnet_convert_attr(attr);
263 if (attr->size > sizeof(struct dnet_addr_attr)) {
264 int i, j, num = (attr->size - sizeof(struct dnet_addr_attr)) / sizeof(struct dnet_raw_id);
266 a = (struct dnet_addr_attr *)(attr + 1);
267 dnet_convert_addr_attr(a);
268 ids = (struct dnet_raw_id *)(a + 1);
270 mutex_lock(&psb->conn_lock);
271 for (j = 0; j < psb->conn_num; ++j) {
272 struct pohmelfs_connection *c = &psb->conn[j];
274 st = pohmelfs_state_create(c, (struct sockaddr_storage *)&a->addr.addr, a->addr.addr_len,
275 0, cmd->id.group_id);
276 if (IS_ERR(st)) {
277 err = PTR_ERR(st);
279 if (err == -EEXIST) {
280 spin_lock(&c->state_lock);
281 st = pohmelfs_addr_exist(c, (struct sockaddr_storage *)&a->addr.addr, a->addr.addr_len);
282 if (st) {
283 st->group_id = cmd->id.group_id;
284 pohmelfs_state_get(st);
285 err = 0;
287 spin_unlock(&c->state_lock);
290 if (err)
291 goto err_out_unlock;
292 } else {
294 * reference grab logic should be the same
295 * as in case when state exist - we will drop
296 * it at the end, so we would not check whether
297 * it is new state (and refcnt == 1) or
298 * existing (refcnt > 1)
300 pohmelfs_state_get(st);
303 for (i = 0; i < num; ++i) {
304 dnet_convert_raw_id(&ids[i]);
305 #if 0
306 pohmelfs_print_addr((struct sockaddr_storage *)&a->addr.addr, "%d:%s\n",
307 cmd->id.group_id, pohmelfs_dump_id(ids[i].id));
308 #endif
310 err = pohmelfs_route_add(st, &ids[i], cmd->id.group_id);
311 if (err) {
312 if (err != -EEXIST) {
313 /* remove this state from route table */
314 spin_lock(&c->state_lock);
315 list_del_init(&st->state_entry);
316 spin_unlock(&c->state_lock);
318 /* drop abovementioned refcnt */
319 pohmelfs_state_put(st);
321 pohmelfs_state_kill(st);
322 goto err_out_exit;
325 err = 0;
329 /* drop abovementioned refcnt */
330 pohmelfs_state_put(st);
332 err_out_unlock:
333 mutex_unlock(&psb->conn_lock);
336 err_out_exit:
337 return err;
340 int pohmelfs_route_request(struct pohmelfs_state *st)
342 struct pohmelfs_sb *psb = st->conn->psb;
343 struct pohmelfs_io *pio;
344 int err;
346 pio = kmem_cache_zalloc(pohmelfs_io_cache, GFP_NOIO);
347 if (!pio) {
348 err = -ENOMEM;
349 goto err_out_exit;
352 pio->pi = psb->root;
353 pio->id = &psb->root->id;
354 pio->cmd = DNET_CMD_ROUTE_LIST;
355 pio->cflags = DNET_FLAGS_DIRECT | DNET_FLAGS_NEED_ACK;
356 pio->cb.complete = pohmelfs_route_request_complete;
358 err = pohmelfs_send_buf_single(pio, st);
359 if (err) {
360 pohmelfs_print_addr(&st->sa, "%s: %d\n", __func__, err);
361 goto err_out_free;
363 pohmelfs_print_addr(&st->sa, "route request sent\n");
365 err_out_free:
366 kmem_cache_free(pohmelfs_io_cache, pio);
367 err_out_exit:
368 return err;