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 struct pohmelfs_size
{
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;
152 sz
= kzalloc(psb
->group_num
* sizeof(struct pohmelfs_size
), GFP_KERNEL
);
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;
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
;
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
;
195 buf
->f_bfree
= buf
->f_bavail
= buf
->f_blocks
= ~0ULL >> PAGE_SHIFT
;
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
;
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
);
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");
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
)
266 wait
->condition
= cmd
->status
;
267 if (!wait
->condition
)
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
);
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
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
;
315 sync
= wbc
->sync_mode
== WB_SYNC_ALL
;
317 pio
= kmem_cache_zalloc(pohmelfs_io_cache
, GFP_NOIO
);
323 bin
= kmem_cache_zalloc(pohmelfs_inode_info_binary_package_cache
, GFP_NOIO
);
326 goto err_out_free_pio
;
329 pohmelfs_fill_inode_info(inode
, &bin
->info
);
330 err
= pohmelfs_wait_init(&bin
->wait
, pi
);
332 goto err_out_put_bin
;
336 pio
->cmd
= DNET_CMD_WRITE
;
338 pio
->size
= sizeof(struct pohmelfs_inode_info
);
339 pio
->cflags
= DNET_FLAGS_NEED_ACK
;
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
);
352 goto err_out_put_bin
;
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
));
364 goto err_out_put_bin
;
367 if (wait
->condition
< 0) {
368 err
= wait
->condition
;
369 goto err_out_put_bin
;
374 kref_put(&bin
->wait
.refcnt
, pohmelfs_write_inode_release
);
376 kmem_cache_free(pohmelfs_io_cache
, pio
);
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
);
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
;
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
);
431 pohmelfs_print_addr(&st
->sa
, "reconnected\n");
434 list_del(&r
->reconnect_entry
);
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
)
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);
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
;
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);
492 psb
->hash
= crypto_alloc_hash("sha512", 0, CRYPTO_ALG_ASYNC
);
493 if (IS_ERR(psb
->hash
)) {
494 err
= PTR_ERR(psb
->hash
);
498 snprintf(name
, sizeof(name
), "pohmelfs-%d", psb
->bdi_num
);
499 psb
->wq
= alloc_workqueue(name
, WQ_HIGHPRI
, 0);
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
);
515 crypto_free_hash(psb
->hash
);
518 sb
->s_fs_info
= NULL
;
522 static int pohmelfs_parse_addr(char *addr
, struct sockaddr_storage
*a
, int *addrlen
)
528 ptr
= strrchr(addr
, ':');
530 goto err_out_print_wrong_param
;
533 goto err_out_print_wrong_param
;
535 family
= simple_strtol(ptr
, NULL
, 10);
537 ptr
= strrchr(addr
, ':');
539 goto err_out_print_wrong_param
;
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
);
571 goto err_out_print_wrong_param
;
575 err_out_print_wrong_param
:
576 pr_err("pohmelfs: %s: wrong addr: '%s', should be 'addr:port:family': %d.\n", __func__
, addr
, err
);
580 static int pohmelfs_option(char *option
, char *data
, int *lenp
, int have_data
)
585 if (!strncmp(option
, data
, strlen(option
))) {
586 len
= strlen(option
);
589 if (have_data
&& (!ptr
|| !*ptr
))
599 static int pohmelfs_set_groups(struct pohmelfs_sb
*psb
, char *value
, int len
)
601 int i
, num
= 0, start
= 0, pos
= 0;
604 for (i
= 0; i
< len
; ++i
) {
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
624 psb
->groups
= kzalloc(sizeof(int) * num
, GFP_KERNEL
);
627 psb
->group_num
= num
;
630 for (i
= 0; i
< len
; ++i
) {
631 if (value
[i
] == ':') {
634 psb
->groups
[pos
] = simple_strtol(ptr
, NULL
, 10);
645 psb
->groups
[pos
] = simple_strtol(ptr
, NULL
, 10);
652 static int pohmelfs_parse_option(struct pohmelfs_sb
*psb
, char *data
)
657 pr_debug("pohmelfs: %s: option: %s\n", __func__
, data
);
659 if (pohmelfs_option("server=", data
, &len
, 1)) {
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
);
670 st
= pohmelfs_state_create(psb
, &sa
, addrlen
, 1, 0);
677 } else if (pohmelfs_option("fsid=", data
, &len
, 1)) {
681 psb
->fsid
= kmalloc(len
+ 1, GFP_KERNEL
);
687 snprintf(psb
->fsid
, len
+ 1, "%s", data
);
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)) {
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;
727 static int pohmelfs_parse_options(struct pohmelfs_sb
*psb
, char *data
)
734 while (ptr
&& *ptr
) {
737 err
= pohmelfs_parse_option(psb
, start
);
751 err
= pohmelfs_parse_option(psb
, start
);
760 static int pohmelfs_fill_super(struct super_block
*sb
, void *data
, int silent
)
762 struct pohmelfs_sb
*psb
;
765 psb
= kzalloc(sizeof(struct pohmelfs_sb
), GFP_KERNEL
);
771 psb
->bdi_num
= atomic_inc_return(&psb_bdi_num
);
773 err
= bdi_init(&psb
->bdi
);
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
);
781 bdi_destroy(&psb
->bdi
);
782 goto err_out_free_psb
;
785 err
= pohmelfs_init_psb(psb
, sb
);
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
);
797 goto err_out_put_root
;
799 if (!psb
->group_num
) {
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
);
809 err
= pohmelfs_hash(psb
, psb
->fsid
, psb
->fsid_len
, &psb
->root
->id
);
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
);
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);
828 iput(&psb
->root
->vfs_inode
);
830 pohmelfs_cleanup_psb(psb
);
832 bdi_destroy(&psb
->bdi
);
836 pr_err("pohmelfs: %s: error: %d\n", __func__
, 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
)
852 static struct file_system_type pohmelfs_type
= {
853 .owner
= THIS_MODULE
,
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)
877 pohmelfs_inode_cache
= KMEM_CACHE(pohmelfs_inode
, SLAB_RECLAIM_ACCOUNT
|SLAB_MEM_SPREAD
);
878 if (!pohmelfs_inode_cache
)
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
) {
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
;
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
);
941 static int __init
pohmelfs_init(void)
945 err
= pohmelfs_init_cache();
949 err
= register_filesystem(&pohmelfs_type
);
951 goto err_out_cleanup_cache
;
955 err_out_cleanup_cache
:
956 pohmelfs_cleanup_cache();
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");