Use dentry_path() to create full path to inode object
[pohmelfs.git] / fs / pohmelfs / trans.c
blob8fb9bf1e859249b49cebcaaaf94567e0fba98f17
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"
12 static void pohmelfs_trans_free(struct pohmelfs_trans *t)
14 iput(t->inode);
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,
26 t->inode->i_ino);
28 if (t->cb.destroy)
29 t->cb.destroy(t);
31 pohmelfs_state_put(t->st);
33 kfree(t->data);
34 kfree(t->recv_data);
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;
46 int err;
48 t = kmem_cache_zalloc(pohmelfs_trans_cache, GFP_NOIO);
49 if (!t) {
50 err = -ENOMEM;
51 goto err_out_exit;
54 kref_init(&t->refcnt);
56 t->inode = igrab(inode);
57 if (!t->inode) {
58 err = -ENOENT;
59 goto err_out_free;
62 return t;
64 err_out_free:
65 kmem_cache_free(pohmelfs_trans_cache, t);
66 err_out_exit:
67 return ERR_PTR(err);
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);
79 return 0;
82 static int pohmelfs_buf_recv(struct pohmelfs_trans *t, struct pohmelfs_state *recv)
84 struct dnet_cmd *cmd = &recv->cmd;
85 int err;
87 if (!t->recv_data) {
88 t->recv_data = kmalloc(cmd->size, GFP_NOIO);
89 if (!t->recv_data) {
90 err = -ENOMEM;
91 goto err_out_exit;
94 t->io_offset = 0;
97 err = pohmelfs_data_recv(recv, t->recv_data + t->io_offset, cmd->size - t->io_offset, MSG_DONTWAIT);
98 if (err < 0)
99 goto err_out_exit;
101 t->io_offset += err;
102 err = 0;
104 err_out_exit:
105 return err;
108 static int pohmelfs_init_callbacks(struct pohmelfs_trans *t, struct pohmelfs_io *pio)
110 int err = 0;
111 struct pohmelfs_state *st = t->st;
113 t->priv = pio->priv;
114 t->cb = pio->cb;
116 if (!t->cb.complete)
117 t->cb.complete = pohmelfs_buf_complete;
119 if (!t->cb.recv_reply)
120 t->cb.recv_reply = pohmelfs_buf_recv;
122 if (t->cb.init) {
123 err = t->cb.init(t);
124 if (err)
125 goto err_out_exit;
128 pohmelfs_trans_insert(t);
130 pohmelfs_state_schedule(st);
131 pohmelfs_state_put(st);
133 err_out_exit:
134 return err;
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;
149 int err;
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)
156 alloc_io_size = 0;
158 t = pohmelfs_trans_alloc(inode);
159 if (IS_ERR(t)) {
160 err = PTR_ERR(t);
161 goto err_out_exit;
164 st = pohmelfs_state_lookup(psb, pio->id, group, pio->size);
165 if (!st) {
166 err = -ENOENT;
167 goto err_out_free;
170 t->st = st;
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);
179 cmd = &t->cmd.cmd;
180 attr = &t->cmd.attr;
181 io = &t->cmd.p.io;
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;
195 io->size = iosize;
196 io->offset = pio->offset;
197 io->type = pio->type;
198 io->start = pio->start;
199 io->num = pio->num;
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);
208 t->wctl = pio->wctl;
210 if (pio->data) {
211 if (pio->alloc_flags & POHMELFS_IO_OWN) {
212 t->data = pio->data;
213 } else {
214 t->data = kmalloc(alloc_io_size, GFP_NOIO);
215 if (!t->data) {
216 err = -ENOMEM;
217 goto err_out_put_state;
220 memcpy(t->data, pio->data, alloc_io_size);
224 err = pohmelfs_init_callbacks(t, pio);
225 if (err)
226 goto err_out_put_state;
229 return 0;
231 err_out_put_state:
232 pohmelfs_state_put(t->st);
233 err_out_free:
234 pohmelfs_trans_free(t);
235 err_out_exit:
236 return err;
239 int pohmelfs_send_io(struct pohmelfs_io *pio)
241 struct pohmelfs_sb *psb = pohmelfs_sb(pio->pi->vfs_inode.i_sb);
242 int i, err, err_num;
244 err = -ENOENT;
245 err_num = 0;
247 for (i = 0; i < psb->group_num; ++i) {
248 err = pohmelfs_send_io_group(pio, psb->groups[i]);
249 if (err)
250 err_num++;
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);
264 return 0;
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;
286 int err = 0;
287 long cmp;
289 while (*n) {
290 parent = *n;
292 tmp = rb_entry(parent, struct pohmelfs_trans, trans_node);
294 cmp = pohmelfs_trans_cmp(tmp, t->trans);
295 if (cmp < 0)
296 n = &parent->rb_left;
297 else if (cmp > 0)
298 n = &parent->rb_right;
299 else {
300 err = -EEXIST;
301 goto err_out_exit;
305 rb_link_node(&t->trans_node, parent, n);
306 rb_insert_color(&t->trans_node, &st->trans_root);
308 err_out_exit:
309 return err;
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;
318 long cmp;
320 mutex_lock(&st->trans_lock);
321 while (n) {
322 t = rb_entry(n, struct pohmelfs_trans, trans_node);
324 cmp = pohmelfs_trans_cmp(t, trans);
325 if (cmp < 0) {
326 n = n->rb_left;
327 } else if (cmp > 0)
328 n = n->rb_right;
329 else {
330 found = t;
331 kref_get(&t->refcnt);
332 break;
335 mutex_unlock(&st->trans_lock);
337 return found;
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;
348 int err;
350 t = pohmelfs_trans_alloc(inode);
351 if (IS_ERR(t)) {
352 err = PTR_ERR(t);
353 goto err_out_exit;
356 if (!st) {
357 st = pohmelfs_state_lookup(psb, pio->id, pio->group_id, pio->size);
358 if (!st) {
359 err = -ENOENT;
360 goto err_out_free;
362 } else {
363 pohmelfs_state_get(st);
366 t->st = st;
367 pohmelfs_state_get(st);
369 cmd = &t->cmd.cmd;
370 attr = &t->cmd.attr;
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);
387 if (pio->data) {
388 if (pio->alloc_flags & POHMELFS_IO_OWN) {
389 t->data = pio->data;
390 } else {
391 t->data = kmalloc(pio->size, GFP_NOIO);
392 if (!t->data) {
393 err = -ENOMEM;
394 goto err_out_put_state;
397 memcpy(t->data, pio->data, pio->size);
401 err = pohmelfs_init_callbacks(t, pio);
402 if (err)
403 goto err_out_put_state;
405 return 0;
407 err_out_put_state:
408 pohmelfs_state_put(t->st);
409 err_out_free:
410 pohmelfs_trans_free(t);
411 err_out_exit:
412 return err;
415 int pohmelfs_send_buf(struct pohmelfs_io *pio)
417 struct pohmelfs_sb *psb = pohmelfs_sb(pio->pi->vfs_inode.i_sb);
418 int i, err, err_num;
420 err = -ENOENT;
421 err_num = 0;
423 for (i = 0; i < psb->group_num; ++i) {
424 pio->group_id = psb->groups[i];
426 err = pohmelfs_send_buf_single(pio, NULL);
427 if (err)
428 err_num++;
431 return (err_num == psb->group_num) ? err : 0;