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_inode_info_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_inode_info_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
;
58 static int pohmelfs_send_inode_info_init(struct pohmelfs_trans
*t
)
60 struct pohmelfs_wait
*wait
= t
->priv
;
62 pohmelfs_wait_get(wait
);
66 static void pohmelfs_send_inode_info_destroy(struct pohmelfs_trans
*t
)
68 struct pohmelfs_wait
*wait
= t
->priv
;
71 pohmelfs_wait_put(wait
);
74 static int pohmelfs_lookup_complete(struct pohmelfs_trans
*t
, struct pohmelfs_state
*recv
)
76 struct pohmelfs_inode
*parent
= pohmelfs_inode(t
->inode
);
77 struct pohmelfs_wait
*wait
= t
->priv
;
78 struct dnet_cmd
*cmd
= &recv
->cmd
;
79 unsigned long long trans
= cmd
->trans
& ~DNET_TRANS_REPLY
;
80 int err
= cmd
->status
;
85 if (cmd
->flags
& DNET_FLAGS_MORE
) {
86 struct pohmelfs_inode_info
*info
;
87 struct pohmelfs_inode
*pi
;
89 if (cmd
->size
!= sizeof(struct dnet_attr
) + sizeof(struct pohmelfs_inode_info
)) {
94 pr_debug("pohmelfs: %s: pohmelfs_lookup_complete: %llu, size: %llu, min size: %zu, flags: %x, status: %d\n",
95 pohmelfs_dump_id(parent
->id
.id
), trans
, cmd
->size
,
96 sizeof(struct dnet_attr
) + sizeof(struct pohmelfs_inode_info
), cmd
->flags
, cmd
->status
);
99 info
= t
->recv_data
+ sizeof(struct dnet_attr
);
100 pohmelfs_convert_inode_info(info
);
102 pi
= pohmelfs_existing_inode(pohmelfs_sb(t
->inode
->i_sb
), info
);
108 pi
->parent_id
= parent
->id
;
114 wait
->condition
= err
;
121 int pohmelfs_send_script_request(struct pohmelfs_inode
*parent
, struct pohmelfs_script_req
*req
)
123 struct pohmelfs_sb
*psb
= pohmelfs_sb(parent
->vfs_inode
.i_sb
);
124 struct pohmelfs_wait
*wait
;
125 struct pohmelfs_io
*pio
;
131 /* 2 commas, \n and 0-byte, which is accounted in sizeof(string) */
132 script_len
= sizeof(POHMELFS_DENTRY_NAME_SCRIPT
) + req
->obj_len
+ 3;
134 wait
= pohmelfs_wait_alloc(parent
);
140 pio
= kmem_cache_zalloc(pohmelfs_io_cache
, GFP_NOIO
);
143 goto err_out_wait_put
;
146 e
= kmalloc(sizeof(struct dnet_exec
) + req
->script_namelen
+ script_len
+ req
->binary_size
, GFP_NOIO
);
149 goto err_out_free_pio
;
152 memset(e
, 0, sizeof(struct dnet_exec
));
154 snprintf(e
->data
, req
->script_namelen
+ script_len
, "%s%s'%s'\n", req
->script_name
, POHMELFS_DENTRY_NAME_SCRIPT
, req
->obj_name
);
155 script_len
--; /* do not include last 0-byte in the script */
157 memcpy(e
->data
+ req
->script_namelen
+ script_len
, req
->binary
, req
->binary_size
);
159 e
->type
= DNET_EXEC_PYTHON_SCRIPT_NAME
;
160 e
->name_size
= req
->script_namelen
;
161 e
->script_size
= script_len
;
162 e
->binary_size
= req
->binary_size
;
163 dnet_convert_exec(e
);
167 pio
->group_id
= req
->group_id
;
168 pio
->cflags
= DNET_FLAGS_NEED_ACK
;
169 if (req
->complete
== pohmelfs_lookup_complete
)
170 pio
->cflags
|= DNET_FLAGS_NOLOCK
;
172 pio
->cmd
= DNET_CMD_EXEC
;
173 pio
->size
= sizeof(struct dnet_exec
) + req
->script_namelen
+ script_len
+ req
->binary_size
;
176 pio
->cb
.init
= pohmelfs_send_inode_info_init
;
177 pio
->cb
.destroy
= pohmelfs_send_inode_info_destroy
;
178 pio
->cb
.complete
= req
->complete
;
181 err
= pohmelfs_send_buf_single(pio
, NULL
);
183 err
= pohmelfs_send_buf(pio
);
189 ret
= wait_event_interruptible_timeout(wait
->wq
, wait
->condition
!= 0, msecs_to_jiffies(psb
->read_wait_timeout
));
197 if (wait
->condition
< 0)
198 err
= wait
->condition
;
200 req
->ret
= wait
->ret
;
201 req
->ret_cond
= wait
->condition
;
206 char parent_id_str
[len
*2+1];
208 pr_debug("pohmelfs: %.*s: %s: inode->id: %s, ino: %lu, object: %s, binary size: %d, ret: %p, condition: %d\n",
209 req
->script_namelen
, req
->script_name
,
210 pohmelfs_dump_id(req
->id
->id
),
211 pohmelfs_dump_id_len_raw(parent
->id
.id
, len
, parent_id_str
),
212 parent
->vfs_inode
.i_ino
, req
->obj_name
, req
->binary_size
,
213 req
->ret
, req
->ret_cond
);
219 kmem_cache_free(pohmelfs_io_cache
, pio
);
221 pohmelfs_wait_put(wait
);
226 int pohmelfs_send_inode_info(struct pohmelfs_inode
*pi
, struct dnet_raw_id
*id
, const char *sname
, int len
, int sync
)
228 struct pohmelfs_inode_info_binary_package
*bin
;
229 struct pohmelfs_script_req req
;
237 bin
= kmem_cache_alloc(pohmelfs_inode_info_binary_package_cache
, GFP_NOIO
);
243 req
.script_name
= POHMELFS_INODE_INFO_SCRIPT_INSERT
;
244 req
.script_namelen
= sizeof(POHMELFS_INODE_INFO_SCRIPT_INSERT
) - 1; /* not including 0-byte */
246 req
.obj_name
= (char *)sname
;
250 req
.binary_size
= sizeof(struct pohmelfs_inode_info
) + sizeof(struct dnet_raw_id
);
257 memcpy(&bin
->parent
, id
, sizeof(struct dnet_raw_id
));
258 pohmelfs_fill_inode_info(&pi
->vfs_inode
, &bin
->info
);
259 bin
->info
.namelen
= len
;
261 pohmelfs_convert_inode_info(&bin
->info
);
263 req
.complete
= pohmelfs_send_inode_info_complete
;
265 err
= pohmelfs_send_script_request(pi
, &req
);
270 kmem_cache_free(pohmelfs_inode_info_binary_package_cache
, bin
);
275 static int pohmelfs_create(struct inode
*dir
, struct dentry
*dentry
, int mode
,
276 struct nameidata
*nd
)
278 struct pohmelfs_sb
*psb
= pohmelfs_sb(dir
->i_sb
);
279 struct pohmelfs_inode
*parent
= pohmelfs_inode(dir
);
280 struct pohmelfs_inode
*pi
;
283 pi
= pohmelfs_new_inode(psb
, mode
);
289 inode_inc_link_count(dir
);
290 pohmelfs_inode_dirty(parent
, pi
);
292 err
= pohmelfs_send_inode_info(pi
, &pi
->parent_id
, dentry
->d_name
.name
, dentry
->d_name
.len
, 0);
296 pr_debug("pohmelfs: create: %s, ino: %lu, parent dir: %lu, object: %s\n",
297 pohmelfs_dump_id(pi
->id
.id
), pi
->vfs_inode
.i_ino
,
298 dir
->i_ino
, dentry
->d_name
.name
);
301 * calling d_instantiate() implies that
302 * ->lookup() used d_splice_alias() with NULL inode
303 * when it failed to find requested object
305 d_instantiate(dentry
, &pi
->vfs_inode
);
310 inode_dec_link_count(dir
);
311 iput(&pi
->vfs_inode
);
316 static struct pohmelfs_inode
*pohmelfs_lookup_group(struct inode
*dir
, struct dentry
*dentry
, int group_id
)
318 struct pohmelfs_inode
*parent
= pohmelfs_inode(dir
);
319 struct pohmelfs_script_req req
;
320 struct pohmelfs_inode
*pi
;
323 req
.script_name
= POHMELFS_LOOKUP_SCRIPT
;
324 req
.script_namelen
= sizeof(POHMELFS_LOOKUP_SCRIPT
) - 1; /* not including 0-byte */
326 req
.obj_name
= (char *)dentry
->d_name
.name
;
327 req
.obj_len
= dentry
->d_name
.len
;
329 req
.binary
= &parent
->id
;
330 req
.binary_size
= sizeof(struct dnet_raw_id
);
332 req
.id
= &parent
->id
;
333 req
.complete
= pohmelfs_lookup_complete
;
335 req
.group_id
= group_id
;
338 err
= pohmelfs_send_script_request(parent
, &req
);
351 pr_debug("pohmelfs: pohmelfs_lookup_group: %s: group: %d: parent ino: %lu, name: %s: %d\n",
352 pohmelfs_dump_id(parent
->id
.id
), group_id
, parent
->vfs_inode
.i_ino
, dentry
->d_name
.name
, err
);
356 static struct dentry
*pohmelfs_lookup(struct inode
*dir
, struct dentry
*dentry
, struct nameidata
*nd
)
358 struct pohmelfs_sb
*psb
= pohmelfs_sb(dir
->i_sb
);
359 struct inode
*inode
= NULL
;
360 struct pohmelfs_inode
*pi
;
361 int i
, err
= -ENOENT
;
363 for (i
= 0; i
< psb
->group_num
; ++i
) {
364 pi
= pohmelfs_lookup_group(dir
, dentry
, psb
->groups
[i
]);
370 inode
= &pi
->vfs_inode
;
375 if (err
&& (err
!= -ENOENT
) && (err
!= -EOPNOTSUPP
))
378 return d_splice_alias(inode
, dentry
);
381 static int pohmelfs_mkdir(struct inode
*dir
, struct dentry
*dentry
, int mode
)
383 struct pohmelfs_sb
*psb
= pohmelfs_sb(dir
->i_sb
);
384 struct pohmelfs_inode
*parent
= pohmelfs_inode(dir
);
385 struct pohmelfs_inode
*pi
;
388 inode_inc_link_count(dir
);
390 pi
= pohmelfs_new_inode(psb
, mode
| S_IFDIR
);
396 pohmelfs_inode_dirty(parent
, pi
);
398 d_instantiate(dentry
, &pi
->vfs_inode
);
399 pr_debug("pohmelfs: mkdir: %s, ino: %lu, parent dir: %lu, object: %s, refcnt: %d\n",
400 pohmelfs_dump_id(pi
->id
.id
), pi
->vfs_inode
.i_ino
,
401 dir
->i_ino
, dentry
->d_name
.name
, dentry
->d_count
);
406 inode_dec_link_count(dir
);
410 static int pohmelfs_unlink(struct inode
*dir
, struct dentry
*dentry
)
412 struct pohmelfs_inode
*parent
= pohmelfs_inode(dir
);
413 struct pohmelfs_inode
*pi
= pohmelfs_inode(dentry
->d_inode
);
414 struct pohmelfs_script_req req
;
417 req
.script_name
= POHMELFS_UNLINK_SCRIPT
;
418 req
.script_namelen
= sizeof(POHMELFS_UNLINK_SCRIPT
) - 1; /* not including 0-byte */
420 req
.obj_name
= (char *)dentry
->d_name
.name
;
421 req
.obj_len
= dentry
->d_name
.len
;
423 req
.binary
= &parent
->id
;
424 req
.binary_size
= sizeof(struct dnet_raw_id
);
427 req
.id
= &parent
->id
;
428 req
.complete
= pohmelfs_send_inode_info_complete
;
432 err
= pohmelfs_send_script_request(parent
, &req
);
436 req
.script_name
= POHMELFS_DATA_UNLINK_SCRIPT
;
437 req
.script_namelen
= sizeof(POHMELFS_DATA_UNLINK_SCRIPT
) - 1; /* not including 0-byte */
439 req
.binary
= &pi
->id
;
440 req
.binary_size
= sizeof(struct dnet_raw_id
);
442 return pohmelfs_send_script_request(parent
, &req
);
445 static int pohmelfs_rmdir(struct inode
*dir
, struct dentry
*dentry
)
447 return pohmelfs_unlink(dir
, dentry
);
450 struct pohmelfs_rename_req
{
451 struct dnet_raw_id old_dir_id
;
452 struct dnet_raw_id new_dir_id
;
455 } __attribute__ ((packed
));
457 static int pohmelfs_rename(struct inode
*old_dir
, struct dentry
*old_dentry
,
458 struct inode
*new_dir
, struct dentry
*new_dentry
)
460 struct pohmelfs_inode
*old_parent
= pohmelfs_inode(old_dir
);
461 struct pohmelfs_script_req req
;
462 struct pohmelfs_rename_req
*r
;
463 int size
= sizeof(struct pohmelfs_rename_req
) + new_dentry
->d_name
.len
;
466 r
= kmalloc(size
, GFP_NOIO
);
472 r
->old_dir_id
= pohmelfs_inode(old_dir
)->id
;
473 r
->new_dir_id
= pohmelfs_inode(new_dir
)->id
;
474 r
->new_len
= cpu_to_le32(new_dentry
->d_name
.len
);
475 memcpy(r
->new_name
, new_dentry
->d_name
.name
, new_dentry
->d_name
.len
);
477 req
.script_name
= POHMELFS_RENAME_SCRIPT
;
478 req
.script_namelen
= sizeof(POHMELFS_RENAME_SCRIPT
) - 1; /* not including 0-byte */
480 req
.obj_name
= (char *)old_dentry
->d_name
.name
;
481 req
.obj_len
= old_dentry
->d_name
.len
;
484 req
.binary_size
= size
;
488 req
.id
= &old_parent
->id
;
489 req
.complete
= pohmelfs_send_inode_info_complete
;
491 err
= pohmelfs_send_script_request(old_parent
, &req
);
501 static int pohmelfs_symlink(struct inode
*dir
, struct dentry
*dentry
, const char *symname
)
503 struct pohmelfs_sb
*psb
= pohmelfs_sb(dir
->i_sb
);
504 struct pohmelfs_inode
*pi
;
506 unsigned len
= strlen(symname
)+1;
509 pi
= pohmelfs_new_inode(psb
, S_IFLNK
| S_IRWXUGO
);
515 pohmelfs_inode_dirty(pohmelfs_inode(dir
), pi
);
516 inode
= &pi
->vfs_inode
;
518 err
= page_symlink(inode
, symname
, len
);
522 d_instantiate(dentry
, inode
);
532 static int pohmelfs_link(struct dentry
*old_dentry
, struct inode
*dir
, struct dentry
*dentry
)
534 struct inode
*inode
= old_dentry
->d_inode
;
535 struct pohmelfs_inode
*parent
= pohmelfs_inode(dir
);
536 struct pohmelfs_inode
*pi
= pohmelfs_inode(inode
);
537 struct pohmelfs_script_req req
;
540 dquot_initialize(dir
);
542 inode
->i_ctime
= CURRENT_TIME_SEC
;
543 inode_inc_link_count(inode
);
546 pohmelfs_inode_dirty(parent
, pi
);
548 err
= pohmelfs_send_inode_info(pi
, &pi
->parent_id
, dentry
->d_name
.name
, dentry
->d_name
.len
, 1);
553 req
.script_name
= POHMELFS_HARDLINK_SCRIPT
;
554 req
.script_namelen
= sizeof(POHMELFS_HARDLINK_SCRIPT
) - 1; /* not including 0-byte */
556 req
.obj_name
= (char *)dentry
->d_name
.name
;
557 req
.obj_len
= dentry
->d_name
.len
;
559 req
.binary
= &pi
->id
;
560 req
.binary_size
= sizeof(struct dnet_raw_id
);
564 req
.complete
= pohmelfs_send_inode_info_complete
;
568 err
= pohmelfs_send_script_request(parent
, &req
);
572 d_instantiate(dentry
, inode
);
576 req
.binary
= &parent
->id
;
577 req
.script_name
= POHMELFS_UNLINK_SCRIPT
;
578 req
.script_namelen
= sizeof(POHMELFS_UNLINK_SCRIPT
) - 1; /* not including 0-byte */
579 pohmelfs_send_script_request(parent
, &req
);
582 inode_dec_link_count(inode
);
587 static int pohmelfs_mknod(struct inode
*dir
, struct dentry
*dentry
, int mode
, dev_t rdev
)
589 struct pohmelfs_sb
*psb
= pohmelfs_sb(dir
->i_sb
);
590 struct pohmelfs_inode
*pi
;
594 if (!new_valid_dev(rdev
))
597 dquot_initialize(dir
);
599 pi
= pohmelfs_new_inode(psb
, mode
);
605 inode
= &pi
->vfs_inode
;
607 init_special_inode(inode
, inode
->i_mode
, rdev
);
608 inode
->i_op
= &pohmelfs_special_inode_operations
;
610 pohmelfs_inode_dirty(pohmelfs_inode(dir
), pi
);
612 d_instantiate(dentry
, inode
);
619 const struct inode_operations pohmelfs_dir_inode_operations
= {
620 .create
= pohmelfs_create
,
621 .lookup
= pohmelfs_lookup
,
622 .mkdir
= pohmelfs_mkdir
,
623 .unlink
= pohmelfs_unlink
,
624 .rmdir
= pohmelfs_rmdir
,
625 .rename
= pohmelfs_rename
,
626 .symlink
= pohmelfs_symlink
,
627 .link
= pohmelfs_link
,
628 .mknod
= pohmelfs_mknod
,
631 struct pohmelfs_readdir_header
{
633 unsigned short version
;
634 unsigned short chunk_size
;
635 unsigned int chunk_num
;
636 } __attribute__((packed
));
638 static void pohmelfs_convert_readdir_header(struct pohmelfs_readdir_header
*h
)
640 h
->version
= dnet_bswap16(h
->version
);
641 h
->chunk_size
= dnet_bswap16(h
->chunk_size
);
642 h
->chunk_num
= dnet_bswap32(h
->chunk_num
);
645 struct pohmelfs_readdir_chunk_header
{
646 unsigned short length
;
648 unsigned short key_size
;
649 unsigned short payload_size
;
650 } __attribute__((packed
));
652 static void pohmelfs_convert_readdir_chunk_header(struct pohmelfs_readdir_chunk_header
*h
)
654 h
->length
= dnet_bswap16(h
->length
);
655 h
->num
= dnet_bswap16(h
->num
);
656 h
->key_size
= dnet_bswap16(h
->key_size
);
657 h
->payload_size
= dnet_bswap16(h
->payload_size
);
660 /* Chunk size = maximum file name length + sizeof header + sizeof pohmelfs_inode_info
661 * It allows to store whole file entry on 1 chunk
663 #define POHMELFS_CHUNK_SIZE (NAME_MAX + 1 + sizeof(struct pohmelfs_inode_info) + sizeof(struct pohmelfs_readdir_chunk_header))
665 enum pohmelfs_readdir_warm_states
{
666 POHMELFS_READDIR_WANT_HEADER
= 1,
667 POHMELFS_READDIR_WANT_RECV_CHUNK
,
670 struct pohmelfs_readdir_warm_priv
{
671 struct pohmelfs_wait
*wait
;
675 struct pohmelfs_readdir_header header
;
678 int read_total
; /* number of inode offsets read or processed total (in all chunks summed) */
679 int read_in_inode
; /* offset of name+pohmelfs_inode_info read in below buffer */
681 char chunk
[POHMELFS_CHUNK_SIZE
];
684 static void pohmelfs_readdir_warm_free(struct kref
*kref
)
686 struct pohmelfs_readdir_warm_priv
*priv
= container_of(kref
, struct pohmelfs_readdir_warm_priv
, refcnt
);
689 pohmelfs_wait_put(priv
->wait
);
693 static void pohmelfs_readdir_warm_destroy(struct pohmelfs_trans
*t
)
695 struct pohmelfs_readdir_warm_priv
*priv
= t
->priv
;
696 struct pohmelfs_wait
*wait
= priv
->wait
;
699 kref_put(&priv
->refcnt
, pohmelfs_readdir_warm_free
);
702 static int pohmelfs_readdir_warm_complete(struct pohmelfs_trans
*t
, struct pohmelfs_state
*recv
)
704 struct pohmelfs_inode
*pi
= pohmelfs_inode(t
->inode
);
705 struct pohmelfs_readdir_warm_priv
*priv
= t
->priv
;
706 struct pohmelfs_wait
*wait
= priv
->wait
;
707 struct dnet_cmd
*cmd
= &recv
->cmd
;
714 pr_debug("pohmelfs: %s: comlete cmd size: %llu, recv offset: %llu, flags: %x\n",
715 pohmelfs_dump_id(pi
->id
.id
), (unsigned long long)cmd
->size
, t
->recv_offset
, cmd
->flags
);
717 if (!(cmd
->flags
& DNET_FLAGS_MORE
)) {
718 wait
->condition
= cmd
->status
;
719 if (!wait
->condition
)
726 static int pohmelfs_dentry_add(struct pohmelfs_inode
*parent
, struct pohmelfs_inode
*pi
, char *name
, int len
)
728 struct inode
*inode
= &pi
->vfs_inode
;
729 struct inode
*dir
= &parent
->vfs_inode
;
730 struct dentry
*dentry
, *parent_dentry
, *old
;
736 str
.hash
= full_name_hash(str
.name
, str
.len
);
738 /* we do not need to hold dir->i_mutex here, don't we? :) */
739 parent_dentry
= d_find_alias(dir
);
740 if (!parent_dentry
) {
745 dentry
= d_lookup(parent_dentry
, &str
);
750 goto err_out_put_parent
;
753 * if things are ok, dentry has 2 references -
754 * one in parent dir, and another its own,
755 * which we should drop
757 dentry
= d_alloc(parent_dentry
, &str
);
760 goto err_out_put_parent
;
763 old
= d_splice_alias(inode
, dentry
);
780 static int pohmelfs_update_inode(struct pohmelfs_inode
*parent
, struct pohmelfs_inode_info
*info
, char *name
)
782 struct pohmelfs_sb
*psb
= pohmelfs_sb(parent
->vfs_inode
.i_sb
);
783 struct pohmelfs_inode
*pi
;
787 pi
= pohmelfs_sb_inode_lookup(psb
, &info
->id
);
789 inode
= &pi
->vfs_inode
;
790 pohmelfs_fill_inode(inode
, info
);
793 pi
= pohmelfs_existing_inode(psb
, info
);
798 inode
= &pi
->vfs_inode
;
800 pi
->parent_id
= parent
->id
;
803 err
= pohmelfs_dentry_add(parent
, pi
, name
, info
->namelen
);
811 static int pohmelfs_readdir_warm_scratch(struct pohmelfs_trans
*t
, struct pohmelfs_state
*recv
)
813 struct pohmelfs_inode
*pi
= pohmelfs_inode(t
->inode
);
814 struct pohmelfs_readdir_warm_priv
*priv
= t
->priv
;
815 struct dnet_cmd
*cmd
= &recv
->cmd
;
818 pr_debug("pohmelfs: %s: cmd size: %llu, recv offset: %llu\n",
819 pohmelfs_dump_id(pi
->id
.id
), (unsigned long long)cmd
->size
, t
->recv_offset
);
820 while (t
->recv_offset
!= cmd
->size
) {
821 long rest
= cmd
->size
- t
->recv_offset
;
823 if (rest
> POHMELFS_CHUNK_SIZE
)
824 rest
= POHMELFS_CHUNK_SIZE
;
826 err
= pohmelfs_recv(t
, recv
, priv
->chunk
, rest
);
832 pr_debug("pohmelfs: %s: done cmd size: %llu, recv offset: %llu\n",
833 pohmelfs_dump_id(pi
->id
.id
), (unsigned long long)cmd
->size
, t
->recv_offset
);
838 static int pohmelfs_readdir_warm_recv_reply(struct pohmelfs_trans
*t
, struct pohmelfs_state
*recv
)
840 struct pohmelfs_inode
*pi
= pohmelfs_inode(t
->inode
);
841 struct pohmelfs_readdir_warm_priv
*priv
= t
->priv
;
842 struct dnet_cmd
*cmd
= &recv
->cmd
;
843 int attr_size
= sizeof(struct dnet_attr
) + sizeof(struct dnet_io_attr
);
844 long old_recv_offset
;
849 pr_debug("pohmelfs: %s: recv reply: cmd size: %llu, recv offset: %llu\n",
850 pohmelfs_dump_id(pi
->id
.id
), (unsigned long long)cmd
->size
, t
->recv_offset
);
852 if (t
->recv_offset
< attr_size
) {
855 data
+= t
->recv_offset
;
856 size
= attr_size
- t
->recv_offset
;
858 err
= pohmelfs_recv(t
, recv
, data
, size
);
862 if (t
->recv_offset
== attr_size
) {
863 dnet_convert_attr(&t
->cmd
.attr
);
864 dnet_convert_io_attr(&t
->cmd
.p
.io
);
866 pr_debug("pohmelfs: %d:%s: cmd size: %llu, io size: %llu\n",
867 cmd
->id
.group_id
, pohmelfs_dump_id(cmd
->id
.id
),
868 (unsigned long long)cmd
->size
, (unsigned long long)t
->cmd
.p
.io
.size
);
870 priv
->state
= POHMELFS_READDIR_WANT_HEADER
;
874 if (priv
->state
== POHMELFS_READDIR_WANT_HEADER
) {
875 int header_size_to_read
= sizeof(struct pohmelfs_readdir_header
) - (t
->recv_offset
- attr_size
);
877 data
= &priv
->header
;
878 data
+= sizeof(struct pohmelfs_readdir_header
) - header_size_to_read
;
880 err
= pohmelfs_recv(t
, recv
, data
, header_size_to_read
);
884 pohmelfs_convert_readdir_header(&priv
->header
);
885 priv
->read_total
= 0;
886 priv
->read_in_inode
= 0;
887 priv
->state
= POHMELFS_READDIR_WANT_RECV_CHUNK
;
889 pr_debug("pohmelfs: %d:%s: header: header size: %d, version: %hd, chunk_size: %hd, chunk_num: %d\n",
890 cmd
->id
.group_id
, pohmelfs_dump_id(cmd
->id
.id
), header_size_to_read
,
891 priv
->header
.version
, priv
->header
.chunk_size
, priv
->header
.chunk_num
);
893 if (priv
->header
.chunk_size
> POHMELFS_CHUNK_SIZE
) {
900 if (priv
->read_total
== priv
->header
.chunk_num
) {
901 err
= pohmelfs_readdir_warm_scratch(t
, recv
);
905 if (priv
->state
== POHMELFS_READDIR_WANT_RECV_CHUNK
) {
906 data
= priv
->chunk
+ priv
->read_in_inode
;
907 size
= POHMELFS_CHUNK_SIZE
- priv
->read_in_inode
;
909 old_recv_offset
= t
->recv_offset
;
911 err
= pohmelfs_recv(t
, recv
, data
, size
);
915 priv
->read_in_inode
+= t
->recv_offset
- old_recv_offset
;
917 if (priv
->read_in_inode
== POHMELFS_CHUNK_SIZE
) {
918 struct pohmelfs_readdir_chunk_header
*chunk_header
;
919 struct pohmelfs_inode_info
*info
;
922 priv
->read_in_inode
= 0;
925 chunk_header
= (struct pohmelfs_readdir_chunk_header
*)priv
->chunk
;
926 pohmelfs_convert_readdir_chunk_header(chunk_header
);
929 * Here we assume that record always fits in 1 chunk.
930 * In future this code should be changed to read several chunks
931 * and concatenate it to build continous buffer for
932 * file name and pohmelfs_inode_info structure
935 info
= (struct pohmelfs_inode_info
*)(priv
->chunk
+ sizeof(struct pohmelfs_readdir_chunk_header
) + chunk_header
->key_size
);
936 pohmelfs_convert_inode_info(info
);
938 filename
= (char *)(priv
->chunk
+ sizeof(struct pohmelfs_readdir_chunk_header
));
940 err
= pohmelfs_update_inode(priv
->wait
->pi
, info
, filename
);
941 pr_debug("pohmelfs: %d:%s: inode: %llu, namelen: %d, name: %.*s: %d\n",
942 cmd
->id
.group_id
, pohmelfs_dump_id(info
->id
.id
), (unsigned long long)info
->ino
,
943 info
->namelen
, info
->namelen
, filename
, err
);
949 if ((priv
->read_total
< priv
->header
.chunk_num
) && (t
->recv_offset
< cmd
->size
))
959 static int pohmelfs_readdir_warm_init(struct pohmelfs_trans
*t
)
961 struct pohmelfs_readdir_warm_priv
*priv
= t
->priv
;
963 kref_get(&priv
->refcnt
);
967 static int pohmelfs_warm_dir_group(struct inode
*dir
, int group_id
)
969 struct pohmelfs_sb
*psb
= pohmelfs_sb(dir
->i_sb
);
970 struct pohmelfs_inode
*parent
= pohmelfs_inode(dir
);
971 struct pohmelfs_io
*io
;
972 struct pohmelfs_readdir_warm_priv
*priv
;
973 struct pohmelfs_wait
*wait
;
977 io
= kmem_cache_zalloc(pohmelfs_io_cache
, GFP_NOIO
);
983 priv
= kzalloc(sizeof(struct pohmelfs_readdir_warm_priv
), GFP_NOIO
);
989 kref_init(&priv
->refcnt
);
991 wait
= pohmelfs_wait_alloc(parent
);
1000 io
->id
= &parent
->id
;
1001 io
->cflags
= DNET_FLAGS_NEED_ACK
| DNET_FLAGS_NOLOCK
;
1002 io
->cmd
= DNET_CMD_READ
;
1003 io
->cb
.recv_reply
= pohmelfs_readdir_warm_recv_reply
;
1004 io
->cb
.complete
= pohmelfs_readdir_warm_complete
;
1005 io
->cb
.destroy
= pohmelfs_readdir_warm_destroy
;
1006 io
->cb
.init
= pohmelfs_readdir_warm_init
;
1009 err
= pohmelfs_send_io_group(io
, group_id
);
1013 /* destruction callback will drop reference */
1014 ret
= wait_event_interruptible_timeout(wait
->wq
, wait
->condition
!= 0, msecs_to_jiffies(psb
->read_wait_timeout
));
1022 if (wait
->condition
< 0) {
1023 err
= wait
->condition
;
1027 /* drop the reference we grabbed at creation time */
1028 kref_put(&priv
->refcnt
, pohmelfs_readdir_warm_free
);
1029 kmem_cache_free(pohmelfs_io_cache
, io
);
1033 kref_put(&priv
->refcnt
, pohmelfs_readdir_warm_free
);
1035 kmem_cache_free(pohmelfs_io_cache
, io
);
1040 static int pohmelfs_warm_dir(struct inode
*dir
)
1042 struct pohmelfs_sb
*psb
= pohmelfs_sb(dir
->i_sb
);
1043 int i
, err
= -ENOENT
;
1045 for (i
= 0; i
< psb
->group_num
; ++i
) {
1046 err
= pohmelfs_warm_dir_group(dir
, psb
->groups
[i
]);
1056 struct pohmelfs_dentry
{
1063 } __attribute__ ((packed
));
1065 static int pohmelfs_readdir_complete(struct pohmelfs_trans
*t
, struct pohmelfs_state
*recv
)
1067 struct pohmelfs_inode
*pi
= pohmelfs_inode(t
->inode
);
1068 struct pohmelfs_wait
*wait
= t
->priv
;
1069 struct dnet_cmd
*cmd
= &recv
->cmd
;
1071 pr_debug("pohmelfs: %s: readdir comlete: cmd size: %llu, recv offset: %llu, flags: %x\n",
1072 pohmelfs_dump_id(pi
->id
.id
), (unsigned long long)cmd
->size
, t
->recv_offset
, cmd
->flags
);
1074 if (cmd
->flags
& DNET_FLAGS_MORE
) {
1075 if (cmd
->size
> sizeof(struct dnet_attr
)) {
1076 wait
->ret
= t
->recv_data
;
1077 wait
->condition
= cmd
->size
;
1079 t
->recv_data
= NULL
;
1082 if (!wait
->condition
) {
1083 wait
->condition
= cmd
->status
;
1084 if (!wait
->condition
)
1085 wait
->condition
= 1;
1092 static int pohmelfs_readdir_process(void *data
, int size
, struct file
*filp
, void *dirent
, filldir_t filldir
)
1097 struct pohmelfs_dentry
*d
= data
;
1099 if (size
< sizeof(struct pohmelfs_dentry
)) {
1104 if (size
< d
->len
) {
1109 err
= filldir(dirent
, d
->name
, d
->len
, filp
->f_pos
, le64_to_cpu(d
->ino
), d
->type
);
1114 size
-= sizeof(struct pohmelfs_dentry
) + d
->len
;
1115 data
+= sizeof(struct pohmelfs_dentry
) + d
->len
;
1121 struct pohmelfs_readdir
{
1122 struct dnet_raw_id id
;
1127 static int pohmelfs_readdir_group(int group_id
, struct file
*filp
, void *dirent
, filldir_t filldir
)
1129 struct dentry
*dentry
= filp
->f_path
.dentry
;
1130 struct inode
*dir
= dentry
->d_inode
;
1131 struct pohmelfs_sb
*psb
= pohmelfs_sb(dir
->i_sb
);
1132 struct pohmelfs_inode
*parent
= pohmelfs_inode(dir
);
1133 struct pohmelfs_readdir rd
;
1134 struct pohmelfs_script_req req
;
1139 req
.script_name
= POHMELFS_READDIR_SCRIPT
;
1140 req
.script_namelen
= sizeof(POHMELFS_READDIR_SCRIPT
) - 1; /* not including 0-byte */
1142 req
.obj_name
= (char *)dentry
->d_name
.name
;
1143 req
.obj_len
= dentry
->d_name
.len
;
1146 rd
.max_size
= psb
->readdir_allocation
* PAGE_SIZE
- sizeof(struct dnet_attr
); /* cmd->size should fit one page */
1147 rd
.fpos
= filp
->f_pos
;
1150 req
.binary_size
= sizeof(struct pohmelfs_readdir
);
1152 req
.id
= &parent
->id
;
1153 req
.complete
= pohmelfs_readdir_complete
;
1155 req
.group_id
= group_id
;
1158 err
= pohmelfs_send_script_request(parent
, &req
);
1163 size
= req
.ret_cond
;
1164 if (!data
|| !size
) {
1169 err
= pohmelfs_readdir_process(data
+ sizeof(struct dnet_attr
), size
- sizeof(struct dnet_attr
), filp
, dirent
, filldir
);
1177 static int pohmelfs_dir_open(struct inode
*dir
, struct file
*filp
)
1179 struct pohmelfs_sb
*psb
= pohmelfs_sb(dir
->i_sb
);
1180 struct pohmelfs_inode
*pi
= pohmelfs_inode(dir
);
1181 struct dentry
*dentry
= filp
->f_path
.dentry
;
1183 if (get_seconds() < pi
->update
+ psb
->sync_timeout
)
1184 return dcache_dir_open(dir
, filp
);
1186 if (list_empty(&dentry
->d_subdirs
)) {
1187 return dcache_dir_open(dir
, filp
);
1194 static int pohmelfs_dir_close(struct inode
*inode
, struct file
*filp
)
1196 if (filp
->private_data
)
1197 return dcache_dir_close(inode
, filp
);
1201 static int pohmelfs_readdir(struct file
*filp
, void *dirent
, filldir_t filldir
)
1203 struct dentry
*dentry
= filp
->f_path
.dentry
;
1204 struct inode
*dir
= dentry
->d_inode
;
1205 struct pohmelfs_inode
*pi
= pohmelfs_inode(dir
);
1206 struct pohmelfs_sb
*psb
= pohmelfs_sb(dir
->i_sb
);
1207 int i
, err
= -ENOENT
;
1209 if (filp
->private_data
) {
1210 if (get_seconds() > pi
->update
+ psb
->sync_timeout
) {
1211 err
= pohmelfs_warm_dir(dir
);
1215 pi
->update
= get_seconds();
1218 return dcache_readdir(filp
, dirent
, filldir
);
1221 for (i
= 0; i
< psb
->group_num
; ++i
) {
1222 err
= pohmelfs_readdir_group(psb
->groups
[i
], filp
, dirent
, filldir
);
1232 const struct file_operations pohmelfs_dir_fops
= {
1233 .open
= pohmelfs_dir_open
,
1234 .release
= pohmelfs_dir_close
,
1235 .read
= generic_read_dir
,
1236 .readdir
= pohmelfs_readdir
,