2 * Copyright (C) 2011+ Evgeniy Polyakov <zbr@ioremap.net>
5 #include <linux/slab.h>
6 #include <linux/workqueue.h>
10 static void pohmelfs_trans_free(struct pohmelfs_trans
*t
)
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
);
28 pohmelfs_state_put(t
->st
);
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
;
45 t
= kmem_cache_zalloc(pohmelfs_trans_cache
, GFP_NOIO
);
51 kref_init(&t
->refcnt
);
53 t
->inode
= igrab(inode
);
62 kmem_cache_free(pohmelfs_trans_cache
, t
);
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
);
79 static int pohmelfs_buf_recv(struct pohmelfs_trans
*t
, struct pohmelfs_state
*recv
)
81 struct dnet_cmd
*cmd
= &recv
->cmd
;
85 t
->recv_data
= kmalloc(cmd
->size
, GFP_NOIO
);
94 err
= pohmelfs_data_recv(recv
, t
->recv_data
+ t
->recv_offset
, cmd
->size
- t
->recv_offset
, MSG_DONTWAIT
);
98 t
->recv_offset
+= err
;
105 static int pohmelfs_init_callbacks(struct pohmelfs_trans
*t
, struct pohmelfs_io
*pio
)
108 struct pohmelfs_state
*st
= t
->st
;
114 t
->cb
.complete
= pohmelfs_buf_complete
;
116 if (!t
->cb
.recv_reply
)
117 t
->cb
.recv_reply
= pohmelfs_buf_recv
;
125 pohmelfs_trans_insert(t
);
127 pohmelfs_state_schedule(st
);
128 pohmelfs_state_put(st
);
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
;
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
)
155 t
= pohmelfs_trans_alloc(inode
);
161 st
= pohmelfs_state_lookup(psb
, pio
->id
, group
);
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
);
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
;
193 io
->offset
= pio
->offset
;
194 io
->type
= pio
->type
;
195 io
->start
= pio
->start
;
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
);
208 if (pio
->alloc_flags
& POHMELFS_IO_OWN
) {
211 t
->data
= kmalloc(alloc_io_size
, GFP_NOIO
);
214 goto err_out_put_state
;
217 memcpy(t
->data
, pio
->data
, alloc_io_size
);
221 err
= pohmelfs_init_callbacks(t
, pio
);
223 goto err_out_put_state
;
229 pohmelfs_state_put(t
->st
);
231 pohmelfs_trans_free(t
);
236 int pohmelfs_send_io(struct pohmelfs_io
*pio
)
238 struct pohmelfs_sb
*psb
= pohmelfs_sb(pio
->pi
->vfs_inode
.i_sb
);
244 for (i
= 0; i
< psb
->group_num
; ++i
) {
245 err
= pohmelfs_send_io_group(pio
, psb
->groups
[i
]);
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
);
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
) {
283 kref_get(&t
->refcnt
);
287 mutex_unlock(&st
->trans_lock
);
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
;
302 t
= pohmelfs_trans_alloc(inode
);
309 st
= pohmelfs_state_lookup(psb
, pio
->id
, pio
->group_id
);
315 pohmelfs_state_get(st
);
319 pohmelfs_state_get(st
);
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
);
340 if (pio
->alloc_flags
& POHMELFS_IO_OWN
) {
343 t
->data
= kmalloc(pio
->size
, GFP_NOIO
);
346 goto err_out_put_state
;
349 memcpy(t
->data
, pio
->data
, pio
->size
);
353 err
= pohmelfs_init_callbacks(t
, pio
);
355 goto err_out_put_state
;
360 pohmelfs_state_put(t
->st
);
362 pohmelfs_trans_free(t
);
367 int pohmelfs_send_buf(struct pohmelfs_io
*pio
)
369 struct pohmelfs_sb
*psb
= pohmelfs_sb(pio
->pi
->vfs_inode
.i_sb
);
375 for (i
= 0; i
< psb
->group_num
; ++i
) {
376 pio
->group_id
= psb
->groups
[i
];
378 err
= pohmelfs_send_buf_single(pio
, NULL
);
383 return (err_num
== psb
->group_num
) ? err
: 0;