Let send/recv work to reschedule themself
[pohmelfs.git] / fs / pohmelfs / super.c
blobeaf4663f443870c3e6389445aa51ebb9ff9132a7
1 /*
2 * Copyright (C) 2011+ Evgeniy Polyakov <zbr@ioremap.net>
3 */
5 #include <linux/module.h>
6 #include <linux/string.h>
7 #include <linux/fs.h>
8 #include <linux/slab.h>
9 #include <linux/init.h>
10 #include <linux/in.h>
11 #include <linux/in6.h>
12 #include <linux/blkdev.h>
13 #include <linux/parser.h>
14 #include <linux/random.h>
15 #include <linux/buffer_head.h>
16 #include <linux/exportfs.h>
17 #include <linux/vfs.h>
18 #include <linux/seq_file.h>
19 #include <linux/mount.h>
20 #include <linux/quotaops.h>
21 #include <asm/uaccess.h>
23 #include "pohmelfs.h"
25 #define POHMELFS_MAGIC_NUM 0x504f482e
27 struct kmem_cache *pohmelfs_inode_cache;
28 struct kmem_cache *pohmelfs_trans_cache;
29 struct kmem_cache *pohmelfs_inode_info_cache;
30 struct kmem_cache *pohmelfs_route_cache;
31 struct kmem_cache *pohmelfs_wait_cache;
32 struct kmem_cache *pohmelfs_io_cache;
33 struct kmem_cache *pohmelfs_inode_info_binary_package_cache;
34 struct kmem_cache *pohmelfs_write_cache;
35 struct kmem_cache *pohmelfs_dentry_cache;
37 static atomic_t psb_bdi_num = ATOMIC_INIT(0);
39 static void pohmelfs_http_compat_cleanup(struct pohmelfs_sb *psb)
41 struct pohmelfs_path *p;
42 int i;
44 for (i = 0; i < psb->http_compat; ++i) {
45 p = &psb->path[i];
47 mutex_destroy(&p->lock);
48 kfree(p->data);
52 static int pohmelfs_http_compat_init(struct pohmelfs_sb *psb)
54 int i, err;
55 struct pohmelfs_path *path, *p;
57 path = kmalloc(psb->http_compat * sizeof(struct pohmelfs_path), GFP_KERNEL);
58 if (!path) {
59 err = -ENOMEM;
60 goto err_out_exit;
63 for (i = 0; i < psb->http_compat; ++i) {
64 p = &path[i];
66 mutex_init(&p->lock);
68 p->data = kmalloc(PAGE_SIZE, GFP_KERNEL);
69 if (!p->data) {
70 err = -ENOMEM;
71 goto err_out_free;
75 psb->path = path;
76 return 0;
78 err_out_free:
79 while (--i >= 0) {
80 p = &path[i];
82 mutex_destroy(&p->lock);
83 kfree(p->data);
86 kfree(path);
87 err_out_exit:
88 psb->http_compat = 0;
89 return err;
92 static void pohmelfs_cleanup_psb(struct pohmelfs_sb *psb)
94 struct pohmelfs_state *st, *tmp;
95 struct pohmelfs_reconnect *r, *rtmp;
97 cancel_delayed_work(&psb->reconnect_work);
98 cancel_delayed_work(&psb->sync_work);
100 list_for_each_entry_safe(st, tmp, &psb->state_list, state_entry) {
101 list_del_init(&st->state_entry);
103 pohmelfs_state_kill(st);
106 list_for_each_entry_safe(st, tmp, &psb->kill_state_list, state_entry) {
107 list_del_init(&st->state_entry);
108 pohmelfs_state_kill(st);
111 list_for_each_entry_safe(r, rtmp, &psb->reconnect_list, reconnect_entry) {
112 list_del(&r->reconnect_entry);
113 kfree(r);
116 destroy_workqueue(psb->wq);
117 crypto_free_hash(psb->hash);
119 pohmelfs_http_compat_cleanup(psb);
121 kfree(psb->groups);
122 kfree(psb->fsid);
125 static void pohmelfs_put_super(struct super_block *sb)
127 struct pohmelfs_sb *psb = pohmelfs_sb(sb);
129 pohmelfs_cleanup_psb(psb);
130 bdi_destroy(&psb->bdi);
133 struct pohmelfs_size {
134 int group_id;
135 uint64_t bsize; /* Block size */
136 uint64_t frsize; /* Fragment size */
137 uint64_t blocks; /* Filesystem size in frsize units */
138 uint64_t bfree; /* # free blocks */
139 uint64_t bavail; /* # free blocks for non-root */
142 static int pohmelfs_statfs(struct dentry *dentry, struct kstatfs *buf)
144 struct super_block *sb = dentry->d_sb;
145 struct pohmelfs_sb *psb = pohmelfs_sb(sb);
146 struct pohmelfs_state *st;
147 struct pohmelfs_size *sz;
148 uint64_t min_size = ~0ULL;
149 int pos = -1;
150 int err, i;
152 sz = kzalloc(psb->group_num * sizeof(struct pohmelfs_size), GFP_KERNEL);
153 if (!sz) {
154 err = -ENOMEM;
155 goto err_out_exit;
158 for (i = 0; i < psb->group_num; ++i) {
159 sz[i].group_id = psb->groups[i];
162 memset(buf, 0, sizeof(struct kstatfs));
164 buf->f_type = POHMELFS_MAGIC_NUM; /* 'POH.' */
165 buf->f_namelen = 4096;
166 buf->f_files = 0;
167 buf->f_bfree = buf->f_bavail = buf->f_blocks = 0;
169 spin_lock(&psb->state_lock);
170 list_for_each_entry(st, &psb->state_list, state_entry) {
171 for (i = 0; i < psb->group_num; ++i) {
172 if (sz[i].group_id == st->group_id) {
173 sz[i].bsize = sb->s_blocksize;
174 sz[i].frsize = st->frsize;
175 sz[i].blocks += (st->blocks * st->frsize) >> PAGE_SHIFT;
176 sz[i].bfree += (st->bfree * st->bsize) >> PAGE_SHIFT;
177 sz[i].bavail += (st->bavail * st->bsize) >> PAGE_SHIFT;
178 break;
184 spin_unlock(&psb->state_lock);
186 for (i = 0; i < psb->group_num; ++i) {
187 /* skip empty groups */
188 if (sz[i].blocks && (sz[i].bavail < min_size)) {
189 min_size = sz[i].bavail;
190 pos = i;
194 if (pos == -1) {
195 buf->f_bfree = buf->f_bavail = buf->f_blocks = ~0ULL >> PAGE_SHIFT;
196 } else {
197 buf->f_bsize = sz[pos].bsize;
198 buf->f_frsize = sz[pos].frsize;
199 buf->f_blocks = sz[pos].blocks;
200 buf->f_bavail = sz[pos].bfree;
201 buf->f_bfree = sz[pos].bavail;
204 kfree(sz);
205 err = 0;
207 err_out_exit:
208 return err;
211 static int pohmelfs_show_options(struct seq_file *seq, struct dentry *dentry)
213 struct pohmelfs_sb *psb = pohmelfs_sb(dentry->d_inode->i_sb);
215 if (psb->no_read_csum)
216 seq_printf(seq, ",noreadcsum");
217 seq_printf(seq, ",sync_timeout=%ld", psb->sync_timeout);
218 if (psb->fsid)
219 seq_printf(seq, ",fsid=%s", psb->fsid);
220 if (psb->successful_write_count)
221 seq_printf(seq, ",successful_write_count=%d", psb->successful_write_count);
222 seq_printf(seq, ",keepalive_cnt=%d", psb->keepalive_cnt);
223 seq_printf(seq, ",keepalive_interval=%d", psb->keepalive_interval);
224 seq_printf(seq, ",keepalive_idle=%d", psb->keepalive_idle);
225 seq_printf(seq, ",readdir_allocation=%d", psb->readdir_allocation);
226 if (psb->http_compat)
227 seq_printf(seq, ",http_compat=%d", psb->http_compat);
228 if (psb->sync_on_close)
229 seq_printf(seq, ",sync_on_close");
230 return 0;
234 * This is tricky function - inode cache can be shrunk and inode is about to be dropped,
235 * since its last reference is dropped. But then icache can __iget() on this inode and
236 * later iput() it, which will again call ->drop_inode() callback.
238 * So, ->drop_inode() can be called multiple times for single inode without its reintialization
239 * And we better to be ready for this
241 static int pohmelfs_drop_inode(struct inode *inode)
243 struct pohmelfs_inode *pi = pohmelfs_inode(inode);
244 struct pohmelfs_sb *psb = pohmelfs_sb(inode->i_sb);
246 pr_debug("pohmelfs: %s: drop ino: %ld, mapping: %p\n", pohmelfs_dump_id(pi->id.id), inode->i_ino, inode->i_mapping);
248 spin_lock(&psb->inode_lock);
249 if (rb_parent(&pi->node) != &pi->node)
250 rb_erase(&pi->node, &psb->inode_root);
251 rb_init_node(&pi->node);
252 spin_unlock(&psb->inode_lock);
254 return generic_drop_inode(inode);
257 static int pohmelfs_write_inode_complete(struct pohmelfs_trans *t, struct pohmelfs_state *recv)
259 struct dnet_cmd *cmd = &recv->cmd;
260 struct pohmelfs_inode_info_binary_package *bin = t->priv;
261 struct pohmelfs_wait *wait = &bin->wait;
263 if (cmd->flags & DNET_FLAGS_MORE)
264 return 0;
266 wait->condition = cmd->status;
267 if (!wait->condition)
268 wait->condition = 1;
269 wake_up(&wait->wq);
271 return 0;
274 static int pohmelfs_write_inode_init(struct pohmelfs_trans *t)
276 struct pohmelfs_inode_info_binary_package *bin = t->priv;
278 kref_get(&bin->wait.refcnt);
279 return 0;
282 static void pohmelfs_write_inode_release(struct kref *kref)
284 struct pohmelfs_wait *wait = container_of(kref, struct pohmelfs_wait, refcnt);
285 struct pohmelfs_inode_info_binary_package *bin = container_of(wait, struct pohmelfs_inode_info_binary_package, wait);
287 iput(&bin->wait.pi->vfs_inode);
288 kmem_cache_free(pohmelfs_inode_info_binary_package_cache, bin);
291 static void pohmelfs_write_inode_destroy(struct pohmelfs_trans *t)
293 struct pohmelfs_inode_info_binary_package *bin = t->priv;
296 * We own this pointer - it points to &bin->info
297 * Zero it here to prevent pohmelfs_trans_release() from freeing it
299 t->data = NULL;
301 kref_put(&bin->wait.refcnt, pohmelfs_write_inode_release);
304 static int pohmelfs_write_inode(struct inode *inode, struct writeback_control *wbc)
306 struct pohmelfs_inode *pi = pohmelfs_inode(inode);
307 struct pohmelfs_inode_info_binary_package *bin;
308 struct pohmelfs_sb *psb = pohmelfs_sb(inode->i_sb);
309 struct pohmelfs_io *pio;
310 int sync = 0;
311 long ret;
312 int err;
314 if (wbc)
315 sync = wbc->sync_mode == WB_SYNC_ALL;
317 pio = kmem_cache_zalloc(pohmelfs_io_cache, GFP_NOIO);
318 if (!pio) {
319 err = -ENOMEM;
320 goto err_out_exit;
323 bin = kmem_cache_zalloc(pohmelfs_inode_info_binary_package_cache, GFP_NOIO);
324 if (!bin) {
325 err = -ENOMEM;
326 goto err_out_free_pio;
329 pohmelfs_fill_inode_info(inode, &bin->info);
330 err = pohmelfs_wait_init(&bin->wait, pi);
331 if (err)
332 goto err_out_put_bin;
334 pio->pi = pi;
335 pio->id = &pi->id;
336 pio->cmd = DNET_CMD_WRITE;
337 pio->offset = 0;
338 pio->size = sizeof(struct pohmelfs_inode_info);
339 pio->cflags = DNET_FLAGS_NEED_ACK;
340 pio->priv = bin;
341 pio->type = 3;
343 pio->data = &bin->info;
344 pio->alloc_flags = POHMELFS_IO_OWN;
346 pio->cb.complete = pohmelfs_write_inode_complete;
347 pio->cb.init = pohmelfs_write_inode_init;
348 pio->cb.destroy = pohmelfs_write_inode_destroy;
350 err = pohmelfs_send_io(pio);
351 if (err)
352 goto err_out_put_bin;
354 if (sync) {
355 struct pohmelfs_wait *wait = &bin->wait;
357 ret = wait_event_interruptible_timeout(wait->wq,
358 wait->condition != 0 && atomic_read(&wait->refcnt.refcount) <= 2,
359 msecs_to_jiffies(psb->write_wait_timeout));
360 if (ret <= 0) {
361 err = ret;
362 if (ret == 0)
363 err = -ETIMEDOUT;
364 goto err_out_put_bin;
367 if (wait->condition < 0) {
368 err = wait->condition;
369 goto err_out_put_bin;
373 err_out_put_bin:
374 kref_put(&bin->wait.refcnt, pohmelfs_write_inode_release);
375 err_out_free_pio:
376 kmem_cache_free(pohmelfs_io_cache, pio);
377 err_out_exit:
378 return err;
381 static int pohmelfs_parse_options(struct pohmelfs_sb *psb, char *data);
383 static int pohmelfs_remount_fs(struct super_block *sb, int *flags, char *data)
385 struct pohmelfs_sb *psb = pohmelfs_sb(sb);
387 return pohmelfs_parse_options(psb, data);
390 static const struct super_operations pohmelfs_sb_ops = {
391 .alloc_inode = pohmelfs_alloc_inode,
392 .destroy_inode = pohmelfs_destroy_inode,
393 .drop_inode = pohmelfs_drop_inode,
394 .write_inode = pohmelfs_write_inode,
395 .put_super = pohmelfs_put_super,
396 .show_options = pohmelfs_show_options,
397 .statfs = pohmelfs_statfs,
398 .remount_fs = pohmelfs_remount_fs,
401 static void pohmelfs_sync(struct work_struct *work)
403 struct pohmelfs_sb *psb = container_of(to_delayed_work(work), struct pohmelfs_sb, sync_work);
404 struct super_block *sb = psb->sb;
406 down_read(&sb->s_umount);
407 sync_filesystem(sb);
408 up_read(&sb->s_umount);
410 queue_delayed_work(psb->wq, &psb->sync_work, msecs_to_jiffies(psb->sync_timeout * 1000));
411 pohmelfs_stat(psb, 0);
414 static void pohmelfs_reconnect(struct work_struct *work)
416 struct pohmelfs_sb *psb = container_of(to_delayed_work(work), struct pohmelfs_sb, reconnect_work);
417 struct pohmelfs_reconnect *r, *tmp;
418 struct pohmelfs_state *st, *stmp;
419 LIST_HEAD(head);
420 int err;
422 mutex_lock(&psb->reconnect_lock);
423 list_for_each_entry_safe(r, tmp, &psb->reconnect_list, reconnect_entry) {
424 st = pohmelfs_state_create(psb, &r->sa, r->addrlen, 1, r->group_id);
425 if (IS_ERR(st)) {
426 err = PTR_ERR(st);
428 if (err != -EEXIST)
429 continue;
430 } else {
431 pohmelfs_print_addr(&st->sa, "reconnected\n");
434 list_del(&r->reconnect_entry);
435 kfree(r);
437 mutex_unlock(&psb->reconnect_lock);
439 spin_lock(&psb->state_lock);
440 list_for_each_entry_safe(st, stmp, &psb->kill_state_list, state_entry) {
441 list_move(&st->state_entry, &head);
443 spin_unlock(&psb->state_lock);
445 list_for_each_entry_safe(st, stmp, &head, state_entry) {
446 list_del_init(&st->state_entry);
447 pohmelfs_state_kill(st);
450 if (!list_empty(&psb->reconnect_list))
451 queue_delayed_work(psb->wq, &psb->reconnect_work, psb->reconnect_timeout);
454 static int pohmelfs_init_psb(struct pohmelfs_sb *psb, struct super_block *sb)
456 int err;
457 char name[16];
459 INIT_LIST_HEAD(&psb->state_list);
460 psb->route_root = RB_ROOT;
462 psb->inode_root = RB_ROOT;
463 spin_lock_init(&psb->inode_lock);
465 spin_lock_init(&psb->state_lock);
467 atomic_long_set(&psb->ino, 0);
468 atomic_long_set(&psb->trans, 0);
470 sb->s_fs_info = psb;
471 sb->s_op = &pohmelfs_sb_ops;
472 sb->s_magic = POHMELFS_MAGIC_NUM;
473 sb->s_maxbytes = MAX_LFS_FILESIZE;
474 sb->s_blocksize = PAGE_SIZE;
475 sb->s_bdi = &psb->bdi;
476 sb->s_time_gran = 0;
478 psb->read_wait_timeout = 5000;
479 psb->write_wait_timeout = 5000;
481 psb->sync_timeout = 300;
483 psb->keepalive_cnt = 5;
484 psb->keepalive_interval = 10;
485 psb->keepalive_idle = 30;
487 psb->readdir_allocation = 4;
488 psb->reconnect_timeout = msecs_to_jiffies(30000);
490 psb->sb = sb;
492 psb->hash = crypto_alloc_hash("sha512", 0, CRYPTO_ALG_ASYNC);
493 if (IS_ERR(psb->hash)) {
494 err = PTR_ERR(psb->hash);
495 goto err_out_exit;
498 snprintf(name, sizeof(name), "pohmelfs-%d", psb->bdi_num);
499 psb->wq = alloc_workqueue(name, WQ_HIGHPRI, 0);
500 if (!psb->wq) {
501 err = -ENOMEM;
502 goto err_out_crypto_free;
505 INIT_DELAYED_WORK(&psb->sync_work, pohmelfs_sync);
507 INIT_DELAYED_WORK(&psb->reconnect_work, pohmelfs_reconnect);
508 mutex_init(&psb->reconnect_lock);
509 INIT_LIST_HEAD(&psb->reconnect_list);
510 INIT_LIST_HEAD(&psb->kill_state_list);
512 return 0;
514 err_out_crypto_free:
515 crypto_free_hash(psb->hash);
516 err_out_exit:
517 psb->sb = NULL;
518 sb->s_fs_info = NULL;
519 return err;
522 static int pohmelfs_parse_addr(char *addr, struct sockaddr_storage *a, int *addrlen)
524 int family, port;
525 char *ptr;
526 int err = -EINVAL;
528 ptr = strrchr(addr, ':');
529 if (!ptr)
530 goto err_out_print_wrong_param;
531 *ptr++ = 0;
532 if (!ptr)
533 goto err_out_print_wrong_param;
535 family = simple_strtol(ptr, NULL, 10);
537 ptr = strrchr(addr, ':');
538 if (!ptr)
539 goto err_out_print_wrong_param;
540 *ptr++ = 0;
541 if (!ptr)
542 goto err_out_print_wrong_param;
544 port = simple_strtol(ptr, NULL, 10);
546 if (family == AF_INET) {
547 struct sockaddr_in *sin = (struct sockaddr_in *)a;
549 sin->sin_family = family;
550 sin->sin_port = htons(port);
552 err = in4_pton(addr, strlen(addr), (u8 *)&sin->sin_addr, ':', NULL);
553 *addrlen = sizeof(struct sockaddr_in);
554 } else if (family == AF_INET6) {
555 struct sockaddr_in6 *sin = (struct sockaddr_in6 *)a;
557 sin->sin6_family = family;
558 sin->sin6_port = htons(port);
559 err = in6_pton(addr, strlen(addr), (u8 *)&sin->sin6_addr, ':', NULL);
560 *addrlen = sizeof(struct sockaddr_in6);
561 } else {
562 err = -ENOTSUPP;
565 if (err == 1)
566 err = 0;
567 else if (!err)
568 err = -EINVAL;
570 if (err)
571 goto err_out_print_wrong_param;
573 return 0;
575 err_out_print_wrong_param:
576 pr_err("pohmelfs: %s: wrong addr: '%s', should be 'addr:port:family': %d.\n", __func__, addr, err);
577 return err;
580 static int pohmelfs_option(char *option, char *data, int *lenp, int have_data)
582 int len;
583 char *ptr;
585 if (!strncmp(option, data, strlen(option))) {
586 len = strlen(option);
587 ptr = data + len;
589 if (have_data && (!ptr || !*ptr))
590 return 0;
592 *lenp = len;
593 return 1;
596 return 0;
599 static int pohmelfs_set_groups(struct pohmelfs_sb *psb, char *value, int len)
601 int i, num = 0, start = 0, pos = 0;
602 char *ptr = value;
604 for (i = 0; i < len; ++i) {
605 if (value[i] == ':')
606 start = 0;
607 else if (!start) {
608 start = 1;
609 num++;
613 if (!num) {
614 return -ENOENT;
618 * We do not allow to mess with different group sets for already built filesystem
619 * But to prevent remount from failing, we just pretend that things went the right way
621 if (psb->groups)
622 return 0;
624 psb->groups = kzalloc(sizeof(int) * num, GFP_KERNEL);
625 if (!psb->groups)
626 return -ENOMEM;
627 psb->group_num = num;
629 start = 0;
630 for (i = 0; i < len; ++i) {
631 if (value[i] == ':') {
632 value[i] = '\0';
633 if (start) {
634 psb->groups[pos] = simple_strtol(ptr, NULL, 10);
635 pos++;
636 start = 0;
638 } else if (!start) {
639 ptr = &value[i];
640 start = 1;
644 if (start) {
645 psb->groups[pos] = simple_strtol(ptr, NULL, 10);
646 pos++;
649 return 0;
652 static int pohmelfs_parse_option(struct pohmelfs_sb *psb, char *data)
654 int len;
655 int err = 0;
657 pr_debug("pohmelfs: %s: option: %s\n", __func__, data);
659 if (pohmelfs_option("server=", data, &len, 1)) {
660 int addrlen;
661 char *addr_str = data + len;
662 struct sockaddr_storage sa;
663 struct pohmelfs_state *st;
665 memset(&sa, 0, sizeof(struct sockaddr_storage));
666 err = pohmelfs_parse_addr(addr_str, &sa, &addrlen);
667 if (err)
668 goto err_out_exit;
670 st = pohmelfs_state_create(psb, &sa, addrlen, 1, 0);
671 if (IS_ERR(st)) {
672 err = PTR_ERR(st);
673 if (err != -EEXIST)
674 goto err_out_exit;
675 err = 0;
677 } else if (pohmelfs_option("fsid=", data, &len, 1)) {
678 data += len;
679 len = strlen(data);
681 psb->fsid = kmalloc(len + 1, GFP_KERNEL);
682 if (!psb->fsid) {
683 err = -ENOMEM;
684 goto err_out_exit;
687 snprintf(psb->fsid, len + 1, "%s", data);
688 psb->fsid_len = len;
689 } else if (pohmelfs_option("sync_timeout=", data, &len, 1)) {
690 psb->sync_timeout = simple_strtol(data + len, NULL, 10);
691 } else if (pohmelfs_option("http_compat=", data, &len, 1)) {
692 psb->http_compat = simple_strtol(data + len, NULL, 10);
693 err = pohmelfs_http_compat_init(psb);
694 } else if (pohmelfs_option("groups=", data, &len, 1)) {
695 data += len;
696 len = strlen(data);
698 err = pohmelfs_set_groups(psb, data, len);
699 } else if (pohmelfs_option("noatime", data, &len, 0)) {
700 psb->sb->s_flags |= FS_NOATIME_FL;
701 } else if (pohmelfs_option("relatime", data, &len, 0)) {
702 psb->sb->s_flags |= MS_RELATIME;
703 } else if (pohmelfs_option("noreadcsum", data, &len, 0)) {
704 psb->no_read_csum = 1;
705 } else if (pohmelfs_option("readcsum", data, &len, 0)) {
706 psb->no_read_csum = 0;
707 } else if (pohmelfs_option("successful_write_count=", data, &len, 1)) {
708 psb->successful_write_count = simple_strtol(data + len, NULL, 10);
709 } else if (pohmelfs_option("keepalive_cnt=", data, &len, 1)) {
710 psb->keepalive_cnt = simple_strtol(data + len, NULL, 10);
711 } else if (pohmelfs_option("keepalive_idle=", data, &len, 1)) {
712 psb->keepalive_idle = simple_strtol(data + len, NULL, 10);
713 } else if (pohmelfs_option("keepalive_interval=", data, &len, 1)) {
714 psb->keepalive_interval = simple_strtol(data + len, NULL, 10);
715 } else if (pohmelfs_option("readdir_allocation=", data, &len, 1)) {
716 psb->readdir_allocation = simple_strtol(data + len, NULL, 10);
717 } else if (pohmelfs_option("sync_on_close", data, &len, 0)) {
718 psb->sync_on_close = 1;
719 } else {
720 err = -ENOTSUPP;
723 err_out_exit:
724 return err;
727 static int pohmelfs_parse_options(struct pohmelfs_sb *psb, char *data)
729 int err = -ENOENT;
730 char *ptr, *start;
732 ptr = start = data;
734 while (ptr && *ptr) {
735 if (*ptr == ',') {
736 *ptr = '\0';
737 err = pohmelfs_parse_option(psb, start);
738 if (err)
739 goto err_out_exit;
740 ptr++;
741 if (ptr && *ptr)
742 start = ptr;
744 continue;
747 ptr++;
750 if (start != ptr) {
751 err = pohmelfs_parse_option(psb, start);
752 if (err)
753 goto err_out_exit;
756 err_out_exit:
757 return err;
760 static int pohmelfs_fill_super(struct super_block *sb, void *data, int silent)
762 struct pohmelfs_sb *psb;
763 int err;
765 psb = kzalloc(sizeof(struct pohmelfs_sb), GFP_KERNEL);
766 if (!psb) {
767 err = -ENOMEM;
768 goto err_out_exit;
771 psb->bdi_num = atomic_inc_return(&psb_bdi_num);
773 err = bdi_init(&psb->bdi);
774 if (err)
775 goto err_out_free_psb;
777 psb->bdi.ra_pages = default_backing_dev_info.ra_pages;
779 err = bdi_register(&psb->bdi, NULL, "pfs-%d", psb->bdi_num);
780 if (err) {
781 bdi_destroy(&psb->bdi);
782 goto err_out_free_psb;
785 err = pohmelfs_init_psb(psb, sb);
786 if (err)
787 goto err_out_free_bdi;
789 psb->root = pohmelfs_new_inode(psb, 0755|S_IFDIR);
790 if (IS_ERR(psb->root)) {
791 err = PTR_ERR(psb->root);
792 goto err_out_cleanup_psb;
795 err = pohmelfs_parse_options(psb, data);
796 if (err)
797 goto err_out_put_root;
799 if (!psb->group_num) {
800 err = -EINVAL;
801 pr_err("pohmelfs: you did not specify groups option, which is mandatory\n");
802 goto err_out_put_root;
805 if (!psb->fsid_len) {
806 char str[] = "pohmelfs";
807 err = pohmelfs_hash(psb, str, 8, &psb->root->id);
808 } else {
809 err = pohmelfs_hash(psb, psb->fsid, psb->fsid_len, &psb->root->id);
811 if (err)
812 goto err_out_put_root;
814 psb->root->parent_id = psb->root->id;
816 sb->s_root = d_alloc_root(&psb->root->vfs_inode);
817 if (!sb->s_root) {
818 err = -ENOMEM;
819 goto err_out_put_root;
822 queue_delayed_work(psb->wq, &psb->sync_work, msecs_to_jiffies(psb->sync_timeout * 1000));
823 pohmelfs_stat(psb, 0);
825 return 0;
827 err_out_put_root:
828 iput(&psb->root->vfs_inode);
829 err_out_cleanup_psb:
830 pohmelfs_cleanup_psb(psb);
831 err_out_free_bdi:
832 bdi_destroy(&psb->bdi);
833 err_out_free_psb:
834 kfree(psb);
835 err_out_exit:
836 pr_err("pohmelfs: %s: error: %d\n", __func__, err);
837 return err;
840 static struct dentry *pohmelfs_mount(struct file_system_type *fs_type,
841 int flags, const char *dev_name, void *data)
843 return mount_nodev(fs_type, flags, data, pohmelfs_fill_super);
846 static void pohmelfs_kill_sb(struct super_block *sb)
848 sync_inodes_sb(sb);
849 kill_anon_super(sb);
852 static struct file_system_type pohmelfs_type = {
853 .owner = THIS_MODULE,
854 .name = "pohmelfs",
855 .mount = pohmelfs_mount,
856 .kill_sb = pohmelfs_kill_sb,
859 static void pohmelfs_cleanup_cache(void)
861 kmem_cache_destroy(pohmelfs_trans_cache);
862 kmem_cache_destroy(pohmelfs_inode_cache);
863 kmem_cache_destroy(pohmelfs_inode_info_cache);
864 kmem_cache_destroy(pohmelfs_route_cache);
865 kmem_cache_destroy(pohmelfs_wait_cache);
866 kmem_cache_destroy(pohmelfs_io_cache);
867 kmem_cache_destroy(pohmelfs_inode_info_binary_package_cache);
868 kfree(pohmelfs_scratch_buf);
869 kmem_cache_destroy(pohmelfs_write_cache);
870 kmem_cache_destroy(pohmelfs_dentry_cache);
873 static int pohmelfs_init_cache(void)
875 int err = -ENOMEM;
877 pohmelfs_inode_cache = KMEM_CACHE(pohmelfs_inode, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
878 if (!pohmelfs_inode_cache)
879 goto err_out_exit;
881 pohmelfs_trans_cache = KMEM_CACHE(pohmelfs_trans, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
882 if (!pohmelfs_trans_cache)
883 goto err_out_destroy_inode_cache;
885 pohmelfs_inode_info_cache = KMEM_CACHE(pohmelfs_inode_info, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
886 if (!pohmelfs_inode_info_cache)
887 goto err_out_destroy_trans_cache;
889 pohmelfs_route_cache = KMEM_CACHE(pohmelfs_route, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
890 if (!pohmelfs_route_cache)
891 goto err_out_destroy_inode_info_cache;
893 pohmelfs_wait_cache = KMEM_CACHE(pohmelfs_wait, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
894 if (!pohmelfs_wait_cache)
895 goto err_out_destroy_inode_info_cache;
897 pohmelfs_io_cache = KMEM_CACHE(pohmelfs_io, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
898 if (!pohmelfs_io_cache)
899 goto err_out_destroy_wait_cache;
901 pohmelfs_scratch_buf = kmalloc(pohmelfs_scratch_buf_size, GFP_KERNEL);
902 if (!pohmelfs_scratch_buf) {
903 err = -ENOMEM;
904 goto err_out_destroy_io_cache;
907 pohmelfs_inode_info_binary_package_cache = KMEM_CACHE(pohmelfs_inode_info_binary_package, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
908 if (!pohmelfs_inode_info_binary_package_cache)
909 goto err_out_free_scratch;
911 pohmelfs_write_cache = KMEM_CACHE(pohmelfs_write_ctl, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
912 if (!pohmelfs_write_cache)
913 goto err_out_destroy_inode_info_binary_package_cache;
915 pohmelfs_dentry_cache = KMEM_CACHE(pohmelfs_dentry, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
916 if (!pohmelfs_dentry_cache)
917 goto err_out_destroy_write_cache;
919 return 0;
921 err_out_destroy_write_cache:
922 kmem_cache_destroy(pohmelfs_write_cache);
923 err_out_destroy_inode_info_binary_package_cache:
924 kmem_cache_destroy(pohmelfs_inode_info_binary_package_cache);
925 err_out_free_scratch:
926 kfree(pohmelfs_scratch_buf);
927 err_out_destroy_io_cache:
928 kmem_cache_destroy(pohmelfs_io_cache);
929 err_out_destroy_wait_cache:
930 kmem_cache_destroy(pohmelfs_wait_cache);
931 err_out_destroy_inode_info_cache:
932 kmem_cache_destroy(pohmelfs_inode_info_cache);
933 err_out_destroy_trans_cache:
934 kmem_cache_destroy(pohmelfs_trans_cache);
935 err_out_destroy_inode_cache:
936 kmem_cache_destroy(pohmelfs_inode_cache);
937 err_out_exit:
938 return err;
941 static int __init pohmelfs_init(void)
943 int err;
945 err = pohmelfs_init_cache();
946 if (err)
947 goto err_out_exit;
949 err = register_filesystem(&pohmelfs_type);
950 if (err)
951 goto err_out_cleanup_cache;
953 return 0;
955 err_out_cleanup_cache:
956 pohmelfs_cleanup_cache();
957 err_out_exit:
958 return err;
961 static void __exit pohmelfs_exit(void)
963 unregister_filesystem(&pohmelfs_type);
964 pohmelfs_cleanup_cache();
967 module_init(pohmelfs_init)
968 module_exit(pohmelfs_exit)
970 MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
971 MODULE_DESCRIPTION("POHMELFS");
972 MODULE_LICENSE("GPL");