From: Valerie Aurora <vaurora@xxxxxxxxxx> Add support for fallthru directory entries to ext2. Signed-off-by: Valerie Aurora <vaurora@xxxxxxxxxx> Signed-off-by: Jan Blunck <jblunck@xxxxxxx> Signed-off-by: David Howells <dhowells@xxxxxxxxxx> Cc: Jan Kara <jack@xxxxxxx> Cc: linux-ext4@xxxxxxxxxxxxxxx --- fs/ext2/dir.c | 49 +++++++++++++++++++++++++++++++++++++++++------ fs/ext2/ext2.h | 1 + fs/ext2/namei.c | 22 +++++++++++++++++++++ fs/ext2/super.c | 2 ++ include/linux/ext2_fs.h | 4 ++++ 5 files changed, 72 insertions(+), 6 deletions(-) diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index df4d6b1..5fd6bbe 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 @@ -355,8 +358,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; @@ -487,6 +502,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,7 +599,9 @@ int ext2_add_entry(struct dentry *dentry, ino_t ino, umode_t mode, rec_len = ext2_rec_len_from_disk(de->rec_len); if (ext2_match(namelen, name, de)) { err = -EEXIST; - /* XXX handle whiteouts and fallthroughs here */ + /* XXX handle whiteouts here too */ + if (de->file_type != EXT2_FT_FALLTHRU) + goto out_unlock; printk("%s: found existing de\n", dentry->d_name.name); goto got_it; } @@ -619,9 +640,17 @@ got_it: err = -EEXIST; if (ext2_match(namelen, name, de)) { switch (de->file_type) { + case EXT2_FT_FALLTHRU: + if (new_file_type == EXT2_FT_FALLTHRU) { + WARN(1, "Ext2: Can't turn fallthru into fallthru: %s\n", + dentry->d_name.name); + goto out_unlock; + } + break; case EXT2_FT_WHT: - if (new_file_type == EXT2_FT_WHT) { - WARN(1, "Ext2: Can't turn whiteout into whiteout: %s\n", + if (new_file_type == EXT2_FT_WHT || + new_file_type == EXT2_FT_FALLTHRU) { + WARN(1, "Ext2: Can't turn whiteout into fallthru/whiteout: %s\n", dentry->d_name.name); goto out_unlock; } @@ -675,6 +704,14 @@ int ext2_whiteout_entry(struct dentry *dentry) } /* + * Create a fallthru entry. + */ +int ext2_fallthru_entry(struct dentry *dentry) +{ + return ext2_add_entry(dentry, 0, 0, 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 b285d9a..dd82bc6 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 *); +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 8227267..957c4b9 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -331,6 +331,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); @@ -349,6 +350,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; + + spin_lock(&dentry->d_lock); + dentry->d_flags |= DCACHE_FALLTHRU; + spin_unlock(&dentry->d_lock); + d_instantiate(dentry, NULL); + return 0; +} + static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry, struct inode * new_dir, struct dentry * new_dentry ) { @@ -447,6 +468,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 8869794..bafd421 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -1100,6 +1100,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 2202faa..cd6d533 100644 --- a/include/linux/ext2_fs.h +++ b/include/linux/ext2_fs.h @@ -506,11 +506,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| \ @@ -578,6 +581,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