2 * Copyright (C) 2011+ Evgeniy Polyakov <zbr@ioremap.net>
5 #include <linux/slab.h>
6 #include <linux/workqueue.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
)
15 if (rt
->group_id
> group_id
)
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
;
32 spin_lock(&psb
->state_lock
);
36 tmp
= rb_entry(parent
, struct pohmelfs_route
, node
);
38 cmp
= pohmelfs_route_cmp(tmp
, rt
);
42 n
= &parent
->rb_right
;
49 rb_link_node(&rt
->node
, parent
, n
);
50 rb_insert_color(&rt
->node
, &psb
->route_root
);
53 spin_unlock(&psb
->state_lock
);
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
;
64 rt
= kmem_cache_zalloc(pohmelfs_route_cache
, GFP_NOIO
);
70 memcpy(&rt
->id
, id
, sizeof(struct dnet_raw_id
));
71 rt
->group_id
= group_id
;
74 pohmelfs_state_get(st
);
76 err
= pohmelfs_route_insert(psb
, rt
);
84 pohmelfs_state_put(st
);
85 kmem_cache_free(pohmelfs_route_cache
, rt
);
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
;
97 spin_lock(&psb
->state_lock
);
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
)) {
110 if (rt
->group_id
== group_id
) {
121 pohmelfs_state_get(st
);
123 spin_unlock(&psb
->state_lock
);
128 static void pohmelfs_route_remove_nolock(struct pohmelfs_sb
*psb
, struct pohmelfs_route
*rt
)
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
;
143 spin_lock(&psb
->state_lock
);
146 n
= rb_first(&psb
->route_root
);
150 rt
= rb_entry(n
, struct pohmelfs_route
, node
);
152 next
= rb_next(&rt
->node
);
155 pohmelfs_route_remove_nolock(psb
, rt
);
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
;
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);
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
);
198 pohmelfs_state_get(st
);
201 spin_unlock(&psb
->state_lock
);
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
]);
220 pohmelfs_print_addr((struct sockaddr_storage
*)&a
->addr
.addr
, "%d:%s\n",
221 cmd
->id
.group_id
, pohmelfs_dump_id(ids
[i
].id
));
224 err
= pohmelfs_route_add(st
, &ids
[i
], cmd
->id
.group_id
);
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
);
243 /* drop abovementioned refcnt */
244 pohmelfs_state_put(st
);
251 int pohmelfs_route_request(struct pohmelfs_state
*st
)
253 struct pohmelfs_sb
*psb
= st
->psb
;
254 struct pohmelfs_io io
;
257 memset(&io
, 0, sizeof(struct pohmelfs_io
));
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
);
267 pohmelfs_print_addr(&st
->sa
, "pohmelfs: pohmelfs_route_request: %d\n", err
);
270 pohmelfs_print_addr(&st
->sa
, "route request sent\n");