Fixed listing and object creation
[pohmelfs.git] / fs / pohmelfs / dir.c
bloba7dd34969b016b59916eafbdda2c9c7e384b156c
1 /*
2 * Copyright (C) 2011+ Evgeniy Polyakov <zbr@ioremap.net>
3 */
5 #include <linux/fs.h>
6 #include <linux/dcache.h>
8 #include "pohmelfs.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;
15 char *dname;
16 int err;
18 memset(&io, 0, sizeof(struct pohmelfs_io));
20 info = kmalloc(sizeof(struct pohmelfs_inode_info) + len, GFP_NOIO);
21 if (!info) {
22 err = -ENOMEM;
23 goto err_out_exit;
25 dname = (char *)(info + 1);
27 pohmelfs_fill_inode_info(&pi->vfs_inode, info);
28 info->namelen = len;
30 pohmelfs_hash(psb, sname, len, &info->name);
32 memcpy(dname, sname, len);
34 pohmelfs_convert_inode_info(info);
36 io.pi = pi;
37 io.id = id;
38 io.group = 2;
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;
43 io.data = info;
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);
50 err_out_exit:
51 return err;
54 static int pohmelfs_create(struct inode *dir, struct dentry *dentry, int mode,
55 struct nameidata *nd)
57 struct pohmelfs_sb *psb = pohmelfs_sb(dir->i_sb);
58 struct pohmelfs_inode *parent = pohmelfs_inode(dir);
59 struct pohmelfs_inode *pi;
60 int err;
62 pi = pohmelfs_new_inode(psb, mode);
63 if (IS_ERR(pi)) {
64 err = PTR_ERR(pi);
65 goto err_out_exit;
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);
71 if (err)
72 goto err_out_put;
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);
87 return 0;
89 err_out_put:
90 iput(&pi->vfs_inode);
91 err_out_exit:
92 return err;
95 struct pohmelfs_lookup_priv {
96 struct pohmelfs_wait *wait;
98 struct kref refcnt;
100 /* if set, all received inodes will be attached to dentries in parent dir */
101 int load_all;
103 /* currently read object name */
104 u32 namelen;
106 /* currently read inode info */
107 long offset;
110 * this is the name we are looking for
112 struct dnet_raw_id name_id;
114 int found;
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);
125 if (priv->wait)
126 pohmelfs_wait_put(priv->wait);
127 kfree(priv);
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;
136 if (t->recv_data) {
137 kfree(t->recv_data);
138 t->recv_data = NULL;
141 if (!(cmd->flags & DNET_FLAGS_MORE)) {
142 int err = cmd->status;
144 if (!priv->found && !err && !priv->load_all)
145 err = -ENOENT;
147 wait->condition = 1;
148 wake_up(&wait->wq);
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);
155 return err;
158 return 0;
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;
166 struct qstr str;
167 int err;
169 str.name = name;
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) {
178 err = -ENOENT;
179 goto read_name_out_unlock;
182 dentry = d_lookup(parent_dentry, &str);
183 if (dentry) {
184 err = -EEXIST;
185 dput(dentry);
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);
194 if (!dentry) {
195 err = -ENOMEM;
196 goto read_name_out_put_parent;
199 old = d_splice_alias(inode, dentry);
200 if (unlikely(old)) {
201 dput(dentry);
202 dentry = old;
203 } else {
204 dput(dentry);
207 dput(parent_dentry);
208 return 0;
210 read_name_out_put_parent:
211 dput(parent_dentry);
212 read_name_out_unlock:
213 iput(inode);
215 return err;
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;
226 struct inode *inode;
227 char *name;
228 int err;
230 /* reading name which follows inode_info */
231 err = pohmelfs_data_recv(recv, t->recv_data + priv->offset, iisize - priv->offset, MSG_DONTWAIT);
232 if (err < 0)
233 goto err_out_exit;
235 t->recv_offset += err;
236 priv->offset += err;
238 if (priv->offset < iisize) {
239 err = -EAGAIN;
240 goto err_out_exit;
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) {
253 err = -ENOENT;
254 goto err_out_done;
257 pi = pohmelfs_sb_inode_lookup(psb, &info->id);
258 if (pi) {
259 inode = &pi->vfs_inode;
261 pohmelfs_fill_inode(inode, info);
262 iput(inode);
264 err = -EEXIST;
265 goto err_out_done;
266 } else {
267 pi = pohmelfs_existing_inode(recv->psb, info);
268 if (IS_ERR(pi)) {
269 err = PTR_ERR(pi);
270 goto err_out_done;
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);
279 } else {
280 if (!memcmp(&info->name, &priv->name_id, sizeof(struct dnet_raw_id))) {
281 if (!priv->found)
282 memcpy(&priv->inode_id, &pi->id, sizeof(struct dnet_raw_id));
283 priv->found = 1;
284 } else {
285 pohmelfs_lookup_dentry(priv, pi, name);
290 err = 0;
292 err_out_done:
293 priv->namelen = 0;
294 priv->offset = 0;
295 err_out_exit:
296 return err;
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);
304 int err = 0;
306 if (!t->recv_data) {
307 t->recv_data = kmalloc(sizeof(struct pohmelfs_inode_info) + NAME_MAX + 1, GFP_NOIO);
308 if (!t->recv_data) {
309 err = -ENOMEM;
310 goto err_out_exit;
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);
321 if (err < 0)
322 goto err_out_exit;
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)
335 priv->offset = 0;
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);
342 if (err < 0)
343 goto err_out_exit;
345 t->recv_offset += err;
346 priv->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);
361 return 0;
363 err_out_exit:
364 return err;
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;
375 long ret;
376 int err;
378 priv = kzalloc(sizeof(struct pohmelfs_lookup_priv), GFP_NOIO);
379 if (!priv) {
380 err = -ENOMEM;
381 goto err_out_exit;
384 kref_init(&priv->refcnt);
386 wait = pohmelfs_wait_alloc(parent);
387 if (!wait) {
388 err = -ENOMEM;
389 goto err_out_put;
392 priv->wait = wait;
393 kref_get(&priv->refcnt);
395 if (!dentry)
396 priv->load_all = 1;
397 else {
398 pohmelfs_hash(psb, dentry->d_name.name, dentry->d_name.len, &priv->name_id);
401 memset(&io, 0, sizeof(struct pohmelfs_io));
403 io.pi = parent;
404 io.id = &parent->id;
405 io.group = 2;
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;
410 io.priv = priv;
412 err = pohmelfs_send_io(&io);
413 if (err) {
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);
416 goto err_out_put;
419 ret = wait_event_interruptible_timeout(wait->wq, wait->condition != 0, msecs_to_jiffies(psb->read_wait_timeout));
420 if (ret <= 0) {
421 err = ret;
422 if (ret == 0)
423 err = -ETIMEDOUT;
424 goto err_out_put;
427 err = -ENOENT;
428 if (!priv->found)
429 goto err_out_put;
431 pi = pohmelfs_sb_inode_lookup(psb, &priv->inode_id);
432 if (!pi)
433 goto err_out_put;
435 kref_put(&priv->refcnt, pohmelfs_lookup_free);
436 return pi;
438 err_out_put:
439 kref_put(&priv->refcnt, pohmelfs_lookup_free);
440 err_out_exit:
441 pr_info("pohmelfs: pohmelfs_warm_dir: %s, parent: %lu: %d\n",
442 pohmelfs_dump_id(parent->id.id), dir->i_ino, err);
443 return ERR_PTR(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);
451 int err;
453 pi = pohmelfs_warm_dir(dir, dentry);
454 if (IS_ERR(pi)) {
455 err = PTR_ERR(pi);
456 if (err != -ENOENT)
457 goto err_out_exit;
458 } else {
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() */
465 iput(inode);
468 return d_splice_alias(inode, dentry);
470 err_out_exit:
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);
473 return ERR_PTR(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);
486 if (!file->f_pos) {
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,