Tux3 kernel port, latest snapshot
From: | Daniel Phillips <phillips@phunq.net> | |
To: | tux3@tux3.org | |
Subject: | Tux3 kernel port, latest snapshot | |
Date: | Fri, 19 Sep 2008 03:25:01 -0700 | |
Message-ID: | <200809190325.01825.phillips@phunq.net> |
Hi all, Pretty soon we will make these Tux3 patches easy to get as snapshots from http://tux3.org, but for now I have to go diff my git tree each time I want one and email to everybody instead of posting a nice tidy URL. Not a problem the first few times... I added Maciej's superblock loading code (slightly massaged) to the Tux3 code, which up to now has been little more than a cut and paste of ramfs. It is still not significantly more than that, except Tux3 now expects to be mounted on a block device (I mount it on a file) and it will load a superblock from that device. Rather stylishly doing this at the bio API level, which was the subject of the most recent Tux3 University session. Which incidentally was lead by Maciej, who now officially takes on the role of our bio transfer goto guy. Talk about running directly on the metal, this is it. Well, compared to FUSE it is. Now we want to think about making a filesystem appear in the space fomerly occupied by this demo. Regards, Daniel P.S.: Next Tux3 U session is Tuesday, 19th September, 20 oclock Pacific time. Subject: Drilling deeper into generic_write. diff --git a/fs/Kconfig b/fs/Kconfig index 2694648..a428126 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -202,6 +202,14 @@ config EXT4DEV_FS_SECURITY If you are not using a security module that requires using extended attributes for file security labels, say N. +config TUX3 + tristate "Tux3 Versioning Filesystem" + help + To compile this filesystem as a module, choose M here: the module will + be called tux3. + + If unsure, say Maybe. + config JBD tristate help diff --git a/fs/Makefile b/fs/Makefile index 1e7a11b..c59a911 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -72,6 +72,7 @@ obj-$(CONFIG_EXT4DEV_FS) += ext4/ # Before ext2 so root fs can be ext4dev obj-$(CONFIG_JBD) += jbd/ obj-$(CONFIG_JBD2) += jbd2/ obj-$(CONFIG_EXT2_FS) += ext2/ +obj-$(CONFIG_TUX3) += tux3/ obj-$(CONFIG_CRAMFS) += cramfs/ obj-y += ramfs/ obj-$(CONFIG_HUGETLBFS) += hugetlbfs/ diff --git a/fs/tux3/Makefile b/fs/tux3/Makefile new file mode 100644 index 0000000..b247e05 --- /dev/null +++ b/fs/tux3/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_TUX3) += tux3.o +tux3-objs += inode.o super.o \ No newline at end of file diff --git a/fs/tux3/inode.c b/fs/tux3/inode.c new file mode 100644 index 0000000..23307cf --- /dev/null +++ b/fs/tux3/inode.c @@ -0,0 +1,147 @@ +/* + * Tux3 Versioning Filesystem + * + * Copyright (c) 2008, Daniel Phillips + * Portions Copyright (c) 2000 Linus Torvalds, 2000 Transmeta Corp. + * Licensed under the GPL v2 + */ + +#include <linux/fs.h> +#include <linux/pagemap.h> +#include <linux/string.h> +#include <linux/backing-dev.h> +#include <linux/module.h> +#include <linux/sched.h> // current +#include <linux/tux3.h> +#include "tux3.h" + +static const struct super_operations tux3_super_ops; +static const struct inode_operations tux3_dir_ops; + +static struct backing_dev_info tux3_backing_dev_info = { .ra_pages = 0, + .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK | + BDI_CAP_MAP_DIRECT | BDI_CAP_MAP_COPY | + BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP | BDI_CAP_EXEC_MAP +}; + +const struct address_space_operations tux3_aops = { + .readpage = simple_readpage, + .write_begin = simple_write_begin, + .write_end = simple_write_end, + .set_page_dirty = __set_page_dirty_no_writeback, +}; + +const struct file_operations tux3_file_ops = { + .read = do_sync_read, + .write = do_sync_write, + .aio_read = generic_file_aio_read, + .aio_write = generic_file_aio_write, + .splice_read = generic_file_splice_read, + .llseek = generic_file_llseek, + .fsync = simple_sync_file, + .mmap = generic_file_mmap, +}; + +const struct inode_operations tux3_file_inode_ops = { + .getattr = simple_getattr, +}; + +struct inode *tux3_get_inode(struct super_block *sb, int mode, dev_t dev) +{ + struct inode *inode = new_inode(sb); + + if (inode) { + inode->i_mode = mode; + inode->i_uid = current->fsuid; + inode->i_gid = current->fsgid; + inode->i_blocks = 0; + inode->i_mapping->a_ops = &tux3_aops; + inode->i_mapping->backing_dev_info = &tux3_backing_dev_info; + mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER); + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + switch (mode & S_IFMT) { + default: + init_special_inode(inode, mode, dev); + break; + case S_IFREG: + inode->i_op = &tux3_file_inode_ops; + inode->i_fop = &tux3_file_ops; + break; + case S_IFDIR: + inode->i_op = &tux3_dir_ops; + inode->i_fop = &simple_dir_operations; + /* directory inodes start off with i_nlink == 2 (for "." entry) */ + inc_nlink(inode); + break; + case S_IFLNK: + inode->i_op = &page_symlink_inode_operations; + break; + } + } + return inode; +} + +static int tux3_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) +{ + struct inode *inode = tux3_get_inode(dir->i_sb, mode, dev); + int error = -ENOSPC; + + if (inode) { + if (dir->i_mode & S_ISGID) { + inode->i_gid = dir->i_gid; + if (S_ISDIR(mode)) + inode->i_mode |= S_ISGID; + } + d_instantiate(dentry, inode); + dget(dentry); /* Extra count - pin the dentry in core */ + error = 0; + dir->i_mtime = dir->i_ctime = CURRENT_TIME; + } + return error; +} + +static int tux3_mkdir(struct inode *dir, struct dentry *dentry, int mode) +{ + int retval = tux3_mknod(dir, dentry, mode | S_IFDIR, 0); + if (!retval) + inc_nlink(dir); + return retval; +} + +static int tux3_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) +{ + return tux3_mknod(dir, dentry, mode | S_IFREG, 0); +} + +static int tux3_symlink(struct inode *dir, struct dentry *dentry, const char *symname) +{ + struct inode *inode; + int error = -ENOSPC; + + inode = tux3_get_inode(dir->i_sb, S_IFLNK|S_IRWXUGO, 0); + if (inode) { + int l = strlen(symname)+1; + error = page_symlink(inode, symname, l); + if (!error) { + if (dir->i_mode & S_ISGID) + inode->i_gid = dir->i_gid; + d_instantiate(dentry, inode); + dget(dentry); + dir->i_mtime = dir->i_ctime = CURRENT_TIME; + } else + iput(inode); + } + return error; +} + +static const struct inode_operations tux3_dir_ops = { + .create = tux3_create, + .lookup = simple_lookup, + .link = simple_link, + .unlink = simple_unlink, + .symlink = tux3_symlink, + .mkdir = tux3_mkdir, + .rmdir = simple_rmdir, + .mknod = tux3_mknod, + .rename = simple_rename, +}; diff --git a/fs/tux3/super.c b/fs/tux3/super.c new file mode 100644 index 0000000..ad4e1e0 --- /dev/null +++ b/fs/tux3/super.c @@ -0,0 +1,122 @@ +/* + * tux3/super.c + * Copyright (c) 2008, Daniel Phillips + * Portions copyright (c) 2008, Maciej Zenczykowski + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/pagemap.h> +#include <linux/bio.h> +#include <linux/fs.h> +#include <linux/tux3.h> +#include "tux3.h" + +#define SB_SIZE 512 + +struct mz { wait_queue_head_t *q; int completed; }; + +static void end_io_read(struct bio *bio, int err) +{ + struct mz *mz = bio->bi_private; +printk("wow! we got here\n"); + bio_put(bio); + mz->completed = 1; + wake_up(mz->q); +} + +static int junkfs_fill_super(struct super_block *sb, void *data, int silent) +{ + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(q); + struct mz mz = { .q = &q }; + struct bio *bio; + int err = 0, i; + u8 *buf; + + if (IS_ERR(bio = bio_alloc(GFP_KERNEL, 1))) + return PTR_ERR(bio); + + bio->bi_bdev = sb->s_bdev; + bio->bi_sector = 0; // first sector + + if (!(buf = kmalloc(SB_SIZE, GFP_KERNEL))) { + bio_put(bio); + err = -ENOMEM; + goto eek; + }; + + bio->bi_io_vec[bio->bi_vcnt] = (struct bio_vec){ + .bv_page = virt_to_page(buf), + .bv_offset = offset_in_page(buf), + .bv_len = SB_SIZE }; + bio->bi_size = SB_SIZE; + bio->bi_end_io = end_io_read; + bio->bi_private = &mz; + bio->bi_vcnt = 1; + submit_bio(READ, bio); + wait_event(q, mz.completed); + printk("super = "); + for(i = 0; i < 16; i++) + printk(" %02X", buf[i]); + printk("\n"); +eek: + return err; +} + +static const struct super_operations tux3_super_ops = { + .statfs = simple_statfs, + .drop_inode = generic_delete_inode, +}; + +static int tux3_fill_super(struct super_block *sb, void *data, int silent) +{ + struct inode *inode; + struct dentry *root; + +printk("we start here.\n"); + sb->s_maxbytes = MAX_LFS_FILESIZE; + sb->s_blocksize = PAGE_CACHE_SIZE; + sb->s_blocksize_bits = PAGE_CACHE_SHIFT; + sb->s_magic = 0x54555833; + sb->s_op = &tux3_super_ops; + sb->s_time_gran = 1; + inode = tux3_get_inode(sb, S_IFDIR | 0755, 0); + if (!inode) + return -ENOMEM; + + root = d_alloc_root(inode); + if (!root) { + iput(inode); + return -ENOMEM; + } + sb->s_root = root; + return junkfs_fill_super(sb, data, silent); +} + +static int tux3_get_sb(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data, struct vfsmount *mnt) +{ + return get_sb_bdev(fs_type, flags, dev_name, data, tux3_fill_super, mnt); +} + +static struct file_system_type tux3 = { + .name = "tux3", + .fs_flags = FS_REQUIRES_DEV, + .get_sb = tux3_get_sb, + .kill_sb = kill_block_super, + .owner = THIS_MODULE, +}; + +static int __init init_tux3(void) +{ + return register_filesystem(&tux3); +} + +static void __exit exit_tux3(void) +{ + unregister_filesystem(&tux3); +} + +module_init(init_tux3) +module_exit(exit_tux3) +MODULE_LICENSE("GPL"); diff --git a/fs/tux3/tux3.h b/fs/tux3/tux3.h new file mode 100644 index 0000000..670d88d --- /dev/null +++ b/fs/tux3/tux3.h @@ -0,0 +1 @@ +struct inode *tux3_get_inode(struct super_block *sb, int mode, dev_t dev); diff --git a/include/linux/tux3.h b/include/linux/tux3.h new file mode 100644 index 0000000..37d1dcb --- /dev/null +++ b/include/linux/tux3.h @@ -0,0 +1,4 @@ +#ifndef LINUX_TUX3_H +#define LINUX_TUX3_H + +#endif _______________________________________________ Tux3 mailing list Tux3@tux3.org http://tux3.org/cgi-bin/mailman/listinfo/tux3