Turn on inode info prefetch
[pohmelfs.git] / fs / pohmelfs / dir.c
blob0ce3ee391dec82e1c409b2a8f942f2d86cb90304
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_dentry_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_dentry_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;
53 wake_up(&wait->wq);
56 return 0;
59 static int pohmelfs_send_inode_info_init(struct pohmelfs_trans *t)
61 struct pohmelfs_wait *wait = t->priv;
63 pohmelfs_wait_get(wait);
64 return 0;
67 static void pohmelfs_send_inode_info_destroy(struct pohmelfs_trans *t)
69 struct pohmelfs_wait *wait = t->priv;
71 wake_up(&wait->wq);
72 pohmelfs_wait_put(wait);
75 static int pohmelfs_lookup_complete(struct pohmelfs_trans *t, struct pohmelfs_state *recv)
77 struct pohmelfs_inode *parent = pohmelfs_inode(t->inode);
78 struct pohmelfs_wait *wait = t->priv;
79 struct dnet_cmd *cmd = &recv->cmd;
80 unsigned long long trans = cmd->trans & ~DNET_TRANS_REPLY;
81 int err = cmd->status;
83 if (err)
84 goto err_out_exit;
86 if (cmd->flags & DNET_FLAGS_MORE) {
87 struct pohmelfs_sb *psb = pohmelfs_sb(t->inode->i_sb);
88 struct pohmelfs_inode_info *info;
89 struct pohmelfs_inode *pi;
91 if (cmd->size != sizeof(struct dnet_attr) + sizeof(struct pohmelfs_inode_info)) {
92 err = -ENOENT;
93 goto err_out_exit;
96 pr_debug("pohmelfs: %s: pohmelfs_lookup_complete: %llu, size: %llu, min size: %zu, flags: %x, status: %d\n",
97 pohmelfs_dump_id(parent->id.id), trans, cmd->size,
98 sizeof(struct dnet_attr) + sizeof(struct pohmelfs_inode_info), cmd->flags, cmd->status);
101 info = t->recv_data + sizeof(struct dnet_attr);
102 pohmelfs_convert_inode_info(info);
104 pi = pohmelfs_existing_inode(psb, info);
105 if (IS_ERR(pi)) {
106 err = PTR_ERR(pi);
108 if (err != -EEXIST)
109 goto err_out_exit;
111 err = 0;
112 pi = pohmelfs_sb_inode_lookup(psb, &info->id);
113 if (!pi) {
114 err = -ENOENT;
115 goto err_out_exit;
118 pohmelfs_fill_inode(&pi->vfs_inode, info);
121 pi->parent_id = parent->id;
122 wait->ret = pi;
125 err_out_exit:
126 if (err)
127 wait->condition = err;
128 else
129 wait->condition = 1;
130 wake_up(&wait->wq);
132 return 0;
135 static int pohmelfs_readdir_complete(struct pohmelfs_trans *t, struct pohmelfs_state *recv);
137 int pohmelfs_send_script_request(struct pohmelfs_inode *parent, struct pohmelfs_script_req *req)
139 struct pohmelfs_sb *psb = pohmelfs_sb(parent->vfs_inode.i_sb);
140 struct pohmelfs_wait *wait;
141 struct pohmelfs_io *pio;
142 struct dnet_exec *e;
143 int script_len;
144 long ret;
145 int err;
147 /* 2 commas, \n and 0-byte, which is accounted in sizeof(string) */
148 script_len = sizeof(POHMELFS_DENTRY_NAME_SCRIPT) + req->obj_len + 3;
150 wait = pohmelfs_wait_alloc(parent);
151 if (!wait) {
152 err = -ENOMEM;
153 goto err_out_exit;
156 pio = kmem_cache_zalloc(pohmelfs_io_cache, GFP_NOIO);
157 if (!pio) {
158 err = -ENOMEM;
159 goto err_out_wait_put;
162 e = kmalloc(sizeof(struct dnet_exec) + req->script_namelen + script_len + req->binary_size, GFP_NOIO);
163 if (!e) {
164 err = -ENOMEM;
165 goto err_out_free_pio;
168 memset(e, 0, sizeof(struct dnet_exec));
170 snprintf(e->data, req->script_namelen + script_len, "%s%s'%s'\n", req->script_name, POHMELFS_DENTRY_NAME_SCRIPT, req->obj_name);
171 script_len--; /* do not include last 0-byte in the script */
173 memcpy(e->data + req->script_namelen + script_len, req->binary, req->binary_size);
175 e->type = DNET_EXEC_PYTHON_SCRIPT_NAME;
176 e->name_size = req->script_namelen;
177 e->script_size = script_len;
178 e->binary_size = req->binary_size;
179 dnet_convert_exec(e);
181 pio->pi = parent;
182 pio->id = req->id;
183 pio->group_id = req->group_id;
184 pio->cflags = DNET_FLAGS_NEED_ACK;
185 if ((req->complete == pohmelfs_lookup_complete) || (req->complete == pohmelfs_readdir_complete))
186 pio->cflags |= DNET_FLAGS_NOLOCK;
188 pio->cmd = DNET_CMD_EXEC;
189 pio->size = sizeof(struct dnet_exec) + req->script_namelen + script_len + req->binary_size;
190 pio->data = e;
191 pio->priv = wait;
192 pio->cb.init = pohmelfs_send_inode_info_init;
193 pio->cb.destroy = pohmelfs_send_inode_info_destroy;
194 pio->cb.complete = req->complete;
196 if (pio->group_id) {
197 err = pohmelfs_send_buf_single(pio, NULL);
198 } else {
199 err = pohmelfs_send_buf(pio);
201 if (err)
202 goto err_out_free;
204 if (req->sync) {
205 ret = wait_event_interruptible_timeout(wait->wq, wait->condition != 0, msecs_to_jiffies(psb->read_wait_timeout));
206 if (ret <= 0) {
207 err = ret;
208 if (ret == 0)
209 err = -ETIMEDOUT;
210 goto err_out_free;
213 if (wait->condition < 0)
214 err = wait->condition;
216 req->ret = wait->ret;
217 req->ret_cond = wait->condition;
221 int len = 6;
222 char parent_id_str[len*2+1];
224 pr_debug("pohmelfs: %.*s: %s: inode->id: %s, ino: %lu, object: %s, binary size: %d, ret: %p, condition: %d\n",
225 req->script_namelen, req->script_name,
226 pohmelfs_dump_id(req->id->id),
227 pohmelfs_dump_id_len_raw(parent->id.id, len, parent_id_str),
228 parent->vfs_inode.i_ino, req->obj_name, req->binary_size,
229 req->ret, req->ret_cond);
232 err_out_free:
233 kfree(e);
234 err_out_free_pio:
235 kmem_cache_free(pohmelfs_io_cache, pio);
236 err_out_wait_put:
237 pohmelfs_wait_put(wait);
238 err_out_exit:
239 return err;
242 int pohmelfs_send_dentry(struct pohmelfs_inode *pi, struct dnet_raw_id *id, const char *sname, int len, int sync)
244 struct inode *inode = &pi->vfs_inode;
245 struct pohmelfs_script_req req;
246 struct pohmelfs_dentry *pd;
247 int err;
249 if (!len) {
250 err = -EINVAL;
251 goto err_out_exit;
254 pd = kmem_cache_alloc(pohmelfs_dentry_cache, GFP_NOIO);
255 if (!pd) {
256 err = -ENOMEM;
257 goto err_out_exit;
260 pd->parent_id = *id;
261 pd->disk.id = pi->id;
262 pd->disk.ino = cpu_to_le64(pi->vfs_inode.i_ino);
263 pd->disk.type = (pi->vfs_inode.i_mode >> 12) & 15;
264 pd->disk.len = len;
266 req.id = id;
268 req.script_name = POHMELFS_INODE_INFO_SCRIPT_INSERT;
269 req.script_namelen = sizeof(POHMELFS_INODE_INFO_SCRIPT_INSERT) - 1; /* not including 0-byte */
271 req.obj_name = (char *)sname;
272 req.obj_len = len;
274 req.binary = pd;
275 req.binary_size = sizeof(struct pohmelfs_dentry);
277 req.group_id = 0;
278 req.id = id;
280 req.sync = sync;
281 req.complete = pohmelfs_send_dentry_complete;
283 err = pohmelfs_send_script_request(pi, &req);
284 if (err)
285 goto err_out_free;
287 err = inode->i_sb->s_op->write_inode(inode, NULL);
289 err_out_free:
290 kmem_cache_free(pohmelfs_dentry_cache, pd);
291 err_out_exit:
292 return err;
295 static int pohmelfs_create(struct inode *dir, struct dentry *dentry, int mode,
296 struct nameidata *nd)
298 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
299 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
300 struct pohmelfs_inode *pi;
301 int err;
303 pi = pohmelfs_new_inode(psb, mode);
304 if (IS_ERR(pi)) {
305 err = PTR_ERR(pi);
306 goto err_out_exit;
309 inode_inc_link_count(dir);
312 * calling d_instantiate() implies that
313 * ->lookup() used d_splice_alias() with NULL inode
314 * when it failed to find requested object
316 d_instantiate(dentry, &pi->vfs_inode);
317 if (psb->http_compat)
318 pohmelfs_http_compat_id(pi);
319 pohmelfs_inode_dirty(parent, pi);
321 err = pohmelfs_send_dentry(pi, &pi->parent_id, dentry->d_name.name, dentry->d_name.len, 0);
322 if (err)
323 goto err_out_put;
325 pr_debug("pohmelfs: create: %s, ino: %lu, parent dir: %lu, object: %s\n",
326 pohmelfs_dump_id(pi->id.id), pi->vfs_inode.i_ino,
327 dir->i_ino, dentry->d_name.name);
329 return 0;
331 err_out_put:
332 inode_dec_link_count(dir);
333 iput(&pi->vfs_inode);
334 d_instantiate(dentry, NULL);
335 err_out_exit:
336 return err;
339 static struct pohmelfs_inode *pohmelfs_lookup_group(struct inode *dir, struct dentry *dentry, int group_id)
341 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
342 struct pohmelfs_script_req req;
343 struct pohmelfs_inode *pi;
344 int err;
346 req.script_name = POHMELFS_LOOKUP_SCRIPT;
347 req.script_namelen = sizeof(POHMELFS_LOOKUP_SCRIPT) - 1; /* not including 0-byte */
349 req.obj_name = (char *)dentry->d_name.name;
350 req.obj_len = dentry->d_name.len;
352 req.binary = &parent->id;
353 req.binary_size = sizeof(struct dnet_raw_id);
355 req.id = &parent->id;
356 req.complete = pohmelfs_lookup_complete;
358 req.group_id = group_id;
359 req.sync = 1;
361 err = pohmelfs_send_script_request(parent, &req);
362 if (err)
363 goto err_out_exit;
365 pi = req.ret;
366 if (!pi) {
367 err = -ENOENT;
368 goto err_out_exit;
371 return pi;
373 err_out_exit:
374 pr_debug("pohmelfs: pohmelfs_lookup_group: %s: group: %d: parent ino: %lu, name: %s: %d\n",
375 pohmelfs_dump_id(parent->id.id), group_id, parent->vfs_inode.i_ino, dentry->d_name.name, err);
376 return ERR_PTR(err);
379 static struct dentry *pohmelfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
381 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
382 struct inode *inode = NULL;
383 struct pohmelfs_inode *pi;
384 int i, err = -ENOENT;
386 for (i = 0; i < psb->group_num; ++i) {
387 pi = pohmelfs_lookup_group(dir, dentry, psb->groups[i]);
388 if (IS_ERR(pi)) {
389 err = PTR_ERR(pi);
390 continue;
393 inode = &pi->vfs_inode;
394 err = 0;
395 break;
398 if (err && (err != -ENOENT) && (err != -EOPNOTSUPP))
399 return ERR_PTR(err);
401 return d_splice_alias(inode, dentry);
404 static int pohmelfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
406 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
407 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
408 struct pohmelfs_inode *pi;
409 int err;
411 inode_inc_link_count(dir);
413 pi = pohmelfs_new_inode(psb, mode | S_IFDIR);
414 if (IS_ERR(pi)) {
415 err = PTR_ERR(pi);
416 goto err_out_dir;
419 d_instantiate(dentry, &pi->vfs_inode);
420 if (psb->http_compat)
421 pohmelfs_http_compat_id(pi);
422 pohmelfs_inode_dirty(parent, pi);
424 err = pohmelfs_send_dentry(pi, &pi->parent_id, dentry->d_name.name, dentry->d_name.len, 0);
425 if (err)
426 goto err_out_put;
428 pr_debug("pohmelfs: mkdir: %s, ino: %lu, parent dir: %lu, object: %s, refcnt: %d\n",
429 pohmelfs_dump_id(pi->id.id), pi->vfs_inode.i_ino,
430 dir->i_ino, dentry->d_name.name, dentry->d_count);
431 return 0;
433 err_out_put:
434 iput(&pi->vfs_inode);
435 d_instantiate(dentry, NULL);
436 err_out_dir:
437 inode_dec_link_count(dir);
438 return err;
441 static int pohmelfs_unlink(struct inode *dir, struct dentry *dentry)
443 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
444 struct pohmelfs_inode *pi = pohmelfs_inode(dentry->d_inode);
445 struct pohmelfs_script_req req;
446 int err;
448 req.script_name = POHMELFS_UNLINK_SCRIPT;
449 req.script_namelen = sizeof(POHMELFS_UNLINK_SCRIPT) - 1; /* not including 0-byte */
451 req.obj_name = (char *)dentry->d_name.name;
452 req.obj_len = dentry->d_name.len;
454 req.binary = &parent->id;
455 req.binary_size = sizeof(struct dnet_raw_id);
457 req.group_id = 0;
458 req.id = &parent->id;
459 req.complete = pohmelfs_send_dentry_complete;
461 req.sync = 0;
463 err = pohmelfs_send_script_request(parent, &req);
464 if (err)
465 return err;
467 req.script_name = POHMELFS_DATA_UNLINK_SCRIPT;
468 req.script_namelen = sizeof(POHMELFS_DATA_UNLINK_SCRIPT) - 1; /* not including 0-byte */
470 req.binary = &pi->id;
471 req.binary_size = sizeof(struct dnet_raw_id);
473 return pohmelfs_send_script_request(parent, &req);
476 static int pohmelfs_rmdir(struct inode *dir, struct dentry *dentry)
478 return pohmelfs_unlink(dir, dentry);
481 struct pohmelfs_rename_req {
482 struct dnet_raw_id old_dir_id;
484 struct pohmelfs_dentry dentry;
485 } __attribute__ ((packed));
487 static int pohmelfs_rename(struct inode *old_dir, struct dentry *old_dentry,
488 struct inode *new_dir, struct dentry *new_dentry)
490 struct pohmelfs_inode *old_parent = pohmelfs_inode(old_dir);
491 struct inode *inode = old_dentry->d_inode;
492 struct pohmelfs_script_req req;
493 struct pohmelfs_rename_req *r;
494 int size = sizeof(struct pohmelfs_rename_req) + new_dentry->d_name.len;
495 int err;
497 if (pohmelfs_sb(inode->i_sb)->http_compat) {
498 err = -ENOTSUPP;
499 goto err_out_exit;
502 r = kzalloc(size, GFP_NOIO);
503 if (!r) {
504 err = -ENOMEM;
505 goto err_out_exit;
508 r->old_dir_id = pohmelfs_inode(old_dir)->id;
509 r->dentry.parent_id = pohmelfs_inode(new_dir)->id;
510 r->dentry.disk.id = pohmelfs_inode(inode)->id;
511 r->dentry.disk.ino = cpu_to_le64(inode->i_ino);
512 r->dentry.disk.type = (inode->i_mode >> 12) & 15;
513 r->dentry.disk.len = new_dentry->d_name.len;
515 memcpy(r->dentry.disk.name, new_dentry->d_name.name, new_dentry->d_name.len);
517 req.script_name = POHMELFS_RENAME_SCRIPT;
518 req.script_namelen = sizeof(POHMELFS_RENAME_SCRIPT) - 1; /* not including 0-byte */
520 req.obj_name = (char *)old_dentry->d_name.name;
521 req.obj_len = old_dentry->d_name.len;
523 req.binary = r;
524 req.binary_size = size;
526 req.sync = 0;
527 req.group_id = 0;
528 req.id = &old_parent->id;
529 req.complete = pohmelfs_send_dentry_complete;
531 err = pohmelfs_send_script_request(old_parent, &req);
532 if (err)
533 goto err_out_free;
535 err_out_free:
536 kfree(r);
537 err_out_exit:
538 return err;
541 static int pohmelfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
543 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
544 struct pohmelfs_inode *pi;
545 struct inode *inode;
546 unsigned len = strlen(symname)+1;
547 int err = 0;
549 pi = pohmelfs_new_inode(psb, S_IFLNK | S_IRWXUGO);
550 if (IS_ERR(pi)) {
551 err = PTR_ERR(pi);
552 goto err_out_exit;
555 inode = &pi->vfs_inode;
557 err = page_symlink(inode, symname, len);
558 if (err)
559 goto err_out_put;
561 d_instantiate(dentry, inode);
562 if (psb->http_compat)
563 pohmelfs_http_compat_id(pi);
564 pohmelfs_inode_dirty(pohmelfs_inode(dir), pi);
565 err = pohmelfs_send_dentry(pi, &pi->parent_id, dentry->d_name.name, dentry->d_name.len, 0);
566 if (err)
567 goto err_out_put;
569 return 0;
571 err_out_put:
572 iput(inode);
573 d_instantiate(dentry, NULL);
574 err_out_exit:
575 return err;
578 static int pohmelfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
580 struct inode *inode = old_dentry->d_inode;
581 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
582 struct pohmelfs_inode *pi = pohmelfs_inode(inode);
583 struct pohmelfs_script_req req;
584 int err;
586 dquot_initialize(dir);
588 inode->i_ctime = CURRENT_TIME_SEC;
589 inode_inc_link_count(inode);
590 ihold(inode);
592 pohmelfs_inode_dirty(parent, pi);
594 err = pohmelfs_send_dentry(pi, &pi->parent_id, dentry->d_name.name, dentry->d_name.len, 1);
595 if (err) {
596 goto err_out_put;
599 req.script_name = POHMELFS_HARDLINK_SCRIPT;
600 req.script_namelen = sizeof(POHMELFS_HARDLINK_SCRIPT) - 1; /* not including 0-byte */
602 req.obj_name = (char *)dentry->d_name.name;
603 req.obj_len = dentry->d_name.len;
605 req.binary = &pi->id;
606 req.binary_size = sizeof(struct dnet_raw_id);
608 req.group_id = 0;
609 req.id = &pi->id;
610 req.complete = pohmelfs_send_dentry_complete;
612 req.sync = 0;
614 err = pohmelfs_send_script_request(parent, &req);
615 if (err)
616 goto err_out_unlink;
618 d_instantiate(dentry, inode);
619 return 0;
621 err_out_unlink:
622 req.binary = &parent->id;
623 req.script_name = POHMELFS_UNLINK_SCRIPT;
624 req.script_namelen = sizeof(POHMELFS_UNLINK_SCRIPT) - 1; /* not including 0-byte */
625 pohmelfs_send_script_request(parent, &req);
627 err_out_put:
628 inode_dec_link_count(inode);
629 iput(inode);
630 return err;
633 static int pohmelfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
635 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
636 struct pohmelfs_inode *pi;
637 struct inode *inode;
638 int err;
640 if (!new_valid_dev(rdev))
641 return -EINVAL;
643 dquot_initialize(dir);
645 pi = pohmelfs_new_inode(psb, mode);
646 if (IS_ERR(pi)) {
647 err = PTR_ERR(pi);
648 goto err_out_exit;
651 inode = &pi->vfs_inode;
653 init_special_inode(inode, inode->i_mode, rdev);
654 inode->i_op = &pohmelfs_special_inode_operations;
656 d_instantiate(dentry, inode);
657 if (psb->http_compat)
658 pohmelfs_http_compat_id(pi);
659 pohmelfs_inode_dirty(pohmelfs_inode(dir), pi);
661 err = pohmelfs_send_dentry(pi, &pi->parent_id, dentry->d_name.name, dentry->d_name.len, 0);
662 if (err)
663 goto err_out_put;
665 return 0;
667 err_out_put:
668 iput(inode);
669 d_instantiate(dentry, NULL);
670 err_out_exit:
671 return err;
674 const struct inode_operations pohmelfs_dir_inode_operations = {
675 .create = pohmelfs_create,
676 .lookup = pohmelfs_lookup,
677 .mkdir = pohmelfs_mkdir,
678 .unlink = pohmelfs_unlink,
679 .rmdir = pohmelfs_rmdir,
680 .rename = pohmelfs_rename,
681 .symlink = pohmelfs_symlink,
682 .link = pohmelfs_link,
683 .mknod = pohmelfs_mknod,
686 static int pohmelfs_readdir_complete(struct pohmelfs_trans *t, struct pohmelfs_state *recv)
688 struct pohmelfs_inode *pi = pohmelfs_inode(t->inode);
689 struct pohmelfs_wait *wait = t->priv;
690 struct dnet_cmd *cmd = &recv->cmd;
692 pr_debug("pohmelfs: %s: readdir comlete: cmd size: %llu, recv offset: %llu, flags: %x\n",
693 pohmelfs_dump_id(pi->id.id), (unsigned long long)cmd->size, t->recv_offset, cmd->flags);
695 if (cmd->flags & DNET_FLAGS_MORE) {
696 if (cmd->size > sizeof(struct dnet_attr)) {
697 wait->ret = t->recv_data;
698 wait->condition = cmd->size;
700 t->recv_data = NULL;
702 } else {
703 if (!wait->condition) {
704 wait->condition = cmd->status;
705 if (!wait->condition)
706 wait->condition = 1;
710 return 0;
713 static int pohmelfs_dentry_add(struct pohmelfs_inode *parent, struct pohmelfs_inode *pi, char *name, int len)
715 struct inode *inode = &pi->vfs_inode;
716 struct inode *dir = &parent->vfs_inode;
717 struct dentry *dentry, *parent_dentry, *old;
718 struct qstr str;
719 int err;
721 str.name = name;
722 str.len = len;
723 str.hash = full_name_hash(str.name, str.len);
725 /* we do not need to hold dir->i_mutex here, don't we? :) */
726 parent_dentry = d_find_alias(dir);
727 if (!parent_dentry) {
728 err = -ENOENT;
729 goto err_out_exit;
732 dentry = d_lookup(parent_dentry, &str);
733 if (dentry) {
734 err = -EEXIST;
736 dput(dentry);
737 goto err_out_put_parent;
740 * if things are ok, dentry has 2 references -
741 * one in parent dir, and another its own,
742 * which we should drop
744 dentry = d_alloc(parent_dentry, &str);
745 if (!dentry) {
746 err = -ENOMEM;
747 goto err_out_put_parent;
750 old = d_splice_alias(inode, dentry);
751 if (unlikely(old)) {
752 dput(dentry);
753 dentry = old;
754 } else {
755 dput(dentry);
758 dput(parent_dentry);
759 return 0;
761 err_out_put_parent:
762 dput(parent_dentry);
763 err_out_exit:
764 return err;
767 static int pohmelfs_update_inode(struct pohmelfs_inode *parent, struct pohmelfs_inode_info *info, char *name)
769 struct pohmelfs_sb *psb = pohmelfs_sb(parent->vfs_inode.i_sb);
770 struct pohmelfs_inode *pi;
771 struct inode *inode;
772 int err = 0;
774 pi = pohmelfs_sb_inode_lookup(psb, &info->id);
775 if (pi) {
776 inode = &pi->vfs_inode;
777 pohmelfs_fill_inode(inode, info);
779 } else {
780 pi = pohmelfs_existing_inode(psb, info);
781 if (IS_ERR(pi)) {
782 err = PTR_ERR(pi);
783 goto err_out_exit;
785 inode = &pi->vfs_inode;
787 pi->parent_id = parent->id;
790 err = pohmelfs_dentry_add(parent, pi, name, info->namelen);
791 if (err)
792 iput(inode);
794 err_out_exit:
795 return err;
798 struct pohmelfs_fetch_info {
799 struct kref refcnt;
800 int len;
801 char name[0];
804 static void pohmelfs_fetch_inode_info_free(struct kref *kref)
806 struct pohmelfs_fetch_info *fi = container_of(kref, struct pohmelfs_fetch_info, refcnt);
808 kfree(fi);
811 static void pohmelfs_fetch_inode_info_destroy(struct pohmelfs_trans *t)
813 struct pohmelfs_fetch_info *fi = t->priv;
815 kref_put(&fi->refcnt, pohmelfs_fetch_inode_info_free);
818 static int pohmelfs_fetch_inode_info_init(struct pohmelfs_trans *t)
820 struct pohmelfs_fetch_info *fi = t->priv;
822 kref_get(&fi->refcnt);
823 return 0;
826 static int pohmelfs_fetch_inode_info_complete(struct pohmelfs_trans *t, struct pohmelfs_state *recv)
828 struct pohmelfs_fetch_info *fi = t->priv;
829 struct dnet_cmd *cmd = &recv->cmd;
830 struct pohmelfs_inode_info *info;
832 if (cmd->status)
833 return 0;
835 if (!(cmd->flags & DNET_FLAGS_MORE))
836 return 0;
838 if (cmd->size <= sizeof(struct dnet_attr) + sizeof(struct dnet_io_attr) + sizeof(struct dnet_io_attr))
839 return 0;
841 info = t->recv_data + sizeof(struct dnet_attr) + sizeof(struct dnet_io_attr);
842 pohmelfs_convert_inode_info(info);
844 info->namelen = fi->len;
845 pohmelfs_update_inode(pohmelfs_inode(t->inode), info, fi->name);
847 return 0;
850 static int pohmelfs_fetch_inode_info_group(struct pohmelfs_inode *pi, struct pohmelfs_dentry_disk *d, int *groups, int group_num)
852 struct pohmelfs_sb *psb = pohmelfs_sb(pi->vfs_inode.i_sb);
853 struct pohmelfs_io *pio;
854 struct pohmelfs_fetch_info *fi;
855 int err, i;
857 pio = kmem_cache_zalloc(pohmelfs_io_cache, GFP_NOIO);
858 if (!pio) {
859 err = -ENOMEM;
860 goto err_out_exit;
863 fi = kmalloc(sizeof(struct pohmelfs_fetch_info) + d->len, GFP_NOIO);
864 if (!fi) {
865 err = -ENOMEM;
866 goto err_out_free;
869 memcpy(fi->name, d->name, d->len);
870 fi->len = d->len;
871 kref_init(&fi->refcnt);
873 pio->pi = pi;
874 pio->id = &d->id;
875 pio->cmd = DNET_CMD_READ;
876 pio->cflags = DNET_FLAGS_NEED_ACK | DNET_FLAGS_NOLOCK;
877 if (psb->no_read_csum)
878 pio->ioflags = DNET_IO_FLAGS_NOCSUM;
879 pio->type = POHMELFS_INODE_COLUMN;
880 pio->cb.complete = pohmelfs_fetch_inode_info_complete;
881 pio->cb.init = pohmelfs_fetch_inode_info_init;
882 pio->cb.destroy = pohmelfs_fetch_inode_info_destroy;
883 pio->priv = fi;
885 err = -ENOENT;
886 for (i = 0; i < group_num; ++i) {
887 pio->group_id = groups[i];
888 err = pohmelfs_send_io_group(pio, groups[i]);
889 if (!err)
890 break;
893 kref_put(&fi->refcnt, pohmelfs_fetch_inode_info_free);
894 err_out_free:
895 kmem_cache_free(pohmelfs_io_cache, pio);
896 err_out_exit:
897 return err;
900 static int pohmelfs_fetch_inode_info(struct pohmelfs_inode *pi, struct pohmelfs_dentry_disk *d)
902 struct pohmelfs_sb *psb = pohmelfs_sb(pi->vfs_inode.i_sb);
903 if (pi->groups)
904 return pohmelfs_fetch_inode_info_group(pi, d, pi->groups, pi->group_num);
905 else
906 return pohmelfs_fetch_inode_info_group(pi, d, psb->groups, psb->group_num);
909 static int pohmelfs_readdir_process(void *data, int size, struct file *filp, void *dirent, filldir_t filldir)
911 struct dentry *dentry = filp->f_path.dentry;
912 struct inode *dir = dentry->d_inode;
913 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
914 struct pohmelfs_inode *pi;
915 int want_fill = 1;
916 int err = 0;
917 umode_t mode;
919 while (size > 0) {
920 struct pohmelfs_dentry_disk *d = data;
922 if (size < sizeof(struct pohmelfs_dentry_disk)) {
923 err = -EINVAL;
924 break;
927 if (size < d->len) {
928 err = -EINVAL;
929 break;
932 if (want_fill) {
933 err = filldir(dirent, d->name, d->len, filp->f_pos, le64_to_cpu(d->ino), d->type);
934 if (err)
935 want_fill = 0;
936 filp->f_pos++;
939 mode = d->type;
940 mode <<= 12;
942 pi = pohmelfs_sb_inode_lookup(psb, &d->id);
943 if (!pi) {
944 pohmelfs_fetch_inode_info(pohmelfs_inode(dir), d);
945 } else {
946 iput(&pi->vfs_inode);
949 filp->f_pos += 1;
950 size -= sizeof(struct pohmelfs_dentry_disk) + d->len;
951 data += sizeof(struct pohmelfs_dentry_disk) + d->len;
954 return err;
957 struct pohmelfs_readdir {
958 struct dnet_raw_id id;
959 int max_size;
960 int fpos;
963 static int pohmelfs_readdir_group(int group_id, struct file *filp, void *dirent, filldir_t filldir)
965 struct dentry *dentry = filp->f_path.dentry;
966 struct inode *dir = dentry->d_inode;
967 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
968 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
969 struct pohmelfs_readdir rd;
970 struct pohmelfs_script_req req;
971 void *data;
972 int size;
973 int err;
975 req.script_name = POHMELFS_READDIR_SCRIPT;
976 req.script_namelen = sizeof(POHMELFS_READDIR_SCRIPT) - 1; /* not including 0-byte */
978 req.obj_name = (char *)dentry->d_name.name;
979 req.obj_len = dentry->d_name.len;
981 rd.id = parent->id;
982 rd.max_size = psb->readdir_allocation * PAGE_SIZE - sizeof(struct dnet_attr); /* cmd->size should fit one page */
983 rd.fpos = filp->f_pos;
985 req.binary = &rd;
986 req.binary_size = sizeof(struct pohmelfs_readdir);
988 req.id = &parent->id;
989 req.complete = pohmelfs_readdir_complete;
991 req.group_id = group_id;
992 req.sync = 1;
994 err = pohmelfs_send_script_request(parent, &req);
995 if (err < 0)
996 goto err_out_exit;
998 data = req.ret;
999 size = req.ret_cond;
1000 if (!data || !size) {
1001 err = -ENOENT;
1002 goto err_out_exit;
1005 err = pohmelfs_readdir_process(data + sizeof(struct dnet_attr), size - sizeof(struct dnet_attr), filp, dirent, filldir);
1007 kfree(data);
1009 err_out_exit:
1010 return err;
1013 static int pohmelfs_dir_open(struct inode *dir, struct file *filp)
1015 struct pohmelfs_inode *pi = pohmelfs_inode(dir);
1017 if (!pohmelfs_need_resync(pi))
1018 return dcache_dir_open(dir, filp);
1020 filp->f_pos = 0;
1021 return 0;
1024 static int pohmelfs_dir_close(struct inode *inode, struct file *filp)
1026 if (filp->private_data)
1027 return dcache_dir_close(inode, filp);
1028 return 0;
1031 static int pohmelfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
1033 struct dentry *dentry = filp->f_path.dentry;
1034 struct inode *dir = dentry->d_inode;
1035 struct pohmelfs_inode *pi = pohmelfs_inode(dir);
1036 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
1037 int i, err = -ENOENT;
1039 if (filp->private_data) {
1040 return dcache_readdir(filp, dirent, filldir);
1043 if (filp->f_pos == 0) {
1044 err = filldir(dirent, ".", 1, filp->f_pos, dir->i_ino, DT_DIR);
1045 if (err)
1046 return err;
1047 filp->f_pos++;
1050 if (filp->f_pos == 1) {
1051 err = filldir(dirent, "..", 2, filp->f_pos, parent_ino(dentry), DT_DIR);
1052 if (err)
1053 return err;
1054 filp->f_pos++;
1057 for (i = 0; i < psb->group_num; ++i) {
1058 err = pohmelfs_readdir_group(psb->groups[i], filp, dirent, filldir);
1059 if (err)
1060 continue;
1062 pi->update = get_seconds();
1063 return 0;
1066 return err;
1069 const struct file_operations pohmelfs_dir_fops = {
1070 .open = pohmelfs_dir_open,
1071 .release = pohmelfs_dir_close,
1072 .read = generic_read_dir,
1073 .readdir = pohmelfs_readdir,