diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-04-19 04:00:00 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-04-19 04:00:00 +0000 |
commit | 46e045034336a2cc90c1798cd7cc07af744ddfd6 (patch) | |
tree | 3b9b51fc482e729f663d25333e77fbed9aaa939a /fs/ramfs | |
parent | 31dc59d503a02e84c4de98826452acaeb56dc15a (diff) |
Merge with Linux 2.3.99-pre4.
Diffstat (limited to 'fs/ramfs')
-rw-r--r-- | fs/ramfs/.cvsignore | 2 | ||||
-rw-r--r-- | fs/ramfs/Makefile | 11 | ||||
-rw-r--r-- | fs/ramfs/inode.c | 393 |
3 files changed, 406 insertions, 0 deletions
diff --git a/fs/ramfs/.cvsignore b/fs/ramfs/.cvsignore new file mode 100644 index 000000000..857dd22e9 --- /dev/null +++ b/fs/ramfs/.cvsignore @@ -0,0 +1,2 @@ +.depend +.*.flags diff --git a/fs/ramfs/Makefile b/fs/ramfs/Makefile new file mode 100644 index 000000000..f57d5966c --- /dev/null +++ b/fs/ramfs/Makefile @@ -0,0 +1,11 @@ +# +# Makefile for the linux ramfs routines. +# + +O_TARGET := ramfs.o + +O_OBJS := inode.o + +M_OBJS := $(O_TARGET) + +include $(TOPDIR)/Rules.make diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c new file mode 100644 index 000000000..e218051f3 --- /dev/null +++ b/fs/ramfs/inode.c @@ -0,0 +1,393 @@ +/* + * Resizable simple ram filesystem for Linux. + * + * Copyright (C) 2000 Linus Torvalds. + * 2000 Transmeta Corp. + * + * This file is released under the GPL. + */ + +/* + * NOTE! This filesystem is probably most useful + * not as a real filesystem, but as an example of + * how virtual filesystems can be written. + * + * It doesn't get much simpler than this. Consider + * that this file implements the full semantics of + * a POSIX-compliant read-write filesystem. + * + * Note in particular how the filesystem does not + * need to implement any data structures of its own + * to keep track of the virtual data: using the VFS + * caches is sufficient. + */ + +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/pagemap.h> +#include <linux/init.h> +#include <linux/string.h> +#include <linux/locks.h> + +#include <asm/uaccess.h> + +/* some random number */ +#define RAMFS_MAGIC 0x858458f6 + +static struct super_operations ramfs_ops; +static struct address_space_operations ramfs_aops; +static struct file_operations ramfs_dir_operations; +static struct file_operations ramfs_file_operations; +static struct inode_operations ramfs_dir_inode_operations; + +static int ramfs_statfs(struct super_block *sb, struct statfs *buf) +{ + buf->f_type = RAMFS_MAGIC; + buf->f_bsize = PAGE_CACHE_SIZE; + buf->f_namelen = 255; + return 0; +} + +/* + * Lookup the data. This is trivial - if the dentry didn't already + * exist, we know it is negative. + */ +static struct dentry * ramfs_lookup(struct inode *dir, struct dentry *dentry) +{ + d_add(dentry, NULL); + return NULL; +} + +/* + * Read a page. Again trivial. If it didn't already exist + * in the page cache, it is zero-filled. + */ +static int ramfs_readpage(struct dentry *dentry, struct page * page) +{ + if (!Page_Uptodate(page)) { + memset((void *) page_address(page), 0, PAGE_CACHE_SIZE); + SetPageUptodate(page); + } + UnlockPage(page); + return 0; +} + +/* + * Writing: just make sure the page gets marked dirty, so that + * the page stealer won't grab it. + */ +static int ramfs_writepage(struct dentry * dentry, struct page *page) +{ + SetPageDirty(page); + return 0; +} + +static int ramfs_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to) +{ + void *addr; + + addr = (void *) kmap(page); + if (!Page_Uptodate(page)) { + memset(addr, 0, PAGE_CACHE_SIZE); + SetPageUptodate(page); + } + SetPageDirty(page); + return 0; +} + +static int ramfs_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to) +{ + struct inode *inode = (struct inode*)page->mapping->host; + loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; + + kunmap(page); + if (pos > inode->i_size) + inode->i_size = pos; + return 0; +} + +struct inode *ramfs_get_inode(struct super_block *sb, int mode, int dev) +{ + struct inode * inode = get_empty_inode(); + + if (inode) { + inode->i_sb = sb; + inode->i_dev = sb->s_dev; + inode->i_mode = mode; + inode->i_uid = current->fsuid; + inode->i_gid = current->fsgid; + inode->i_size = 0; + inode->i_blksize = PAGE_CACHE_SIZE; + inode->i_blocks = 0; + inode->i_rdev = dev; + inode->i_nlink = 1; + inode->i_op = NULL; + inode->i_fop = NULL; + inode->i_mapping->a_ops = &ramfs_aops; + 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_fop = &ramfs_file_operations; + break; + case S_IFDIR: + inode->i_op = &ramfs_dir_inode_operations; + inode->i_fop = &ramfs_dir_operations; + break; + case S_IFLNK: + inode->i_op = &page_symlink_inode_operations; + break; + } + } + return inode; +} + +/* + * File creation. Allocate an inode, and we're done.. + */ +static int ramfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int dev) +{ + struct inode * inode = ramfs_get_inode(dir->i_sb, mode, dev); + int error = -ENOSPC; + + if (inode) { + d_instantiate(dentry, inode); + dget(dentry); /* Extra count - pin the dentry in core */ + error = 0; + } + return error; +} + +static int ramfs_mkdir(struct inode * dir, struct dentry * dentry, int mode) +{ + return ramfs_mknod(dir, dentry, mode | S_IFDIR, 0); +} + +static int ramfs_create(struct inode *dir, struct dentry *dentry, int mode) +{ + return ramfs_mknod(dir, dentry, mode | S_IFREG, 0); +} + +/* + * Link a file.. + */ +static int ramfs_link(struct dentry *old_dentry, struct inode * dir, struct dentry * dentry) +{ + struct inode *inode = old_dentry->d_inode; + + if (S_ISDIR(inode->i_mode)) + return -EPERM; + + inode->i_nlink++; + inode->i_count++; /* New dentry reference */ + dget(dentry); /* Extra pinning count for the created dentry */ + d_instantiate(dentry, inode); + return 0; +} + +static inline int ramfs_positive(struct dentry *dentry) +{ + return dentry->d_inode && !d_unhashed(dentry); +} + +/* + * Check that a directory is empty (this works + * for regular files too, they'll just always be + * considered empty..). + * + * Note that an empty directory can still have + * children, they just all have to be negative.. + */ +static int ramfs_empty(struct dentry *dentry) +{ + struct list_head *list = dentry->d_subdirs.next; + + while (list != &dentry->d_subdirs) { + struct dentry *de = list_entry(list, struct dentry, d_child); + + if (ramfs_positive(de)) + return 0; + list = list->next; + } + return 1; +} + +/* + * This works for both directories and regular files. + * (non-directories will always have empty subdirs) + */ +static int ramfs_unlink(struct inode * dir, struct dentry *dentry) +{ + int retval = -ENOTEMPTY; + + if (ramfs_empty(dentry)) { + struct inode *inode = dentry->d_inode; + + inode->i_nlink--; + dput(dentry); /* Undo the count from "create" - this does all the work */ + d_delete(dentry); + retval = 0; + } + return retval; +} + +#define ramfs_rmdir ramfs_unlink + +/* + * The VFS layer already does all the dentry stuff for rename, + * we just have to decrement the usage count for the target if + * it exists so that the VFS layer correctly free's it when it + * gets overwritten. + */ +static int ramfs_rename(struct inode * old_dir, struct dentry *old_dentry, struct inode * new_dir,struct dentry *new_dentry) +{ + int error = -ENOTEMPTY; + + if (ramfs_empty(new_dentry)) { + struct inode *inode = new_dentry->d_inode; + if (inode) { + inode->i_nlink--; + dput(new_dentry); + } + error = 0; + } + return error; +} + +static int ramfs_symlink(struct inode * dir, struct dentry *dentry, const char * symname) +{ + int error; + + error = ramfs_mknod(dir, dentry, S_IFLNK | S_IRWXUGO, 0); + if (!error) { + int l = strlen(symname)+1; + struct inode *inode = dentry->d_inode; + error = block_symlink(inode, symname, l); + } + return error; +} + +/* + * This really should be the same as the proc filldir, + * once proc does the "one dentry tree" thing.. + */ +static int ramfs_readdir(struct file * filp, void * dirent, filldir_t filldir) +{ + int i; + struct dentry *dentry = filp->f_dentry; + + i = filp->f_pos; + switch (i) { + case 0: + if (filldir(dirent, ".", 1, i, dentry->d_inode->i_ino) < 0) + break; + i++; + filp->f_pos++; + /* fallthrough */ + case 1: + if (filldir(dirent, "..", 2, i, dentry->d_parent->d_inode->i_ino) < 0) + break; + i++; + filp->f_pos++; + /* fallthrough */ + default: { + struct list_head *list = dentry->d_subdirs.next; + + int j = i-2; + for (;;) { + if (list == &dentry->d_subdirs) + return 0; + if (!j) + break; + j--; + list = list->next; + } + + do { + struct dentry *de = list_entry(list, struct dentry, d_child); + + if (ramfs_positive(de)) { + if (filldir(dirent, de->d_name.name, de->d_name.len, filp->f_pos, de->d_inode->i_ino) < 0) + break; + } + filp->f_pos++; + list = list->next; + } while (list != &dentry->d_subdirs); + } + } + return 0; +} + +static struct address_space_operations ramfs_aops = { + readpage: ramfs_readpage, + writepage: ramfs_writepage, + prepare_write: ramfs_prepare_write, + commit_write: ramfs_commit_write +}; + +static struct file_operations ramfs_file_operations = { + read: generic_file_read, + write: generic_file_write, + mmap: generic_file_mmap +}; + +static struct file_operations ramfs_dir_operations = { + read: generic_read_dir, + readdir: ramfs_readdir, +}; + +static struct inode_operations ramfs_dir_inode_operations = { + create: ramfs_create, + lookup: ramfs_lookup, + link: ramfs_link, + unlink: ramfs_unlink, + symlink: ramfs_symlink, + mkdir: ramfs_mkdir, + rmdir: ramfs_rmdir, + mknod: ramfs_mknod, + rename: ramfs_rename, +}; + + +static struct super_operations ramfs_ops = { + statfs: ramfs_statfs, +}; + +static struct super_block *ramfs_read_super(struct super_block * sb, void * data, int silent) +{ + struct inode * inode; + struct dentry * root; + + sb->s_blocksize = PAGE_CACHE_SIZE; + sb->s_blocksize_bits = PAGE_CACHE_SHIFT; + sb->s_magic = RAMFS_MAGIC; + sb->s_op = &ramfs_ops; + inode = ramfs_get_inode(sb, S_IFDIR | 0755, 0); + if (!inode) + return NULL; + + root = d_alloc_root(inode); + if (!root) { + iput(inode); + return NULL; + } + sb->s_root = root; + return sb; +} + +static DECLARE_FSTYPE(ramfs_fs_type, "ramfs", ramfs_read_super, 0); + +static int __init init_ramfs_fs(void) +{ + return register_filesystem(&ramfs_fs_type); +} + +static void __exit exit_ramfs_fs(void) +{ + unregister_filesystem(&ramfs_fs_type); +} + +module_init(init_ramfs_fs) +module_exit(exit_ramfs_fs) |