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>
12 static void pohmelfs_trans_free(struct pohmelfs_trans
*t
)
16 kmem_cache_free(pohmelfs_trans_cache
, t
);
19 static void pohmelfs_trans_release(struct kref
*kref
)
21 struct pohmelfs_trans
*t
= container_of(kref
, struct pohmelfs_trans
, refcnt
);
22 struct pohmelfs_inode
*pi
= pohmelfs_inode(t
->inode
);
24 pr_debug("%s: %lu, io_offset: %llu, ino: %ld\n",
25 pohmelfs_dump_id(pi
->id
.id
), t
->trans
, t
->io_offset
,
31 pohmelfs_state_put(t
->st
);
35 pohmelfs_trans_free(t
);
38 void pohmelfs_trans_put(struct pohmelfs_trans
*t
)
40 kref_put(&t
->refcnt
, pohmelfs_trans_release
);
43 struct pohmelfs_trans
*pohmelfs_trans_alloc(struct inode
*inode
)
45 struct pohmelfs_trans
*t
;
48 t
= kmem_cache_zalloc(pohmelfs_trans_cache
, GFP_NOIO
);
54 kref_init(&t
->refcnt
);
56 t
->inode
= igrab(inode
);
65 kmem_cache_free(pohmelfs_trans_cache
, t
);
70 static int pohmelfs_buf_complete(struct pohmelfs_trans
*t
, struct pohmelfs_state
*recv
)
72 struct pohmelfs_inode
*pi
= pohmelfs_inode(t
->inode
);
73 struct dnet_cmd
*cmd
= &recv
->cmd
;
74 unsigned long long trans
= cmd
->trans
& ~DNET_TRANS_REPLY
;
76 pr_debug("%s: %llu, flags: %x\n",
77 pohmelfs_dump_id(pi
->id
.id
), trans
, cmd
->flags
);
82 static int pohmelfs_buf_recv(struct pohmelfs_trans
*t
, struct pohmelfs_state
*recv
)
84 struct dnet_cmd
*cmd
= &recv
->cmd
;
88 t
->recv_data
= kmalloc(cmd
->size
, GFP_NOIO
);
97 err
= pohmelfs_data_recv(recv
, t
->recv_data
+ t
->io_offset
, cmd
->size
- t
->io_offset
, MSG_DONTWAIT
);
108 static int pohmelfs_init_callbacks(struct pohmelfs_trans
*t
, struct pohmelfs_io
*pio
)
111 struct pohmelfs_state
*st
= t
->st
;
117 t
->cb
.complete
= pohmelfs_buf_complete
;
119 if (!t
->cb
.recv_reply
)
120 t
->cb
.recv_reply
= pohmelfs_buf_recv
;
128 pohmelfs_trans_insert(t
);
130 pohmelfs_state_schedule(st
);
131 pohmelfs_state_put(st
);
137 int pohmelfs_send_io_group(struct pohmelfs_io
*pio
, int group
)
139 struct pohmelfs_inode
*pi
= pio
->pi
;
140 struct inode
*inode
= &pi
->vfs_inode
;
141 struct pohmelfs_sb
*psb
= pohmelfs_sb(inode
->i_sb
);
142 struct pohmelfs_state
*st
;
143 struct pohmelfs_trans
*t
;
144 struct dnet_cmd
*cmd
;
145 struct dnet_attr
*attr
;
146 struct dnet_io_attr
*io
;
147 u64 iosize
= pio
->size
;
148 u64 alloc_io_size
= pio
->size
;
151 /* Dirty hack to prevent setting cmd/attr size to pio->size,
152 * since in read command we specify in io->size number bytes we want,
153 * and it should not be accounted in the packet we send to remote node
155 if (pio
->cmd
== DNET_CMD_READ
)
158 t
= pohmelfs_trans_alloc(inode
);
164 st
= pohmelfs_state_lookup(psb
, pio
->id
, group
, pio
->size
);
173 * We already hold a reference grabbed in pohmelfs_state_lookup(), it is dropped when transaction is destroyed
174 * We have to have valid state pointer to schedule sending, but after transaction is inserted into state's list,
175 * it can be processed immediately and freed and grabbed reference pointer will dissapear.
177 pohmelfs_state_get(st
);
183 dnet_setup_id(&cmd
->id
, group
, pio
->id
->id
);
184 cmd
->flags
= pio
->cflags
;
185 cmd
->trans
= t
->trans
= atomic_long_inc_return(&psb
->trans
);
186 cmd
->size
= alloc_io_size
+ sizeof(struct dnet_io_attr
) + sizeof(struct dnet_attr
);
188 attr
->cmd
= pio
->cmd
;
189 attr
->size
= alloc_io_size
+ sizeof(struct dnet_io_attr
);
190 attr
->flags
= pio
->aflags
;
192 memcpy(io
->id
, pio
->id
->id
, DNET_ID_SIZE
);
193 memcpy(io
->parent
, pio
->id
->id
, DNET_ID_SIZE
);
194 io
->flags
= pio
->ioflags
;
196 io
->offset
= pio
->offset
;
197 io
->type
= pio
->type
;
198 io
->start
= pio
->start
;
201 t
->header_size
= sizeof(struct dnet_cmd
) + sizeof(struct dnet_attr
) + sizeof(struct dnet_io_attr
);
202 t
->data_size
= alloc_io_size
;
204 dnet_convert_cmd(cmd
);
205 dnet_convert_attr(attr
);
206 dnet_convert_io_attr(io
);
211 if (pio
->alloc_flags
& POHMELFS_IO_OWN
) {
214 t
->data
= kmalloc(alloc_io_size
, GFP_NOIO
);
217 goto err_out_put_state
;
220 memcpy(t
->data
, pio
->data
, alloc_io_size
);
224 err
= pohmelfs_init_callbacks(t
, pio
);
226 goto err_out_put_state
;
232 pohmelfs_state_put(t
->st
);
234 pohmelfs_trans_free(t
);
239 int pohmelfs_send_io(struct pohmelfs_io
*pio
)
241 struct pohmelfs_sb
*psb
= pohmelfs_sb(pio
->pi
->vfs_inode
.i_sb
);
247 for (i
= 0; i
< psb
->group_num
; ++i
) {
248 err
= pohmelfs_send_io_group(pio
, psb
->groups
[i
]);
253 return (err_num
== psb
->group_num
) ? err
: 0;
256 int pohmelfs_trans_insert(struct pohmelfs_trans
*t
)
258 struct pohmelfs_state
*st
= t
->st
;
260 mutex_lock(&st
->trans_lock
);
261 list_add_tail(&t
->trans_entry
, &st
->trans_list
);
262 mutex_unlock(&st
->trans_lock
);
267 void pohmelfs_trans_remove(struct pohmelfs_trans
*t
)
269 struct pohmelfs_state
*st
= t
->st
;
271 mutex_lock(&st
->trans_lock
);
272 rb_erase(&t
->trans_node
, &st
->trans_root
);
273 mutex_unlock(&st
->trans_lock
);
276 static inline long pohmelfs_trans_cmp(struct pohmelfs_trans
*t1
, long trans
)
278 return t1
->trans
- trans
;
281 /* Must be called under st->trans_lock */
282 int pohmelfs_trans_insert_tree(struct pohmelfs_state
*st
, struct pohmelfs_trans
*t
)
284 struct rb_node
**n
= &st
->trans_root
.rb_node
, *parent
= NULL
;
285 struct pohmelfs_trans
*tmp
;
292 tmp
= rb_entry(parent
, struct pohmelfs_trans
, trans_node
);
294 cmp
= pohmelfs_trans_cmp(tmp
, t
->trans
);
296 n
= &parent
->rb_left
;
298 n
= &parent
->rb_right
;
305 rb_link_node(&t
->trans_node
, parent
, n
);
306 rb_insert_color(&t
->trans_node
, &st
->trans_root
);
313 struct pohmelfs_trans
*pohmelfs_trans_lookup(struct pohmelfs_state
*st
, struct dnet_cmd
*cmd
)
315 struct pohmelfs_trans
*t
, *found
= NULL
;
316 u64 trans
= cmd
->trans
& ~DNET_TRANS_REPLY
;
317 struct rb_node
*n
= st
->trans_root
.rb_node
;
320 mutex_lock(&st
->trans_lock
);
322 t
= rb_entry(n
, struct pohmelfs_trans
, trans_node
);
324 cmp
= pohmelfs_trans_cmp(t
, trans
);
331 kref_get(&t
->refcnt
);
335 mutex_unlock(&st
->trans_lock
);
340 int pohmelfs_send_buf_single(struct pohmelfs_io
*pio
, struct pohmelfs_state
*st
)
342 struct pohmelfs_inode
*pi
= pio
->pi
;
343 struct inode
*inode
= &pi
->vfs_inode
;
344 struct pohmelfs_sb
*psb
= pohmelfs_sb(inode
->i_sb
);
345 struct pohmelfs_trans
*t
;
346 struct dnet_cmd
*cmd
;
347 struct dnet_attr
*attr
;
350 t
= pohmelfs_trans_alloc(inode
);
357 st
= pohmelfs_state_lookup(psb
, pio
->id
, pio
->group_id
, pio
->size
);
363 pohmelfs_state_get(st
);
367 pohmelfs_state_get(st
);
372 dnet_setup_id(&cmd
->id
, st
->group_id
, pio
->id
->id
);
373 cmd
->flags
= pio
->cflags
;
374 cmd
->trans
= t
->trans
= atomic_long_inc_return(&psb
->trans
);
375 cmd
->size
= pio
->size
+ sizeof(struct dnet_attr
);
377 attr
->cmd
= pio
->cmd
;
378 attr
->size
= pio
->size
;
379 attr
->flags
= pio
->aflags
;
381 t
->header_size
= sizeof(struct dnet_cmd
) + sizeof(struct dnet_attr
);
382 t
->data_size
= pio
->size
;
384 dnet_convert_cmd(cmd
);
385 dnet_convert_attr(attr
);
388 if (pio
->alloc_flags
& POHMELFS_IO_OWN
) {
391 t
->data
= kmalloc(pio
->size
, GFP_NOIO
);
394 goto err_out_put_state
;
397 memcpy(t
->data
, pio
->data
, pio
->size
);
401 err
= pohmelfs_init_callbacks(t
, pio
);
403 goto err_out_put_state
;
408 pohmelfs_state_put(t
->st
);
410 pohmelfs_trans_free(t
);
415 int pohmelfs_send_buf(struct pohmelfs_io
*pio
)
417 struct pohmelfs_sb
*psb
= pohmelfs_sb(pio
->pi
->vfs_inode
.i_sb
);
423 for (i
= 0; i
< psb
->group_num
; ++i
) {
424 pio
->group_id
= psb
->groups
[i
];
426 err
= pohmelfs_send_buf_single(pio
, NULL
);
431 return (err_num
== psb
->group_num
) ? err
: 0;