Use correct parent ID when doing hard/symlinks
[pohmelfs.git] / fs / pohmelfs / dir.c
blob8d64345d1a6094542ecda09f899918aee0d06c02
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_init_local(struct pohmelfs_inode *pi, struct inode *dir)
22 struct inode *inode = &pi->vfs_inode;
24 inode_init_owner(inode, dir, inode->i_mode);
25 pi->parent_id = pohmelfs_inode(dir)->id;
26 pi->local = 1;
29 static int pohmelfs_send_dentry_complete(struct pohmelfs_trans *t, struct pohmelfs_state *recv)
31 struct pohmelfs_inode *pi = pohmelfs_inode(t->inode);
32 struct pohmelfs_wait *wait = t->priv;
33 struct dnet_cmd *cmd = &recv->cmd;
34 unsigned long long trans = cmd->trans & ~DNET_TRANS_REPLY;
36 if (cmd->flags & DNET_FLAGS_MORE) {
37 if (cmd->status == 0 && cmd->size != sizeof(struct dnet_attr) + 2)
38 cmd->status = -EINVAL;
40 pr_debug("pohmelfs: %s: pohmelfs_send_dentry_complete: %llu, cmd_size: %llu, flags: %x, status: %d\n",
41 pohmelfs_dump_id(pi->id.id), trans, cmd->size, cmd->flags, cmd->status);
43 if (!cmd->status)
44 wait->condition = 1;
45 else
46 wait->condition = cmd->status;
47 wake_up(&wait->wq);
50 return 0;
53 static int pohmelfs_send_inode_info_init(struct pohmelfs_trans *t)
55 struct pohmelfs_wait *wait = t->priv;
57 pohmelfs_wait_get(wait);
58 return 0;
61 static void pohmelfs_send_inode_info_destroy(struct pohmelfs_trans *t)
63 struct pohmelfs_wait *wait = t->priv;
65 if (!wait->condition)
66 wait->condition = 1;
67 wake_up(&wait->wq);
68 pohmelfs_wait_put(wait);
71 static int pohmelfs_lookup_complete(struct pohmelfs_trans *t, struct pohmelfs_state *recv)
73 struct pohmelfs_inode *parent = pohmelfs_inode(t->inode);
74 struct pohmelfs_wait *wait = t->priv;
75 struct dnet_cmd *cmd = &recv->cmd;
76 unsigned long long trans = cmd->trans & ~DNET_TRANS_REPLY;
77 int err = cmd->status;
79 if (err)
80 goto err_out_exit;
82 if (cmd->flags & DNET_FLAGS_MORE) {
83 struct pohmelfs_sb *psb = pohmelfs_sb(t->inode->i_sb);
84 struct pohmelfs_inode_info *info;
85 struct pohmelfs_inode *pi;
87 if (cmd->size != sizeof(struct dnet_attr) + sizeof(struct pohmelfs_inode_info)) {
88 err = -ENOENT;
89 goto err_out_exit;
92 pr_debug("pohmelfs: %s: pohmelfs_lookup_complete: %llu, size: %llu, min size: %zu, flags: %x, status: %d\n",
93 pohmelfs_dump_id(parent->id.id), trans, cmd->size,
94 sizeof(struct dnet_attr) + sizeof(struct pohmelfs_inode_info), cmd->flags, cmd->status);
97 info = t->recv_data + sizeof(struct dnet_attr);
98 pohmelfs_convert_inode_info(info);
100 pi = pohmelfs_existing_inode(psb, info);
101 if (IS_ERR(pi)) {
102 err = PTR_ERR(pi);
104 if (err != -EEXIST)
105 goto err_out_exit;
107 err = 0;
108 pi = pohmelfs_sb_inode_lookup(psb, &info->id);
109 if (!pi) {
110 err = -ENOENT;
111 goto err_out_exit;
114 pohmelfs_fill_inode(&pi->vfs_inode, info);
117 pi->parent_id = parent->id;
118 wait->ret = pi;
121 err_out_exit:
122 if (err)
123 wait->condition = err;
124 else
125 wait->condition = 1;
126 wake_up(&wait->wq);
128 return 0;
131 int pohmelfs_send_script_request(struct pohmelfs_inode *parent, struct pohmelfs_script_req *req)
133 struct pohmelfs_sb *psb = pohmelfs_sb(parent->vfs_inode.i_sb);
134 struct pohmelfs_wait *wait;
135 struct pohmelfs_io *pio;
136 struct dnet_exec *e;
137 int script_len;
138 long ret;
139 int err;
141 /* 2 commas, \n and 0-byte, which is accounted in sizeof(string) */
142 script_len = sizeof(POHMELFS_DENTRY_NAME_SCRIPT) + req->obj_len + 3;
144 wait = pohmelfs_wait_alloc(parent);
145 if (!wait) {
146 err = -ENOMEM;
147 goto err_out_exit;
150 pio = kmem_cache_zalloc(pohmelfs_io_cache, GFP_NOIO);
151 if (!pio) {
152 err = -ENOMEM;
153 goto err_out_wait_put;
156 e = kmalloc(sizeof(struct dnet_exec) + req->script_namelen + script_len + req->binary_size, GFP_NOIO);
157 if (!e) {
158 err = -ENOMEM;
159 goto err_out_free_pio;
162 memset(e, 0, sizeof(struct dnet_exec));
164 snprintf(e->data, req->script_namelen + script_len, "%s%s'%s'\n", req->script_name, POHMELFS_DENTRY_NAME_SCRIPT, req->obj_name);
165 script_len--; /* do not include last 0-byte in the script */
167 memcpy(e->data + req->script_namelen + script_len, req->binary, req->binary_size);
169 e->type = DNET_EXEC_PYTHON_SCRIPT_NAME;
170 e->name_size = req->script_namelen;
171 e->script_size = script_len;
172 e->binary_size = req->binary_size;
173 dnet_convert_exec(e);
175 pio->pi = parent;
176 pio->id = req->id;
177 pio->group_id = req->group_id;
178 pio->cflags = DNET_FLAGS_NEED_ACK | req->cflags;
180 pio->cmd = DNET_CMD_EXEC;
181 pio->size = sizeof(struct dnet_exec) + req->script_namelen + script_len + req->binary_size;
182 pio->data = e;
183 pio->priv = wait;
184 pio->cb.init = pohmelfs_send_inode_info_init;
185 pio->cb.destroy = pohmelfs_send_inode_info_destroy;
186 pio->cb.complete = req->complete;
188 if (pio->group_id) {
189 err = pohmelfs_send_buf_single(pio, NULL);
190 } else {
191 err = pohmelfs_send_buf(pio);
193 if (err)
194 goto err_out_free;
197 int len = 6;
198 char parent_id_str[len*2+1];
200 pr_debug("pohmelfs: SENT: %.*s: %s: inode->id: %s, ino: %lu, object: %s, binary size: %d, ret: %p, condition: %d\n",
201 req->script_namelen, req->script_name,
202 pohmelfs_dump_id(req->id->id),
203 pohmelfs_dump_id_len_raw(parent->id.id, len, parent_id_str),
204 parent->vfs_inode.i_ino, req->obj_name, req->binary_size,
205 req->ret, req->ret_cond);
208 if (req->sync) {
209 ret = wait_event_interruptible_timeout(wait->wq, wait->condition != 0, msecs_to_jiffies(psb->read_wait_timeout));
210 if (ret <= 0) {
211 err = ret;
212 if (ret == 0)
213 err = -ETIMEDOUT;
214 goto err_out_free;
217 if (wait->condition < 0)
218 err = wait->condition;
220 req->ret = wait->ret;
221 req->ret_cond = wait->condition;
224 err_out_free:
225 kfree(e);
226 err_out_free_pio:
227 kmem_cache_free(pohmelfs_io_cache, pio);
228 err_out_wait_put:
229 pohmelfs_wait_put(wait);
230 err_out_exit:
232 int len = 6;
233 char parent_id_str[len*2+1];
235 pr_debug("pohmelfs: DONE: %.*s: %s: inode->id: %s, ino: %lu, object: %s, binary size: %d, ret: %p, condition: %d, err: %d\n",
236 req->script_namelen, req->script_name,
237 pohmelfs_dump_id(req->id->id),
238 pohmelfs_dump_id_len_raw(parent->id.id, len, parent_id_str),
239 parent->vfs_inode.i_ino, req->obj_name, req->binary_size,
240 req->ret, req->ret_cond, err);
242 return err;
245 int pohmelfs_send_dentry(struct pohmelfs_inode *pi, struct dnet_raw_id *id, const char *sname, int len, int sync)
247 struct inode *inode = &pi->vfs_inode;
248 struct pohmelfs_script_req req;
249 struct pohmelfs_dentry *pd;
250 int err;
252 if (!len) {
253 err = -EINVAL;
254 goto err_out_exit;
257 pd = kmem_cache_alloc(pohmelfs_dentry_cache, GFP_NOIO);
258 if (!pd) {
259 err = -ENOMEM;
260 goto err_out_exit;
263 pd->parent_id = *id;
264 pd->disk.id = pi->id;
265 pd->disk.ino = cpu_to_le64(pi->vfs_inode.i_ino);
266 pd->disk.type = (pi->vfs_inode.i_mode >> 12) & 15;
267 pd->disk.len = len;
269 memset(&req, 0, sizeof(struct pohmelfs_script_req));
271 req.id = id;
273 req.script_name = POHMELFS_INODE_INFO_SCRIPT_INSERT;
274 req.script_namelen = sizeof(POHMELFS_INODE_INFO_SCRIPT_INSERT) - 1; /* not including 0-byte */
276 req.obj_name = (char *)sname;
277 req.obj_len = len;
279 req.binary = pd;
280 req.binary_size = sizeof(struct pohmelfs_dentry);
282 req.group_id = 0;
283 req.id = id;
285 req.sync = sync;
286 req.complete = pohmelfs_send_dentry_complete;
288 err = pohmelfs_send_script_request(pi, &req);
289 if (err)
290 goto err_out_free;
292 err = inode->i_sb->s_op->write_inode(inode, NULL);
294 err_out_free:
295 kmem_cache_free(pohmelfs_dentry_cache, pd);
296 err_out_exit:
297 return err;
300 static int pohmelfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
301 struct nameidata *nd)
303 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
304 struct pohmelfs_inode *pi;
305 int err;
307 inode_inc_link_count(dir);
309 pi = pohmelfs_new_inode(psb, mode);
310 if (IS_ERR(pi)) {
311 err = PTR_ERR(pi);
312 goto err_out_exit;
314 pohmelfs_init_local(pi, dir);
317 * calling d_instantiate() implies that
318 * ->lookup() used d_splice_alias() with NULL inode
319 * when it failed to find requested object
321 d_instantiate(dentry, &pi->vfs_inode);
322 if (psb->http_compat)
323 pohmelfs_http_compat_id(pi);
325 err = pohmelfs_send_dentry(pi, &pi->parent_id, dentry->d_name.name, dentry->d_name.len, 1);
326 if (err)
327 goto err_out_exit;
329 pr_debug("pohmelfs: create: %s, ino: %lu, parent dir: %lu, object: %s\n",
330 pohmelfs_dump_id(pi->id.id), pi->vfs_inode.i_ino,
331 dir->i_ino, dentry->d_name.name);
333 return 0;
335 err_out_exit:
336 inode_dec_link_count(dir);
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 = 0;
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 return d_splice_alias(inode, dentry);
405 static int pohmelfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
407 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
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;
418 pohmelfs_init_local(pi, dir);
420 d_instantiate(dentry, &pi->vfs_inode);
421 if (psb->http_compat)
422 pohmelfs_http_compat_id(pi);
424 err = pohmelfs_send_dentry(pi, &pi->parent_id, dentry->d_name.name, dentry->d_name.len, 1);
425 if (err)
426 goto err_out_dir;
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_dir:
434 inode_dec_link_count(dir);
435 return err;
438 static int pohmelfs_unlink(struct inode *dir, struct dentry *dentry)
440 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
441 struct inode *inode = dentry->d_inode;
442 struct pohmelfs_inode *pi = pohmelfs_inode(inode);
443 struct pohmelfs_script_req req;
444 int err;
446 inode->i_ctime = dir->i_ctime;
448 memset(&req, 0, sizeof(struct pohmelfs_script_req));
450 req.script_name = POHMELFS_UNLINK_SCRIPT;
451 req.script_namelen = sizeof(POHMELFS_UNLINK_SCRIPT) - 1; /* not including 0-byte */
453 req.obj_name = (char *)dentry->d_name.name;
454 req.obj_len = dentry->d_name.len;
456 req.binary = &parent->id;
457 req.binary_size = sizeof(struct dnet_raw_id);
459 req.group_id = 0;
460 req.id = &parent->id;
461 req.complete = pohmelfs_send_dentry_complete;
463 req.sync = 1;
465 err = pohmelfs_send_script_request(parent, &req);
466 if (err)
467 return err;
469 req.script_name = POHMELFS_DATA_UNLINK_SCRIPT;
470 req.script_namelen = sizeof(POHMELFS_DATA_UNLINK_SCRIPT) - 1; /* not including 0-byte */
472 req.binary = &pi->id;
473 req.binary_size = sizeof(struct dnet_raw_id);
475 return pohmelfs_send_script_request(parent, &req);
478 static int pohmelfs_rmdir(struct inode *dir, struct dentry *dentry)
480 return pohmelfs_unlink(dir, dentry);
483 struct pohmelfs_rename_req {
484 struct dnet_raw_id old_dir_id;
486 struct pohmelfs_dentry dentry;
487 } __attribute__ ((packed));
489 static int pohmelfs_rename(struct inode *old_dir, struct dentry *old_dentry,
490 struct inode *new_dir, struct dentry *new_dentry)
492 struct pohmelfs_inode *old_parent = pohmelfs_inode(old_dir);
493 struct inode *inode = old_dentry->d_inode;
494 struct inode *new_inode = new_dentry->d_inode;
495 struct pohmelfs_inode *pi = pohmelfs_inode(inode);
496 struct pohmelfs_script_req req;
497 struct pohmelfs_rename_req *r;
498 int size = sizeof(struct pohmelfs_rename_req) + new_dentry->d_name.len;
499 int err;
501 pr_debug("pohmelfs: %s: rename: %.*s -> %.*s: mtime: %ld\n", pohmelfs_dump_id(pi->id.id),
502 old_dentry->d_name.len, old_dentry->d_name.name,
503 new_dentry->d_name.len, new_dentry->d_name.name,
504 inode->i_mtime.tv_sec);
506 if (pohmelfs_sb(inode->i_sb)->http_compat) {
507 err = -ENOTSUPP;
508 goto err_out_exit;
511 r = kzalloc(size, GFP_NOIO);
512 if (!r) {
513 err = -ENOMEM;
514 goto err_out_exit;
517 r->old_dir_id = pohmelfs_inode(old_dir)->id;
518 r->dentry.parent_id = pohmelfs_inode(new_dir)->id;
519 r->dentry.disk.id = pohmelfs_inode(inode)->id;
520 r->dentry.disk.ino = cpu_to_le64(inode->i_ino);
521 r->dentry.disk.type = (inode->i_mode >> 12) & 15;
522 r->dentry.disk.len = new_dentry->d_name.len;
524 memcpy(r->dentry.disk.name, new_dentry->d_name.name, new_dentry->d_name.len);
526 memset(&req, 0, sizeof(struct pohmelfs_script_req));
528 req.script_name = POHMELFS_RENAME_SCRIPT;
529 req.script_namelen = sizeof(POHMELFS_RENAME_SCRIPT) - 1; /* not including 0-byte */
531 req.obj_name = (char *)old_dentry->d_name.name;
532 req.obj_len = old_dentry->d_name.len;
534 req.binary = r;
535 req.binary_size = size;
537 req.sync = 1;
538 req.group_id = 0;
539 req.id = &old_parent->id;
540 req.complete = pohmelfs_send_dentry_complete;
542 if (new_inode) {
543 new_inode->i_ctime = CURRENT_TIME_SEC;
545 inode->i_ctime = CURRENT_TIME_SEC;
546 mark_inode_dirty(inode);
548 err = pohmelfs_send_script_request(old_parent, &req);
549 if (err)
550 goto err_out_free;
552 err_out_free:
553 kfree(r);
554 err_out_exit:
555 return err;
558 static int pohmelfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
560 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
561 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
562 struct pohmelfs_inode *pi;
563 struct inode *inode;
564 unsigned len = strlen(symname)+1;
565 int err = 0;
567 inode_inc_link_count(dir);
568 pi = pohmelfs_new_inode(psb, S_IFLNK | S_IRWXUGO);
569 if (IS_ERR(pi)) {
570 err = PTR_ERR(pi);
571 goto err_out_exit;
573 inode = &pi->vfs_inode;
574 pohmelfs_init_local(pi, dir);
576 err = page_symlink(inode, symname, len);
577 if (err)
578 goto err_out_put;
580 d_instantiate(dentry, inode);
581 if (psb->http_compat)
582 pohmelfs_http_compat_id(pi);
584 err = pohmelfs_send_dentry(pi, &parent->id, dentry->d_name.name, dentry->d_name.len, 1);
585 if (err)
586 goto err_out_exit;
588 return 0;
590 err_out_put:
591 iput(inode);
592 err_out_exit:
593 inode_dec_link_count(dir);
594 return err;
597 static int pohmelfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
599 struct inode *inode = old_dentry->d_inode;
600 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
601 struct pohmelfs_inode *pi = pohmelfs_inode(inode);
602 struct pohmelfs_script_req req;
603 int err;
605 if (pohmelfs_sb(inode->i_sb)->http_compat) {
606 err = -ENOTSUPP;
607 goto err_out_exit;
610 dquot_initialize(dir);
612 inode->i_ctime = CURRENT_TIME_SEC;
613 inode_inc_link_count(inode);
614 ihold(inode);
616 err = pohmelfs_send_dentry(pi, &parent->id, dentry->d_name.name, dentry->d_name.len, 1);
617 if (err) {
618 goto err_out_put;
621 memset(&req, 0, sizeof(struct pohmelfs_script_req));
623 req.script_name = POHMELFS_HARDLINK_SCRIPT;
624 req.script_namelen = sizeof(POHMELFS_HARDLINK_SCRIPT) - 1; /* not including 0-byte */
626 req.obj_name = (char *)dentry->d_name.name;
627 req.obj_len = dentry->d_name.len;
629 req.binary = &pi->id;
630 req.binary_size = sizeof(struct dnet_raw_id);
632 req.group_id = 0;
633 req.id = &pi->id;
634 req.complete = pohmelfs_send_dentry_complete;
636 req.sync = 1;
638 err = pohmelfs_send_script_request(parent, &req);
639 if (err)
640 goto err_out_unlink;
642 d_instantiate(dentry, inode);
643 return 0;
645 err_out_unlink:
646 req.binary = &parent->id;
647 req.script_name = POHMELFS_UNLINK_SCRIPT;
648 req.script_namelen = sizeof(POHMELFS_UNLINK_SCRIPT) - 1; /* not including 0-byte */
649 pohmelfs_send_script_request(parent, &req);
650 err_out_put:
651 inode_dec_link_count(inode);
652 iput(inode);
653 err_out_exit:
654 return err;
657 static int pohmelfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev)
659 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
660 struct pohmelfs_inode *pi;
661 struct inode *inode;
662 int err;
664 if (!new_valid_dev(rdev))
665 return -EINVAL;
667 inode_inc_link_count(dir);
668 dquot_initialize(dir);
670 pi = pohmelfs_new_inode(psb, mode);
671 if (IS_ERR(pi)) {
672 err = PTR_ERR(pi);
673 goto err_out_exit;
675 inode = &pi->vfs_inode;
676 pohmelfs_init_local(pi, dir);
678 init_special_inode(inode, inode->i_mode, rdev);
679 inode->i_op = &pohmelfs_special_inode_operations;
681 d_instantiate(dentry, inode);
682 if (psb->http_compat)
683 pohmelfs_http_compat_id(pi);
685 err = pohmelfs_send_dentry(pi, &pi->parent_id, dentry->d_name.name, dentry->d_name.len, 1);
686 if (err)
687 goto err_out_exit;
689 return 0;
691 err_out_exit:
692 inode_dec_link_count(dir);
693 return err;
696 const struct inode_operations pohmelfs_dir_inode_operations = {
697 .create = pohmelfs_create,
698 .lookup = pohmelfs_lookup,
699 .mkdir = pohmelfs_mkdir,
700 .unlink = pohmelfs_unlink,
701 .rmdir = pohmelfs_rmdir,
702 .rename = pohmelfs_rename,
703 .symlink = pohmelfs_symlink,
704 .link = pohmelfs_link,
705 .mknod = pohmelfs_mknod,
708 static int pohmelfs_readdir_complete(struct pohmelfs_trans *t, struct pohmelfs_state *recv)
710 struct pohmelfs_inode *pi = pohmelfs_inode(t->inode);
711 struct pohmelfs_wait *wait = t->priv;
712 struct dnet_cmd *cmd = &recv->cmd;
714 pr_debug("pohmelfs: %s: readdir comlete: cmd size: %llu, flags: %x\n",
715 pohmelfs_dump_id(pi->id.id), (unsigned long long)cmd->size, cmd->flags);
717 if (cmd->flags & DNET_FLAGS_MORE) {
718 if (cmd->size > sizeof(struct dnet_attr)) {
719 wait->ret = t->recv_data;
720 wait->condition = cmd->size;
722 t->recv_data = NULL;
723 wake_up(&wait->wq);
725 } else {
726 if (!wait->condition) {
727 wait->condition = cmd->status;
728 if (!wait->condition)
729 wait->condition = 1;
733 return 0;
736 static int pohmelfs_dentry_add(struct pohmelfs_inode *parent, struct pohmelfs_inode *pi, char *name, int len)
738 struct inode *inode = &pi->vfs_inode;
739 struct inode *dir = &parent->vfs_inode;
740 struct dentry *dentry, *parent_dentry, *old;
741 struct qstr str;
742 int err;
744 str.name = name;
745 str.len = len;
746 str.hash = full_name_hash(str.name, str.len);
748 /* we do not need to hold dir->i_mutex here, don't we? :) */
749 parent_dentry = d_find_alias(dir);
750 if (!parent_dentry) {
751 err = -ENOENT;
752 goto err_out_exit;
755 dentry = d_lookup(parent_dentry, &str);
756 if (dentry) {
757 err = -EEXIST;
759 dput(dentry);
760 goto err_out_put_parent;
763 * if things are ok, dentry has 2 references -
764 * one in parent dir, and another its own,
765 * which we should drop
767 dentry = d_alloc(parent_dentry, &str);
768 if (!dentry) {
769 err = -ENOMEM;
770 goto err_out_put_parent;
773 old = d_splice_alias(inode, dentry);
774 if (unlikely(old)) {
775 dput(dentry);
776 dentry = old;
777 } else {
778 dput(dentry);
781 dput(parent_dentry);
782 return 0;
784 err_out_put_parent:
785 dput(parent_dentry);
786 err_out_exit:
787 return err;
790 static int pohmelfs_update_inode(struct pohmelfs_inode *parent, struct pohmelfs_inode_info *info, char *name)
792 struct pohmelfs_sb *psb = pohmelfs_sb(parent->vfs_inode.i_sb);
793 struct pohmelfs_inode *pi;
794 struct inode *inode;
795 int err = 0;
797 pi = pohmelfs_sb_inode_lookup(psb, &info->id);
798 if (pi) {
799 inode = &pi->vfs_inode;
800 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;
810 pi->parent_id = parent->id;
813 err = pohmelfs_dentry_add(parent, pi, name, info->namelen);
814 if (err)
815 iput(inode);
817 err_out_exit:
818 return err;
821 struct pohmelfs_fetch_info {
822 struct kref refcnt;
823 int len;
824 char name[0];
827 static void pohmelfs_fetch_inode_info_free(struct kref *kref)
829 struct pohmelfs_fetch_info *fi = container_of(kref, struct pohmelfs_fetch_info, refcnt);
831 kfree(fi);
834 static void pohmelfs_fetch_inode_info_destroy(struct pohmelfs_trans *t)
836 struct pohmelfs_fetch_info *fi = t->priv;
838 kref_put(&fi->refcnt, pohmelfs_fetch_inode_info_free);
841 static int pohmelfs_fetch_inode_info_init(struct pohmelfs_trans *t)
843 struct pohmelfs_fetch_info *fi = t->priv;
845 kref_get(&fi->refcnt);
846 return 0;
849 static int pohmelfs_fetch_inode_info_complete(struct pohmelfs_trans *t, struct pohmelfs_state *recv)
851 struct pohmelfs_fetch_info *fi = t->priv;
852 struct dnet_cmd *cmd = &recv->cmd;
853 struct pohmelfs_inode_info *info;
855 if (cmd->status)
856 return 0;
858 if (!(cmd->flags & DNET_FLAGS_MORE))
859 return 0;
861 if (cmd->size <= sizeof(struct dnet_attr) + sizeof(struct dnet_io_attr) + sizeof(struct dnet_io_attr))
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 pohmelfs_update_inode(pohmelfs_inode(t->inode), info, fi->name);
870 return 0;
873 static int pohmelfs_fetch_inode_info_group(struct pohmelfs_inode *pi, struct pohmelfs_dentry_disk *d, int *groups, int group_num)
875 struct pohmelfs_sb *psb = pohmelfs_sb(pi->vfs_inode.i_sb);
876 struct pohmelfs_io *pio;
877 struct pohmelfs_fetch_info *fi;
878 int err, i;
880 pio = kmem_cache_zalloc(pohmelfs_io_cache, GFP_NOIO);
881 if (!pio) {
882 err = -ENOMEM;
883 goto err_out_exit;
886 fi = kmalloc(sizeof(struct pohmelfs_fetch_info) + d->len, GFP_NOIO);
887 if (!fi) {
888 err = -ENOMEM;
889 goto err_out_free;
892 memcpy(fi->name, d->name, d->len);
893 fi->len = d->len;
894 kref_init(&fi->refcnt);
896 pio->pi = pi;
897 pio->id = &d->id;
898 pio->cmd = DNET_CMD_READ;
899 pio->cflags = DNET_FLAGS_NEED_ACK | DNET_FLAGS_NOLOCK;
900 if (psb->no_read_csum)
901 pio->ioflags = DNET_IO_FLAGS_NOCSUM;
902 pio->type = POHMELFS_INODE_COLUMN;
903 pio->cb.complete = pohmelfs_fetch_inode_info_complete;
904 pio->cb.init = pohmelfs_fetch_inode_info_init;
905 pio->cb.destroy = pohmelfs_fetch_inode_info_destroy;
906 pio->priv = fi;
908 err = -ENOENT;
909 for (i = 0; i < group_num; ++i) {
910 pio->group_id = groups[i];
911 err = pohmelfs_send_io_group(pio, groups[i]);
912 if (!err)
913 break;
916 kref_put(&fi->refcnt, pohmelfs_fetch_inode_info_free);
917 err_out_free:
918 kmem_cache_free(pohmelfs_io_cache, pio);
919 err_out_exit:
920 return err;
923 static int pohmelfs_fetch_inode_info(struct pohmelfs_inode *pi, struct pohmelfs_dentry_disk *d)
925 struct pohmelfs_sb *psb = pohmelfs_sb(pi->vfs_inode.i_sb);
926 if (pi->groups)
927 return pohmelfs_fetch_inode_info_group(pi, d, pi->groups, pi->group_num);
928 else
929 return pohmelfs_fetch_inode_info_group(pi, d, psb->groups, psb->group_num);
932 static int pohmelfs_readdir_process(void *data, int size, struct file *filp, void *dirent, filldir_t filldir)
934 struct dentry *dentry = filp->f_path.dentry;
935 struct inode *dir = dentry->d_inode;
936 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
937 struct pohmelfs_inode *pi;
938 int err = 0;
940 while (size > 0) {
941 struct pohmelfs_dentry_disk *d = data;
943 if (size < sizeof(struct pohmelfs_dentry_disk)) {
944 err = -EINVAL;
945 break;
948 if (size < d->len) {
949 err = -EINVAL;
950 break;
953 err = filldir(dirent, d->name, d->len, filp->f_pos, le64_to_cpu(d->ino), d->type);
954 if (err)
955 break;
956 filp->f_pos += 1;
958 pi = pohmelfs_sb_inode_lookup(psb, &d->id);
959 if (!pi) {
960 pohmelfs_fetch_inode_info(pohmelfs_inode(dir), d);
961 } else {
962 iput(&pi->vfs_inode);
965 size -= sizeof(struct pohmelfs_dentry_disk) + d->len;
966 data += sizeof(struct pohmelfs_dentry_disk) + d->len;
969 return err;
972 struct pohmelfs_readdir {
973 struct dnet_raw_id id;
974 int max_size;
975 int fpos;
978 static void *pohmelfs_readdir_group(int group_id, struct file *filp, int *sizep)
980 struct dentry *dentry = filp->f_path.dentry;
981 struct inode *dir = dentry->d_inode;
982 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
983 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
984 struct pohmelfs_readdir rd;
985 struct pohmelfs_script_req req;
986 void *data;
987 int size;
988 int err;
990 memset(&req, 0, sizeof(struct pohmelfs_script_req));
992 req.script_name = POHMELFS_READDIR_SCRIPT;
993 req.script_namelen = sizeof(POHMELFS_READDIR_SCRIPT) - 1; /* not including 0-byte */
995 req.obj_name = (char *)dentry->d_name.name;
996 req.obj_len = dentry->d_name.len;
998 rd.id = parent->id;
999 rd.max_size = psb->readdir_allocation * PAGE_SIZE - sizeof(struct dnet_attr); /* cmd->size should fit one page */
1000 rd.fpos = filp->f_pos - 2; /* account for . and .. */
1002 req.binary = &rd;
1003 req.binary_size = sizeof(struct pohmelfs_readdir);
1005 req.id = &parent->id;
1006 req.complete = pohmelfs_readdir_complete;
1007 req.cflags = 0;
1009 req.group_id = group_id;
1010 req.sync = 1;
1012 err = pohmelfs_send_script_request(parent, &req);
1013 if (err < 0)
1014 goto err_out_exit;
1016 data = req.ret;
1017 size = req.ret_cond;
1018 if (!data || !size) {
1019 err = -ENOENT;
1020 goto err_out_exit;
1023 *sizep = size;
1024 return data;
1026 err_out_exit:
1027 return ERR_PTR(err);
1030 static int pohmelfs_dir_open(struct inode *dir, struct file *filp)
1032 #if 0
1033 struct pohmelfs_inode *pi = pohmelfs_inode(dir);
1035 if (!pohmelfs_need_resync(pi))
1036 return dcache_dir_open(dir, filp);
1037 #endif
1038 filp->f_pos = 0;
1039 return 0;
1042 static int pohmelfs_dir_close(struct inode *inode, struct file *filp)
1044 if (filp->private_data)
1045 return dcache_dir_close(inode, filp);
1046 return 0;
1049 static int pohmelfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
1051 struct dentry *dentry = filp->f_path.dentry;
1052 struct inode *dir = dentry->d_inode;
1053 struct pohmelfs_inode *pi = pohmelfs_inode(dir);
1054 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
1055 int i, err = -ENOENT;
1057 if (filp->private_data) {
1058 return dcache_readdir(filp, dirent, filldir);
1061 if (filp->f_pos == 0) {
1062 err = filldir(dirent, ".", 1, filp->f_pos, dir->i_ino, DT_DIR);
1063 if (err)
1064 return err;
1065 filp->f_pos++;
1068 if (filp->f_pos == 1) {
1069 err = filldir(dirent, "..", 2, filp->f_pos, parent_ino(dentry), DT_DIR);
1070 if (err)
1071 return err;
1072 filp->f_pos++;
1075 for (i = 0; i < psb->group_num; ++i) {
1076 int size;
1077 void *data;
1079 data = pohmelfs_readdir_group(psb->groups[i], filp, &size);
1080 if (IS_ERR(data)) {
1081 err = PTR_ERR(data);
1082 continue;
1085 pi->update = get_seconds();
1086 err = pohmelfs_readdir_process(data + sizeof(struct dnet_attr), size - sizeof(struct dnet_attr), filp, dirent, filldir);
1087 kfree(data);
1089 break;
1092 return err;
1095 const struct file_operations pohmelfs_dir_fops = {
1096 .open = pohmelfs_dir_open,
1097 .release = pohmelfs_dir_close,
1098 .read = generic_read_dir,
1099 .readdir = pohmelfs_readdir,