Documentation/filesystems/ext2.txt | 16 ++ fs/ext3/inode.c | 3 fs/ext3/iopen.c | 239 +++++++++++++++++++++++++++++++++++++ fs/ext3/iopen.h | 15 ++ fs/ext3/namei.c | 13 ++ fs/ext3/super.c | 17 ++ include/linux/ext3_fs.h | 2 7 files changed, 304 insertions(+), 1 deletion(-) Index: linux-2.6.4-51.1/fs/ext3/inode.c =================================================================== --- linux-2.6.4-51.1.orig/fs/ext3/inode.c 2004-04-06 00:31:14.000000000 -0400 +++ linux-2.6.4-51.1/fs/ext3/inode.c 2004-04-06 00:31:24.000000000 -0400 @@ -37,6 +37,7 @@ #include #include #include "xattr.h" +#include "iopen.h" #include "acl.h" /* @@ -2472,6 +2473,8 @@ ei->i_acl = EXT3_ACL_NOT_CACHED; ei->i_default_acl = EXT3_ACL_NOT_CACHED; #endif + if (ext3_iopen_get_inode(inode)) + return; if (ext3_get_inode_loc(inode, &iloc, 0)) goto bad_inode; bh = iloc.bh; Index: linux-2.6.4-51.1/fs/ext3/iopen.c =================================================================== --- linux-2.6.4-51.1.orig/fs/ext3/iopen.c 2004-04-06 00:31:24.000000000 -0400 +++ linux-2.6.4-51.1/fs/ext3/iopen.c 2004-04-06 00:31:24.000000000 -0400 @@ -0,0 +1,223 @@ + + +/* + * linux/fs/ext3/iopen.c + * + * Special support for open by inode number + * + * Copyright (C) 2001 by Theodore Ts'o (tytso@alum.mit.edu). + * + * This file may be redistributed under the terms of the GNU General + * Public License. + */ + +#include +#include +#include +#include +#include +#include +#include "iopen.h" + +#ifndef assert +#define assert(test) J_ASSERT(test) +#endif + +#define IOPEN_NAME_LEN 32 + +/* + * This implements looking up an inode by number. + */ +static struct dentry *iopen_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) +{ + struct inode * inode; + unsigned long ino; + struct list_head *lp; + struct dentry *alternate; + char buf[IOPEN_NAME_LEN]; + + if (dentry->d_name.len >= IOPEN_NAME_LEN) + return ERR_PTR(-ENAMETOOLONG); + + memcpy(buf, dentry->d_name.name, dentry->d_name.len); + buf[dentry->d_name.len] = 0; + + if (strcmp(buf, ".") == 0) + ino = dir->i_ino; + else if (strcmp(buf, "..") == 0) + ino = EXT3_ROOT_INO; + else + ino = simple_strtoul(buf, 0, 0); + + if ((ino != EXT3_ROOT_INO && + //ino != EXT3_ACL_IDX_INO && + //ino != EXT3_ACL_DATA_INO && + ino < EXT3_FIRST_INO(dir->i_sb)) || + ino > le32_to_cpu(EXT3_SB(dir->i_sb)->s_es->s_inodes_count)) + return ERR_PTR(-ENOENT); + + inode = iget(dir->i_sb, ino); + if (!inode) + return ERR_PTR(-EACCES); + if (is_bad_inode(inode)) { + iput(inode); + return ERR_PTR(-ENOENT); + } + + /* preferrably return a connected dentry */ + spin_lock(&dcache_lock); + list_for_each(lp, &inode->i_dentry) { + alternate = list_entry(lp, struct dentry, d_alias); + assert(!(alternate->d_flags & DCACHE_DISCONNECTED)); + } + + if (!list_empty(&inode->i_dentry)) { + alternate = list_entry(inode->i_dentry.next, + struct dentry, d_alias); + dget_locked(alternate); + alternate->d_vfs_flags |= DCACHE_REFERENCED; + iput(inode); + spin_unlock(&dcache_lock); + return alternate; + } + dentry->d_flags |= DCACHE_DISCONNECTED; + spin_unlock(&dcache_lock); + + d_add(dentry, inode); + return NULL; +} + +#define do_switch(x,y) do { \ + __typeof__ (x) __tmp = x; \ + x = y; y = __tmp; } while (0) + +static inline void switch_names(struct dentry * dentry, struct dentry * target) +{ + const unsigned char *old_name, *new_name; + + memcpy(dentry->d_iname, target->d_iname, DNAME_INLINE_LEN); + old_name = target->d_name.name; + new_name = dentry->d_name.name; + if (old_name == target->d_iname) + old_name = dentry->d_iname; + if (new_name == dentry->d_iname) + new_name = target->d_iname; + target->d_name.name = new_name; + dentry->d_name.name = old_name; +} + + +struct dentry *iopen_connect_dentry(struct dentry *de, struct inode *inode) +{ + struct dentry *tmp, *goal = NULL; + struct list_head *lp; + + /* preferrably return a connected dentry */ + spin_lock(&dcache_lock); + /* verify this dentry is really new */ + assert(!de->d_inode); + assert(list_empty(&de->d_subdirs)); + assert(list_empty(&de->d_alias)); + + + list_for_each(lp, &inode->i_dentry) { + tmp = list_entry(lp, struct dentry, d_alias); + if (tmp->d_flags & DCACHE_DISCONNECTED) { + assert(tmp->d_alias.next == &inode->i_dentry); + assert(tmp->d_alias.prev == &inode->i_dentry); + goal = tmp; + dget_locked(goal); + break; + } + } + spin_unlock(&dcache_lock); + + if (!goal) + return NULL; + + goal->d_flags &= ~DCACHE_DISCONNECTED; + d_rehash(de); + d_move(goal, de); + + return goal; +} + +/* + * These are the special structures for the iopen pseudo directory. + */ + +static struct inode_operations iopen_inode_operations = { + lookup: iopen_lookup, /* BKL held */ +}; + +static struct file_operations iopen_file_operations = { + read: generic_read_dir, +}; + +static int match_dentry(struct dentry *dentry, const char *name) +{ + int len; + + len = strlen(name); + if (dentry->d_name.len != len) + return 0; + if (strncmp(dentry->d_name.name, name, len)) + return 0; + return 1; +} + +/* + * This function is spliced into ext3_lookup and returns 1 the file + * name is __iopen__ and dentry has been filled in appropriately. + */ +int ext3_check_for_iopen(struct inode * dir, struct dentry *dentry) +{ + struct inode * inode; + + if (dir->i_ino != EXT3_ROOT_INO || + !test_opt(dir->i_sb, IOPEN) || + !match_dentry(dentry, "__iopen__")) + return 0; + + inode = iget(dir->i_sb, EXT3_BAD_INO); + + if (!inode) + return 0; + d_add(dentry, inode); + return 1; +} + +/* + * This function is spliced into read_inode; it returns 1 if inode + * number is the one for /__iopen__, in which case the inode is filled + * in appropriately. Otherwise, this fuction returns 0. + */ +int ext3_iopen_get_inode(struct inode * inode) +{ + if (inode->i_ino != EXT3_BAD_INO) + return 0; + + inode->i_mode = S_IFDIR | S_IRUSR | S_IXUSR; + if (test_opt(inode->i_sb, IOPEN_NOPRIV)) + inode->i_mode |= 0777; + inode->i_uid = 0; + inode->i_gid = 0; + inode->i_nlink = 1; + inode->i_size = 4096; + inode->i_atime = CURRENT_TIME; + inode->i_ctime = CURRENT_TIME; + inode->i_mtime = CURRENT_TIME; + EXT3_I(inode)->i_dtime = 0; + inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size + * (for stat), not the fs block + * size */ + inode->i_blocks = 0; + inode->i_version = 1; + inode->i_generation = 0; + + inode->i_op = &iopen_inode_operations; + inode->i_fop = &iopen_file_operations; + inode->i_mapping->a_ops = 0; + + return 1; +} Index: linux-2.6.4-51.1/fs/ext3/iopen.h =================================================================== --- linux-2.6.4-51.1.orig/fs/ext3/iopen.h 2004-04-06 00:31:24.000000000 -0400 +++ linux-2.6.4-51.1/fs/ext3/iopen.h 2004-04-06 00:31:24.000000000 -0400 @@ -0,0 +1,15 @@ +/* + * iopen.h + * + * Special support for opening files by inode number. + * + * Copyright (C) 2001 by Theodore Ts'o (tytso@alum.mit.edu). + * + * This file may be redistributed under the terms of the GNU General + * Public License. + */ + +extern int ext3_check_for_iopen(struct inode * dir, struct dentry *dentry); +extern int ext3_iopen_get_inode(struct inode * inode); + + Index: linux-2.6.4-51.1/fs/ext3/namei.c =================================================================== --- linux-2.6.4-51.1.orig/fs/ext3/namei.c 2004-04-06 00:31:11.000000000 -0400 +++ linux-2.6.4-51.1/fs/ext3/namei.c 2004-04-06 00:31:24.000000000 -0400 @@ -37,6 +37,7 @@ #include #include #include "xattr.h" +#include "iopen.h" #include "acl.h" /* @@ -970,15 +971,21 @@ } #endif +struct dentry *iopen_connect_dentry(struct dentry *de, struct inode *inode); + static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) { struct inode * inode; struct ext3_dir_entry_2 * de; struct buffer_head * bh; + struct dentry *alternate = NULL; if (dentry->d_name.len > EXT3_NAME_LEN) return ERR_PTR(-ENAMETOOLONG); + if (ext3_check_for_iopen(dir, dentry)) + return NULL; + bh = ext3_find_entry(dentry, &de); inode = NULL; if (bh) { @@ -989,8 +996,14 @@ if (!inode) return ERR_PTR(-EACCES); } + if (inode && (alternate = iopen_connect_dentry(dentry, inode))) { + iput(inode); + return alternate; + } + if (inode) return d_splice_alias(inode, dentry); + d_add(dentry, inode); return NULL; } Index: linux-2.6.4-51.1/fs/ext3/super.c =================================================================== --- linux-2.6.4-51.1.orig/fs/ext3/super.c 2004-04-06 00:31:14.000000000 -0400 +++ linux-2.6.4-51.1/fs/ext3/super.c 2004-04-06 00:31:24.000000000 -0400 @@ -536,7 +536,7 @@ Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, Opt_noload, Opt_commit, Opt_journal_update, Opt_journal_inum, Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback, - Opt_ignore, Opt_err, + Opt_ignore, Opt_err, Opt_iopen, Opt_noiopen, Opt_iopen_nopriv, }; static match_table_t tokens = { @@ -575,6 +575,9 @@ {Opt_ignore, "noquota"}, {Opt_ignore, "quota"}, {Opt_ignore, "usrquota"}, + {Opt_iopen, "iopen"}, + {Opt_noiopen, "noiopen"}, + {Opt_iopen_nopriv, "iopen_nopriv"}, {Opt_err, NULL} }; @@ -762,6 +765,18 @@ case Opt_abort: set_opt(sbi->s_mount_opt, ABORT); break; + case Opt_iopen: + set_opt (sbi->s_mount_opt, IOPEN); + clear_opt (sbi->s_mount_opt, IOPEN_NOPRIV); + break; + case Opt_noiopen: + clear_opt (sbi->s_mount_opt, IOPEN); + clear_opt (sbi->s_mount_opt, IOPEN_NOPRIV); + break; + case Opt_iopen_nopriv: + set_opt (sbi->s_mount_opt, IOPEN); + set_opt (sbi->s_mount_opt, IOPEN_NOPRIV); + break; case Opt_ignore: break; default: Index: linux-2.6.4-51.1/include/linux/ext3_fs.h =================================================================== --- linux-2.6.4-51.1.orig/include/linux/ext3_fs.h 2004-04-06 00:31:11.000000000 -0400 +++ linux-2.6.4-51.1/include/linux/ext3_fs.h 2004-04-06 00:31:24.000000000 -0400 @@ -325,6 +325,8 @@ #define EXT3_MOUNT_NO_UID32 0x2000 /* Disable 32-bit UIDs */ #define EXT3_MOUNT_XATTR_USER 0x4000 /* Extended user attributes */ #define EXT3_MOUNT_POSIX_ACL 0x8000 /* POSIX Access Control Lists */ +#define EXT3_MOUNT_IOPEN 0x10000 /* Allow access via iopen */ +#define EXT3_MOUNT_IOPEN_NOPRIV 0x20000 /* Make iopen world-readable */ /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */ #ifndef _LINUX_EXT2_FS_H Index: linux-2.6.4-51.1/fs/ext3/Makefile =================================================================== --- linux-2.6.4-51.1.orig/fs/ext3/Makefile 2004-04-06 00:27:21.000000000 -0400 +++ linux-2.6.4-51.1/fs/ext3/Makefile 2004-04-06 00:31:42.000000000 -0400 @@ -5,7 +5,7 @@ obj-$(CONFIG_EXT3_FS) += ext3.o ext3-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \ - ioctl.o namei.o super.o symlink.o hash.o + ioctl.o namei.o super.o symlink.o hash.o iopen.o ext3-$(CONFIG_EXT3_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o ext3-$(CONFIG_EXT3_FS_POSIX_ACL) += acl.o