Use dentry_path() to create full path to inode object
[pohmelfs.git] / fs / pohmelfs / dir.c
blob67b61ac53bbbaa08ed3f33af62f43258af7bc16e
1 /*
2 * Copyright (C) 2011+ Evgeniy Polyakov <zbr@ioremap.net>
3 */
5 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
7 #include <linux/fs.h>
8 #include <linux/dcache.h>
9 #include <linux/quotaops.h>
11 #include "pohmelfs.h"
13 #define POHMELFS_LOOKUP_SCRIPT "pohmelfs_lookup.py"
14 #define POHMELFS_UNLINK_SCRIPT "pohmelfs_unlink.py"
15 #define POHMELFS_DATA_UNLINK_SCRIPT "pohmelfs_data_unlink.py"
16 #define POHMELFS_HARDLINK_SCRIPT "pohmelfs_hardlink.py"
17 #define POHMELFS_RENAME_SCRIPT "pohmelfs_rename.py"
18 #define POHMELFS_INODE_INFO_SCRIPT_INSERT "pohmelfs_inode_info_insert.py"
19 #define POHMELFS_READDIR_SCRIPT "pohmelfs_readdir.py"
20 #define POHMELFS_DENTRY_NAME_SCRIPT "pohmelfs_dentry_name="
22 static void pohmelfs_init_local(struct pohmelfs_inode *pi, struct inode *dir)
24 struct inode *inode = &pi->vfs_inode;
26 inode_init_owner(inode, dir, inode->i_mode);
27 pi->local = 1;
29 mark_inode_dirty(inode);
32 static int pohmelfs_send_dentry_complete(struct pohmelfs_trans *t, struct pohmelfs_state *recv)
34 struct pohmelfs_inode *pi = pohmelfs_inode(t->inode);
35 struct pohmelfs_wait *wait = t->priv;
36 struct dnet_cmd *cmd = &recv->cmd;
37 unsigned long long trans = cmd->trans & ~DNET_TRANS_REPLY;
39 if (cmd->flags & DNET_FLAGS_MORE) {
40 if (cmd->status == 0 && cmd->size != sizeof(struct dnet_attr) + 2)
41 cmd->status = -EINVAL;
43 pr_debug("%s: %llu, cmd_size: %llu, flags: %x, status: %d\n",
44 pohmelfs_dump_id(pi->id.id), trans, cmd->size,
45 cmd->flags, cmd->status);
47 if (!cmd->status)
48 wait->condition = 1;
49 else
50 wait->condition = cmd->status;
51 wake_up(&wait->wq);
54 return 0;
57 static int pohmelfs_send_inode_info_init(struct pohmelfs_trans *t)
59 struct pohmelfs_wait *wait = t->priv;
61 pohmelfs_wait_get(wait);
62 return 0;
65 static void pohmelfs_send_inode_info_destroy(struct pohmelfs_trans *t)
67 struct pohmelfs_wait *wait = t->priv;
69 if (!wait->condition)
70 wait->condition = 1;
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("%s: %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),
99 cmd->flags, cmd->status);
102 info = t->recv_data + sizeof(struct dnet_attr);
103 pohmelfs_convert_inode_info(info);
105 pi = pohmelfs_existing_inode(psb, info);
106 if (IS_ERR(pi)) {
107 err = PTR_ERR(pi);
109 if (err != -EEXIST)
110 goto err_out_exit;
112 err = 0;
113 pi = pohmelfs_sb_inode_lookup(psb, &info->id);
114 if (!pi) {
115 err = -ENOENT;
116 goto err_out_exit;
119 pohmelfs_fill_inode(&pi->vfs_inode, info);
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 int pohmelfs_send_script_request(struct pohmelfs_inode *parent, struct pohmelfs_script_req *req)
137 struct pohmelfs_sb *psb = pohmelfs_sb(parent->vfs_inode.i_sb);
138 struct pohmelfs_wait *wait;
139 struct pohmelfs_io *pio;
140 struct dnet_exec *e;
141 int script_len;
142 long ret;
143 int err;
145 /* 2 commas, \n and 0-byte, which is accounted in sizeof(string) */
146 script_len = sizeof(POHMELFS_DENTRY_NAME_SCRIPT) + req->obj_len + 3;
148 wait = pohmelfs_wait_alloc(parent);
149 if (!wait) {
150 err = -ENOMEM;
151 goto err_out_exit;
154 pio = kmem_cache_zalloc(pohmelfs_io_cache, GFP_NOIO);
155 if (!pio) {
156 err = -ENOMEM;
157 goto err_out_wait_put;
160 e = kmalloc(sizeof(struct dnet_exec) + req->script_namelen + script_len + req->binary_size, GFP_NOIO);
161 if (!e) {
162 err = -ENOMEM;
163 goto err_out_free_pio;
166 memset(e, 0, sizeof(struct dnet_exec));
168 snprintf(e->data, req->script_namelen + script_len, "%s%s'%s'\n", req->script_name, POHMELFS_DENTRY_NAME_SCRIPT, req->obj_name);
169 script_len--; /* do not include last 0-byte in the script */
171 memcpy(e->data + req->script_namelen + script_len, req->binary, req->binary_size);
173 e->type = DNET_EXEC_PYTHON_SCRIPT_NAME;
174 e->name_size = req->script_namelen;
175 e->script_size = script_len;
176 e->binary_size = req->binary_size;
177 dnet_convert_exec(e);
179 pio->pi = parent;
180 pio->id = req->id;
181 pio->group_id = req->group_id;
182 pio->cflags = DNET_FLAGS_NEED_ACK | req->cflags;
184 pio->cmd = DNET_CMD_EXEC;
185 pio->size = sizeof(struct dnet_exec) + req->script_namelen + script_len + req->binary_size;
186 pio->data = e;
187 pio->priv = wait;
188 pio->cb.init = pohmelfs_send_inode_info_init;
189 pio->cb.destroy = pohmelfs_send_inode_info_destroy;
190 pio->cb.complete = req->complete;
192 if (pio->group_id) {
193 err = pohmelfs_send_buf_single(pio, NULL);
194 } else {
195 err = pohmelfs_send_buf(pio);
197 if (err)
198 goto err_out_free;
201 int len = 6;
202 char parent_id_str[len*2+1];
204 pr_debug("SENT: %.*s: %s: inode->id: %s, ino: %lu, object: %s, binary size: %d, ret: %p, condition: %d\n",
205 req->script_namelen, req->script_name,
206 pohmelfs_dump_id(req->id->id),
207 pohmelfs_dump_id_len_raw(parent->id.id, len,
208 parent_id_str),
209 parent->vfs_inode.i_ino, req->obj_name,
210 req->binary_size, req->ret, req->ret_cond);
213 if (req->sync) {
214 ret = wait_event_interruptible_timeout(wait->wq, wait->condition != 0, msecs_to_jiffies(psb->read_wait_timeout));
215 if (ret <= 0) {
216 err = ret;
217 if (ret == 0)
218 err = -ETIMEDOUT;
219 goto err_out_free;
222 if (wait->condition < 0)
223 err = wait->condition;
225 req->ret = wait->ret;
226 req->ret_cond = wait->condition;
229 err_out_free:
230 kfree(e);
231 err_out_free_pio:
232 kmem_cache_free(pohmelfs_io_cache, pio);
233 err_out_wait_put:
234 pohmelfs_wait_put(wait);
235 err_out_exit:
237 int len = 6;
238 char parent_id_str[len*2+1];
240 pr_debug("DONE: %.*s: %s: inode->id: %s, ino: %lu, object: %s, binary size: %d, ret: %p, condition: %d, err: %d\n",
241 req->script_namelen, req->script_name,
242 pohmelfs_dump_id(req->id->id),
243 pohmelfs_dump_id_len_raw(parent->id.id, len,
244 parent_id_str),
245 parent->vfs_inode.i_ino, req->obj_name,
246 req->binary_size, req->ret, req->ret_cond, err);
248 return err;
251 int pohmelfs_send_dentry(struct pohmelfs_inode *pi, struct dnet_raw_id *id, const char *sname, int len, int sync)
253 struct pohmelfs_script_req req;
254 struct pohmelfs_dentry *pd;
255 int err;
257 if (!len) {
258 err = -EINVAL;
259 goto err_out_exit;
262 pd = kmem_cache_alloc(pohmelfs_dentry_cache, GFP_NOIO);
263 if (!pd) {
264 err = -ENOMEM;
265 goto err_out_exit;
268 pd->parent_id = *id;
269 pd->disk.id = pi->id;
270 pd->disk.ino = cpu_to_le64(pi->vfs_inode.i_ino);
271 pd->disk.type = (pi->vfs_inode.i_mode >> 12) & 15;
272 pd->disk.len = len;
274 memset(&req, 0, sizeof(struct pohmelfs_script_req));
276 req.id = id;
278 req.script_name = POHMELFS_INODE_INFO_SCRIPT_INSERT;
279 req.script_namelen = sizeof(POHMELFS_INODE_INFO_SCRIPT_INSERT) - 1; /* not including 0-byte */
281 req.obj_name = (char *)sname;
282 req.obj_len = len;
284 req.binary = pd;
285 req.binary_size = sizeof(struct pohmelfs_dentry);
287 req.group_id = 0;
288 req.id = id;
290 req.sync = sync;
291 req.complete = pohmelfs_send_dentry_complete;
293 err = pohmelfs_send_script_request(pi, &req);
294 if (err)
295 goto err_out_free;
297 err_out_free:
298 kmem_cache_free(pohmelfs_dentry_cache, pd);
299 err_out_exit:
300 return err;
303 static int pohmelfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
304 struct nameidata *nd)
306 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
307 struct pohmelfs_inode *pi;
308 int err;
310 inode_inc_link_count(dir);
312 pi = pohmelfs_new_inode(psb, mode);
313 if (IS_ERR(pi)) {
314 err = PTR_ERR(pi);
315 goto err_out_exit;
317 pohmelfs_init_local(pi, dir);
318 mark_inode_dirty(dir);
321 * calling d_instantiate() implies that
322 * ->lookup() used d_splice_alias() with NULL inode
323 * when it failed to find requested object
325 d_instantiate(dentry, &pi->vfs_inode);
326 if (psb->http_compat)
327 pohmelfs_http_compat_id(pi);
329 err = pohmelfs_send_dentry(pi, &pohmelfs_inode(dir)->id, dentry->d_name.name, dentry->d_name.len, 1);
330 if (err)
331 goto err_out_exit;
333 pr_debug("%s: ino: %lu, parent dir: %lu, object: %s\n",
334 pohmelfs_dump_id(pi->id.id), pi->vfs_inode.i_ino,
335 dir->i_ino, dentry->d_name.name);
337 return 0;
339 err_out_exit:
340 inode_dec_link_count(dir);
341 return err;
344 static struct pohmelfs_inode *pohmelfs_lookup_group(struct inode *dir, struct dentry *dentry, int group_id)
346 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
347 struct pohmelfs_script_req req;
348 struct pohmelfs_inode *pi;
349 int err;
351 memset(&req, 0, sizeof(struct pohmelfs_script_req));
353 req.script_name = POHMELFS_LOOKUP_SCRIPT;
354 req.script_namelen = sizeof(POHMELFS_LOOKUP_SCRIPT) - 1; /* not including 0-byte */
356 req.obj_name = (char *)dentry->d_name.name;
357 req.obj_len = dentry->d_name.len;
359 req.binary = &parent->id;
360 req.binary_size = sizeof(struct dnet_raw_id);
362 req.id = &parent->id;
363 req.complete = pohmelfs_lookup_complete;
365 req.group_id = group_id;
366 req.sync = 1;
367 req.cflags = 0;
369 err = pohmelfs_send_script_request(parent, &req);
370 if (err)
371 goto err_out_exit;
373 pi = req.ret;
374 if (!pi) {
375 err = -ENOENT;
376 goto err_out_exit;
379 return pi;
381 err_out_exit:
382 pr_debug("%s: group: %d: parent ino: %lu, name: %s: %d\n",
383 pohmelfs_dump_id(parent->id.id), group_id,
384 parent->vfs_inode.i_ino, dentry->d_name.name, err);
385 return ERR_PTR(err);
388 static struct dentry *pohmelfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
390 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
391 struct inode *inode = NULL;
392 struct pohmelfs_inode *pi;
393 int i, err = -ENOENT;
395 for (i = 0; i < psb->group_num; ++i) {
396 pi = pohmelfs_lookup_group(dir, dentry, psb->groups[i]);
397 if (IS_ERR(pi)) {
398 err = PTR_ERR(pi);
399 continue;
402 inode = &pi->vfs_inode;
403 err = 0;
404 break;
407 return d_splice_alias(inode, dentry);
410 static int pohmelfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
412 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
413 struct pohmelfs_inode *pi;
414 int err;
416 inode_inc_link_count(dir);
418 pi = pohmelfs_new_inode(psb, mode | S_IFDIR);
419 if (IS_ERR(pi)) {
420 err = PTR_ERR(pi);
421 goto err_out_dir;
423 pohmelfs_init_local(pi, dir);
424 mark_inode_dirty(dir);
426 d_instantiate(dentry, &pi->vfs_inode);
427 if (psb->http_compat)
428 pohmelfs_http_compat_id(pi);
430 err = pohmelfs_send_dentry(pi, &pohmelfs_inode(dir)->id, dentry->d_name.name, dentry->d_name.len, 1);
431 if (err)
432 goto err_out_dir;
434 pr_debug("%s: ino: %lu, parent dir: %lu, object: %s, refcnt: %d\n",
435 pohmelfs_dump_id(pi->id.id), pi->vfs_inode.i_ino,
436 dir->i_ino, dentry->d_name.name, dentry->d_count);
437 return 0;
439 err_out_dir:
440 inode_dec_link_count(dir);
441 return err;
444 static int pohmelfs_unlink(struct inode *dir, struct dentry *dentry)
446 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
447 struct inode *inode = dentry->d_inode;
448 struct pohmelfs_inode *pi = pohmelfs_inode(inode);
449 struct pohmelfs_script_req req;
450 int err;
452 inode->i_ctime = dir->i_ctime;
453 mark_inode_dirty(dir);
455 memset(&req, 0, sizeof(struct pohmelfs_script_req));
457 req.script_name = POHMELFS_UNLINK_SCRIPT;
458 req.script_namelen = sizeof(POHMELFS_UNLINK_SCRIPT) - 1; /* not including 0-byte */
460 req.obj_name = (char *)dentry->d_name.name;
461 req.obj_len = dentry->d_name.len;
463 req.binary = &parent->id;
464 req.binary_size = sizeof(struct dnet_raw_id);
466 req.group_id = 0;
467 req.id = &parent->id;
468 req.complete = pohmelfs_send_dentry_complete;
470 req.sync = 1;
472 err = pohmelfs_send_script_request(parent, &req);
473 if (err)
474 return err;
476 req.script_name = POHMELFS_DATA_UNLINK_SCRIPT;
477 req.script_namelen = sizeof(POHMELFS_DATA_UNLINK_SCRIPT) - 1; /* not including 0-byte */
479 req.binary = &pi->id;
480 req.binary_size = sizeof(struct dnet_raw_id);
482 return pohmelfs_send_script_request(parent, &req);
485 static int pohmelfs_rmdir(struct inode *dir, struct dentry *dentry)
487 return pohmelfs_unlink(dir, dentry);
490 struct pohmelfs_rename_req {
491 struct dnet_raw_id old_dir_id;
493 struct pohmelfs_dentry dentry;
494 } __attribute__ ((packed));
496 static int pohmelfs_rename(struct inode *old_dir, struct dentry *old_dentry,
497 struct inode *new_dir, struct dentry *new_dentry)
499 struct pohmelfs_inode *old_parent = pohmelfs_inode(old_dir);
500 struct inode *inode = old_dentry->d_inode;
501 struct inode *new_inode = new_dentry->d_inode;
502 struct pohmelfs_inode *pi = pohmelfs_inode(inode);
503 struct pohmelfs_script_req req;
504 struct pohmelfs_rename_req *r;
505 int size = sizeof(struct pohmelfs_rename_req) + new_dentry->d_name.len;
506 int err;
508 pr_debug("%s: rename: %.*s -> %.*s: mtime: %ld\n",
509 pohmelfs_dump_id(pi->id.id),
510 old_dentry->d_name.len, old_dentry->d_name.name,
511 new_dentry->d_name.len, new_dentry->d_name.name,
512 inode->i_mtime.tv_sec);
514 if (pohmelfs_sb(inode->i_sb)->http_compat) {
515 err = -ENOTSUPP;
516 goto err_out_exit;
519 r = kzalloc(size, GFP_NOIO);
520 if (!r) {
521 err = -ENOMEM;
522 goto err_out_exit;
525 r->old_dir_id = pohmelfs_inode(old_dir)->id;
526 r->dentry.parent_id = pohmelfs_inode(new_dir)->id;
527 r->dentry.disk.id = pohmelfs_inode(inode)->id;
528 r->dentry.disk.ino = cpu_to_le64(inode->i_ino);
529 r->dentry.disk.type = (inode->i_mode >> 12) & 15;
530 r->dentry.disk.len = new_dentry->d_name.len;
532 memcpy(r->dentry.disk.name, new_dentry->d_name.name, new_dentry->d_name.len);
534 memset(&req, 0, sizeof(struct pohmelfs_script_req));
536 req.script_name = POHMELFS_RENAME_SCRIPT;
537 req.script_namelen = sizeof(POHMELFS_RENAME_SCRIPT) - 1; /* not including 0-byte */
539 req.obj_name = (char *)old_dentry->d_name.name;
540 req.obj_len = old_dentry->d_name.len;
542 req.binary = r;
543 req.binary_size = size;
545 req.sync = 1;
546 req.group_id = 0;
547 req.id = &old_parent->id;
548 req.complete = pohmelfs_send_dentry_complete;
550 if (new_inode) {
551 new_inode->i_ctime = CURRENT_TIME_SEC;
553 inode->i_ctime = CURRENT_TIME_SEC;
554 mark_inode_dirty(inode);
555 mark_inode_dirty(new_dir);
557 err = pohmelfs_send_script_request(old_parent, &req);
558 if (err)
559 goto err_out_free;
561 err_out_free:
562 kfree(r);
563 err_out_exit:
564 return err;
567 static int pohmelfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
569 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
570 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
571 struct pohmelfs_inode *pi;
572 struct inode *inode;
573 unsigned len = strlen(symname)+1;
574 int err = 0;
576 inode_inc_link_count(dir);
577 pi = pohmelfs_new_inode(psb, S_IFLNK | S_IRWXUGO);
578 if (IS_ERR(pi)) {
579 err = PTR_ERR(pi);
580 goto err_out_exit;
582 inode = &pi->vfs_inode;
583 pohmelfs_init_local(pi, dir);
584 mark_inode_dirty(dir);
586 err = page_symlink(inode, symname, len);
587 if (err)
588 goto err_out_put;
590 d_instantiate(dentry, inode);
591 if (psb->http_compat)
592 pohmelfs_http_compat_id(pi);
594 err = pohmelfs_send_dentry(pi, &parent->id, dentry->d_name.name, dentry->d_name.len, 1);
595 if (err)
596 goto err_out_exit;
598 return 0;
600 err_out_put:
601 iput(inode);
602 err_out_exit:
603 inode_dec_link_count(dir);
604 return err;
607 static int pohmelfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
609 struct inode *inode = old_dentry->d_inode;
610 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
611 struct pohmelfs_inode *pi = pohmelfs_inode(inode);
612 struct pohmelfs_script_req req;
613 int err;
615 if (pohmelfs_sb(inode->i_sb)->http_compat) {
616 err = -ENOTSUPP;
617 goto err_out_exit;
620 dquot_initialize(dir);
622 inode->i_ctime = CURRENT_TIME_SEC;
623 inode_inc_link_count(inode);
624 ihold(inode);
626 err = pohmelfs_send_dentry(pi, &parent->id, dentry->d_name.name, dentry->d_name.len, 1);
627 if (err) {
628 goto err_out_put;
631 memset(&req, 0, sizeof(struct pohmelfs_script_req));
633 req.script_name = POHMELFS_HARDLINK_SCRIPT;
634 req.script_namelen = sizeof(POHMELFS_HARDLINK_SCRIPT) - 1; /* not including 0-byte */
636 req.obj_name = (char *)dentry->d_name.name;
637 req.obj_len = dentry->d_name.len;
639 req.binary = &pi->id;
640 req.binary_size = sizeof(struct dnet_raw_id);
642 req.group_id = 0;
643 req.id = &pi->id;
644 req.complete = pohmelfs_send_dentry_complete;
646 req.sync = 1;
648 err = pohmelfs_send_script_request(parent, &req);
649 if (err)
650 goto err_out_unlink;
652 mark_inode_dirty(dir);
653 mark_inode_dirty(inode);
654 d_instantiate(dentry, inode);
655 return 0;
657 err_out_unlink:
658 req.binary = &parent->id;
659 req.script_name = POHMELFS_UNLINK_SCRIPT;
660 req.script_namelen = sizeof(POHMELFS_UNLINK_SCRIPT) - 1; /* not including 0-byte */
661 pohmelfs_send_script_request(parent, &req);
662 err_out_put:
663 inode_dec_link_count(inode);
664 iput(inode);
665 err_out_exit:
666 return err;
669 static int pohmelfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev)
671 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
672 struct pohmelfs_inode *pi;
673 struct inode *inode;
674 int err;
676 if (!new_valid_dev(rdev))
677 return -EINVAL;
679 inode_inc_link_count(dir);
680 dquot_initialize(dir);
682 pi = pohmelfs_new_inode(psb, mode);
683 if (IS_ERR(pi)) {
684 err = PTR_ERR(pi);
685 goto err_out_exit;
687 inode = &pi->vfs_inode;
688 pohmelfs_init_local(pi, dir);
689 mark_inode_dirty(dir);
691 init_special_inode(inode, inode->i_mode, rdev);
692 inode->i_op = &pohmelfs_special_inode_operations;
694 d_instantiate(dentry, inode);
695 if (psb->http_compat)
696 pohmelfs_http_compat_id(pi);
698 err = pohmelfs_send_dentry(pi, &pohmelfs_inode(dir)->id, dentry->d_name.name, dentry->d_name.len, 1);
699 if (err)
700 goto err_out_exit;
702 return 0;
704 err_out_exit:
705 inode_dec_link_count(dir);
706 return err;
709 const struct inode_operations pohmelfs_dir_inode_operations = {
710 .create = pohmelfs_create,
711 .lookup = pohmelfs_lookup,
712 .mkdir = pohmelfs_mkdir,
713 .unlink = pohmelfs_unlink,
714 .rmdir = pohmelfs_rmdir,
715 .rename = pohmelfs_rename,
716 .symlink = pohmelfs_symlink,
717 .link = pohmelfs_link,
718 .mknod = pohmelfs_mknod,
721 static int pohmelfs_readdir_complete(struct pohmelfs_trans *t, struct pohmelfs_state *recv)
723 struct pohmelfs_inode *pi = pohmelfs_inode(t->inode);
724 struct pohmelfs_wait *wait = t->priv;
725 struct dnet_cmd *cmd = &recv->cmd;
727 pr_debug("%s: cmd size: %llu, flags: %x\n",
728 pohmelfs_dump_id(pi->id.id), (unsigned long long)cmd->size,
729 cmd->flags);
731 if (cmd->flags & DNET_FLAGS_MORE) {
732 if (cmd->size > sizeof(struct dnet_attr)) {
733 wait->ret = t->recv_data;
734 wait->condition = cmd->size;
736 t->recv_data = NULL;
737 wake_up(&wait->wq);
739 } else {
740 if (!wait->condition) {
741 wait->condition = cmd->status;
742 if (!wait->condition)
743 wait->condition = 1;
747 return 0;
750 static int pohmelfs_dentry_add(struct dentry *parent_dentry, struct pohmelfs_inode *pi, char *name, int len)
752 struct inode *inode = &pi->vfs_inode;
753 struct dentry *dentry, *old;
754 struct qstr str;
755 int err = 0;
757 str.name = name;
758 str.len = len;
759 str.hash = full_name_hash(str.name, str.len);
761 dentry = d_lookup(parent_dentry, &str);
762 if (dentry) {
763 err = -EEXIST;
765 dput(dentry);
766 goto err_out_exit;
769 * if things are ok, dentry has 2 references -
770 * one in parent dir, and another its own,
771 * which we should drop
773 dentry = d_alloc(parent_dentry, &str);
774 if (!dentry) {
775 err = -ENOMEM;
776 goto err_out_exit;
779 old = d_splice_alias(inode, dentry);
780 if (unlikely(old)) {
781 dput(dentry);
782 err = -EEXIST;
783 } else {
784 dput(dentry);
787 err_out_exit:
788 return err;
791 static int pohmelfs_update_inode(struct dentry *parent_dentry, struct pohmelfs_inode_info *info, char *name)
793 struct pohmelfs_sb *psb = pohmelfs_sb(parent_dentry->d_inode->i_sb);
794 struct pohmelfs_inode *pi;
795 struct inode *inode;
796 int err = 0;
798 pi = pohmelfs_sb_inode_lookup(psb, &info->id);
799 if (pi) {
800 inode = &pi->vfs_inode;
801 pohmelfs_fill_inode(inode, info);
802 } else {
803 pi = pohmelfs_existing_inode(psb, info);
804 if (IS_ERR(pi)) {
805 err = PTR_ERR(pi);
806 goto err_out_exit;
808 inode = &pi->vfs_inode;
811 mutex_lock(&inode->i_mutex);
812 err = pohmelfs_dentry_add(parent_dentry, pi, name, info->namelen);
813 mutex_unlock(&inode->i_mutex);
814 if (err)
815 iput(inode);
817 err_out_exit:
818 return err;
821 struct pohmelfs_fetch_info {
822 struct dentry *parent;
823 struct kref refcnt;
824 int len;
825 char name[0];
828 static void pohmelfs_fetch_inode_info_free(struct kref *kref)
830 struct pohmelfs_fetch_info *fi = container_of(kref, struct pohmelfs_fetch_info, refcnt);
832 dput(fi->parent);
833 kfree(fi);
836 static void pohmelfs_fetch_inode_info_destroy(struct pohmelfs_trans *t)
838 struct pohmelfs_fetch_info *fi = t->priv;
840 kref_put(&fi->refcnt, pohmelfs_fetch_inode_info_free);
843 static int pohmelfs_fetch_inode_info_init(struct pohmelfs_trans *t)
845 struct pohmelfs_fetch_info *fi = t->priv;
847 kref_get(&fi->refcnt);
848 return 0;
851 static int pohmelfs_fetch_inode_info_complete(struct pohmelfs_trans *t, struct pohmelfs_state *recv)
853 struct pohmelfs_fetch_info *fi = t->priv;
854 struct dnet_cmd *cmd = &recv->cmd;
855 struct pohmelfs_inode_info *info;
856 int err;
858 if (cmd->status)
859 return 0;
861 if (cmd->size < sizeof(struct dnet_attr) + sizeof(struct dnet_io_attr) + sizeof(struct pohmelfs_inode_info))
862 return 0;
864 info = t->recv_data + sizeof(struct dnet_attr) + sizeof(struct dnet_io_attr);
865 pohmelfs_convert_inode_info(info);
867 info->namelen = fi->len;
868 err = pohmelfs_update_inode(fi->parent, info, fi->name);
870 pr_debug("%s: fetched: '%.*s': %d\n",
871 pohmelfs_dump_id(cmd->id.id), fi->len, fi->name, err);
872 return 0;
875 static int pohmelfs_fetch_inode_info_group(struct dentry *parent, struct pohmelfs_inode *pi,
876 struct pohmelfs_dentry_disk *d, int *groups, int group_num)
878 struct pohmelfs_sb *psb = pohmelfs_sb(pi->vfs_inode.i_sb);
879 struct pohmelfs_io *pio;
880 struct pohmelfs_fetch_info *fi;
881 int err, i;
883 pio = kmem_cache_zalloc(pohmelfs_io_cache, GFP_NOIO);
884 if (!pio) {
885 err = -ENOMEM;
886 goto err_out_exit;
889 fi = kmalloc(sizeof(struct pohmelfs_fetch_info) + d->len, GFP_NOIO);
890 if (!fi) {
891 err = -ENOMEM;
892 goto err_out_free;
895 memcpy(fi->name, d->name, d->len);
896 fi->len = d->len;
897 kref_init(&fi->refcnt);
898 fi->parent = dget(parent);
900 pio->pi = pi;
901 pio->id = &d->id;
902 pio->cmd = DNET_CMD_READ;
903 pio->cflags = DNET_FLAGS_NEED_ACK | DNET_FLAGS_NOLOCK;
904 if (psb->no_read_csum)
905 pio->ioflags = DNET_IO_FLAGS_NOCSUM;
906 pio->type = POHMELFS_INODE_COLUMN;
907 pio->cb.complete = pohmelfs_fetch_inode_info_complete;
908 pio->cb.init = pohmelfs_fetch_inode_info_init;
909 pio->cb.destroy = pohmelfs_fetch_inode_info_destroy;
910 pio->priv = fi;
912 err = -ENOENT;
913 for (i = 0; i < group_num; ++i) {
914 pio->group_id = groups[i];
915 err = pohmelfs_send_io_group(pio, groups[i]);
916 if (!err)
917 break;
920 kref_put(&fi->refcnt, pohmelfs_fetch_inode_info_free);
921 err_out_free:
922 kmem_cache_free(pohmelfs_io_cache, pio);
923 err_out_exit:
924 return err;
927 static int pohmelfs_fetch_inode_info(struct dentry *parent, struct pohmelfs_inode *pi, struct pohmelfs_dentry_disk *d)
929 struct pohmelfs_sb *psb = pohmelfs_sb(pi->vfs_inode.i_sb);
930 if (pi->groups)
931 return pohmelfs_fetch_inode_info_group(parent, pi, d, pi->groups, pi->group_num);
932 else
933 return pohmelfs_fetch_inode_info_group(parent, pi, d, psb->groups, psb->group_num);
936 static int pohmelfs_readdir_process(void *data, int size, struct file *filp, void *dirent, filldir_t filldir)
938 struct dentry *dentry = filp->f_path.dentry, *child;
939 struct inode *dir = dentry->d_inode;
940 void *orig_data = data;
941 int orig_size = size;
942 struct qstr str;
943 int err = 0;
945 while (size > 0) {
946 struct pohmelfs_dentry_disk *d = data;
948 if (size < sizeof(struct pohmelfs_dentry_disk)) {
949 err = -EINVAL;
950 goto err_out_exit;
953 if (size < d->len) {
954 err = -EINVAL;
955 goto err_out_exit;
958 str.name = d->name;
959 str.len = d->len;
960 str.hash = full_name_hash(str.name, str.len);
962 child = d_lookup(dentry, &str);
963 pr_debug("%s: child: %.*s/%.*s: %p\n",
964 pohmelfs_dump_id(d->id.id),
965 dentry->d_name.len, dentry->d_name.name,
966 d->len, d->name,
967 child);
968 if (!child) {
969 pohmelfs_fetch_inode_info(dentry, pohmelfs_inode(dir), d);
970 } else {
971 dput(child);
974 size -= sizeof(struct pohmelfs_dentry_disk) + d->len;
975 data += sizeof(struct pohmelfs_dentry_disk) + d->len;
978 data = orig_data;
979 size = orig_size;
980 while (size > 0) {
981 struct pohmelfs_dentry_disk *d = data;
983 err = filldir(dirent, d->name, d->len, filp->f_pos, le64_to_cpu(d->ino), d->type);
984 if (err)
985 return 0;
987 filp->f_pos += 1;
988 size -= sizeof(struct pohmelfs_dentry_disk) + d->len;
989 data += sizeof(struct pohmelfs_dentry_disk) + d->len;
992 err_out_exit:
993 return err;
996 struct pohmelfs_readdir {
997 struct dnet_raw_id id;
998 int max_size;
999 int fpos;
1002 static void *pohmelfs_readdir_group(int group_id, struct file *filp, int *sizep)
1004 struct dentry *dentry = filp->f_path.dentry;
1005 struct inode *dir = dentry->d_inode;
1006 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
1007 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
1008 struct pohmelfs_readdir rd;
1009 struct pohmelfs_script_req req;
1010 void *data;
1011 int size;
1012 int err;
1014 memset(&req, 0, sizeof(struct pohmelfs_script_req));
1016 req.script_name = POHMELFS_READDIR_SCRIPT;
1017 req.script_namelen = sizeof(POHMELFS_READDIR_SCRIPT) - 1; /* not including 0-byte */
1019 req.obj_name = (char *)dentry->d_name.name;
1020 req.obj_len = dentry->d_name.len;
1022 rd.id = parent->id;
1023 rd.max_size = psb->readdir_allocation * PAGE_SIZE - sizeof(struct dnet_attr); /* cmd->size should fit one page */
1024 rd.fpos = filp->f_pos - 2; /* account for . and .. */
1026 req.binary = &rd;
1027 req.binary_size = sizeof(struct pohmelfs_readdir);
1029 req.id = &parent->id;
1030 req.complete = pohmelfs_readdir_complete;
1031 req.cflags = 0;
1033 req.group_id = group_id;
1034 req.sync = 1;
1036 err = pohmelfs_send_script_request(parent, &req);
1037 if (err < 0)
1038 goto err_out_exit;
1040 data = req.ret;
1041 size = req.ret_cond;
1042 if (!data || !size) {
1043 err = -ENOENT;
1044 goto err_out_exit;
1047 *sizep = size;
1048 return data;
1050 err_out_exit:
1051 return ERR_PTR(err);
1054 static int pohmelfs_dir_open(struct inode *dir, struct file *filp)
1056 #if 0
1057 struct pohmelfs_inode *pi = pohmelfs_inode(dir);
1059 if (!pohmelfs_need_resync(pi))
1060 return dcache_dir_open(dir, filp);
1061 #endif
1062 filp->f_pos = 0;
1063 return 0;
1066 static int pohmelfs_dir_close(struct inode *inode, struct file *filp)
1068 if (filp->private_data)
1069 return dcache_dir_close(inode, filp);
1070 return 0;
1073 static int pohmelfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
1075 struct dentry *dentry = filp->f_path.dentry;
1076 struct inode *dir = dentry->d_inode;
1077 struct pohmelfs_inode *pi = pohmelfs_inode(dir);
1078 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
1079 int i, err = -ENOENT;
1081 if (filp->private_data) {
1082 return dcache_readdir(filp, dirent, filldir);
1085 if (filp->f_pos == 0) {
1086 err = filldir(dirent, ".", 1, filp->f_pos, dir->i_ino, DT_DIR);
1087 if (err)
1088 return err;
1089 filp->f_pos++;
1092 if (filp->f_pos == 1) {
1093 err = filldir(dirent, "..", 2, filp->f_pos, parent_ino(dentry), DT_DIR);
1094 if (err)
1095 return err;
1096 filp->f_pos++;
1099 for (i = 0; i < psb->group_num; ++i) {
1100 int size;
1101 void *data;
1103 data = pohmelfs_readdir_group(psb->groups[i], filp, &size);
1104 if (IS_ERR(data)) {
1105 err = PTR_ERR(data);
1106 continue;
1109 pi->update = get_seconds();
1110 err = pohmelfs_readdir_process(data + sizeof(struct dnet_attr), size - sizeof(struct dnet_attr), filp, dirent, filldir);
1111 kfree(data);
1113 break;
1116 return err;
1119 const struct file_operations pohmelfs_dir_fops = {
1120 .open = pohmelfs_dir_open,
1121 .release = pohmelfs_dir_close,
1122 .read = generic_read_dir,
1123 .readdir = pohmelfs_readdir,