Use column 3 to store inode information instead of saving it in directory. This fixes...
[pohmelfs.git] / fs / pohmelfs / trans.c
blob8a623fce06fc37847dff7f31edfbd19e3984889b
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"
10 static void pohmelfs_trans_free(struct pohmelfs_trans *t)
12 iput(t->inode);
14 kmem_cache_free(pohmelfs_trans_cache, t);
17 static void pohmelfs_trans_release(struct kref *kref)
19 struct pohmelfs_trans *t = container_of(kref, struct pohmelfs_trans, refcnt);
20 struct pohmelfs_inode *pi = pohmelfs_inode(t->inode);
22 pr_debug("pohmelfs: %s: trans freed: %lu, recv_offset: %llu, ino: %ld\n",
23 pohmelfs_dump_id(pi->id.id), t->trans, t->recv_offset, t->inode->i_ino);
25 if (t->cb.destroy)
26 t->cb.destroy(t);
28 pohmelfs_state_put(t->st);
30 kfree(t->data);
31 kfree(t->recv_data);
32 pohmelfs_trans_free(t);
35 void pohmelfs_trans_put(struct pohmelfs_trans *t)
37 kref_put(&t->refcnt, pohmelfs_trans_release);
40 struct pohmelfs_trans *pohmelfs_trans_alloc(struct inode *inode)
42 struct pohmelfs_trans *t;
43 int err;
45 t = kmem_cache_zalloc(pohmelfs_trans_cache, GFP_NOIO);
46 if (!t) {
47 err = -ENOMEM;
48 goto err_out_exit;
51 kref_init(&t->refcnt);
53 t->inode = igrab(inode);
54 if (!t->inode) {
55 err = -ENOENT;
56 goto err_out_free;
59 return t;
61 err_out_free:
62 kmem_cache_free(pohmelfs_trans_cache, t);
63 err_out_exit:
64 return ERR_PTR(err);
67 static int pohmelfs_buf_complete(struct pohmelfs_trans *t, struct pohmelfs_state *recv)
69 struct pohmelfs_inode *pi = pohmelfs_inode(t->inode);
70 struct dnet_cmd *cmd = &recv->cmd;
71 unsigned long long trans = cmd->trans & ~DNET_TRANS_REPLY;
73 pr_debug("pohmelfs: %s: trans complete: %llu, flags: %x\n",
74 pohmelfs_dump_id(pi->id.id), trans, cmd->flags);
76 return 0;
79 static int pohmelfs_buf_recv(struct pohmelfs_trans *t, struct pohmelfs_state *recv)
81 struct dnet_cmd *cmd = &recv->cmd;
82 int err;
84 if (!t->recv_data) {
85 t->recv_data = kmalloc(cmd->size, GFP_NOIO);
86 if (!t->recv_data) {
87 err = -ENOMEM;
88 goto err_out_exit;
91 t->recv_offset = 0;
94 err = pohmelfs_data_recv(recv, t->recv_data + t->recv_offset, cmd->size - t->recv_offset, MSG_DONTWAIT);
95 if (err < 0)
96 goto err_out_exit;
98 t->recv_offset += err;
99 err = 0;
101 err_out_exit:
102 return err;
105 static int pohmelfs_init_callbacks(struct pohmelfs_trans *t, struct pohmelfs_io *pio)
107 int err = 0;
108 struct pohmelfs_state *st = t->st;
110 t->priv = pio->priv;
111 t->cb = pio->cb;
113 if (!t->cb.complete)
114 t->cb.complete = pohmelfs_buf_complete;
116 if (!t->cb.recv_reply)
117 t->cb.recv_reply = pohmelfs_buf_recv;
119 if (t->cb.init) {
120 err = t->cb.init(t);
121 if (err)
122 goto err_out_exit;
125 pohmelfs_trans_insert(t);
127 pohmelfs_state_schedule(st);
128 pohmelfs_state_put(st);
130 err_out_exit:
131 return err;
134 int pohmelfs_send_io_group(struct pohmelfs_io *pio, int group)
136 struct pohmelfs_inode *pi = pio->pi;
137 struct inode *inode = &pi->vfs_inode;
138 struct pohmelfs_sb *psb = pohmelfs_sb(inode->i_sb);
139 struct pohmelfs_state *st;
140 struct pohmelfs_trans *t;
141 struct dnet_cmd *cmd;
142 struct dnet_attr *attr;
143 struct dnet_io_attr *io;
144 u64 iosize = pio->size;
145 u64 alloc_io_size = pio->size;
146 int err;
148 /* Dirty hack to prevent setting cmd/attr size to pio->size,
149 * since in read command we specify in io->size number bytes we want,
150 * and it should not be accounted in the packet we send to remote node
152 if (pio->cmd == DNET_CMD_READ)
153 alloc_io_size = 0;
155 t = pohmelfs_trans_alloc(inode);
156 if (IS_ERR(t)) {
157 err = PTR_ERR(t);
158 goto err_out_exit;
161 st = pohmelfs_state_lookup(psb, pio->id, group);
162 if (!st) {
163 err = -ENOENT;
164 goto err_out_free;
167 t->st = st;
170 * We already hold a reference grabbed in pohmelfs_state_lookup(), it is dropped when transaction is destroyed
171 * We have to have valid state pointer to schedule sending, but after transaction is inserted into state's list,
172 * it can be processed immediately and freed and grabbed reference pointer will dissapear.
174 pohmelfs_state_get(st);
176 cmd = &t->cmd.cmd;
177 attr = &t->cmd.attr;
178 io = &t->cmd.p.io;
180 dnet_setup_id(&cmd->id, group, pio->id->id);
181 cmd->flags = pio->cflags;
182 cmd->trans = t->trans = atomic_long_inc_return(&psb->trans);
183 cmd->size = alloc_io_size + sizeof(struct dnet_io_attr) + sizeof(struct dnet_attr);
185 attr->cmd = pio->cmd;
186 attr->size = alloc_io_size + sizeof(struct dnet_io_attr);
187 attr->flags = pio->aflags;
189 memcpy(io->id, pio->id->id, DNET_ID_SIZE);
190 memcpy(io->parent, pio->id->id, DNET_ID_SIZE);
191 io->flags = pio->ioflags;
192 io->size = iosize;
193 io->offset = pio->offset;
194 io->type = pio->type;
195 io->start = pio->start;
196 io->num = pio->num;
198 t->header_size = sizeof(struct dnet_cmd) + sizeof(struct dnet_attr) + sizeof(struct dnet_io_attr);
199 t->data_size = alloc_io_size;
201 dnet_convert_cmd(cmd);
202 dnet_convert_attr(attr);
203 dnet_convert_io_attr(io);
205 t->wctl = pio->wctl;
207 if (pio->data) {
208 if (pio->alloc_flags & POHMELFS_IO_OWN) {
209 t->data = pio->data;
210 } else {
211 t->data = kmalloc(alloc_io_size, GFP_NOIO);
212 if (!t->data) {
213 err = -ENOMEM;
214 goto err_out_put_state;
217 memcpy(t->data, pio->data, alloc_io_size);
221 err = pohmelfs_init_callbacks(t, pio);
222 if (err)
223 goto err_out_put_state;
226 return 0;
228 err_out_put_state:
229 pohmelfs_state_put(t->st);
230 err_out_free:
231 pohmelfs_trans_free(t);
232 err_out_exit:
233 return err;
236 int pohmelfs_send_io(struct pohmelfs_io *pio)
238 struct pohmelfs_sb *psb = pohmelfs_sb(pio->pi->vfs_inode.i_sb);
239 int i, err, err_num;
241 err = -ENOENT;
242 err_num = 0;
244 for (i = 0; i < psb->group_num; ++i) {
245 err = pohmelfs_send_io_group(pio, psb->groups[i]);
246 if (err)
247 err_num++;
250 return (err_num == psb->group_num) ? err : 0;
253 int pohmelfs_trans_insert(struct pohmelfs_trans *t)
255 struct pohmelfs_state *st = t->st;
257 mutex_lock(&st->trans_lock);
258 list_add_tail(&t->trans_entry, &st->trans_list);
259 mutex_unlock(&st->trans_lock);
261 return 0;
264 void pohmelfs_trans_remove(struct pohmelfs_trans *t)
266 struct pohmelfs_state *st = t->st;
268 mutex_lock(&st->trans_lock);
269 list_del(&t->trans_entry);
270 mutex_unlock(&st->trans_lock);
273 struct pohmelfs_trans *pohmelfs_trans_lookup(struct pohmelfs_state *st, struct dnet_cmd *cmd)
275 struct pohmelfs_trans *t, *found = NULL;
276 u64 trans = cmd->trans & ~DNET_TRANS_REPLY;
278 mutex_lock(&st->trans_lock);
279 list_for_each_entry(t, &st->sent_trans_list, trans_entry) {
280 if (trans == t->trans) {
281 found = t;
283 kref_get(&t->refcnt);
284 break;
287 mutex_unlock(&st->trans_lock);
289 return found;
292 int pohmelfs_send_buf_single(struct pohmelfs_io *pio, struct pohmelfs_state *st)
294 struct pohmelfs_inode *pi = pio->pi;
295 struct inode *inode = &pi->vfs_inode;
296 struct pohmelfs_sb *psb = pohmelfs_sb(inode->i_sb);
297 struct pohmelfs_trans *t;
298 struct dnet_cmd *cmd;
299 struct dnet_attr *attr;
300 int err;
302 t = pohmelfs_trans_alloc(inode);
303 if (IS_ERR(t)) {
304 err = PTR_ERR(t);
305 goto err_out_exit;
308 if (!st) {
309 st = pohmelfs_state_lookup(psb, pio->id, pio->group_id);
310 if (!st) {
311 err = -ENOENT;
312 goto err_out_free;
314 } else {
315 pohmelfs_state_get(st);
318 t->st = st;
319 pohmelfs_state_get(st);
321 cmd = &t->cmd.cmd;
322 attr = &t->cmd.attr;
324 dnet_setup_id(&cmd->id, st->group_id, pio->id->id);
325 cmd->flags = pio->cflags;
326 cmd->trans = t->trans = atomic_long_inc_return(&psb->trans);
327 cmd->size = pio->size + sizeof(struct dnet_attr);
329 attr->cmd = pio->cmd;
330 attr->size = pio->size;
331 attr->flags = pio->aflags;
333 t->header_size = sizeof(struct dnet_cmd) + sizeof(struct dnet_attr);
334 t->data_size = pio->size;
336 dnet_convert_cmd(cmd);
337 dnet_convert_attr(attr);
339 if (pio->data) {
340 if (pio->alloc_flags & POHMELFS_IO_OWN) {
341 t->data = pio->data;
342 } else {
343 t->data = kmalloc(pio->size, GFP_NOIO);
344 if (!t->data) {
345 err = -ENOMEM;
346 goto err_out_put_state;
349 memcpy(t->data, pio->data, pio->size);
353 err = pohmelfs_init_callbacks(t, pio);
354 if (err)
355 goto err_out_put_state;
357 return 0;
359 err_out_put_state:
360 pohmelfs_state_put(t->st);
361 err_out_free:
362 pohmelfs_trans_free(t);
363 err_out_exit:
364 return err;
367 int pohmelfs_send_buf(struct pohmelfs_io *pio)
369 struct pohmelfs_sb *psb = pohmelfs_sb(pio->pi->vfs_inode.i_sb);
370 int i, err, err_num;
372 err = -ENOENT;
373 err_num = 0;
375 for (i = 0; i < psb->group_num; ++i) {
376 pio->group_id = psb->groups[i];
378 err = pohmelfs_send_buf_single(pio, NULL);
379 if (err)
380 err_num++;
383 return (err_num == psb->group_num) ? err : 0;