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
;
33 static atomic_t psb_bdi_num
= ATOMIC_INIT(0);
35 static void pohmelfs_cleanup_psb(struct pohmelfs_sb
*psb
)
37 struct pohmelfs_state
*st
, *tmp
;
39 list_for_each_entry_safe(st
, tmp
, &psb
->state_list
, state_entry
) {
40 list_del_init(&st
->state_entry
);
42 pohmelfs_state_kill(st
);
45 destroy_workqueue(psb
->wq
);
46 crypto_free_hash(psb
->hash
);
49 kfree(pohmelfs_scratch_buf
);
52 static void pohmelfs_put_super(struct super_block
*sb
)
54 struct pohmelfs_sb
*psb
= pohmelfs_sb(sb
);
56 pohmelfs_cleanup_psb(psb
);
57 bdi_destroy(&psb
->bdi
);
60 static int pohmelfs_statfs(struct dentry
*dentry
, struct kstatfs
*buf
)
62 struct super_block
*sb
= dentry
->d_sb
;
65 * There are no filesystem size limits yet.
67 memset(buf
, 0, sizeof(struct kstatfs
));
69 buf
->f_type
= POHMELFS_MAGIC_NUM
; /* 'POH.' */
70 buf
->f_bsize
= sb
->s_blocksize
;
72 buf
->f_namelen
= 4096;
74 buf
->f_bfree
= buf
->f_bavail
= ~0ULL >> PAGE_SHIFT
;
75 buf
->f_blocks
= ~0ULL >> PAGE_SHIFT
;
80 static int pohmelfs_show_options(struct seq_file
*seq
, struct vfsmount
*vfs
)
82 struct pohmelfs_sb
*psb
= pohmelfs_sb(vfs
->mnt_sb
);
85 seq_printf(seq
, ",sync=%u", psb
->sync
);
87 seq_printf(seq
, ",fsid=%s", psb
->fsid
);
91 static int pohmelfs_drop_inode(struct inode
*inode
)
93 pr_info("pohmelfs_drop_inode: ino: %lu\n", inode
->i_ino
);
97 static int pohmelfs_write_inode(struct inode
*inode
, struct writeback_control
*wbc
)
99 struct pohmelfs_inode
*pi
= pohmelfs_inode(inode
);
100 u64 isize
= i_size_read(inode
);
103 if (isize
!= pi
->isize
) {
104 struct dentry
*dentry
;
106 dentry
= d_find_alias(inode
);
109 err
= pohmelfs_send_inode_info(pi
, &pi
->parent_id
, dentry
->d_name
.name
, dentry
->d_name
.len
, 1);
117 static const struct super_operations pohmelfs_sb_ops
= {
118 .alloc_inode
= pohmelfs_alloc_inode
,
119 .destroy_inode
= pohmelfs_destroy_inode
,
120 .drop_inode
= pohmelfs_drop_inode
,
121 .write_inode
= pohmelfs_write_inode
,
122 .put_super
= pohmelfs_put_super
,
123 .show_options
= pohmelfs_show_options
,
124 .statfs
= pohmelfs_statfs
,
127 static int pohmelfs_init_psb(struct pohmelfs_sb
*psb
, struct super_block
*sb
)
132 INIT_LIST_HEAD(&psb
->state_list
);
133 psb
->route_root
= RB_ROOT
;
135 psb
->inode_root
= RB_ROOT
;
136 spin_lock_init(&psb
->inode_lock
);
138 spin_lock_init(&psb
->state_lock
);
140 atomic_long_set(&psb
->ino
, 0);
141 atomic_long_set(&psb
->trans
, 0);
144 sb
->s_op
= &pohmelfs_sb_ops
;
145 sb
->s_magic
= POHMELFS_MAGIC_NUM
;
146 sb
->s_maxbytes
= MAX_LFS_FILESIZE
;
147 sb
->s_blocksize
= PAGE_SIZE
;
148 sb
->s_bdi
= &psb
->bdi
;
150 psb
->read_wait_timeout
= 5000;
151 psb
->write_wait_timeout
= 5000;
155 pohmelfs_scratch_buf
= kmalloc(pohmelfs_scratch_buf_size
, GFP_KERNEL
);
156 if (!pohmelfs_scratch_buf
) {
161 psb
->hash
= crypto_alloc_hash("sha512", 0, CRYPTO_ALG_ASYNC
);
162 if (IS_ERR(psb
->hash
)) {
163 err
= PTR_ERR(psb
->hash
);
164 goto err_out_free_scratch
;
167 snprintf(name
, sizeof(name
), "pohmelfs-%d", psb
->bdi_num
);
168 psb
->wq
= alloc_workqueue(name
, WQ_NON_REENTRANT
| WQ_UNBOUND
| WQ_FREEZABLE
| WQ_MEM_RECLAIM
, 0);
171 goto err_out_crypto_free
;
177 crypto_free_hash(psb
->hash
);
178 err_out_free_scratch
:
179 kfree(pohmelfs_scratch_buf
);
182 sb
->s_fs_info
= NULL
;
186 static int pohmelfs_parse_addr(char *addr
, struct sockaddr_storage
*a
, int *addrlen
)
192 ptr
= strrchr(addr
, ':');
194 goto err_out_print_wrong_param
;
197 goto err_out_print_wrong_param
;
199 family
= simple_strtol(ptr
, NULL
, 10);
201 ptr
= strrchr(addr
, ':');
203 goto err_out_print_wrong_param
;
206 goto err_out_print_wrong_param
;
208 port
= simple_strtol(ptr
, NULL
, 10);
210 if (family
== AF_INET
) {
211 struct sockaddr_in
*sin
= (struct sockaddr_in
*)a
;
213 sin
->sin_family
= family
;
214 sin
->sin_port
= htons(port
);
216 err
= in4_pton(addr
, strlen(addr
), (u8
*)&sin
->sin_addr
, ':', NULL
);
217 *addrlen
= sizeof(struct sockaddr_in
);
218 } else if (family
== AF_INET6
) {
219 struct sockaddr_in6
*sin
= (struct sockaddr_in6
*)a
;
221 sin
->sin6_family
= family
;
222 sin
->sin6_port
= htons(port
);
223 err
= in6_pton(addr
, strlen(addr
), (u8
*)&sin
->sin6_addr
, ':', NULL
);
224 *addrlen
= sizeof(struct sockaddr_in6
);
235 goto err_out_print_wrong_param
;
239 err_out_print_wrong_param
:
240 pr_err("pohmelfs: %s: wrong addr: '%s', should be 'addr:port:family': %d.\n", __func__
, addr
, err
);
244 static int pohmelfs_option(char *option
, char *data
, int *lenp
)
249 if (!strncmp(option
, data
, strlen(option
))) {
250 len
= strlen(option
);
263 static int pohmelfs_parse_option(struct pohmelfs_sb
*psb
, char *data
)
268 pr_debug("pohmelfs: %s: option: %s\n", __func__
, data
);
270 if (pohmelfs_option("server=", data
, &len
)) {
272 char *addr_str
= data
+ len
;
273 struct sockaddr_storage sa
;
274 struct pohmelfs_state
*st
;
276 memset(&sa
, 0, sizeof(struct sockaddr_storage
));
277 err
= pohmelfs_parse_addr(addr_str
, &sa
, &addrlen
);
281 st
= pohmelfs_state_create(psb
, &sa
, addrlen
, 1);
286 } else if (pohmelfs_option("fsid=", data
, &len
)) {
290 psb
->fsid
= kmalloc(len
+ 1, GFP_KERNEL
);
296 snprintf(psb
->fsid
, len
+ 1, "%s", data
);
298 } else if (pohmelfs_option("sync=", data
, &len
)) {
299 psb
->sync
= simple_strtol(data
+ len
, NULL
, 10);
308 static int pohmelfs_parse_options(struct pohmelfs_sb
*psb
, char *data
)
315 while (ptr
&& *ptr
) {
318 err
= pohmelfs_parse_option(psb
, start
);
332 err
= pohmelfs_parse_option(psb
, start
);
341 static int pohmelfs_fill_super(struct super_block
*sb
, void *data
, int silent
)
343 struct pohmelfs_sb
*psb
;
346 psb
= kzalloc(sizeof(struct pohmelfs_sb
), GFP_KERNEL
);
352 psb
->bdi_num
= atomic_inc_return(&psb_bdi_num
);
354 err
= bdi_init(&psb
->bdi
);
356 goto err_out_free_psb
;
358 err
= bdi_register(&psb
->bdi
, NULL
, "pfs-%d", psb
->bdi_num
);
360 bdi_destroy(&psb
->bdi
);
361 goto err_out_free_psb
;
364 err
= pohmelfs_init_psb(psb
, sb
);
366 goto err_out_free_bdi
;
368 psb
->root
= pohmelfs_new_inode(psb
, 0755|S_IFDIR
);
369 if (IS_ERR(psb
->root
)) {
370 err
= PTR_ERR(psb
->root
);
371 goto err_out_cleanup_psb
;
374 err
= pohmelfs_parse_options(psb
, data
);
376 goto err_out_put_root
;
378 if (!psb
->fsid_len
) {
379 char str
[] = "pohmelfs";
380 err
= pohmelfs_hash(psb
, str
, 8, &psb
->root
->id
);
382 err
= pohmelfs_hash(psb
, psb
->fsid
, psb
->fsid_len
, &psb
->root
->id
);
385 goto err_out_put_root
;
387 sb
->s_root
= d_alloc_root(&psb
->root
->vfs_inode
);
390 goto err_out_put_root
;
396 iput(&psb
->root
->vfs_inode
);
398 pohmelfs_cleanup_psb(psb
);
400 bdi_destroy(&psb
->bdi
);
404 pr_err("pohmelfs: %s: error: %d\n", __func__
, err
);
408 static struct dentry
*pohmelfs_mount(struct file_system_type
*fs_type
,
409 int flags
, const char *dev_name
, void *data
)
411 return mount_nodev(fs_type
, flags
, data
, pohmelfs_fill_super
);
414 static void pohmelfs_kill_sb(struct super_block
*sb
)
420 static struct file_system_type pohmelfs_type
= {
421 .owner
= THIS_MODULE
,
423 .mount
= pohmelfs_mount
,
424 .kill_sb
= pohmelfs_kill_sb
,
427 static void pohmelfs_init_inode_once(void *data
)
429 struct pohmelfs_inode
*ino
= data
;
430 inode_init_once(&ino
->vfs_inode
);
433 static void pohmelfs_cleanup_cache(void)
435 kmem_cache_destroy(pohmelfs_trans_cache
);
436 kmem_cache_destroy(pohmelfs_inode_cache
);
437 kmem_cache_destroy(pohmelfs_inode_info_cache
);
438 kmem_cache_destroy(pohmelfs_route_cache
);
439 kmem_cache_destroy(pohmelfs_wait_cache
);
442 static int pohmelfs_init_cache(void)
446 pohmelfs_inode_cache
= kmem_cache_create("pohmelfs_inode",
447 sizeof(struct pohmelfs_inode
),
448 __alignof__(struct pohmelfs_inode
),
449 (SLAB_RECLAIM_ACCOUNT
|SLAB_MEM_SPREAD
),
450 pohmelfs_init_inode_once
);
451 if (!pohmelfs_inode_cache
)
454 pohmelfs_trans_cache
= KMEM_CACHE(pohmelfs_trans
, SLAB_RECLAIM_ACCOUNT
|SLAB_MEM_SPREAD
);
455 if (!pohmelfs_trans_cache
)
456 goto err_out_destroy_inode_cache
;
458 pohmelfs_inode_info_cache
= KMEM_CACHE(pohmelfs_inode_info
, SLAB_RECLAIM_ACCOUNT
|SLAB_MEM_SPREAD
);
459 if (!pohmelfs_inode_info_cache
)
460 goto err_out_destroy_trans_cache
;
462 pohmelfs_route_cache
= KMEM_CACHE(pohmelfs_route
, SLAB_RECLAIM_ACCOUNT
|SLAB_MEM_SPREAD
);
463 if (!pohmelfs_route_cache
)
464 goto err_out_destroy_inode_info_cache
;
466 pohmelfs_wait_cache
= KMEM_CACHE(pohmelfs_wait
, SLAB_RECLAIM_ACCOUNT
|SLAB_MEM_SPREAD
);
467 if (!pohmelfs_wait_cache
)
468 goto err_out_destroy_inode_info_cache
;
472 err_out_destroy_inode_info_cache
:
473 kmem_cache_destroy(pohmelfs_inode_info_cache
);
474 err_out_destroy_trans_cache
:
475 kmem_cache_destroy(pohmelfs_trans_cache
);
476 err_out_destroy_inode_cache
:
477 kmem_cache_destroy(pohmelfs_inode_cache
);
482 static int __init
pohmelfs_init(void)
486 err
= pohmelfs_init_cache();
490 err
= register_filesystem(&pohmelfs_type
);
492 goto err_out_cleanup_cache
;
496 err_out_cleanup_cache
:
497 pohmelfs_cleanup_cache();
502 static void __exit
pohmelfs_exit(void)
504 unregister_filesystem(&pohmelfs_type
);
505 pohmelfs_cleanup_cache();
508 module_init(pohmelfs_init
)
509 module_exit(pohmelfs_exit
)
511 MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
512 MODULE_DESCRIPTION("POHMELFS");
513 MODULE_LICENSE("GPL");