Added scratch readdir reading
[pohmelfs.git] / fs / pohmelfs / dir.c
blobbe27b9f6a1c9816ed6ba3d73a4cef439e8e8e14f
1 /*
2 * Copyright (C) 2011+ Evgeniy Polyakov <zbr@ioremap.net>
3 */
5 #include <linux/fs.h>
6 #include <linux/dcache.h>
8 #include "pohmelfs.h"
10 #define POHMELFS_LOOKUP_SCRIPT "pohmelfs_lookup.py"
11 #define POHMELFS_UNLINK_SCRIPT "pohmelfs_unlink.py"
12 #define POHMELFS_RENAME_SCRIPT "pohmelfs_rename.py"
13 #define POHMELFS_INODE_INFO_SCRIPT_INSERT "pohmelfs_inode_info_insert.py"
14 #define POHMELFS_DENTRY_NAME_SCRIPT "pohmelfs_dentry_name="
16 static void pohmelfs_inode_dirty(struct pohmelfs_inode *parent, struct pohmelfs_inode *pi)
18 struct inode *inode = &pi->vfs_inode;
19 struct inode *dir = &parent->vfs_inode;
21 pi->parent_id = parent->id;
22 inode_init_owner(inode, dir, inode->i_mode);
24 inode->i_mtime = inode->i_ctime = CURRENT_TIME;
25 dir->i_mtime = CURRENT_TIME;
27 mark_inode_dirty(inode);
28 mark_inode_dirty(dir);
31 static int pohmelfs_send_inode_info_complete(struct pohmelfs_trans *t, struct pohmelfs_state *recv)
33 struct pohmelfs_inode *pi = pohmelfs_inode(t->inode);
34 struct pohmelfs_wait *wait = t->priv;
35 struct dnet_cmd *cmd = &recv->cmd;
36 unsigned long long trans = cmd->trans & ~DNET_TRANS_REPLY;
38 if (cmd->flags & DNET_FLAGS_MORE) {
39 if (cmd->status == 0 && cmd->size != sizeof(struct dnet_attr) + 2)
40 cmd->status = -EINVAL;
42 pr_debug("pohmelfs: %s: pohmelfs_send_inode_info_complete: %llu, cmd_size: %llu, flags: %x, status: %d\n",
43 pohmelfs_dump_id(pi->id.id), trans, cmd->size, cmd->flags, cmd->status);
45 if (!cmd->status)
46 wait->condition = 1;
47 else
48 wait->condition = cmd->status;
51 return 0;
54 static int pohmelfs_send_inode_info_init(struct pohmelfs_trans *t)
56 struct pohmelfs_wait *wait = t->priv;
58 pohmelfs_wait_get(wait);
59 return 0;
62 static void pohmelfs_send_inode_info_destroy(struct pohmelfs_trans *t)
64 struct pohmelfs_wait *wait = t->priv;
66 wake_up(&wait->wq);
67 pohmelfs_wait_put(wait);
70 static int pohmelfs_lookup_complete(struct pohmelfs_trans *t, struct pohmelfs_state *recv)
72 struct pohmelfs_inode *parent = pohmelfs_inode(t->inode);
73 struct pohmelfs_wait *wait = t->priv;
74 struct dnet_cmd *cmd = &recv->cmd;
75 unsigned long long trans = cmd->trans & ~DNET_TRANS_REPLY;
76 int err = cmd->status;
78 if (err)
79 goto err_out_exit;
81 if (cmd->flags & DNET_FLAGS_MORE) {
82 struct pohmelfs_inode_info *info;
83 struct pohmelfs_inode *pi;
85 if (cmd->size != sizeof(struct dnet_attr) + sizeof(struct pohmelfs_inode_info)) {
86 err = -ENOENT;
87 goto err_out_exit;
90 pr_debug("pohmelfs: %s: pohmelfs_lookup_complete: %llu, size: %llu, min size: %zu, flags: %x, status: %d\n",
91 pohmelfs_dump_id(parent->id.id), trans, cmd->size,
92 sizeof(struct dnet_attr) + sizeof(struct pohmelfs_inode_info), cmd->flags, cmd->status);
95 info = t->recv_data + sizeof(struct dnet_attr);
96 pohmelfs_convert_inode_info(info);
98 pi = pohmelfs_existing_inode(pohmelfs_sb(t->inode->i_sb), info);
99 if (IS_ERR(pi)) {
100 err = PTR_ERR(pi);
101 goto err_out_exit;
104 pi->parent_id = parent->id;
105 pi->received = 1;
106 wait->ret = pi;
109 err_out_exit:
110 if (err)
111 wait->condition = err;
112 else
113 wait->condition = 1;
115 return 0;
118 int pohmelfs_send_script_request(struct pohmelfs_inode *parent, struct pohmelfs_script_req *req)
120 struct pohmelfs_sb *psb = pohmelfs_sb(parent->vfs_inode.i_sb);
121 struct pohmelfs_wait *wait;
122 struct pohmelfs_io *pio;
123 struct dnet_exec *e;
124 int script_len;
125 long ret;
126 int err;
128 /* 2 commas, \n and 0-byte, which is accounted in sizeof(string) */
129 script_len = sizeof(POHMELFS_DENTRY_NAME_SCRIPT) + req->obj_len + 3;
131 wait = pohmelfs_wait_alloc(parent);
132 if (!wait) {
133 err = -ENOMEM;
134 goto err_out_exit;
137 pio = kmem_cache_zalloc(pohmelfs_io_cache, GFP_NOIO);
138 if (!pio) {
139 err = -ENOMEM;
140 goto err_out_wait_put;
143 e = kmalloc(sizeof(struct dnet_exec) + req->script_namelen + script_len + req->binary_size, GFP_NOIO);
144 if (!e) {
145 err = -ENOMEM;
146 goto err_out_free_pio;
149 memset(e, 0, sizeof(struct dnet_exec));
151 snprintf(e->data, req->script_namelen + script_len, "%s%s'%s'\n", req->script_name, POHMELFS_DENTRY_NAME_SCRIPT, req->obj_name);
152 script_len--; /* do not include last 0-byte in the script */
154 memcpy(e->data + req->script_namelen + script_len, req->binary, req->binary_size);
156 e->type = DNET_EXEC_PYTHON_SCRIPT_NAME;
157 e->name_size = req->script_namelen;
158 e->script_size = script_len;
159 e->binary_size = req->binary_size;
160 dnet_convert_exec(e);
162 pio->pi = parent;
163 pio->id = req->id;
164 pio->group_id = req->group_id;
165 pio->cflags = DNET_FLAGS_NEED_ACK;
166 if (req->complete == pohmelfs_lookup_complete)
167 pio->cflags |= DNET_FLAGS_NOLOCK;
169 pio->cmd = DNET_CMD_EXEC;
170 pio->size = sizeof(struct dnet_exec) + req->script_namelen + script_len + req->binary_size;
171 pio->data = e;
172 pio->priv = wait;
173 pio->cb.init = pohmelfs_send_inode_info_init;
174 pio->cb.destroy = pohmelfs_send_inode_info_destroy;
175 pio->cb.complete = req->complete;
177 if (pio->group_id) {
178 err = pohmelfs_send_buf_single(pio, NULL);
179 } else {
180 err = pohmelfs_send_buf(pio);
182 if (err)
183 goto err_out_free;
185 if (req->sync) {
186 ret = wait_event_interruptible_timeout(wait->wq, wait->condition != 0, msecs_to_jiffies(psb->read_wait_timeout));
187 if (ret <= 0) {
188 err = ret;
189 if (ret == 0)
190 err = -ETIMEDOUT;
191 goto err_out_free;
194 if (wait->condition < 0)
195 err = wait->condition;
197 req->ret = wait->ret;
201 int len = 6;
202 char parent_id_str[len*2+1];
204 pr_debug("pohmelfs: %.*s: %s: inode->id: %s, ino: %lu, object: %s, binary size: %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, parent_id_str),
208 parent->vfs_inode.i_ino, req->obj_name, req->binary_size);
211 err_out_free:
212 kfree(e);
213 err_out_free_pio:
214 kmem_cache_free(pohmelfs_io_cache, pio);
215 err_out_wait_put:
216 pohmelfs_wait_put(wait);
217 err_out_exit:
218 return err;
221 int pohmelfs_send_inode_info(struct pohmelfs_inode *pi, struct dnet_raw_id *id, const char *sname, int len, int sync)
223 struct pohmelfs_inode_info_binary_package *bin;
224 struct pohmelfs_script_req req;
225 int err;
227 if (!len) {
228 err = -EINVAL;
229 goto err_out_exit;
232 bin = kmem_cache_alloc(pohmelfs_inode_info_binary_package_cache, GFP_NOIO);
233 if (!bin) {
234 err = -ENOMEM;
235 goto err_out_exit;
238 req.script_name = POHMELFS_INODE_INFO_SCRIPT_INSERT;
239 req.script_namelen = sizeof(POHMELFS_INODE_INFO_SCRIPT_INSERT) - 1; /* not including 0-byte */
241 req.obj_name = (char *)sname;
242 req.obj_len = len;
244 req.binary = bin;
245 req.binary_size = sizeof(struct pohmelfs_inode_info) + sizeof(struct dnet_raw_id);
247 req.group_id = 0;
248 req.id = id;
250 req.sync = sync;
252 memcpy(&bin->parent, id, sizeof(struct dnet_raw_id));
253 pohmelfs_fill_inode_info(&pi->vfs_inode, &bin->info);
254 bin->info.namelen = len;
256 pohmelfs_convert_inode_info(&bin->info);
258 req.complete = pohmelfs_send_inode_info_complete;
260 err = pohmelfs_send_script_request(pi, &req);
261 if (err)
262 goto err_out_free;
264 err_out_free:
265 kmem_cache_free(pohmelfs_inode_info_binary_package_cache, bin);
266 err_out_exit:
267 return err;
270 static int pohmelfs_create(struct inode *dir, struct dentry *dentry, int mode,
271 struct nameidata *nd)
273 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
274 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
275 struct pohmelfs_inode *pi;
276 int err;
278 pi = pohmelfs_new_inode(psb, mode);
279 if (IS_ERR(pi)) {
280 err = PTR_ERR(pi);
281 goto err_out_exit;
284 pohmelfs_inode_dirty(parent, pi);
286 pr_debug("pohmelfs: create: %s, ino: %lu, parent dir: %lu, object: %s\n",
287 pohmelfs_dump_id(pi->id.id), pi->vfs_inode.i_ino,
288 dir->i_ino, dentry->d_name.name);
291 * calling d_instantiate() implies that
292 * ->lookup() used d_splice_alias() with NULL inode
293 * when it failed to find requested object
295 d_instantiate(dentry, &pi->vfs_inode);
297 return 0;
299 err_out_exit:
300 return err;
303 struct pohmelfs_readdir_header {
304 char magic[8];
305 unsigned short version;
306 unsigned short chunk_size;
307 unsigned int chunk_num;
308 } __attribute__((packed));
310 static void pohmelfs_convert_readdir_header(struct pohmelfs_readdir_header *h)
312 h->version = dnet_bswap16(h->version);
313 h->chunk_size = dnet_bswap16(h->chunk_size);
314 h->chunk_num = dnet_bswap32(h->chunk_num);
317 struct pohmelfs_readdir_chunk_header {
318 unsigned short length;
319 unsigned short num;
320 unsigned short key_size;
321 unsigned short payload_size;
322 } __attribute__((packed));
324 static void pohmelfs_convert_readdir_chunk_header(struct pohmelfs_readdir_chunk_header *h)
326 h->length = dnet_bswap16(h->length);
327 h->num = dnet_bswap16(h->num);
328 h->key_size = dnet_bswap16(h->key_size);
329 h->payload_size = dnet_bswap16(h->payload_size);
332 /* Chunk size = maximum file name length + sizeof header + sizeof pohmelfs_inode_info
333 * It allows to store whole file entry on 1 chunk
335 #define POHMELFS_CHUNK_SIZE (NAME_MAX + 1 + sizeof(struct pohmelfs_inode_info) + sizeof(struct pohmelfs_readdir_chunk_header))
337 enum pohmelfs_readdir_states {
338 POHMELFS_READDIR_WANT_HEADER = 1,
339 POHMELFS_READDIR_WANT_RECV_CHUNK,
342 struct pohmelfs_readdir_priv {
343 struct pohmelfs_wait *wait;
345 struct kref refcnt;
347 struct pohmelfs_readdir_header header;
349 int state;
350 int read_total; /* number of inode offsets read or processed total (in all chunks summed) */
351 int read_in_inode; /* offset of name+pohmelfs_inode_info read in below buffer */
353 char chunk[POHMELFS_CHUNK_SIZE];
356 static void pohmelfs_readdir_free(struct kref *kref)
358 struct pohmelfs_readdir_priv *priv = container_of(kref, struct pohmelfs_readdir_priv, refcnt);
360 if (priv->wait)
361 pohmelfs_wait_put(priv->wait);
362 kfree(priv);
365 static void pohmelfs_readdir_destroy(struct pohmelfs_trans *t)
367 struct pohmelfs_readdir_priv *priv = t->priv;
368 struct pohmelfs_wait *wait = priv->wait;
370 wake_up(&wait->wq);
371 kref_put(&priv->refcnt, pohmelfs_readdir_free);
374 static int pohmelfs_readdir_complete(struct pohmelfs_trans *t, struct pohmelfs_state *recv)
376 struct pohmelfs_inode *pi = pohmelfs_inode(t->inode);
377 struct pohmelfs_readdir_priv *priv = t->priv;
378 struct pohmelfs_wait *wait = priv->wait;
379 struct dnet_cmd *cmd = &recv->cmd;
381 if (t->recv_data) {
382 kfree(t->recv_data);
383 t->recv_data = NULL;
386 pr_debug("pohmelfs: %s: comlete cmd size: %llu, recv offset: %llu, flags: %x\n",
387 pohmelfs_dump_id(pi->id.id), (unsigned long long)cmd->size, t->recv_offset, cmd->flags);
389 if (!(cmd->flags & DNET_FLAGS_MORE)) {
390 wait->condition = cmd->status;
391 if (!wait->condition)
392 wait->condition = 1;
395 return 0;
398 static int pohmelfs_dentry_add(struct pohmelfs_inode *parent, struct pohmelfs_inode *pi, char *name, int len)
400 struct inode *inode = &pi->vfs_inode;
401 struct inode *dir = &parent->vfs_inode;
402 struct dentry *dentry, *parent_dentry, *old;
403 struct qstr str;
404 int err;
406 str.name = name;
407 str.len = len;
408 str.hash = full_name_hash(str.name, str.len);
410 /* we do not need to hold dir->i_mutex here, don't we? :) */
411 parent_dentry = d_find_alias(dir);
412 if (!parent_dentry) {
413 err = -ENOENT;
414 goto err_out_exit;
417 dentry = d_lookup(parent_dentry, &str);
418 if (dentry) {
419 err = -EEXIST;
421 dentry->d_fsdata = NULL;
422 dput(dentry);
423 goto err_out_put_parent;
426 * if things are ok, dentry has 2 references -
427 * one in parent dir, and another its own,
428 * which we should drop
430 dentry = d_alloc(parent_dentry, &str);
431 if (!dentry) {
432 err = -ENOMEM;
433 goto err_out_put_parent;
436 old = d_splice_alias(inode, dentry);
437 if (unlikely(old)) {
438 dput(dentry);
439 dentry = old;
440 } else {
441 dput(dentry);
444 dput(parent_dentry);
445 return 0;
447 err_out_put_parent:
448 dput(parent_dentry);
449 err_out_exit:
450 return err;
453 static int pohmelfs_update_inode(struct pohmelfs_inode *parent, struct pohmelfs_inode_info *info, char *name)
455 struct pohmelfs_sb *psb = pohmelfs_sb(parent->vfs_inode.i_sb);
456 struct pohmelfs_inode *pi;
457 struct inode *inode;
458 int err = 0;
459 int existing = 0;
461 pi = pohmelfs_sb_inode_lookup(psb, &info->id);
462 if (pi) {
463 inode = &pi->vfs_inode;
464 pohmelfs_fill_inode(inode, info);
465 existing = 1;
466 } else {
467 pi = pohmelfs_existing_inode(psb, info);
468 if (IS_ERR(pi)) {
469 err = PTR_ERR(pi);
470 goto err_out_exit;
472 inode = &pi->vfs_inode;
474 pi->parent_id = parent->id;
477 err = pohmelfs_dentry_add(parent, pi, name, info->namelen);
478 inode->i_version = 0;
479 pi->received = 1;
482 * We incremented refcnt for existing inodes,
483 * but if there is no dentry for inode in question,
484 * then we will allocate and connect them, otherwise
485 * we have to drop its reference counter (i.e. when
486 * dentry for this inode already exists)
489 pr_debug("pohmelfs: %s: update inode: %lu, existing: %d, refcnt: %d, err: %d\n",
490 pohmelfs_dump_id(pi->id.id), inode->i_ino, existing,
491 atomic_read(&inode->i_count), err);
492 if (err)
493 iput(inode);
495 err_out_exit:
496 return err;
499 static int pohmelfs_readdir_scratch(struct pohmelfs_trans *t, struct pohmelfs_state *recv)
501 struct pohmelfs_inode *pi = pohmelfs_inode(t->inode);
502 struct pohmelfs_readdir_priv *priv = t->priv;
503 struct dnet_cmd *cmd = &recv->cmd;
504 int err = 0;
506 pr_debug("pohmelfs: %s: cmd size: %llu, recv offset: %llu\n",
507 pohmelfs_dump_id(pi->id.id), (unsigned long long)cmd->size, t->recv_offset);
508 while (t->recv_offset != cmd->size) {
509 long rest = cmd->size - t->recv_offset;
511 if (rest > POHMELFS_CHUNK_SIZE)
512 rest = POHMELFS_CHUNK_SIZE;
514 err = pohmelfs_recv(t, recv, priv->chunk, rest);
515 if (err < 0)
516 break;
518 err = 0;
520 pr_debug("pohmelfs: %s: done cmd size: %llu, recv offset: %llu\n",
521 pohmelfs_dump_id(pi->id.id), (unsigned long long)cmd->size, t->recv_offset);
523 return err;
526 static int pohmelfs_readdir_recv_reply(struct pohmelfs_trans *t, struct pohmelfs_state *recv)
528 struct pohmelfs_inode *pi = pohmelfs_inode(t->inode);
529 struct pohmelfs_readdir_priv *priv = t->priv;
530 struct dnet_cmd *cmd = &recv->cmd;
531 int attr_size = sizeof(struct dnet_attr) + sizeof(struct dnet_io_attr);
532 long old_recv_offset;
533 void *data;
534 int size;
535 int err = 0;
537 pr_debug("pohmelfs: %s: recv reply: cmd size: %llu, recv offset: %llu\n",
538 pohmelfs_dump_id(pi->id.id), (unsigned long long)cmd->size, t->recv_offset);
540 if (t->recv_offset < attr_size) {
541 data = &t->cmd.attr;
543 data += t->recv_offset;
544 size = attr_size - t->recv_offset;
546 err = pohmelfs_recv(t, recv, data, size);
547 if (err < 0)
548 goto err_out_exit;
550 if (t->recv_offset == attr_size) {
551 dnet_convert_attr(&t->cmd.attr);
552 dnet_convert_io_attr(&t->cmd.p.io);
554 pr_debug("pohmelfs: %d:%s: cmd size: %llu, io size: %llu\n",
555 cmd->id.group_id, pohmelfs_dump_id(cmd->id.id),
556 (unsigned long long)cmd->size, (unsigned long long)t->cmd.p.io.size);
558 priv->state = POHMELFS_READDIR_WANT_HEADER;
562 if (priv->state == POHMELFS_READDIR_WANT_HEADER) {
563 int header_size_to_read = sizeof(struct pohmelfs_readdir_header) - (t->recv_offset - attr_size);
565 data = &priv->header;
566 data += sizeof(struct pohmelfs_readdir_header) - header_size_to_read;
568 err = pohmelfs_recv(t, recv, data, header_size_to_read);
569 if (err < 0)
570 goto err_out_exit;
572 pohmelfs_convert_readdir_header(&priv->header);
573 priv->read_total = 0;
574 priv->read_in_inode = 0;
575 priv->state = POHMELFS_READDIR_WANT_RECV_CHUNK;
577 pr_debug("pohmelfs: %d:%s: header: header size: %d, version: %hd, chunk_size: %hd, chunk_num: %d\n",
578 cmd->id.group_id, pohmelfs_dump_id(cmd->id.id), header_size_to_read,
579 priv->header.version, priv->header.chunk_size, priv->header.chunk_num);
581 if (priv->header.chunk_size > POHMELFS_CHUNK_SIZE) {
582 err = -E2BIG;
583 goto err_out_exit;
587 get_new_chunk:
588 if (priv->read_total == priv->header.chunk_num) {
589 err = pohmelfs_readdir_scratch(t, recv);
590 goto err_out_exit;
593 if (priv->state == POHMELFS_READDIR_WANT_RECV_CHUNK) {
594 data = priv->chunk + priv->read_in_inode;
595 size = POHMELFS_CHUNK_SIZE - priv->read_in_inode;
597 old_recv_offset = t->recv_offset;
599 err = pohmelfs_recv(t, recv, data, size);
600 if (err < 0)
601 goto err_out_exit;
603 priv->read_in_inode += t->recv_offset - old_recv_offset;
605 if (priv->read_in_inode == POHMELFS_CHUNK_SIZE) {
606 struct pohmelfs_readdir_chunk_header *chunk_header;
607 struct pohmelfs_inode_info *info;
608 char *filename;
610 priv->read_in_inode = 0;
611 priv->read_total++;
613 chunk_header = (struct pohmelfs_readdir_chunk_header *)priv->chunk;
614 pohmelfs_convert_readdir_chunk_header(chunk_header);
617 * Here we assume that record always fits in 1 chunk.
618 * In future this code should be changed to read several chunks
619 * and concatenate it to build continous buffer for
620 * file name and pohmelfs_inode_info structure
623 info = (struct pohmelfs_inode_info *)(priv->chunk + sizeof(struct pohmelfs_readdir_chunk_header) + chunk_header->key_size);
624 pohmelfs_convert_inode_info(info);
626 filename = (char *)(priv->chunk + sizeof(struct pohmelfs_readdir_chunk_header));
628 err = pohmelfs_update_inode(priv->wait->pi, info, filename);
629 pr_debug("pohmelfs: %d:%s: inode: %llu, namelen: %d, name: %.*s: %d\n",
630 cmd->id.group_id, pohmelfs_dump_id(info->id.id), (unsigned long long)info->ino,
631 info->namelen, info->namelen, filename, err);
632 } else {
633 err = -EAGAIN;
634 goto err_out_exit;
637 if ((priv->read_total < priv->header.chunk_num) && (t->recv_offset < cmd->size))
638 goto get_new_chunk;
641 return 0;
643 err_out_exit:
644 return err;
647 static int pohmelfs_readdir_init(struct pohmelfs_trans *t)
649 struct pohmelfs_readdir_priv *priv = t->priv;
651 kref_get(&priv->refcnt);
652 return 0;
655 static int pohmelfs_warm_dir_group(struct inode *dir, int group_id)
657 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
658 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
659 struct pohmelfs_io *io;
660 struct pohmelfs_readdir_priv *priv;
661 struct pohmelfs_wait *wait;
662 long ret;
663 int err;
665 io = kmem_cache_zalloc(pohmelfs_io_cache, GFP_NOIO);
666 if (!io) {
667 err = -ENOMEM;
668 goto err_out_exit;
671 priv = kzalloc(sizeof(struct pohmelfs_readdir_priv), GFP_NOIO);
672 if (!priv) {
673 err = -ENOMEM;
674 goto err_out_free;
677 kref_init(&priv->refcnt);
679 wait = pohmelfs_wait_alloc(parent);
680 if (!wait) {
681 err = -ENOMEM;
682 goto err_out_put;
685 priv->wait = wait;
687 io->pi = parent;
688 io->id = &parent->id;
689 io->cflags = DNET_FLAGS_NEED_ACK | DNET_FLAGS_NOLOCK;
690 io->cmd = DNET_CMD_READ;
691 io->cb.recv_reply = pohmelfs_readdir_recv_reply;
692 io->cb.complete = pohmelfs_readdir_complete;
693 io->cb.destroy = pohmelfs_readdir_destroy;
694 io->cb.init = pohmelfs_readdir_init;
695 io->priv = priv;
697 err = pohmelfs_send_io_group(io, group_id);
698 if (err)
699 goto err_out_put;
701 /* destruction callback will drop reference */
702 ret = wait_event_interruptible_timeout(wait->wq, wait->condition != 0, msecs_to_jiffies(psb->read_wait_timeout));
703 if (ret <= 0) {
704 err = ret;
705 if (ret == 0)
706 err = -ETIMEDOUT;
707 goto err_out_put;
710 if (wait->condition < 0) {
711 err = wait->condition;
712 goto err_out_put;
715 /* drop the reference we grabbed at creation time */
716 kref_put(&priv->refcnt, pohmelfs_readdir_free);
717 kmem_cache_free(pohmelfs_io_cache, io);
718 return 0;
720 err_out_put:
721 kref_put(&priv->refcnt, pohmelfs_readdir_free);
722 err_out_free:
723 kmem_cache_free(pohmelfs_io_cache, io);
724 err_out_exit:
725 return err;
728 static int pohmelfs_warm_dir(struct inode *dir)
730 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
731 int i, err = -ENOENT;
733 for (i = 0; i < psb->group_num; ++i) {
734 err = pohmelfs_warm_dir_group(dir, psb->groups[i]);
735 if (err)
736 continue;
738 return 0;
741 return err;
744 static struct pohmelfs_inode *pohmelfs_lookup_group(struct inode *dir, struct dentry *dentry, int group_id)
746 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
747 struct pohmelfs_script_req req;
748 struct pohmelfs_inode *pi;
749 int err;
751 req.script_name = POHMELFS_LOOKUP_SCRIPT;
752 req.script_namelen = sizeof(POHMELFS_LOOKUP_SCRIPT) - 1; /* not including 0-byte */
754 req.obj_name = (char *)dentry->d_name.name;
755 req.obj_len = dentry->d_name.len;
757 req.binary = &parent->id;
758 req.binary_size = sizeof(struct dnet_raw_id);
760 req.id = &parent->id;
761 req.complete = pohmelfs_lookup_complete;
763 req.group_id = group_id;
764 req.sync = 1;
766 err = pohmelfs_send_script_request(parent, &req);
767 if (err)
768 goto err_out_exit;
770 pi = req.ret;
771 if (!pi) {
772 err = -ENOENT;
773 goto err_out_exit;
776 return pi;
778 err_out_exit:
779 pr_debug("pohmelfs: pohmelfs_lookup_group: %s: group: %d: parent ino: %lu, name: %s: %d\n",
780 pohmelfs_dump_id(parent->id.id), group_id, parent->vfs_inode.i_ino, dentry->d_name.name, err);
781 return ERR_PTR(err);
784 static struct dentry *pohmelfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
786 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
787 struct inode *inode = NULL;
788 struct pohmelfs_inode *pi;
789 int i, err = -ENOENT;
791 for (i = 0; i < psb->group_num; ++i) {
792 pi = pohmelfs_lookup_group(dir, dentry, psb->groups[i]);
793 if (IS_ERR(pi)) {
794 err = PTR_ERR(pi);
795 continue;
798 inode = &pi->vfs_inode;
799 err = 0;
800 break;
803 if (err && (err != -ENOENT) && (err != -EOPNOTSUPP))
804 return ERR_PTR(err);
806 return d_splice_alias(inode, dentry);
809 static int pohmelfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
811 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
812 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
813 struct pohmelfs_inode *pi;
814 int err;
816 inode_inc_link_count(dir);
818 pi = pohmelfs_new_inode(psb, mode | S_IFDIR);
819 if (IS_ERR(pi)) {
820 err = PTR_ERR(pi);
821 goto err_out_dir;
824 pohmelfs_inode_dirty(parent, pi);
826 d_instantiate(dentry, &pi->vfs_inode);
827 pr_debug("pohmelfs: mkdir: %s, ino: %lu, parent dir: %lu, object: %s, refcnt: %d\n",
828 pohmelfs_dump_id(pi->id.id), pi->vfs_inode.i_ino,
829 dir->i_ino, dentry->d_name.name, dentry->d_count);
831 return 0;
833 err_out_dir:
834 inode_dec_link_count(dir);
835 return err;
838 static int pohmelfs_unlink(struct inode *dir, struct dentry *dentry)
840 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
841 struct pohmelfs_script_req req;
843 req.script_name = POHMELFS_UNLINK_SCRIPT;
844 req.script_namelen = sizeof(POHMELFS_UNLINK_SCRIPT) - 1; /* not including 0-byte */
846 req.obj_name = (char *)dentry->d_name.name;
847 req.obj_len = dentry->d_name.len;
849 req.binary = &parent->id;
850 req.binary_size = sizeof(struct dnet_raw_id);
852 req.group_id = 0;
853 req.id = &parent->id;
854 req.complete = pohmelfs_send_inode_info_complete;
856 req.sync = 0;
858 return pohmelfs_send_script_request(parent, &req);
861 static int pohmelfs_rmdir(struct inode *dir, struct dentry *dentry)
863 return pohmelfs_unlink(dir, dentry);
866 struct pohmelfs_rename_req {
867 struct dnet_raw_id old_dir_id;
868 struct dnet_raw_id new_dir_id;
869 int new_len;
870 char new_name[0];
871 } __attribute__ ((packed));
873 static int pohmelfs_rename(struct inode *old_dir, struct dentry *old_dentry,
874 struct inode *new_dir, struct dentry *new_dentry)
876 struct pohmelfs_inode *old_parent = pohmelfs_inode(old_dir);
877 struct pohmelfs_script_req req;
878 struct pohmelfs_rename_req *r;
879 int size = sizeof(struct pohmelfs_rename_req) + new_dentry->d_name.len;
880 int err;
882 r = kmalloc(size, GFP_NOIO);
883 if (!r) {
884 err = -ENOMEM;
885 goto err_out_exit;
888 r->old_dir_id = pohmelfs_inode(old_dir)->id;
889 r->new_dir_id = pohmelfs_inode(new_dir)->id;
890 r->new_len = cpu_to_le32(new_dentry->d_name.len);
891 memcpy(r->new_name, new_dentry->d_name.name, new_dentry->d_name.len);
893 req.script_name = POHMELFS_RENAME_SCRIPT;
894 req.script_namelen = sizeof(POHMELFS_RENAME_SCRIPT) - 1; /* not including 0-byte */
896 req.obj_name = (char *)old_dentry->d_name.name;
897 req.obj_len = old_dentry->d_name.len;
899 req.binary = r;
900 req.binary_size = size;
902 req.sync = 0;
903 req.group_id = 0;
904 req.id = &old_parent->id;
905 req.complete = pohmelfs_send_inode_info_complete;
907 err = pohmelfs_send_script_request(old_parent, &req);
908 if (err)
909 goto err_out_free;
911 err_out_free:
912 kfree(r);
913 err_out_exit:
914 return err;
917 static int pohmelfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
919 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
920 struct pohmelfs_inode *pi;
921 struct inode *inode;
922 unsigned len = strlen(symname)+1;
923 int err = 0;
925 pi = pohmelfs_new_inode(psb, S_IFLNK | S_IRWXUGO);
926 if (IS_ERR(pi)) {
927 err = PTR_ERR(pi);
928 goto err_out_exit;
931 pohmelfs_inode_dirty(pohmelfs_inode(dir), pi);
932 inode = &pi->vfs_inode;
934 err = page_symlink(inode, symname, len);
935 if (err)
936 goto err_out_put;
938 d_instantiate(dentry, inode);
940 return 0;
942 err_out_put:
943 iput(inode);
944 err_out_exit:
945 return err;
948 const struct inode_operations pohmelfs_dir_inode_operations = {
949 .create = pohmelfs_create,
950 .lookup = pohmelfs_lookup,
951 .mkdir = pohmelfs_mkdir,
952 .unlink = pohmelfs_unlink,
953 .rmdir = pohmelfs_rmdir,
954 .rename = pohmelfs_rename,
955 .symlink = pohmelfs_symlink,
958 static int pohmelfs_dir_open(struct inode *dir, struct file *file)
960 struct pohmelfs_inode *pi;
961 struct dentry *parent_dentry = file->f_path.dentry;
962 struct dentry *dentry, *tmp;
963 LIST_HEAD(kill_list);
964 int err;
965 u64 magic_version = 0x100;
966 void *magic_data = (void *)(0x1234);
967 #if 1
968 spin_lock(&parent_dentry->d_lock);
969 list_for_each_entry_safe(dentry, tmp, &file->f_path.dentry->d_subdirs, d_u.d_child) {
970 pi = pohmelfs_inode(dentry->d_inode);
972 if (dentry->d_inode && pi->received) {
973 pi->vfs_inode.i_version = magic_version;
974 dentry->d_fsdata = magic_data;
977 spin_unlock(&parent_dentry->d_lock);
979 pohmelfs_warm_dir(dir);
981 spin_lock(&parent_dentry->d_lock);
982 list_for_each_entry_safe(dentry, tmp, &file->f_path.dentry->d_subdirs, d_u.d_child) {
983 pi = pohmelfs_inode(dentry->d_inode);
985 if ((dentry->d_inode && pi->received && (pi->vfs_inode.i_version == magic_version)) || (dentry->d_fsdata == magic_data)) {
986 spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
987 __d_drop(dentry);
988 dget_dlock(dentry);
990 list_move(&dentry->d_u.d_child, &kill_list);
991 spin_unlock(&dentry->d_lock);
994 spin_unlock(&parent_dentry->d_lock);
996 list_for_each_entry_safe(dentry, tmp, &kill_list, d_u.d_child) {
997 d_delete(dentry);
998 dput(dentry);
1000 #else
1001 pohmelfs_warm_dir(dir);
1002 #endif
1004 err = dcache_dir_open(dir, file);
1005 if (err)
1006 goto err_out_exit;
1008 err_out_exit:
1009 return err;
1012 const struct file_operations pohmelfs_dir_fops = {
1013 .open = pohmelfs_dir_open,
1014 .release = dcache_dir_close,
1015 .llseek = dcache_dir_lseek,
1017 .read = generic_read_dir,
1018 .readdir = dcache_readdir,