2 * Copyright (C) 2011+ Evgeniy Polyakov <zbr@ioremap.net>
6 #include <linux/dcache.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
);
48 wait
->condition
= cmd
->status
;
54 static int pohmelfs_send_inode_info_init(struct pohmelfs_trans
*t
)
56 struct pohmelfs_wait
*wait
= t
->priv
;
58 pohmelfs_wait_get(wait
);
62 static void pohmelfs_send_inode_info_destroy(struct pohmelfs_trans
*t
)
64 struct pohmelfs_wait
*wait
= t
->priv
;
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
;
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
)) {
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
);
104 pi
->parent_id
= parent
->id
;
111 wait
->condition
= err
;
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
;
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
);
137 pio
= kmem_cache_zalloc(pohmelfs_io_cache
, GFP_NOIO
);
140 goto err_out_wait_put
;
143 e
= kmalloc(sizeof(struct dnet_exec
) + req
->script_namelen
+ script_len
+ req
->binary_size
, GFP_NOIO
);
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
);
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
;
173 pio
->cb
.init
= pohmelfs_send_inode_info_init
;
174 pio
->cb
.destroy
= pohmelfs_send_inode_info_destroy
;
175 pio
->cb
.complete
= req
->complete
;
178 err
= pohmelfs_send_buf_single(pio
, NULL
);
180 err
= pohmelfs_send_buf(pio
);
186 ret
= wait_event_interruptible_timeout(wait
->wq
, wait
->condition
!= 0, msecs_to_jiffies(psb
->read_wait_timeout
));
194 if (wait
->condition
< 0)
195 err
= wait
->condition
;
197 req
->ret
= wait
->ret
;
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
);
214 kmem_cache_free(pohmelfs_io_cache
, pio
);
216 pohmelfs_wait_put(wait
);
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
;
232 bin
= kmem_cache_alloc(pohmelfs_inode_info_binary_package_cache
, GFP_NOIO
);
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
;
245 req
.binary_size
= sizeof(struct pohmelfs_inode_info
) + sizeof(struct dnet_raw_id
);
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
);
265 kmem_cache_free(pohmelfs_inode_info_binary_package_cache
, bin
);
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
;
278 pi
= pohmelfs_new_inode(psb
, mode
);
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
);
303 struct pohmelfs_readdir_header
{
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
;
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
;
347 struct pohmelfs_readdir_header header
;
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
);
361 pohmelfs_wait_put(priv
->wait
);
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
;
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
;
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
)
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
;
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
) {
417 dentry
= d_lookup(parent_dentry
, &str
);
421 dentry
->d_fsdata
= NULL
;
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
);
433 goto err_out_put_parent
;
436 old
= d_splice_alias(inode
, dentry
);
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
;
461 pi
= pohmelfs_sb_inode_lookup(psb
, &info
->id
);
463 inode
= &pi
->vfs_inode
;
464 pohmelfs_fill_inode(inode
, info
);
467 pi
= pohmelfs_existing_inode(psb
, info
);
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;
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
);
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
;
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
);
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
);
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
;
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
) {
543 data
+= t
->recv_offset
;
544 size
= attr_size
- t
->recv_offset
;
546 err
= pohmelfs_recv(t
, recv
, data
, size
);
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
);
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
) {
588 if (priv
->read_total
== priv
->header
.chunk_num
) {
589 err
= pohmelfs_readdir_scratch(t
, recv
);
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
);
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
;
610 priv
->read_in_inode
= 0;
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
);
637 if ((priv
->read_total
< priv
->header
.chunk_num
) && (t
->recv_offset
< cmd
->size
))
647 static int pohmelfs_readdir_init(struct pohmelfs_trans
*t
)
649 struct pohmelfs_readdir_priv
*priv
= t
->priv
;
651 kref_get(&priv
->refcnt
);
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
;
665 io
= kmem_cache_zalloc(pohmelfs_io_cache
, GFP_NOIO
);
671 priv
= kzalloc(sizeof(struct pohmelfs_readdir_priv
), GFP_NOIO
);
677 kref_init(&priv
->refcnt
);
679 wait
= pohmelfs_wait_alloc(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
;
697 err
= pohmelfs_send_io_group(io
, group_id
);
701 /* destruction callback will drop reference */
702 ret
= wait_event_interruptible_timeout(wait
->wq
, wait
->condition
!= 0, msecs_to_jiffies(psb
->read_wait_timeout
));
710 if (wait
->condition
< 0) {
711 err
= wait
->condition
;
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
);
721 kref_put(&priv
->refcnt
, pohmelfs_readdir_free
);
723 kmem_cache_free(pohmelfs_io_cache
, io
);
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
]);
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
;
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
;
766 err
= pohmelfs_send_script_request(parent
, &req
);
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
);
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
]);
798 inode
= &pi
->vfs_inode
;
803 if (err
&& (err
!= -ENOENT
) && (err
!= -EOPNOTSUPP
))
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
;
816 inode_inc_link_count(dir
);
818 pi
= pohmelfs_new_inode(psb
, mode
| S_IFDIR
);
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
);
834 inode_dec_link_count(dir
);
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
);
853 req
.id
= &parent
->id
;
854 req
.complete
= pohmelfs_send_inode_info_complete
;
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
;
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
;
882 r
= kmalloc(size
, GFP_NOIO
);
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
;
900 req
.binary_size
= size
;
904 req
.id
= &old_parent
->id
;
905 req
.complete
= pohmelfs_send_inode_info_complete
;
907 err
= pohmelfs_send_script_request(old_parent
, &req
);
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
;
922 unsigned len
= strlen(symname
)+1;
925 pi
= pohmelfs_new_inode(psb
, S_IFLNK
| S_IRWXUGO
);
931 pohmelfs_inode_dirty(pohmelfs_inode(dir
), pi
);
932 inode
= &pi
->vfs_inode
;
934 err
= page_symlink(inode
, symname
, len
);
938 d_instantiate(dentry
, inode
);
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
);
965 u64 magic_version
= 0x100;
966 void *magic_data
= (void *)(0x1234);
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
);
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
) {
1001 pohmelfs_warm_dir(dir
);
1004 err
= dcache_dir_open(dir
, file
);
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
,