2 * Copyright (C) 2011+ Evgeniy Polyakov <zbr@ioremap.net>
6 #include <linux/dcache.h>
10 int pohmelfs_send_inode_info(struct pohmelfs_inode
*pi
, struct dnet_raw_id
*id
, const char *sname
, int len
, int overwrite
)
12 struct pohmelfs_sb
*psb
= pohmelfs_sb(pi
->vfs_inode
.i_sb
);
13 struct pohmelfs_inode_info
*info
;
14 struct pohmelfs_io io
;
18 memset(&io
, 0, sizeof(struct pohmelfs_io
));
20 info
= kmalloc(sizeof(struct pohmelfs_inode_info
) + len
, GFP_NOIO
);
25 dname
= (char *)(info
+ 1);
27 pohmelfs_fill_inode_info(&pi
->vfs_inode
, info
);
30 pohmelfs_hash(psb
, sname
, len
, &info
->name
);
32 memcpy(dname
, sname
, len
);
34 pohmelfs_convert_inode_info(info
);
39 io
.cmd
= DNET_CMD_WRITE
;
40 io
.aflags
= DNET_ATTR_NOCSUM
;
41 io
.size
= sizeof(struct pohmelfs_inode_info
) + len
;
42 io
.ioflags
= DNET_IO_FLAGS_APPEND
;
44 io
.alloc_flags
= POHMELFS_IO_OWN
;
46 err
= pohmelfs_send_io(&io
);
47 pr_info("pohmelfs: pohmelfs_send_inode_info: %s: pohmelfs_send_io: object ino: %lu, name: %s, overwrite: %d, offset: %llu: %d\n",
48 pohmelfs_dump_id(id
->id
), pi
->vfs_inode
.i_ino
, sname
, overwrite
, pi
->offset
, err
);
54 static int pohmelfs_create(struct inode
*dir
, struct dentry
*dentry
, int mode
,
57 struct pohmelfs_sb
*psb
= pohmelfs_sb(dir
->i_sb
);
58 struct pohmelfs_inode
*parent
= pohmelfs_inode(dir
);
59 struct pohmelfs_inode
*pi
;
62 pi
= pohmelfs_new_inode(psb
, mode
);
68 memcpy(&pi
->parent_id
, &parent
->id
, sizeof(struct dnet_raw_id
));
70 err
= pohmelfs_send_inode_info(pi
, &parent
->id
, dentry
->d_name
.name
, dentry
->d_name
.len
, 0);
74 pr_info("pohmelfs: create: %s, ino: %lu, parent dir: %lu, object: %s\n",
75 pohmelfs_dump_id(pi
->id
.id
), pi
->vfs_inode
.i_ino
,
76 dir
->i_ino
, dentry
->d_name
.name
);
78 inode_init_owner(&pi
->vfs_inode
, dir
, mode
);
81 * calling d_instantiate() implies that
82 * ->lookup() used d_splice_alias() with NULL inode
83 * when it failed to find requested object
85 d_instantiate(dentry
, &pi
->vfs_inode
);
95 struct pohmelfs_lookup_priv
{
96 struct pohmelfs_wait
*wait
;
100 /* if set, all received inodes will be attached to dentries in parent dir */
103 /* currently read object name */
106 /* currently read inode info */
110 * this is the name we are looking for
112 struct dnet_raw_id name_id
;
116 * will be filled, if inode with given name was found
118 struct dnet_raw_id inode_id
;
121 static void pohmelfs_lookup_free(struct kref
*kref
)
123 struct pohmelfs_lookup_priv
*priv
= container_of(kref
, struct pohmelfs_lookup_priv
, refcnt
);
126 pohmelfs_wait_put(priv
->wait
);
130 static int pohmelfs_lookup_complete(struct pohmelfs_trans
*t
, struct pohmelfs_state
*recv
)
132 struct pohmelfs_lookup_priv
*priv
= t
->priv
;
133 struct pohmelfs_wait
*wait
= priv
->wait
;
134 struct dnet_cmd
*cmd
= &recv
->cmd
;
141 if (!(cmd
->flags
& DNET_FLAGS_MORE
)) {
142 int err
= cmd
->status
;
144 if (!priv
->found
&& !err
&& !priv
->load_all
)
150 pohmelfs_print_addr(&recv
->sa
, "%s: pohmelfs_lookup_complete: %d\n",
151 pohmelfs_dump_id(priv
->name_id
.id
), err
);
153 kref_put(&priv
->refcnt
, pohmelfs_lookup_free
);
161 static int pohmelfs_lookup_dentry(struct pohmelfs_lookup_priv
*priv
, struct pohmelfs_inode
*pi
, char *name
)
163 struct inode
*inode
= &pi
->vfs_inode
;
164 struct inode
*dir
= &priv
->wait
->pi
->vfs_inode
;
165 struct dentry
*dentry
, *parent_dentry
, *old
;
170 str
.len
= priv
->namelen
;
171 str
.hash
= full_name_hash(str
.name
, str
.len
);
173 name
[str
.len
] = '\0';
175 /* we do not need to hold dir->i_mutex here, don't we? :) */
176 parent_dentry
= d_find_alias(dir
);
177 if (!parent_dentry
) {
179 goto read_name_out_unlock
;
182 dentry
= d_lookup(parent_dentry
, &str
);
186 goto read_name_out_put_parent
;
189 * if things are ok, dentry has 2 references -
190 * one in parent dir, and another its own,
191 * which we should drop
193 dentry
= d_alloc(parent_dentry
, &str
);
196 goto read_name_out_put_parent
;
199 old
= d_splice_alias(inode
, dentry
);
210 read_name_out_put_parent
:
212 read_name_out_unlock
:
218 static int pohmelfs_lookup_recv_inode(struct pohmelfs_trans
*t
, struct pohmelfs_state
*recv
)
220 struct pohmelfs_lookup_priv
*priv
= t
->priv
;
221 u32 iisize
= sizeof(struct pohmelfs_inode_info
) + priv
->namelen
;
222 int attr_size
= sizeof(struct dnet_attr
) + sizeof(struct dnet_io_attr
);
223 struct pohmelfs_sb
*psb
= pohmelfs_sb(t
->inode
->i_sb
);
224 struct pohmelfs_inode_info
*info
= t
->recv_data
;
225 struct pohmelfs_inode
*pi
;
230 /* reading name which follows inode_info */
231 err
= pohmelfs_data_recv(recv
, t
->recv_data
+ priv
->offset
, iisize
- priv
->offset
, MSG_DONTWAIT
);
235 t
->recv_offset
+= err
;
238 if (priv
->offset
< iisize
) {
243 name
= (char *)(info
+ 1);
244 /* we allocated enough space for this */
245 name
[priv
->namelen
] = '\0';
247 pohmelfs_print_addr(&recv
->sa
, "name: %s: ino: %llu, removed: %d, name: %s, namelen: %u, size: %llu\n",
248 pohmelfs_dump_id(info
->name
.id
), (unsigned long long)info
->ino
,
249 !!(info
->flags
& POHMELFS_INODE_INFO_REMOVED
), name
, priv
->namelen
,
250 (unsigned long long)info
->size
);
252 if (info
->flags
& POHMELFS_INODE_INFO_REMOVED
) {
257 pi
= pohmelfs_sb_inode_lookup(psb
, &info
->id
);
259 inode
= &pi
->vfs_inode
;
261 pohmelfs_fill_inode(inode
, info
);
267 pi
= pohmelfs_existing_inode(recv
->psb
, info
);
273 memcpy(&pi
->parent_id
, &priv
->wait
->pi
->id
, sizeof(struct dnet_raw_id
));
275 pi
->offset
= t
->recv_offset
- sizeof(struct pohmelfs_inode_info
) - attr_size
;
277 if (priv
->load_all
) {
278 pohmelfs_lookup_dentry(priv
, pi
, name
);
280 if (!memcmp(&info
->name
, &priv
->name_id
, sizeof(struct dnet_raw_id
))) {
282 memcpy(&priv
->inode_id
, &pi
->id
, sizeof(struct dnet_raw_id
));
285 pohmelfs_lookup_dentry(priv
, pi
, name
);
299 static int pohmelfs_lookup_recv_reply(struct pohmelfs_trans
*t
, struct pohmelfs_state
*recv
)
301 struct pohmelfs_lookup_priv
*priv
= t
->priv
;
302 struct dnet_cmd
*cmd
= &recv
->cmd
;
303 int attr_size
= sizeof(struct dnet_attr
) + sizeof(struct dnet_io_attr
);
307 t
->recv_data
= kmalloc(sizeof(struct pohmelfs_inode_info
) + NAME_MAX
+ 1, GFP_NOIO
);
313 pohmelfs_print_addr(&recv
->sa
, "name: %s: recv_data: %p, cmd size: %llu\n",
314 pohmelfs_dump_id(priv
->name_id
.id
), t
->recv_data
, (unsigned long long)cmd
->size
);
317 if (t
->recv_offset
< attr_size
) {
318 void *attr
= &t
->cmd
.attr
;
320 err
= pohmelfs_data_recv(recv
, attr
+ t
->recv_offset
, attr_size
- t
->recv_offset
, MSG_DONTWAIT
);
323 t
->recv_offset
+= err
;
325 if (t
->recv_offset
== attr_size
) {
326 dnet_convert_attr(&t
->cmd
.attr
);
327 dnet_convert_io_attr(&t
->cmd
.p
.io
);
329 pohmelfs_print_addr(&recv
->sa
, "%s: io size: %llu\n",
330 pohmelfs_dump_id(cmd
->id
.id
), (unsigned long long)t
->cmd
.p
.io
.size
);
334 if (t
->recv_offset
== attr_size
)
337 if (t
->recv_offset
>= attr_size
) {
338 if (priv
->offset
< sizeof(struct pohmelfs_inode_info
)) {
339 /* receiving pohmelfs_inode_info first */
340 err
= pohmelfs_data_recv(recv
, t
->recv_data
+ priv
->offset
,
341 sizeof(struct pohmelfs_inode_info
) - priv
->offset
, MSG_DONTWAIT
);
345 t
->recv_offset
+= err
;
349 if ((priv
->offset
== sizeof(struct pohmelfs_inode_info
)) && !priv
->namelen
) {
350 struct pohmelfs_inode_info
*info
= t
->recv_data
;
351 pohmelfs_convert_inode_info(info
);
352 priv
->namelen
= info
->namelen
;
355 if ((priv
->offset
>= sizeof(struct pohmelfs_inode_info
)) && priv
->namelen
) {
356 pohmelfs_lookup_recv_inode(t
, recv
);
367 static struct pohmelfs_inode
*pohmelfs_warm_dir(struct inode
*dir
, struct dentry
*dentry
)
369 struct pohmelfs_sb
*psb
= pohmelfs_sb(dir
->i_sb
);
370 struct pohmelfs_inode
*parent
= pohmelfs_inode(dir
);
371 struct pohmelfs_inode
*pi
;
372 struct pohmelfs_io io
;
373 struct pohmelfs_lookup_priv
*priv
;
374 struct pohmelfs_wait
*wait
;
378 priv
= kzalloc(sizeof(struct pohmelfs_lookup_priv
), GFP_NOIO
);
384 kref_init(&priv
->refcnt
);
386 wait
= pohmelfs_wait_alloc(parent
);
393 kref_get(&priv
->refcnt
);
398 pohmelfs_hash(psb
, dentry
->d_name
.name
, dentry
->d_name
.len
, &priv
->name_id
);
401 memset(&io
, 0, sizeof(struct pohmelfs_io
));
406 io
.aflags
= DNET_ATTR_NOCSUM
;
407 io
.cmd
= DNET_CMD_READ
;
408 io
.recv_reply
= pohmelfs_lookup_recv_reply
;
409 io
.complete
= pohmelfs_lookup_complete
;
412 err
= pohmelfs_send_io(&io
);
414 pr_info("pohmelfs: pohmelfs_warm_dir: pohmelfs_send_io: %s, ino: %lu: %d\n",
415 pohmelfs_dump_id(parent
->id
.id
), dir
->i_ino
, err
);
419 ret
= wait_event_interruptible_timeout(wait
->wq
, wait
->condition
!= 0, msecs_to_jiffies(psb
->read_wait_timeout
));
431 pi
= pohmelfs_sb_inode_lookup(psb
, &priv
->inode_id
);
435 kref_put(&priv
->refcnt
, pohmelfs_lookup_free
);
439 kref_put(&priv
->refcnt
, pohmelfs_lookup_free
);
441 pr_info("pohmelfs: pohmelfs_warm_dir: %s, parent: %lu: %d\n",
442 pohmelfs_dump_id(parent
->id
.id
), dir
->i_ino
, err
);
446 static struct dentry
*pohmelfs_lookup(struct inode
*dir
, struct dentry
*dentry
, struct nameidata
*nd
)
448 struct pohmelfs_inode
*pi
;
449 struct inode
*inode
= NULL
;
450 struct pohmelfs_inode
*parent
= pohmelfs_inode(dir
);
453 pi
= pohmelfs_warm_dir(dir
, dentry
);
459 inode
= &pi
->vfs_inode
;
461 pr_info("pohmelfs: lookup: %s, parent: %lu, object: %s -> ino: %lu\n",
462 pohmelfs_dump_id(parent
->id
.id
), dir
->i_ino
, dentry
->d_name
.name
, pi
->vfs_inode
.i_ino
);
464 /* we grabbed a reference in pohmelfs_sb_inode_lookup() */
468 return d_splice_alias(inode
, dentry
);
471 pr_err("pohmelfs: lookup failed: %s, parent: %lu, object: %s: %d\n",
472 pohmelfs_dump_id(parent
->id
.id
), dir
->i_ino
, dentry
->d_name
.name
, err
);
476 const struct inode_operations pohmelfs_dir_inode_operations
= {
477 .create
= pohmelfs_create
,
478 .lookup
= pohmelfs_lookup
,
481 static int pohmelfs_readdir(struct file
*file
, void *dirent
, filldir_t filldir
)
483 struct inode
*inode
= file
->f_path
.dentry
->d_inode
;
484 struct pohmelfs_inode
*pi
= pohmelfs_inode(inode
);
487 pr_info("pohmelfs: readdir: %s: ino: %lu\n", pohmelfs_dump_id(pi
->id
.id
), inode
->i_ino
);
488 pohmelfs_warm_dir(inode
, NULL
);
491 return dcache_readdir(file
, dirent
, filldir
);
494 const struct file_operations pohmelfs_dir_fops
= {
495 .open
= dcache_dir_open
,
496 .release
= dcache_dir_close
,
497 .llseek
= dcache_dir_lseek
,
499 .read
= generic_read_dir
,
500 .readdir
= pohmelfs_readdir
,