Fixed listing and object creation
[pohmelfs.git] / fs / pohmelfs / route.c
blob5596407104fe4b7035873b1e64bfd0aef7b03d5a
1 /*
2 * Copyright (C) 2011+ Evgeniy Polyakov <zbr@ioremap.net>
3 */
5 #include <linux/slab.h>
6 #include <linux/workqueue.h>
8 #include "pohmelfs.h"
11 static inline int pohmelfs_route_cmp_raw(const struct pohmelfs_route *rt, const struct dnet_raw_id *raw, int group_id)
13 if (rt->group_id < group_id)
14 return -1;
15 if (rt->group_id > group_id)
16 return 1;
18 return dnet_id_cmp_str(rt->id.id, raw->id);
21 static inline int pohmelfs_route_cmp(const struct pohmelfs_route *id1, const struct pohmelfs_route *id2)
23 return pohmelfs_route_cmp_raw(id1, &id2->id, id2->group_id);
26 static int pohmelfs_route_insert(struct pohmelfs_sb *psb, struct pohmelfs_route *rt)
28 struct rb_node **n = &psb->route_root.rb_node, *parent = NULL;
29 struct pohmelfs_route *tmp;
30 int cmp, err = 0;
32 spin_lock(&psb->state_lock);
33 while (*n) {
34 parent = *n;
36 tmp = rb_entry(parent, struct pohmelfs_route, node);
38 cmp = pohmelfs_route_cmp(tmp, rt);
39 if (cmp < 0)
40 n = &parent->rb_left;
41 else if (cmp > 0)
42 n = &parent->rb_right;
43 else {
44 err = -EEXIST;
45 goto err_out_unlock;
49 rb_link_node(&rt->node, parent, n);
50 rb_insert_color(&rt->node, &psb->route_root);
52 err_out_unlock:
53 spin_unlock(&psb->state_lock);
54 return err;
58 static int pohmelfs_route_add(struct pohmelfs_state *st, struct dnet_raw_id *id, int group_id)
60 struct pohmelfs_sb *psb = st->psb;
61 struct pohmelfs_route *rt;
62 int err;
64 rt = kmem_cache_zalloc(pohmelfs_route_cache, GFP_NOIO);
65 if (!rt) {
66 err = -ENOMEM;
67 goto err_out_exit;
70 memcpy(&rt->id, id, sizeof(struct dnet_raw_id));
71 rt->group_id = group_id;
72 rt->st = st;
74 pohmelfs_state_get(st);
76 err = pohmelfs_route_insert(psb, rt);
77 if (err)
78 goto err_out_put;
80 rt->st->routes++;
81 return 0;
83 err_out_put:
84 pohmelfs_state_put(st);
85 kmem_cache_free(pohmelfs_route_cache, rt);
86 err_out_exit:
87 return err;
90 struct pohmelfs_state *pohmelfs_state_lookup(struct pohmelfs_sb *psb, struct dnet_raw_id *id, int group_id)
92 struct rb_node *n = psb->route_root.rb_node;
93 struct pohmelfs_route *rt;
94 struct pohmelfs_state *st = NULL;
95 int cmp;
97 spin_lock(&psb->state_lock);
98 while (n) {
99 rt = rb_entry(n, struct pohmelfs_route, node);
101 cmp = pohmelfs_route_cmp_raw(rt, id, group_id);
103 if (!st && (rt->group_id == group_id)) {
104 st = rt->st;
107 if (cmp < 0) {
108 n = n->rb_left;
110 if (rt->group_id == group_id) {
111 st = rt->st;
113 } else if (cmp > 0)
114 n = n->rb_right;
115 else {
116 st = rt->st;
117 break;
120 if (st)
121 pohmelfs_state_get(st);
123 spin_unlock(&psb->state_lock);
125 return st;
128 static void pohmelfs_route_remove_nolock(struct pohmelfs_sb *psb, struct pohmelfs_route *rt)
130 rt->st->routes--;
131 rb_erase(&rt->node, &psb->route_root);
132 pohmelfs_state_put(rt->st);
133 kmem_cache_free(pohmelfs_route_cache, rt);
136 void pohmelfs_route_remove_all(struct pohmelfs_state *st)
138 struct pohmelfs_sb *psb = st->psb;
139 struct pohmelfs_route *rt;
140 struct rb_node *n, *next;
141 int found = 1;
143 spin_lock(&psb->state_lock);
145 while (found) {
146 n = rb_first(&psb->route_root);
147 found = 0;
149 while (n) {
150 rt = rb_entry(n, struct pohmelfs_route, node);
152 next = rb_next(&rt->node);
154 if (rt->st == st) {
155 pohmelfs_route_remove_nolock(psb, rt);
156 found = 1;
157 break;
160 n = next;
164 spin_unlock(&psb->state_lock);
167 static int pohmelfs_route_request_complete(struct pohmelfs_trans *t, struct pohmelfs_state *recv)
169 struct pohmelfs_sb *psb = pohmelfs_sb(t->inode->i_sb);
170 struct dnet_cmd *cmd = &recv->cmd;
171 struct pohmelfs_state *st;
172 struct dnet_attr *attr;
173 struct dnet_addr_attr *a;
174 struct dnet_raw_id *ids;
175 int err = 0;
177 if (!t->recv_offset)
178 goto err_out_exit;
180 attr = t->recv_data;
181 dnet_convert_attr(attr);
183 if (attr->size > sizeof(struct dnet_addr_attr)) {
184 int i, num = (attr->size - sizeof(struct dnet_addr_attr)) / sizeof(struct dnet_raw_id);
186 a = (struct dnet_addr_attr *)(attr + 1);
187 dnet_convert_addr_attr(a);
188 ids = (struct dnet_raw_id *)(a + 1);
190 st = pohmelfs_state_create(psb, (struct sockaddr_storage *)&a->addr.addr, a->addr.addr_len, 0);
191 if (IS_ERR(st)) {
192 err = PTR_ERR(st);
194 if (err == -EEXIST) {
195 spin_lock(&psb->state_lock);
196 st = pohmelfs_addr_exist(psb, (struct sockaddr_storage *)&a->addr.addr, a->addr.addr_len);
197 if (st) {
198 pohmelfs_state_get(st);
199 err = 0;
201 spin_unlock(&psb->state_lock);
204 if (err)
205 goto err_out_exit;
206 } else {
208 * reference grab logic should be the same
209 * as in case when state exist - we will drop
210 * it at the end, so we would not check whether
211 * it is new state (and refcnt == 1) or
212 * existing (refcnt > 1)
214 pohmelfs_state_get(st);
217 for (i = 0; i < num; ++i) {
218 dnet_convert_raw_id(&ids[i]);
219 #if 0
220 pohmelfs_print_addr((struct sockaddr_storage *)&a->addr.addr, "%d:%s\n",
221 cmd->id.group_id, pohmelfs_dump_id(ids[i].id));
222 #endif
224 err = pohmelfs_route_add(st, &ids[i], cmd->id.group_id);
225 if (err) {
226 if (err != -EEXIST) {
227 /* remove this state from route table */
228 spin_lock(&psb->state_lock);
229 list_del_init(&st->state_entry);
230 spin_unlock(&psb->state_lock);
232 /* drop abovementioned refcnt */
233 pohmelfs_state_put(st);
235 pohmelfs_state_kill(st);
236 goto err_out_exit;
239 err = 0;
243 /* drop abovementioned refcnt */
244 pohmelfs_state_put(st);
247 err_out_exit:
248 return err;
251 int pohmelfs_route_request(struct pohmelfs_state *st)
253 struct pohmelfs_sb *psb = st->psb;
254 struct pohmelfs_io io;
255 int err;
257 memset(&io, 0, sizeof(struct pohmelfs_io));
259 io.pi = psb->root;
260 io.id = &psb->root->id;
261 io.cmd = DNET_CMD_ROUTE_LIST;
262 io.cflags = DNET_FLAGS_DIRECT;
263 io.complete = pohmelfs_route_request_complete;
265 err = pohmelfs_send_buf(st, &io);
266 if (err) {
267 pohmelfs_print_addr(&st->sa, "pohmelfs: pohmelfs_route_request: %d\n", err);
268 goto err_out_exit;
270 pohmelfs_print_addr(&st->sa, "route request sent\n");
272 err_out_exit:
273 return err;