2 * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
6 #include <linux/kernel.h>
7 #include <linux/list.h>
8 #include <linux/sched.h>
9 #include <linux/slab.h>
10 #include <linux/stat.h>
11 #include <linux/types.h>
12 #include <linux/errno.h>
13 #include <linux/string.h>
14 #include <linux/kdev_t.h>
15 #include "linux/init.h"
16 #include "linux/workqueue.h"
25 #include "filehandle.h"
28 #define HUMFS_VERSION 2
30 static int humfs_stat_file(const char *path, struct externfs_data *ed,
31 dev_t *dev_out, unsigned long long *inode_out,
32 int *mode_out, int *nlink_out, int *uid_out,
33 int *gid_out, unsigned long long *size_out,
34 unsigned long *atime_out, unsigned long *mtime_out,
35 unsigned long *ctime_out, int *blksize_out,
36 unsigned long long *blocks_out)
38 struct humfs *mount = container_of(ed, struct humfs, ext);
39 const char *data_path[3] = { mount->data, path, NULL };
40 int err, mode, perms, major, minor;
43 err = host_stat_file(data_path, NULL, inode_out, mode_out,
44 nlink_out, NULL, NULL, size_out, atime_out,
45 mtime_out, ctime_out, blksize_out, blocks_out);
49 err = (*mount->meta->ownerships)(path, &perms, uid_out, gid_out,
50 &type, &major, &minor, mount);
54 *mode_out = (*mode_out & ~S_IRWXUGO) | perms;
60 *dev_out = MKDEV(major, minor);
64 *dev_out = MKDEV(major, minor);
74 *mode_out = (*mode_out & ~S_IFMT) | mode;
79 static int meta_type(const char *path, int *dev_out, void *m)
81 struct humfs *mount = m;
82 int err, type, maj, min;
85 err = (*mount->meta->ownerships)(path, NULL, NULL, NULL, &c, &maj,
94 *dev_out = MKDEV(maj, min);
98 type = OS_TYPE_CHARDEV;
101 type = OS_TYPE_BLOCKDEV;
117 static int humfs_file_type(const char *path, int *dev_out,
118 struct externfs_data *ed)
120 struct humfs *mount = container_of(ed, struct humfs, ext);
121 const char *data_path[3] = { mount->data, path, NULL };
124 type = meta_type(path, dev_out, mount);
128 return(host_file_type(data_path, dev_out));
131 static char *humfs_data_name(struct inode *inode)
133 struct externfs_data *ed = inode_externfs_info(inode);
134 struct humfs *mount = container_of(ed, struct humfs, ext);
136 return(inode_name_prefix(inode, mount->data));
139 static struct externfs_inode *humfs_init_file(struct externfs_data *ed)
141 struct humfs *mount = container_of(ed, struct humfs, ext);
142 struct humfs_file *hf;
144 hf = (*mount->meta->init_file)();
152 static int humfs_open_file(struct externfs_inode *ext, char *path, int uid,
153 int gid, struct inode *inode,
154 struct externfs_data *ed)
156 struct humfs *mount = container_of(ed, struct humfs, ext);
157 struct humfs_file *hf = container_of(ext, struct humfs_file, ext);
158 const char *data_path[3] = { mount->data, path, NULL };
159 struct openflags flags;
160 char tmp[HOSTFS_BUFSIZE], *file;
163 file = get_path(data_path, tmp, sizeof(tmp));
167 flags = of_rdwr(OPENFLAGS());
169 flags = of_direct(flags);
173 err = (*mount->meta->open_file)(hf, path, inode, mount);
177 err = open_filehandle(file, flags, 0, &hf->data);
180 else if(err == -EPERM){
181 flags = of_set_rw(flags, 1, 0);
182 err = open_filehandle(file, flags, 0, &hf->data);
189 is_reclaimable(&hf->data, humfs_data_name, inode);
192 free_path(file, tmp);
197 (*mount->meta->close_file)(hf);
201 static void *humfs_open_dir(char *path, int uid, int gid,
202 struct externfs_data *ed)
204 struct humfs *mount = container_of(ed, struct humfs, ext);
205 const char *data_path[3] = { mount->data, path, NULL };
207 return(host_open_dir(data_path));
210 static void humfs_close_dir(void *stream, struct externfs_data *ed)
212 os_close_dir(stream);
215 static char *humfs_read_dir(void *stream, unsigned long long *pos,
216 unsigned long long *ino_out, int *len_out,
217 struct externfs_data *ed)
219 struct humfs *mount = container_of(ed, struct humfs, ext);
221 return(generic_host_read_dir(stream, pos, ino_out, len_out, mount));
224 LIST_HEAD(humfs_replies);
227 struct aio_context aio;
228 struct list_head list;
229 void (*completion)(char *, int, void *);
236 static int humfs_reply_fd = -1;
238 struct humfs_aio last_task_aio, last_intr_aio;
239 struct humfs_aio *last_task_aio_ptr, *last_intr_aio_ptr;
241 void humfs_work_proc(void *unused)
243 struct humfs_aio *aio;
246 while(!list_empty(&humfs_replies)){
247 local_irq_save(flags);
248 aio = list_entry(humfs_replies.next, struct humfs_aio, list);
250 last_task_aio = *aio;
251 last_task_aio_ptr = aio;
253 list_del(&aio->list);
254 local_irq_restore(flags);
257 aio->err = aio->real_len;
258 (*aio->completion)(aio->buf, aio->err, aio->data);
263 DECLARE_WORK(humfs_work, humfs_work_proc, NULL);
265 static irqreturn_t humfs_interrupt(int irq, void *dev_id,
266 struct pt_regs *unused)
268 struct aio_thread_reply reply;
269 struct humfs_aio *aio;
270 int err, fd = (int) dev_id;
273 err = os_read_file(fd, &reply, sizeof(reply));
277 printk("humfs_interrupt - read returned err %d\n",
282 aio->err = reply.err;
283 list_add(&aio->list, &humfs_replies);
284 last_intr_aio = *aio;
285 last_intr_aio_ptr = aio;
288 if(!list_empty(&humfs_replies))
289 schedule_work(&humfs_work);
290 reactivate_fd(fd, HUMFS_IRQ);
294 static int init_humfs_aio(void)
298 err = os_pipe(fds, 1, 1);
300 printk("init_humfs_aio - pipe failed, err = %d\n", -err);
304 err = um_request_irq(HUMFS_IRQ, fds[0], IRQ_READ, humfs_interrupt,
305 SA_INTERRUPT | SA_SAMPLE_RANDOM, "humfs",
308 printk("init_humfs_aio - : um_request_irq failed, err = %d\n",
313 humfs_reply_fd = fds[1];
317 os_close_file(fds[0]);
318 os_close_file(fds[1]);
323 __initcall(init_humfs_aio);
325 static int humfs_aio(enum aio_type type, int fd, unsigned long long offset,
326 char *buf, int len, int real_len,
327 void (*completion)(char *, int, void *), void *arg)
329 struct humfs_aio *aio;
332 aio = kmalloc(sizeof(*aio), GFP_KERNEL);
335 *aio = ((struct humfs_aio) { .aio = INIT_AIO_CONTEXT,
336 .list = LIST_HEAD_INIT(aio->list),
337 .completion= completion,
340 .real_len = real_len,
343 err = submit_aio(type, fd, buf, len, offset, humfs_reply_fd, aio);
345 (*completion)(buf, err, arg);
351 static int humfs_read_file(struct externfs_inode *ext,
352 unsigned long long offset, char *buf, int len,
353 int ignore_start, int ignore_end,
354 void (*completion)(char *, int, void *), void *arg,
355 struct externfs_data *ed)
357 struct humfs_file *hf = container_of(ext, struct humfs_file, ext);
358 int fd = filehandle_fd(&hf->data);
361 (*completion)(buf, fd, arg);
365 return(humfs_aio(AIO_READ, fd, offset, buf, len, len, completion,
369 static int humfs_write_file(struct externfs_inode *ext,
370 unsigned long long offset,
371 const char *buf, int start, int len,
372 void (*completion)(char *, int, void *), void *arg,
373 struct externfs_data *ed)
375 struct humfs *mount = container_of(ed, struct humfs, ext);
376 struct humfs_file *hf = container_of(ext, struct humfs_file, ext);
377 int err, orig_len = len, fd = filehandle_fd(&hf->data);
380 (*completion)((char *) buf, fd, arg);
391 err = humfs_aio(AIO_WRITE, fd, offset, (char *) buf, len, orig_len,
403 static int humfs_map_file_page(struct externfs_inode *ext,
404 unsigned long long offset, char *buf, int w,
405 struct externfs_data *ed)
407 struct humfs_file *hf = container_of(ext, struct humfs_file, ext);
408 unsigned long long size, need;
409 int err, fd = filehandle_fd(&hf->data);
414 err = os_fd_size(fd, &size);
418 need = offset + PAGE_SIZE;
420 err = os_truncate_fd(fd, need);
425 return(physmem_subst_mapping(buf, fd, offset, w));
428 static void humfs_close_file(struct externfs_inode *ext,
429 unsigned long long size)
431 struct humfs_file *hf = container_of(ext, struct humfs_file, ext);
434 if(hf->data.fd == -1)
437 fd = filehandle_fd(&hf->data);
438 physmem_forget_descriptor(fd);
439 truncate_file(&hf->data, size);
440 close_file(&hf->data);
442 (*hf->mount->meta->close_file)(hf);
445 /* XXX Assumes that you can't make a normal file */
447 static int humfs_make_node(const char *path, int mode, int uid, int gid,
448 int type, int major, int minor,
449 struct externfs_data *ed)
451 struct humfs *mount = container_of(ed, struct humfs, ext);
452 struct file_handle fh;
453 const char *data_path[3] = { mount->data, path, NULL };
457 err = host_create_file(data_path, S_IRWXUGO, &fh);
478 printk("make_node - bad node type : %d\n", type);
482 err = (*mount->meta->make_node)(path, mode, uid, gid, t, major, minor,
491 host_unlink_file(data_path);
495 static int humfs_create_file(struct externfs_inode *ext, char *path, int mode,
496 int uid, int gid, struct inode *inode,
497 struct externfs_data *ed)
499 struct humfs *mount = container_of(ed, struct humfs, ext);
500 struct humfs_file *hf = container_of(ext, struct humfs_file, ext);
501 const char *data_path[3] = { mount->data, path, NULL };
504 err = (*mount->meta->create_file)(hf, path, mode, uid, gid, inode,
509 err = host_create_file(data_path, S_IRWXUGO, &hf->data);
514 is_reclaimable(&hf->data, humfs_data_name, inode);
519 (*mount->meta->remove_file)(path, mount);
520 (*mount->meta->close_file)(hf);
525 static int humfs_set_attr(const char *path, struct externfs_iattr *attrs,
526 struct externfs_data *ed)
528 struct humfs *mount = container_of(ed, struct humfs, ext);
529 const char *data_path[3] = { mount->data, path, NULL };
530 int (*chown)(const char *, int, int, int, struct humfs *);
533 chown = mount->meta->change_ownerships;
534 if(attrs->ia_valid & EXTERNFS_ATTR_MODE){
535 err = (*chown)(path, attrs->ia_mode, -1, -1, mount);
539 if(attrs->ia_valid & EXTERNFS_ATTR_UID){
540 err = (*chown)(path, -1, attrs->ia_uid, -1, mount);
544 if(attrs->ia_valid & EXTERNFS_ATTR_GID){
545 err = (*chown)(path, -1, -1, attrs->ia_gid, mount);
550 attrs->ia_valid &= ~(EXTERNFS_ATTR_MODE | EXTERNFS_ATTR_UID |
553 return(host_set_attr(data_path, attrs));
556 static int humfs_make_symlink(const char *from, const char *to, int uid,
557 int gid, struct externfs_data *ed)
559 struct humfs *mount = container_of(ed, struct humfs, ext);
560 struct humfs_file *hf;
561 const char *data_path[3] = { mount->data, from, NULL };
564 hf = (*mount->meta->init_file)();
568 err = (*mount->meta->create_file)(hf, from, S_IRWXUGO, uid, gid, NULL,
573 err = host_make_symlink(data_path, to);
575 (*mount->meta->remove_file)(from, mount);
578 (*mount->meta->close_file)(hf);
583 static int humfs_link_file(const char *to, const char *from, int uid, int gid,
584 struct externfs_data *ed)
586 struct humfs *mount = container_of(ed, struct humfs, ext);
587 const char *data_path_from[3] = { mount->data, from, NULL };
588 const char *data_path_to[3] = { mount->data, to, NULL };
591 err = (*mount->meta->create_link)(to, from, mount);
595 err = host_link_file(data_path_to, data_path_from);
597 (*mount->meta->remove_file)(from, mount);
602 static int humfs_unlink_file(const char *path, struct externfs_data *ed)
604 struct humfs *mount = container_of(ed, struct humfs, ext);
605 const char *data_path[3] = { mount->data, path, NULL };
608 err = (*mount->meta->remove_file)(path, mount);
612 (*mount->meta->remove_file)(path, mount);
613 return(host_unlink_file(data_path));
616 static void humfs_invisible(struct externfs_inode *ext)
618 struct humfs_file *hf = container_of(ext, struct humfs_file, ext);
619 struct humfs *mount = hf->mount;
621 (*mount->meta->invisible)(hf);
622 not_reclaimable(&hf->data);
625 static int humfs_make_dir(const char *path, int mode, int uid, int gid,
626 struct externfs_data *ed)
628 struct humfs *mount = container_of(ed, struct humfs, ext);
629 const char *data_path[3] = { mount->data, path, NULL };
632 err = (*mount->meta->create_dir)(path, mode, uid, gid, mount);
636 err = host_make_dir(data_path, S_IRWXUGO);
638 (*mount->meta->remove_dir)(path, mount);
643 static int humfs_remove_dir(const char *path, int uid, int gid,
644 struct externfs_data *ed)
646 struct humfs *mount = container_of(ed, struct humfs, ext);
647 const char *data_path[3] = { mount->data, path, NULL };
650 err = host_remove_dir(data_path);
654 (*mount->meta->remove_dir)(path, mount);
659 static int humfs_read_link(char *file, int uid, int gid, char *buf, int size,
660 struct externfs_data *ed)
662 struct humfs *mount = container_of(ed, struct humfs, ext);
663 const char *data_path[3] = { mount->data, file, NULL };
665 return(host_read_link(data_path, buf, size));
668 struct humfs *inode_humfs_info(struct inode *inode)
670 return(container_of(inode_externfs_info(inode), struct humfs, ext));
673 static int humfs_rename_file(char *from, char *to, struct externfs_data *ed)
675 struct humfs *mount = container_of(ed, struct humfs, ext);
676 const char *data_path_from[3] = { mount->data, from, NULL };
677 const char *data_path_to[3] = { mount->data, to, NULL };
680 err = (*mount->meta->rename_file)(from, to, mount);
684 err = host_rename_file(data_path_from, data_path_to);
686 (*mount->meta->rename_file)(to, from, mount);
691 static int humfs_stat_fs(long *bsize_out, long long *blocks_out,
692 long long *bfree_out, long long *bavail_out,
693 long long *files_out, long long *ffree_out,
694 void *fsid_out, int fsid_size, long *namelen_out,
695 long *spare_out, struct externfs_data *ed)
697 struct humfs *mount = container_of(ed, struct humfs, ext);
698 const char *data_path[3] = { mount->data, NULL };
701 /* XXX Needs to maintain this info as metadata */
702 err = host_stat_fs(data_path, bsize_out, blocks_out, bfree_out,
703 bavail_out, files_out, ffree_out, fsid_out,
704 fsid_size, namelen_out, spare_out);
708 *blocks_out = mount->total / *bsize_out;
709 *bfree_out = (mount->total - mount->used) / *bsize_out;
710 *bavail_out = (mount->total - mount->used) / *bsize_out;
714 int humfs_truncate_file(struct externfs_inode *ext, __u64 size,
715 struct externfs_data *ed)
717 struct humfs_file *hf = container_of(ext, struct humfs_file, ext);
719 return(truncate_file(&hf->data, size));
722 char *humfs_path(char *dir, char *file)
724 int need_slash, len = strlen(dir) + strlen(file);
727 need_slash = (dir[strlen(dir) - 1] != '/');
731 new = kmalloc(len + 1, GFP_KERNEL);
743 DECLARE_MUTEX(meta_sem);
744 struct list_head metas = LIST_HEAD_INIT(metas);
746 static struct humfs_meta_ops *find_meta(const char *name)
748 struct list_head *ele;
749 struct humfs_meta_ops *m;
752 list_for_each(ele, &metas){
753 m = list_entry(ele, struct humfs_meta_ops, list);
754 if(!strcmp(m->name, name))
763 void register_meta(struct humfs_meta_ops *ops)
766 list_add(&ops->list, &metas);
770 void unregister_meta(struct humfs_meta_ops *ops)
773 list_del(&ops->list);
777 static struct humfs *read_superblock(char *root)
780 struct humfs_meta_ops *meta = NULL;
781 struct file_handle *fh;
782 const char *path[] = { root, "superblock", NULL };
784 char meta_buf[33], line[HOSTFS_BUFSIZE], *newline;
785 unsigned long long pos;
786 int version, i, n, err;
788 fh = kmalloc(sizeof(*fh), GFP_KERNEL);
790 return(ERR_PTR(-ENOMEM));
792 err = host_open_file(path, 1, 0, fh);
794 printk("Failed to open %s/%s, errno = %d\n", path[0],
796 return(ERR_PTR(err));
804 n = read_file(fh, pos, &line[i], sizeof(line) - i - 1);
805 if((n == 0) && (i == 0))
814 newline = strchr(line, '\n');
816 printk("read_superblock - line too long : '%s'\n",
818 return(ERR_PTR(-EINVAL));
822 if(sscanf(line, "version %d\n", &version) == 1){
823 if(version != HUMFS_VERSION){
824 printk("humfs version mismatch - want version "
825 "%d, got version %d.\n", HUMFS_VERSION,
827 return(ERR_PTR(-EINVAL));
830 else if(sscanf(line, "used %Lu\n", &used) == 1) ;
831 else if(sscanf(line, "total %Lu\n", &total) == 1) ;
832 else if(sscanf(line, "metadata %32s\n", meta_buf) == 1){
833 meta = find_meta(meta_buf);
835 printk("read_superblock - meta api \"%s\" not "
836 "registered\n", meta_buf);
837 return(ERR_PTR(-EINVAL));
842 printk("read_superblock - bogus line : '%s'\n", line);
843 return(ERR_PTR(-EINVAL));
847 memmove(line, newline, sizeof(line) - i);
852 printk("read_superblock - used not specified or set to "
854 return(ERR_PTR(-EINVAL));
857 printk("read_superblock - total not specified or set to "
859 return(ERR_PTR(-EINVAL));
862 printk("read_superblock - used is greater than total\n");
863 return(ERR_PTR(-EINVAL));
867 meta = find_meta("shadow_fs");
871 printk("read_superblock - valid meta api was not specified\n");
872 return(ERR_PTR(-EINVAL));
875 mount = (*meta->init_mount)(root);
879 *mount = ((struct humfs) { .total = total,
885 struct externfs_file_ops humfs_no_mmap_file_ops = {
886 .stat_file = humfs_stat_file,
887 .file_type = humfs_file_type,
889 .open_file = humfs_open_file,
890 .open_dir = humfs_open_dir,
891 .read_dir = humfs_read_dir,
892 .read_file = humfs_read_file,
893 .write_file = humfs_write_file,
894 .map_file_page = NULL,
895 .close_file = humfs_close_file,
896 .close_dir = humfs_close_dir,
897 .invisible = humfs_invisible,
898 .create_file = humfs_create_file,
899 .set_attr = humfs_set_attr,
900 .make_symlink = humfs_make_symlink,
901 .unlink_file = humfs_unlink_file,
902 .make_dir = humfs_make_dir,
903 .remove_dir = humfs_remove_dir,
904 .make_node = humfs_make_node,
905 .link_file = humfs_link_file,
906 .read_link = humfs_read_link,
907 .rename_file = humfs_rename_file,
908 .statfs = humfs_stat_fs,
909 .truncate_file = humfs_truncate_file
912 struct externfs_file_ops humfs_mmap_file_ops = {
913 .stat_file = humfs_stat_file,
914 .file_type = humfs_file_type,
916 .open_file = humfs_open_file,
917 .open_dir = humfs_open_dir,
918 .invisible = humfs_invisible,
919 .read_dir = humfs_read_dir,
920 .read_file = humfs_read_file,
921 .write_file = humfs_write_file,
922 .map_file_page = humfs_map_file_page,
923 .close_file = humfs_close_file,
924 .close_dir = humfs_close_dir,
925 .create_file = humfs_create_file,
926 .set_attr = humfs_set_attr,
927 .make_symlink = humfs_make_symlink,
928 .unlink_file = humfs_unlink_file,
929 .make_dir = humfs_make_dir,
930 .remove_dir = humfs_remove_dir,
931 .make_node = humfs_make_node,
932 .link_file = humfs_link_file,
933 .read_link = humfs_read_link,
934 .rename_file = humfs_rename_file,
935 .statfs = humfs_stat_fs,
936 .truncate_file = humfs_truncate_file
939 static struct externfs_data *mount_fs(char *mount_arg)
941 char *root, *data, *flags;
943 struct externfs_file_ops *file_ops;
944 int err, do_mmap = 0;
946 if(mount_arg == NULL){
947 printk("humfs - no host directory specified\n");
951 flags = strchr((char *) mount_arg, ',');
956 if(!strcmp(flags, "mmap"))
959 flags = strchr(flags, ',');
960 } while(flags != NULL);
964 root = host_root_filename(mount_arg);
968 mount = read_superblock(root);
970 err = PTR_ERR(mount);
974 data = humfs_path(root, "data/");
978 if(CHOOSE_MODE(do_mmap, 0)){
979 printk("humfs doesn't support mmap in tt mode\n");
984 mount->mmap = do_mmap;
986 file_ops = do_mmap ? &humfs_mmap_file_ops : &humfs_no_mmap_file_ops;
987 init_externfs(&mount->ext, file_ops);
999 struct externfs_mount_ops humfs_mount_ops = {
1000 .init_file = humfs_init_file,
1004 static int __init init_humfs(void)
1006 return(register_externfs("humfs", &humfs_mount_ops));
1009 static void __exit exit_humfs(void)
1011 unregister_externfs("humfs");
1014 __initcall(init_humfs);
1015 __exitcall(exit_humfs);
1018 * Overrides for Emacs so that we follow Linus's tabbing style.
1019 * Emacs will notice this stuff at the end of the file and automatically
1020 * adjust the settings for this buffer only. This must remain at the end
1022 * ---------------------------------------------------------------------------
1024 * c-file-style: "linux"