filldir call cleanup. Do not use dcache in dir-open
[pohmelfs.git] / fs / pohmelfs / dir.c
blob1a63654d128868ce9c2767cd3e2eac8e72d72fbf
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;
203 int len = 6;
204 char parent_id_str[len*2+1];
206 pr_debug("pohmelfs: SENT: %.*s: %s: inode->id: %s, ino: %lu, object: %s, binary size: %d, ret: %p, condition: %d\n",
207 req->script_namelen, req->script_name,
208 pohmelfs_dump_id(req->id->id),
209 pohmelfs_dump_id_len_raw(parent->id.id, len, parent_id_str),
210 parent->vfs_inode.i_ino, req->obj_name, req->binary_size,
211 req->ret, req->ret_cond);
214 if (req->sync) {
215 ret = wait_event_interruptible_timeout(wait->wq, wait->condition != 0, msecs_to_jiffies(psb->read_wait_timeout));
216 if (ret <= 0) {
217 err = ret;
218 if (ret == 0)
219 err = -ETIMEDOUT;
220 goto err_out_free;
223 if (wait->condition < 0)
224 err = wait->condition;
226 req->ret = wait->ret;
227 req->ret_cond = wait->condition;
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:
238 int len = 6;
239 char parent_id_str[len*2+1];
241 pr_debug("pohmelfs: DONE: %.*s: %s: inode->id: %s, ino: %lu, object: %s, binary size: %d, ret: %p, condition: %d, err: %d\n",
242 req->script_namelen, req->script_name,
243 pohmelfs_dump_id(req->id->id),
244 pohmelfs_dump_id_len_raw(parent->id.id, len, parent_id_str),
245 parent->vfs_inode.i_ino, req->obj_name, req->binary_size,
246 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 inode *inode = &pi->vfs_inode;
254 struct pohmelfs_script_req req;
255 struct pohmelfs_dentry *pd;
256 int err;
258 if (!len) {
259 err = -EINVAL;
260 goto err_out_exit;
263 pd = kmem_cache_alloc(pohmelfs_dentry_cache, GFP_NOIO);
264 if (!pd) {
265 err = -ENOMEM;
266 goto err_out_exit;
269 pd->parent_id = *id;
270 pd->disk.id = pi->id;
271 pd->disk.ino = cpu_to_le64(pi->vfs_inode.i_ino);
272 pd->disk.type = (pi->vfs_inode.i_mode >> 12) & 15;
273 pd->disk.len = len;
275 memset(&req, 0, sizeof(struct pohmelfs_script_req));
277 req.id = id;
279 req.script_name = POHMELFS_INODE_INFO_SCRIPT_INSERT;
280 req.script_namelen = sizeof(POHMELFS_INODE_INFO_SCRIPT_INSERT) - 1; /* not including 0-byte */
282 req.obj_name = (char *)sname;
283 req.obj_len = len;
285 req.binary = pd;
286 req.binary_size = sizeof(struct pohmelfs_dentry);
288 req.group_id = 0;
289 req.id = id;
291 req.sync = sync;
292 req.complete = pohmelfs_send_dentry_complete;
294 err = pohmelfs_send_script_request(pi, &req);
295 if (err)
296 goto err_out_free;
298 err = inode->i_sb->s_op->write_inode(inode, NULL);
300 err_out_free:
301 kmem_cache_free(pohmelfs_dentry_cache, pd);
302 err_out_exit:
303 return err;
306 static int pohmelfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
307 struct nameidata *nd)
309 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
310 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
311 struct pohmelfs_inode *pi;
312 int err;
314 inode_inc_link_count(dir);
316 pi = pohmelfs_new_inode(psb, mode);
317 if (IS_ERR(pi)) {
318 err = PTR_ERR(pi);
319 goto err_out_exit;
322 pi->local = 1;
325 * calling d_instantiate() implies that
326 * ->lookup() used d_splice_alias() with NULL inode
327 * when it failed to find requested object
329 d_instantiate(dentry, &pi->vfs_inode);
330 if (psb->http_compat)
331 pohmelfs_http_compat_id(pi);
332 pohmelfs_inode_dirty(parent, pi);
334 err = pohmelfs_send_dentry(pi, &pi->parent_id, dentry->d_name.name, dentry->d_name.len, 1);
335 if (err)
336 goto err_out_exit;
338 pr_debug("pohmelfs: create: %s, ino: %lu, parent dir: %lu, object: %s\n",
339 pohmelfs_dump_id(pi->id.id), pi->vfs_inode.i_ino,
340 dir->i_ino, dentry->d_name.name);
342 return 0;
344 err_out_exit:
345 inode_dec_link_count(dir);
346 return err;
349 static struct pohmelfs_inode *pohmelfs_lookup_group(struct inode *dir, struct dentry *dentry, int group_id)
351 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
352 struct pohmelfs_script_req req;
353 struct pohmelfs_inode *pi;
354 int err;
356 memset(&req, 0, sizeof(struct pohmelfs_script_req));
358 req.script_name = POHMELFS_LOOKUP_SCRIPT;
359 req.script_namelen = sizeof(POHMELFS_LOOKUP_SCRIPT) - 1; /* not including 0-byte */
361 req.obj_name = (char *)dentry->d_name.name;
362 req.obj_len = dentry->d_name.len;
364 req.binary = &parent->id;
365 req.binary_size = sizeof(struct dnet_raw_id);
367 req.id = &parent->id;
368 req.complete = pohmelfs_lookup_complete;
370 req.group_id = group_id;
371 req.sync = 1;
372 req.cflags = 0;
374 err = pohmelfs_send_script_request(parent, &req);
375 if (err)
376 goto err_out_exit;
378 pi = req.ret;
379 if (!pi) {
380 err = -ENOENT;
381 goto err_out_exit;
384 return pi;
386 err_out_exit:
387 pr_debug("pohmelfs: pohmelfs_lookup_group: %s: group: %d: parent ino: %lu, name: %s: %d\n",
388 pohmelfs_dump_id(parent->id.id), group_id, parent->vfs_inode.i_ino, dentry->d_name.name, err);
389 return ERR_PTR(err);
392 static struct dentry *pohmelfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
394 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
395 struct inode *inode = NULL;
396 struct pohmelfs_inode *pi;
397 int i, err = -ENOENT;
399 for (i = 0; i < psb->group_num; ++i) {
400 pi = pohmelfs_lookup_group(dir, dentry, psb->groups[i]);
401 if (IS_ERR(pi)) {
402 err = PTR_ERR(pi);
403 continue;
406 inode = &pi->vfs_inode;
407 err = 0;
408 break;
411 return d_splice_alias(inode, dentry);
414 static int pohmelfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
416 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
417 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
418 struct pohmelfs_inode *pi;
419 int err;
421 inode_inc_link_count(dir);
423 pi = pohmelfs_new_inode(psb, mode | S_IFDIR);
424 if (IS_ERR(pi)) {
425 err = PTR_ERR(pi);
426 goto err_out_dir;
429 pi->local = 1;
430 d_instantiate(dentry, &pi->vfs_inode);
431 if (psb->http_compat)
432 pohmelfs_http_compat_id(pi);
433 pohmelfs_inode_dirty(parent, pi);
435 err = pohmelfs_send_dentry(pi, &pi->parent_id, dentry->d_name.name, dentry->d_name.len, 1);
436 if (err)
437 goto err_out_dir;
439 pr_debug("pohmelfs: mkdir: %s, ino: %lu, parent dir: %lu, object: %s, refcnt: %d\n",
440 pohmelfs_dump_id(pi->id.id), pi->vfs_inode.i_ino,
441 dir->i_ino, dentry->d_name.name, dentry->d_count);
442 return 0;
444 err_out_dir:
445 inode_dec_link_count(dir);
446 return err;
449 static int pohmelfs_unlink(struct inode *dir, struct dentry *dentry)
451 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
452 struct pohmelfs_inode *pi = pohmelfs_inode(dentry->d_inode);
453 struct pohmelfs_script_req req;
454 int err;
456 memset(&req, 0, sizeof(struct pohmelfs_script_req));
458 req.script_name = POHMELFS_UNLINK_SCRIPT;
459 req.script_namelen = sizeof(POHMELFS_UNLINK_SCRIPT) - 1; /* not including 0-byte */
461 req.obj_name = (char *)dentry->d_name.name;
462 req.obj_len = dentry->d_name.len;
464 req.binary = &parent->id;
465 req.binary_size = sizeof(struct dnet_raw_id);
467 req.group_id = 0;
468 req.id = &parent->id;
469 req.complete = pohmelfs_send_dentry_complete;
471 req.sync = 1;
473 err = pohmelfs_send_script_request(parent, &req);
474 if (err)
475 return err;
477 req.script_name = POHMELFS_DATA_UNLINK_SCRIPT;
478 req.script_namelen = sizeof(POHMELFS_DATA_UNLINK_SCRIPT) - 1; /* not including 0-byte */
480 req.binary = &pi->id;
481 req.binary_size = sizeof(struct dnet_raw_id);
483 return pohmelfs_send_script_request(parent, &req);
486 static int pohmelfs_rmdir(struct inode *dir, struct dentry *dentry)
488 return pohmelfs_unlink(dir, dentry);
491 struct pohmelfs_rename_req {
492 struct dnet_raw_id old_dir_id;
494 struct pohmelfs_dentry dentry;
495 } __attribute__ ((packed));
497 static int pohmelfs_rename(struct inode *old_dir, struct dentry *old_dentry,
498 struct inode *new_dir, struct dentry *new_dentry)
500 struct pohmelfs_inode *old_parent = pohmelfs_inode(old_dir);
501 struct inode *inode = old_dentry->d_inode;
502 struct pohmelfs_script_req req;
503 struct pohmelfs_rename_req *r;
504 int size = sizeof(struct pohmelfs_rename_req) + new_dentry->d_name.len;
505 int err;
507 if (pohmelfs_sb(inode->i_sb)->http_compat) {
508 err = -ENOTSUPP;
509 goto err_out_exit;
512 r = kzalloc(size, GFP_NOIO);
513 if (!r) {
514 err = -ENOMEM;
515 goto err_out_exit;
518 r->old_dir_id = pohmelfs_inode(old_dir)->id;
519 r->dentry.parent_id = pohmelfs_inode(new_dir)->id;
520 r->dentry.disk.id = pohmelfs_inode(inode)->id;
521 r->dentry.disk.ino = cpu_to_le64(inode->i_ino);
522 r->dentry.disk.type = (inode->i_mode >> 12) & 15;
523 r->dentry.disk.len = new_dentry->d_name.len;
525 memcpy(r->dentry.disk.name, new_dentry->d_name.name, new_dentry->d_name.len);
527 memset(&req, 0, sizeof(struct pohmelfs_script_req));
529 req.script_name = POHMELFS_RENAME_SCRIPT;
530 req.script_namelen = sizeof(POHMELFS_RENAME_SCRIPT) - 1; /* not including 0-byte */
532 req.obj_name = (char *)old_dentry->d_name.name;
533 req.obj_len = old_dentry->d_name.len;
535 req.binary = r;
536 req.binary_size = size;
538 req.sync = 1;
539 req.group_id = 0;
540 req.id = &old_parent->id;
541 req.complete = pohmelfs_send_dentry_complete;
543 err = pohmelfs_send_script_request(old_parent, &req);
544 if (err)
545 goto err_out_free;
547 err_out_free:
548 kfree(r);
549 err_out_exit:
550 return err;
553 static int pohmelfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
555 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
556 struct pohmelfs_inode *pi;
557 struct inode *inode;
558 unsigned len = strlen(symname)+1;
559 int err = 0;
561 inode_inc_link_count(dir);
562 pi = pohmelfs_new_inode(psb, S_IFLNK | S_IRWXUGO);
563 if (IS_ERR(pi)) {
564 err = PTR_ERR(pi);
565 goto err_out_exit;
568 pi->local = 1;
569 inode = &pi->vfs_inode;
571 err = page_symlink(inode, symname, len);
572 if (err)
573 goto err_out_put;
575 d_instantiate(dentry, inode);
576 if (psb->http_compat)
577 pohmelfs_http_compat_id(pi);
578 pohmelfs_inode_dirty(pohmelfs_inode(dir), pi);
579 err = pohmelfs_send_dentry(pi, &pi->parent_id, dentry->d_name.name, dentry->d_name.len, 1);
580 if (err)
581 goto err_out_exit;
583 return 0;
585 err_out_put:
586 iput(inode);
587 err_out_exit:
588 inode_dec_link_count(dir);
589 return err;
592 static int pohmelfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
594 struct inode *inode = old_dentry->d_inode;
595 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
596 struct pohmelfs_inode *pi = pohmelfs_inode(inode);
597 struct pohmelfs_script_req req;
598 int err;
600 dquot_initialize(dir);
602 inode->i_ctime = CURRENT_TIME_SEC;
603 inode_inc_link_count(inode);
604 ihold(inode);
606 pohmelfs_inode_dirty(parent, pi);
608 err = pohmelfs_send_dentry(pi, &pi->parent_id, dentry->d_name.name, dentry->d_name.len, 1);
609 if (err) {
610 goto err_out_put;
613 memset(&req, 0, sizeof(struct pohmelfs_script_req));
615 req.script_name = POHMELFS_HARDLINK_SCRIPT;
616 req.script_namelen = sizeof(POHMELFS_HARDLINK_SCRIPT) - 1; /* not including 0-byte */
618 req.obj_name = (char *)dentry->d_name.name;
619 req.obj_len = dentry->d_name.len;
621 req.binary = &pi->id;
622 req.binary_size = sizeof(struct dnet_raw_id);
624 req.group_id = 0;
625 req.id = &pi->id;
626 req.complete = pohmelfs_send_dentry_complete;
628 req.sync = 1;
630 err = pohmelfs_send_script_request(parent, &req);
631 if (err)
632 goto err_out_unlink;
634 d_instantiate(dentry, inode);
635 return 0;
637 err_out_unlink:
638 req.binary = &parent->id;
639 req.script_name = POHMELFS_UNLINK_SCRIPT;
640 req.script_namelen = sizeof(POHMELFS_UNLINK_SCRIPT) - 1; /* not including 0-byte */
641 pohmelfs_send_script_request(parent, &req);
643 err_out_put:
644 inode_dec_link_count(inode);
645 iput(inode);
646 return err;
649 static int pohmelfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev)
651 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
652 struct pohmelfs_inode *pi;
653 struct inode *inode;
654 int err;
656 if (!new_valid_dev(rdev))
657 return -EINVAL;
659 inode_inc_link_count(dir);
660 dquot_initialize(dir);
662 pi = pohmelfs_new_inode(psb, mode);
663 if (IS_ERR(pi)) {
664 err = PTR_ERR(pi);
665 goto err_out_exit;
667 pi->local = 1;
669 inode = &pi->vfs_inode;
671 init_special_inode(inode, inode->i_mode, rdev);
672 inode->i_op = &pohmelfs_special_inode_operations;
674 d_instantiate(dentry, inode);
675 if (psb->http_compat)
676 pohmelfs_http_compat_id(pi);
677 pohmelfs_inode_dirty(pohmelfs_inode(dir), pi);
679 err = pohmelfs_send_dentry(pi, &pi->parent_id, dentry->d_name.name, dentry->d_name.len, 1);
680 if (err)
681 goto err_out_exit;
683 return 0;
685 err_out_exit:
686 inode_dec_link_count(dir);
687 return err;
690 const struct inode_operations pohmelfs_dir_inode_operations = {
691 .create = pohmelfs_create,
692 .lookup = pohmelfs_lookup,
693 .mkdir = pohmelfs_mkdir,
694 .unlink = pohmelfs_unlink,
695 .rmdir = pohmelfs_rmdir,
696 .rename = pohmelfs_rename,
697 .symlink = pohmelfs_symlink,
698 .link = pohmelfs_link,
699 .mknod = pohmelfs_mknod,
702 static int pohmelfs_readdir_complete(struct pohmelfs_trans *t, struct pohmelfs_state *recv)
704 struct pohmelfs_inode *pi = pohmelfs_inode(t->inode);
705 struct pohmelfs_wait *wait = t->priv;
706 struct dnet_cmd *cmd = &recv->cmd;
708 pr_debug("pohmelfs: %s: readdir comlete: cmd size: %llu, flags: %x\n",
709 pohmelfs_dump_id(pi->id.id), (unsigned long long)cmd->size, cmd->flags);
711 if (cmd->flags & DNET_FLAGS_MORE) {
712 if (cmd->size > sizeof(struct dnet_attr)) {
713 wait->ret = t->recv_data;
714 wait->condition = cmd->size;
716 t->recv_data = NULL;
717 wake_up(&wait->wq);
719 } else {
720 if (!wait->condition) {
721 wait->condition = cmd->status;
722 if (!wait->condition)
723 wait->condition = 1;
727 return 0;
730 static int pohmelfs_dentry_add(struct pohmelfs_inode *parent, struct pohmelfs_inode *pi, char *name, int len)
732 struct inode *inode = &pi->vfs_inode;
733 struct inode *dir = &parent->vfs_inode;
734 struct dentry *dentry, *parent_dentry, *old;
735 struct qstr str;
736 int err;
738 str.name = name;
739 str.len = len;
740 str.hash = full_name_hash(str.name, str.len);
742 /* we do not need to hold dir->i_mutex here, don't we? :) */
743 parent_dentry = d_find_alias(dir);
744 if (!parent_dentry) {
745 err = -ENOENT;
746 goto err_out_exit;
749 dentry = d_lookup(parent_dentry, &str);
750 if (dentry) {
751 err = -EEXIST;
753 dput(dentry);
754 goto err_out_put_parent;
757 * if things are ok, dentry has 2 references -
758 * one in parent dir, and another its own,
759 * which we should drop
761 dentry = d_alloc(parent_dentry, &str);
762 if (!dentry) {
763 err = -ENOMEM;
764 goto err_out_put_parent;
767 old = d_splice_alias(inode, dentry);
768 if (unlikely(old)) {
769 dput(dentry);
770 dentry = old;
771 } else {
772 dput(dentry);
775 dput(parent_dentry);
776 return 0;
778 err_out_put_parent:
779 dput(parent_dentry);
780 err_out_exit:
781 return err;
784 static int pohmelfs_update_inode(struct pohmelfs_inode *parent, struct pohmelfs_inode_info *info, char *name)
786 struct pohmelfs_sb *psb = pohmelfs_sb(parent->vfs_inode.i_sb);
787 struct pohmelfs_inode *pi;
788 struct inode *inode;
789 int err = 0;
791 pi = pohmelfs_sb_inode_lookup(psb, &info->id);
792 if (pi) {
793 inode = &pi->vfs_inode;
794 pohmelfs_fill_inode(inode, info);
796 } else {
797 pi = pohmelfs_existing_inode(psb, info);
798 if (IS_ERR(pi)) {
799 err = PTR_ERR(pi);
800 goto err_out_exit;
802 inode = &pi->vfs_inode;
804 pi->parent_id = parent->id;
807 err = pohmelfs_dentry_add(parent, pi, name, info->namelen);
808 if (err)
809 iput(inode);
811 err_out_exit:
812 return err;
815 struct pohmelfs_fetch_info {
816 struct kref refcnt;
817 int len;
818 char name[0];
821 static void pohmelfs_fetch_inode_info_free(struct kref *kref)
823 struct pohmelfs_fetch_info *fi = container_of(kref, struct pohmelfs_fetch_info, refcnt);
825 kfree(fi);
828 static void pohmelfs_fetch_inode_info_destroy(struct pohmelfs_trans *t)
830 struct pohmelfs_fetch_info *fi = t->priv;
832 kref_put(&fi->refcnt, pohmelfs_fetch_inode_info_free);
835 static int pohmelfs_fetch_inode_info_init(struct pohmelfs_trans *t)
837 struct pohmelfs_fetch_info *fi = t->priv;
839 kref_get(&fi->refcnt);
840 return 0;
843 static int pohmelfs_fetch_inode_info_complete(struct pohmelfs_trans *t, struct pohmelfs_state *recv)
845 struct pohmelfs_fetch_info *fi = t->priv;
846 struct dnet_cmd *cmd = &recv->cmd;
847 struct pohmelfs_inode_info *info;
849 if (cmd->status)
850 return 0;
852 if (!(cmd->flags & DNET_FLAGS_MORE))
853 return 0;
855 if (cmd->size <= sizeof(struct dnet_attr) + sizeof(struct dnet_io_attr) + sizeof(struct dnet_io_attr))
856 return 0;
858 info = t->recv_data + sizeof(struct dnet_attr) + sizeof(struct dnet_io_attr);
859 pohmelfs_convert_inode_info(info);
861 info->namelen = fi->len;
862 pohmelfs_update_inode(pohmelfs_inode(t->inode), info, fi->name);
864 return 0;
867 static int pohmelfs_fetch_inode_info_group(struct pohmelfs_inode *pi, struct pohmelfs_dentry_disk *d, int *groups, int group_num)
869 struct pohmelfs_sb *psb = pohmelfs_sb(pi->vfs_inode.i_sb);
870 struct pohmelfs_io *pio;
871 struct pohmelfs_fetch_info *fi;
872 int err, i;
874 pio = kmem_cache_zalloc(pohmelfs_io_cache, GFP_NOIO);
875 if (!pio) {
876 err = -ENOMEM;
877 goto err_out_exit;
880 fi = kmalloc(sizeof(struct pohmelfs_fetch_info) + d->len, GFP_NOIO);
881 if (!fi) {
882 err = -ENOMEM;
883 goto err_out_free;
886 memcpy(fi->name, d->name, d->len);
887 fi->len = d->len;
888 kref_init(&fi->refcnt);
890 pio->pi = pi;
891 pio->id = &d->id;
892 pio->cmd = DNET_CMD_READ;
893 pio->cflags = DNET_FLAGS_NEED_ACK | DNET_FLAGS_NOLOCK;
894 if (psb->no_read_csum)
895 pio->ioflags = DNET_IO_FLAGS_NOCSUM;
896 pio->type = POHMELFS_INODE_COLUMN;
897 pio->cb.complete = pohmelfs_fetch_inode_info_complete;
898 pio->cb.init = pohmelfs_fetch_inode_info_init;
899 pio->cb.destroy = pohmelfs_fetch_inode_info_destroy;
900 pio->priv = fi;
902 err = -ENOENT;
903 for (i = 0; i < group_num; ++i) {
904 pio->group_id = groups[i];
905 err = pohmelfs_send_io_group(pio, groups[i]);
906 if (!err)
907 break;
910 kref_put(&fi->refcnt, pohmelfs_fetch_inode_info_free);
911 err_out_free:
912 kmem_cache_free(pohmelfs_io_cache, pio);
913 err_out_exit:
914 return err;
917 static int pohmelfs_fetch_inode_info(struct pohmelfs_inode *pi, struct pohmelfs_dentry_disk *d)
919 struct pohmelfs_sb *psb = pohmelfs_sb(pi->vfs_inode.i_sb);
920 if (pi->groups)
921 return pohmelfs_fetch_inode_info_group(pi, d, pi->groups, pi->group_num);
922 else
923 return pohmelfs_fetch_inode_info_group(pi, d, psb->groups, psb->group_num);
926 static int pohmelfs_readdir_process(void *data, int size, struct file *filp, void *dirent, filldir_t filldir)
928 struct dentry *dentry = filp->f_path.dentry;
929 struct inode *dir = dentry->d_inode;
930 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
931 struct pohmelfs_inode *pi;
932 int err = 0;
934 while (size > 0) {
935 struct pohmelfs_dentry_disk *d = data;
937 if (size < sizeof(struct pohmelfs_dentry_disk)) {
938 err = -EINVAL;
939 break;
942 if (size < d->len) {
943 err = -EINVAL;
944 break;
947 err = filldir(dirent, d->name, d->len, filp->f_pos, le64_to_cpu(d->ino), d->type);
948 if (err)
949 break;
950 filp->f_pos += 1;
952 pi = pohmelfs_sb_inode_lookup(psb, &d->id);
953 if (!pi) {
954 pohmelfs_fetch_inode_info(pohmelfs_inode(dir), d);
955 } else {
956 iput(&pi->vfs_inode);
959 size -= sizeof(struct pohmelfs_dentry_disk) + d->len;
960 data += sizeof(struct pohmelfs_dentry_disk) + d->len;
963 return err;
966 struct pohmelfs_readdir {
967 struct dnet_raw_id id;
968 int max_size;
969 int fpos;
972 static void *pohmelfs_readdir_group(int group_id, struct file *filp, int *sizep)
974 struct dentry *dentry = filp->f_path.dentry;
975 struct inode *dir = dentry->d_inode;
976 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
977 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
978 struct pohmelfs_readdir rd;
979 struct pohmelfs_script_req req;
980 void *data;
981 int size;
982 int err;
984 memset(&req, 0, sizeof(struct pohmelfs_script_req));
986 req.script_name = POHMELFS_READDIR_SCRIPT;
987 req.script_namelen = sizeof(POHMELFS_READDIR_SCRIPT) - 1; /* not including 0-byte */
989 req.obj_name = (char *)dentry->d_name.name;
990 req.obj_len = dentry->d_name.len;
992 rd.id = parent->id;
993 rd.max_size = psb->readdir_allocation * PAGE_SIZE - sizeof(struct dnet_attr); /* cmd->size should fit one page */
994 rd.fpos = filp->f_pos - 2; /* account for . and .. */
996 req.binary = &rd;
997 req.binary_size = sizeof(struct pohmelfs_readdir);
999 req.id = &parent->id;
1000 req.complete = pohmelfs_readdir_complete;
1001 req.cflags = 0;
1003 req.group_id = group_id;
1004 req.sync = 1;
1006 err = pohmelfs_send_script_request(parent, &req);
1007 if (err < 0)
1008 goto err_out_exit;
1010 data = req.ret;
1011 size = req.ret_cond;
1012 if (!data || !size) {
1013 err = -ENOENT;
1014 goto err_out_exit;
1017 *sizep = size;
1018 return data;
1020 err_out_exit:
1021 return ERR_PTR(err);
1024 static int pohmelfs_dir_open(struct inode *dir, struct file *filp)
1026 struct pohmelfs_inode *pi = pohmelfs_inode(dir);
1028 #if 0
1029 if (!pohmelfs_need_resync(pi))
1030 return dcache_dir_open(dir, filp);
1031 #endif
1032 filp->f_pos = 0;
1033 return 0;
1036 static int pohmelfs_dir_close(struct inode *inode, struct file *filp)
1038 if (filp->private_data)
1039 return dcache_dir_close(inode, filp);
1040 return 0;
1043 static int pohmelfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
1045 struct dentry *dentry = filp->f_path.dentry;
1046 struct inode *dir = dentry->d_inode;
1047 struct pohmelfs_inode *pi = pohmelfs_inode(dir);
1048 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
1049 int i, err = -ENOENT;
1051 if (filp->private_data) {
1052 return dcache_readdir(filp, dirent, filldir);
1055 if (filp->f_pos == 0) {
1056 err = filldir(dirent, ".", 1, filp->f_pos, dir->i_ino, DT_DIR);
1057 if (err)
1058 return err;
1059 filp->f_pos++;
1062 if (filp->f_pos == 1) {
1063 err = filldir(dirent, "..", 2, filp->f_pos, parent_ino(dentry), DT_DIR);
1064 if (err)
1065 return err;
1066 filp->f_pos++;
1069 for (i = 0; i < psb->group_num; ++i) {
1070 int size;
1071 void *data;
1073 data = pohmelfs_readdir_group(psb->groups[i], filp, &size);
1074 if (IS_ERR(data)) {
1075 err = PTR_ERR(data);
1076 continue;
1079 pi->update = get_seconds();
1080 err = pohmelfs_readdir_process(data + sizeof(struct dnet_attr), size - sizeof(struct dnet_attr), filp, dirent, filldir);
1081 kfree(data);
1083 break;
1086 return err;
1089 const struct file_operations pohmelfs_dir_fops = {
1090 .open = pohmelfs_dir_open,
1091 .release = pohmelfs_dir_close,
1092 .read = generic_read_dir,
1093 .readdir = pohmelfs_readdir,