2 * Copyright (C) 2011+ Evgeniy Polyakov <zbr@ioremap.net>
6 #include <linux/dcache.h>
7 #include <linux/quotaops.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
);
52 wait
->condition
= cmd
->status
;
59 static int pohmelfs_send_inode_info_init(struct pohmelfs_trans
*t
)
61 struct pohmelfs_wait
*wait
= t
->priv
;
63 pohmelfs_wait_get(wait
);
67 static void pohmelfs_send_inode_info_destroy(struct pohmelfs_trans
*t
)
69 struct pohmelfs_wait
*wait
= t
->priv
;
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
;
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
)) {
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
);
114 pi
= pohmelfs_sb_inode_lookup(psb
, &info
->id
);
120 pohmelfs_fill_inode(&pi
->vfs_inode
, info
);
123 pi
->parent_id
= parent
->id
;
129 wait
->condition
= err
;
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
;
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
);
156 pio
= kmem_cache_zalloc(pohmelfs_io_cache
, GFP_NOIO
);
159 goto err_out_wait_put
;
162 e
= kmalloc(sizeof(struct dnet_exec
) + req
->script_namelen
+ script_len
+ req
->binary_size
, GFP_NOIO
);
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
);
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
;
190 pio
->cb
.init
= pohmelfs_send_inode_info_init
;
191 pio
->cb
.destroy
= pohmelfs_send_inode_info_destroy
;
192 pio
->cb
.complete
= req
->complete
;
195 err
= pohmelfs_send_buf_single(pio
, NULL
);
197 err
= pohmelfs_send_buf(pio
);
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
);
215 ret
= wait_event_interruptible_timeout(wait
->wq
, wait
->condition
!= 0, msecs_to_jiffies(psb
->read_wait_timeout
));
223 if (wait
->condition
< 0)
224 err
= wait
->condition
;
226 req
->ret
= wait
->ret
;
227 req
->ret_cond
= wait
->condition
;
233 kmem_cache_free(pohmelfs_io_cache
, pio
);
235 pohmelfs_wait_put(wait
);
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
);
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
;
263 pd
= kmem_cache_alloc(pohmelfs_dentry_cache
, GFP_NOIO
);
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;
275 memset(&req
, 0, sizeof(struct pohmelfs_script_req
));
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
;
286 req
.binary_size
= sizeof(struct pohmelfs_dentry
);
292 req
.complete
= pohmelfs_send_dentry_complete
;
294 err
= pohmelfs_send_script_request(pi
, &req
);
298 err
= inode
->i_sb
->s_op
->write_inode(inode
, NULL
);
301 kmem_cache_free(pohmelfs_dentry_cache
, pd
);
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
;
314 inode_inc_link_count(dir
);
316 pi
= pohmelfs_new_inode(psb
, mode
);
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);
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
);
345 inode_dec_link_count(dir
);
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
;
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
;
374 err
= pohmelfs_send_script_request(parent
, &req
);
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
);
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
]);
406 inode
= &pi
->vfs_inode
;
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
;
421 inode_inc_link_count(dir
);
423 pi
= pohmelfs_new_inode(psb
, mode
| S_IFDIR
);
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);
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
);
445 inode_dec_link_count(dir
);
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
;
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
);
468 req
.id
= &parent
->id
;
469 req
.complete
= pohmelfs_send_dentry_complete
;
473 err
= pohmelfs_send_script_request(parent
, &req
);
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
;
507 if (pohmelfs_sb(inode
->i_sb
)->http_compat
) {
512 r
= kzalloc(size
, GFP_NOIO
);
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
;
536 req
.binary_size
= size
;
540 req
.id
= &old_parent
->id
;
541 req
.complete
= pohmelfs_send_dentry_complete
;
543 err
= pohmelfs_send_script_request(old_parent
, &req
);
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
;
558 unsigned len
= strlen(symname
)+1;
561 inode_inc_link_count(dir
);
562 pi
= pohmelfs_new_inode(psb
, S_IFLNK
| S_IRWXUGO
);
569 inode
= &pi
->vfs_inode
;
571 err
= page_symlink(inode
, symname
, len
);
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);
588 inode_dec_link_count(dir
);
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
;
600 dquot_initialize(dir
);
602 inode
->i_ctime
= CURRENT_TIME_SEC
;
603 inode_inc_link_count(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);
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
);
626 req
.complete
= pohmelfs_send_dentry_complete
;
630 err
= pohmelfs_send_script_request(parent
, &req
);
634 d_instantiate(dentry
, inode
);
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
);
644 inode_dec_link_count(inode
);
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
;
656 if (!new_valid_dev(rdev
))
659 inode_inc_link_count(dir
);
660 dquot_initialize(dir
);
662 pi
= pohmelfs_new_inode(psb
, mode
);
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);
686 inode_dec_link_count(dir
);
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
;
720 if (!wait
->condition
) {
721 wait
->condition
= cmd
->status
;
722 if (!wait
->condition
)
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
;
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
) {
749 dentry
= d_lookup(parent_dentry
, &str
);
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
);
764 goto err_out_put_parent
;
767 old
= d_splice_alias(inode
, dentry
);
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
;
791 pi
= pohmelfs_sb_inode_lookup(psb
, &info
->id
);
793 inode
= &pi
->vfs_inode
;
794 pohmelfs_fill_inode(inode
, info
);
797 pi
= pohmelfs_existing_inode(psb
, info
);
802 inode
= &pi
->vfs_inode
;
804 pi
->parent_id
= parent
->id
;
807 err
= pohmelfs_dentry_add(parent
, pi
, name
, info
->namelen
);
815 struct pohmelfs_fetch_info
{
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
);
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
);
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
;
852 if (!(cmd
->flags
& DNET_FLAGS_MORE
))
855 if (cmd
->size
<= sizeof(struct dnet_attr
) + sizeof(struct dnet_io_attr
) + sizeof(struct dnet_io_attr
))
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
);
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
;
874 pio
= kmem_cache_zalloc(pohmelfs_io_cache
, GFP_NOIO
);
880 fi
= kmalloc(sizeof(struct pohmelfs_fetch_info
) + d
->len
, GFP_NOIO
);
886 memcpy(fi
->name
, d
->name
, d
->len
);
888 kref_init(&fi
->refcnt
);
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
;
903 for (i
= 0; i
< group_num
; ++i
) {
904 pio
->group_id
= groups
[i
];
905 err
= pohmelfs_send_io_group(pio
, groups
[i
]);
910 kref_put(&fi
->refcnt
, pohmelfs_fetch_inode_info_free
);
912 kmem_cache_free(pohmelfs_io_cache
, pio
);
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
);
921 return pohmelfs_fetch_inode_info_group(pi
, d
, pi
->groups
, pi
->group_num
);
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
;
935 struct pohmelfs_dentry_disk
*d
= data
;
937 if (size
< sizeof(struct pohmelfs_dentry_disk
)) {
947 err
= filldir(dirent
, d
->name
, d
->len
, filp
->f_pos
, le64_to_cpu(d
->ino
), d
->type
);
952 pi
= pohmelfs_sb_inode_lookup(psb
, &d
->id
);
954 pohmelfs_fetch_inode_info(pohmelfs_inode(dir
), d
);
956 iput(&pi
->vfs_inode
);
959 size
-= sizeof(struct pohmelfs_dentry_disk
) + d
->len
;
960 data
+= sizeof(struct pohmelfs_dentry_disk
) + d
->len
;
966 struct pohmelfs_readdir
{
967 struct dnet_raw_id id
;
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
;
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
;
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 .. */
997 req
.binary_size
= sizeof(struct pohmelfs_readdir
);
999 req
.id
= &parent
->id
;
1000 req
.complete
= pohmelfs_readdir_complete
;
1003 req
.group_id
= group_id
;
1006 err
= pohmelfs_send_script_request(parent
, &req
);
1011 size
= req
.ret_cond
;
1012 if (!data
|| !size
) {
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
);
1029 if (!pohmelfs_need_resync(pi
))
1030 return dcache_dir_open(dir
, filp
);
1036 static int pohmelfs_dir_close(struct inode
*inode
, struct file
*filp
)
1038 if (filp
->private_data
)
1039 return dcache_dir_close(inode
, filp
);
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
);
1062 if (filp
->f_pos
== 1) {
1063 err
= filldir(dirent
, "..", 2, filp
->f_pos
, parent_ino(dentry
), DT_DIR
);
1069 for (i
= 0; i
< psb
->group_num
; ++i
) {
1073 data
= pohmelfs_readdir_group(psb
->groups
[i
], filp
, &size
);
1075 err
= PTR_ERR(data
);
1079 pi
->update
= get_seconds();
1080 err
= pohmelfs_readdir_process(data
+ sizeof(struct dnet_attr
), size
- sizeof(struct dnet_attr
), filp
, dirent
, filldir
);
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
,