2 * Copyright (C) 2011+ Evgeniy Polyakov <zbr@ioremap.net>
5 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
8 #include <linux/dcache.h>
9 #include <linux/quotaops.h>
13 #define POHMELFS_LOOKUP_SCRIPT "pohmelfs_lookup.py"
14 #define POHMELFS_UNLINK_SCRIPT "pohmelfs_unlink.py"
15 #define POHMELFS_DATA_UNLINK_SCRIPT "pohmelfs_data_unlink.py"
16 #define POHMELFS_HARDLINK_SCRIPT "pohmelfs_hardlink.py"
17 #define POHMELFS_RENAME_SCRIPT "pohmelfs_rename.py"
18 #define POHMELFS_INODE_INFO_SCRIPT_INSERT "pohmelfs_inode_info_insert.py"
19 #define POHMELFS_READDIR_SCRIPT "pohmelfs_readdir.py"
20 #define POHMELFS_DENTRY_NAME_SCRIPT "pohmelfs_dentry_name="
22 static void pohmelfs_init_local(struct pohmelfs_inode
*pi
, struct inode
*dir
)
24 struct inode
*inode
= &pi
->vfs_inode
;
26 inode_init_owner(inode
, dir
, inode
->i_mode
);
29 mark_inode_dirty(inode
);
32 static int pohmelfs_send_dentry_complete(struct pohmelfs_trans
*t
, struct pohmelfs_state
*recv
)
34 struct pohmelfs_inode
*pi
= pohmelfs_inode(t
->inode
);
35 struct pohmelfs_wait
*wait
= t
->priv
;
36 struct dnet_cmd
*cmd
= &recv
->cmd
;
37 unsigned long long trans
= cmd
->trans
& ~DNET_TRANS_REPLY
;
39 if (cmd
->flags
& DNET_FLAGS_MORE
) {
40 if (cmd
->status
== 0 && cmd
->size
!= sizeof(struct dnet_attr
) + 2)
41 cmd
->status
= -EINVAL
;
43 pr_debug("%s: %llu, cmd_size: %llu, flags: %x, status: %d\n",
44 pohmelfs_dump_id(pi
->id
.id
), trans
, cmd
->size
,
45 cmd
->flags
, cmd
->status
);
50 wait
->condition
= cmd
->status
;
57 static int pohmelfs_send_inode_info_init(struct pohmelfs_trans
*t
)
59 struct pohmelfs_wait
*wait
= t
->priv
;
61 pohmelfs_wait_get(wait
);
65 static void pohmelfs_send_inode_info_destroy(struct pohmelfs_trans
*t
)
67 struct pohmelfs_wait
*wait
= t
->priv
;
72 pohmelfs_wait_put(wait
);
75 static int pohmelfs_lookup_complete(struct pohmelfs_trans
*t
, struct pohmelfs_state
*recv
)
77 struct pohmelfs_inode
*parent
= pohmelfs_inode(t
->inode
);
78 struct pohmelfs_wait
*wait
= t
->priv
;
79 struct dnet_cmd
*cmd
= &recv
->cmd
;
80 unsigned long long trans
= cmd
->trans
& ~DNET_TRANS_REPLY
;
81 int err
= cmd
->status
;
86 if (cmd
->flags
& DNET_FLAGS_MORE
) {
87 struct pohmelfs_sb
*psb
= pohmelfs_sb(t
->inode
->i_sb
);
88 struct pohmelfs_inode_info
*info
;
89 struct pohmelfs_inode
*pi
;
91 if (cmd
->size
!= sizeof(struct dnet_attr
) + sizeof(struct pohmelfs_inode_info
)) {
96 pr_debug("%s: %llu, size: %llu, min size: %zu, flags: %x, status: %d\n",
97 pohmelfs_dump_id(parent
->id
.id
), trans
, cmd
->size
,
98 sizeof(struct dnet_attr
) + sizeof(struct pohmelfs_inode_info
),
99 cmd
->flags
, cmd
->status
);
102 info
= t
->recv_data
+ sizeof(struct dnet_attr
);
103 pohmelfs_convert_inode_info(info
);
105 pi
= pohmelfs_existing_inode(psb
, info
);
113 pi
= pohmelfs_sb_inode_lookup(psb
, &info
->id
);
119 pohmelfs_fill_inode(&pi
->vfs_inode
, info
);
127 wait
->condition
= err
;
135 int pohmelfs_send_script_request(struct pohmelfs_inode
*parent
, struct pohmelfs_script_req
*req
)
137 struct pohmelfs_sb
*psb
= pohmelfs_sb(parent
->vfs_inode
.i_sb
);
138 struct pohmelfs_wait
*wait
;
139 struct pohmelfs_io
*pio
;
145 /* 2 commas, \n and 0-byte, which is accounted in sizeof(string) */
146 script_len
= sizeof(POHMELFS_DENTRY_NAME_SCRIPT
) + req
->obj_len
+ 3;
148 wait
= pohmelfs_wait_alloc(parent
);
154 pio
= kmem_cache_zalloc(pohmelfs_io_cache
, GFP_NOIO
);
157 goto err_out_wait_put
;
160 e
= kmalloc(sizeof(struct dnet_exec
) + req
->script_namelen
+ script_len
+ req
->binary_size
, GFP_NOIO
);
163 goto err_out_free_pio
;
166 memset(e
, 0, sizeof(struct dnet_exec
));
168 snprintf(e
->data
, req
->script_namelen
+ script_len
, "%s%s'%s'\n", req
->script_name
, POHMELFS_DENTRY_NAME_SCRIPT
, req
->obj_name
);
169 script_len
--; /* do not include last 0-byte in the script */
171 memcpy(e
->data
+ req
->script_namelen
+ script_len
, req
->binary
, req
->binary_size
);
173 e
->type
= DNET_EXEC_PYTHON_SCRIPT_NAME
;
174 e
->name_size
= req
->script_namelen
;
175 e
->script_size
= script_len
;
176 e
->binary_size
= req
->binary_size
;
177 dnet_convert_exec(e
);
181 pio
->group_id
= req
->group_id
;
182 pio
->cflags
= DNET_FLAGS_NEED_ACK
| req
->cflags
;
184 pio
->cmd
= DNET_CMD_EXEC
;
185 pio
->size
= sizeof(struct dnet_exec
) + req
->script_namelen
+ script_len
+ req
->binary_size
;
188 pio
->cb
.init
= pohmelfs_send_inode_info_init
;
189 pio
->cb
.destroy
= pohmelfs_send_inode_info_destroy
;
190 pio
->cb
.complete
= req
->complete
;
193 err
= pohmelfs_send_buf_single(pio
, NULL
);
195 err
= pohmelfs_send_buf(pio
);
202 char parent_id_str
[len
*2+1];
204 pr_debug("SENT: %.*s: %s: inode->id: %s, ino: %lu, object: %s, binary size: %d, ret: %p, condition: %d\n",
205 req
->script_namelen
, req
->script_name
,
206 pohmelfs_dump_id(req
->id
->id
),
207 pohmelfs_dump_id_len_raw(parent
->id
.id
, len
,
209 parent
->vfs_inode
.i_ino
, req
->obj_name
,
210 req
->binary_size
, req
->ret
, req
->ret_cond
);
214 ret
= wait_event_interruptible_timeout(wait
->wq
, wait
->condition
!= 0, msecs_to_jiffies(psb
->read_wait_timeout
));
222 if (wait
->condition
< 0)
223 err
= wait
->condition
;
225 req
->ret
= wait
->ret
;
226 req
->ret_cond
= wait
->condition
;
232 kmem_cache_free(pohmelfs_io_cache
, pio
);
234 pohmelfs_wait_put(wait
);
238 char parent_id_str
[len
*2+1];
240 pr_debug("DONE: %.*s: %s: inode->id: %s, ino: %lu, object: %s, binary size: %d, ret: %p, condition: %d, err: %d\n",
241 req
->script_namelen
, req
->script_name
,
242 pohmelfs_dump_id(req
->id
->id
),
243 pohmelfs_dump_id_len_raw(parent
->id
.id
, len
,
245 parent
->vfs_inode
.i_ino
, req
->obj_name
,
246 req
->binary_size
, 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 pohmelfs_script_req req
;
254 struct pohmelfs_dentry
*pd
;
262 pd
= kmem_cache_alloc(pohmelfs_dentry_cache
, GFP_NOIO
);
269 pd
->disk
.id
= pi
->id
;
270 pd
->disk
.ino
= cpu_to_le64(pi
->vfs_inode
.i_ino
);
271 pd
->disk
.type
= (pi
->vfs_inode
.i_mode
>> 12) & 15;
274 memset(&req
, 0, sizeof(struct pohmelfs_script_req
));
278 req
.script_name
= POHMELFS_INODE_INFO_SCRIPT_INSERT
;
279 req
.script_namelen
= sizeof(POHMELFS_INODE_INFO_SCRIPT_INSERT
) - 1; /* not including 0-byte */
281 req
.obj_name
= (char *)sname
;
285 req
.binary_size
= sizeof(struct pohmelfs_dentry
);
291 req
.complete
= pohmelfs_send_dentry_complete
;
293 err
= pohmelfs_send_script_request(pi
, &req
);
298 kmem_cache_free(pohmelfs_dentry_cache
, pd
);
303 static int pohmelfs_create(struct inode
*dir
, struct dentry
*dentry
, umode_t mode
,
304 struct nameidata
*nd
)
306 struct pohmelfs_sb
*psb
= pohmelfs_sb(dir
->i_sb
);
307 struct pohmelfs_inode
*pi
;
310 inode_inc_link_count(dir
);
312 pi
= pohmelfs_new_inode(psb
, mode
);
317 pohmelfs_init_local(pi
, dir
);
318 mark_inode_dirty(dir
);
321 * calling d_instantiate() implies that
322 * ->lookup() used d_splice_alias() with NULL inode
323 * when it failed to find requested object
325 d_instantiate(dentry
, &pi
->vfs_inode
);
326 if (psb
->http_compat
)
327 pohmelfs_http_compat_id(pi
);
329 err
= pohmelfs_send_dentry(pi
, &pohmelfs_inode(dir
)->id
, dentry
->d_name
.name
, dentry
->d_name
.len
, 1);
333 pr_debug("%s: ino: %lu, parent dir: %lu, object: %s\n",
334 pohmelfs_dump_id(pi
->id
.id
), pi
->vfs_inode
.i_ino
,
335 dir
->i_ino
, dentry
->d_name
.name
);
340 inode_dec_link_count(dir
);
344 static struct pohmelfs_inode
*pohmelfs_lookup_group(struct inode
*dir
, struct dentry
*dentry
, int group_id
)
346 struct pohmelfs_inode
*parent
= pohmelfs_inode(dir
);
347 struct pohmelfs_script_req req
;
348 struct pohmelfs_inode
*pi
;
351 memset(&req
, 0, sizeof(struct pohmelfs_script_req
));
353 req
.script_name
= POHMELFS_LOOKUP_SCRIPT
;
354 req
.script_namelen
= sizeof(POHMELFS_LOOKUP_SCRIPT
) - 1; /* not including 0-byte */
356 req
.obj_name
= (char *)dentry
->d_name
.name
;
357 req
.obj_len
= dentry
->d_name
.len
;
359 req
.binary
= &parent
->id
;
360 req
.binary_size
= sizeof(struct dnet_raw_id
);
362 req
.id
= &parent
->id
;
363 req
.complete
= pohmelfs_lookup_complete
;
365 req
.group_id
= group_id
;
369 err
= pohmelfs_send_script_request(parent
, &req
);
382 pr_debug("%s: group: %d: parent ino: %lu, name: %s: %d\n",
383 pohmelfs_dump_id(parent
->id
.id
), group_id
,
384 parent
->vfs_inode
.i_ino
, dentry
->d_name
.name
, err
);
388 static struct dentry
*pohmelfs_lookup(struct inode
*dir
, struct dentry
*dentry
, struct nameidata
*nd
)
390 struct pohmelfs_sb
*psb
= pohmelfs_sb(dir
->i_sb
);
391 struct inode
*inode
= NULL
;
392 struct pohmelfs_inode
*pi
;
393 int i
, err
= -ENOENT
;
395 for (i
= 0; i
< psb
->group_num
; ++i
) {
396 pi
= pohmelfs_lookup_group(dir
, dentry
, psb
->groups
[i
]);
402 inode
= &pi
->vfs_inode
;
407 return d_splice_alias(inode
, dentry
);
410 static int pohmelfs_mkdir(struct inode
*dir
, struct dentry
*dentry
, umode_t mode
)
412 struct pohmelfs_sb
*psb
= pohmelfs_sb(dir
->i_sb
);
413 struct pohmelfs_inode
*pi
;
416 inode_inc_link_count(dir
);
418 pi
= pohmelfs_new_inode(psb
, mode
| S_IFDIR
);
423 pohmelfs_init_local(pi
, dir
);
424 mark_inode_dirty(dir
);
426 d_instantiate(dentry
, &pi
->vfs_inode
);
427 if (psb
->http_compat
)
428 pohmelfs_http_compat_id(pi
);
430 err
= pohmelfs_send_dentry(pi
, &pohmelfs_inode(dir
)->id
, dentry
->d_name
.name
, dentry
->d_name
.len
, 1);
434 pr_debug("%s: ino: %lu, parent dir: %lu, object: %s, refcnt: %d\n",
435 pohmelfs_dump_id(pi
->id
.id
), pi
->vfs_inode
.i_ino
,
436 dir
->i_ino
, dentry
->d_name
.name
, dentry
->d_count
);
440 inode_dec_link_count(dir
);
444 static int pohmelfs_unlink(struct inode
*dir
, struct dentry
*dentry
)
446 struct pohmelfs_inode
*parent
= pohmelfs_inode(dir
);
447 struct inode
*inode
= dentry
->d_inode
;
448 struct pohmelfs_inode
*pi
= pohmelfs_inode(inode
);
449 struct pohmelfs_script_req req
;
452 inode
->i_ctime
= dir
->i_ctime
;
453 mark_inode_dirty(dir
);
455 memset(&req
, 0, sizeof(struct pohmelfs_script_req
));
457 req
.script_name
= POHMELFS_UNLINK_SCRIPT
;
458 req
.script_namelen
= sizeof(POHMELFS_UNLINK_SCRIPT
) - 1; /* not including 0-byte */
460 req
.obj_name
= (char *)dentry
->d_name
.name
;
461 req
.obj_len
= dentry
->d_name
.len
;
463 req
.binary
= &parent
->id
;
464 req
.binary_size
= sizeof(struct dnet_raw_id
);
467 req
.id
= &parent
->id
;
468 req
.complete
= pohmelfs_send_dentry_complete
;
472 err
= pohmelfs_send_script_request(parent
, &req
);
476 req
.script_name
= POHMELFS_DATA_UNLINK_SCRIPT
;
477 req
.script_namelen
= sizeof(POHMELFS_DATA_UNLINK_SCRIPT
) - 1; /* not including 0-byte */
479 req
.binary
= &pi
->id
;
480 req
.binary_size
= sizeof(struct dnet_raw_id
);
482 return pohmelfs_send_script_request(parent
, &req
);
485 static int pohmelfs_rmdir(struct inode
*dir
, struct dentry
*dentry
)
487 return pohmelfs_unlink(dir
, dentry
);
490 struct pohmelfs_rename_req
{
491 struct dnet_raw_id old_dir_id
;
493 struct pohmelfs_dentry dentry
;
494 } __attribute__ ((packed
));
496 static int pohmelfs_rename(struct inode
*old_dir
, struct dentry
*old_dentry
,
497 struct inode
*new_dir
, struct dentry
*new_dentry
)
499 struct pohmelfs_inode
*old_parent
= pohmelfs_inode(old_dir
);
500 struct inode
*inode
= old_dentry
->d_inode
;
501 struct inode
*new_inode
= new_dentry
->d_inode
;
502 struct pohmelfs_inode
*pi
= pohmelfs_inode(inode
);
503 struct pohmelfs_script_req req
;
504 struct pohmelfs_rename_req
*r
;
505 int size
= sizeof(struct pohmelfs_rename_req
) + new_dentry
->d_name
.len
;
508 pr_debug("%s: rename: %.*s -> %.*s: mtime: %ld\n",
509 pohmelfs_dump_id(pi
->id
.id
),
510 old_dentry
->d_name
.len
, old_dentry
->d_name
.name
,
511 new_dentry
->d_name
.len
, new_dentry
->d_name
.name
,
512 inode
->i_mtime
.tv_sec
);
514 if (pohmelfs_sb(inode
->i_sb
)->http_compat
) {
519 r
= kzalloc(size
, GFP_NOIO
);
525 r
->old_dir_id
= pohmelfs_inode(old_dir
)->id
;
526 r
->dentry
.parent_id
= pohmelfs_inode(new_dir
)->id
;
527 r
->dentry
.disk
.id
= pohmelfs_inode(inode
)->id
;
528 r
->dentry
.disk
.ino
= cpu_to_le64(inode
->i_ino
);
529 r
->dentry
.disk
.type
= (inode
->i_mode
>> 12) & 15;
530 r
->dentry
.disk
.len
= new_dentry
->d_name
.len
;
532 memcpy(r
->dentry
.disk
.name
, new_dentry
->d_name
.name
, new_dentry
->d_name
.len
);
534 memset(&req
, 0, sizeof(struct pohmelfs_script_req
));
536 req
.script_name
= POHMELFS_RENAME_SCRIPT
;
537 req
.script_namelen
= sizeof(POHMELFS_RENAME_SCRIPT
) - 1; /* not including 0-byte */
539 req
.obj_name
= (char *)old_dentry
->d_name
.name
;
540 req
.obj_len
= old_dentry
->d_name
.len
;
543 req
.binary_size
= size
;
547 req
.id
= &old_parent
->id
;
548 req
.complete
= pohmelfs_send_dentry_complete
;
551 new_inode
->i_ctime
= CURRENT_TIME_SEC
;
553 inode
->i_ctime
= CURRENT_TIME_SEC
;
554 mark_inode_dirty(inode
);
555 mark_inode_dirty(new_dir
);
557 err
= pohmelfs_send_script_request(old_parent
, &req
);
567 static int pohmelfs_symlink(struct inode
*dir
, struct dentry
*dentry
, const char *symname
)
569 struct pohmelfs_sb
*psb
= pohmelfs_sb(dir
->i_sb
);
570 struct pohmelfs_inode
*parent
= pohmelfs_inode(dir
);
571 struct pohmelfs_inode
*pi
;
573 unsigned len
= strlen(symname
)+1;
576 inode_inc_link_count(dir
);
577 pi
= pohmelfs_new_inode(psb
, S_IFLNK
| S_IRWXUGO
);
582 inode
= &pi
->vfs_inode
;
583 pohmelfs_init_local(pi
, dir
);
584 mark_inode_dirty(dir
);
586 err
= page_symlink(inode
, symname
, len
);
590 d_instantiate(dentry
, inode
);
591 if (psb
->http_compat
)
592 pohmelfs_http_compat_id(pi
);
594 err
= pohmelfs_send_dentry(pi
, &parent
->id
, dentry
->d_name
.name
, dentry
->d_name
.len
, 1);
603 inode_dec_link_count(dir
);
607 static int pohmelfs_link(struct dentry
*old_dentry
, struct inode
*dir
, struct dentry
*dentry
)
609 struct inode
*inode
= old_dentry
->d_inode
;
610 struct pohmelfs_inode
*parent
= pohmelfs_inode(dir
);
611 struct pohmelfs_inode
*pi
= pohmelfs_inode(inode
);
612 struct pohmelfs_script_req req
;
615 if (pohmelfs_sb(inode
->i_sb
)->http_compat
) {
620 dquot_initialize(dir
);
622 inode
->i_ctime
= CURRENT_TIME_SEC
;
623 inode_inc_link_count(inode
);
626 err
= pohmelfs_send_dentry(pi
, &parent
->id
, dentry
->d_name
.name
, dentry
->d_name
.len
, 1);
631 memset(&req
, 0, sizeof(struct pohmelfs_script_req
));
633 req
.script_name
= POHMELFS_HARDLINK_SCRIPT
;
634 req
.script_namelen
= sizeof(POHMELFS_HARDLINK_SCRIPT
) - 1; /* not including 0-byte */
636 req
.obj_name
= (char *)dentry
->d_name
.name
;
637 req
.obj_len
= dentry
->d_name
.len
;
639 req
.binary
= &pi
->id
;
640 req
.binary_size
= sizeof(struct dnet_raw_id
);
644 req
.complete
= pohmelfs_send_dentry_complete
;
648 err
= pohmelfs_send_script_request(parent
, &req
);
652 mark_inode_dirty(dir
);
653 mark_inode_dirty(inode
);
654 d_instantiate(dentry
, inode
);
658 req
.binary
= &parent
->id
;
659 req
.script_name
= POHMELFS_UNLINK_SCRIPT
;
660 req
.script_namelen
= sizeof(POHMELFS_UNLINK_SCRIPT
) - 1; /* not including 0-byte */
661 pohmelfs_send_script_request(parent
, &req
);
663 inode_dec_link_count(inode
);
669 static int pohmelfs_mknod(struct inode
*dir
, struct dentry
*dentry
, umode_t mode
, dev_t rdev
)
671 struct pohmelfs_sb
*psb
= pohmelfs_sb(dir
->i_sb
);
672 struct pohmelfs_inode
*pi
;
676 if (!new_valid_dev(rdev
))
679 inode_inc_link_count(dir
);
680 dquot_initialize(dir
);
682 pi
= pohmelfs_new_inode(psb
, mode
);
687 inode
= &pi
->vfs_inode
;
688 pohmelfs_init_local(pi
, dir
);
689 mark_inode_dirty(dir
);
691 init_special_inode(inode
, inode
->i_mode
, rdev
);
692 inode
->i_op
= &pohmelfs_special_inode_operations
;
694 d_instantiate(dentry
, inode
);
695 if (psb
->http_compat
)
696 pohmelfs_http_compat_id(pi
);
698 err
= pohmelfs_send_dentry(pi
, &pohmelfs_inode(dir
)->id
, dentry
->d_name
.name
, dentry
->d_name
.len
, 1);
705 inode_dec_link_count(dir
);
709 const struct inode_operations pohmelfs_dir_inode_operations
= {
710 .create
= pohmelfs_create
,
711 .lookup
= pohmelfs_lookup
,
712 .mkdir
= pohmelfs_mkdir
,
713 .unlink
= pohmelfs_unlink
,
714 .rmdir
= pohmelfs_rmdir
,
715 .rename
= pohmelfs_rename
,
716 .symlink
= pohmelfs_symlink
,
717 .link
= pohmelfs_link
,
718 .mknod
= pohmelfs_mknod
,
721 static int pohmelfs_readdir_complete(struct pohmelfs_trans
*t
, struct pohmelfs_state
*recv
)
723 struct pohmelfs_inode
*pi
= pohmelfs_inode(t
->inode
);
724 struct pohmelfs_wait
*wait
= t
->priv
;
725 struct dnet_cmd
*cmd
= &recv
->cmd
;
727 pr_debug("%s: cmd size: %llu, flags: %x\n",
728 pohmelfs_dump_id(pi
->id
.id
), (unsigned long long)cmd
->size
,
731 if (cmd
->flags
& DNET_FLAGS_MORE
) {
732 if (cmd
->size
> sizeof(struct dnet_attr
)) {
733 wait
->ret
= t
->recv_data
;
734 wait
->condition
= cmd
->size
;
740 if (!wait
->condition
) {
741 wait
->condition
= cmd
->status
;
742 if (!wait
->condition
)
750 static int pohmelfs_dentry_add(struct dentry
*parent_dentry
, struct pohmelfs_inode
*pi
, char *name
, int len
)
752 struct inode
*inode
= &pi
->vfs_inode
;
753 struct dentry
*dentry
, *old
;
759 str
.hash
= full_name_hash(str
.name
, str
.len
);
761 dentry
= d_lookup(parent_dentry
, &str
);
769 * if things are ok, dentry has 2 references -
770 * one in parent dir, and another its own,
771 * which we should drop
773 dentry
= d_alloc(parent_dentry
, &str
);
779 old
= d_splice_alias(inode
, dentry
);
791 static int pohmelfs_update_inode(struct dentry
*parent_dentry
, struct pohmelfs_inode_info
*info
, char *name
)
793 struct pohmelfs_sb
*psb
= pohmelfs_sb(parent_dentry
->d_inode
->i_sb
);
794 struct pohmelfs_inode
*pi
;
798 pi
= pohmelfs_sb_inode_lookup(psb
, &info
->id
);
800 inode
= &pi
->vfs_inode
;
801 pohmelfs_fill_inode(inode
, info
);
803 pi
= pohmelfs_existing_inode(psb
, info
);
808 inode
= &pi
->vfs_inode
;
811 mutex_lock(&inode
->i_mutex
);
812 err
= pohmelfs_dentry_add(parent_dentry
, pi
, name
, info
->namelen
);
813 mutex_unlock(&inode
->i_mutex
);
821 struct pohmelfs_fetch_info
{
822 struct dentry
*parent
;
828 static void pohmelfs_fetch_inode_info_free(struct kref
*kref
)
830 struct pohmelfs_fetch_info
*fi
= container_of(kref
, struct pohmelfs_fetch_info
, refcnt
);
836 static void pohmelfs_fetch_inode_info_destroy(struct pohmelfs_trans
*t
)
838 struct pohmelfs_fetch_info
*fi
= t
->priv
;
840 kref_put(&fi
->refcnt
, pohmelfs_fetch_inode_info_free
);
843 static int pohmelfs_fetch_inode_info_init(struct pohmelfs_trans
*t
)
845 struct pohmelfs_fetch_info
*fi
= t
->priv
;
847 kref_get(&fi
->refcnt
);
851 static int pohmelfs_fetch_inode_info_complete(struct pohmelfs_trans
*t
, struct pohmelfs_state
*recv
)
853 struct pohmelfs_fetch_info
*fi
= t
->priv
;
854 struct dnet_cmd
*cmd
= &recv
->cmd
;
855 struct pohmelfs_inode_info
*info
;
861 if (cmd
->size
< sizeof(struct dnet_attr
) + sizeof(struct dnet_io_attr
) + sizeof(struct pohmelfs_inode_info
))
864 info
= t
->recv_data
+ sizeof(struct dnet_attr
) + sizeof(struct dnet_io_attr
);
865 pohmelfs_convert_inode_info(info
);
867 info
->namelen
= fi
->len
;
868 err
= pohmelfs_update_inode(fi
->parent
, info
, fi
->name
);
870 pr_debug("%s: fetched: '%.*s': %d\n",
871 pohmelfs_dump_id(cmd
->id
.id
), fi
->len
, fi
->name
, err
);
875 static int pohmelfs_fetch_inode_info_group(struct dentry
*parent
, struct pohmelfs_inode
*pi
,
876 struct pohmelfs_dentry_disk
*d
, int *groups
, int group_num
)
878 struct pohmelfs_sb
*psb
= pohmelfs_sb(pi
->vfs_inode
.i_sb
);
879 struct pohmelfs_io
*pio
;
880 struct pohmelfs_fetch_info
*fi
;
883 pio
= kmem_cache_zalloc(pohmelfs_io_cache
, GFP_NOIO
);
889 fi
= kmalloc(sizeof(struct pohmelfs_fetch_info
) + d
->len
, GFP_NOIO
);
895 memcpy(fi
->name
, d
->name
, d
->len
);
897 kref_init(&fi
->refcnt
);
898 fi
->parent
= dget(parent
);
902 pio
->cmd
= DNET_CMD_READ
;
903 pio
->cflags
= DNET_FLAGS_NEED_ACK
| DNET_FLAGS_NOLOCK
;
904 if (psb
->no_read_csum
)
905 pio
->ioflags
= DNET_IO_FLAGS_NOCSUM
;
906 pio
->type
= POHMELFS_INODE_COLUMN
;
907 pio
->cb
.complete
= pohmelfs_fetch_inode_info_complete
;
908 pio
->cb
.init
= pohmelfs_fetch_inode_info_init
;
909 pio
->cb
.destroy
= pohmelfs_fetch_inode_info_destroy
;
913 for (i
= 0; i
< group_num
; ++i
) {
914 pio
->group_id
= groups
[i
];
915 err
= pohmelfs_send_io_group(pio
, groups
[i
]);
920 kref_put(&fi
->refcnt
, pohmelfs_fetch_inode_info_free
);
922 kmem_cache_free(pohmelfs_io_cache
, pio
);
927 static int pohmelfs_fetch_inode_info(struct dentry
*parent
, struct pohmelfs_inode
*pi
, struct pohmelfs_dentry_disk
*d
)
929 struct pohmelfs_sb
*psb
= pohmelfs_sb(pi
->vfs_inode
.i_sb
);
931 return pohmelfs_fetch_inode_info_group(parent
, pi
, d
, pi
->groups
, pi
->group_num
);
933 return pohmelfs_fetch_inode_info_group(parent
, pi
, d
, psb
->groups
, psb
->group_num
);
936 static int pohmelfs_readdir_process(void *data
, int size
, struct file
*filp
, void *dirent
, filldir_t filldir
)
938 struct dentry
*dentry
= filp
->f_path
.dentry
, *child
;
939 struct inode
*dir
= dentry
->d_inode
;
940 void *orig_data
= data
;
941 int orig_size
= size
;
946 struct pohmelfs_dentry_disk
*d
= data
;
948 if (size
< sizeof(struct pohmelfs_dentry_disk
)) {
960 str
.hash
= full_name_hash(str
.name
, str
.len
);
962 child
= d_lookup(dentry
, &str
);
963 pr_debug("%s: child: %.*s/%.*s: %p\n",
964 pohmelfs_dump_id(d
->id
.id
),
965 dentry
->d_name
.len
, dentry
->d_name
.name
,
969 pohmelfs_fetch_inode_info(dentry
, pohmelfs_inode(dir
), d
);
974 size
-= sizeof(struct pohmelfs_dentry_disk
) + d
->len
;
975 data
+= sizeof(struct pohmelfs_dentry_disk
) + d
->len
;
981 struct pohmelfs_dentry_disk
*d
= data
;
983 err
= filldir(dirent
, d
->name
, d
->len
, filp
->f_pos
, le64_to_cpu(d
->ino
), d
->type
);
988 size
-= sizeof(struct pohmelfs_dentry_disk
) + d
->len
;
989 data
+= sizeof(struct pohmelfs_dentry_disk
) + d
->len
;
996 struct pohmelfs_readdir
{
997 struct dnet_raw_id id
;
1002 static void *pohmelfs_readdir_group(int group_id
, struct file
*filp
, int *sizep
)
1004 struct dentry
*dentry
= filp
->f_path
.dentry
;
1005 struct inode
*dir
= dentry
->d_inode
;
1006 struct pohmelfs_sb
*psb
= pohmelfs_sb(dir
->i_sb
);
1007 struct pohmelfs_inode
*parent
= pohmelfs_inode(dir
);
1008 struct pohmelfs_readdir rd
;
1009 struct pohmelfs_script_req req
;
1014 memset(&req
, 0, sizeof(struct pohmelfs_script_req
));
1016 req
.script_name
= POHMELFS_READDIR_SCRIPT
;
1017 req
.script_namelen
= sizeof(POHMELFS_READDIR_SCRIPT
) - 1; /* not including 0-byte */
1019 req
.obj_name
= (char *)dentry
->d_name
.name
;
1020 req
.obj_len
= dentry
->d_name
.len
;
1023 rd
.max_size
= psb
->readdir_allocation
* PAGE_SIZE
- sizeof(struct dnet_attr
); /* cmd->size should fit one page */
1024 rd
.fpos
= filp
->f_pos
- 2; /* account for . and .. */
1027 req
.binary_size
= sizeof(struct pohmelfs_readdir
);
1029 req
.id
= &parent
->id
;
1030 req
.complete
= pohmelfs_readdir_complete
;
1033 req
.group_id
= group_id
;
1036 err
= pohmelfs_send_script_request(parent
, &req
);
1041 size
= req
.ret_cond
;
1042 if (!data
|| !size
) {
1051 return ERR_PTR(err
);
1054 static int pohmelfs_dir_open(struct inode
*dir
, struct file
*filp
)
1057 struct pohmelfs_inode
*pi
= pohmelfs_inode(dir
);
1059 if (!pohmelfs_need_resync(pi
))
1060 return dcache_dir_open(dir
, filp
);
1066 static int pohmelfs_dir_close(struct inode
*inode
, struct file
*filp
)
1068 if (filp
->private_data
)
1069 return dcache_dir_close(inode
, filp
);
1073 static int pohmelfs_readdir(struct file
*filp
, void *dirent
, filldir_t filldir
)
1075 struct dentry
*dentry
= filp
->f_path
.dentry
;
1076 struct inode
*dir
= dentry
->d_inode
;
1077 struct pohmelfs_inode
*pi
= pohmelfs_inode(dir
);
1078 struct pohmelfs_sb
*psb
= pohmelfs_sb(dir
->i_sb
);
1079 int i
, err
= -ENOENT
;
1081 if (filp
->private_data
) {
1082 return dcache_readdir(filp
, dirent
, filldir
);
1085 if (filp
->f_pos
== 0) {
1086 err
= filldir(dirent
, ".", 1, filp
->f_pos
, dir
->i_ino
, DT_DIR
);
1092 if (filp
->f_pos
== 1) {
1093 err
= filldir(dirent
, "..", 2, filp
->f_pos
, parent_ino(dentry
), DT_DIR
);
1099 for (i
= 0; i
< psb
->group_num
; ++i
) {
1103 data
= pohmelfs_readdir_group(psb
->groups
[i
], filp
, &size
);
1105 err
= PTR_ERR(data
);
1109 pi
->update
= get_seconds();
1110 err
= pohmelfs_readdir_process(data
+ sizeof(struct dnet_attr
), size
- sizeof(struct dnet_attr
), filp
, dirent
, filldir
);
1119 const struct file_operations pohmelfs_dir_fops
= {
1120 .open
= pohmelfs_dir_open
,
1121 .release
= pohmelfs_dir_close
,
1122 .read
= generic_read_dir
,
1123 .readdir
= pohmelfs_readdir
,