Introduced pi->local, cflags in script request, memset cript req with 0
[pohmelfs.git] / fs / pohmelfs / dir.c
blob7c127d6b3886fabaf1507c5c789449ab5f11094b
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 if (!wait->condition)
72 wait->condition = 1;
73 wake_up(&wait->wq);
74 pohmelfs_wait_put(wait);
77 static int pohmelfs_lookup_complete(struct pohmelfs_trans *t, struct pohmelfs_state *recv)
79 struct pohmelfs_inode *parent = pohmelfs_inode(t->inode);
80 struct pohmelfs_wait *wait = t->priv;
81 struct dnet_cmd *cmd = &recv->cmd;
82 unsigned long long trans = cmd->trans & ~DNET_TRANS_REPLY;
83 int err = cmd->status;
85 if (err)
86 goto err_out_exit;
88 if (cmd->flags & DNET_FLAGS_MORE) {
89 struct pohmelfs_sb *psb = pohmelfs_sb(t->inode->i_sb);
90 struct pohmelfs_inode_info *info;
91 struct pohmelfs_inode *pi;
93 if (cmd->size != sizeof(struct dnet_attr) + sizeof(struct pohmelfs_inode_info)) {
94 err = -ENOENT;
95 goto err_out_exit;
98 pr_debug("pohmelfs: %s: pohmelfs_lookup_complete: %llu, size: %llu, min size: %zu, flags: %x, status: %d\n",
99 pohmelfs_dump_id(parent->id.id), trans, cmd->size,
100 sizeof(struct dnet_attr) + sizeof(struct pohmelfs_inode_info), cmd->flags, cmd->status);
103 info = t->recv_data + sizeof(struct dnet_attr);
104 pohmelfs_convert_inode_info(info);
106 pi = pohmelfs_existing_inode(psb, info);
107 if (IS_ERR(pi)) {
108 err = PTR_ERR(pi);
110 if (err != -EEXIST)
111 goto err_out_exit;
113 err = 0;
114 pi = pohmelfs_sb_inode_lookup(psb, &info->id);
115 if (!pi) {
116 err = -ENOENT;
117 goto err_out_exit;
120 pohmelfs_fill_inode(&pi->vfs_inode, info);
123 pi->parent_id = parent->id;
124 wait->ret = pi;
127 err_out_exit:
128 if (err)
129 wait->condition = err;
130 else
131 wait->condition = 1;
132 wake_up(&wait->wq);
134 return 0;
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 | req->cflags;
186 pio->cmd = DNET_CMD_EXEC;
187 pio->size = sizeof(struct dnet_exec) + req->script_namelen + script_len + req->binary_size;
188 pio->data = e;
189 pio->priv = wait;
190 pio->cb.init = pohmelfs_send_inode_info_init;
191 pio->cb.destroy = pohmelfs_send_inode_info_destroy;
192 pio->cb.complete = req->complete;
194 if (pio->group_id) {
195 err = pohmelfs_send_buf_single(pio, NULL);
196 } else {
197 err = pohmelfs_send_buf(pio);
199 if (err)
200 goto err_out_free;
202 if (req->sync) {
203 ret = wait_event_interruptible_timeout(wait->wq, wait->condition != 0, msecs_to_jiffies(psb->read_wait_timeout));
204 if (ret <= 0) {
205 err = ret;
206 if (ret == 0)
207 err = -ETIMEDOUT;
208 goto err_out_free;
211 if (wait->condition < 0)
212 err = wait->condition;
214 req->ret = wait->ret;
215 req->ret_cond = wait->condition;
219 int len = 6;
220 char parent_id_str[len*2+1];
222 pr_debug("pohmelfs: %.*s: %s: inode->id: %s, ino: %lu, object: %s, binary size: %d, ret: %p, condition: %d\n",
223 req->script_namelen, req->script_name,
224 pohmelfs_dump_id(req->id->id),
225 pohmelfs_dump_id_len_raw(parent->id.id, len, parent_id_str),
226 parent->vfs_inode.i_ino, req->obj_name, req->binary_size,
227 req->ret, req->ret_cond);
230 err_out_free:
231 kfree(e);
232 err_out_free_pio:
233 kmem_cache_free(pohmelfs_io_cache, pio);
234 err_out_wait_put:
235 pohmelfs_wait_put(wait);
236 err_out_exit:
237 return err;
240 int pohmelfs_send_dentry(struct pohmelfs_inode *pi, struct dnet_raw_id *id, const char *sname, int len, int sync)
242 struct inode *inode = &pi->vfs_inode;
243 struct pohmelfs_script_req req;
244 struct pohmelfs_dentry *pd;
245 int err;
247 if (!len) {
248 err = -EINVAL;
249 goto err_out_exit;
252 pd = kmem_cache_alloc(pohmelfs_dentry_cache, GFP_NOIO);
253 if (!pd) {
254 err = -ENOMEM;
255 goto err_out_exit;
258 pd->parent_id = *id;
259 pd->disk.id = pi->id;
260 pd->disk.ino = cpu_to_le64(pi->vfs_inode.i_ino);
261 pd->disk.type = (pi->vfs_inode.i_mode >> 12) & 15;
262 pd->disk.len = len;
264 memset(&req, 0, sizeof(struct pohmelfs_script_req));
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 pi->local = 1;
310 inode_inc_link_count(dir);
313 * calling d_instantiate() implies that
314 * ->lookup() used d_splice_alias() with NULL inode
315 * when it failed to find requested object
317 d_instantiate(dentry, &pi->vfs_inode);
318 if (psb->http_compat)
319 pohmelfs_http_compat_id(pi);
320 pohmelfs_inode_dirty(parent, pi);
322 err = pohmelfs_send_dentry(pi, &pi->parent_id, dentry->d_name.name, dentry->d_name.len, 0);
323 if (err)
324 goto err_out_put;
326 pr_debug("pohmelfs: create: %s, ino: %lu, parent dir: %lu, object: %s\n",
327 pohmelfs_dump_id(pi->id.id), pi->vfs_inode.i_ino,
328 dir->i_ino, dentry->d_name.name);
330 return 0;
332 err_out_put:
333 inode_dec_link_count(dir);
334 iput(&pi->vfs_inode);
335 d_instantiate(dentry, NULL);
336 err_out_exit:
337 return err;
340 static struct pohmelfs_inode *pohmelfs_lookup_group(struct inode *dir, struct dentry *dentry, int group_id)
342 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
343 struct pohmelfs_script_req req;
344 struct pohmelfs_inode *pi;
345 int err;
347 memset(&req, 0, sizeof(struct pohmelfs_script_req));
349 req.script_name = POHMELFS_LOOKUP_SCRIPT;
350 req.script_namelen = sizeof(POHMELFS_LOOKUP_SCRIPT) - 1; /* not including 0-byte */
352 req.obj_name = (char *)dentry->d_name.name;
353 req.obj_len = dentry->d_name.len;
355 req.binary = &parent->id;
356 req.binary_size = sizeof(struct dnet_raw_id);
358 req.id = &parent->id;
359 req.complete = pohmelfs_lookup_complete;
361 req.group_id = group_id;
362 req.sync = 1;
363 req.cflags = DNET_FLAGS_NOLOCK;
365 err = pohmelfs_send_script_request(parent, &req);
366 if (err)
367 goto err_out_exit;
369 pi = req.ret;
370 if (!pi) {
371 err = -ENOENT;
372 goto err_out_exit;
375 return pi;
377 err_out_exit:
378 pr_debug("pohmelfs: pohmelfs_lookup_group: %s: group: %d: parent ino: %lu, name: %s: %d\n",
379 pohmelfs_dump_id(parent->id.id), group_id, parent->vfs_inode.i_ino, dentry->d_name.name, err);
380 return ERR_PTR(err);
383 static struct dentry *pohmelfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
385 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
386 struct inode *inode = NULL;
387 struct pohmelfs_inode *pi;
388 int i, err = -ENOENT;
390 for (i = 0; i < psb->group_num; ++i) {
391 pi = pohmelfs_lookup_group(dir, dentry, psb->groups[i]);
392 if (IS_ERR(pi)) {
393 err = PTR_ERR(pi);
394 continue;
397 inode = &pi->vfs_inode;
398 err = 0;
399 break;
402 if (err && (err != -ENOENT) && (err != -EOPNOTSUPP))
403 return ERR_PTR(err);
405 return d_splice_alias(inode, dentry);
408 static int pohmelfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
410 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
411 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
412 struct pohmelfs_inode *pi;
413 int err;
415 inode_inc_link_count(dir);
417 pi = pohmelfs_new_inode(psb, mode | S_IFDIR);
418 if (IS_ERR(pi)) {
419 err = PTR_ERR(pi);
420 goto err_out_dir;
423 pi->local = 1;
424 d_instantiate(dentry, &pi->vfs_inode);
425 if (psb->http_compat)
426 pohmelfs_http_compat_id(pi);
427 pohmelfs_inode_dirty(parent, pi);
429 err = pohmelfs_send_dentry(pi, &pi->parent_id, dentry->d_name.name, dentry->d_name.len, 0);
430 if (err)
431 goto err_out_put;
433 pr_debug("pohmelfs: mkdir: %s, ino: %lu, parent dir: %lu, object: %s, refcnt: %d\n",
434 pohmelfs_dump_id(pi->id.id), pi->vfs_inode.i_ino,
435 dir->i_ino, dentry->d_name.name, dentry->d_count);
436 return 0;
438 err_out_put:
439 iput(&pi->vfs_inode);
440 d_instantiate(dentry, NULL);
441 err_out_dir:
442 inode_dec_link_count(dir);
443 return err;
446 static int pohmelfs_unlink(struct inode *dir, struct dentry *dentry)
448 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
449 struct pohmelfs_inode *pi = pohmelfs_inode(dentry->d_inode);
450 struct pohmelfs_script_req req;
451 int err;
453 memset(&req, 0, sizeof(struct pohmelfs_script_req));
455 req.script_name = POHMELFS_UNLINK_SCRIPT;
456 req.script_namelen = sizeof(POHMELFS_UNLINK_SCRIPT) - 1; /* not including 0-byte */
458 req.obj_name = (char *)dentry->d_name.name;
459 req.obj_len = dentry->d_name.len;
461 req.binary = &parent->id;
462 req.binary_size = sizeof(struct dnet_raw_id);
464 req.group_id = 0;
465 req.id = &parent->id;
466 req.complete = pohmelfs_send_dentry_complete;
468 req.sync = 0;
470 err = pohmelfs_send_script_request(parent, &req);
471 if (err)
472 return err;
474 req.script_name = POHMELFS_DATA_UNLINK_SCRIPT;
475 req.script_namelen = sizeof(POHMELFS_DATA_UNLINK_SCRIPT) - 1; /* not including 0-byte */
477 req.binary = &pi->id;
478 req.binary_size = sizeof(struct dnet_raw_id);
480 return pohmelfs_send_script_request(parent, &req);
483 static int pohmelfs_rmdir(struct inode *dir, struct dentry *dentry)
485 return pohmelfs_unlink(dir, dentry);
488 struct pohmelfs_rename_req {
489 struct dnet_raw_id old_dir_id;
491 struct pohmelfs_dentry dentry;
492 } __attribute__ ((packed));
494 static int pohmelfs_rename(struct inode *old_dir, struct dentry *old_dentry,
495 struct inode *new_dir, struct dentry *new_dentry)
497 struct pohmelfs_inode *old_parent = pohmelfs_inode(old_dir);
498 struct inode *inode = old_dentry->d_inode;
499 struct pohmelfs_script_req req;
500 struct pohmelfs_rename_req *r;
501 int size = sizeof(struct pohmelfs_rename_req) + new_dentry->d_name.len;
502 int err;
504 if (pohmelfs_sb(inode->i_sb)->http_compat) {
505 err = -ENOTSUPP;
506 goto err_out_exit;
509 r = kzalloc(size, GFP_NOIO);
510 if (!r) {
511 err = -ENOMEM;
512 goto err_out_exit;
515 r->old_dir_id = pohmelfs_inode(old_dir)->id;
516 r->dentry.parent_id = pohmelfs_inode(new_dir)->id;
517 r->dentry.disk.id = pohmelfs_inode(inode)->id;
518 r->dentry.disk.ino = cpu_to_le64(inode->i_ino);
519 r->dentry.disk.type = (inode->i_mode >> 12) & 15;
520 r->dentry.disk.len = new_dentry->d_name.len;
522 memcpy(r->dentry.disk.name, new_dentry->d_name.name, new_dentry->d_name.len);
524 memset(&req, 0, sizeof(struct pohmelfs_script_req));
526 req.script_name = POHMELFS_RENAME_SCRIPT;
527 req.script_namelen = sizeof(POHMELFS_RENAME_SCRIPT) - 1; /* not including 0-byte */
529 req.obj_name = (char *)old_dentry->d_name.name;
530 req.obj_len = old_dentry->d_name.len;
532 req.binary = r;
533 req.binary_size = size;
535 req.sync = 0;
536 req.group_id = 0;
537 req.id = &old_parent->id;
538 req.complete = pohmelfs_send_dentry_complete;
540 err = pohmelfs_send_script_request(old_parent, &req);
541 if (err)
542 goto err_out_free;
544 err_out_free:
545 kfree(r);
546 err_out_exit:
547 return err;
550 static int pohmelfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
552 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
553 struct pohmelfs_inode *pi;
554 struct inode *inode;
555 unsigned len = strlen(symname)+1;
556 int err = 0;
558 pi = pohmelfs_new_inode(psb, S_IFLNK | S_IRWXUGO);
559 if (IS_ERR(pi)) {
560 err = PTR_ERR(pi);
561 goto err_out_exit;
564 pi->local = 1;
565 inode = &pi->vfs_inode;
567 err = page_symlink(inode, symname, len);
568 if (err)
569 goto err_out_put;
571 d_instantiate(dentry, inode);
572 if (psb->http_compat)
573 pohmelfs_http_compat_id(pi);
574 pohmelfs_inode_dirty(pohmelfs_inode(dir), pi);
575 err = pohmelfs_send_dentry(pi, &pi->parent_id, dentry->d_name.name, dentry->d_name.len, 0);
576 if (err)
577 goto err_out_put;
579 return 0;
581 err_out_put:
582 iput(inode);
583 d_instantiate(dentry, NULL);
584 err_out_exit:
585 return err;
588 static int pohmelfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
590 struct inode *inode = old_dentry->d_inode;
591 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
592 struct pohmelfs_inode *pi = pohmelfs_inode(inode);
593 struct pohmelfs_script_req req;
594 int err;
596 dquot_initialize(dir);
598 inode->i_ctime = CURRENT_TIME_SEC;
599 inode_inc_link_count(inode);
600 ihold(inode);
602 pohmelfs_inode_dirty(parent, pi);
604 err = pohmelfs_send_dentry(pi, &pi->parent_id, dentry->d_name.name, dentry->d_name.len, 1);
605 if (err) {
606 goto err_out_put;
609 memset(&req, 0, sizeof(struct pohmelfs_script_req));
611 req.script_name = POHMELFS_HARDLINK_SCRIPT;
612 req.script_namelen = sizeof(POHMELFS_HARDLINK_SCRIPT) - 1; /* not including 0-byte */
614 req.obj_name = (char *)dentry->d_name.name;
615 req.obj_len = dentry->d_name.len;
617 req.binary = &pi->id;
618 req.binary_size = sizeof(struct dnet_raw_id);
620 req.group_id = 0;
621 req.id = &pi->id;
622 req.complete = pohmelfs_send_dentry_complete;
624 req.sync = 0;
626 err = pohmelfs_send_script_request(parent, &req);
627 if (err)
628 goto err_out_unlink;
630 d_instantiate(dentry, inode);
631 return 0;
633 err_out_unlink:
634 req.binary = &parent->id;
635 req.script_name = POHMELFS_UNLINK_SCRIPT;
636 req.script_namelen = sizeof(POHMELFS_UNLINK_SCRIPT) - 1; /* not including 0-byte */
637 pohmelfs_send_script_request(parent, &req);
639 err_out_put:
640 inode_dec_link_count(inode);
641 iput(inode);
642 return err;
645 static int pohmelfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
647 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
648 struct pohmelfs_inode *pi;
649 struct inode *inode;
650 int err;
652 if (!new_valid_dev(rdev))
653 return -EINVAL;
655 dquot_initialize(dir);
657 pi = pohmelfs_new_inode(psb, mode);
658 if (IS_ERR(pi)) {
659 err = PTR_ERR(pi);
660 goto err_out_exit;
662 pi->local = 1;
664 inode = &pi->vfs_inode;
666 init_special_inode(inode, inode->i_mode, rdev);
667 inode->i_op = &pohmelfs_special_inode_operations;
669 d_instantiate(dentry, inode);
670 if (psb->http_compat)
671 pohmelfs_http_compat_id(pi);
672 pohmelfs_inode_dirty(pohmelfs_inode(dir), pi);
674 err = pohmelfs_send_dentry(pi, &pi->parent_id, dentry->d_name.name, dentry->d_name.len, 0);
675 if (err)
676 goto err_out_put;
678 return 0;
680 err_out_put:
681 iput(inode);
682 d_instantiate(dentry, NULL);
683 err_out_exit:
684 return err;
687 const struct inode_operations pohmelfs_dir_inode_operations = {
688 .create = pohmelfs_create,
689 .lookup = pohmelfs_lookup,
690 .mkdir = pohmelfs_mkdir,
691 .unlink = pohmelfs_unlink,
692 .rmdir = pohmelfs_rmdir,
693 .rename = pohmelfs_rename,
694 .symlink = pohmelfs_symlink,
695 .link = pohmelfs_link,
696 .mknod = pohmelfs_mknod,
699 static int pohmelfs_readdir_complete(struct pohmelfs_trans *t, struct pohmelfs_state *recv)
701 struct pohmelfs_inode *pi = pohmelfs_inode(t->inode);
702 struct pohmelfs_wait *wait = t->priv;
703 struct dnet_cmd *cmd = &recv->cmd;
705 pr_debug("pohmelfs: %s: readdir comlete: cmd size: %llu, recv offset: %llu, flags: %x\n",
706 pohmelfs_dump_id(pi->id.id), (unsigned long long)cmd->size, t->recv_offset, cmd->flags);
708 if (cmd->flags & DNET_FLAGS_MORE) {
709 if (cmd->size > sizeof(struct dnet_attr)) {
710 wait->ret = t->recv_data;
711 wait->condition = cmd->size;
713 t->recv_data = NULL;
715 } else {
716 if (!wait->condition) {
717 wait->condition = cmd->status;
718 if (!wait->condition)
719 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 struct pohmelfs_fetch_info {
812 struct kref refcnt;
813 int len;
814 char name[0];
817 static void pohmelfs_fetch_inode_info_free(struct kref *kref)
819 struct pohmelfs_fetch_info *fi = container_of(kref, struct pohmelfs_fetch_info, refcnt);
821 kfree(fi);
824 static void pohmelfs_fetch_inode_info_destroy(struct pohmelfs_trans *t)
826 struct pohmelfs_fetch_info *fi = t->priv;
828 kref_put(&fi->refcnt, pohmelfs_fetch_inode_info_free);
831 static int pohmelfs_fetch_inode_info_init(struct pohmelfs_trans *t)
833 struct pohmelfs_fetch_info *fi = t->priv;
835 kref_get(&fi->refcnt);
836 return 0;
839 static int pohmelfs_fetch_inode_info_complete(struct pohmelfs_trans *t, struct pohmelfs_state *recv)
841 struct pohmelfs_fetch_info *fi = t->priv;
842 struct dnet_cmd *cmd = &recv->cmd;
843 struct pohmelfs_inode_info *info;
845 if (cmd->status)
846 return 0;
848 if (!(cmd->flags & DNET_FLAGS_MORE))
849 return 0;
851 if (cmd->size <= sizeof(struct dnet_attr) + sizeof(struct dnet_io_attr) + sizeof(struct dnet_io_attr))
852 return 0;
854 info = t->recv_data + sizeof(struct dnet_attr) + sizeof(struct dnet_io_attr);
855 pohmelfs_convert_inode_info(info);
857 info->namelen = fi->len;
858 pohmelfs_update_inode(pohmelfs_inode(t->inode), info, fi->name);
860 return 0;
863 static int pohmelfs_fetch_inode_info_group(struct pohmelfs_inode *pi, struct pohmelfs_dentry_disk *d, int *groups, int group_num)
865 struct pohmelfs_sb *psb = pohmelfs_sb(pi->vfs_inode.i_sb);
866 struct pohmelfs_io *pio;
867 struct pohmelfs_fetch_info *fi;
868 int err, i;
870 pio = kmem_cache_zalloc(pohmelfs_io_cache, GFP_NOIO);
871 if (!pio) {
872 err = -ENOMEM;
873 goto err_out_exit;
876 fi = kmalloc(sizeof(struct pohmelfs_fetch_info) + d->len, GFP_NOIO);
877 if (!fi) {
878 err = -ENOMEM;
879 goto err_out_free;
882 memcpy(fi->name, d->name, d->len);
883 fi->len = d->len;
884 kref_init(&fi->refcnt);
886 pio->pi = pi;
887 pio->id = &d->id;
888 pio->cmd = DNET_CMD_READ;
889 pio->cflags = DNET_FLAGS_NEED_ACK | DNET_FLAGS_NOLOCK;
890 if (psb->no_read_csum)
891 pio->ioflags = DNET_IO_FLAGS_NOCSUM;
892 pio->type = POHMELFS_INODE_COLUMN;
893 pio->cb.complete = pohmelfs_fetch_inode_info_complete;
894 pio->cb.init = pohmelfs_fetch_inode_info_init;
895 pio->cb.destroy = pohmelfs_fetch_inode_info_destroy;
896 pio->priv = fi;
898 err = -ENOENT;
899 for (i = 0; i < group_num; ++i) {
900 pio->group_id = groups[i];
901 err = pohmelfs_send_io_group(pio, groups[i]);
902 if (!err)
903 break;
906 kref_put(&fi->refcnt, pohmelfs_fetch_inode_info_free);
907 err_out_free:
908 kmem_cache_free(pohmelfs_io_cache, pio);
909 err_out_exit:
910 return err;
913 static int pohmelfs_fetch_inode_info(struct pohmelfs_inode *pi, struct pohmelfs_dentry_disk *d)
915 struct pohmelfs_sb *psb = pohmelfs_sb(pi->vfs_inode.i_sb);
916 if (pi->groups)
917 return pohmelfs_fetch_inode_info_group(pi, d, pi->groups, pi->group_num);
918 else
919 return pohmelfs_fetch_inode_info_group(pi, d, psb->groups, psb->group_num);
922 static int pohmelfs_readdir_process(void *data, int size, struct file *filp, void *dirent, filldir_t filldir)
924 struct dentry *dentry = filp->f_path.dentry;
925 struct inode *dir = dentry->d_inode;
926 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
927 struct pohmelfs_inode *pi;
928 int want_fill = 1;
929 int err = 0;
930 umode_t mode;
932 while (size > 0) {
933 struct pohmelfs_dentry_disk *d = data;
935 if (size < sizeof(struct pohmelfs_dentry_disk)) {
936 err = -EINVAL;
937 break;
940 if (size < d->len) {
941 err = -EINVAL;
942 break;
945 if (want_fill) {
946 err = filldir(dirent, d->name, d->len, filp->f_pos, le64_to_cpu(d->ino), d->type);
947 if (err)
948 want_fill = 0;
949 filp->f_pos++;
952 mode = d->type;
953 mode <<= 12;
956 pi = pohmelfs_sb_inode_lookup(psb, &d->id);
957 if (!pi) {
958 pohmelfs_fetch_inode_info(pohmelfs_inode(dir), d);
959 } else {
960 iput(&pi->vfs_inode);
963 filp->f_pos += 1;
964 size -= sizeof(struct pohmelfs_dentry_disk) + d->len;
965 data += sizeof(struct pohmelfs_dentry_disk) + d->len;
968 return err;
971 struct pohmelfs_readdir {
972 struct dnet_raw_id id;
973 int max_size;
974 int fpos;
977 static int pohmelfs_readdir_group(int group_id, struct file *filp, void *dirent, filldir_t filldir)
979 struct dentry *dentry = filp->f_path.dentry;
980 struct inode *dir = dentry->d_inode;
981 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
982 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
983 struct pohmelfs_readdir rd;
984 struct pohmelfs_script_req req;
985 void *data;
986 int size;
987 int err;
989 memset(&req, 0, sizeof(struct pohmelfs_script_req));
991 req.script_name = POHMELFS_READDIR_SCRIPT;
992 req.script_namelen = sizeof(POHMELFS_READDIR_SCRIPT) - 1; /* not including 0-byte */
994 req.obj_name = (char *)dentry->d_name.name;
995 req.obj_len = dentry->d_name.len;
997 rd.id = parent->id;
998 rd.max_size = psb->readdir_allocation * PAGE_SIZE - sizeof(struct dnet_attr); /* cmd->size should fit one page */
999 rd.fpos = filp->f_pos - 2; /* account for . and .. */
1001 req.binary = &rd;
1002 req.binary_size = sizeof(struct pohmelfs_readdir);
1004 req.id = &parent->id;
1005 req.complete = pohmelfs_readdir_complete;
1006 req.cflags = DNET_FLAGS_NOLOCK;
1008 req.group_id = group_id;
1009 req.sync = 1;
1011 err = pohmelfs_send_script_request(parent, &req);
1012 if (err < 0)
1013 goto err_out_exit;
1015 data = req.ret;
1016 size = req.ret_cond;
1017 if (!data || !size) {
1018 err = -ENOENT;
1019 goto err_out_exit;
1022 err = pohmelfs_readdir_process(data + sizeof(struct dnet_attr), size - sizeof(struct dnet_attr), filp, dirent, filldir);
1024 kfree(data);
1026 err_out_exit:
1027 return err;
1030 static int pohmelfs_dir_open(struct inode *dir, struct file *filp)
1032 struct pohmelfs_inode *pi = pohmelfs_inode(dir);
1034 if (!pohmelfs_need_resync(pi))
1035 return dcache_dir_open(dir, filp);
1037 filp->f_pos = 0;
1038 return 0;
1041 static int pohmelfs_dir_close(struct inode *inode, struct file *filp)
1043 if (filp->private_data)
1044 return dcache_dir_close(inode, filp);
1045 return 0;
1048 static int pohmelfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
1050 struct dentry *dentry = filp->f_path.dentry;
1051 struct inode *dir = dentry->d_inode;
1052 struct pohmelfs_inode *pi = pohmelfs_inode(dir);
1053 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
1054 int i, err = -ENOENT;
1056 if (filp->private_data) {
1057 return dcache_readdir(filp, dirent, filldir);
1060 if (filp->f_pos == 0) {
1061 err = filldir(dirent, ".", 1, filp->f_pos, dir->i_ino, DT_DIR);
1062 if (err)
1063 return err;
1064 filp->f_pos++;
1067 if (filp->f_pos == 1) {
1068 err = filldir(dirent, "..", 2, filp->f_pos, parent_ino(dentry), DT_DIR);
1069 if (err)
1070 return err;
1071 filp->f_pos++;
1074 for (i = 0; i < psb->group_num; ++i) {
1075 err = pohmelfs_readdir_group(psb->groups[i], filp, dirent, filldir);
1076 if (err)
1077 continue;
1079 pi->update = get_seconds();
1080 return 0;
1083 return err;
1086 const struct file_operations pohmelfs_dir_fops = {
1087 .open = pohmelfs_dir_open,
1088 .release = pohmelfs_dir_close,
1089 .read = generic_read_dir,
1090 .readdir = pohmelfs_readdir,