fs/libfs.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++- include/linux/fs.h | 7 +++++ 2 files changed, 72 insertions(+), 1 deletion(-) Index: linux-2.6/fs/libfs.c =================================================================== --- linux-2.6.orig/fs/libfs.c +++ linux-2.6/fs/libfs.c @@ -238,13 +238,72 @@ Enomem: return ERR_PTR(-ENOMEM); } +struct inode *simple_get_inode(struct super_block *sb, int mode, + int (*init)(struct inode *, void *), void *arg) +{ + struct inode * inode = new_inode(sb); + + if (!inode) + return ERR_PTR(-ENOSPC); + + inode->i_mode = mode; + inode->i_uid = current->fsuid; + inode->i_gid = current->fsgid; + inode->i_blksize = sb->s_blocksize; + inode->i_blocks = 0; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + + if (S_ISDIR(mode)) { + /* directory inodes start with i_nlink == 2 (for "." entry) */ + inode->i_nlink++; + /* i_size for "." and ".." */ + inode->i_size = 2 * SIMPLE_BOGO_DIRENT_SIZE; + } + + if (init) { + int error = init(inode, arg); + if (error) { + iput(inode); + inode = ERR_PTR(error); + } + } + + return inode; +} + +int simple_mknod_init(struct inode *dir, struct dentry *dentry, int mode, + int (*init)(struct inode *, void *), void *arg) +{ + struct inode * inode; + + inode = simple_get_inode(dir->i_sb, mode, init, arg); + if (IS_ERR(inode)) + return PTR_ERR(inode); + + if (dir->i_mode & S_ISGID) { + inode->i_gid = dir->i_gid; + if (S_ISDIR(mode)) + inode->i_mode |= S_ISGID; + } + + if (S_ISDIR(mode)) + dir->i_nlink++; + + dir->i_mtime = dir->i_ctime = CURRENT_TIME; + dir->i_size += SIMPLE_BOGO_DIRENT_SIZE; + d_instantiate(dentry, inode); + dget(dentry); /* pin the dentry in core */ + return 0; +} + int simple_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) { struct inode *inode = old_dentry->d_inode; - inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; + inode->i_ctime = dir->i_mtime = dir->i_ctime = CURRENT_TIME; inode->i_nlink++; atomic_inc(&inode->i_count); + dir->i_size += SIMPLE_BOGO_DIRENT_SIZE; dget(dentry); d_instantiate(dentry, inode); return 0; @@ -276,6 +335,7 @@ int simple_unlink(struct inode *dir, str inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; inode->i_nlink--; + dir->i_size -= SIMPLE_BOGO_DIRENT_SIZE; dput(dentry); return 0; } @@ -311,6 +371,8 @@ int simple_rename(struct inode *old_dir, old_dir->i_ctime = old_dir->i_mtime = new_dir->i_ctime = new_dir->i_mtime = inode->i_ctime = CURRENT_TIME; + old_dir->i_size -= SIMPLE_BOGO_DIRENT_SIZE; + new_dir->i_size += SIMPLE_BOGO_DIRENT_SIZE; return 0; } @@ -629,6 +691,8 @@ EXPORT_SYMBOL(simple_empty); EXPORT_SYMBOL(d_alloc_name); EXPORT_SYMBOL(simple_fill_super); EXPORT_SYMBOL(simple_getattr); +EXPORT_SYMBOL(simple_get_inode); +EXPORT_SYMBOL(simple_mknod_init); EXPORT_SYMBOL(simple_link); EXPORT_SYMBOL(simple_lookup); EXPORT_SYMBOL(simple_pin_fs); Index: linux-2.6/include/linux/fs.h =================================================================== --- linux-2.6.orig/include/linux/fs.h +++ linux-2.6/include/linux/fs.h @@ -1624,6 +1624,11 @@ extern loff_t dcache_dir_lseek(struct fi extern int dcache_readdir(struct file *, void *, filldir_t); extern int simple_getattr(struct vfsmount *, struct dentry *, struct kstat *); extern int simple_statfs(struct super_block *, struct kstatfs *); +extern struct inode *simple_get_inode(struct super_block *, int , + int (*init)(struct inode *, void *), + void *); +extern int simple_mknod_init(struct inode *, struct dentry *, int , + int (*init)(struct inode *, void *), void *); extern int simple_link(struct dentry *, struct inode *, struct dentry *); extern int simple_unlink(struct inode *, struct dentry *); extern int simple_rmdir(struct inode *, struct dentry *); @@ -1744,6 +1749,8 @@ ssize_t simple_attr_read(struct file *fi ssize_t simple_attr_write(struct file *file, const char __user *buf, size_t len, loff_t *ppos); +/* Pretend that each dirent is of this size in simple directories */ +#define SIMPLE_BOGO_DIRENT_SIZE 20 #ifdef CONFIG_SECURITY static inline char *alloc_secdata(void)