Added ->mknod() callback support.
[pohmelfs.git] / fs / pohmelfs / dir.c
blob84b1a92de9e56594519a2c2b41facfd8f889348b
1 /*
2 * Copyright (C) 2011+ Evgeniy Polyakov <zbr@ioremap.net>
3 */
5 #include <linux/fs.h>
6 #include <linux/dcache.h>
7 #include <linux/quotaops.h>
9 #include "pohmelfs.h"
11 #define POHMELFS_LOOKUP_SCRIPT "pohmelfs_lookup.py"
12 #define POHMELFS_UNLINK_SCRIPT "pohmelfs_unlink.py"
13 #define POHMELFS_DATA_UNLINK_SCRIPT "pohmelfs_data_unlink.py"
14 #define POHMELFS_HARDLINK_SCRIPT "pohmelfs_hardlink.py"
15 #define POHMELFS_RENAME_SCRIPT "pohmelfs_rename.py"
16 #define POHMELFS_INODE_INFO_SCRIPT_INSERT "pohmelfs_inode_info_insert.py"
17 #define POHMELFS_READDIR_SCRIPT "pohmelfs_readdir.py"
18 #define POHMELFS_DENTRY_NAME_SCRIPT "pohmelfs_dentry_name="
20 static void pohmelfs_inode_dirty(struct pohmelfs_inode *parent, struct pohmelfs_inode *pi)
22 struct inode *inode = &pi->vfs_inode;
23 struct inode *dir = &parent->vfs_inode;
25 pi->parent_id = parent->id;
26 inode_init_owner(inode, dir, inode->i_mode);
28 inode->i_mtime = inode->i_ctime = CURRENT_TIME;
29 dir->i_mtime = CURRENT_TIME;
31 mark_inode_dirty(inode);
32 mark_inode_dirty(dir);
35 static int pohmelfs_send_inode_info_complete(struct pohmelfs_trans *t, struct pohmelfs_state *recv)
37 struct pohmelfs_inode *pi = pohmelfs_inode(t->inode);
38 struct pohmelfs_wait *wait = t->priv;
39 struct dnet_cmd *cmd = &recv->cmd;
40 unsigned long long trans = cmd->trans & ~DNET_TRANS_REPLY;
42 if (cmd->flags & DNET_FLAGS_MORE) {
43 if (cmd->status == 0 && cmd->size != sizeof(struct dnet_attr) + 2)
44 cmd->status = -EINVAL;
46 pr_debug("pohmelfs: %s: pohmelfs_send_inode_info_complete: %llu, cmd_size: %llu, flags: %x, status: %d\n",
47 pohmelfs_dump_id(pi->id.id), trans, cmd->size, cmd->flags, cmd->status);
49 if (!cmd->status)
50 wait->condition = 1;
51 else
52 wait->condition = cmd->status;
55 return 0;
58 static int pohmelfs_send_inode_info_init(struct pohmelfs_trans *t)
60 struct pohmelfs_wait *wait = t->priv;
62 pohmelfs_wait_get(wait);
63 return 0;
66 static void pohmelfs_send_inode_info_destroy(struct pohmelfs_trans *t)
68 struct pohmelfs_wait *wait = t->priv;
70 wake_up(&wait->wq);
71 pohmelfs_wait_put(wait);
74 static int pohmelfs_lookup_complete(struct pohmelfs_trans *t, struct pohmelfs_state *recv)
76 struct pohmelfs_inode *parent = pohmelfs_inode(t->inode);
77 struct pohmelfs_wait *wait = t->priv;
78 struct dnet_cmd *cmd = &recv->cmd;
79 unsigned long long trans = cmd->trans & ~DNET_TRANS_REPLY;
80 int err = cmd->status;
82 if (err)
83 goto err_out_exit;
85 if (cmd->flags & DNET_FLAGS_MORE) {
86 struct pohmelfs_inode_info *info;
87 struct pohmelfs_inode *pi;
89 if (cmd->size != sizeof(struct dnet_attr) + sizeof(struct pohmelfs_inode_info)) {
90 err = -ENOENT;
91 goto err_out_exit;
94 pr_debug("pohmelfs: %s: pohmelfs_lookup_complete: %llu, size: %llu, min size: %zu, flags: %x, status: %d\n",
95 pohmelfs_dump_id(parent->id.id), trans, cmd->size,
96 sizeof(struct dnet_attr) + sizeof(struct pohmelfs_inode_info), cmd->flags, cmd->status);
99 info = t->recv_data + sizeof(struct dnet_attr);
100 pohmelfs_convert_inode_info(info);
102 pi = pohmelfs_existing_inode(pohmelfs_sb(t->inode->i_sb), info);
103 if (IS_ERR(pi)) {
104 err = PTR_ERR(pi);
105 goto err_out_exit;
108 pi->parent_id = parent->id;
109 wait->ret = pi;
112 err_out_exit:
113 if (err)
114 wait->condition = err;
115 else
116 wait->condition = 1;
118 return 0;
121 int pohmelfs_send_script_request(struct pohmelfs_inode *parent, struct pohmelfs_script_req *req)
123 struct pohmelfs_sb *psb = pohmelfs_sb(parent->vfs_inode.i_sb);
124 struct pohmelfs_wait *wait;
125 struct pohmelfs_io *pio;
126 struct dnet_exec *e;
127 int script_len;
128 long ret;
129 int err;
131 /* 2 commas, \n and 0-byte, which is accounted in sizeof(string) */
132 script_len = sizeof(POHMELFS_DENTRY_NAME_SCRIPT) + req->obj_len + 3;
134 wait = pohmelfs_wait_alloc(parent);
135 if (!wait) {
136 err = -ENOMEM;
137 goto err_out_exit;
140 pio = kmem_cache_zalloc(pohmelfs_io_cache, GFP_NOIO);
141 if (!pio) {
142 err = -ENOMEM;
143 goto err_out_wait_put;
146 e = kmalloc(sizeof(struct dnet_exec) + req->script_namelen + script_len + req->binary_size, GFP_NOIO);
147 if (!e) {
148 err = -ENOMEM;
149 goto err_out_free_pio;
152 memset(e, 0, sizeof(struct dnet_exec));
154 snprintf(e->data, req->script_namelen + script_len, "%s%s'%s'\n", req->script_name, POHMELFS_DENTRY_NAME_SCRIPT, req->obj_name);
155 script_len--; /* do not include last 0-byte in the script */
157 memcpy(e->data + req->script_namelen + script_len, req->binary, req->binary_size);
159 e->type = DNET_EXEC_PYTHON_SCRIPT_NAME;
160 e->name_size = req->script_namelen;
161 e->script_size = script_len;
162 e->binary_size = req->binary_size;
163 dnet_convert_exec(e);
165 pio->pi = parent;
166 pio->id = req->id;
167 pio->group_id = req->group_id;
168 pio->cflags = DNET_FLAGS_NEED_ACK;
169 if (req->complete == pohmelfs_lookup_complete)
170 pio->cflags |= DNET_FLAGS_NOLOCK;
172 pio->cmd = DNET_CMD_EXEC;
173 pio->size = sizeof(struct dnet_exec) + req->script_namelen + script_len + req->binary_size;
174 pio->data = e;
175 pio->priv = wait;
176 pio->cb.init = pohmelfs_send_inode_info_init;
177 pio->cb.destroy = pohmelfs_send_inode_info_destroy;
178 pio->cb.complete = req->complete;
180 if (pio->group_id) {
181 err = pohmelfs_send_buf_single(pio, NULL);
182 } else {
183 err = pohmelfs_send_buf(pio);
185 if (err)
186 goto err_out_free;
188 if (req->sync) {
189 ret = wait_event_interruptible_timeout(wait->wq, wait->condition != 0, msecs_to_jiffies(psb->read_wait_timeout));
190 if (ret <= 0) {
191 err = ret;
192 if (ret == 0)
193 err = -ETIMEDOUT;
194 goto err_out_free;
197 if (wait->condition < 0)
198 err = wait->condition;
200 req->ret = wait->ret;
201 req->ret_cond = wait->condition;
205 int len = 6;
206 char parent_id_str[len*2+1];
208 pr_debug("pohmelfs: %.*s: %s: inode->id: %s, ino: %lu, object: %s, binary size: %d, ret: %p, condition: %d\n",
209 req->script_namelen, req->script_name,
210 pohmelfs_dump_id(req->id->id),
211 pohmelfs_dump_id_len_raw(parent->id.id, len, parent_id_str),
212 parent->vfs_inode.i_ino, req->obj_name, req->binary_size,
213 req->ret, req->ret_cond);
216 err_out_free:
217 kfree(e);
218 err_out_free_pio:
219 kmem_cache_free(pohmelfs_io_cache, pio);
220 err_out_wait_put:
221 pohmelfs_wait_put(wait);
222 err_out_exit:
223 return err;
226 int pohmelfs_send_inode_info(struct pohmelfs_inode *pi, struct dnet_raw_id *id, const char *sname, int len, int sync)
228 struct pohmelfs_inode_info_binary_package *bin;
229 struct pohmelfs_script_req req;
230 int err;
232 if (!len) {
233 err = -EINVAL;
234 goto err_out_exit;
237 bin = kmem_cache_alloc(pohmelfs_inode_info_binary_package_cache, GFP_NOIO);
238 if (!bin) {
239 err = -ENOMEM;
240 goto err_out_exit;
243 req.script_name = POHMELFS_INODE_INFO_SCRIPT_INSERT;
244 req.script_namelen = sizeof(POHMELFS_INODE_INFO_SCRIPT_INSERT) - 1; /* not including 0-byte */
246 req.obj_name = (char *)sname;
247 req.obj_len = len;
249 req.binary = bin;
250 req.binary_size = sizeof(struct pohmelfs_inode_info) + sizeof(struct dnet_raw_id);
252 req.group_id = 0;
253 req.id = id;
255 req.sync = sync;
257 memcpy(&bin->parent, id, sizeof(struct dnet_raw_id));
258 pohmelfs_fill_inode_info(&pi->vfs_inode, &bin->info);
259 bin->info.namelen = len;
261 pohmelfs_convert_inode_info(&bin->info);
263 req.complete = pohmelfs_send_inode_info_complete;
265 err = pohmelfs_send_script_request(pi, &req);
266 if (err)
267 goto err_out_free;
269 err_out_free:
270 kmem_cache_free(pohmelfs_inode_info_binary_package_cache, bin);
271 err_out_exit:
272 return err;
275 static int pohmelfs_create(struct inode *dir, struct dentry *dentry, int mode,
276 struct nameidata *nd)
278 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
279 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
280 struct pohmelfs_inode *pi;
281 int err;
283 pi = pohmelfs_new_inode(psb, mode);
284 if (IS_ERR(pi)) {
285 err = PTR_ERR(pi);
286 goto err_out_exit;
289 inode_inc_link_count(dir);
290 pohmelfs_inode_dirty(parent, pi);
292 err = pohmelfs_send_inode_info(pi, &pi->parent_id, dentry->d_name.name, dentry->d_name.len, 0);
293 if (err)
294 goto err_out_put;
296 pr_debug("pohmelfs: create: %s, ino: %lu, parent dir: %lu, object: %s\n",
297 pohmelfs_dump_id(pi->id.id), pi->vfs_inode.i_ino,
298 dir->i_ino, dentry->d_name.name);
301 * calling d_instantiate() implies that
302 * ->lookup() used d_splice_alias() with NULL inode
303 * when it failed to find requested object
305 d_instantiate(dentry, &pi->vfs_inode);
307 return 0;
309 err_out_put:
310 inode_dec_link_count(dir);
311 iput(&pi->vfs_inode);
312 err_out_exit:
313 return err;
316 static struct pohmelfs_inode *pohmelfs_lookup_group(struct inode *dir, struct dentry *dentry, int group_id)
318 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
319 struct pohmelfs_script_req req;
320 struct pohmelfs_inode *pi;
321 int err;
323 req.script_name = POHMELFS_LOOKUP_SCRIPT;
324 req.script_namelen = sizeof(POHMELFS_LOOKUP_SCRIPT) - 1; /* not including 0-byte */
326 req.obj_name = (char *)dentry->d_name.name;
327 req.obj_len = dentry->d_name.len;
329 req.binary = &parent->id;
330 req.binary_size = sizeof(struct dnet_raw_id);
332 req.id = &parent->id;
333 req.complete = pohmelfs_lookup_complete;
335 req.group_id = group_id;
336 req.sync = 1;
338 err = pohmelfs_send_script_request(parent, &req);
339 if (err)
340 goto err_out_exit;
342 pi = req.ret;
343 if (!pi) {
344 err = -ENOENT;
345 goto err_out_exit;
348 return pi;
350 err_out_exit:
351 pr_debug("pohmelfs: pohmelfs_lookup_group: %s: group: %d: parent ino: %lu, name: %s: %d\n",
352 pohmelfs_dump_id(parent->id.id), group_id, parent->vfs_inode.i_ino, dentry->d_name.name, err);
353 return ERR_PTR(err);
356 static struct dentry *pohmelfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
358 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
359 struct inode *inode = NULL;
360 struct pohmelfs_inode *pi;
361 int i, err = -ENOENT;
363 for (i = 0; i < psb->group_num; ++i) {
364 pi = pohmelfs_lookup_group(dir, dentry, psb->groups[i]);
365 if (IS_ERR(pi)) {
366 err = PTR_ERR(pi);
367 continue;
370 inode = &pi->vfs_inode;
371 err = 0;
372 break;
375 if (err && (err != -ENOENT) && (err != -EOPNOTSUPP))
376 return ERR_PTR(err);
378 return d_splice_alias(inode, dentry);
381 static int pohmelfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
383 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
384 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
385 struct pohmelfs_inode *pi;
386 int err;
388 inode_inc_link_count(dir);
390 pi = pohmelfs_new_inode(psb, mode | S_IFDIR);
391 if (IS_ERR(pi)) {
392 err = PTR_ERR(pi);
393 goto err_out_dir;
396 pohmelfs_inode_dirty(parent, pi);
398 d_instantiate(dentry, &pi->vfs_inode);
399 pr_debug("pohmelfs: mkdir: %s, ino: %lu, parent dir: %lu, object: %s, refcnt: %d\n",
400 pohmelfs_dump_id(pi->id.id), pi->vfs_inode.i_ino,
401 dir->i_ino, dentry->d_name.name, dentry->d_count);
403 return 0;
405 err_out_dir:
406 inode_dec_link_count(dir);
407 return err;
410 static int pohmelfs_unlink(struct inode *dir, struct dentry *dentry)
412 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
413 struct pohmelfs_inode *pi = pohmelfs_inode(dentry->d_inode);
414 struct pohmelfs_script_req req;
415 int err;
417 req.script_name = POHMELFS_UNLINK_SCRIPT;
418 req.script_namelen = sizeof(POHMELFS_UNLINK_SCRIPT) - 1; /* not including 0-byte */
420 req.obj_name = (char *)dentry->d_name.name;
421 req.obj_len = dentry->d_name.len;
423 req.binary = &parent->id;
424 req.binary_size = sizeof(struct dnet_raw_id);
426 req.group_id = 0;
427 req.id = &parent->id;
428 req.complete = pohmelfs_send_inode_info_complete;
430 req.sync = 0;
432 err = pohmelfs_send_script_request(parent, &req);
433 if (err)
434 return err;
436 req.script_name = POHMELFS_DATA_UNLINK_SCRIPT;
437 req.script_namelen = sizeof(POHMELFS_DATA_UNLINK_SCRIPT) - 1; /* not including 0-byte */
439 req.binary = &pi->id;
440 req.binary_size = sizeof(struct dnet_raw_id);
442 return pohmelfs_send_script_request(parent, &req);
445 static int pohmelfs_rmdir(struct inode *dir, struct dentry *dentry)
447 return pohmelfs_unlink(dir, dentry);
450 struct pohmelfs_rename_req {
451 struct dnet_raw_id old_dir_id;
452 struct dnet_raw_id new_dir_id;
453 int new_len;
454 char new_name[0];
455 } __attribute__ ((packed));
457 static int pohmelfs_rename(struct inode *old_dir, struct dentry *old_dentry,
458 struct inode *new_dir, struct dentry *new_dentry)
460 struct pohmelfs_inode *old_parent = pohmelfs_inode(old_dir);
461 struct pohmelfs_script_req req;
462 struct pohmelfs_rename_req *r;
463 int size = sizeof(struct pohmelfs_rename_req) + new_dentry->d_name.len;
464 int err;
466 r = kmalloc(size, GFP_NOIO);
467 if (!r) {
468 err = -ENOMEM;
469 goto err_out_exit;
472 r->old_dir_id = pohmelfs_inode(old_dir)->id;
473 r->new_dir_id = pohmelfs_inode(new_dir)->id;
474 r->new_len = cpu_to_le32(new_dentry->d_name.len);
475 memcpy(r->new_name, new_dentry->d_name.name, new_dentry->d_name.len);
477 req.script_name = POHMELFS_RENAME_SCRIPT;
478 req.script_namelen = sizeof(POHMELFS_RENAME_SCRIPT) - 1; /* not including 0-byte */
480 req.obj_name = (char *)old_dentry->d_name.name;
481 req.obj_len = old_dentry->d_name.len;
483 req.binary = r;
484 req.binary_size = size;
486 req.sync = 0;
487 req.group_id = 0;
488 req.id = &old_parent->id;
489 req.complete = pohmelfs_send_inode_info_complete;
491 err = pohmelfs_send_script_request(old_parent, &req);
492 if (err)
493 goto err_out_free;
495 err_out_free:
496 kfree(r);
497 err_out_exit:
498 return err;
501 static int pohmelfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
503 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
504 struct pohmelfs_inode *pi;
505 struct inode *inode;
506 unsigned len = strlen(symname)+1;
507 int err = 0;
509 pi = pohmelfs_new_inode(psb, S_IFLNK | S_IRWXUGO);
510 if (IS_ERR(pi)) {
511 err = PTR_ERR(pi);
512 goto err_out_exit;
515 pohmelfs_inode_dirty(pohmelfs_inode(dir), pi);
516 inode = &pi->vfs_inode;
518 err = page_symlink(inode, symname, len);
519 if (err)
520 goto err_out_put;
522 d_instantiate(dentry, inode);
524 return 0;
526 err_out_put:
527 iput(inode);
528 err_out_exit:
529 return err;
532 static int pohmelfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
534 struct inode *inode = old_dentry->d_inode;
535 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
536 struct pohmelfs_inode *pi = pohmelfs_inode(inode);
537 struct pohmelfs_script_req req;
538 int err;
540 dquot_initialize(dir);
542 inode->i_ctime = CURRENT_TIME_SEC;
543 inode_inc_link_count(inode);
544 ihold(inode);
546 pohmelfs_inode_dirty(parent, pi);
548 err = pohmelfs_send_inode_info(pi, &pi->parent_id, dentry->d_name.name, dentry->d_name.len, 1);
549 if (err) {
550 goto err_out_put;
553 req.script_name = POHMELFS_HARDLINK_SCRIPT;
554 req.script_namelen = sizeof(POHMELFS_HARDLINK_SCRIPT) - 1; /* not including 0-byte */
556 req.obj_name = (char *)dentry->d_name.name;
557 req.obj_len = dentry->d_name.len;
559 req.binary = &pi->id;
560 req.binary_size = sizeof(struct dnet_raw_id);
562 req.group_id = 0;
563 req.id = &pi->id;
564 req.complete = pohmelfs_send_inode_info_complete;
566 req.sync = 0;
568 err = pohmelfs_send_script_request(parent, &req);
569 if (err)
570 goto err_out_unlink;
572 d_instantiate(dentry, inode);
573 return 0;
575 err_out_unlink:
576 req.binary = &parent->id;
577 req.script_name = POHMELFS_UNLINK_SCRIPT;
578 req.script_namelen = sizeof(POHMELFS_UNLINK_SCRIPT) - 1; /* not including 0-byte */
579 pohmelfs_send_script_request(parent, &req);
581 err_out_put:
582 inode_dec_link_count(inode);
583 iput(inode);
584 return err;
587 static int pohmelfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
589 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
590 struct pohmelfs_inode *pi;
591 struct inode *inode;
592 int err;
594 if (!new_valid_dev(rdev))
595 return -EINVAL;
597 dquot_initialize(dir);
599 pi = pohmelfs_new_inode(psb, mode);
600 if (IS_ERR(pi)) {
601 err = PTR_ERR(pi);
602 goto err_out_exit;
605 inode = &pi->vfs_inode;
607 init_special_inode(inode, inode->i_mode, rdev);
608 inode->i_op = &pohmelfs_special_inode_operations;
610 pohmelfs_inode_dirty(pohmelfs_inode(dir), pi);
612 d_instantiate(dentry, inode);
613 return 0;
615 err_out_exit:
616 return err;
619 const struct inode_operations pohmelfs_dir_inode_operations = {
620 .create = pohmelfs_create,
621 .lookup = pohmelfs_lookup,
622 .mkdir = pohmelfs_mkdir,
623 .unlink = pohmelfs_unlink,
624 .rmdir = pohmelfs_rmdir,
625 .rename = pohmelfs_rename,
626 .symlink = pohmelfs_symlink,
627 .link = pohmelfs_link,
628 .mknod = pohmelfs_mknod,
631 struct pohmelfs_readdir_header {
632 char magic[8];
633 unsigned short version;
634 unsigned short chunk_size;
635 unsigned int chunk_num;
636 } __attribute__((packed));
638 static void pohmelfs_convert_readdir_header(struct pohmelfs_readdir_header *h)
640 h->version = dnet_bswap16(h->version);
641 h->chunk_size = dnet_bswap16(h->chunk_size);
642 h->chunk_num = dnet_bswap32(h->chunk_num);
645 struct pohmelfs_readdir_chunk_header {
646 unsigned short length;
647 unsigned short num;
648 unsigned short key_size;
649 unsigned short payload_size;
650 } __attribute__((packed));
652 static void pohmelfs_convert_readdir_chunk_header(struct pohmelfs_readdir_chunk_header *h)
654 h->length = dnet_bswap16(h->length);
655 h->num = dnet_bswap16(h->num);
656 h->key_size = dnet_bswap16(h->key_size);
657 h->payload_size = dnet_bswap16(h->payload_size);
660 /* Chunk size = maximum file name length + sizeof header + sizeof pohmelfs_inode_info
661 * It allows to store whole file entry on 1 chunk
663 #define POHMELFS_CHUNK_SIZE (NAME_MAX + 1 + sizeof(struct pohmelfs_inode_info) + sizeof(struct pohmelfs_readdir_chunk_header))
665 enum pohmelfs_readdir_warm_states {
666 POHMELFS_READDIR_WANT_HEADER = 1,
667 POHMELFS_READDIR_WANT_RECV_CHUNK,
670 struct pohmelfs_readdir_warm_priv {
671 struct pohmelfs_wait *wait;
673 struct kref refcnt;
675 struct pohmelfs_readdir_header header;
677 int state;
678 int read_total; /* number of inode offsets read or processed total (in all chunks summed) */
679 int read_in_inode; /* offset of name+pohmelfs_inode_info read in below buffer */
681 char chunk[POHMELFS_CHUNK_SIZE];
684 static void pohmelfs_readdir_warm_free(struct kref *kref)
686 struct pohmelfs_readdir_warm_priv *priv = container_of(kref, struct pohmelfs_readdir_warm_priv, refcnt);
688 if (priv->wait)
689 pohmelfs_wait_put(priv->wait);
690 kfree(priv);
693 static void pohmelfs_readdir_warm_destroy(struct pohmelfs_trans *t)
695 struct pohmelfs_readdir_warm_priv *priv = t->priv;
696 struct pohmelfs_wait *wait = priv->wait;
698 wake_up(&wait->wq);
699 kref_put(&priv->refcnt, pohmelfs_readdir_warm_free);
702 static int pohmelfs_readdir_warm_complete(struct pohmelfs_trans *t, struct pohmelfs_state *recv)
704 struct pohmelfs_inode *pi = pohmelfs_inode(t->inode);
705 struct pohmelfs_readdir_warm_priv *priv = t->priv;
706 struct pohmelfs_wait *wait = priv->wait;
707 struct dnet_cmd *cmd = &recv->cmd;
709 if (t->recv_data) {
710 kfree(t->recv_data);
711 t->recv_data = NULL;
714 pr_debug("pohmelfs: %s: comlete cmd size: %llu, recv offset: %llu, flags: %x\n",
715 pohmelfs_dump_id(pi->id.id), (unsigned long long)cmd->size, t->recv_offset, cmd->flags);
717 if (!(cmd->flags & DNET_FLAGS_MORE)) {
718 wait->condition = cmd->status;
719 if (!wait->condition)
720 wait->condition = 1;
723 return 0;
726 static int pohmelfs_dentry_add(struct pohmelfs_inode *parent, struct pohmelfs_inode *pi, char *name, int len)
728 struct inode *inode = &pi->vfs_inode;
729 struct inode *dir = &parent->vfs_inode;
730 struct dentry *dentry, *parent_dentry, *old;
731 struct qstr str;
732 int err;
734 str.name = name;
735 str.len = len;
736 str.hash = full_name_hash(str.name, str.len);
738 /* we do not need to hold dir->i_mutex here, don't we? :) */
739 parent_dentry = d_find_alias(dir);
740 if (!parent_dentry) {
741 err = -ENOENT;
742 goto err_out_exit;
745 dentry = d_lookup(parent_dentry, &str);
746 if (dentry) {
747 err = -EEXIST;
749 dput(dentry);
750 goto err_out_put_parent;
753 * if things are ok, dentry has 2 references -
754 * one in parent dir, and another its own,
755 * which we should drop
757 dentry = d_alloc(parent_dentry, &str);
758 if (!dentry) {
759 err = -ENOMEM;
760 goto err_out_put_parent;
763 old = d_splice_alias(inode, dentry);
764 if (unlikely(old)) {
765 dput(dentry);
766 dentry = old;
767 } else {
768 dput(dentry);
771 dput(parent_dentry);
772 return 0;
774 err_out_put_parent:
775 dput(parent_dentry);
776 err_out_exit:
777 return err;
780 static int pohmelfs_update_inode(struct pohmelfs_inode *parent, struct pohmelfs_inode_info *info, char *name)
782 struct pohmelfs_sb *psb = pohmelfs_sb(parent->vfs_inode.i_sb);
783 struct pohmelfs_inode *pi;
784 struct inode *inode;
785 int err = 0;
787 pi = pohmelfs_sb_inode_lookup(psb, &info->id);
788 if (pi) {
789 inode = &pi->vfs_inode;
790 pohmelfs_fill_inode(inode, info);
792 } else {
793 pi = pohmelfs_existing_inode(psb, info);
794 if (IS_ERR(pi)) {
795 err = PTR_ERR(pi);
796 goto err_out_exit;
798 inode = &pi->vfs_inode;
800 pi->parent_id = parent->id;
803 err = pohmelfs_dentry_add(parent, pi, name, info->namelen);
804 if (err)
805 iput(inode);
807 err_out_exit:
808 return err;
811 static int pohmelfs_readdir_warm_scratch(struct pohmelfs_trans *t, struct pohmelfs_state *recv)
813 struct pohmelfs_inode *pi = pohmelfs_inode(t->inode);
814 struct pohmelfs_readdir_warm_priv *priv = t->priv;
815 struct dnet_cmd *cmd = &recv->cmd;
816 int err = 0;
818 pr_debug("pohmelfs: %s: cmd size: %llu, recv offset: %llu\n",
819 pohmelfs_dump_id(pi->id.id), (unsigned long long)cmd->size, t->recv_offset);
820 while (t->recv_offset != cmd->size) {
821 long rest = cmd->size - t->recv_offset;
823 if (rest > POHMELFS_CHUNK_SIZE)
824 rest = POHMELFS_CHUNK_SIZE;
826 err = pohmelfs_recv(t, recv, priv->chunk, rest);
827 if (err < 0)
828 break;
830 err = 0;
832 pr_debug("pohmelfs: %s: done cmd size: %llu, recv offset: %llu\n",
833 pohmelfs_dump_id(pi->id.id), (unsigned long long)cmd->size, t->recv_offset);
835 return err;
838 static int pohmelfs_readdir_warm_recv_reply(struct pohmelfs_trans *t, struct pohmelfs_state *recv)
840 struct pohmelfs_inode *pi = pohmelfs_inode(t->inode);
841 struct pohmelfs_readdir_warm_priv *priv = t->priv;
842 struct dnet_cmd *cmd = &recv->cmd;
843 int attr_size = sizeof(struct dnet_attr) + sizeof(struct dnet_io_attr);
844 long old_recv_offset;
845 void *data;
846 int size;
847 int err = 0;
849 pr_debug("pohmelfs: %s: recv reply: cmd size: %llu, recv offset: %llu\n",
850 pohmelfs_dump_id(pi->id.id), (unsigned long long)cmd->size, t->recv_offset);
852 if (t->recv_offset < attr_size) {
853 data = &t->cmd.attr;
855 data += t->recv_offset;
856 size = attr_size - t->recv_offset;
858 err = pohmelfs_recv(t, recv, data, size);
859 if (err < 0)
860 goto err_out_exit;
862 if (t->recv_offset == attr_size) {
863 dnet_convert_attr(&t->cmd.attr);
864 dnet_convert_io_attr(&t->cmd.p.io);
866 pr_debug("pohmelfs: %d:%s: cmd size: %llu, io size: %llu\n",
867 cmd->id.group_id, pohmelfs_dump_id(cmd->id.id),
868 (unsigned long long)cmd->size, (unsigned long long)t->cmd.p.io.size);
870 priv->state = POHMELFS_READDIR_WANT_HEADER;
874 if (priv->state == POHMELFS_READDIR_WANT_HEADER) {
875 int header_size_to_read = sizeof(struct pohmelfs_readdir_header) - (t->recv_offset - attr_size);
877 data = &priv->header;
878 data += sizeof(struct pohmelfs_readdir_header) - header_size_to_read;
880 err = pohmelfs_recv(t, recv, data, header_size_to_read);
881 if (err < 0)
882 goto err_out_exit;
884 pohmelfs_convert_readdir_header(&priv->header);
885 priv->read_total = 0;
886 priv->read_in_inode = 0;
887 priv->state = POHMELFS_READDIR_WANT_RECV_CHUNK;
889 pr_debug("pohmelfs: %d:%s: header: header size: %d, version: %hd, chunk_size: %hd, chunk_num: %d\n",
890 cmd->id.group_id, pohmelfs_dump_id(cmd->id.id), header_size_to_read,
891 priv->header.version, priv->header.chunk_size, priv->header.chunk_num);
893 if (priv->header.chunk_size > POHMELFS_CHUNK_SIZE) {
894 err = -E2BIG;
895 goto err_out_exit;
899 get_new_chunk:
900 if (priv->read_total == priv->header.chunk_num) {
901 err = pohmelfs_readdir_warm_scratch(t, recv);
902 goto err_out_exit;
905 if (priv->state == POHMELFS_READDIR_WANT_RECV_CHUNK) {
906 data = priv->chunk + priv->read_in_inode;
907 size = POHMELFS_CHUNK_SIZE - priv->read_in_inode;
909 old_recv_offset = t->recv_offset;
911 err = pohmelfs_recv(t, recv, data, size);
912 if (err < 0)
913 goto err_out_exit;
915 priv->read_in_inode += t->recv_offset - old_recv_offset;
917 if (priv->read_in_inode == POHMELFS_CHUNK_SIZE) {
918 struct pohmelfs_readdir_chunk_header *chunk_header;
919 struct pohmelfs_inode_info *info;
920 char *filename;
922 priv->read_in_inode = 0;
923 priv->read_total++;
925 chunk_header = (struct pohmelfs_readdir_chunk_header *)priv->chunk;
926 pohmelfs_convert_readdir_chunk_header(chunk_header);
929 * Here we assume that record always fits in 1 chunk.
930 * In future this code should be changed to read several chunks
931 * and concatenate it to build continous buffer for
932 * file name and pohmelfs_inode_info structure
935 info = (struct pohmelfs_inode_info *)(priv->chunk + sizeof(struct pohmelfs_readdir_chunk_header) + chunk_header->key_size);
936 pohmelfs_convert_inode_info(info);
938 filename = (char *)(priv->chunk + sizeof(struct pohmelfs_readdir_chunk_header));
940 err = pohmelfs_update_inode(priv->wait->pi, info, filename);
941 pr_debug("pohmelfs: %d:%s: inode: %llu, namelen: %d, name: %.*s: %d\n",
942 cmd->id.group_id, pohmelfs_dump_id(info->id.id), (unsigned long long)info->ino,
943 info->namelen, info->namelen, filename, err);
944 } else {
945 err = -EAGAIN;
946 goto err_out_exit;
949 if ((priv->read_total < priv->header.chunk_num) && (t->recv_offset < cmd->size))
950 goto get_new_chunk;
953 return 0;
955 err_out_exit:
956 return err;
959 static int pohmelfs_readdir_warm_init(struct pohmelfs_trans *t)
961 struct pohmelfs_readdir_warm_priv *priv = t->priv;
963 kref_get(&priv->refcnt);
964 return 0;
967 static int pohmelfs_warm_dir_group(struct inode *dir, int group_id)
969 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
970 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
971 struct pohmelfs_io *io;
972 struct pohmelfs_readdir_warm_priv *priv;
973 struct pohmelfs_wait *wait;
974 long ret;
975 int err;
977 io = kmem_cache_zalloc(pohmelfs_io_cache, GFP_NOIO);
978 if (!io) {
979 err = -ENOMEM;
980 goto err_out_exit;
983 priv = kzalloc(sizeof(struct pohmelfs_readdir_warm_priv), GFP_NOIO);
984 if (!priv) {
985 err = -ENOMEM;
986 goto err_out_free;
989 kref_init(&priv->refcnt);
991 wait = pohmelfs_wait_alloc(parent);
992 if (!wait) {
993 err = -ENOMEM;
994 goto err_out_put;
997 priv->wait = wait;
999 io->pi = parent;
1000 io->id = &parent->id;
1001 io->cflags = DNET_FLAGS_NEED_ACK | DNET_FLAGS_NOLOCK;
1002 io->cmd = DNET_CMD_READ;
1003 io->cb.recv_reply = pohmelfs_readdir_warm_recv_reply;
1004 io->cb.complete = pohmelfs_readdir_warm_complete;
1005 io->cb.destroy = pohmelfs_readdir_warm_destroy;
1006 io->cb.init = pohmelfs_readdir_warm_init;
1007 io->priv = priv;
1009 err = pohmelfs_send_io_group(io, group_id);
1010 if (err)
1011 goto err_out_put;
1013 /* destruction callback will drop reference */
1014 ret = wait_event_interruptible_timeout(wait->wq, wait->condition != 0, msecs_to_jiffies(psb->read_wait_timeout));
1015 if (ret <= 0) {
1016 err = ret;
1017 if (ret == 0)
1018 err = -ETIMEDOUT;
1019 goto err_out_put;
1022 if (wait->condition < 0) {
1023 err = wait->condition;
1024 goto err_out_put;
1027 /* drop the reference we grabbed at creation time */
1028 kref_put(&priv->refcnt, pohmelfs_readdir_warm_free);
1029 kmem_cache_free(pohmelfs_io_cache, io);
1030 return 0;
1032 err_out_put:
1033 kref_put(&priv->refcnt, pohmelfs_readdir_warm_free);
1034 err_out_free:
1035 kmem_cache_free(pohmelfs_io_cache, io);
1036 err_out_exit:
1037 return err;
1040 static int pohmelfs_warm_dir(struct inode *dir)
1042 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
1043 int i, err = -ENOENT;
1045 for (i = 0; i < psb->group_num; ++i) {
1046 err = pohmelfs_warm_dir_group(dir, psb->groups[i]);
1047 if (err)
1048 continue;
1050 return 0;
1053 return err;
1056 struct pohmelfs_dentry {
1057 uint64_t ino;
1058 char type;
1059 char len;
1060 short pad0;
1061 int pad1;
1062 char name[0];
1063 } __attribute__ ((packed));
1065 static int pohmelfs_readdir_complete(struct pohmelfs_trans *t, struct pohmelfs_state *recv)
1067 struct pohmelfs_inode *pi = pohmelfs_inode(t->inode);
1068 struct pohmelfs_wait *wait = t->priv;
1069 struct dnet_cmd *cmd = &recv->cmd;
1071 pr_debug("pohmelfs: %s: readdir comlete: cmd size: %llu, recv offset: %llu, flags: %x\n",
1072 pohmelfs_dump_id(pi->id.id), (unsigned long long)cmd->size, t->recv_offset, cmd->flags);
1074 if (cmd->flags & DNET_FLAGS_MORE) {
1075 if (cmd->size > sizeof(struct dnet_attr)) {
1076 wait->ret = t->recv_data;
1077 wait->condition = cmd->size;
1079 t->recv_data = NULL;
1081 } else {
1082 if (!wait->condition) {
1083 wait->condition = cmd->status;
1084 if (!wait->condition)
1085 wait->condition = 1;
1089 return 0;
1092 static int pohmelfs_readdir_process(void *data, int size, struct file *filp, void *dirent, filldir_t filldir)
1094 int err = 0;
1096 while (size > 0) {
1097 struct pohmelfs_dentry *d = data;
1099 if (size < sizeof(struct pohmelfs_dentry)) {
1100 err = -EINVAL;
1101 break;
1104 if (size < d->len) {
1105 err = -EINVAL;
1106 break;
1109 err = filldir(dirent, d->name, d->len, filp->f_pos, le64_to_cpu(d->ino), d->type);
1110 if (err)
1111 break;
1113 filp->f_pos++;
1114 size -= sizeof(struct pohmelfs_dentry) + d->len;
1115 data += sizeof(struct pohmelfs_dentry) + d->len;
1118 return err;
1121 struct pohmelfs_readdir {
1122 struct dnet_raw_id id;
1123 int max_size;
1124 int fpos;
1127 static int pohmelfs_readdir_group(int group_id, struct file *filp, void *dirent, filldir_t filldir)
1129 struct dentry *dentry = filp->f_path.dentry;
1130 struct inode *dir = dentry->d_inode;
1131 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
1132 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
1133 struct pohmelfs_readdir rd;
1134 struct pohmelfs_script_req req;
1135 void *data;
1136 int size;
1137 int err;
1139 req.script_name = POHMELFS_READDIR_SCRIPT;
1140 req.script_namelen = sizeof(POHMELFS_READDIR_SCRIPT) - 1; /* not including 0-byte */
1142 req.obj_name = (char *)dentry->d_name.name;
1143 req.obj_len = dentry->d_name.len;
1145 rd.id = parent->id;
1146 rd.max_size = psb->readdir_allocation * PAGE_SIZE - sizeof(struct dnet_attr); /* cmd->size should fit one page */
1147 rd.fpos = filp->f_pos;
1149 req.binary = &rd;
1150 req.binary_size = sizeof(struct pohmelfs_readdir);
1152 req.id = &parent->id;
1153 req.complete = pohmelfs_readdir_complete;
1155 req.group_id = group_id;
1156 req.sync = 1;
1158 err = pohmelfs_send_script_request(parent, &req);
1159 if (err < 0)
1160 goto err_out_exit;
1162 data = req.ret;
1163 size = req.ret_cond;
1164 if (!data || !size) {
1165 err = -ENOENT;
1166 goto err_out_exit;
1169 err = pohmelfs_readdir_process(data + sizeof(struct dnet_attr), size - sizeof(struct dnet_attr), filp, dirent, filldir);
1171 kfree(data);
1173 err_out_exit:
1174 return err;
1177 static int pohmelfs_dir_open(struct inode *dir, struct file *filp)
1179 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
1180 struct pohmelfs_inode *pi = pohmelfs_inode(dir);
1181 struct dentry *dentry = filp->f_path.dentry;
1183 if (get_seconds() < pi->update + psb->sync_timeout)
1184 return dcache_dir_open(dir, filp);
1186 if (list_empty(&dentry->d_subdirs)) {
1187 return dcache_dir_open(dir, filp);
1188 } else {
1189 filp->f_pos = 0;
1191 return 0;
1194 static int pohmelfs_dir_close(struct inode *inode, struct file *filp)
1196 if (filp->private_data)
1197 return dcache_dir_close(inode, filp);
1198 return 0;
1201 static int pohmelfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
1203 struct dentry *dentry = filp->f_path.dentry;
1204 struct inode *dir = dentry->d_inode;
1205 struct pohmelfs_inode *pi = pohmelfs_inode(dir);
1206 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
1207 int i, err = -ENOENT;
1209 if (filp->private_data) {
1210 if (get_seconds() > pi->update + psb->sync_timeout) {
1211 err = pohmelfs_warm_dir(dir);
1212 if (err)
1213 return err;
1215 pi->update = get_seconds();
1218 return dcache_readdir(filp, dirent, filldir);
1221 for (i = 0; i < psb->group_num; ++i) {
1222 err = pohmelfs_readdir_group(psb->groups[i], filp, dirent, filldir);
1223 if (err)
1224 continue;
1226 return 0;
1229 return err;
1232 const struct file_operations pohmelfs_dir_fops = {
1233 .open = pohmelfs_dir_open,
1234 .release = pohmelfs_dir_close,
1235 .read = generic_read_dir,
1236 .readdir = pohmelfs_readdir,