Added correct statfs support
[pohmelfs.git] / fs / pohmelfs / super.c
blobf4322f35b5fce3e679daa0cfe074996c45e8a8e2
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 static int pohmelfs_statfs(struct dentry *dentry, struct kstatfs *buf)
135 struct super_block *sb = dentry->d_sb;
136 struct pohmelfs_sb *psb = pohmelfs_sb(sb);
137 struct pohmelfs_state *st;
140 * There are no filesystem size limits yet.
142 memset(buf, 0, sizeof(struct kstatfs));
144 buf->f_type = POHMELFS_MAGIC_NUM; /* 'POH.' */
145 buf->f_namelen = 4096;
146 buf->f_files = 0;
147 buf->f_bfree = buf->f_bavail = 0;
148 buf->f_blocks = 0;
150 spin_lock(&psb->state_lock);
151 list_for_each_entry(st, &psb->state_list, state_entry) {
152 buf->f_bsize = sb->s_blocksize;
153 buf->f_frsize = st->frsize;
155 buf->f_blocks += (st->blocks * st->frsize) >> PAGE_SHIFT;
156 buf->f_bfree += (st->bfree * st->bsize) >> PAGE_SHIFT;
157 buf->f_bavail += (st->bavail * st->bsize) >> PAGE_SHIFT;
159 spin_unlock(&psb->state_lock);
161 return 0;
164 static int pohmelfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
166 struct pohmelfs_sb *psb = pohmelfs_sb(vfs->mnt_sb);
168 if (psb->no_read_csum)
169 seq_printf(seq, ",noreadcsum");
170 seq_printf(seq, ",sync_timeout=%ld", psb->sync_timeout);
171 if (psb->fsid)
172 seq_printf(seq, ",fsid=%s", psb->fsid);
173 if (psb->successful_write_count)
174 seq_printf(seq, ",successful_write_count=%d", psb->successful_write_count);
175 seq_printf(seq, ",keepalive_cnt=%d", psb->keepalive_cnt);
176 seq_printf(seq, ",keepalive_interval=%d", psb->keepalive_interval);
177 seq_printf(seq, ",keepalive_idle=%d", psb->keepalive_idle);
178 seq_printf(seq, ",readdir_allocation=%d", psb->readdir_allocation);
179 if (psb->http_compat)
180 seq_printf(seq, ",http_compat=%d", psb->http_compat);
181 if (psb->sync_on_close)
182 seq_printf(seq, ",sync_on_close");
183 return 0;
187 * This is tricky function - inode cache can be shrunk and inode is about to be dropped,
188 * since its last reference is dropped. But then icache can __iget() on this inode and
189 * later iput() it, which will again call ->drop_inode() callback.
191 * So, ->drop_inode() can be called multiple times for single inode without its reintialization
192 * And we better to be ready for this
194 static int pohmelfs_drop_inode(struct inode *inode)
196 struct pohmelfs_inode *pi = pohmelfs_inode(inode);
197 struct pohmelfs_sb *psb = pohmelfs_sb(inode->i_sb);
199 pr_debug("pohmelfs: %s: drop ino: %ld, mapping: %p\n", pohmelfs_dump_id(pi->id.id), inode->i_ino, inode->i_mapping);
201 spin_lock(&psb->inode_lock);
202 if (rb_parent(&pi->node) != &pi->node)
203 rb_erase(&pi->node, &psb->inode_root);
204 rb_init_node(&pi->node);
205 spin_unlock(&psb->inode_lock);
207 return generic_drop_inode(inode);
210 static int pohmelfs_write_inode_complete(struct pohmelfs_trans *t, struct pohmelfs_state *recv)
212 struct dnet_cmd *cmd = &recv->cmd;
213 struct pohmelfs_inode_info_binary_package *bin = t->priv;
214 struct pohmelfs_wait *wait = &bin->wait;
216 if (cmd->flags & DNET_FLAGS_MORE)
217 return 0;
219 wait->condition = cmd->status;
220 if (!wait->condition)
221 wait->condition = 1;
222 wake_up(&wait->wq);
224 return 0;
227 static int pohmelfs_write_inode_init(struct pohmelfs_trans *t)
229 struct pohmelfs_inode_info_binary_package *bin = t->priv;
231 kref_get(&bin->wait.refcnt);
232 return 0;
235 static void pohmelfs_write_inode_release(struct kref *kref)
237 struct pohmelfs_wait *wait = container_of(kref, struct pohmelfs_wait, refcnt);
238 struct pohmelfs_inode_info_binary_package *bin = container_of(wait, struct pohmelfs_inode_info_binary_package, wait);
240 iput(&bin->wait.pi->vfs_inode);
241 kmem_cache_free(pohmelfs_inode_info_binary_package_cache, bin);
244 static void pohmelfs_write_inode_destroy(struct pohmelfs_trans *t)
246 struct pohmelfs_inode_info_binary_package *bin = t->priv;
249 * We own this pointer - it points to &bin->info
250 * Zero it here to prevent pohmelfs_trans_release() from freeing it
252 t->data = NULL;
254 kref_put(&bin->wait.refcnt, pohmelfs_write_inode_release);
257 static int pohmelfs_write_inode(struct inode *inode, struct writeback_control *wbc)
259 struct pohmelfs_inode *pi = pohmelfs_inode(inode);
260 struct pohmelfs_inode_info_binary_package *bin;
261 struct pohmelfs_sb *psb = pohmelfs_sb(inode->i_sb);
262 struct pohmelfs_io *pio;
263 int sync = 0;
264 long ret;
265 int err;
267 if (wbc)
268 sync = wbc->sync_mode == WB_SYNC_ALL;
270 pio = kmem_cache_zalloc(pohmelfs_io_cache, GFP_NOIO);
271 if (!pio) {
272 err = -ENOMEM;
273 goto err_out_exit;
276 bin = kmem_cache_zalloc(pohmelfs_inode_info_binary_package_cache, GFP_NOIO);
277 if (!bin) {
278 err = -ENOMEM;
279 goto err_out_free_pio;
282 pohmelfs_fill_inode_info(inode, &bin->info);
283 err = pohmelfs_wait_init(&bin->wait, pi);
284 if (err)
285 goto err_out_put_bin;
287 pio->pi = pi;
288 pio->id = &pi->id;
289 pio->cmd = DNET_CMD_WRITE;
290 pio->offset = 0;
291 pio->size = sizeof(struct pohmelfs_inode_info);
292 pio->cflags = DNET_FLAGS_NEED_ACK;
293 pio->priv = bin;
294 pio->type = 3;
296 pio->data = &bin->info;
297 pio->alloc_flags = POHMELFS_IO_OWN;
299 pio->cb.complete = pohmelfs_write_inode_complete;
300 pio->cb.init = pohmelfs_write_inode_init;
301 pio->cb.destroy = pohmelfs_write_inode_destroy;
303 err = pohmelfs_send_io(pio);
304 if (err)
305 goto err_out_put_bin;
307 if (sync) {
308 struct pohmelfs_wait *wait = &bin->wait;
310 ret = wait_event_interruptible_timeout(wait->wq,
311 wait->condition != 0 && atomic_read(&wait->refcnt.refcount) <= 2,
312 msecs_to_jiffies(psb->write_wait_timeout));
313 if (ret <= 0) {
314 err = ret;
315 if (ret == 0)
316 err = -ETIMEDOUT;
317 goto err_out_put_bin;
320 if (wait->condition < 0) {
321 err = wait->condition;
322 goto err_out_put_bin;
326 err_out_put_bin:
327 kref_put(&bin->wait.refcnt, pohmelfs_write_inode_release);
328 err_out_free_pio:
329 kmem_cache_free(pohmelfs_io_cache, pio);
330 err_out_exit:
331 return err;
334 static int pohmelfs_parse_options(struct pohmelfs_sb *psb, char *data);
336 static int pohmelfs_remount_fs(struct super_block *sb, int *flags, char *data)
338 struct pohmelfs_sb *psb = pohmelfs_sb(sb);
340 return pohmelfs_parse_options(psb, data);
343 static const struct super_operations pohmelfs_sb_ops = {
344 .alloc_inode = pohmelfs_alloc_inode,
345 .destroy_inode = pohmelfs_destroy_inode,
346 .drop_inode = pohmelfs_drop_inode,
347 .write_inode = pohmelfs_write_inode,
348 .put_super = pohmelfs_put_super,
349 .show_options = pohmelfs_show_options,
350 .statfs = pohmelfs_statfs,
351 .remount_fs = pohmelfs_remount_fs,
354 static void pohmelfs_sync(struct work_struct *work)
356 struct pohmelfs_sb *psb = container_of(to_delayed_work(work), struct pohmelfs_sb, sync_work);
357 struct super_block *sb = psb->sb;
359 down_read(&sb->s_umount);
360 sync_filesystem(sb);
361 up_read(&sb->s_umount);
363 queue_delayed_work(psb->wq, &psb->sync_work, msecs_to_jiffies(psb->sync_timeout * 1000));
364 pohmelfs_stat(psb, 0);
367 static void pohmelfs_reconnect(struct work_struct *work)
369 struct pohmelfs_sb *psb = container_of(to_delayed_work(work), struct pohmelfs_sb, reconnect_work);
370 struct pohmelfs_reconnect *r, *tmp;
371 struct pohmelfs_state *st, *stmp;
372 LIST_HEAD(head);
373 int err;
375 mutex_lock(&psb->reconnect_lock);
376 list_for_each_entry_safe(r, tmp, &psb->reconnect_list, reconnect_entry) {
377 st = pohmelfs_state_create(psb, &r->sa, r->addrlen, 1, r->group_id);
378 if (IS_ERR(st)) {
379 err = PTR_ERR(st);
381 if (err != -EEXIST)
382 continue;
383 } else {
384 pohmelfs_print_addr(&st->sa, "reconnected\n");
387 list_del(&r->reconnect_entry);
388 kfree(r);
390 mutex_unlock(&psb->reconnect_lock);
392 spin_lock(&psb->state_lock);
393 list_for_each_entry_safe(st, stmp, &psb->kill_state_list, state_entry) {
394 list_move(&st->state_entry, &head);
396 spin_unlock(&psb->state_lock);
398 list_for_each_entry_safe(st, stmp, &head, state_entry) {
399 list_del_init(&st->state_entry);
400 pohmelfs_state_kill(st);
403 if (!list_empty(&psb->reconnect_list))
404 queue_delayed_work(psb->wq, &psb->reconnect_work, psb->reconnect_timeout);
407 static int pohmelfs_init_psb(struct pohmelfs_sb *psb, struct super_block *sb)
409 int err;
410 char name[16];
412 INIT_LIST_HEAD(&psb->state_list);
413 psb->route_root = RB_ROOT;
415 psb->inode_root = RB_ROOT;
416 spin_lock_init(&psb->inode_lock);
418 spin_lock_init(&psb->state_lock);
420 atomic_long_set(&psb->ino, 0);
421 atomic_long_set(&psb->trans, 0);
423 sb->s_fs_info = psb;
424 sb->s_op = &pohmelfs_sb_ops;
425 sb->s_magic = POHMELFS_MAGIC_NUM;
426 sb->s_maxbytes = MAX_LFS_FILESIZE;
427 sb->s_blocksize = PAGE_SIZE;
428 sb->s_bdi = &psb->bdi;
429 sb->s_time_gran = 0;
431 psb->read_wait_timeout = 5000;
432 psb->write_wait_timeout = 5000;
434 psb->sync_timeout = 300;
436 psb->keepalive_cnt = 5;
437 psb->keepalive_interval = 10;
438 psb->keepalive_idle = 30;
440 psb->readdir_allocation = 4;
441 psb->reconnect_timeout = msecs_to_jiffies(30000);
443 psb->sb = sb;
445 psb->hash = crypto_alloc_hash("sha512", 0, CRYPTO_ALG_ASYNC);
446 if (IS_ERR(psb->hash)) {
447 err = PTR_ERR(psb->hash);
448 goto err_out_exit;
451 snprintf(name, sizeof(name), "pohmelfs-%d", psb->bdi_num);
452 psb->wq = alloc_workqueue(name, WQ_NON_REENTRANT | WQ_UNBOUND | WQ_FREEZABLE | WQ_MEM_RECLAIM, 0);
453 if (!psb->wq) {
454 err = -ENOMEM;
455 goto err_out_crypto_free;
458 INIT_DELAYED_WORK(&psb->sync_work, pohmelfs_sync);
460 INIT_DELAYED_WORK(&psb->reconnect_work, pohmelfs_reconnect);
461 mutex_init(&psb->reconnect_lock);
462 INIT_LIST_HEAD(&psb->reconnect_list);
463 INIT_LIST_HEAD(&psb->kill_state_list);
465 return 0;
467 err_out_crypto_free:
468 crypto_free_hash(psb->hash);
469 err_out_exit:
470 psb->sb = NULL;
471 sb->s_fs_info = NULL;
472 return err;
475 static int pohmelfs_parse_addr(char *addr, struct sockaddr_storage *a, int *addrlen)
477 int family, port;
478 char *ptr;
479 int err = -EINVAL;
481 ptr = strrchr(addr, ':');
482 if (!ptr)
483 goto err_out_print_wrong_param;
484 *ptr++ = 0;
485 if (!ptr)
486 goto err_out_print_wrong_param;
488 family = simple_strtol(ptr, NULL, 10);
490 ptr = strrchr(addr, ':');
491 if (!ptr)
492 goto err_out_print_wrong_param;
493 *ptr++ = 0;
494 if (!ptr)
495 goto err_out_print_wrong_param;
497 port = simple_strtol(ptr, NULL, 10);
499 if (family == AF_INET) {
500 struct sockaddr_in *sin = (struct sockaddr_in *)a;
502 sin->sin_family = family;
503 sin->sin_port = htons(port);
505 err = in4_pton(addr, strlen(addr), (u8 *)&sin->sin_addr, ':', NULL);
506 *addrlen = sizeof(struct sockaddr_in);
507 } else if (family == AF_INET6) {
508 struct sockaddr_in6 *sin = (struct sockaddr_in6 *)a;
510 sin->sin6_family = family;
511 sin->sin6_port = htons(port);
512 err = in6_pton(addr, strlen(addr), (u8 *)&sin->sin6_addr, ':', NULL);
513 *addrlen = sizeof(struct sockaddr_in6);
514 } else {
515 err = -ENOTSUPP;
518 if (err == 1)
519 err = 0;
520 else if (!err)
521 err = -EINVAL;
523 if (err)
524 goto err_out_print_wrong_param;
526 return 0;
528 err_out_print_wrong_param:
529 pr_err("pohmelfs: %s: wrong addr: '%s', should be 'addr:port:family': %d.\n", __func__, addr, err);
530 return err;
533 static int pohmelfs_option(char *option, char *data, int *lenp, int have_data)
535 int len;
536 char *ptr;
538 if (!strncmp(option, data, strlen(option))) {
539 len = strlen(option);
540 ptr = data + len;
542 if (have_data && (!ptr || !*ptr))
543 return 0;
545 *lenp = len;
546 return 1;
549 return 0;
552 static int pohmelfs_set_groups(struct pohmelfs_sb *psb, char *value, int len)
554 int i, num = 0, start = 0, pos = 0;
555 char *ptr = value;
557 for (i = 0; i < len; ++i) {
558 if (value[i] == ':')
559 start = 0;
560 else if (!start) {
561 start = 1;
562 num++;
566 if (!num) {
567 return -ENOENT;
570 psb->groups = kzalloc(sizeof(int) * num, GFP_KERNEL);
571 if (!psb->groups)
572 return -ENOMEM;
573 psb->group_num = num;
575 start = 0;
576 for (i = 0; i < len; ++i) {
577 if (value[i] == ':') {
578 value[i] = '\0';
579 if (start) {
580 psb->groups[pos] = simple_strtol(ptr, NULL, 10);
581 pos++;
582 start = 0;
584 } else if (!start) {
585 ptr = &value[i];
586 start = 1;
590 if (start) {
591 psb->groups[pos] = simple_strtol(ptr, NULL, 10);
592 pos++;
595 return 0;
598 static int pohmelfs_parse_option(struct pohmelfs_sb *psb, char *data)
600 int len;
601 int err = 0;
603 pr_debug("pohmelfs: %s: option: %s\n", __func__, data);
605 if (pohmelfs_option("server=", data, &len, 1)) {
606 int addrlen;
607 char *addr_str = data + len;
608 struct sockaddr_storage sa;
609 struct pohmelfs_state *st;
611 memset(&sa, 0, sizeof(struct sockaddr_storage));
612 err = pohmelfs_parse_addr(addr_str, &sa, &addrlen);
613 if (err)
614 goto err_out_exit;
616 st = pohmelfs_state_create(psb, &sa, addrlen, 1, 0);
617 if (IS_ERR(st)) {
618 err = PTR_ERR(st);
619 if (err != -EEXIST)
620 goto err_out_exit;
621 err = 0;
623 } else if (pohmelfs_option("fsid=", data, &len, 1)) {
624 data += len;
625 len = strlen(data);
627 psb->fsid = kmalloc(len + 1, GFP_KERNEL);
628 if (!psb->fsid) {
629 err = -ENOMEM;
630 goto err_out_exit;
633 snprintf(psb->fsid, len + 1, "%s", data);
634 psb->fsid_len = len;
635 } else if (pohmelfs_option("sync_timeout=", data, &len, 1)) {
636 psb->sync_timeout = simple_strtol(data + len, NULL, 10);
637 } else if (pohmelfs_option("http_compat=", data, &len, 1)) {
638 psb->http_compat = simple_strtol(data + len, NULL, 10);
639 err = pohmelfs_http_compat_init(psb);
640 } else if (pohmelfs_option("groups=", data, &len, 1)) {
641 data += len;
642 len = strlen(data);
644 err = pohmelfs_set_groups(psb, data, len);
645 } else if (pohmelfs_option("noatime", data, &len, 0)) {
646 psb->sb->s_flags |= FS_NOATIME_FL;
647 } else if (pohmelfs_option("relatime", data, &len, 0)) {
648 psb->sb->s_flags |= MS_RELATIME;
649 } else if (pohmelfs_option("noreadcsum", data, &len, 0)) {
650 psb->no_read_csum = 1;
651 } else if (pohmelfs_option("readcsum", data, &len, 0)) {
652 psb->no_read_csum = 0;
653 } else if (pohmelfs_option("successful_write_count=", data, &len, 1)) {
654 psb->successful_write_count = simple_strtol(data + len, NULL, 10);
655 } else if (pohmelfs_option("keepalive_cnt=", data, &len, 1)) {
656 psb->keepalive_cnt = simple_strtol(data + len, NULL, 10);
657 } else if (pohmelfs_option("keepalive_idle=", data, &len, 1)) {
658 psb->keepalive_idle = simple_strtol(data + len, NULL, 10);
659 } else if (pohmelfs_option("keepalive_interval=", data, &len, 1)) {
660 psb->keepalive_interval = simple_strtol(data + len, NULL, 10);
661 } else if (pohmelfs_option("readdir_allocation=", data, &len, 1)) {
662 psb->readdir_allocation = simple_strtol(data + len, NULL, 10);
663 } else if (pohmelfs_option("sync_on_close", data, &len, 0)) {
664 psb->sync_on_close = 1;
665 } else {
666 err = -ENOTSUPP;
669 err_out_exit:
670 return err;
673 static int pohmelfs_parse_options(struct pohmelfs_sb *psb, char *data)
675 int err = -ENOENT;
676 char *ptr, *start;
678 ptr = start = data;
680 while (ptr && *ptr) {
681 if (*ptr == ',') {
682 *ptr = '\0';
683 err = pohmelfs_parse_option(psb, start);
684 if (err)
685 goto err_out_exit;
686 ptr++;
687 if (ptr && *ptr)
688 start = ptr;
690 continue;
693 ptr++;
696 if (start != ptr) {
697 err = pohmelfs_parse_option(psb, start);
698 if (err)
699 goto err_out_exit;
702 err_out_exit:
703 return err;
706 static int pohmelfs_fill_super(struct super_block *sb, void *data, int silent)
708 struct pohmelfs_sb *psb;
709 int err;
711 psb = kzalloc(sizeof(struct pohmelfs_sb), GFP_KERNEL);
712 if (!psb) {
713 err = -ENOMEM;
714 goto err_out_exit;
717 psb->bdi_num = atomic_inc_return(&psb_bdi_num);
719 err = bdi_init(&psb->bdi);
720 if (err)
721 goto err_out_free_psb;
723 psb->bdi.ra_pages = default_backing_dev_info.ra_pages;
725 err = bdi_register(&psb->bdi, NULL, "pfs-%d", psb->bdi_num);
726 if (err) {
727 bdi_destroy(&psb->bdi);
728 goto err_out_free_psb;
731 err = pohmelfs_init_psb(psb, sb);
732 if (err)
733 goto err_out_free_bdi;
735 psb->root = pohmelfs_new_inode(psb, 0755|S_IFDIR);
736 if (IS_ERR(psb->root)) {
737 err = PTR_ERR(psb->root);
738 goto err_out_cleanup_psb;
741 err = pohmelfs_parse_options(psb, data);
742 if (err)
743 goto err_out_put_root;
745 if (!psb->group_num) {
746 err = -EINVAL;
747 pr_err("pohmelfs: you did not specify groups option, which is mandatory\n");
748 goto err_out_put_root;
751 if (!psb->fsid_len) {
752 char str[] = "pohmelfs";
753 err = pohmelfs_hash(psb, str, 8, &psb->root->id);
754 } else {
755 err = pohmelfs_hash(psb, psb->fsid, psb->fsid_len, &psb->root->id);
757 if (err)
758 goto err_out_put_root;
760 psb->root->parent_id = psb->root->id;
762 sb->s_root = d_alloc_root(&psb->root->vfs_inode);
763 if (!sb->s_root) {
764 err = -ENOMEM;
765 goto err_out_put_root;
768 queue_delayed_work(psb->wq, &psb->sync_work, msecs_to_jiffies(psb->sync_timeout * 1000));
769 pohmelfs_stat(psb, 0);
771 return 0;
773 err_out_put_root:
774 iput(&psb->root->vfs_inode);
775 err_out_cleanup_psb:
776 pohmelfs_cleanup_psb(psb);
777 err_out_free_bdi:
778 bdi_destroy(&psb->bdi);
779 err_out_free_psb:
780 kfree(psb);
781 err_out_exit:
782 pr_err("pohmelfs: %s: error: %d\n", __func__, err);
783 return err;
786 static struct dentry *pohmelfs_mount(struct file_system_type *fs_type,
787 int flags, const char *dev_name, void *data)
789 return mount_nodev(fs_type, flags, data, pohmelfs_fill_super);
792 static void pohmelfs_kill_sb(struct super_block *sb)
794 sync_inodes_sb(sb);
795 kill_anon_super(sb);
798 static struct file_system_type pohmelfs_type = {
799 .owner = THIS_MODULE,
800 .name = "pohmelfs",
801 .mount = pohmelfs_mount,
802 .kill_sb = pohmelfs_kill_sb,
805 static void pohmelfs_cleanup_cache(void)
807 kmem_cache_destroy(pohmelfs_trans_cache);
808 kmem_cache_destroy(pohmelfs_inode_cache);
809 kmem_cache_destroy(pohmelfs_inode_info_cache);
810 kmem_cache_destroy(pohmelfs_route_cache);
811 kmem_cache_destroy(pohmelfs_wait_cache);
812 kmem_cache_destroy(pohmelfs_io_cache);
813 kmem_cache_destroy(pohmelfs_inode_info_binary_package_cache);
814 kfree(pohmelfs_scratch_buf);
815 kmem_cache_destroy(pohmelfs_write_cache);
816 kmem_cache_destroy(pohmelfs_dentry_cache);
819 static int pohmelfs_init_cache(void)
821 int err = -ENOMEM;
823 pohmelfs_inode_cache = KMEM_CACHE(pohmelfs_inode, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
824 if (!pohmelfs_inode_cache)
825 goto err_out_exit;
827 pohmelfs_trans_cache = KMEM_CACHE(pohmelfs_trans, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
828 if (!pohmelfs_trans_cache)
829 goto err_out_destroy_inode_cache;
831 pohmelfs_inode_info_cache = KMEM_CACHE(pohmelfs_inode_info, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
832 if (!pohmelfs_inode_info_cache)
833 goto err_out_destroy_trans_cache;
835 pohmelfs_route_cache = KMEM_CACHE(pohmelfs_route, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
836 if (!pohmelfs_route_cache)
837 goto err_out_destroy_inode_info_cache;
839 pohmelfs_wait_cache = KMEM_CACHE(pohmelfs_wait, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
840 if (!pohmelfs_wait_cache)
841 goto err_out_destroy_inode_info_cache;
843 pohmelfs_io_cache = KMEM_CACHE(pohmelfs_io, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
844 if (!pohmelfs_io_cache)
845 goto err_out_destroy_wait_cache;
847 pohmelfs_scratch_buf = kmalloc(pohmelfs_scratch_buf_size, GFP_KERNEL);
848 if (!pohmelfs_scratch_buf) {
849 err = -ENOMEM;
850 goto err_out_destroy_io_cache;
853 pohmelfs_inode_info_binary_package_cache = KMEM_CACHE(pohmelfs_inode_info_binary_package, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
854 if (!pohmelfs_inode_info_binary_package_cache)
855 goto err_out_free_scratch;
857 pohmelfs_write_cache = KMEM_CACHE(pohmelfs_write_ctl, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
858 if (!pohmelfs_write_cache)
859 goto err_out_destroy_inode_info_binary_package_cache;
861 pohmelfs_dentry_cache = KMEM_CACHE(pohmelfs_dentry, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
862 if (!pohmelfs_dentry_cache)
863 goto err_out_destroy_write_cache;
865 return 0;
867 err_out_destroy_write_cache:
868 kmem_cache_destroy(pohmelfs_write_cache);
869 err_out_destroy_inode_info_binary_package_cache:
870 kmem_cache_destroy(pohmelfs_inode_info_binary_package_cache);
871 err_out_free_scratch:
872 kfree(pohmelfs_scratch_buf);
873 err_out_destroy_io_cache:
874 kmem_cache_destroy(pohmelfs_io_cache);
875 err_out_destroy_wait_cache:
876 kmem_cache_destroy(pohmelfs_wait_cache);
877 err_out_destroy_inode_info_cache:
878 kmem_cache_destroy(pohmelfs_inode_info_cache);
879 err_out_destroy_trans_cache:
880 kmem_cache_destroy(pohmelfs_trans_cache);
881 err_out_destroy_inode_cache:
882 kmem_cache_destroy(pohmelfs_inode_cache);
883 err_out_exit:
884 return err;
887 static int __init pohmelfs_init(void)
889 int err;
891 err = pohmelfs_init_cache();
892 if (err)
893 goto err_out_exit;
895 err = register_filesystem(&pohmelfs_type);
896 if (err)
897 goto err_out_cleanup_cache;
899 return 0;
901 err_out_cleanup_cache:
902 pohmelfs_cleanup_cache();
903 err_out_exit:
904 return err;
907 static void __exit pohmelfs_exit(void)
909 unregister_filesystem(&pohmelfs_type);
910 pohmelfs_cleanup_cache();
913 module_init(pohmelfs_init)
914 module_exit(pohmelfs_exit)
916 MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
917 MODULE_DESCRIPTION("POHMELFS");
918 MODULE_LICENSE("GPL");