pohmelfs: Use current logging styles.
[pohmelfs.git] / fs / pohmelfs / super.c
blobc719937f6d41bb030681ceca84e852dcb886ce46
1 /*
2 * Copyright (C) 2011+ Evgeniy Polyakov <zbr@ioremap.net>
3 */
5 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
7 #include <linux/module.h>
8 #include <linux/string.h>
9 #include <linux/fs.h>
10 #include <linux/slab.h>
11 #include <linux/inet.h>
12 #include <linux/init.h>
13 #include <linux/in.h>
14 #include <linux/in6.h>
15 #include <linux/blkdev.h>
16 #include <linux/parser.h>
17 #include <linux/random.h>
18 #include <linux/buffer_head.h>
19 #include <linux/exportfs.h>
20 #include <linux/vfs.h>
21 #include <linux/seq_file.h>
22 #include <linux/mount.h>
23 #include <linux/quotaops.h>
24 #include <asm/uaccess.h>
26 #include "pohmelfs.h"
28 #define POHMELFS_MAGIC_NUM 0x504f482e
30 struct kmem_cache *pohmelfs_inode_cache;
31 struct kmem_cache *pohmelfs_trans_cache;
32 struct kmem_cache *pohmelfs_inode_info_cache;
33 struct kmem_cache *pohmelfs_route_cache;
34 struct kmem_cache *pohmelfs_wait_cache;
35 struct kmem_cache *pohmelfs_io_cache;
36 struct kmem_cache *pohmelfs_inode_info_binary_package_cache;
37 struct kmem_cache *pohmelfs_write_cache;
38 struct kmem_cache *pohmelfs_dentry_cache;
40 static atomic_t psb_bdi_num = ATOMIC_INIT(0);
42 static void pohmelfs_http_compat_cleanup(struct pohmelfs_sb *psb)
44 struct pohmelfs_path *p;
45 int i;
47 for (i = 0; i < psb->http_compat; ++i) {
48 p = &psb->path[i];
50 mutex_destroy(&p->lock);
51 kfree(p->data);
55 static int pohmelfs_http_compat_init(struct pohmelfs_sb *psb)
57 int i, err;
58 struct pohmelfs_path *path, *p;
60 path = kmalloc(psb->http_compat * sizeof(struct pohmelfs_path), GFP_KERNEL);
61 if (!path) {
62 err = -ENOMEM;
63 goto err_out_exit;
66 for (i = 0; i < psb->http_compat; ++i) {
67 p = &path[i];
69 mutex_init(&p->lock);
71 p->data = kmalloc(PAGE_SIZE, GFP_KERNEL);
72 if (!p->data) {
73 err = -ENOMEM;
74 goto err_out_free;
78 psb->path = path;
79 return 0;
81 err_out_free:
82 while (--i >= 0) {
83 p = &path[i];
85 mutex_destroy(&p->lock);
86 kfree(p->data);
89 kfree(path);
90 err_out_exit:
91 psb->http_compat = 0;
92 return err;
95 static void pohmelfs_cleanup_psb(struct pohmelfs_sb *psb)
97 struct pohmelfs_addr *a, *tmp;
99 psb->need_exit = 1;
100 cancel_delayed_work(&psb->sync_work);
101 destroy_workqueue(psb->wq);
103 pohmelfs_pool_clean(psb->conn, psb->conn_num);
105 list_for_each_entry_safe(a, tmp, &psb->addr_list, addr_entry) {
106 list_del(&a->addr_entry);
107 kfree(a);
110 crypto_free_hash(psb->hash);
112 pohmelfs_http_compat_cleanup(psb);
114 kfree(psb->groups);
115 kfree(psb->fsid);
118 static void pohmelfs_put_super(struct super_block *sb)
120 struct pohmelfs_sb *psb = pohmelfs_sb(sb);
122 pohmelfs_cleanup_psb(psb);
123 bdi_destroy(&psb->bdi);
126 struct pohmelfs_size {
127 int group_id;
128 uint64_t bsize; /* Block size */
129 uint64_t frsize; /* Fragment size */
130 uint64_t blocks; /* Filesystem size in frsize units */
131 uint64_t bfree; /* # free blocks */
132 uint64_t bavail; /* # free blocks for non-root */
135 static int pohmelfs_statfs(struct dentry *dentry, struct kstatfs *buf)
137 struct super_block *sb = dentry->d_sb;
138 struct pohmelfs_sb *psb = pohmelfs_sb(sb);
139 struct pohmelfs_connection *c;
140 struct pohmelfs_state *st;
141 struct pohmelfs_size *sz;
142 uint64_t min_size = ~0ULL;
143 int pos = -1;
144 int err, i;
146 sz = kzalloc(psb->group_num * sizeof(struct pohmelfs_size), GFP_KERNEL);
147 if (!sz) {
148 err = -ENOMEM;
149 goto err_out_exit;
152 for (i = 0; i < psb->group_num; ++i) {
153 sz[i].group_id = psb->groups[i];
156 memset(buf, 0, sizeof(struct kstatfs));
158 buf->f_type = POHMELFS_MAGIC_NUM; /* 'POH.' */
159 buf->f_namelen = 4096;
160 buf->f_files = 0;
161 buf->f_bfree = buf->f_bavail = buf->f_blocks = 0;
163 mutex_lock(&psb->conn_lock);
164 c = &psb->conn[0];
166 spin_lock(&c->state_lock);
167 list_for_each_entry(st, &c->state_list, state_entry) {
168 for (i = 0; i < psb->group_num; ++i) {
169 if (sz[i].group_id == st->group_id) {
170 sz[i].bsize = sb->s_blocksize;
171 sz[i].frsize = st->frsize;
172 sz[i].blocks += (st->blocks * st->frsize) >> PAGE_SHIFT;
173 sz[i].bfree += (st->bfree * st->bsize) >> PAGE_SHIFT;
174 sz[i].bavail += (st->bavail * st->bsize) >> PAGE_SHIFT;
175 break;
181 spin_unlock(&c->state_lock);
182 mutex_unlock(&psb->conn_lock);
184 for (i = 0; i < psb->group_num; ++i) {
185 /* skip empty groups */
186 if (sz[i].blocks && (sz[i].bavail < min_size)) {
187 min_size = sz[i].bavail;
188 pos = i;
192 if (pos == -1) {
193 buf->f_bfree = buf->f_bavail = buf->f_blocks = ~0ULL >> PAGE_SHIFT;
194 } else {
195 buf->f_bsize = sz[pos].bsize;
196 buf->f_frsize = sz[pos].frsize;
197 buf->f_blocks = sz[pos].blocks;
198 buf->f_bavail = sz[pos].bfree;
199 buf->f_bfree = sz[pos].bavail;
202 kfree(sz);
203 err = 0;
205 err_out_exit:
206 return err;
209 #if 0
210 static int pohmelfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
212 struct pohmelfs_sb *psb = pohmelfs_sb(vfs->mnt_sb);
213 #else
214 static int pohmelfs_show_options(struct seq_file *seq, struct dentry *dentry)
216 struct pohmelfs_sb *psb = pohmelfs_sb(dentry->d_inode->i_sb);
217 #endif
218 struct pohmelfs_addr *a;
220 mutex_lock(&psb->conn_lock);
221 list_for_each_entry(a, &psb->addr_list, addr_entry) {
222 struct sockaddr *sa = (struct sockaddr *)&a->sa;
223 if (sa->sa_family == AF_INET) {
224 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
225 seq_printf(seq, ",server=%pI4:%d:2", &sin->sin_addr.s_addr, ntohs(sin->sin_port));
226 } else if (sa->sa_family == AF_INET6) {
227 struct sockaddr_in6 *sin = (struct sockaddr_in6 *)sa;
228 seq_printf(seq, ",server=%pI6:%d:6", &sin->sin6_addr.s6_addr, ntohs(sin->sin6_port));
231 mutex_unlock(&psb->conn_lock);
233 if (psb->no_read_csum)
234 seq_printf(seq, ",noreadcsum");
235 seq_printf(seq, ",sync_timeout=%ld", psb->sync_timeout);
236 if (psb->fsid)
237 seq_printf(seq, ",fsid=%s", psb->fsid);
238 if (psb->successful_write_count)
239 seq_printf(seq, ",successful_write_count=%d", psb->successful_write_count);
240 seq_printf(seq, ",keepalive_cnt=%d", psb->keepalive_cnt);
241 seq_printf(seq, ",keepalive_interval=%d", psb->keepalive_interval);
242 seq_printf(seq, ",keepalive_idle=%d", psb->keepalive_idle);
243 seq_printf(seq, ",readdir_allocation=%d", psb->readdir_allocation);
244 if (psb->http_compat)
245 seq_printf(seq, ",http_compat=%d", psb->http_compat);
246 if (psb->sync_on_close)
247 seq_printf(seq, ",sync_on_close");
248 seq_printf(seq, ",connection_pool_size=%d", psb->conn_num);
249 seq_printf(seq, ",read_wait_timeout=%ld", psb->read_wait_timeout);
250 seq_printf(seq, ",write_wait_timeout=%ld", psb->write_wait_timeout);
251 return 0;
255 * This is tricky function - inode cache can be shrunk and inode is about to be dropped,
256 * since its last reference is dropped. But then icache can __iget() on this inode and
257 * later iput() it, which will again call ->drop_inode() callback.
259 * So, ->drop_inode() can be called multiple times for single inode without its reintialization
260 * And we better to be ready for this
262 static int pohmelfs_drop_inode(struct inode *inode)
264 struct pohmelfs_inode *pi = pohmelfs_inode(inode);
265 struct pohmelfs_sb *psb = pohmelfs_sb(inode->i_sb);
267 pr_debug("%s: %ld, mapping: %p\n",
268 pohmelfs_dump_id(pi->id.id), inode->i_ino, inode->i_mapping);
270 spin_lock(&psb->inode_lock);
271 if (rb_parent(&pi->node) != &pi->node)
272 rb_erase(&pi->node, &psb->inode_root);
273 rb_init_node(&pi->node);
274 spin_unlock(&psb->inode_lock);
276 return generic_drop_inode(inode);
279 static int pohmelfs_write_inode_complete(struct pohmelfs_trans *t, struct pohmelfs_state *recv)
281 struct dnet_cmd *cmd = &recv->cmd;
282 struct pohmelfs_inode_info_binary_package *bin = t->priv;
283 struct pohmelfs_wait *wait = &bin->wait;
285 if (cmd->flags & DNET_FLAGS_MORE)
286 return 0;
288 wait->condition = cmd->status;
289 if (!wait->condition)
290 wait->condition = 1;
291 wake_up(&wait->wq);
293 return 0;
296 static int pohmelfs_write_inode_init(struct pohmelfs_trans *t)
298 struct pohmelfs_inode_info_binary_package *bin = t->priv;
300 kref_get(&bin->wait.refcnt);
301 return 0;
304 static void pohmelfs_write_inode_release(struct kref *kref)
306 struct pohmelfs_wait *wait = container_of(kref, struct pohmelfs_wait, refcnt);
307 struct pohmelfs_inode_info_binary_package *bin = container_of(wait, struct pohmelfs_inode_info_binary_package, wait);
309 iput(&bin->wait.pi->vfs_inode);
310 kmem_cache_free(pohmelfs_inode_info_binary_package_cache, bin);
313 static void pohmelfs_write_inode_destroy(struct pohmelfs_trans *t)
315 struct pohmelfs_inode_info_binary_package *bin = t->priv;
318 * We own this pointer - it points to &bin->info
319 * Zero it here to prevent pohmelfs_trans_release() from freeing it
321 t->data = NULL;
323 kref_put(&bin->wait.refcnt, pohmelfs_write_inode_release);
326 static int pohmelfs_write_inode(struct inode *inode, struct writeback_control *wbc)
328 struct pohmelfs_inode *pi = pohmelfs_inode(inode);
329 struct pohmelfs_inode_info_binary_package *bin;
330 struct pohmelfs_sb *psb = pohmelfs_sb(inode->i_sb);
331 struct pohmelfs_io *pio;
332 int sync = 0;
333 long ret;
334 int err;
336 if (wbc)
337 sync = wbc->sync_mode == WB_SYNC_ALL;
339 pio = kmem_cache_zalloc(pohmelfs_io_cache, GFP_NOIO);
340 if (!pio) {
341 err = -ENOMEM;
342 goto err_out_exit;
345 bin = kmem_cache_zalloc(pohmelfs_inode_info_binary_package_cache, GFP_NOIO);
346 if (!bin) {
347 err = -ENOMEM;
348 goto err_out_free_pio;
351 pohmelfs_fill_inode_info(inode, &bin->info);
352 err = pohmelfs_wait_init(&bin->wait, pi);
353 if (err)
354 goto err_out_put_bin;
356 pio->pi = pi;
357 pio->id = &pi->id;
358 pio->cmd = DNET_CMD_WRITE;
359 pio->offset = 0;
360 pio->size = sizeof(struct pohmelfs_inode_info);
361 pio->cflags = DNET_FLAGS_NEED_ACK;
362 pio->priv = bin;
363 pio->type = POHMELFS_INODE_COLUMN;
364 pio->ioflags = DNET_IO_FLAGS_OVERWRITE;
366 pio->data = &bin->info;
367 pio->alloc_flags = POHMELFS_IO_OWN;
369 pio->cb.complete = pohmelfs_write_inode_complete;
370 pio->cb.init = pohmelfs_write_inode_init;
371 pio->cb.destroy = pohmelfs_write_inode_destroy;
373 err = pohmelfs_send_io(pio);
374 if (err)
375 goto err_out_put_bin;
377 if (sync) {
378 struct pohmelfs_wait *wait = &bin->wait;
380 ret = wait_event_interruptible_timeout(wait->wq,
381 wait->condition != 0 && atomic_read(&wait->refcnt.refcount) <= 2,
382 msecs_to_jiffies(psb->write_wait_timeout));
383 if (ret <= 0) {
384 err = ret;
385 if (ret == 0)
386 err = -ETIMEDOUT;
387 goto err_out_put_bin;
390 if (wait->condition < 0) {
391 err = wait->condition;
392 goto err_out_put_bin;
396 err_out_put_bin:
397 kref_put(&bin->wait.refcnt, pohmelfs_write_inode_release);
398 err_out_free_pio:
399 kmem_cache_free(pohmelfs_io_cache, pio);
400 err_out_exit:
401 return err;
404 static int pohmelfs_parse_options(struct pohmelfs_sb *psb, char *data);
406 static int pohmelfs_remount_fs(struct super_block *sb, int *flags, char *data)
408 struct pohmelfs_sb *psb = pohmelfs_sb(sb);
410 return pohmelfs_parse_options(psb, data);
413 static const struct super_operations pohmelfs_sb_ops = {
414 .alloc_inode = pohmelfs_alloc_inode,
415 .destroy_inode = pohmelfs_destroy_inode,
416 .drop_inode = pohmelfs_drop_inode,
417 .write_inode = pohmelfs_write_inode,
418 .put_super = pohmelfs_put_super,
419 .show_options = pohmelfs_show_options,
420 .statfs = pohmelfs_statfs,
421 .remount_fs = pohmelfs_remount_fs,
424 static void pohmelfs_sync(struct work_struct *work)
426 struct pohmelfs_sb *psb = container_of(to_delayed_work(work), struct pohmelfs_sb, sync_work);
427 struct super_block *sb = psb->sb;
428 long timeout = msecs_to_jiffies(psb->sync_timeout * 1000);
430 if (down_read_trylock(&sb->s_umount)) {
431 sync_filesystem(sb);
432 up_read(&sb->s_umount);
434 pohmelfs_stat(psb, 0);
435 } else {
436 timeout = 0;
439 if (!psb->need_exit)
440 queue_delayed_work(psb->wq, &psb->sync_work, timeout);
443 static int pohmelfs_init_psb(struct pohmelfs_sb *psb, struct super_block *sb)
445 char name[16];
446 int err;
448 psb->inode_root = RB_ROOT;
449 spin_lock_init(&psb->inode_lock);
451 atomic_long_set(&psb->ino, 0);
452 atomic_long_set(&psb->trans, 0);
454 sb->s_fs_info = psb;
455 sb->s_op = &pohmelfs_sb_ops;
456 sb->s_magic = POHMELFS_MAGIC_NUM;
457 sb->s_maxbytes = MAX_LFS_FILESIZE;
458 sb->s_blocksize = PAGE_SIZE;
459 sb->s_bdi = &psb->bdi;
460 sb->s_time_gran = 0;
462 psb->read_wait_timeout = 5000;
463 psb->write_wait_timeout = 5000;
465 psb->sync_timeout = 300;
467 psb->keepalive_cnt = 5;
468 psb->keepalive_interval = 10;
469 psb->keepalive_idle = 30;
471 psb->readdir_allocation = 4;
472 psb->reconnect_timeout = msecs_to_jiffies(30000);
474 psb->conn_num = 5;
476 psb->sb = sb;
478 psb->hash = crypto_alloc_hash("sha512", 0, CRYPTO_ALG_ASYNC);
479 if (IS_ERR(psb->hash)) {
480 err = PTR_ERR(psb->hash);
481 goto err_out_exit;
484 snprintf(name, sizeof(name), "pohmelfs-sync-%d", psb->bdi_num);
485 psb->wq = alloc_workqueue(name, WQ_NON_REENTRANT | WQ_UNBOUND | WQ_FREEZABLE | WQ_MEM_RECLAIM, 0);
486 if (!psb->wq) {
487 err = -ENOMEM;
488 goto err_out_crypto_free;
491 mutex_init(&psb->conn_lock);
492 INIT_LIST_HEAD(&psb->addr_list);
494 INIT_DELAYED_WORK(&psb->sync_work, pohmelfs_sync);
496 return 0;
498 err_out_crypto_free:
499 crypto_free_hash(psb->hash);
500 err_out_exit:
501 psb->sb = NULL;
502 sb->s_fs_info = NULL;
503 return err;
506 static int pohmelfs_parse_addr(char *addr, struct sockaddr_storage *a, int *addrlen)
508 int family, port;
509 char *ptr;
510 int err = -EINVAL;
512 ptr = strrchr(addr, ':');
513 if (!ptr)
514 goto err_out_print_wrong_param;
515 *ptr++ = 0;
516 if (!ptr)
517 goto err_out_print_wrong_param;
519 family = simple_strtol(ptr, NULL, 10);
521 ptr = strrchr(addr, ':');
522 if (!ptr)
523 goto err_out_print_wrong_param;
524 *ptr++ = 0;
525 if (!ptr)
526 goto err_out_print_wrong_param;
528 port = simple_strtol(ptr, NULL, 10);
530 if (family == AF_INET) {
531 struct sockaddr_in *sin = (struct sockaddr_in *)a;
533 sin->sin_family = family;
534 sin->sin_port = htons(port);
536 err = in4_pton(addr, strlen(addr), (u8 *)&sin->sin_addr, ':', NULL);
537 *addrlen = sizeof(struct sockaddr_in);
538 } else if (family == AF_INET6) {
539 struct sockaddr_in6 *sin = (struct sockaddr_in6 *)a;
541 sin->sin6_family = family;
542 sin->sin6_port = htons(port);
543 err = in6_pton(addr, strlen(addr), (u8 *)&sin->sin6_addr, ':', NULL);
544 *addrlen = sizeof(struct sockaddr_in6);
545 } else {
546 err = -ENOTSUPP;
549 if (err == 1)
550 err = 0;
551 else if (!err)
552 err = -EINVAL;
554 if (err)
555 goto err_out_print_wrong_param;
557 return 0;
559 err_out_print_wrong_param:
560 pr_err("%s: wrong addr: '%s', should be 'addr:port:family': %d\n",
561 __func__, addr, err);
562 return err;
565 static int pohmelfs_option(char *option, char *data, int *lenp, int have_data)
567 int len;
568 char *ptr;
570 if (!strncmp(option, data, strlen(option))) {
571 len = strlen(option);
572 ptr = data + len;
574 if (have_data && (!ptr || !*ptr))
575 return 0;
577 *lenp = len;
578 return 1;
581 return 0;
584 static int pohmelfs_set_groups(struct pohmelfs_sb *psb, char *value, int len)
586 int i, num = 0, start = 0, pos = 0;
587 char *ptr = value;
589 for (i = 0; i < len; ++i) {
590 if (value[i] == ':')
591 start = 0;
592 else if (!start) {
593 start = 1;
594 num++;
598 if (!num) {
599 return -ENOENT;
603 * We do not allow to mess with different group sets for already built filesystem
604 * But to prevent remount from failing, we just pretend that things went the right way
606 if (psb->groups)
607 return 0;
609 psb->groups = kzalloc(sizeof(int) * num, GFP_KERNEL);
610 if (!psb->groups)
611 return -ENOMEM;
612 psb->group_num = num;
614 start = 0;
615 for (i = 0; i < len; ++i) {
616 if (value[i] == ':') {
617 value[i] = '\0';
618 if (start) {
619 psb->groups[pos] = simple_strtol(ptr, NULL, 10);
620 pos++;
621 start = 0;
623 } else if (!start) {
624 ptr = &value[i];
625 start = 1;
629 if (start) {
630 psb->groups[pos] = simple_strtol(ptr, NULL, 10);
631 pos++;
634 return 0;
637 static int pohmelfs_parse_option(struct pohmelfs_sb *psb, char *data)
639 int len;
640 int err = 0;
642 pr_debug("option: %s\n", data);
644 if (pohmelfs_option("server=", data, &len, 1)) {
645 struct pohmelfs_addr *a, *tmp;
646 char *addr_str = data + len;
648 a = kzalloc(sizeof(struct pohmelfs_addr), GFP_KERNEL);
649 if (!a) {
650 err = -ENOMEM;
651 goto err_out_exit;
654 err = pohmelfs_parse_addr(addr_str, &a->sa, &a->addrlen);
655 if (err)
656 goto err_out_exit;
658 mutex_lock(&psb->conn_lock);
659 list_for_each_entry(tmp, &psb->addr_list, addr_entry) {
660 if (tmp->addrlen != a->addrlen)
661 continue;
663 if (!memcmp(&tmp->sa, &a->sa, a->addrlen)) {
664 err = -EEXIST;
665 break;
669 if (!err)
670 list_add_tail(&a->addr_entry, &psb->addr_list);
671 else
672 kfree(a);
673 mutex_unlock(&psb->conn_lock);
674 err = 0;
675 } else if (pohmelfs_option("fsid=", data, &len, 1)) {
676 data += len;
677 len = strlen(data);
679 psb->fsid = kmalloc(len + 1, GFP_KERNEL);
680 if (!psb->fsid) {
681 err = -ENOMEM;
682 goto err_out_exit;
685 snprintf(psb->fsid, len + 1, "%s", data);
686 psb->fsid_len = len;
687 } else if (pohmelfs_option("sync_timeout=", data, &len, 1)) {
688 psb->sync_timeout = simple_strtol(data + len, NULL, 10);
689 } else if (pohmelfs_option("http_compat=", data, &len, 1)) {
690 psb->http_compat = simple_strtol(data + len, NULL, 10);
691 err = pohmelfs_http_compat_init(psb);
692 } else if (pohmelfs_option("groups=", data, &len, 1)) {
693 data += len;
694 len = strlen(data);
696 err = pohmelfs_set_groups(psb, data, len);
697 } else if (pohmelfs_option("noatime", data, &len, 0)) {
698 psb->sb->s_flags |= FS_NOATIME_FL;
699 } else if (pohmelfs_option("relatime", data, &len, 0)) {
700 psb->sb->s_flags |= MS_RELATIME;
701 } else if (pohmelfs_option("noreadcsum", data, &len, 0)) {
702 psb->no_read_csum = 1;
703 } else if (pohmelfs_option("readcsum", data, &len, 0)) {
704 psb->no_read_csum = 0;
705 } else if (pohmelfs_option("successful_write_count=", data, &len, 1)) {
706 psb->successful_write_count = simple_strtol(data + len, NULL, 10);
707 } else if (pohmelfs_option("keepalive_cnt=", data, &len, 1)) {
708 psb->keepalive_cnt = simple_strtol(data + len, NULL, 10);
709 } else if (pohmelfs_option("keepalive_idle=", data, &len, 1)) {
710 psb->keepalive_idle = simple_strtol(data + len, NULL, 10);
711 } else if (pohmelfs_option("keepalive_interval=", data, &len, 1)) {
712 psb->keepalive_interval = simple_strtol(data + len, NULL, 10);
713 } else if (pohmelfs_option("readdir_allocation=", data, &len, 1)) {
714 psb->readdir_allocation = simple_strtol(data + len, NULL, 10);
715 } else if (pohmelfs_option("sync_on_close", data, &len, 0)) {
716 psb->sync_on_close = 1;
717 } else if (pohmelfs_option("connection_pool_size=", data, &len, 1)) {
718 psb->conn_num = simple_strtol(data + len, NULL, 10);
719 if (psb->conn_num < 2)
720 psb->conn_num = 2;
721 } else if (pohmelfs_option("read_wait_timeout=", data, &len, 1)) {
722 psb->read_wait_timeout = simple_strtol(data + len, NULL, 10);
723 } else if (pohmelfs_option("write_wait_timeout=", data, &len, 1)) {
724 psb->write_wait_timeout = simple_strtol(data + len, NULL, 10);
725 } else {
726 err = -ENOTSUPP;
729 err_out_exit:
730 return err;
733 static int pohmelfs_parse_options(struct pohmelfs_sb *psb, char *data)
735 int err = -ENOENT;
736 char *ptr, *start;
738 ptr = start = data;
740 while (ptr && *ptr) {
741 if (*ptr == ',') {
742 *ptr = '\0';
743 err = pohmelfs_parse_option(psb, start);
744 if (err)
745 goto err_out_exit;
746 ptr++;
747 if (ptr && *ptr)
748 start = ptr;
750 continue;
753 ptr++;
756 if (start != ptr) {
757 err = pohmelfs_parse_option(psb, start);
758 if (err)
759 goto err_out_exit;
762 err_out_exit:
763 return err;
766 static int pohmelfs_fill_super(struct super_block *sb, void *data, int silent)
768 struct pohmelfs_sb *psb;
769 int err;
771 psb = kzalloc(sizeof(struct pohmelfs_sb), GFP_KERNEL);
772 if (!psb) {
773 err = -ENOMEM;
774 goto err_out_exit;
777 psb->bdi_num = atomic_inc_return(&psb_bdi_num);
779 err = bdi_init(&psb->bdi);
780 if (err)
781 goto err_out_free_psb;
783 psb->bdi.ra_pages = default_backing_dev_info.ra_pages;
785 err = bdi_register(&psb->bdi, NULL, "pfs-%d", psb->bdi_num);
786 if (err) {
787 bdi_destroy(&psb->bdi);
788 goto err_out_free_psb;
791 err = pohmelfs_init_psb(psb, sb);
792 if (err)
793 goto err_out_free_bdi;
795 psb->root = pohmelfs_new_inode(psb, 0755|S_IFDIR);
796 if (IS_ERR(psb->root)) {
797 err = PTR_ERR(psb->root);
798 goto err_out_cleanup_psb;
801 err = pohmelfs_parse_options(psb, data);
802 if (err)
803 goto err_out_put_root;
805 if (!psb->group_num || list_empty(&psb->addr_list)) {
806 err = -EINVAL;
807 pr_err("you have to specify number of groups and add remote node address (at least one)\n");
808 goto err_out_put_root;
811 if (!psb->fsid_len) {
812 char str[] = "pohmelfs";
813 err = pohmelfs_hash(psb, str, 8, &psb->root->id);
814 } else {
815 err = pohmelfs_hash(psb, psb->fsid, psb->fsid_len, &psb->root->id);
817 if (err)
818 goto err_out_put_root;
820 err = psb->conn_num;
821 psb->conn_num = 0;
822 err = pohmelfs_pool_resize(psb, err);
823 if (err)
824 goto err_out_put_root;
826 sb->s_root = d_make_root(&psb->root->vfs_inode);
827 if (!sb->s_root) {
828 err = -ENOMEM;
829 goto err_out_cleanup_psb;
832 queue_delayed_work(psb->wq, &psb->sync_work, msecs_to_jiffies(psb->sync_timeout * 1000));
833 pohmelfs_stat(psb, 0);
835 return 0;
837 err_out_put_root:
838 iput(&psb->root->vfs_inode);
839 err_out_cleanup_psb:
840 pohmelfs_cleanup_psb(psb);
841 err_out_free_bdi:
842 bdi_destroy(&psb->bdi);
843 err_out_free_psb:
844 kfree(psb);
845 err_out_exit:
846 pr_err("%s: error: %d\n", __func__, err);
847 return err;
850 static struct dentry *pohmelfs_mount(struct file_system_type *fs_type,
851 int flags, const char *dev_name, void *data)
853 return mount_nodev(fs_type, flags, data, pohmelfs_fill_super);
856 static void pohmelfs_kill_sb(struct super_block *sb)
858 sync_inodes_sb(sb);
859 kill_anon_super(sb);
862 static struct file_system_type pohmelfs_type = {
863 .owner = THIS_MODULE,
864 .name = "pohmelfs",
865 .mount = pohmelfs_mount,
866 .kill_sb = pohmelfs_kill_sb,
869 static void pohmelfs_cleanup_cache(void)
871 kmem_cache_destroy(pohmelfs_trans_cache);
872 kmem_cache_destroy(pohmelfs_inode_cache);
873 kmem_cache_destroy(pohmelfs_inode_info_cache);
874 kmem_cache_destroy(pohmelfs_route_cache);
875 kmem_cache_destroy(pohmelfs_wait_cache);
876 kmem_cache_destroy(pohmelfs_io_cache);
877 kmem_cache_destroy(pohmelfs_inode_info_binary_package_cache);
878 kfree(pohmelfs_scratch_buf);
879 kmem_cache_destroy(pohmelfs_write_cache);
880 kmem_cache_destroy(pohmelfs_dentry_cache);
883 static int pohmelfs_init_cache(void)
885 int err = -ENOMEM;
887 pohmelfs_inode_cache = KMEM_CACHE(pohmelfs_inode, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
888 if (!pohmelfs_inode_cache)
889 goto err_out_exit;
891 pohmelfs_trans_cache = KMEM_CACHE(pohmelfs_trans, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
892 if (!pohmelfs_trans_cache)
893 goto err_out_destroy_inode_cache;
895 pohmelfs_inode_info_cache = KMEM_CACHE(pohmelfs_inode_info, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
896 if (!pohmelfs_inode_info_cache)
897 goto err_out_destroy_trans_cache;
899 pohmelfs_route_cache = KMEM_CACHE(pohmelfs_route, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
900 if (!pohmelfs_route_cache)
901 goto err_out_destroy_inode_info_cache;
903 pohmelfs_wait_cache = KMEM_CACHE(pohmelfs_wait, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
904 if (!pohmelfs_wait_cache)
905 goto err_out_destroy_inode_info_cache;
907 pohmelfs_io_cache = KMEM_CACHE(pohmelfs_io, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
908 if (!pohmelfs_io_cache)
909 goto err_out_destroy_wait_cache;
911 pohmelfs_scratch_buf = kmalloc(pohmelfs_scratch_buf_size, GFP_KERNEL);
912 if (!pohmelfs_scratch_buf) {
913 err = -ENOMEM;
914 goto err_out_destroy_io_cache;
917 pohmelfs_inode_info_binary_package_cache = KMEM_CACHE(pohmelfs_inode_info_binary_package, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
918 if (!pohmelfs_inode_info_binary_package_cache)
919 goto err_out_free_scratch;
921 pohmelfs_write_cache = KMEM_CACHE(pohmelfs_write_ctl, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
922 if (!pohmelfs_write_cache)
923 goto err_out_destroy_inode_info_binary_package_cache;
925 pohmelfs_dentry_cache = KMEM_CACHE(pohmelfs_dentry, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
926 if (!pohmelfs_dentry_cache)
927 goto err_out_destroy_write_cache;
929 return 0;
931 err_out_destroy_write_cache:
932 kmem_cache_destroy(pohmelfs_write_cache);
933 err_out_destroy_inode_info_binary_package_cache:
934 kmem_cache_destroy(pohmelfs_inode_info_binary_package_cache);
935 err_out_free_scratch:
936 kfree(pohmelfs_scratch_buf);
937 err_out_destroy_io_cache:
938 kmem_cache_destroy(pohmelfs_io_cache);
939 err_out_destroy_wait_cache:
940 kmem_cache_destroy(pohmelfs_wait_cache);
941 err_out_destroy_inode_info_cache:
942 kmem_cache_destroy(pohmelfs_inode_info_cache);
943 err_out_destroy_trans_cache:
944 kmem_cache_destroy(pohmelfs_trans_cache);
945 err_out_destroy_inode_cache:
946 kmem_cache_destroy(pohmelfs_inode_cache);
947 err_out_exit:
948 return err;
951 static int __init pohmelfs_init(void)
953 int err;
955 err = pohmelfs_init_cache();
956 if (err)
957 goto err_out_exit;
959 err = register_filesystem(&pohmelfs_type);
960 if (err)
961 goto err_out_cleanup_cache;
963 return 0;
965 err_out_cleanup_cache:
966 pohmelfs_cleanup_cache();
967 err_out_exit:
968 return err;
971 static void __exit pohmelfs_exit(void)
973 unregister_filesystem(&pohmelfs_type);
974 pohmelfs_cleanup_cache();
977 module_init(pohmelfs_init)
978 module_exit(pohmelfs_exit)
980 MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
981 MODULE_DESCRIPTION("POHMELFS");
982 MODULE_LICENSE("GPL");