Fixed listing and object creation
[pohmelfs.git] / fs / pohmelfs / super.c
blob521f123feffb05222844fadfa8d34a3fb4e35447
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;
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);
48 kfree(psb->fsid);
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;
71 buf->f_files = 0;
72 buf->f_namelen = 4096;
73 buf->f_files = 0;
74 buf->f_bfree = buf->f_bavail = ~0ULL >> PAGE_SHIFT;
75 buf->f_blocks = ~0ULL >> PAGE_SHIFT;
77 return 0;
80 static int pohmelfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
82 struct pohmelfs_sb *psb = pohmelfs_sb(vfs->mnt_sb);
84 if (psb->sync)
85 seq_printf(seq, ",sync=%u", psb->sync);
86 if (psb->fsid)
87 seq_printf(seq, ",fsid=%s", psb->fsid);
88 return 0;
91 static int pohmelfs_drop_inode(struct inode *inode)
93 pr_info("pohmelfs_drop_inode: ino: %lu\n", inode->i_ino);
94 return 1;
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);
101 int err = 0;
103 if (isize != pi->isize) {
104 struct dentry *dentry;
106 dentry = d_find_alias(inode);
107 if (dentry) {
108 pi->isize = isize;
109 err = pohmelfs_send_inode_info(pi, &pi->parent_id, dentry->d_name.name, dentry->d_name.len, 1);
110 dput(dentry);
114 return err;
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)
129 int err;
130 char name[16];
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);
143 sb->s_fs_info = psb;
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;
153 psb->sb = sb;
155 pohmelfs_scratch_buf = kmalloc(pohmelfs_scratch_buf_size, GFP_KERNEL);
156 if (!pohmelfs_scratch_buf) {
157 err = -ENOMEM;
158 goto err_out_exit;
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);
169 if (!psb->wq) {
170 err = -ENOMEM;
171 goto err_out_crypto_free;
174 return 0;
176 err_out_crypto_free:
177 crypto_free_hash(psb->hash);
178 err_out_free_scratch:
179 kfree(pohmelfs_scratch_buf);
180 err_out_exit:
181 psb->sb = NULL;
182 sb->s_fs_info = NULL;
183 return err;
186 static int pohmelfs_parse_addr(char *addr, struct sockaddr_storage *a, int *addrlen)
188 int family, port;
189 char *ptr;
190 int err = -EINVAL;
192 ptr = strrchr(addr, ':');
193 if (!ptr)
194 goto err_out_print_wrong_param;
195 *ptr++ = 0;
196 if (!ptr)
197 goto err_out_print_wrong_param;
199 family = simple_strtol(ptr, NULL, 10);
201 ptr = strrchr(addr, ':');
202 if (!ptr)
203 goto err_out_print_wrong_param;
204 *ptr++ = 0;
205 if (!ptr)
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);
225 } else {
226 err = -ENOTSUPP;
229 if (err == 1)
230 err = 0;
231 else if (!err)
232 err = -EINVAL;
234 if (err)
235 goto err_out_print_wrong_param;
237 return 0;
239 err_out_print_wrong_param:
240 pr_err("pohmelfs: %s: wrong addr: '%s', should be 'addr:port:family': %d.\n", __func__, addr, err);
241 return err;
244 static int pohmelfs_option(char *option, char *data, int *lenp)
246 int len;
247 char *ptr;
249 if (!strncmp(option, data, strlen(option))) {
250 len = strlen(option);
251 ptr = data + len;
253 if (!ptr || !*ptr)
254 return 0;
256 *lenp = len;
257 return 1;
260 return 0;
263 static int pohmelfs_parse_option(struct pohmelfs_sb *psb, char *data)
265 int len;
266 int err = 0;
268 pr_debug("pohmelfs: %s: option: %s\n", __func__, data);
270 if (pohmelfs_option("server=", data, &len)) {
271 int addrlen;
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);
278 if (err)
279 goto err_out_exit;
281 st = pohmelfs_state_create(psb, &sa, addrlen, 1);
282 if (IS_ERR(st)) {
283 err = PTR_ERR(st);
284 goto err_out_exit;
286 } else if (pohmelfs_option("fsid=", data, &len)) {
287 data += len;
288 len = strlen(data);
290 psb->fsid = kmalloc(len + 1, GFP_KERNEL);
291 if (!psb->fsid) {
292 err = -ENOMEM;
293 goto err_out_exit;
296 snprintf(psb->fsid, len + 1, "%s", data);
297 psb->fsid_len = len;
298 } else if (pohmelfs_option("sync=", data, &len)) {
299 psb->sync = simple_strtol(data + len, NULL, 10);
300 } else {
301 err = -ENOTSUPP;
304 err_out_exit:
305 return err;
308 static int pohmelfs_parse_options(struct pohmelfs_sb *psb, char *data)
310 int err = -ENOENT;
311 char *ptr, *start;
313 ptr = start = data;
315 while (ptr && *ptr) {
316 if (*ptr == ';') {
317 *ptr = '\0';
318 err = pohmelfs_parse_option(psb, start);
319 if (err)
320 goto err_out_exit;
321 ptr++;
322 if (ptr && *ptr)
323 start = ptr;
325 continue;
328 ptr++;
331 if (start != ptr) {
332 err = pohmelfs_parse_option(psb, start);
333 if (err)
334 goto err_out_exit;
337 err_out_exit:
338 return err;
341 static int pohmelfs_fill_super(struct super_block *sb, void *data, int silent)
343 struct pohmelfs_sb *psb;
344 int err;
346 psb = kzalloc(sizeof(struct pohmelfs_sb), GFP_KERNEL);
347 if (!psb) {
348 err = -ENOMEM;
349 goto err_out_exit;
352 psb->bdi_num = atomic_inc_return(&psb_bdi_num);
354 err = bdi_init(&psb->bdi);
355 if (err)
356 goto err_out_free_psb;
358 err = bdi_register(&psb->bdi, NULL, "pfs-%d", psb->bdi_num);
359 if (err) {
360 bdi_destroy(&psb->bdi);
361 goto err_out_free_psb;
364 err = pohmelfs_init_psb(psb, sb);
365 if (err)
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);
375 if (err)
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);
381 } else {
382 err = pohmelfs_hash(psb, psb->fsid, psb->fsid_len, &psb->root->id);
384 if (err)
385 goto err_out_put_root;
387 sb->s_root = d_alloc_root(&psb->root->vfs_inode);
388 if (!sb->s_root) {
389 err = -ENOMEM;
390 goto err_out_put_root;
393 return 0;
395 err_out_put_root:
396 iput(&psb->root->vfs_inode);
397 err_out_cleanup_psb:
398 pohmelfs_cleanup_psb(psb);
399 err_out_free_bdi:
400 bdi_destroy(&psb->bdi);
401 err_out_free_psb:
402 kfree(psb);
403 err_out_exit:
404 pr_err("pohmelfs: %s: error: %d\n", __func__, err);
405 return 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)
416 sync_inodes_sb(sb);
417 kill_anon_super(sb);
420 static struct file_system_type pohmelfs_type = {
421 .owner = THIS_MODULE,
422 .name = "pohmelfs",
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)
444 int err = -ENOMEM;
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)
452 goto err_out_exit;
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;
470 return 0;
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);
478 err_out_exit:
479 return err;
482 static int __init pohmelfs_init(void)
484 int err;
486 err = pohmelfs_init_cache();
487 if (err)
488 goto err_out_exit;
490 err = register_filesystem(&pohmelfs_type);
491 if (err)
492 goto err_out_cleanup_cache;
494 return 0;
496 err_out_cleanup_cache:
497 pohmelfs_cleanup_cache();
498 err_out_exit:
499 return err;
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");