2 * Copyright (C) 2011+ Evgeniy Polyakov <zbr@ioremap.net>
5 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
7 #include <linux/slab.h>
8 #include <linux/workqueue.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
)
17 if (rt
->group_id
> group_id
)
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
;
34 spin_lock(&conn
->state_lock
);
38 tmp
= rb_entry(parent
, struct pohmelfs_route
, node
);
40 cmp
= pohmelfs_route_cmp(tmp
, rt
);
44 n
= &parent
->rb_right
;
51 rb_link_node(&rt
->node
, parent
, n
);
52 rb_insert_color(&rt
->node
, &conn
->route_root
);
55 spin_unlock(&conn
->state_lock
);
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
;
66 rt
= kmem_cache_zalloc(pohmelfs_route_cache
, GFP_NOIO
);
72 memcpy(&rt
->id
, id
, sizeof(struct dnet_raw_id
));
73 rt
->group_id
= group_id
;
76 pohmelfs_state_get(st
);
78 err
= pohmelfs_route_insert(conn
, rt
);
86 pohmelfs_state_put(st
);
87 kmem_cache_free(pohmelfs_route_cache
, rt
);
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
;
99 spin_lock(&conn
->state_lock
);
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
)) {
112 if (rt
->group_id
== group_id
) {
123 pohmelfs_state_get(st
);
125 spin_unlock(&conn
->state_lock
);
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
;
136 mutex_lock(&psb
->conn_lock
);
137 if ((size
> PAGE_SIZE
) || (size
< 0)) {
139 if (++psb
->bulk_idx
>= psb
->bulk_num
)
142 /* meta connections are placed after bulk */
143 idx
= psb
->meta_idx
+ psb
->bulk_num
;
144 if (++psb
->meta_idx
>= psb
->meta_num
)
148 pr_debug("%s: selected connection: %d, group: %d, size: %zd\n",
149 pohmelfs_dump_id(id
->id
), idx
, group_id
, size
);
152 st
= pohmelfs_state_lookup_connection(c
, id
, group_id
);
153 mutex_unlock(&psb
->conn_lock
);
158 int pohmelfs_grab_states(struct pohmelfs_sb
*psb
, struct pohmelfs_state
***stp
)
160 struct pohmelfs_state
**states
, *st
;
161 struct pohmelfs_connection
*c
;
163 int num
= 0, pos
= 0;
165 mutex_lock(&psb
->conn_lock
);
168 spin_lock(&c
->state_lock
);
169 list_for_each_entry(st
, &c
->state_list
, state_entry
) {
172 spin_unlock(&c
->state_lock
);
173 mutex_unlock(&psb
->conn_lock
);
180 states
= kzalloc(sizeof(struct pohmelfs_state
*) * num
, GFP_NOIO
);
186 mutex_lock(&psb
->conn_lock
);
189 spin_lock(&c
->state_lock
);
190 list_for_each_entry(st
, &c
->state_list
, state_entry
) {
191 pohmelfs_state_get(st
);
195 spin_unlock(&c
->state_lock
);
196 mutex_unlock(&psb
->conn_lock
);
205 static void pohmelfs_route_remove_nolock(struct pohmelfs_connection
*conn
, struct pohmelfs_route
*rt
)
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
;
221 spin_lock(&conn
->state_lock
);
223 n
= rb_first(&conn
->route_root
);
225 spin_unlock(&conn
->state_lock
);
231 rt
= rb_entry(n
, struct pohmelfs_route
, node
);
234 pohmelfs_route_remove_nolock(conn
, rt
);
241 spin_unlock(&conn
->state_lock
);
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
;
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
);
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
);
283 st
->group_id
= cmd
->id
.group_id
;
284 pohmelfs_state_get(st
);
287 spin_unlock(&c
->state_lock
);
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
]);
306 pohmelfs_print_addr((struct sockaddr_storage
*)&a
->addr
.addr
, "%d:%s\n",
307 cmd
->id
.group_id
, pohmelfs_dump_id(ids
[i
].id
));
310 err
= pohmelfs_route_add(st
, &ids
[i
], cmd
->id
.group_id
);
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
);
329 /* drop abovementioned refcnt */
330 pohmelfs_state_put(st
);
333 mutex_unlock(&psb
->conn_lock
);
340 int pohmelfs_route_request(struct pohmelfs_state
*st
)
342 struct pohmelfs_sb
*psb
= st
->conn
->psb
;
343 struct pohmelfs_io
*pio
;
346 pio
= kmem_cache_zalloc(pohmelfs_io_cache
, GFP_NOIO
);
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
);
360 pohmelfs_print_addr(&st
->sa
, "%s: %d\n", __func__
, err
);
363 pohmelfs_print_addr(&st
->sa
, "route request sent\n");
366 kmem_cache_free(pohmelfs_io_cache
, pio
);