From: Valerie Aurora <vaurora@xxxxxxxxxx> Add support for fallthru directory entries to ext2. Cc: Jan Kara <jack@xxxxxxx> Cc: linux-ext4@xxxxxxxxxxxxxxx Signed-off-by: Valerie Aurora <vaurora@xxxxxxxxxx> Signed-off-by: Jan Blunck <jblunck@xxxxxxx> --- fs/ext2/dir.c | 44 ++++++++++++++++++++++++++++++++++++++------ fs/ext2/ext2.h | 1 + fs/ext2/namei.c | 22 ++++++++++++++++++++++ fs/ext2/super.c | 2 ++ include/linux/ext2_fs.h | 4 ++++ 5 files changed, 67 insertions(+), 6 deletions(-) diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index 4ef5777..0a95eea 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c @@ -220,7 +220,9 @@ fail: static inline int ext2_dirent_in_use(struct ext2_dir_entry_2 *de) { - return de->inode != 0 || de->file_type == EXT2_FT_WHT; + return de->inode != 0 || + de->file_type == EXT2_FT_WHT || + de->file_type == EXT2_FT_FALLTHRU; } /* @@ -270,6 +272,7 @@ static unsigned char ext2_filetype_table[EXT2_FT_MAX] = { [EXT2_FT_SOCK] = DT_SOCK, [EXT2_FT_SYMLINK] = DT_LNK, [EXT2_FT_WHT] = DT_WHT, + [EXT2_FT_FALLTHRU] = DT_UNKNOWN, }; #define S_SHIFT 12 @@ -350,8 +353,20 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir) offset = (char *)de - kaddr; over = filldir(dirent, de->name, de->name_len, - (n<<PAGE_CACHE_SHIFT) | offset, - le32_to_cpu(de->inode), d_type); + (n << PAGE_CACHE_SHIFT) | offset, + le32_to_cpu(de->inode), d_type); + if (over) { + ext2_put_page(page); + return 0; + } + } else if (de->file_type == EXT2_FT_FALLTHRU) { + int over; + + offset = (char *)de - kaddr; + /* XXX placeholder until generic_readdir_fallthru() arrives */ + over = filldir(dirent, de->name, de->name_len, + (n<<PAGE_CACHE_SHIFT) | offset, + 1, DT_UNKNOWN); /* XXX */ if (over) { ext2_put_page(page); return 0; @@ -482,6 +497,10 @@ ino_t ext2_inode_by_dentry(struct inode *dir, struct dentry *dentry) spin_lock(&dentry->d_lock); dentry->d_flags |= DCACHE_WHITEOUT; spin_unlock(&dentry->d_lock); + } else if (!res && de->file_type == EXT2_FT_FALLTHRU) { + spin_lock(&dentry->d_lock); + dentry->d_flags |= DCACHE_FALLTHRU; + spin_unlock(&dentry->d_lock); } ext2_put_page(page); } @@ -580,15 +599,18 @@ got_it: /* * Pre-existing entries with the same name are allowable * depending on the type of the entry being created. Regular - * entries replace whiteouts. Whiteouts replace regular - * entries. + * entries replace whiteouts and fallthrus. Whiteouts replace + * regular entries. Fallthrus replace nothing. */ err = -EEXIST; if (ext2_match(namelen, name, de)) { if (new_file_type == EXT2_FT_WHT) { if (de->file_type == EXT2_FT_WHT) goto out_unlock; - } else if (de->file_type != EXT2_FT_WHT) { + } else if (new_file_type == EXT2_FT_FALLTHRU) { + goto out_unlock; + } else if ((de->file_type != EXT2_FT_WHT) && + (de->file_type != EXT2_FT_FALLTHRU)) { goto out_unlock; } } @@ -639,6 +661,16 @@ int ext2_whiteout_entry (struct dentry *dentry, ext2_dirent *de, struct page *pa } /* + * Create a fallthru entry. + */ +int ext2_fallthru_entry (struct dentry *dentry) +{ + ext2_dirent *de = NULL; + struct page *page = NULL; + return ext2_add_entry(dentry, NULL, de, page, EXT2_FT_FALLTHRU); +} + +/* * ext2_delete_entry deletes a directory entry by merging it with the * previous entry. Page is up-to-date. Releases the page. */ diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h index 78719f4..cd538b5 100644 --- a/fs/ext2/ext2.h +++ b/fs/ext2/ext2.h @@ -107,6 +107,7 @@ extern int ext2_make_empty(struct inode *, struct inode *); extern struct ext2_dir_entry_2 * ext2_find_entry (struct inode *,struct qstr *, struct page **); extern int ext2_delete_entry (struct ext2_dir_entry_2 *, struct page *); extern int ext2_whiteout_entry (struct dentry *, struct ext2_dir_entry_2 *, struct page *); +extern int ext2_fallthru_entry (struct dentry *); extern int ext2_empty_dir (struct inode *); extern struct ext2_dir_entry_2 * ext2_dotdot (struct inode *, struct page **); extern void ext2_set_link(struct inode *, struct ext2_dir_entry_2 *, struct page *, struct inode *, int); diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index a17c9c8..61db2dd 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -345,6 +345,7 @@ static int ext2_whiteout(struct inode *dir, struct dentry *dentry, goto out; spin_lock(&new_dentry->d_lock); + new_dentry->d_flags &= ~DCACHE_FALLTHRU; new_dentry->d_flags |= DCACHE_WHITEOUT; spin_unlock(&new_dentry->d_lock); d_add(new_dentry, NULL); @@ -363,6 +364,26 @@ out: return err; } +/* + * Create a fallthru entry. + */ +static int ext2_fallthru (struct inode *dir, struct dentry *dentry) +{ + int err; + + dquot_initialize(dir); + + err = ext2_fallthru_entry(dentry); + if (err) + return err; + + d_instantiate(dentry, NULL); + spin_lock(&dentry->d_lock); + dentry->d_flags |= DCACHE_FALLTHRU; + spin_unlock(&dentry->d_lock); + return 0; +} + static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry, struct inode * new_dir, struct dentry * new_dentry ) { @@ -461,6 +482,7 @@ const struct inode_operations ext2_dir_inode_operations = { .rmdir = ext2_rmdir, .mknod = ext2_mknod, .whiteout = ext2_whiteout, + .fallthru = ext2_fallthru, .rename = ext2_rename, #ifdef CONFIG_EXT2_FS_XATTR .setxattr = generic_setxattr, diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 6167ff3..797f47d 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -1101,6 +1101,8 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) if (EXT2_HAS_INCOMPAT_FEATURE(sb, EXT2_FEATURE_INCOMPAT_WHITEOUT)) sb->s_flags |= MS_WHITEOUT; + if (EXT2_HAS_INCOMPAT_FEATURE(sb, EXT2_FEATURE_INCOMPAT_FALLTHRU)) + sb->s_flags |= MS_FALLTHRU; if (ext2_setup_super (sb, es, sb->s_flags & MS_RDONLY)) sb->s_flags |= MS_RDONLY; diff --git a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h index b0fb356..1a6f929 100644 --- a/include/linux/ext2_fs.h +++ b/include/linux/ext2_fs.h @@ -505,11 +505,14 @@ struct ext2_super_block { #define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 #define EXT2_FEATURE_INCOMPAT_META_BG 0x0010 #define EXT2_FEATURE_INCOMPAT_WHITEOUT 0x0020 +/* ext3/4 incompat flags take up the intervening constants */ +#define EXT2_FEATURE_INCOMPAT_FALLTHRU 0x2000 #define EXT2_FEATURE_INCOMPAT_ANY 0xffffffff #define EXT2_FEATURE_COMPAT_SUPP EXT2_FEATURE_COMPAT_EXT_ATTR #define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \ EXT2_FEATURE_INCOMPAT_WHITEOUT| \ + EXT2_FEATURE_INCOMPAT_FALLTHRU| \ EXT2_FEATURE_INCOMPAT_META_BG) #define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \ EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \ @@ -577,6 +580,7 @@ enum { EXT2_FT_SOCK = 6, EXT2_FT_SYMLINK = 7, EXT2_FT_WHT = 8, + EXT2_FT_FALLTHRU = 9, EXT2_FT_MAX }; -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html