2 * Copyright (C) 2011+ Evgeniy Polyakov <zbr@ioremap.net>
5 #include <linux/module.h>
6 #include <linux/string.h>
8 #include <linux/slab.h>
9 #include <linux/init.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>
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
;
44 for (i
= 0; i
< psb
->http_compat
; ++i
) {
47 mutex_destroy(&p
->lock
);
52 static int pohmelfs_http_compat_init(struct pohmelfs_sb
*psb
)
55 struct pohmelfs_path
*path
, *p
;
57 path
= kmalloc(psb
->http_compat
* sizeof(struct pohmelfs_path
), GFP_KERNEL
);
63 for (i
= 0; i
< psb
->http_compat
; ++i
) {
68 p
->data
= kmalloc(PAGE_SIZE
, GFP_KERNEL
);
82 mutex_destroy(&p
->lock
);
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
);
116 destroy_workqueue(psb
->wq
);
117 crypto_free_hash(psb
->hash
);
119 pohmelfs_http_compat_cleanup(psb
);
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;
147 buf
->f_bfree
= buf
->f_bavail
= 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
);
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
);
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");
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
)
219 wait
->condition
= cmd
->status
;
220 if (!wait
->condition
)
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
);
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
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
;
268 sync
= wbc
->sync_mode
== WB_SYNC_ALL
;
270 pio
= kmem_cache_zalloc(pohmelfs_io_cache
, GFP_NOIO
);
276 bin
= kmem_cache_zalloc(pohmelfs_inode_info_binary_package_cache
, GFP_NOIO
);
279 goto err_out_free_pio
;
282 pohmelfs_fill_inode_info(inode
, &bin
->info
);
283 err
= pohmelfs_wait_init(&bin
->wait
, pi
);
285 goto err_out_put_bin
;
289 pio
->cmd
= DNET_CMD_WRITE
;
291 pio
->size
= sizeof(struct pohmelfs_inode_info
);
292 pio
->cflags
= DNET_FLAGS_NEED_ACK
;
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
);
305 goto err_out_put_bin
;
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
));
317 goto err_out_put_bin
;
320 if (wait
->condition
< 0) {
321 err
= wait
->condition
;
322 goto err_out_put_bin
;
327 kref_put(&bin
->wait
.refcnt
, pohmelfs_write_inode_release
);
329 kmem_cache_free(pohmelfs_io_cache
, pio
);
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
);
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
;
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
);
384 pohmelfs_print_addr(&st
->sa
, "reconnected\n");
387 list_del(&r
->reconnect_entry
);
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
)
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);
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
;
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);
445 psb
->hash
= crypto_alloc_hash("sha512", 0, CRYPTO_ALG_ASYNC
);
446 if (IS_ERR(psb
->hash
)) {
447 err
= PTR_ERR(psb
->hash
);
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);
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
);
468 crypto_free_hash(psb
->hash
);
471 sb
->s_fs_info
= NULL
;
475 static int pohmelfs_parse_addr(char *addr
, struct sockaddr_storage
*a
, int *addrlen
)
481 ptr
= strrchr(addr
, ':');
483 goto err_out_print_wrong_param
;
486 goto err_out_print_wrong_param
;
488 family
= simple_strtol(ptr
, NULL
, 10);
490 ptr
= strrchr(addr
, ':');
492 goto err_out_print_wrong_param
;
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
);
524 goto err_out_print_wrong_param
;
528 err_out_print_wrong_param
:
529 pr_err("pohmelfs: %s: wrong addr: '%s', should be 'addr:port:family': %d.\n", __func__
, addr
, err
);
533 static int pohmelfs_option(char *option
, char *data
, int *lenp
, int have_data
)
538 if (!strncmp(option
, data
, strlen(option
))) {
539 len
= strlen(option
);
542 if (have_data
&& (!ptr
|| !*ptr
))
552 static int pohmelfs_set_groups(struct pohmelfs_sb
*psb
, char *value
, int len
)
554 int i
, num
= 0, start
= 0, pos
= 0;
557 for (i
= 0; i
< len
; ++i
) {
570 psb
->groups
= kzalloc(sizeof(int) * num
, GFP_KERNEL
);
573 psb
->group_num
= num
;
576 for (i
= 0; i
< len
; ++i
) {
577 if (value
[i
] == ':') {
580 psb
->groups
[pos
] = simple_strtol(ptr
, NULL
, 10);
591 psb
->groups
[pos
] = simple_strtol(ptr
, NULL
, 10);
598 static int pohmelfs_parse_option(struct pohmelfs_sb
*psb
, char *data
)
603 pr_debug("pohmelfs: %s: option: %s\n", __func__
, data
);
605 if (pohmelfs_option("server=", data
, &len
, 1)) {
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
);
616 st
= pohmelfs_state_create(psb
, &sa
, addrlen
, 1, 0);
623 } else if (pohmelfs_option("fsid=", data
, &len
, 1)) {
627 psb
->fsid
= kmalloc(len
+ 1, GFP_KERNEL
);
633 snprintf(psb
->fsid
, len
+ 1, "%s", data
);
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)) {
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;
673 static int pohmelfs_parse_options(struct pohmelfs_sb
*psb
, char *data
)
680 while (ptr
&& *ptr
) {
683 err
= pohmelfs_parse_option(psb
, start
);
697 err
= pohmelfs_parse_option(psb
, start
);
706 static int pohmelfs_fill_super(struct super_block
*sb
, void *data
, int silent
)
708 struct pohmelfs_sb
*psb
;
711 psb
= kzalloc(sizeof(struct pohmelfs_sb
), GFP_KERNEL
);
717 psb
->bdi_num
= atomic_inc_return(&psb_bdi_num
);
719 err
= bdi_init(&psb
->bdi
);
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
);
727 bdi_destroy(&psb
->bdi
);
728 goto err_out_free_psb
;
731 err
= pohmelfs_init_psb(psb
, sb
);
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
);
743 goto err_out_put_root
;
745 if (!psb
->group_num
) {
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
);
755 err
= pohmelfs_hash(psb
, psb
->fsid
, psb
->fsid_len
, &psb
->root
->id
);
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
);
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);
774 iput(&psb
->root
->vfs_inode
);
776 pohmelfs_cleanup_psb(psb
);
778 bdi_destroy(&psb
->bdi
);
782 pr_err("pohmelfs: %s: error: %d\n", __func__
, 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
)
798 static struct file_system_type pohmelfs_type
= {
799 .owner
= THIS_MODULE
,
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)
823 pohmelfs_inode_cache
= KMEM_CACHE(pohmelfs_inode
, SLAB_RECLAIM_ACCOUNT
|SLAB_MEM_SPREAD
);
824 if (!pohmelfs_inode_cache
)
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
) {
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
;
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
);
887 static int __init
pohmelfs_init(void)
891 err
= pohmelfs_init_cache();
895 err
= register_filesystem(&pohmelfs_type
);
897 goto err_out_cleanup_cache
;
901 err_out_cleanup_cache
:
902 pohmelfs_cleanup_cache();
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");