linux-ext4.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 65/73] ext2: Add ext2_dirent_in_use() [ver #2]
       [not found] <20120221175721.25235.8901.stgit@warthog.procyon.org.uk>
@ 2012-02-21 18:05 ` David Howells
  2012-02-21 18:05 ` [PATCH 66/73] ext2: Split ext2_add_entry() from ext2_add_link() " David Howells
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 9+ messages in thread
From: David Howells @ 2012-02-21 18:05 UTC (permalink / raw)
  To: linux-fsdevel, viro, valerie.aurora
  Cc: linux-kernel, David Howells, linux-ext4

From: Valerie Aurora <vaurora@redhat.com>

Currently ext2 checks if a directory entry is in-use by checking if the inode
is non-zero.  Fallthrus and whiteouts will have zero inode but be in-use.  Add
a function to abstract out the directory entry in-use test.

Original-author: Valerie Aurora <vaurora@redhat.com>
Signed-off-by: David Howells <dhowells@redhat.com>
cc: linux-ext4@vger.kernel.org
---

 fs/ext2/dir.c |   12 +++++++++---
 1 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index d37df35..89015f1 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -218,6 +218,11 @@ fail:
 	return ERR_PTR(-EIO);
 }
 
+static inline int ext2_dirent_in_use(struct ext2_dir_entry_2 *de)
+{
+	return de->inode != 0;
+}
+
 /*
  * NOTE! unlike strncmp, ext2_match returns 1 for success, 0 for failure.
  *
@@ -228,7 +233,7 @@ static inline int ext2_match (int len, const char * const name,
 {
 	if (len != de->name_len)
 		return 0;
-	if (!de->inode)
+	if (!ext2_dirent_in_use(de))
 		return 0;
 	return !memcmp(name, de->name, len);
 }
@@ -527,6 +532,7 @@ int ext2_add_link (struct dentry *dentry, struct inode *inode)
 				rec_len = chunk_size;
 				de->rec_len = ext2_rec_len_to_disk(chunk_size);
 				de->inode = 0;
+				de->file_type = 0;
 				goto got_it;
 			}
 			if (de->rec_len == 0) {
@@ -540,7 +546,7 @@ int ext2_add_link (struct dentry *dentry, struct inode *inode)
 				goto out_unlock;
 			name_len = EXT2_DIR_REC_LEN(de->name_len);
 			rec_len = ext2_rec_len_from_disk(de->rec_len);
-			if (!de->inode && rec_len >= reclen)
+			if (!ext2_dirent_in_use(de) && rec_len >= reclen)
 				goto got_it;
 			if (rec_len >= name_len + reclen)
 				goto got_it;
@@ -558,7 +564,7 @@ got_it:
 	err = ext2_prepare_chunk(page, pos, rec_len);
 	if (err)
 		goto out_unlock;
-	if (de->inode) {
+	if (ext2_dirent_in_use(de)) {
 		ext2_dirent *de1 = (ext2_dirent *) ((char *) de + name_len);
 		de1->rec_len = ext2_rec_len_to_disk(rec_len - name_len);
 		de->rec_len = ext2_rec_len_to_disk(name_len);

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 66/73] ext2: Split ext2_add_entry() from ext2_add_link() [ver #2]
       [not found] <20120221175721.25235.8901.stgit@warthog.procyon.org.uk>
  2012-02-21 18:05 ` [PATCH 65/73] ext2: Add ext2_dirent_in_use() [ver #2] David Howells
@ 2012-02-21 18:05 ` David Howells
  2012-02-27  0:04   ` Ted Ts'o
  2012-02-21 18:06 ` [PATCH 68/73] ext2: Add whiteout and opaque directory support " David Howells
  2012-02-21 18:06 ` [PATCH 69/73] ext2: Add fallthru " David Howells
  3 siblings, 1 reply; 9+ messages in thread
From: David Howells @ 2012-02-21 18:05 UTC (permalink / raw)
  To: linux-fsdevel, viro, valerie.aurora
  Cc: linux-kernel, David Howells, Jan Kara, linux-ext4

From: Valerie Aurora <vaurora@redhat.com>

Allow future code to use the guts of ext2_add_link().

Original-author: Valerie Aurora <vaurora@redhat.com>
Signed-off-by: David Howells <dhowells@redhat.com>
Cc: Jan Kara <jack@suse.cz>
Cc: linux-ext4@kernel.org
---

 fs/ext2/dir.c |   10 ++++++----
 1 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index 89015f1..d8382dc 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -489,10 +489,7 @@ void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de,
 	mark_inode_dirty(dir);
 }
 
-/*
- *	Parent is locked.
- */
-int ext2_add_link (struct dentry *dentry, struct inode *inode)
+int ext2_add_entry(struct dentry *dentry, struct inode *inode)
 {
 	struct inode *dir = dentry->d_parent->d_inode;
 	const char *name = dentry->d_name.name;
@@ -588,6 +585,11 @@ out_unlock:
 	goto out_put;
 }
 
+int ext2_add_link(struct dentry *dentry, struct inode *inode)
+{
+	return ext2_add_entry(dentry, inode);
+}
+
 /*
  * ext2_delete_entry deletes a directory entry by merging it with the
  * previous entry. Page is up-to-date. Releases the page.

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 68/73] ext2: Add whiteout and opaque directory support [ver #2]
       [not found] <20120221175721.25235.8901.stgit@warthog.procyon.org.uk>
  2012-02-21 18:05 ` [PATCH 65/73] ext2: Add ext2_dirent_in_use() [ver #2] David Howells
  2012-02-21 18:05 ` [PATCH 66/73] ext2: Split ext2_add_entry() from ext2_add_link() " David Howells
@ 2012-02-21 18:06 ` David Howells
  2012-02-21 18:06 ` [PATCH 69/73] ext2: Add fallthru " David Howells
  3 siblings, 0 replies; 9+ messages in thread
From: David Howells @ 2012-02-21 18:06 UTC (permalink / raw)
  To: linux-fsdevel, viro, valerie.aurora
  Cc: linux-kernel, David Howells, linux-ext4

Add support for whiteouts and opaque directories to ext2.

Original-author: Valerie Aurora <vaurora@redhat.com>
Signed-off-by: David Howells <dhowells@redhat.com> (Further development)
cc: linux-ext4@vger.kernel.org
---

 fs/ext2/dir.c           |   62 ++++++++++++++++++++++++++++++++++++++++++++++-
 fs/ext2/ext2.h          |    2 ++
 fs/ext2/inode.c         |   11 ++++++--
 fs/ext2/namei.c         |   51 +++++++++++++++++++++++++++++++++++++--
 fs/ext2/super.c         |    4 +++
 include/linux/ext2_fs.h |    4 +++
 6 files changed, 128 insertions(+), 6 deletions(-)

diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index dcb2d64..df4d6b1 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -220,7 +220,7 @@ fail:
 
 static inline int ext2_dirent_in_use(struct ext2_dir_entry_2 *de)
 {
-	return de->inode != 0;
+	return de->inode != 0 || de->file_type == EXT2_FT_WHT;
 }
 
 /*
@@ -269,6 +269,7 @@ static unsigned char ext2_filetype_table[EXT2_FT_MAX] = {
 	[EXT2_FT_FIFO]		= DT_FIFO,
 	[EXT2_FT_SOCK]		= DT_SOCK,
 	[EXT2_FT_SYMLINK]	= DT_LNK,
+	[EXT2_FT_WHT]		= DT_WHT,
 };
 
 #define S_SHIFT 12
@@ -472,6 +473,26 @@ static int ext2_prepare_chunk(struct page *page, loff_t pos, unsigned len)
 	return __block_write_begin(page, pos, len, ext2_get_block);
 }
 
+/* Special version for filetype based whiteout support */
+ino_t ext2_inode_by_dentry(struct inode *dir, struct dentry *dentry)
+{
+	ino_t res = 0;
+	struct ext2_dir_entry_2 *de;
+	struct page *page;
+
+	de = ext2_find_entry(dir, &dentry->d_name, &page);
+	if (de) {
+		res = le32_to_cpu(de->inode);
+		if (!res && de->file_type == EXT2_FT_WHT) {
+			spin_lock(&dentry->d_lock);
+			dentry->d_flags |= DCACHE_WHITEOUT;
+			spin_unlock(&dentry->d_lock);
+		}
+		ext2_put_page(page);
+	}
+	return res;
+}
+
 /* Releases the page */
 void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de,
 		   struct page *page, struct inode *inode, int update_times)
@@ -580,6 +601,40 @@ int ext2_add_entry(struct dentry *dentry, ino_t ino, umode_t mode,
 	return -EINVAL;
 
 got_it:
+	/* Pre-existing entries with the same name are allowable depending on
+	 * the type of the entry being created, so we need to sanity check what
+	 * we got.
+	 *
+	 * - Fallthru entries may be replaced by regular entries (copyup or
+	 *   rename) or whiteouts (unlink, rmdir or rename), but not by another
+	 *   fallthru.
+	 * - Whiteout entries may be replaced by a regular entry (open, link,
+	 *   symlink, mkdir, mknod, socket or rename).
+	 * - Regular entries may be replaced by a whiteout (unlink, rmdir or
+	 *   rename).
+	 *
+	 * Fallthru entries may only be created during directory copyup and
+	 * should not already exist in the top directory at that time.
+	 */
+	err = -EEXIST;
+	if (ext2_match(namelen, name, de)) {
+		switch (de->file_type) {
+		case EXT2_FT_WHT:
+			if (new_file_type == EXT2_FT_WHT) {
+				WARN(1, "Ext2: Can't turn whiteout into whiteout: %s\n",
+				     dentry->d_name.name);
+				goto out_unlock;
+			}
+			break;
+		default:
+			if (new_file_type != EXT2_FT_WHT) {
+				WARN(1, "Ext2: Can't turn dirent into non-whiteout: %s\n",
+				     dentry->d_name.name);
+				goto out_unlock;
+			}
+			break;
+		}
+	}
 	pos = page_offset(page) +
 		(char*)de - (char*)page_address(page);
 	err = ext2_prepare_chunk(page, pos, rec_len);
@@ -614,6 +669,11 @@ int ext2_add_link(struct dentry *dentry, struct inode *inode)
 	return ext2_add_entry(dentry, inode->i_ino, inode->i_mode, 0);
 }
 
+int ext2_whiteout_entry(struct dentry *dentry)
+{
+	return ext2_add_entry(dentry, 0, 0, EXT2_FT_WHT);
+}
+
 /*
  * 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 75ad433..b285d9a 100644
--- a/fs/ext2/ext2.h
+++ b/fs/ext2/ext2.h
@@ -102,9 +102,11 @@ extern void ext2_rsv_window_add(struct super_block *sb, struct ext2_reserve_wind
 /* dir.c */
 extern int ext2_add_link (struct dentry *, struct inode *);
 extern ino_t ext2_inode_by_name(struct inode *, struct qstr *);
+extern ino_t ext2_inode_by_dentry(struct inode *, struct dentry *);
 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_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/inode.c b/fs/ext2/inode.c
index 740cad8..2ffc91a 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -1253,7 +1253,8 @@ void ext2_set_inode_flags(struct inode *inode)
 {
 	unsigned int flags = EXT2_I(inode)->i_flags;
 
-	inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC);
+	inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC|
+			    S_OPAQUE);
 	if (flags & EXT2_SYNC_FL)
 		inode->i_flags |= S_SYNC;
 	if (flags & EXT2_APPEND_FL)
@@ -1264,6 +1265,8 @@ void ext2_set_inode_flags(struct inode *inode)
 		inode->i_flags |= S_NOATIME;
 	if (flags & EXT2_DIRSYNC_FL)
 		inode->i_flags |= S_DIRSYNC;
+	if (flags & EXT2_OPAQUE_FL)
+		inode->i_flags |= S_OPAQUE;
 }
 
 /* Propagate flags from i_flags to EXT2_I(inode)->i_flags */
@@ -1271,8 +1274,8 @@ void ext2_get_inode_flags(struct ext2_inode_info *ei)
 {
 	unsigned int flags = ei->vfs_inode.i_flags;
 
-	ei->i_flags &= ~(EXT2_SYNC_FL|EXT2_APPEND_FL|
-			EXT2_IMMUTABLE_FL|EXT2_NOATIME_FL|EXT2_DIRSYNC_FL);
+	ei->i_flags &= ~(EXT2_SYNC_FL|EXT2_APPEND_FL|EXT2_IMMUTABLE_FL|
+			 EXT2_NOATIME_FL|EXT2_DIRSYNC_FL|EXT2_OPAQUE_FL);
 	if (flags & S_SYNC)
 		ei->i_flags |= EXT2_SYNC_FL;
 	if (flags & S_APPEND)
@@ -1283,6 +1286,8 @@ void ext2_get_inode_flags(struct ext2_inode_info *ei)
 		ei->i_flags |= EXT2_NOATIME_FL;
 	if (flags & S_DIRSYNC)
 		ei->i_flags |= EXT2_DIRSYNC_FL;
+	if (flags & S_OPAQUE)
+		ei->i_flags |= EXT2_OPAQUE_FL;
 }
 
 struct inode *ext2_iget (struct super_block *sb, unsigned long ino)
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index 0804198..8227267 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -55,7 +55,8 @@ static inline int ext2_add_nondir(struct dentry *dentry, struct inode *inode)
  * Methods themselves.
  */
 
-static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
+static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry,
+				  struct nameidata *nd)
 {
 	struct inode * inode;
 	ino_t ino;
@@ -63,7 +64,7 @@ static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, str
 	if (dentry->d_name.len > EXT2_NAME_LEN)
 		return ERR_PTR(-ENAMETOOLONG);
 
-	ino = ext2_inode_by_name(dir, &dentry->d_name);
+	ino = ext2_inode_by_dentry(dir, dentry);
 	inode = NULL;
 	if (ino) {
 		inode = ext2_iget(dir->i_sb, ino);
@@ -303,6 +304,51 @@ static int ext2_rmdir (struct inode * dir, struct dentry *dentry)
 	return err;
 }
 
+/*
+ * Create a whiteout for the dentry
+ */
+static int ext2_whiteout(struct inode *dir, struct dentry *dentry,
+			 struct dentry *new_dentry)
+{
+	struct inode *inode = dentry->d_inode;
+	int err = -ENOTEMPTY;
+
+	if (!EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
+				       EXT2_FEATURE_INCOMPAT_FILETYPE)) {
+		ext2_error(dir->i_sb, "ext2_whiteout",
+			   "can't set whiteout filetype");
+		err = -EPERM;
+		goto out;
+	}
+
+	dquot_initialize(dir);
+
+	if (inode && S_ISDIR(inode->i_mode) && !ext2_empty_dir(inode))
+		goto out;
+
+	err = ext2_whiteout_entry(dentry);
+	if (err)
+		goto out;
+
+	spin_lock(&new_dentry->d_lock);
+	new_dentry->d_flags |= DCACHE_WHITEOUT;
+	spin_unlock(&new_dentry->d_lock);
+	d_add(new_dentry, NULL);
+
+	if (inode) {
+		inode->i_ctime = dir->i_ctime;
+		inode_dec_link_count(inode);
+		if (S_ISDIR(inode->i_mode)) {
+			inode->i_size = 0;
+			inode_dec_link_count(inode);
+			inode_dec_link_count(dir);
+		}
+	}
+	err = 0;
+out:
+	return err;
+}
+
 static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry,
 	struct inode * new_dir,	struct dentry * new_dentry )
 {
@@ -400,6 +446,7 @@ const struct inode_operations ext2_dir_inode_operations = {
 	.mkdir		= ext2_mkdir,
 	.rmdir		= ext2_rmdir,
 	.mknod		= ext2_mknod,
+	.whiteout	= ext2_whiteout,
 	.rename		= ext2_rename,
 #ifdef CONFIG_EXT2_FS_XATTR
 	.setxattr	= generic_setxattr,
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 0090595..8869794 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -1097,6 +1097,10 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
 	if (EXT2_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL))
 		ext2_msg(sb, KERN_WARNING,
 			"warning: mounting ext3 filesystem as ext2");
+
+	if (EXT2_HAS_INCOMPAT_FEATURE(sb, EXT2_FEATURE_INCOMPAT_WHITEOUT))
+		sb->s_flags |= MS_WHITEOUT;
+
 	if (ext2_setup_super (sb, es, sb->s_flags & MS_RDONLY))
 		sb->s_flags |= MS_RDONLY;
 	ext2_write_super(sb);
diff --git a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h
index ce1b719..2202faa 100644
--- a/include/linux/ext2_fs.h
+++ b/include/linux/ext2_fs.h
@@ -190,6 +190,7 @@ struct ext2_group_desc
 #define EXT2_NOTAIL_FL			FS_NOTAIL_FL	/* file tail should not be merged */
 #define EXT2_DIRSYNC_FL			FS_DIRSYNC_FL	/* dirsync behaviour (directories only) */
 #define EXT2_TOPDIR_FL			FS_TOPDIR_FL	/* Top of directory hierarchies*/
+#define EXT2_OPAQUE_FL			FS_OPAQUE_FL	/* Dir is opaque */
 #define EXT2_RESERVED_FL		FS_RESERVED_FL	/* reserved for ext2 lib */
 
 #define EXT2_FL_USER_VISIBLE		FS_FL_USER_VISIBLE	/* User visible flags */
@@ -504,10 +505,12 @@ struct ext2_super_block {
 #define EXT3_FEATURE_INCOMPAT_RECOVER		0x0004
 #define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV	0x0008
 #define EXT2_FEATURE_INCOMPAT_META_BG		0x0010
+#define EXT2_FEATURE_INCOMPAT_WHITEOUT		0x0020
 #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_META_BG)
 #define EXT2_FEATURE_RO_COMPAT_SUPP	(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
 					 EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
@@ -574,6 +577,7 @@ enum {
 	EXT2_FT_FIFO		= 5,
 	EXT2_FT_SOCK		= 6,
 	EXT2_FT_SYMLINK		= 7,
+	EXT2_FT_WHT		= 8,
 	EXT2_FT_MAX
 };
 

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 69/73] ext2: Add fallthru support [ver #2]
       [not found] <20120221175721.25235.8901.stgit@warthog.procyon.org.uk>
                   ` (2 preceding siblings ...)
  2012-02-21 18:06 ` [PATCH 68/73] ext2: Add whiteout and opaque directory support " David Howells
@ 2012-02-21 18:06 ` David Howells
  2012-02-27  0:33   ` Ted Ts'o
  3 siblings, 1 reply; 9+ messages in thread
From: David Howells @ 2012-02-21 18:06 UTC (permalink / raw)
  To: linux-fsdevel, viro, valerie.aurora
  Cc: linux-kernel, Valerie Aurora, Jan Blunck, David Howells, Jan Kara,
	linux-ext4

From: Valerie Aurora <vaurora@redhat.com>

Add support for fallthru directory entries to ext2.

Signed-off-by: Valerie Aurora <vaurora@redhat.com>
Signed-off-by: Jan Blunck <jblunck@suse.de>
Signed-off-by: David Howells <dhowells@redhat.com>
Cc: Jan Kara <jack@suse.cz>
Cc: linux-ext4@vger.kernel.org
---

 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
 };
 


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH 66/73] ext2: Split ext2_add_entry() from ext2_add_link() [ver #2]
  2012-02-21 18:05 ` [PATCH 66/73] ext2: Split ext2_add_entry() from ext2_add_link() " David Howells
@ 2012-02-27  0:04   ` Ted Ts'o
  2012-02-27  3:30     ` Andreas Dilger
  0 siblings, 1 reply; 9+ messages in thread
From: Ted Ts'o @ 2012-02-27  0:04 UTC (permalink / raw)
  To: David Howells
  Cc: linux-fsdevel, viro, valerie.aurora, linux-kernel, Jan Kara,
	linux-ext4

On Tue, Feb 21, 2012 at 06:05:46PM +0000, David Howells wrote:
> From: Valerie Aurora <vaurora@redhat.com>
> 
> Allow future code to use the guts of ext2_add_link().
> 
> Original-author: Valerie Aurora <vaurora@redhat.com>
> Signed-off-by: David Howells <dhowells@redhat.com>
> Cc: Jan Kara <jack@suse.cz>
> Cc: linux-ext4@kernel.org

I'd suggest folding this in with the following patch (67/73).  It's
not clear from this patch why renaming ext2_add_link to
ext2_add_entry() makes sense and then adding a new ext2_add_link()
which calls ext_add_entry().   It doesn't seem to clarify much....

I won't insist on it, but this seems to be unnecessary complication.

      	    		       	  	       - Ted

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 69/73] ext2: Add fallthru support [ver #2]
  2012-02-21 18:06 ` [PATCH 69/73] ext2: Add fallthru " David Howells
@ 2012-02-27  0:33   ` Ted Ts'o
  0 siblings, 0 replies; 9+ messages in thread
From: Ted Ts'o @ 2012-02-27  0:33 UTC (permalink / raw)
  To: David Howells
  Cc: linux-fsdevel, viro, valerie.aurora, linux-kernel, Valerie Aurora,
	Jan Blunck, Jan Kara, linux-ext4

On Tue, Feb 21, 2012 at 06:06:11PM +0000, David Howells wrote:
> From: Valerie Aurora <vaurora@redhat.com>
> 
> Add support for fallthru directory entries to ext2.

As I mentioned, I wonder if it makes sense combine the patches for
whiteout and fallthrough director entries into a single patch.  Given
that the two patches modify the same functions, and in some cases
second modifies lines added or modified by first, it just makes life
easier if the two are folded together.

> --- 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

... and the codepoint 0x2000 in the INCOMPAT mask has since already
been assigned.

As I mentioned in a comment to the previous patch, any objections if
you combine these two fields into a single ROCOMPAT feature?

#define EXT2_FEATURE_RO_COMPAT_UNION_MOUNT	0x0800

						- Ted

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 66/73] ext2: Split ext2_add_entry() from ext2_add_link() [ver #2]
  2012-02-27  0:04   ` Ted Ts'o
@ 2012-02-27  3:30     ` Andreas Dilger
  2012-02-27 19:09       ` Ted Ts'o
  0 siblings, 1 reply; 9+ messages in thread
From: Andreas Dilger @ 2012-02-27  3:30 UTC (permalink / raw)
  To: Ted Ts'o
  Cc: David Howells, linux-fsdevel@vger.kernel.org,
	viro@ZenIV.linux.org.uk, valerie.aurora@gmail.com,
	linux-kernel@vger.kernel.org, Jan Kara, linux-ext4@kernel.org

On 2012-02-26, at 17:04, Ted Ts'o <tytso@mit.edu> wrote:
> On Tue, Feb 21, 2012 at 06:05:46PM +0000, David Howells wrote:
>> From: Valerie Aurora <vaurora@redhat.com>
>> 
>> Allow future code to use the guts of ext2_add_link().
>> 
>> Original-author: Valerie Aurora <vaurora@redhat.com>
>> Signed-off-by: David Howells <dhowells@redhat.com>
>> Cc: Jan Kara <jack@suse.cz>
>> Cc: linux-ext4@kernel.org
> 
> I'd suggest folding this in with the following patch (67/73).  It's
> not clear from this patch why renaming ext2_add_link to
> ext2_add_entry() makes sense and then adding a new ext2_add_link()
> which calls ext_add_entry().   It doesn't seem to clarify much....

Also, why is this being done in ext2, when it should only be done in ext4?

Fedora is already using ext4 for ext2- and ext3-formatted filesystems, to allow us to finally deprecate and then delete both of those trees and their ongoing duplicate maintenance.  Adding new features to ext2 doesn't help that goal at all.

Cheers, Andreas

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 66/73] ext2: Split ext2_add_entry() from ext2_add_link() [ver #2]
  2012-02-27  3:30     ` Andreas Dilger
@ 2012-02-27 19:09       ` Ted Ts'o
  2012-02-27 20:45         ` Andreas Dilger
  0 siblings, 1 reply; 9+ messages in thread
From: Ted Ts'o @ 2012-02-27 19:09 UTC (permalink / raw)
  To: Andreas Dilger
  Cc: David Howells, linux-fsdevel@vger.kernel.org,
	viro@ZenIV.linux.org.uk, valerie.aurora@gmail.com,
	linux-kernel@vger.kernel.org, Jan Kara, linux-ext4@kernel.org

On Sun, Feb 26, 2012 at 08:30:34PM -0700, Andreas Dilger wrote:
> > I'd suggest folding this in with the following patch (67/73).  It's
> > not clear from this patch why renaming ext2_add_link to
> > ext2_add_entry() makes sense and then adding a new ext2_add_link()
> > which calls ext_add_entry().   It doesn't seem to clarify much....
> 
> Also, why is this being done in ext2, when it should only be done in ext4?

I believe Val used ext2 as a proof-of-concept, because the codebase
was stable (and Union Mounts has been in the oven a loooong time, so
that was probably a good choice).  I agree that if union mounts is
finally going to make it upstream, this would be a good time to
support implemented for ext4, and to get the support into e2fsprogs.

BTW, one thing that I think would be a good thing to do while we're
making this change is to mask off the low 4 bits when looking at the
filetype field so eventually we can use the high 4 bits for some
future extension.

						- Ted

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 66/73] ext2: Split ext2_add_entry() from ext2_add_link() [ver #2]
  2012-02-27 19:09       ` Ted Ts'o
@ 2012-02-27 20:45         ` Andreas Dilger
  0 siblings, 0 replies; 9+ messages in thread
From: Andreas Dilger @ 2012-02-27 20:45 UTC (permalink / raw)
  To: Ted Ts'o
  Cc: David Howells, linux-fsdevel@vger.kernel.org,
	viro@ZenIV.linux.org.uk, valerie.aurora@gmail.com,
	linux-kernel@vger.kernel.org, Jan Kara, linux-ext4@kernel.org

On 2012-02-27, at 12:09 PM, Ted Ts'o wrote:
> On Sun, Feb 26, 2012 at 08:30:34PM -0700, Andreas Dilger wrote:
>>> I'd suggest folding this in with the following patch (67/73).  It's
>>> not clear from this patch why renaming ext2_add_link to
>>> ext2_add_entry() makes sense and then adding a new ext2_add_link()
>>> which calls ext_add_entry().   It doesn't seem to clarify much....
>> 
>> Also, why is this being done in ext2, when it should only be done in ext4?
> 
> I believe Val used ext2 as a proof-of-concept, because the codebase
> was stable (and Union Mounts has been in the oven a loooong time, so
> that was probably a good choice).  I agree that if union mounts is
> finally going to make it upstream, this would be a good time to
> support implemented for ext4, and to get the support into e2fsprogs.
> 
> BTW, one thing that I think would be a good thing to do while we're
> making this change is to mask off the low 4 bits when looking at the
> filetype field so eventually we can use the high 4 bits for some
> future extension.

Umm, we already DO use the high 4 bits for a future extension in the
EXT4_FEATURE_INCOMPAT_DIRDATA feature.  The bare minimum for this is
extracted from a larger patch that allows storing extra data in the
dirent.  We use it to store a filesystem-wide 128-bit identifier into
the dirent, and it could also be used to store the high 32 bits of the
inode number in a compatible way.

I haven't pushed this upstream as I don't think anyone else is interested
in this yet, but masking off the file type is definitely simple and could
be accepted upstream.

Index: linux-stage/fs/ext4/ext4.h
===================================================================
--- linux-stage.orig/fs/ext4/ext4.h
+++ linux-stage/fs/ext4/ext4.h
@@ -1262,6 +1265,24 @@ struct ext4_dir_entry_2 {
 #define EXT4_FT_SYMLINK		7

 #define EXT4_FT_MAX		8
+#define EXT4_FT_MASK		0xf
+
+#if EXT4_FT_MAX > EXT4_FT_MASK
+#error "conflicting EXT4_FT_MAX and EXT4_FT_MASK"
+#endif
+
+/*
+ * d_type has 4 unused bits, so it can hold four types data. these different
+ * type of data (e.g. lustre file ID, high 32 bits of 64-bit inode number)
+ * can be stored, in flag order, after file-name in ext4 dirent.
+*/
+/*
+ * This flag is added to d_type if ext4 dirent has extra data after filename.
+ * This data length is variable and length is stored in first byte of data.
+ * Data starts after filename NUL byte. This is used by Lustre FS.
+  */
+#define EXT4_DIRENT_LUFID		0x10

 /*
  * EXT4_DIR_PAD defines the directory entries boundaries
Index: linux-stage/fs/ext4/dir.c
===================================================================
--- linux-stage.orig/fs/ext4/dir.c
+++ linux-stage/fs/ext4/dir.c
@@ -53,11 +53,14 @@ const struct file_operations ext4_dir_op
 
 static unsigned char get_dtype(struct super_block *sb, int filetype)
 {
+	int fl_index = filetype & EXT4_FT_MASK;
+
 	if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FILETYPE) ||
-	    (filetype >= EXT4_FT_MAX))
+	    (fl_index >= EXT4_FT_MAX))
 		return DT_UNKNOWN;

-	return (ext4_filetype_table[filetype]);
+	return ext4_filetype_table[fl_index]);
+
 }




Cheers, Andreas

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2012-02-27 20:45 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <20120221175721.25235.8901.stgit@warthog.procyon.org.uk>
2012-02-21 18:05 ` [PATCH 65/73] ext2: Add ext2_dirent_in_use() [ver #2] David Howells
2012-02-21 18:05 ` [PATCH 66/73] ext2: Split ext2_add_entry() from ext2_add_link() " David Howells
2012-02-27  0:04   ` Ted Ts'o
2012-02-27  3:30     ` Andreas Dilger
2012-02-27 19:09       ` Ted Ts'o
2012-02-27 20:45         ` Andreas Dilger
2012-02-21 18:06 ` [PATCH 68/73] ext2: Add whiteout and opaque directory support " David Howells
2012-02-21 18:06 ` [PATCH 69/73] ext2: Add fallthru " David Howells
2012-02-27  0:33   ` Ted Ts'o

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).