linux-ext4.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data
@ 2012-09-22  4:00 Zheng Liu
  2012-09-22  4:00 ` [PATCH 01/21 v5] libext2fs: add INLINE_DATA into EXT2_LIB_SOFTSUPP_INCOMPAT Zheng Liu
                   ` (20 more replies)
  0 siblings, 21 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22  4:00 UTC (permalink / raw)
  To: linux-ext4; +Cc: tytso, Zheng Liu

Hi list,

Here is fifth try to make e2fsprogs support inline data.  In this version, all
patches are reworked according to Ted's comment, and now it is based on master
branch of e2fsprogs because part of this patch set has been applied.  Moreover,
it can handle new layout of inline data, which only stores parent inode number
in inode, and removes '.' and '..' directory entries.

v4->v5:
* rework all patches.
* handle new layout of inline data

v3->v4:
* [tune2fs] add inline data support
* [libext2fs] set EXT4_INLINE_DATA_FL to 0x1000000

v2->v3:
* [mke2fs] EXT4_FEATURE_INCOMPAT_INLINE_DATA is set back to 0x8000
* [mke2fs] enable inline_data on ext4dev filesystem
* [tests] modify a regression test in tests
* rebase to the latest pu branch of e2fsprogs
* fix some bugs

v1->v2:
* [mke2fs] automatically set EXT_ATTR feature when INLINE_DATA is set
* [debugfs] supports read-write mode

Regards,
Zheng
---
Zheng Liu (21):
      libext2fs: add INLINE_DATA into EXT2_LIB_SOFTSUPP_INCOMPAT
      libext2fs: add function to check inline_data flag for an inode
      libext2fs: add functions to operate extend attribute
      libext2fs: handle inline data in dir iterator function
      libext2fs: handle inline_data in block iterator function
      debugfs: make stat command support inline data
      libext2fs: handle inline data when expanding directory
      debugfs: make lsdel command support inline data
      libext2fs: handle inline data in read/write function
      debugfs: handle inline_data feature in dirsearch command
      debugfs: handle inline_data feature in bmap command
      debugfs: handle inline_data in punch command
      libext2fs: add inline_data feature into EXT2_LIB_FEATURE_INCOMPAT_SUPP
      mke2fs: add inline_data support in mke2fs
      tune2fs: add inline_data feature in tune2fs
      e2fsck: add problem descriptions and check inline data feature
      e2fsck: check inline_data in pass1
      e2fsck: check inline_data in pass2
      e2fsck: check inline_data in pass3
      tests: change result in f_bad_disconnected_inode
      mke2fs: enable inline_data feature on ext4dev filesystem

 debugfs/debugfs.c                       |  13 +-
 debugfs/htree.c                         |   7 +
 debugfs/lsdel.c                         |   3 +-
 e2fsck/pass1.c                          | 104 +++++++++++-
 e2fsck/pass2.c                          | 123 +++++++++++----
 e2fsck/pass3.c                          |   8 +
 e2fsck/problem.c                        |  15 ++
 e2fsck/problem.h                        |   9 ++
 e2fsck/rehash.c                         |   3 +-
 lib/ext2fs/Makefile.in                  |   8 +
 lib/ext2fs/Makefile.pq                  |   1 +
 lib/ext2fs/block.c                      |   7 +
 lib/ext2fs/bmap.c                       |  15 ++
 lib/ext2fs/dblist_dir.c                 |  10 +-
 lib/ext2fs/dir_iterate.c                | 101 +++++++++++-
 lib/ext2fs/expanddir.c                  |  18 ++-
 lib/ext2fs/ext2_err.et.in               |   9 ++
 lib/ext2fs/ext2_ext_attr.h              |  30 ++++
 lib/ext2fs/ext2_fs.h                    |   7 +
 lib/ext2fs/ext2fs.h                     |  49 +++++-
 lib/ext2fs/ext2fsP.h                    |  18 +++
 lib/ext2fs/ext_attr.c                   | 169 ++++++++++++++++++++
 lib/ext2fs/fileio.c                     |  19 ++-
 lib/ext2fs/inline_data.c                | 896 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/ext2fs/mkdir.c                      |  18 ++-
 lib/ext2fs/punch.c                      |  10 +-
 misc/mke2fs.8.in                        |   3 +
 misc/mke2fs.c                           |  14 +-
 misc/mke2fs.conf.in                     |   2 +-
 misc/tune2fs.8.in                       |   5 +
 misc/tune2fs.c                          |  17 +-
 tests/f_bad_disconnected_inode/expect.1 |   9 ++
 32 files changed, 1665 insertions(+), 55 deletions(-)

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

* [PATCH 01/21 v5] libext2fs: add INLINE_DATA into EXT2_LIB_SOFTSUPP_INCOMPAT
  2012-09-22  4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
@ 2012-09-22  4:00 ` Zheng Liu
  2012-09-22  4:00 ` [PATCH 02/21 v5] libext2fs: add function to check inline_data flag for an inode Zheng Liu
                   ` (19 subsequent siblings)
  20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22  4:00 UTC (permalink / raw)
  To: linux-ext4; +Cc: tytso, Zheng Liu

From: Zheng Liu <wenqing.lz@taobao.com>

EXT4_FEATURE_INCOMPAT_INLINE_DATA flag is added into EXT2_LIB_SOFTSUPP_INCOMPAT
due to we still need to take a long time to test inline_data feature.

Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 lib/ext2fs/ext2fs.h |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 9927875..1cd53f0 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -602,7 +602,7 @@ typedef struct ext2_icount *ext2_icount_t;
  * These features are only allowed if EXT2_FLAG_SOFTSUPP_FEATURES is passed
  * to ext2fs_openfs()
  */
-#define EXT2_LIB_SOFTSUPP_INCOMPAT	(0)
+#define EXT2_LIB_SOFTSUPP_INCOMPAT	(EXT4_FEATURE_INCOMPAT_INLINE_DATA)
 #define EXT2_LIB_SOFTSUPP_RO_COMPAT	(EXT4_FEATURE_RO_COMPAT_REPLICA)
 
 
-- 
1.7.4.1


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

* [PATCH 02/21 v5] libext2fs: add function to check inline_data flag for an inode
  2012-09-22  4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
  2012-09-22  4:00 ` [PATCH 01/21 v5] libext2fs: add INLINE_DATA into EXT2_LIB_SOFTSUPP_INCOMPAT Zheng Liu
@ 2012-09-22  4:00 ` Zheng Liu
  2012-09-22  4:00 ` [PATCH 03/21 v5] libext2fs: add functions to operate extend attribute Zheng Liu
                   ` (18 subsequent siblings)
  20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22  4:00 UTC (permalink / raw)
  To: linux-ext4; +Cc: tytso, Zheng Liu

From: Zheng Liu <wenqing.lz@taobao.com>

A new file called `inline_data.c' is created, and a function called
`ext2fs_inode_has_inline_data' is defined to check whether an inode
has inline data or not.

Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 lib/ext2fs/Makefile.in   |    8 ++++++++
 lib/ext2fs/Makefile.pq   |    1 +
 lib/ext2fs/ext2fs.h      |    3 +++
 lib/ext2fs/inline_data.c |   30 ++++++++++++++++++++++++++++++
 4 files changed, 42 insertions(+), 0 deletions(-)
 create mode 100644 lib/ext2fs/inline_data.c

diff --git a/lib/ext2fs/Makefile.in b/lib/ext2fs/Makefile.in
index 8930fdb..7201fa2 100644
--- a/lib/ext2fs/Makefile.in
+++ b/lib/ext2fs/Makefile.in
@@ -59,6 +59,7 @@ OBJS= $(DEBUGFS_LIB_OBJS) $(RESIZE_LIB_OBJS) $(E2IMAGE_LIB_OBJS) \
 	ind_block.o \
 	initialize.o \
 	inline.o \
+	inline_data.o \
 	inode.o \
 	io_manager.o \
 	ismounted.o \
@@ -132,6 +133,7 @@ SRCS= ext2_err.c \
 	$(srcdir)/ind_block.c \
 	$(srcdir)/initialize.c \
 	$(srcdir)/inline.c \
+	$(srcdir)/inline_data.c	\
 	$(srcdir)/inode.c \
 	$(srcdir)/inode_io.c \
 	$(srcdir)/imager.c \
@@ -743,6 +745,12 @@ inline.o: $(srcdir)/inline.c $(top_builddir)/lib/config.h \
  $(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
  $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
  $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
+inline_data.o: $(srcdir)/inline_data.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/ext2_fs.h \
+ $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
+ $(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 inode.o: $(srcdir)/inode.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/dirpaths.h $(srcdir)/ext2_fs.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fsP.h \
diff --git a/lib/ext2fs/Makefile.pq b/lib/ext2fs/Makefile.pq
index 2f7b654..89082a7 100644
--- a/lib/ext2fs/Makefile.pq
+++ b/lib/ext2fs/Makefile.pq
@@ -27,6 +27,7 @@ OBJS= 	alloc.obj \
 	icount.obj \
 	initialize.obj \
 	inline.obj \
+	inline_data.obj \
 	inode.obj \
 	ismounted.obj \
 	link.obj \
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 1cd53f0..8714f58 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -1320,6 +1320,9 @@ extern errcode_t ext2fs_icount_store(ext2_icount_t icount, ext2_ino_t ino,
 extern ext2_ino_t ext2fs_get_icount_size(ext2_icount_t icount);
 errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *);
 
+/* inline_data.c */
+extern int ext2fs_inode_has_inline_data(ext2_filsys fs, ext2_ino_t ino);
+
 /* inode.c */
 extern errcode_t ext2fs_flush_icache(ext2_filsys fs);
 extern errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan,
diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c
new file mode 100644
index 0000000..0341ee3
--- /dev/null
+++ b/lib/ext2fs/inline_data.c
@@ -0,0 +1,30 @@
+/*
+ * inline_data.c --- data in inode
+ *
+ * Copyright (C) 2012 Zheng Liu <wenqing.lz@taobao.com>
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU library
+ * General Public License, version 2.
+ * %End-Header%
+ */
+
+#include "config.h"
+#include <stdio.h>
+
+#include "ext2_fs.h"
+
+#include "ext2fs.h"
+#include "ext2fsP.h"
+
+int ext2fs_inode_has_inline_data(ext2_filsys fs, ext2_ino_t ino)
+{
+	struct ext2_inode inode;
+	errcode_t retval;
+
+	retval = ext2fs_read_inode(fs, ino, &inode);
+	if (retval)
+		return 0;
+
+	return (inode.i_flags & EXT4_INLINE_DATA_FL);
+}
-- 
1.7.4.1


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

* [PATCH 03/21 v5] libext2fs: add functions to operate extend attribute
  2012-09-22  4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
  2012-09-22  4:00 ` [PATCH 01/21 v5] libext2fs: add INLINE_DATA into EXT2_LIB_SOFTSUPP_INCOMPAT Zheng Liu
  2012-09-22  4:00 ` [PATCH 02/21 v5] libext2fs: add function to check inline_data flag for an inode Zheng Liu
@ 2012-09-22  4:00 ` Zheng Liu
  2012-09-22  4:00 ` [PATCH 04/21 v5] libext2fs: handle inline data in dir iterator function Zheng Liu
                   ` (17 subsequent siblings)
  20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22  4:00 UTC (permalink / raw)
  To: linux-ext4; +Cc: tytso, Zheng Liu

From: Zheng Liu <wenqing.lz@taobao.com>

We need to define some functions to operate extend attribte due to inline data
needs to change it.

Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 lib/ext2fs/ext2_ext_attr.h |   30 ++++++++
 lib/ext2fs/ext2fs.h        |   13 ++++
 lib/ext2fs/ext_attr.c      |  169 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 212 insertions(+), 0 deletions(-)

diff --git a/lib/ext2fs/ext2_ext_attr.h b/lib/ext2fs/ext2_ext_attr.h
index bbb0aaa..de60097 100644
--- a/lib/ext2fs/ext2_ext_attr.h
+++ b/lib/ext2fs/ext2_ext_attr.h
@@ -15,6 +15,10 @@
 /* Maximum number of references to one attribute block */
 #define EXT2_EXT_ATTR_REFCOUNT_MAX	1024
 
+/* Name indexes */
+#define EXT4_EXT_ATTR_INDEX_SYSTEM	7
+#define EXT4_EXT_ATTR_SYSTEM_DATA	"data"
+
 struct ext2_ext_attr_header {
 	__u32	h_magic;	/* magic number for identification */
 	__u32	h_refcount;	/* reference count */
@@ -25,6 +29,10 @@ struct ext2_ext_attr_header {
 	__u32	h_reserved[3];	/* zero right now */
 };
 
+struct ext2_ext_attr_ibody_header {
+	__u32	h_magic;
+};
+
 struct ext2_ext_attr_entry {
 	__u8	e_name_len;	/* length of name */
 	__u8	e_name_index;	/* attribute name index */
@@ -57,6 +65,28 @@ struct ext2_ext_attr_entry {
 #define EXT2_XATTR_SIZE(size) \
 	(((size) + EXT2_EXT_ATTR_ROUND) & ~EXT2_EXT_ATTR_ROUND)
 
+#define IHDR(inode) \
+	((struct ext2_ext_attr_ibody_header *) \
+		((void *)inode + \
+		EXT2_GOOD_OLD_INODE_SIZE + \
+		inode->i_extra_isize))
+#define IFIRST(hdr) ((struct ext2_ext_attr_entry *)((hdr)+1))
+
+struct ext2_ext_attr_info {
+	int name_index;
+	const char *name;
+	const void *value;
+	size_t value_len;
+};
+
+struct ext2_ext_attr_search {
+	struct ext2_ext_attr_entry *first;
+	void *base;
+	void *end;
+	struct ext2_ext_attr_entry *here;
+	int not_found;
+};
+
 #ifdef __KERNEL__
 # ifdef CONFIG_EXT2_FS_EXT_ATTR
 extern int ext2_get_ext_attr(struct inode *, const char *, char *, size_t, int);
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 8714f58..b076c3c 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -1132,6 +1132,19 @@ extern errcode_t ext2fs_adjust_ea_refcount3(ext2_filsys fs, blk64_t blk,
 					   char *block_buf,
 					   int adjust, __u32 *newcount,
 					   ext2_ino_t inum);
+extern errcode_t ext2fs_ibody_find_ext_attr(ext2_filsys fs,
+					    struct ext2_inode_large *inode,
+					    struct ext2_ext_attr_info *i,
+					    struct ext2_ext_attr_search *s);
+extern errcode_t ext2fs_find_entry_ext_attr(struct ext2_ext_attr_entry **pentry,
+					    int name_index, const char *name,
+					    size_t size, int sorted);
+extern errcode_t ext2fs_set_entry_ext_attr(struct ext2_ext_attr_info *i,
+					   struct ext2_ext_attr_search *s);
+extern int ext2fs_ibody_get_ext_attr(ext2_filsys fs,
+				     struct ext2_inode_large *inode,
+				     int name_index, const char *name,
+				     void *buffer, size_t buf_len);
 
 /* extent.c */
 extern errcode_t ext2fs_extent_header_verify(void *ptr, int size);
diff --git a/lib/ext2fs/ext_attr.c b/lib/ext2fs/ext_attr.c
index 9649a14..c663f31 100644
--- a/lib/ext2fs/ext_attr.c
+++ b/lib/ext2fs/ext_attr.c
@@ -186,3 +186,172 @@ errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
 	return ext2fs_adjust_ea_refcount2(fs, blk, block_buf, adjust,
 					  newcount);
 }
+
+errcode_t ext2fs_find_entry_ext_attr(struct ext2_ext_attr_entry **pentry,
+				     int name_index, const char *name,
+				     size_t size, int sorted)
+{
+	struct ext2_ext_attr_entry *entry;
+	size_t name_len;
+	int cmp;
+
+	name_len = strlen(name);
+	for (entry = *pentry; !EXT2_EXT_IS_LAST_ENTRY(entry);
+	     entry = EXT2_EXT_ATTR_NEXT(entry)) {
+		cmp = name_index - entry->e_name_index;
+		if (!cmp)
+			cmp = name_len - entry->e_name_len;
+		if (!cmp)
+			cmp = memcmp(name, EXT2_EXT_ATTR_NAME(entry),
+				     name_len);
+		if (!cmp)
+			break;
+	}
+	*pentry = entry;
+
+	return cmp;
+}
+
+errcode_t ext2fs_ibody_find_ext_attr(ext2_filsys fs,
+				     struct ext2_inode_large *inode,
+				     struct ext2_ext_attr_info *i,
+				     struct ext2_ext_attr_search *s)
+{
+	struct ext2_ext_attr_ibody_header *header;
+	int error;
+
+	if (inode->i_extra_isize == 0)
+		return 0;
+	header = IHDR(inode);
+	s->base = s->first = IFIRST(header);
+	s->here = s->first;
+	s->end = (void *)inode + EXT2_INODE_SIZE(fs->super);
+	error = ext2fs_find_entry_ext_attr(&s->here, i->name_index,
+					   i->name, s->end -
+					   (void *)s->base, 0);
+	s->not_found = error;
+	return 0;
+}
+
+extern int ext2fs_ibody_get_ext_attr(ext2_filsys fs,
+				     struct ext2_inode_large *inode,
+				     int name_index, const char *name,
+				     void *buffer, size_t buf_len)
+{
+	struct ext2_ext_attr_ibody_header *header;
+	struct ext2_ext_attr_entry *entry;
+	size_t size;
+	void *end;
+	int error;
+
+	header = IHDR(inode);
+	entry = IFIRST(header);
+	end = (void *)inode + EXT2_INODE_SIZE(fs->super);
+	error = ext2fs_find_entry_ext_attr(&entry, name_index, name,
+					   end - (void *)entry, 0);
+	if (error)
+		return error;
+	size = ext2fs_le32_to_cpu(entry->e_value_size);
+	if (buffer) {
+		if (size > buf_len)
+			return error;
+		memcpy(buffer, (void *)IFIRST(header) +
+		       ext2fs_le16_to_cpu(entry->e_value_offs), size);
+	}
+	error = size;
+
+	return error;
+}
+
+errcode_t ext2fs_set_entry_ext_attr(struct ext2_ext_attr_info *i,
+				    struct ext2_ext_attr_search *s)
+{
+	struct ext2_ext_attr_entry *last;
+	size_t free, min_offs = s->end - s->base, name_len = strlen(i->name);
+
+	last = s->first;
+	for (; !EXT2_EXT_IS_LAST_ENTRY(last); last = EXT2_EXT_ATTR_NEXT(last)) {
+		if (!last->e_value_block && last->e_value_size) {
+			size_t offs = ext2fs_le16_to_cpu(last->e_value_offs);
+			if (offs < min_offs)
+				min_offs = offs;
+		}
+	}
+	free = min_offs - ((void *)last - s->base) - sizeof(__u32);
+	if (!s->not_found) {
+		if (!s->here->e_value_block & s->here->e_value_size) {
+			size_t size = ext2fs_le32_to_cpu(s->here->e_value_size);
+			free += EXT2_EXT_ATTR_SIZE(size);
+		}
+		free += EXT2_EXT_ATTR_LEN(name_len);
+	}
+	if (i->value) {
+		if (free < EXT2_EXT_ATTR_SIZE(i->value_len) ||
+		    free < EXT2_EXT_ATTR_LEN(name_len) +
+			   EXT2_EXT_ATTR_SIZE(i->value_len))
+			return -1;
+	}
+	if (i->value && s->not_found) {
+		size_t size = EXT2_EXT_ATTR_LEN(name_len);
+		size_t rest = (void *)last - (void *)s->here + sizeof(__u32);
+		memmove((void *)s->here + size, s->here, rest);
+		memset(s->here, 0, size);
+		s->here->e_name_index = i->name_index;
+		s->here->e_name_len = name_len;
+		memcpy(EXT2_EXT_ATTR_NAME(s->here),
+		       EXT2_EXT_ATTR_NAME(i), name_len);
+	} else {
+		if (!s->here->e_value_block && s->here->e_value_size) {
+			void *first_val = s->base + min_offs;
+			size_t offs = ext2fs_le16_to_cpu(s->here->e_value_offs);
+			void *val = s->base + offs;
+			size_t size = EXT2_EXT_ATTR_SIZE(
+				ext2fs_le32_to_cpu(s->here->e_value_size));
+
+			if (i->value && size == EXT2_EXT_ATTR_SIZE(i->value_len)) {
+				s->here->e_value_size =
+					ext2fs_cpu_to_le32(i->value_len);
+				memset(val + size - EXT2_EXT_ATTR_PAD, 0,
+					EXT2_EXT_ATTR_PAD);
+				memcpy(val, i->value, i->value_len);
+				return 0;
+			}
+
+			memmove(first_val + size, first_val, val - first_val);
+			memset(first_val, 0, size);
+			s->here->e_value_size = 0;
+			s->here->e_value_offs = 0;
+			min_offs += size;
+
+			last = s->first;
+			while (!EXT2_EXT_IS_LAST_ENTRY(last)) {
+				size_t o = ext2fs_le16_to_cpu(last->e_value_offs);
+				if (!last->e_value_block &&
+				    last->e_value_size && o < offs)
+					last->e_value_offs =
+						ext2fs_cpu_to_le16(o + size);
+				last = EXT2_EXT_ATTR_NEXT(last);
+			}
+		}
+		if (!i->value) {
+			size_t size = EXT2_EXT_ATTR_LEN(name_len);
+			last = (struct ext2_ext_attr_entry *)last - size;
+			memmove(s->here, (void *)s->here + size,
+				(void *)last - (void *)s->here + sizeof(__u32));
+			memset(last, 0, size);
+		}
+	}
+
+	if (i->value) {
+		s->here->e_value_size = ext2fs_cpu_to_le32(i->value_len);
+		if (i->value_len) {
+			size_t size = EXT2_EXT_ATTR_SIZE(i->value_len);
+			void *val = s->base + min_offs - size;
+			s->here->e_value_offs = ext2fs_cpu_to_le16(min_offs - size);
+			memset(val + size - EXT2_EXT_ATTR_PAD, 0,
+				EXT2_EXT_ATTR_PAD);
+			memcpy(val, i->value, i->value_len);
+		}
+	}
+	return 0;
+}
-- 
1.7.4.1


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

* [PATCH 04/21 v5] libext2fs: handle inline data in dir iterator function
  2012-09-22  4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
                   ` (2 preceding siblings ...)
  2012-09-22  4:00 ` [PATCH 03/21 v5] libext2fs: add functions to operate extend attribute Zheng Liu
@ 2012-09-22  4:00 ` Zheng Liu
  2012-09-22  4:00 ` [PATCH 05/21 v5] libext2fs: handle inline_data in block " Zheng Liu
                   ` (16 subsequent siblings)
  20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22  4:00 UTC (permalink / raw)
  To: linux-ext4; +Cc: tytso, Zheng Liu

From: Zheng Liu <wenqing.lz@taobao.com>

Inline_data is handled in dir iterator because a lot of commands use this
function to traverse directory entries debugfs.  We need to handle inline_data
individually because inline_data is saved in two places.  One is in i_block, and
another is in ibody extend attribute.

After adding these functions, some commands in debugfs can support inline_data
feature as below:
	- ncheck
	- chroot
	- cd
	- ls
	- pwd
	- link*
	- unlink

* If inline_data doesn't expand to ibody extend attribute, link command will
  allocate a new block for this inode instead of using extend attribute when we
  exhaust all space of i_block.

Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 lib/ext2fs/dir_iterate.c  |  101 +++++++++++++++++++++++++++++++++-
 lib/ext2fs/ext2_err.et.in |    6 ++
 lib/ext2fs/ext2_fs.h      |    7 +++
 lib/ext2fs/ext2fs.h       |   11 ++++
 lib/ext2fs/ext2fsP.h      |    7 +++
 lib/ext2fs/inline_data.c  |  132 +++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 262 insertions(+), 2 deletions(-)

diff --git a/lib/ext2fs/dir_iterate.c b/lib/ext2fs/dir_iterate.c
index c24015c..7b82fb1 100644
--- a/lib/ext2fs/dir_iterate.c
+++ b/lib/ext2fs/dir_iterate.c
@@ -123,8 +123,14 @@ errcode_t ext2fs_dir_iterate2(ext2_filsys fs,
 	ctx.func = func;
 	ctx.priv_data = priv_data;
 	ctx.errcode = 0;
-	retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_READ_ONLY, 0,
-				       ext2fs_process_dir_block, &ctx);
+	if (ext2fs_inode_has_inline_data(fs, dir))
+		retval = ext2fs_inline_data_iterate(fs, dir,
+						BLOCK_FLAG_READ_ONLY, 0,
+						ext2fs_process_dir_inline_data,
+						&ctx);
+	else
+		retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_READ_ONLY, 0,
+					       ext2fs_process_dir_block, &ctx);
 	if (!block_buf)
 		ext2fs_free_mem(&ctx.buf);
 	if (retval)
@@ -275,3 +281,94 @@ next:
 	return 0;
 }
 
+int ext2fs_process_dir_inline_data(ext2_filsys	fs,
+				   void		*buf,
+				   int		buf_len,
+				   e2_blkcnt_t	blockcnt,
+				   struct ext2_inode_large *inode,
+				   void		*priv_data)
+{
+	struct dir_context *ctx = (struct dir_context *) priv_data;
+	unsigned int	offset = 0;
+	unsigned int	next_real_entry = 0;
+	int		ret = 0;
+	int		changed = 0;
+	int		do_abort = 0;
+	unsigned int	rec_len, size;
+	int		entry;
+	struct ext2_dir_entry *dirent;
+
+	if (blockcnt < 0)
+		return 0;
+
+	entry = blockcnt ? DIRENT_OTHER_FILE : DIRENT_DOT_FILE;
+
+	while (offset < buf_len) {
+		dirent = (struct ext2_dir_entry *) (buf + offset);
+		if (ext2fs_get_rec_len(fs, dirent, &rec_len))
+			return BLOCK_ABORT;
+		if (((offset + rec_len) > buf_len) ||
+		    (rec_len < 8) ||
+		    ((rec_len % 4) != 0) ||
+		    ((((unsigned) dirent->name_len & 0xFF)+8) > rec_len)) {
+			ctx->errcode = EXT2_ET_DIR_CORRUPTED;
+			return BLOCK_ABORT;
+		}
+		if (!dirent->inode &&
+		    !(ctx->flags & DIRENT_FLAG_INCLUDE_EMPTY))
+			goto next;
+
+		ret = (ctx->func)(ctx->dir,
+				  (next_real_entry > offset) ?
+				  DIRENT_DELETED_FILE : entry,
+				  dirent, offset,
+				  buf_len, buf,
+				  ctx->priv_data);
+		if (entry < DIRENT_OTHER_FILE)
+			entry++;
+
+		if (ret & DIRENT_CHANGED) {
+			dirent->rec_len = rec_len;
+			changed++;
+		}
+		if (ret & DIRENT_ABORT) {
+			do_abort++;
+			break;
+		}
+next:
+		if (next_real_entry == offset)
+			next_real_entry += rec_len;
+
+		if (ctx->flags & DIRENT_FLAG_INCLUDE_REMOVED) {
+			size = ((dirent->name_len & 0xFF) + 11) & ~3;
+
+			if (rec_len != size)  {
+				unsigned int final_offset;
+
+				final_offset = offset + rec_len;
+				offset += size;
+				while (offset < final_offset &&
+				       !ext2fs_validate_entry(fs, buf,
+							      offset,
+							      final_offset))
+					offset += 4;
+				continue;
+			}
+		}
+		offset += rec_len;
+	}
+
+	if (changed) {
+		/* change parent ino */
+		if (buf_len == EXT2_DIR_REC_LEN(2))
+			((struct ext2_dir_entry *)inode->i_block)->inode =
+								 dirent->inode;
+		ctx->errcode = ext2fs_write_inode_full(fs, ctx->dir, (void *)inode,
+						       EXT2_INODE_SIZE(fs->super));
+		if (ctx->errcode)
+			return BLOCK_ABORT;
+	}
+	if (do_abort)
+		return BLOCK_ABORT;
+	return 0;
+}
diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in
index c99a167..537d840 100644
--- a/lib/ext2fs/ext2_err.et.in
+++ b/lib/ext2fs/ext2_err.et.in
@@ -68,6 +68,9 @@ ec	EXT2_ET_MAGIC_EXTENT_HANDLE,
 ec	EXT2_ET_BAD_MAGIC,
 	"Bad magic number in super-block"
 
+ec	EXT2_ET_BAD_EXT_ATTR_MAGIC,
+	"Bad magic number in extend attribute"
+
 ec	EXT2_ET_REV_TOO_HIGH,
 	"Filesystem revision too high"
 
@@ -473,4 +476,7 @@ ec	EXT2_ET_UNKNOWN_CSUM,
 ec	EXT2_ET_MMP_CSUM_INVALID,
 	"MMP block checksum does not match MMP block"
 
+ec	EXT2_ET_BAD_EXTRA_SIZE,
+	"Bad inode extra isizevalue"
+
 	end
diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
index 5b6e315..4201c71 100644
--- a/lib/ext2fs/ext2_fs.h
+++ b/lib/ext2fs/ext2_fs.h
@@ -905,4 +905,11 @@ struct mmp_struct {
  */
 #define EXT4_MMP_MIN_CHECK_INTERVAL     5
 
+struct inline_data {
+	__u16	inline_off;
+	__u16	inline_size;
+};
+
+#define EXT4_MIN_INLINE_DATA_SIZE	((sizeof(__u32) * EXT2_N_BLOCKS))
+
 #endif	/* _LINUX_EXT2_FS_H */
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index b076c3c..b0efda6 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -1335,6 +1335,17 @@ errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *);
 
 /* inline_data.c */
 extern int ext2fs_inode_has_inline_data(ext2_filsys fs, ext2_ino_t ino);
+extern int ext2fs_inline_data_iterate(ext2_filsys fs,
+				      ext2_ino_t ino,
+				      int flags,
+				      char *block_buf,
+				      int (*func)(ext2_filsys fs,
+						  void *buf,
+						  int buf_len,
+						  e2_blkcnt_t blockcnt,
+						  struct ext2_inode_large *inode,
+						  void *priv_data),
+				      void *priv_data);
 
 /* inode.c */
 extern errcode_t ext2fs_flush_icache(ext2_filsys fs);
diff --git a/lib/ext2fs/ext2fsP.h b/lib/ext2fs/ext2fsP.h
index 3de9278..742ddf6 100644
--- a/lib/ext2fs/ext2fsP.h
+++ b/lib/ext2fs/ext2fsP.h
@@ -87,6 +87,13 @@ extern int ext2fs_process_dir_block(ext2_filsys  	fs,
 				    int			ref_offset,
 				    void		*priv_data);
 
+extern int ext2fs_process_dir_inline_data(ext2_filsys	fs,
+					  void		*buf,
+					  int		buf_len,
+					  e2_blkcnt_t	blockcnt,
+					  struct ext2_inode_large *inode,
+					  void		*priv_data);
+
 /* Generic numeric progress meter */
 
 struct ext2fs_numeric_progress_struct {
diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c
index 0341ee3..2be1a61 100644
--- a/lib/ext2fs/inline_data.c
+++ b/lib/ext2fs/inline_data.c
@@ -13,10 +13,60 @@
 #include <stdio.h>
 
 #include "ext2_fs.h"
+#include "ext2_ext_attr.h"
 
 #include "ext2fs.h"
 #include "ext2fsP.h"
 
+#define EXT4_INLINE_DATA_DOTDOT_SIZE	(4)
+
+static int ext2fs_iget_extra_inode(ext2_filsys fs, struct ext2_inode_large *inode,
+				    struct inline_data *data);
+static void *ext2fs_get_inline_xattr_pos(struct ext2_inode_large *inode,
+					 struct inline_data *data);
+
+static int ext2fs_iget_extra_inode(ext2_filsys fs, struct ext2_inode_large *inode,
+				    struct inline_data *data)
+{
+	struct ext2_ext_attr_ibody_header *header;
+	struct ext2_ext_attr_search s = {
+		.not_found = -1,
+	};
+	struct ext2_ext_attr_info i = {
+		.name_index = EXT4_EXT_ATTR_INDEX_SYSTEM,
+		.name = EXT4_EXT_ATTR_SYSTEM_DATA,
+	};
+
+	data->inline_off = 0;
+	if (inode->i_extra_isize > (EXT2_INODE_SIZE(fs->super) -
+				   EXT2_GOOD_OLD_INODE_SIZE))
+		return EXT2_ET_BAD_EXTRA_SIZE;
+
+	(void)ext2fs_ibody_find_ext_attr(fs, inode, &i, &s);
+
+	if (!s.not_found) {
+		data->inline_off = (__u16)((void *)s.here - (void *)inode);
+		data->inline_size = EXT4_MIN_INLINE_DATA_SIZE +
+				    s.here->e_value_size;
+		return 0;
+	}
+
+	return EXT2_ET_BAD_EXT_ATTR_MAGIC;
+}
+
+static void *ext2fs_get_inline_xattr_pos(struct ext2_inode_large *inode,
+					 struct inline_data *data)
+{
+	struct ext2_ext_attr_entry *entry;
+	struct ext2_ext_attr_ibody_header *header;
+
+	header = IHDR(inode);
+	entry = (struct ext2_ext_attr_entry *)
+			((void *)inode + data->inline_off);
+
+	return (void *)IFIRST(header) + entry->e_value_offs;
+}
+
 int ext2fs_inode_has_inline_data(ext2_filsys fs, ext2_ino_t ino)
 {
 	struct ext2_inode inode;
@@ -28,3 +78,85 @@ int ext2fs_inode_has_inline_data(ext2_filsys fs, ext2_ino_t ino)
 
 	return (inode.i_flags & EXT4_INLINE_DATA_FL);
 }
+
+int ext2fs_inline_data_iterate(ext2_filsys fs,
+			       ext2_ino_t ino,
+			       int flags,
+			       char *block_buf,
+			       int (*func)(ext2_filsys fs,
+					   void *buf,
+					   int buf_len,
+					   e2_blkcnt_t blockcnt,
+					   struct ext2_inode_large *inode,
+					   void *priv_data),
+			       void *priv_data)
+{
+	struct dir_context *ctx;
+	struct ext2_inode_large *inode;
+	struct ext2_dir_entry dirent;
+	struct inline_data data;
+	errcode_t retval = 0;
+	e2_blkcnt_t blockcnt = 0;
+	void *inline_start;
+	int inline_size;
+
+	ctx = (struct dir_context *)priv_data;
+
+	retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
+	if (retval)
+		return retval;
+
+	retval = ext2fs_read_inode_full(fs, ino, (void *)inode,
+					EXT2_INODE_SIZE(fs->super));
+	if (retval)
+		goto out;
+
+	if (inode->i_size == 0)
+		goto out;
+
+	/* we first check '.' and '..' dir */
+	dirent.inode = ino;
+	dirent.name_len = 1;
+	ext2fs_set_rec_len(fs, EXT2_DIR_REC_LEN(2), &dirent);
+	dirent.name[0] = '.';
+	dirent.name[1] = '\0';
+	retval |= (*func)(fs, (void *)&dirent, dirent.rec_len, blockcnt++,
+			 inode, priv_data);
+	if (retval & BLOCK_ABORT)
+		goto out;
+
+	dirent.inode = (__u32)*inode->i_block;
+	dirent.name_len = 2;
+	ext2fs_set_rec_len(fs, EXT2_DIR_REC_LEN(3), &dirent);
+	dirent.name[0] = '.';
+	dirent.name[1] = '.';
+	dirent.name[2] = '\0';
+	retval |= (*func)(fs, (void *)&dirent, dirent.rec_len, blockcnt++,
+			 inode, priv_data);
+	if (retval & BLOCK_ABORT)
+		goto out;
+
+	inline_start = (void *)inode->i_block + EXT4_INLINE_DATA_DOTDOT_SIZE;
+	inline_size = EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DATA_DOTDOT_SIZE;
+	retval |= (*func)(fs, inline_start, inline_size, blockcnt++,
+			 inode, priv_data);
+	if (retval & BLOCK_ABORT)
+		goto out;
+
+	retval = ext2fs_iget_extra_inode(fs, inode, &data);
+	if (retval)
+		goto out;
+	if (data.inline_size > EXT4_MIN_INLINE_DATA_SIZE) {
+		inline_start = ext2fs_get_inline_xattr_pos(inode, &data);
+		inline_size = data.inline_size - EXT4_MIN_INLINE_DATA_SIZE;
+		retval |= (*func)(fs, inline_start, inline_size, blockcnt++,
+			 inode, priv_data);
+		if (retval & BLOCK_ABORT)
+			goto out;
+	}
+
+out:
+	retval |= BLOCK_ERROR;
+	ext2fs_free_mem(&inode);
+	return retval & BLOCK_ERROR ? ctx->errcode : 0;
+}
-- 
1.7.4.1


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

* [PATCH 05/21 v5] libext2fs: handle inline_data in block iterator function
  2012-09-22  4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
                   ` (3 preceding siblings ...)
  2012-09-22  4:00 ` [PATCH 04/21 v5] libext2fs: handle inline data in dir iterator function Zheng Liu
@ 2012-09-22  4:00 ` Zheng Liu
  2012-09-22  4:00 ` [PATCH 06/21 v5] debugfs: make stat command support inline data Zheng Liu
                   ` (15 subsequent siblings)
  20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22  4:00 UTC (permalink / raw)
  To: linux-ext4; +Cc: tytso, Zheng Liu

From: Zheng Liu <wenqing.lz@taobao.com>

We needn't traverse blocks for an inode which has inline data because no block
belongs to it.  After appling this patch, the following commands in debugfs can
handle inline_data feature:
	- icheck
	- blocks
	- filefrag

In some places, block iterator functions are used to traverse blocks of
directory.  In this case, we need to check whether inode has inline_data flag or
not, and handle it manually.

Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 lib/ext2fs/block.c |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/lib/ext2fs/block.c b/lib/ext2fs/block.c
index 68dcb03..4abcedf 100644
--- a/lib/ext2fs/block.c
+++ b/lib/ext2fs/block.c
@@ -345,6 +345,13 @@ errcode_t ext2fs_block_iterate3(ext2_filsys fs,
 		return ctx.errcode;
 
 	/*
+	 * If an inode has inline data, we needn't traverse its blocks
+	 * because no block belong to this inode.
+	 */
+	if (inode.i_flags & EXT4_INLINE_DATA_FL)
+		return ctx.errcode;
+
+	/*
 	 * Check to see if we need to limit large files
 	 */
 	if (flags & BLOCK_FLAG_NO_LARGE) {
-- 
1.7.4.1


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

* [PATCH 06/21 v5] debugfs: make stat command support inline data
  2012-09-22  4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
                   ` (4 preceding siblings ...)
  2012-09-22  4:00 ` [PATCH 05/21 v5] libext2fs: handle inline_data in block " Zheng Liu
@ 2012-09-22  4:00 ` Zheng Liu
  2012-09-22  4:00 ` [PATCH 07/21 v5] libext2fs: handle inline data when expanding directory Zheng Liu
                   ` (14 subsequent siblings)
  20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22  4:00 UTC (permalink / raw)
  To: linux-ext4; +Cc: tytso, Zheng Liu

From: Zheng Liu <wenqing.lz@taobao.com>

Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 debugfs/debugfs.c        |   13 ++++++++++++-
 lib/ext2fs/ext2fs.h      |    1 +
 lib/ext2fs/inline_data.c |   30 ++++++++++++++++++++++++++++++
 3 files changed, 43 insertions(+), 1 deletions(-)

diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c
index aec61ab..2099478 100644
--- a/debugfs/debugfs.c
+++ b/debugfs/debugfs.c
@@ -706,6 +706,15 @@ static void dump_extents(FILE *f, const char *prefix, ext2_ino_t ino,
 		fprintf(f, "\n");
 }
 
+void dump_inline_data(FILE *out, const char *prefix, ext2_ino_t inode_num)
+{
+	int size;
+
+	fprintf(out, "%sINLINE DATA:\n%s", prefix, prefix);
+	size = ext2fs_get_inline_data_size(current_fs, inode_num);
+	fprintf(out, "  The size of inline data: %d", size);
+}
+
 void internal_dump_inode(FILE *out, const char *prefix,
 			 ext2_ino_t inode_num, struct ext2_inode *inode,
 			 int do_dump_blocks)
@@ -836,7 +845,9 @@ void internal_dump_inode(FILE *out, const char *prefix,
 		fprintf(out, "%sDevice major/minor number: %02d:%02d (hex %02x:%02x)\n",
 			devnote, major, minor, major, minor);
 	} else if (do_dump_blocks) {
-		if (inode->i_flags & EXT4_EXTENTS_FL)
+		if (inode->i_flags & EXT4_INLINE_DATA_FL)
+			dump_inline_data(out, prefix, inode_num);
+		else if (inode->i_flags & EXT4_EXTENTS_FL)
 			dump_extents(out, prefix, inode_num,
 				     DUMP_LEAF_EXTENTS|DUMP_NODE_EXTENTS, 0, 0);
 		else
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 51dbad4..25a8e98 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -1331,6 +1331,7 @@ errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *);
 
 /* inline_data.c */
 extern int ext2fs_inode_has_inline_data(ext2_filsys fs, ext2_ino_t ino);
+extern int ext2fs_get_inline_data_size(ext2_filsys fs, ext2_ino_t ino);
 extern int ext2fs_inline_data_iterate(ext2_filsys fs,
 				      ext2_ino_t ino,
 				      int flags,
diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c
index 0652079..5570aa0 100644
--- a/lib/ext2fs/inline_data.c
+++ b/lib/ext2fs/inline_data.c
@@ -79,6 +79,36 @@ int ext2fs_inode_has_inline_data(ext2_filsys fs, ext2_ino_t ino)
 	return (inode.i_flags & EXT4_INLINE_DATA_FL);
 }
 
+int ext2fs_get_inline_data_size(ext2_filsys fs, ext2_ino_t ino)
+{
+	struct inline_data data;
+	struct ext2_inode_large *inode;
+	errcode_t retval = 0;
+	int inline_size = 0;
+
+	if (!ext2fs_inode_has_inline_data(fs, ino))
+		return 0;
+
+	retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
+	if (retval)
+		return 0;
+
+	retval = ext2fs_read_inode_full(fs, ino, (void *)inode,
+					EXT2_INODE_SIZE(fs->super));
+	if (retval)
+		goto out;
+
+	retval = ext2fs_iget_extra_inode(fs, inode, &data);
+	if (retval)
+		goto out;
+
+	inline_size = data.inline_size;
+
+out:
+	ext2fs_free_mem(&inode);
+	return inline_size;
+}
+
 int ext2fs_inline_data_iterate(ext2_filsys fs,
 			       ext2_ino_t ino,
 			       int flags,
-- 
1.7.4.1


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

* [PATCH 07/21 v5] libext2fs: handle inline data when expanding directory
  2012-09-22  4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
                   ` (5 preceding siblings ...)
  2012-09-22  4:00 ` [PATCH 06/21 v5] debugfs: make stat command support inline data Zheng Liu
@ 2012-09-22  4:00 ` Zheng Liu
  2012-09-22  4:00 ` [PATCH 08/21 v5] debugfs: make lsdel command support inline data Zheng Liu
                   ` (13 subsequent siblings)
  20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22  4:00 UTC (permalink / raw)
  To: linux-ext4; +Cc: tytso, Zheng Liu

From: Zheng Liu <wenqing.lz@taobao.com>

When inline space is filled up, we need to allocate a new block for this inode.
So a new function called `ext2fs_convert_inline_data' is define to handle it.
`expand_dir_struct' is exported to libext2fs because we need to change its
status.  After adding it, the following commands in debugfs can handle
inline_data feature:
	- mkdir
	- expand_dir

Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 lib/ext2fs/expanddir.c   |   18 ++-
 lib/ext2fs/ext2fs.h      |    4 +
 lib/ext2fs/ext2fsP.h     |   11 ++
 lib/ext2fs/ext_attr.c    |    6 +-
 lib/ext2fs/inline_data.c |  337 ++++++++++++++++++++++++++++++++++++++++++++++
 lib/ext2fs/mkdir.c       |   18 +++-
 6 files changed, 383 insertions(+), 11 deletions(-)

diff --git a/lib/ext2fs/expanddir.c b/lib/ext2fs/expanddir.c
index 22558d6..b5e790b 100644
--- a/lib/ext2fs/expanddir.c
+++ b/lib/ext2fs/expanddir.c
@@ -19,13 +19,7 @@
 #include "ext2_fs.h"
 #include "ext2fs.h"
 
-struct expand_dir_struct {
-	int		done;
-	int		newblocks;
-	blk64_t		goal;
-	errcode_t	err;
-	ext2_ino_t	dir;
-};
+#include "ext2fsP.h"
 
 static int expand_dir_proc(ext2_filsys	fs,
 			   blk64_t	*blocknr,
@@ -114,6 +108,16 @@ errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir)
 	es.newblocks = 0;
 	es.dir = dir;
 
+	if (ext2fs_inode_has_inline_data(fs, dir)) {
+		retval = ext2fs_convert_inline_data(fs, dir, &es);
+		if (retval)
+			return retval;
+		if (!es.done)
+			return EXT2_ET_EXPAND_DIR_ERR;
+
+		return 0;
+	}
+
 	retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND,
 				       0, expand_dir_proc, &es);
 
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 6c2393e..91da02c 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -1347,6 +1347,10 @@ extern int ext2fs_inline_data_iterate(ext2_filsys fs,
 						  struct ext2_inode_large *inode,
 						  void *priv_data),
 				      void *priv_data);
+extern errcode_t ext2fs_inline_data_mkdir(ext2_filsys fs, ext2_ino_t parent,
+					  ext2_ino_t ino, const char *name);
+extern errcode_t ext2fs_convert_inline_data(ext2_filsys fs, ext2_ino_t ino,
+					    void *priv_data);
 
 /* inode.c */
 extern errcode_t ext2fs_flush_icache(ext2_filsys fs);
diff --git a/lib/ext2fs/ext2fsP.h b/lib/ext2fs/ext2fsP.h
index 742ddf6..503ebbf 100644
--- a/lib/ext2fs/ext2fsP.h
+++ b/lib/ext2fs/ext2fsP.h
@@ -62,6 +62,17 @@ struct dir_context {
 };
 
 /*
+ * For expanding directory
+ */
+struct expand_dir_struct {
+	int		done;
+	int		newblocks;
+	blk64_t		goal;
+	errcode_t	err;
+	ext2_ino_t	dir;
+};
+
+/*
  * Inode cache structure
  */
 struct ext2_inode_cache {
diff --git a/lib/ext2fs/ext_attr.c b/lib/ext2fs/ext_attr.c
index c663f31..5a8d1ca 100644
--- a/lib/ext2fs/ext_attr.c
+++ b/lib/ext2fs/ext_attr.c
@@ -267,7 +267,8 @@ errcode_t ext2fs_set_entry_ext_attr(struct ext2_ext_attr_info *i,
 				    struct ext2_ext_attr_search *s)
 {
 	struct ext2_ext_attr_entry *last;
-	size_t free, min_offs = s->end - s->base, name_len = strlen(i->name);
+	size_t free, min_offs = s->end - s->base;
+	size_t name_len = strlen(i->name);
 
 	last = s->first;
 	for (; !EXT2_EXT_IS_LAST_ENTRY(last); last = EXT2_EXT_ATTR_NEXT(last)) {
@@ -298,8 +299,7 @@ errcode_t ext2fs_set_entry_ext_attr(struct ext2_ext_attr_info *i,
 		memset(s->here, 0, size);
 		s->here->e_name_index = i->name_index;
 		s->here->e_name_len = name_len;
-		memcpy(EXT2_EXT_ATTR_NAME(s->here),
-		       EXT2_EXT_ATTR_NAME(i), name_len);
+		memcpy(EXT2_EXT_ATTR_NAME(s->here), i->name, name_len);
 	} else {
 		if (!s->here->e_value_block && s->here->e_value_size) {
 			void *first_val = s->base + min_offs;
diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c
index 3bfe49d..85cfeac 100644
--- a/lib/ext2fs/inline_data.c
+++ b/lib/ext2fs/inline_data.c
@@ -24,6 +24,17 @@ static int ext2fs_iget_extra_inode(ext2_filsys fs, struct ext2_inode_large *inod
 				    struct inline_data *data);
 static void *ext2fs_get_inline_xattr_pos(struct ext2_inode_large *inode,
 					 struct inline_data *data);
+static void ext2fs_inline_data_finish_convert(ext2_filsys fs, ext2_ino_t ino,
+					      char *target, void *buf,
+					      int inline_size);
+static void ext2fs_update_final_de(ext2_filsys fs, void *de_buf,
+				   int old_size, int new_size);
+static errcode_t ext2fs_inline_data_destory_data(ext2_filsys fs, ext2_ino_t ino,
+					   struct ext2_inode_large *inode,
+					   struct inline_data *data);
+static errcode_t ext2fs_create_inline_data(ext2_filsys fs,
+					   struct ext2_inode_large *inode,
+					   int len);
 
 static int ext2fs_iget_extra_inode(ext2_filsys fs, struct ext2_inode_large *inode,
 				    struct inline_data *data)
@@ -67,6 +78,46 @@ static void *ext2fs_get_inline_xattr_pos(struct ext2_inode_large *inode,
 	return (void *)IFIRST(header) + entry->e_value_offs;
 }
 
+static errcode_t ext2fs_inline_data_destory_data(ext2_filsys fs, ext2_ino_t ino,
+						 struct ext2_inode_large *inode,
+						 struct inline_data *data)
+{
+	struct ext2_ext_attr_ibody_header *header;
+	struct ext2_ext_attr_search s = {
+		.not_found = -1,
+	};
+	struct ext2_ext_attr_info i = {
+		.name_index = EXT4_EXT_ATTR_INDEX_SYSTEM,
+		.name = EXT4_EXT_ATTR_SYSTEM_DATA,
+		.value = "",
+		.value_len = 0,
+	};
+	errcode_t retval;
+
+	if (!data->inline_off)
+		return 0;
+
+	if (inode->i_extra_isize > (EXT2_INODE_SIZE(fs->super) -
+				    EXT2_GOOD_OLD_INODE_SIZE))
+		return EXT2_ET_BAD_EXTRA_SIZE;
+
+	header = IHDR(inode);
+	if (header->h_magic != EXT2_EXT_ATTR_MAGIC)
+		return EXT2_ET_BAD_EXT_ATTR_MAGIC;
+
+	(void)ext2fs_ibody_find_ext_attr(fs, inode, &i, &s);
+
+	if (!s.not_found) {
+		retval = ext2fs_set_entry_ext_attr(&i, &s);
+		if (retval)
+			return retval;
+	}
+
+	memset((void *)inode->i_block, 0, EXT4_MIN_INLINE_DATA_SIZE);
+
+	return 0;
+}
+
 int ext2fs_inode_has_inline_data(ext2_filsys fs, ext2_ino_t ino)
 {
 	struct ext2_inode inode;
@@ -109,6 +160,83 @@ out:
 	return inline_size;
 }
 
+static void ext2fs_update_final_de(ext2_filsys fs, void *de_buf,
+				   int old_size, int new_size)
+{
+	struct ext2_dir_entry *de, *prev_de;
+	void *limit;
+	int de_len;
+
+	de = (struct ext2_dir_entry *)de_buf;
+	if (old_size) {
+		limit = de_buf + old_size;
+		do {
+			prev_de = de;
+			ext2fs_get_rec_len(fs, de, &de_len);
+			de_buf += de_len;
+			de = (struct ext2_dir_entry *)de_buf;
+		} while (de_buf < limit);
+
+		ext2fs_set_rec_len(fs, de_len + new_size - old_size,
+				   prev_de);
+	} else {
+		de->inode = 0;
+		ext2fs_set_rec_len(fs, new_size, de);
+	}
+}
+
+static void ext2fs_inline_data_finish_convert(ext2_filsys fs, ext2_ino_t ino,
+					      char *target, void *buf,
+					      int inline_size)
+{
+	struct ext2_dir_entry *de;
+	struct ext2_dir_entry_tail *t;
+	int header_size = 0;
+	int csum_size = 0;
+	int filetype = 0;
+
+	if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+				       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+		csum_size = sizeof(struct ext2_dir_entry_tail);
+
+	/* First create '.' and '..' */
+	if (fs->super->s_feature_incompat &
+	    EXT2_FEATURE_INCOMPAT_FILETYPE)
+		filetype = EXT2_FT_DIR << 8;
+
+	de = (struct ext2_dir_entry *)target;
+	de->inode = ino;
+	de->name_len = 1 | filetype;
+	de->name[0] = '.';
+	de->name[1] = '\0';
+	de->rec_len = EXT2_DIR_REC_LEN(1);
+
+	de = (struct ext2_dir_entry *)(target + de->rec_len);
+	de->rec_len = EXT2_DIR_REC_LEN(2);
+	de->inode = ((struct ext2_dir_entry *)buf)->inode;
+	de->name_len = 2 | filetype;
+	de->name[0] = '.';
+	de->name[1] = '.';
+	de->name[2] = '\0';
+
+	de = (struct ext2_dir_entry *)(target +
+				       EXT2_DIR_REC_LEN(1) +
+				       EXT2_DIR_REC_LEN(2));
+	header_size = (void *)de - (void *)target;
+
+	memcpy((void *)de, buf + EXT4_INLINE_DATA_DOTDOT_SIZE,
+		inline_size - EXT4_INLINE_DATA_DOTDOT_SIZE);
+
+	ext2fs_update_final_de(fs, target,
+		inline_size - EXT4_INLINE_DATA_DOTDOT_SIZE + header_size,
+		fs->blocksize - csum_size);
+
+	if (csum_size) {
+		t = EXT2_DIRENT_TAIL(target, fs->blocksize);
+		ext2fs_initialize_dirent_tail(fs, t);
+	}
+}
+
 int ext2fs_inline_data_iterate(ext2_filsys fs,
 			       ext2_ino_t ino,
 			       int flags,
@@ -190,3 +318,212 @@ out:
 	ext2fs_free_mem(&inode);
 	return retval & BLOCK_ERROR ? ctx->errcode : 0;
 }
+
+errcode_t ext2fs_convert_inline_data(ext2_filsys fs,
+				     ext2_ino_t  ino,
+				     void *priv_data)
+{
+	struct expand_dir_struct *es;
+	struct ext2_inode_large *inode;
+	struct inline_data data;
+	ext2_extent_handle_t handle;
+	errcode_t retval;
+	blk64_t blk;
+	void *inline_start;
+	char *backup_buf;
+	char *blk_buf;
+	int inline_size;
+	int i, limit, r;
+
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+	es = (struct expand_dir_struct *)priv_data;
+	retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
+	if (retval)
+		return retval;
+
+	retval = ext2fs_read_inode_full(fs, ino, (void *)inode,
+					EXT2_INODE_SIZE(fs->super));
+	if (retval)
+		goto out;
+
+	retval = ext2fs_iget_extra_inode(fs, inode, &data);
+	if (retval)
+		goto out;
+
+	inline_size = data.inline_size;
+	retval = ext2fs_get_mem(inline_size, &backup_buf);
+	if (retval)
+		goto out;
+
+	memcpy(backup_buf, (void *)inode->i_block, EXT4_MIN_INLINE_DATA_SIZE);
+	if (inline_size > EXT4_MIN_INLINE_DATA_SIZE)
+		memcpy(backup_buf + EXT4_MIN_INLINE_DATA_SIZE,
+		       ext2fs_get_inline_xattr_pos(inode, &data),
+		       inline_size - EXT4_MIN_INLINE_DATA_SIZE);
+
+	/* clear the entry and the flag in dir now */
+	retval = ext2fs_inline_data_destory_data(fs, ino, inode, &data);
+	if (retval)
+		goto out1;
+
+	if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) {
+		if (LINUX_S_ISDIR(inode->i_mode) ||
+		    LINUX_S_ISREG(inode->i_mode) ||
+		    LINUX_S_ISLNK(inode->i_mode))
+			inode->i_flags |= EXT4_EXTENTS_FL;
+	}
+
+	inode->i_flags &= ~EXT4_INLINE_DATA_FL;
+
+	retval = ext2fs_new_block2(fs, 0, 0, &blk);
+	if (retval)
+		goto out1;
+
+	ext2fs_iblk_set(fs, (void*)inode, 1);
+	if (!(fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS))
+		inode->i_block[0] = blk;
+	inode->i_size = fs->blocksize;
+
+	retval = ext2fs_get_mem(fs->blocksize, &blk_buf);
+	if (retval)
+		goto out1;
+
+	memset(blk_buf, 0, sizeof(fs->blocksize));
+	if (LINUX_S_ISDIR(inode->i_mode)) {
+		/* set the final dir entry to cover the whole block */
+		ext2fs_inline_data_finish_convert(fs, ino, blk_buf, backup_buf,
+						  inline_size);
+	} else {
+		memcpy(blk_buf, backup_buf, inline_size);
+	}
+
+	retval = ext2fs_write_dir_block4(fs, blk, blk_buf, 0, ino);
+	if (retval)
+		goto out2;
+	retval = ext2fs_write_inode_full(fs, ino, (void *)inode,
+					 EXT2_INODE_SIZE(fs->super));
+	if (retval)
+		goto out2;
+
+	if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) {
+		retval = ext2fs_extent_open2(fs, ino, (void *)inode, &handle);
+		if (retval)
+			goto out2;
+		retval = ext2fs_extent_set_bmap(handle, 0, blk, 0);
+		ext2fs_extent_free(handle);
+		if (retval)
+			goto out2;
+	}
+
+	ext2fs_block_alloc_stats2(fs, blk, +1);
+
+out2:
+	ext2fs_free_mem(&blk_buf);
+out1:
+	ext2fs_free_mem(&backup_buf);
+out:
+	ext2fs_free_mem(&inode);
+
+	if (retval) {
+		es->err = retval;
+	} else {
+		es->done = 1;
+		es->newblocks++;
+		es->goal = blk;
+	}
+	return retval;
+}
+
+static errcode_t ext2fs_create_inline_data(ext2_filsys fs,
+					   struct ext2_inode_large *inode,
+					   int len)
+{
+	struct ext2_ext_attr_ibody_header *header;
+	struct ext2_ext_attr_search s = {
+		.not_found = -1,
+	};
+	struct ext2_ext_attr_info i = {
+		.name_index = EXT4_EXT_ATTR_INDEX_SYSTEM,
+		.name = EXT4_EXT_ATTR_SYSTEM_DATA,
+	};
+	void *buf;
+	errcode_t ret;
+
+	if (len > EXT4_MIN_INLINE_DATA_SIZE) {
+		i.value_len = len - EXT4_MIN_INLINE_DATA_SIZE;
+		ret = ext2fs_get_mem(i.value_len, &buf);
+		if (ret)
+			return ret;
+		memset(buf, 0, i.value_len);
+		i.value = buf;
+	} else {
+		i.value = "";
+		i.value_len = 0;
+	}
+
+	(void) ext2fs_ibody_find_ext_attr(fs, inode, &i, &s);
+	ret = ext2fs_set_entry_ext_attr(&i, &s);
+	if (ret)
+		return -1;
+
+	header = IHDR(inode);
+	if (!EXT2_EXT_IS_LAST_ENTRY(s.first))
+		header->h_magic = ext2fs_cpu_to_le32(EXT2_EXT_ATTR_MAGIC);
+	else
+		header->h_magic = ext2fs_cpu_to_le32(0);
+
+	return 0;
+}
+
+errcode_t ext2fs_inline_data_mkdir(ext2_filsys fs, ext2_ino_t parent,
+				   ext2_ino_t ino, const char *name)
+{
+	struct ext2_inode_large *inode;
+	struct ext2_dir_entry *de;
+	errcode_t retval = 0;
+	char *buf;
+	int inline_size = EXT4_MIN_INLINE_DATA_SIZE;
+	__u32 t = fs->now ? fs->now : time(NULL);
+
+	retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
+	if (retval)
+		return retval;
+	memset(inode, 0, EXT2_INODE_SIZE(fs->super));
+
+	inode->i_extra_isize = sizeof(struct ext2_inode_large) -
+		EXT2_GOOD_OLD_INODE_SIZE;
+	/* prepare inline data*/
+	retval = ext2fs_create_inline_data(fs, inode, inline_size);
+	if (retval)
+		goto out;
+
+	de = (struct ext2_dir_entry *)inode->i_block;
+	de->inode = parent;
+
+	de = (struct ext2_dir_entry *)((void *)de + EXT4_INLINE_DATA_DOTDOT_SIZE);
+	de->inode = 0;
+	de->rec_len = inline_size - EXT4_INLINE_DATA_DOTDOT_SIZE;
+
+	inode->i_mode = LINUX_S_IFDIR | (0777 & ~fs->umask);
+	inode->i_uid = inode->i_gid = 0;
+	inode->i_links_count = 2;
+	inode->i_size = inline_size;
+	inode->i_flags &= ~EXT4_EXTENTS_FL;
+	inode->i_flags |= EXT4_INLINE_DATA_FL;
+	if (!inode->i_ctime)
+		inode->i_ctime = t;
+	if (!inode->i_mtime)
+		inode->i_mtime = t;
+	if (!inode->i_atime)
+		inode->i_atime = t;
+	if (!inode->i_crtime)
+		inode->i_crtime = t;
+
+	retval = ext2fs_write_inode_full(fs, ino, (void *)inode,
+					 EXT2_INODE_SIZE(fs->super));
+
+out:
+	ext2fs_free_mem(&inode);
+	return retval;
+}
diff --git a/lib/ext2fs/mkdir.c b/lib/ext2fs/mkdir.c
index 4a85439..3bbe808 100644
--- a/lib/ext2fs/mkdir.c
+++ b/lib/ext2fs/mkdir.c
@@ -41,6 +41,7 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
 	ext2_ino_t		scratch_ino;
 	blk64_t			blk;
 	char			*block = 0;
+	int			inline_data = 0;
 
 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
@@ -54,6 +55,15 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
 			goto cleanup;
 	}
 
+	if (fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_INLINE_DATA &&
+	    ino > EXT2_FIRST_INO(fs->super) && strcmp("lost+found", name) != 0) {
+		retval = ext2fs_inline_data_mkdir(fs, parent, ino, name);
+		if (retval)
+			goto cleanup;
+		inline_data = 1;
+		goto make_link;
+	}
+
 	/*
 	 * Allocate a data block for the directory
 	 */
@@ -114,6 +124,7 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
 			goto cleanup;
 	}
 
+make_link:
 	/*
 	 * Link the directory into the filesystem hierarchy
 	 */
@@ -136,6 +147,10 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
 	 * Update parent inode's counts
 	 */
 	if (parent != ino) {
+		/* Reload parent inode due to inline data */
+		retval = ext2fs_read_inode(fs, parent, &parent_inode);
+		if (retval)
+			goto cleanup;
 		parent_inode.i_links_count++;
 		retval = ext2fs_write_inode(fs, parent, &parent_inode);
 		if (retval)
@@ -145,7 +160,8 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
 	/*
 	 * Update accounting....
 	 */
-	ext2fs_block_alloc_stats2(fs, blk, +1);
+	if (!inline_data)
+		ext2fs_block_alloc_stats2(fs, blk, +1);
 	ext2fs_inode_alloc_stats2(fs, ino, +1, 1);
 
 cleanup:
-- 
1.7.4.1


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

* [PATCH 08/21 v5] debugfs: make lsdel command support inline data
  2012-09-22  4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
                   ` (6 preceding siblings ...)
  2012-09-22  4:00 ` [PATCH 07/21 v5] libext2fs: handle inline data when expanding directory Zheng Liu
@ 2012-09-22  4:00 ` Zheng Liu
  2012-09-22  4:00 ` [PATCH 09/21 v5] libext2fs: handle inline data in read/write function Zheng Liu
                   ` (12 subsequent siblings)
  20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22  4:00 UTC (permalink / raw)
  To: linux-ext4; +Cc: tytso, Zheng Liu

From: Zheng Liu <wenqing.lz@taobao.com>

Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 debugfs/lsdel.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/debugfs/lsdel.c b/debugfs/lsdel.c
index bed0ce6..71546c7 100644
--- a/debugfs/lsdel.c
+++ b/debugfs/lsdel.c
@@ -149,7 +149,8 @@ void do_lsdel(int argc, char **argv)
 				"while calling ext2fs_block_iterate2");
 			goto next;
 		}
-		if (lsd.free_blocks && !lsd.bad_blocks) {
+		if (lsd.free_blocks && !lsd.bad_blocks ||
+		    inode.i_flags & EXT4_INLINE_DATA_FL) {
 			if (num_delarray >= max_delarray) {
 				max_delarray += 50;
 				delarray = realloc(delarray,
-- 
1.7.4.1


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

* [PATCH 09/21 v5] libext2fs: handle inline data in read/write function
  2012-09-22  4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
                   ` (7 preceding siblings ...)
  2012-09-22  4:00 ` [PATCH 08/21 v5] debugfs: make lsdel command support inline data Zheng Liu
@ 2012-09-22  4:00 ` Zheng Liu
  2012-09-22  4:00 ` [PATCH 10/21 v5] debugfs: handle inline_data feature in dirsearch command Zheng Liu
                   ` (11 subsequent siblings)
  20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22  4:00 UTC (permalink / raw)
  To: linux-ext4; +Cc: tytso, Zheng Liu

From: Zheng Liu <wenqing.lz@taobao.com>

Ext2fs_read/write_inline_data functions copy inline_data from/to user's buffer
directly.  When we want to write some data to a file with inline_data,
ext2fs_try_to_write_inline_data is called.  In this function, it firstly check
the length of data.  If the data can be saved in innode, this function will
create a new extend attribute to record information of inline_data, and copy all
data into this inode.

The following commands in debugfs can handle inline_data feature after
applying this patch:
	- dump
	- cat
	- rdump
	- write

Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 lib/ext2fs/ext2_err.et.in |    3 +
 lib/ext2fs/ext2fs.h       |    7 ++
 lib/ext2fs/fileio.c       |   19 +++++-
 lib/ext2fs/inline_data.c  |  170 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 198 insertions(+), 1 deletions(-)

diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in
index 537d840..17de695 100644
--- a/lib/ext2fs/ext2_err.et.in
+++ b/lib/ext2fs/ext2_err.et.in
@@ -476,6 +476,9 @@ ec	EXT2_ET_UNKNOWN_CSUM,
 ec	EXT2_ET_MMP_CSUM_INVALID,
 	"MMP block checksum does not match MMP block"
 
+ec	EXT2_ET_INLINE_DATA_NO_SPACE,
+	"No free space in inline data"
+
 ec	EXT2_ET_BAD_EXTRA_SIZE,
 	"Bad inode extra isizevalue"
 
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 779eca5..801e2dd 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -1347,6 +1347,13 @@ extern errcode_t ext2fs_inline_data_mkdir(ext2_filsys fs, ext2_ino_t parent,
 					  ext2_ino_t ino, const char *name);
 extern errcode_t ext2fs_convert_inline_data(ext2_filsys fs, ext2_ino_t ino,
 					    void *priv_data);
+extern errcode_t ext2fs_read_inline_data(ext2_filsys fs, ext2_ino_t ino,
+					 char *buf);
+extern errcode_t ext2fs_write_inline_data(ext2_filsys fs, ext2_ino_t ino,
+					  char *buf);
+extern errcode_t ext2fs_try_to_write_inline_data(ext2_filsys fs, ext2_ino_t ino,
+						 const void *buf, unsigned int nbytes,
+						 unsigned int *written);
 
 /* inode.c */
 extern errcode_t ext2fs_flush_icache(ext2_filsys fs);
diff --git a/lib/ext2fs/fileio.c b/lib/ext2fs/fileio.c
index 1f7002c..d751666 100644
--- a/lib/ext2fs/fileio.c
+++ b/lib/ext2fs/fileio.c
@@ -163,7 +163,8 @@ static errcode_t sync_buffer_position(ext2_file_t file)
 
 	b = file->pos / file->fs->blocksize;
 	if (b != file->blockno) {
-		retval = ext2fs_file_flush(file);
+		if (!ext2fs_inode_has_inline_data(file->fs, file->ino))
+			retval = ext2fs_file_flush(file);
 		if (retval)
 			return retval;
 		file->flags &= ~EXT2_FILE_BUF_VALID;
@@ -186,6 +187,12 @@ static errcode_t load_buffer(ext2_file_t file, int dontfill)
 	ext2_filsys	fs = file->fs;
 	errcode_t	retval;
 
+	/* We first handle inline_data */
+	if (file->inode.i_flags & EXT4_INLINE_DATA_FL) {
+		retval = ext2fs_read_inline_data(fs, file->ino, file->buf);
+		return retval;
+	}
+
 	if (!(file->flags & EXT2_FILE_BUF_VALID)) {
 		retval = ext2fs_bmap2(fs, file->ino, &file->inode,
 				     BMAP_BUFFER, 0, file->blockno, 0,
@@ -280,6 +287,16 @@ errcode_t ext2fs_file_write(ext2_file_t file, const void *buf,
 	if (!(file->flags & EXT2_FILE_WRITE))
 		return EXT2_ET_FILE_RO;
 
+	if (fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_INLINE_DATA) {
+		retval = ext2fs_try_to_write_inline_data(fs, file->ino, buf,
+							 nbytes, written);
+		if (!retval)
+			return retval;
+		if (retval != EXT2_ET_INLINE_DATA_NO_SPACE)
+			return retval;
+		retval = 0;
+	}
+
 	while (nbytes > 0) {
 		retval = sync_buffer_position(file);
 		if (retval)
diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c
index ef7b216..a847b68 100644
--- a/lib/ext2fs/inline_data.c
+++ b/lib/ext2fs/inline_data.c
@@ -24,6 +24,7 @@ static int ext2fs_iget_extra_inode(ext2_filsys fs, struct ext2_inode_large *inod
 				    struct inline_data *data);
 static void *ext2fs_get_inline_xattr_pos(struct ext2_inode_large *inode,
 					 struct inline_data *data);
+static int ext2fs_get_max_inline_size(ext2_filsys fs, struct ext2_inode_large *inode);
 static void ext2fs_inline_data_finish_convert(ext2_filsys fs, ext2_ino_t ino,
 					      char *target, void *buf,
 					      int inline_size);
@@ -314,6 +315,73 @@ out:
 	return retval & BLOCK_ERROR ? ctx->errcode : 0;
 }
 
+errcode_t ext2fs_read_inline_data(ext2_filsys fs, ext2_ino_t ino, char *buf)
+{
+	struct ext2_inode_large *inode;
+	struct inline_data data;
+	errcode_t retval = 0;
+	int inline_size;
+
+	retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
+	if (retval)
+		return retval;
+
+	retval = ext2fs_read_inode_full(fs, ino, (void *)inode,
+					EXT2_INODE_SIZE(fs->super));
+	if (retval)
+		goto err;
+
+	retval = ext2fs_iget_extra_inode(fs, inode, &data);
+	if (retval)
+		goto err;
+
+	inline_size = data.inline_size;
+
+	memcpy(buf, (void *)inode->i_block, EXT4_MIN_INLINE_DATA_SIZE);
+	if (inline_size > EXT4_MIN_INLINE_DATA_SIZE)
+		memcpy(buf + EXT4_MIN_INLINE_DATA_SIZE,
+		       ext2fs_get_inline_xattr_pos(inode, &data),
+		       inline_size - EXT4_MIN_INLINE_DATA_SIZE);
+
+err:
+	ext2fs_free_mem(&inode);
+	return retval;
+}
+
+errcode_t ext2fs_write_inline_data(ext2_filsys fs, ext2_ino_t ino, char *buf)
+{
+	struct ext2_inode_large *inode;
+	struct inline_data data;
+	errcode_t retval = 0;
+	int inline_size;
+
+	retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
+	if (retval)
+		return retval;
+
+	retval = ext2fs_read_inode_full(fs, ino, (void *)inode,
+					EXT2_INODE_SIZE(fs->super));
+	if (retval)
+		goto err;
+
+	retval = ext2fs_iget_extra_inode(fs, inode, &data);
+	if (retval)
+		goto err;
+
+	inline_size = data.inline_size;
+
+	memcpy((void *)inode->i_block, buf, EXT4_MIN_INLINE_DATA_SIZE);
+	if (inline_size > EXT4_MIN_INLINE_DATA_SIZE)
+		memcpy(ext2fs_get_inline_xattr_pos(inode, &data),
+		       buf + EXT4_MIN_INLINE_DATA_SIZE,
+		       inline_size - EXT4_MIN_INLINE_DATA_SIZE);
+
+	retval = ext2fs_write_inode_full(fs, ino, (void *)inode,
+					 EXT2_INODE_SIZE(fs->super));
+err:
+	ext2fs_free_mem(&inode);
+	return retval;
+}
 errcode_t ext2fs_convert_inline_data(ext2_filsys fs,
 				     ext2_ino_t  ino,
 				     void *priv_data)
@@ -519,3 +587,105 @@ out:
 	ext2fs_free_mem(&inode);
 	return retval;
 }
+
+static int ext2fs_get_max_inline_size(ext2_filsys fs, struct ext2_inode_large *inode)
+{
+	struct ext2_ext_attr_entry *entry;
+	struct ext2_ext_attr_ibody_header *header;
+	struct inline_data data;
+	errcode_t retval = 0;
+	int free, min_offs;
+
+	min_offs = EXT2_INODE_SIZE(fs->super) -
+		   EXT2_GOOD_OLD_INODE_SIZE -
+		   inode->i_extra_isize -
+		   sizeof(struct ext2_ext_attr_ibody_header);
+
+	header = IHDR(inode);
+	entry = IFIRST(header);
+
+	for (; !EXT2_EXT_IS_LAST_ENTRY(entry);
+	     entry = EXT2_EXT_ATTR_NEXT(entry)) {
+		if (!entry->e_value_block && entry->e_value_size) {
+			size_t offs = ext2fs_le16_to_cpu(entry->e_value_offs);
+			if (offs < min_offs)
+				min_offs = offs;
+		}
+	}
+	free = min_offs -
+		((void *)entry - (void *)IFIRST(header)) - sizeof(__u32);
+
+	/*
+	 * We try to get inline data offset, but maybe it doesn't be
+	 * created.  So we ignore this error.
+	 */
+	retval = ext2fs_iget_extra_inode(fs, inode, &data);
+	if (retval && retval != EXT2_ET_BAD_EXT_ATTR_MAGIC)
+		return 0;
+
+	if (data.inline_off) {
+		entry = (struct ext2_ext_attr_entry *)
+			((void *)inode + data.inline_off);
+		free += ext2fs_le32_to_cpu(entry->e_value_size);
+		goto out;
+	}
+
+	free -= EXT2_EXT_ATTR_LEN(strlen(EXT4_EXT_ATTR_SYSTEM_DATA));
+
+	if (free > EXT2_EXT_ATTR_ROUND)
+		free = EXT2_EXT_ATTR_SIZE(free - EXT2_EXT_ATTR_ROUND);
+	else
+		free = 0;
+
+out:
+	return free + EXT4_MIN_INLINE_DATA_SIZE;
+}
+
+errcode_t ext2fs_try_to_write_inline_data(ext2_filsys fs, ext2_ino_t ino,
+					  const void *buf, unsigned int nbytes,
+					  unsigned int *written)
+{
+	struct ext2_inode_large *inode;
+	struct inline_data data;
+	errcode_t retval = 0;
+	int inline_size = 0;
+
+	retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
+	if (retval)
+		return retval;
+	retval = ext2fs_read_inode_full(fs, ino, (void *)inode,
+					EXT2_INODE_SIZE(fs->super));
+	if (retval)
+		goto out;
+
+	if (nbytes > ext2fs_get_max_inline_size(fs, inode)) {
+		retval = EXT2_ET_INLINE_DATA_NO_SPACE;
+		goto out;
+	}
+
+	retval = ext2fs_create_inline_data(fs, inode, nbytes);
+	if (retval)
+		goto out;
+
+	retval = ext2fs_iget_extra_inode(fs, inode, &data);
+	if (retval)
+		goto out;
+
+	inline_size = data.inline_size;
+
+	memcpy((void *)inode->i_block, buf, EXT4_MIN_INLINE_DATA_SIZE);
+	if (inline_size > EXT4_MIN_INLINE_DATA_SIZE)
+		memcpy(ext2fs_get_inline_xattr_pos(inode, &data),
+		       buf + EXT4_MIN_INLINE_DATA_SIZE,
+		       inline_size - EXT4_MIN_INLINE_DATA_SIZE);
+
+	inode->i_flags &= ~EXT4_EXTENTS_FL;
+	inode->i_flags |= EXT4_INLINE_DATA_FL;
+
+	retval = ext2fs_write_inode_full(fs, ino, (void *)inode,
+					 EXT2_INODE_SIZE(fs->super));
+
+out:
+	ext2fs_free_mem(&inode);
+	return retval;
+}
-- 
1.7.4.1


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

* [PATCH 10/21 v5] debugfs: handle inline_data feature in dirsearch command
  2012-09-22  4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
                   ` (8 preceding siblings ...)
  2012-09-22  4:00 ` [PATCH 09/21 v5] libext2fs: handle inline data in read/write function Zheng Liu
@ 2012-09-22  4:00 ` Zheng Liu
  2012-09-22  4:00 ` [PATCH 11/21 v5] debugfs: handle inline_data feature in bmap command Zheng Liu
                   ` (10 subsequent siblings)
  20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22  4:00 UTC (permalink / raw)
  To: linux-ext4; +Cc: tytso, Zheng Liu

From: Zheng Liu <wenqing.lz@taobao.com>

Inode with inline_data hasn't any blocks.  So we need to handle it in a new
function.

Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 debugfs/htree.c          |    7 ++++
 lib/ext2fs/ext2fs.h      |    2 +
 lib/ext2fs/inline_data.c |   89 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 98 insertions(+), 0 deletions(-)

diff --git a/debugfs/htree.c b/debugfs/htree.c
index 1932962..eb71a40 100644
--- a/debugfs/htree.c
+++ b/debugfs/htree.c
@@ -374,9 +374,16 @@ void do_dirsearch(int argc, char *argv[])
 	pb.search_name = argv[2];
 	pb.len = strlen(pb.search_name);
 
+	if (ext2fs_inode_has_inline_data(current_fs, inode)) {
+		ext2fs_inline_data_dirsearch(current_fs, inode,
+					     argv[2], strlen(argv[2]));
+		goto out;
+	}
+
 	ext2fs_block_iterate3(current_fs, inode, BLOCK_FLAG_READ_ONLY, 0,
 			      search_dir_block, &pb);
 
+out:
 	free(pb.buf);
 }
 
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 801e2dd..9b7d608 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -1354,6 +1354,8 @@ extern errcode_t ext2fs_write_inline_data(ext2_filsys fs, ext2_ino_t ino,
 extern errcode_t ext2fs_try_to_write_inline_data(ext2_filsys fs, ext2_ino_t ino,
 						 const void *buf, unsigned int nbytes,
 						 unsigned int *written);
+extern errcode_t ext2fs_inline_data_dirsearch(ext2_filsys fs, ext2_ino_t ino,
+					      const char *name, size_t namelen);
 
 /* inode.c */
 extern errcode_t ext2fs_flush_icache(ext2_filsys fs);
diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c
index a847b68..402bc10 100644
--- a/lib/ext2fs/inline_data.c
+++ b/lib/ext2fs/inline_data.c
@@ -36,6 +36,8 @@ static int ext2fs_inline_data_destory_data(ext2_filsys fs, ext2_ino_t ino,
 static errcode_t ext2fs_create_inline_data(ext2_filsys fs,
 					   struct ext2_inode_large *inode,
 					   int len);
+static int do_search_dir(ext2_filsys fs, void *start, int size,
+			 const char *name, size_t len);
 
 static int ext2fs_iget_extra_inode(ext2_filsys fs, struct ext2_inode_large *inode,
 				    struct inline_data *data)
@@ -117,6 +119,93 @@ static int ext2fs_inline_data_destory_data(ext2_filsys fs, ext2_ino_t ino,
 	return 0;
 }
 
+static int do_search_dir(ext2_filsys fs, void *start, int size,
+			 const char *name, size_t len)
+{
+	struct ext2_dir_entry *de;
+	unsigned offset = 0;
+	unsigned rec_len;
+	errcode_t errcode;
+
+	while (offset < len) {
+		de = (struct ext2_dir_entry *)(start + offset);
+		errcode = ext2fs_get_rec_len(fs, de, &rec_len);
+		if (errcode) {
+			com_err("search_dir_inline_data", errcode,
+				"while getting rec_len for inline data");
+			return errcode;
+		}
+		if (de->inode &&
+		    len == (de->name_len & 0xFF) &&
+		    strncmp(name, de->name, len) == 0) {
+			printf("Entry found at inline data\n");
+			return 1;
+		}
+		offset += rec_len;
+	}
+	return 0;
+}
+
+errcode_t ext2fs_inline_data_dirsearch(ext2_filsys fs, ext2_ino_t ino,
+				       const char *name, size_t namelen)
+{
+	struct ext2_inode_large *inode;
+	struct ext2_dir_entry dirent;
+	struct inline_data data;
+	unsigned int offset = 0;
+	unsigned int rec_len;
+	void *inline_start;
+	int inline_size;
+	errcode_t retval = 0;
+
+	retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
+	if (retval)
+		return retval;
+
+	retval = ext2fs_read_inode_full(fs, ino, (void *)inode,
+					EXT2_INODE_SIZE(fs->super));
+	if (retval)
+		goto out;
+
+	/* check '.' and '..' firstly */
+	dirent.inode = ino;
+	dirent.name_len = 1;
+	ext2fs_set_rec_len(fs, EXT2_DIR_REC_LEN(2), &dirent);
+	dirent.name[0] = '.';
+	retval = do_search_dir(fs, (void *)&dirent, dirent.rec_len, name, namelen);
+	if (retval)
+		goto out;
+
+	dirent.inode = ((struct ext2_dir_entry *)inode->i_block)->inode;
+	dirent.name_len = 2;
+	ext2fs_set_rec_len(fs, EXT2_DIR_REC_LEN(3), &dirent);
+	dirent.name[0] = '.';
+	dirent.name[1] = '.';
+	retval = do_search_dir(fs, (void *)&dirent, dirent.rec_len, name, namelen);
+	if (retval)
+		goto out;
+
+	inline_start = (void *)inode->i_block + EXT4_INLINE_DATA_DOTDOT_SIZE;
+	inline_size = EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DATA_DOTDOT_SIZE;
+	retval = do_search_dir(fs, inline_start, inline_size, name, namelen);
+	if (retval)
+		goto out;
+
+	retval = ext2fs_iget_extra_inode(fs, inode, &data);
+	if (retval)
+		goto out;
+	if (data.inline_size == EXT4_MIN_INLINE_DATA_SIZE)
+		goto out;
+
+	inline_start = ext2fs_get_inline_xattr_pos(inode, &data);
+	inline_size = data.inline_size - EXT4_MIN_INLINE_DATA_SIZE;
+	retval = do_search_dir(fs, inline_start, inline_size, name, namelen);
+
+out:
+	ext2fs_free_mem(&inode);
+	return retval;
+}
+
 int ext2fs_inode_has_inline_data(ext2_filsys fs, ext2_ino_t ino)
 {
 	struct ext2_inode inode;
-- 
1.7.4.1


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

* [PATCH 11/21 v5] debugfs: handle inline_data feature in bmap command
  2012-09-22  4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
                   ` (9 preceding siblings ...)
  2012-09-22  4:00 ` [PATCH 10/21 v5] debugfs: handle inline_data feature in dirsearch command Zheng Liu
@ 2012-09-22  4:00 ` Zheng Liu
  2012-09-22  4:01 ` [PATCH 12/21 v5] debugfs: handle inline_data in punch command Zheng Liu
                   ` (9 subsequent siblings)
  20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22  4:00 UTC (permalink / raw)
  To: linux-ext4; +Cc: tytso, Zheng Liu

From: Zheng Liu <wenqing.lz@taobao.com>

If an inode has inline data, bmap command will return the physical block of this
inode.

Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 lib/ext2fs/bmap.c |   15 +++++++++++++++
 1 files changed, 15 insertions(+), 0 deletions(-)

diff --git a/lib/ext2fs/bmap.c b/lib/ext2fs/bmap.c
index 16d51e0..4746a1f 100644
--- a/lib/ext2fs/bmap.c
+++ b/lib/ext2fs/bmap.c
@@ -264,6 +264,21 @@ errcode_t ext2fs_bmap2(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode,
 		block_buf = buf;
 	}
 
+	if (inode->i_flags & EXT4_INLINE_DATA_FL) {
+		unsigned long group, block, offset;
+
+		group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
+		if (group > fs->group_desc_count)
+			return EXT2_ET_BAD_INODE_NUM;
+		offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
+			 EXT2_INODE_SIZE(fs->super);
+		block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super);
+		if (!ext2fs_inode_table_loc(fs, (unsigned) group))
+			return EXT2_ET_MISSING_INODE_TABLE;
+		*phys_blk = ext2fs_inode_table_loc(fs, group) + block;
+		goto done;
+	}
+
 	if (inode->i_flags & EXT4_EXTENTS_FL) {
 		retval = ext2fs_extent_open2(fs, ino, inode, &handle);
 		if (retval)
-- 
1.7.4.1


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

* [PATCH 12/21 v5] debugfs: handle inline_data in punch command
  2012-09-22  4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
                   ` (10 preceding siblings ...)
  2012-09-22  4:00 ` [PATCH 11/21 v5] debugfs: handle inline_data feature in bmap command Zheng Liu
@ 2012-09-22  4:01 ` Zheng Liu
  2012-09-22  4:01 ` [PATCH 13/21 v5] libext2fs: add inline_data feature into EXT2_LIB_FEATURE_INCOMPAT_SUPP Zheng Liu
                   ` (8 subsequent siblings)
  20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22  4:01 UTC (permalink / raw)
  To: linux-ext4; +Cc: tytso, Zheng Liu

From: Zheng Liu <wenqing.lz@taobao.com>

Now punch command only can truncate an inode with inline_data.

Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 lib/ext2fs/ext2fs.h      |    2 +
 lib/ext2fs/inline_data.c |   80 ++++++++++++++++++++++++++++++++++++++++++++++
 lib/ext2fs/punch.c       |   10 +++++-
 3 files changed, 91 insertions(+), 1 deletions(-)

diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index b451a4a..4e467a0 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -1360,6 +1360,8 @@ extern errcode_t ext2fs_try_to_write_inline_data(ext2_filsys fs, ext2_ino_t ino,
 						 unsigned int *written);
 extern errcode_t ext2fs_inline_data_dirsearch(ext2_filsys fs, ext2_ino_t ino,
 					      const char *name, size_t namelen);
+extern errcode_t ext2fs_punch_inline_data(ext2_filsys fs, ext2_ino_t ino,
+					  blk64_t start, blk64_t end);
 
 /* inode.c */
 extern errcode_t ext2fs_flush_icache(ext2_filsys fs);
diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c
index db33ddd..229e723 100644
--- a/lib/ext2fs/inline_data.c
+++ b/lib/ext2fs/inline_data.c
@@ -476,6 +476,86 @@ err:
 	ext2fs_free_mem(&inode);
 	return retval;
 }
+
+errcode_t ext2fs_punch_inline_data(ext2_filsys fs, ext2_ino_t ino,
+				   blk64_t start, blk64_t end)
+{
+	struct ext2_inode_large *inode;
+	struct inline_data data;
+	errcode_t retval = 0;
+	void *value;
+	int inline_size, value_len;
+
+	retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
+	if (retval)
+		return retval;
+
+	retval = ext2fs_read_inode_full(fs, ino, (void *)inode,
+					EXT2_INODE_SIZE(fs->super));
+	if (retval)
+		goto out;
+
+	retval = ext2fs_iget_extra_inode(fs, inode, &data);
+	if (retval)
+		goto out;
+	inline_size = data.inline_size;
+
+	if (start > inline_size)
+		goto out;
+
+	if (start < inline_size) {
+		struct ext2_ext_attr_ibody_header *header;
+		struct ext2_ext_attr_search s = {
+			.not_found = -1,
+		};
+		struct ext2_ext_attr_info i = {
+			.name_index = EXT4_EXT_ATTR_INDEX_SYSTEM,
+			.name = EXT4_EXT_ATTR_SYSTEM_DATA,
+		};
+
+		if (!data.inline_off)
+			goto out;
+
+		if (inode->i_extra_isize > (EXT2_INODE_SIZE(fs->super) -
+					    EXT2_GOOD_OLD_INODE_SIZE)) {
+			retval = EXT2_ET_BAD_EXTRA_SIZE;
+			goto out;
+		}
+
+		(void)ext2fs_ibody_find_ext_attr(fs, inode, &i, &s);
+
+		value_len = ext2fs_le32_to_cpu(s.here->e_value_size);
+
+		retval = ext2fs_get_mem(s.here->e_value_size, &value);
+		if (retval)
+			goto out;
+
+		retval = ext2fs_ibody_get_ext_attr(fs, inode, i.name_index,
+						   i.name, value, value_len);
+
+		if (!s.not_found) {
+			i.value = value;
+			i.value_len = start > EXT4_MIN_INLINE_DATA_SIZE ?
+					start - EXT4_MIN_INLINE_DATA_SIZE : 0;
+		}
+		retval = ext2fs_set_entry_ext_attr(&i, &s);
+		if (retval)
+			goto out;
+	}
+
+	if (start < EXT4_MIN_INLINE_DATA_SIZE) {
+		memset((void *)inode->i_block + start, 0,
+			EXT4_MIN_INLINE_DATA_SIZE - start);
+	}
+
+	inode->i_size = start;
+	retval = ext2fs_write_inode_full(fs, ino, (void *)inode,
+					 EXT2_INODE_SIZE(fs->super));
+out:
+	ext2fs_free_mem(&inode);
+	return retval;
+}
+
 errcode_t ext2fs_convert_inline_data(ext2_filsys fs,
 				     ext2_ino_t  ino,
 				     void *priv_data)
diff --git a/lib/ext2fs/punch.c b/lib/ext2fs/punch.c
index b53653a..4b8d51c 100644
--- a/lib/ext2fs/punch.c
+++ b/lib/ext2fs/punch.c
@@ -307,7 +307,15 @@ extern errcode_t ext2fs_punch(ext2_filsys fs, ext2_ino_t ino,
 			return retval;
 		inode = &inode_buf;
 	}
-	if (inode->i_flags & EXT4_EXTENTS_FL)
+	if (inode->i_flags & EXT4_INLINE_DATA_FL) {
+		/* punching hole for inline_data is not supported */
+		if (end != ~0)
+			retval = EXT2_ET_OP_NOT_SUPPORTED;
+		else
+			retval = ext2fs_punch_inline_data(fs, ino, start, end);
+
+		return retval;
+	} else if (inode->i_flags & EXT4_EXTENTS_FL)
 		retval = ext2fs_punch_extent(fs, ino, inode, start, end);
 	else {
 		blk_t	count;
-- 
1.7.4.1


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

* [PATCH 13/21 v5] libext2fs: add inline_data feature into EXT2_LIB_FEATURE_INCOMPAT_SUPP
  2012-09-22  4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
                   ` (11 preceding siblings ...)
  2012-09-22  4:01 ` [PATCH 12/21 v5] debugfs: handle inline_data in punch command Zheng Liu
@ 2012-09-22  4:01 ` Zheng Liu
  2012-09-22  4:01 ` [PATCH 14/21 v5] mke2fs: add inline_data support in mke2fs Zheng Liu
                   ` (7 subsequent siblings)
  20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22  4:01 UTC (permalink / raw)
  To: linux-ext4; +Cc: tytso, Zheng Liu

From: Zheng Liu <wenqing.lz@taobao.com>

let e2fsprogs support inline_data feature.

Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 lib/ext2fs/ext2fs.h |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index dd1c94c..d1f4218 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -586,7 +586,8 @@ typedef struct ext2_icount *ext2_icount_t;
 					 EXT3_FEATURE_INCOMPAT_EXTENTS|\
 					 EXT4_FEATURE_INCOMPAT_FLEX_BG|\
 					 EXT4_LIB_INCOMPAT_MMP|\
-					 EXT4_FEATURE_INCOMPAT_64BIT)
+					 EXT4_FEATURE_INCOMPAT_64BIT|\
+					 EXT4_FEATURE_INCOMPAT_INLINE_DATA)
 
 #define EXT2_LIB_FEATURE_RO_COMPAT_SUPP	(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|\
 					 EXT4_FEATURE_RO_COMPAT_HUGE_FILE|\
-- 
1.7.4.1


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

* [PATCH 14/21 v5] mke2fs: add inline_data support in mke2fs
  2012-09-22  4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
                   ` (12 preceding siblings ...)
  2012-09-22  4:01 ` [PATCH 13/21 v5] libext2fs: add inline_data feature into EXT2_LIB_FEATURE_INCOMPAT_SUPP Zheng Liu
@ 2012-09-22  4:01 ` Zheng Liu
  2012-09-22  4:01 ` [PATCH 15/21 v5] tune2fs: add inline_data feature in tune2fs Zheng Liu
                   ` (6 subsequent siblings)
  20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22  4:01 UTC (permalink / raw)
  To: linux-ext4; +Cc: tytso, Zheng Liu

From: Zheng Liu <wenqing.lz@taobao.com>

Ext_attr feature not enabled, inline_data feature doesn't be specified.

Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 misc/mke2fs.8.in |    3 +++
 misc/mke2fs.c    |   14 +++++++++++++-
 2 files changed, 16 insertions(+), 1 deletions(-)

diff --git a/misc/mke2fs.8.in b/misc/mke2fs.8.in
index 6d443a2..bfe6c94 100644
--- a/misc/mke2fs.8.in
+++ b/misc/mke2fs.8.in
@@ -551,6 +551,9 @@ option).
 @JDEV@must be created with the same
 @JDEV@block size as the filesystems that will be using it.
 .TP
+.B inline_data
+Allow data to be stored in inode
+.TP
 .B large_file
 Filesystem can contain files that are greater than 2GB.  (Modern kernels
 set this feature automatically when a file > 2GB is created.)
diff --git a/misc/mke2fs.c b/misc/mke2fs.c
index 072e656..19c23c1 100644
--- a/misc/mke2fs.c
+++ b/misc/mke2fs.c
@@ -883,7 +883,8 @@ static __u32 ok_features[3] = {
 		EXT2_FEATURE_INCOMPAT_META_BG|
 		EXT4_FEATURE_INCOMPAT_FLEX_BG|
 		EXT4_FEATURE_INCOMPAT_MMP |
-		EXT4_FEATURE_INCOMPAT_64BIT,
+		EXT4_FEATURE_INCOMPAT_64BIT|
+		EXT4_FEATURE_INCOMPAT_INLINE_DATA,
 	/* R/O compat */
 	EXT2_FEATURE_RO_COMPAT_LARGE_FILE|
 		EXT4_FEATURE_RO_COMPAT_HUGE_FILE|
@@ -1956,6 +1957,17 @@ profile_error:
 		exit(1);
 	}
 
+	/* Since inline_data depends on ext_attr, we would ask it to be
+	 * enabled.
+	 */
+	if ((fs_param.s_feature_incompat & EXT4_FEATURE_INCOMPAT_INLINE_DATA) &&
+	    !(fs_param.s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
+		com_err(program_name, 0,
+			_("Ext_attr feature not enabled, so inline_data "
+			  "feature doesn't be specified"));
+		exit(1);
+	}
+
 	if (fs_param.s_blocks_per_group) {
 		if (fs_param.s_blocks_per_group < 256 ||
 		    fs_param.s_blocks_per_group > 8 * (unsigned) blocksize) {
-- 
1.7.4.1


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

* [PATCH 15/21 v5] tune2fs: add inline_data feature in tune2fs
  2012-09-22  4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
                   ` (13 preceding siblings ...)
  2012-09-22  4:01 ` [PATCH 14/21 v5] mke2fs: add inline_data support in mke2fs Zheng Liu
@ 2012-09-22  4:01 ` Zheng Liu
  2012-09-22  4:01 ` [PATCH 16/21 v5] e2fsck: add problem descriptions and check inline data feature Zheng Liu
                   ` (5 subsequent siblings)
  20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22  4:01 UTC (permalink / raw)
  To: linux-ext4; +Cc: tytso, Zheng Liu

From: Zheng Liu <wenqing.lz@taobao.com>

Inline_data feature can be set when ext_attr feature is enabled.  Now this
feature only can be enabled because we may be out of space when disabling
it.  If this feature is disabled, we need to allocate a block for every
file and directory, and it might exhaust all space.

Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 misc/tune2fs.8.in |    5 +++++
 misc/tune2fs.c    |   17 ++++++++++++++++-
 2 files changed, 21 insertions(+), 1 deletions(-)

diff --git a/misc/tune2fs.8.in b/misc/tune2fs.8.in
index 55c6dd9..b768fff 100644
--- a/misc/tune2fs.8.in
+++ b/misc/tune2fs.8.in
@@ -531,6 +531,11 @@ Setting the filesystem feature is equivalent to using the
 .B \-j
 option.
 .TP
+.B inline_data
+Allow data to be stored in inode.
+.B Tune2fs
+only supports setting this filesystem feature.
+.TP
 .B large_file
 Filesystem can contain files that are greater than 2GB.  (Modern kernels
 set this feature automatically when a file > 2GB is created.)
diff --git a/misc/tune2fs.c b/misc/tune2fs.c
index b290c46..e9a0e85 100644
--- a/misc/tune2fs.c
+++ b/misc/tune2fs.c
@@ -137,7 +137,8 @@ static __u32 ok_features[3] = {
 	EXT2_FEATURE_INCOMPAT_FILETYPE |
 		EXT3_FEATURE_INCOMPAT_EXTENTS |
 		EXT4_FEATURE_INCOMPAT_FLEX_BG |
-		EXT4_FEATURE_INCOMPAT_MMP,
+		EXT4_FEATURE_INCOMPAT_MMP |
+		EXT4_FEATURE_INCOMPAT_INLINE_DATA,
 	/* R/O compat */
 	EXT2_FEATURE_RO_COMPAT_LARGE_FILE |
 		EXT4_FEATURE_RO_COMPAT_HUGE_FILE|
@@ -992,6 +993,20 @@ mmp_error:
 		disable_uninit_bg(fs,
 				EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
 
+	if (FEATURE_ON(E2P_FEATURE_INCOMPAT,
+		       EXT4_FEATURE_INCOMPAT_INLINE_DATA)) {
+		/* Inline_data feature cannot be enabled if ext_attr is
+		 * disabled.
+		 */
+		if (!(fs->super->s_feature_compat &
+		      EXT2_FEATURE_COMPAT_EXT_ATTR)) {
+			fputs(_("The inline_data feature cannot "
+				"be set if ext_attr feature is disabled.\n"),
+				stderr);
+			return 1;
+		}
+	}
+
 	if (FEATURE_ON(E2P_FEATURE_RO_INCOMPAT,
 				EXT4_FEATURE_RO_COMPAT_QUOTA)) {
 		/*
-- 
1.7.4.1


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

* [PATCH 16/21 v5] e2fsck: add problem descriptions and check inline data feature
  2012-09-22  4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
                   ` (14 preceding siblings ...)
  2012-09-22  4:01 ` [PATCH 15/21 v5] tune2fs: add inline_data feature in tune2fs Zheng Liu
@ 2012-09-22  4:01 ` Zheng Liu
  2012-10-14 13:22   ` Theodore Ts'o
  2012-09-22  4:01 ` [PATCH 17/21 v5] e2fsck: check inline_data in pass1 Zheng Liu
                   ` (4 subsequent siblings)
  20 siblings, 1 reply; 24+ messages in thread
From: Zheng Liu @ 2012-09-22  4:01 UTC (permalink / raw)
  To: linux-ext4; +Cc: tytso, Zheng Liu

From: Zheng Liu <wenqing.lz@taobao.com>

Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 e2fsck/pass1.c           |   33 ++++++++++++++++++++++++++++++++-
 e2fsck/problem.c         |   15 +++++++++++++++
 e2fsck/problem.h         |    9 +++++++++
 lib/ext2fs/ext2fs.h      |    1 +
 lib/ext2fs/inline_data.c |   28 ++++++++++++++++++++++++++++
 5 files changed, 85 insertions(+), 1 deletions(-)

diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index a4bd956..1a12ed3 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -593,7 +593,7 @@ void e2fsck_pass1(e2fsck_t ctx)
 	struct ext2_super_block *sb = ctx->fs->super;
 	const char	*old_op;
 	unsigned int	save_type;
-	int		imagic_fs, extent_fs;
+	int		imagic_fs, extent_fs, inlinedata_fs;
 	int		busted_fs_time = 0;
 	int		inode_size;
 	int		failed_csum = 0;
@@ -627,6 +627,8 @@ void e2fsck_pass1(e2fsck_t ctx)
 
 	imagic_fs = (sb->s_feature_compat & EXT2_FEATURE_COMPAT_IMAGIC_INODES);
 	extent_fs = (sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS);
+	inlinedata_fs = (sb->s_feature_incompat &
+			EXT4_FEATURE_INCOMPAT_INLINE_DATA);
 
 	/*
 	 * Allocate bitmaps structures
@@ -758,6 +760,20 @@ void e2fsck_pass1(e2fsck_t ctx)
 		ext2fs_mark_block_bitmap2(ctx->block_found_map,
 					  fs->super->s_mmp_block);
 
+	/*
+	 * If INLINE_DATA feature is set and EXT_ATTR feature missing,
+	 * EXT_ATTR needs to be set because INLINE_DATA depends on it and
+	 * this feature is enabled on default.
+	 */
+	if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR) &&
+	    inlinedata_fs) {
+		if (fix_problem(ctx, PR_1_INLINE_DATA_AND_EXT_ATTR, &pctx)) {
+			fs->super->s_feature_compat |=
+				EXT2_FEATURE_COMPAT_EXT_ATTR;
+			ext2fs_mark_super_dirty(fs);
+		}
+	}
+
 	/* Set up ctx->lost_and_found if possible */
 	(void) e2fsck_get_lost_and_found(ctx, 0);
 
@@ -809,6 +825,21 @@ void e2fsck_pass1(e2fsck_t ctx)
 			}
 		}
 
+		/* Test for incrrect inline_data flags settings. */
+		if ((inode->i_flags & EXT4_INLINE_DATA_FL) && !inlinedata_fs &&
+		    (ino >= EXT2_FIRST_INODE(fs->super))) {
+			if (ext2fs_inline_data_header_check(fs, ino) &&
+			    !fix_problem(ctx, PR_1_INLINE_DATA_FEATURE, &pctx)) {
+				sb->s_feature_incompat |=
+					EXT4_FEATURE_INCOMPAT_INLINE_DATA;
+				ext2fs_mark_super_dirty(fs);
+				inlinedata_fs = 1;
+			} else if (!fix_problem(ctx, PR_1_INLINE_DATA_SET, &pctx)) {
+				e2fsck_clear_inode(ctx, ino, inode, 0, "pass1");
+				continue;
+			}
+		}
+
 		/*
 		 * Test for incorrect extent flag settings.
 		 *
diff --git a/e2fsck/problem.c b/e2fsck/problem.c
index 78b05bb..ae99d6c 100644
--- a/e2fsck/problem.c
+++ b/e2fsck/problem.c
@@ -1000,6 +1000,21 @@ static struct e2fsck_problem problem_table[] = {
 	     "@i %i does not match.  "),
 	  PROMPT_FIX, 0 },
 
+	/* INLINE_DATA feature is set, but EXT_ATTR missing */
+	{ PR_1_INLINE_DATA_AND_EXT_ATTR,
+	  N_("INLINE_DATA feature is set in @S, but EXT_ATTR feature missing\n"),
+	  PROMPT_FIX, 0 },
+
+	/* Inode has inline data, but superblock is missing INLINE_DATA feature. */
+	{ PR_1_INLINE_DATA_FEATURE,
+	  N_("@i %i has inline data, but @S is missing INLINE_DATA feature\n"),
+	  PROMPT_CLEAR, PR_PREEN_OK },
+
+	/* INLINE_DATA feature is set in a non-inline-data filesystem */
+	{ PR_1_INLINE_DATA_SET,
+	  N_("@i %i has INLINE_DATA_FL flag on @f without inline data support.\n"),
+	  PROMPT_CLEAR, 0 },
+
 	/* Pass 1b errors */
 
 	/* Pass 1B: Rescan for duplicate/bad blocks */
diff --git a/e2fsck/problem.h b/e2fsck/problem.h
index 5caade4..2713f6c 100644
--- a/e2fsck/problem.h
+++ b/e2fsck/problem.h
@@ -586,6 +586,15 @@ struct problem_context {
 /* ea block passes checks, but checksum invalid */
 #define PR_1_EA_BLOCK_ONLY_CSUM_INVALID        0x01006C
 
+/* INLINE_DATA feature is set, but EXT_ATTR missing */
+#define PR_1_INLINE_DATA_AND_EXT_ATTR  0x01006D
+
+/* Inode has inline data, but superblock is missing INLINE_DATA feature. */
+#define PR_1_INLINE_DATA_FEATURE       0x01006E
+
+/* INLINE_DATA feature is set in a non-inline-data filesystem */
+#define PR_1_INLINE_DATA_SET	       0x01006F
+
 
 /*
  * Pass 1b errors
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index d1f4218..a4a3d06 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -1344,6 +1344,7 @@ extern int ext2fs_inline_data_iterate(ext2_filsys fs,
 						  struct ext2_inode_large *inode,
 						  void *priv_data),
 				      void *priv_data);
+extern int ext2fs_inline_data_header_check(ext2_filsys fs, ext2_ino_t ino);
 extern errcode_t ext2fs_inline_data_mkdir(ext2_filsys fs, ext2_ino_t parent,
 					  ext2_ino_t ino, const char *name);
 extern errcode_t ext2fs_convert_inline_data(ext2_filsys fs, ext2_ino_t ino,
diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c
index 4a98a37..d98b6c7 100644
--- a/lib/ext2fs/inline_data.c
+++ b/lib/ext2fs/inline_data.c
@@ -541,6 +541,34 @@ out:
 	return retval;
 }
 
+int ext2fs_inline_data_header_check(ext2_filsys fs, ext2_ino_t ino)
+{
+	struct ext2_inode_large *inode;
+	struct inline_data data;
+	errcode_t retval = 0;
+	int pass = 0;
+
+	retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
+	if (retval);
+		return pass;
+
+	retval = ext2fs_read_inode_full(fs, ino, (void *)inode,
+					EXT2_INODE_SIZE(fs->super));
+	if (retval)
+		goto err;
+
+	retval = ext2fs_iget_extra_inode(fs, inode, &data);
+	if (retval)
+		goto err;
+
+	if (data.inline_off != 0)
+		pass = 1;
+
+err:
+	ext2fs_free_mem(&inode);
+	return pass;
+}
+
 errcode_t ext2fs_convert_inline_data(ext2_filsys fs,
 				     ext2_ino_t  ino,
 				     void *priv_data)
-- 
1.7.4.1


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

* [PATCH 17/21 v5] e2fsck: check inline_data in pass1
  2012-09-22  4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
                   ` (15 preceding siblings ...)
  2012-09-22  4:01 ` [PATCH 16/21 v5] e2fsck: add problem descriptions and check inline data feature Zheng Liu
@ 2012-09-22  4:01 ` Zheng Liu
  2012-09-22  4:01 ` [PATCH 18/21 v5] e2fsck: check inline_data in pass2 Zheng Liu
                   ` (3 subsequent siblings)
  20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22  4:01 UTC (permalink / raw)
  To: linux-ext4; +Cc: tytso, Zheng Liu

From: Zheng Liu <wenqing.lz@taobao.com>

Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 e2fsck/pass1.c          |   71 ++++++++++++++++++++++++++++++++++++++++++++--
 lib/ext2fs/dblist_dir.c |   10 +++++-
 2 files changed, 75 insertions(+), 6 deletions(-)

diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index 1a12ed3..41352c7 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -202,6 +202,16 @@ int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino,
 		return i;
 	}
 
+	if (inode->i_flags & EXT4_INLINE_DATA_FL) {
+		int inline_size;
+
+		inline_size = ext2fs_get_inline_data_size(fs, ino);
+		if (inline_size == inode->i_size)
+			return 1;
+		else
+			return 0;
+	}
+
 	blocks = ext2fs_inode_data_blocks2(fs, inode);
 	if (blocks) {
 		if ((inode->i_size >= fs->blocksize) ||
@@ -304,6 +314,16 @@ static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx)
 			goto fix;
 		}
 
+		/*
+		 * Don't do the following checks for inline_data because
+		 * other checks ensure that the content of inline data
+		 * is corrent.
+		 */
+		if (strncmp(EXT2_EXT_ATTR_NAME(entry),
+		    EXT4_EXT_ATTR_SYSTEM_DATA,
+		    strlen(EXT4_EXT_ATTR_SYSTEM_DATA)) == 0)
+			goto next;
+
 		/* attribute len eats this space */
 		remain -= EXT2_EXT_ATTR_SIZE(entry->e_name_len);
 
@@ -331,6 +351,7 @@ static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx)
 			goto fix;
 		}
 
+next:
 		remain -= entry->e_value_size;
 
 		entry = EXT2_EXT_ATTR_NEXT(entry);
@@ -408,6 +429,7 @@ static void check_is_really_dir(e2fsck_t ctx, struct problem_context *pctx,
 	blk64_t			blk;
 	unsigned int		i, rec_len, not_device = 0;
 	int			extent_fs;
+	int			inlinedata_fs;
 
 	/*
 	 * If the mode looks OK, we believe it.  If the first block in
@@ -435,11 +457,19 @@ static void check_is_really_dir(e2fsck_t ctx, struct problem_context *pctx,
 	 * For extent mapped files, we don't do any sanity checking:
 	 * just try to get the phys block of logical block 0 and run
 	 * with it.
+	 *
+	 * For inline_data files, we just skip it because, in e2fsck
+	 * pass1, we cannot get parent inode of a inode.  So we have
+	 * no way to determine the inode is a directory or not.
 	 */
 
 	extent_fs = (ctx->fs->super->s_feature_incompat &
 		     EXT3_FEATURE_INCOMPAT_EXTENTS);
-	if (extent_fs && (inode->i_flags & EXT4_EXTENTS_FL)) {
+	inlinedata_fs = (ctx->fs->super->s_feature_incompat &
+			EXT4_FEATURE_INCOMPAT_INLINE_DATA);
+	if (inlinedata_fs && (inode->i_flags & EXT4_INLINE_DATA_FL))
+		return;
+	else if (extent_fs && (inode->i_flags & EXT4_EXTENTS_FL)) {
 		/* extent mapped */
 		if  (ext2fs_bmap2(ctx->fs, pctx->ino, inode, 0, 0, 0, 0,
 				 &blk))
@@ -1206,7 +1236,8 @@ void e2fsck_pass1(e2fsck_t ctx)
 			ctx->fs_sockets_count++;
 		} else
 			mark_inode_bad(ctx, ino);
-		if (!(inode->i_flags & EXT4_EXTENTS_FL)) {
+		if (!(inode->i_flags & EXT4_EXTENTS_FL) &&
+		    !(inode->i_flags & EXT4_INLINE_DATA_FL)) {
 			if (inode->i_block[EXT2_IND_BLOCK])
 				ctx->fs_ind_count++;
 			if (inode->i_block[EXT2_DIND_BLOCK])
@@ -1215,6 +1246,7 @@ void e2fsck_pass1(e2fsck_t ctx)
 				ctx->fs_tind_count++;
 		}
 		if (!(inode->i_flags & EXT4_EXTENTS_FL) &&
+		    !(inode->i_flags & EXT4_INLINE_DATA_FL) &&
 		    (inode->i_block[EXT2_IND_BLOCK] ||
 		     inode->i_block[EXT2_DIND_BLOCK] ||
 		     inode->i_block[EXT2_TIND_BLOCK] ||
@@ -2099,6 +2131,28 @@ static void check_blocks_extents(e2fsck_t ctx, struct problem_context *pctx,
 }
 
 /*
+ * In fact we needn't check blocks for a inode that has inline data because
+ * this inode doesn't have any blocks.  In this function, all we need to do
+ * is add this inode into dblist when it is a directory.
+ */
+static void check_blocks_inline_data(e2fsck_t ctx,
+				     struct problem_context *pctx,
+				     struct process_block_struct *pb)
+{
+	if (!pb->is_dir)
+		return;
+
+	pctx->errcode = ext2fs_add_dir_block2(ctx->fs->dblist,
+					      pb->ino, 0, 0);
+	if (pctx->errcode) {
+		pctx->blk = 0;
+		pctx->num = 0;
+		fix_problem(ctx, PR_1_ADD_DBLOCK, pctx);
+		ctx->flags |= E2F_FLAG_ABORT;
+	}
+}
+
+/*
  * This subroutine is called on each inode to account for all of the
  * blocks used by that inode.
  */
@@ -2112,6 +2166,7 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
 	int		bad_size = 0;
 	int		dirty_inode = 0;
 	int		extent_fs;
+	int		inlinedata_fs;
 	__u64		size;
 
 	pb.ino = ino;
@@ -2135,6 +2190,8 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
 
 	extent_fs = (ctx->fs->super->s_feature_incompat &
                      EXT3_FEATURE_INCOMPAT_EXTENTS);
+	inlinedata_fs = (ctx->fs->super->s_feature_incompat &
+			 EXT4_FEATURE_INCOMPAT_INLINE_DATA);
 
 	if (inode->i_flags & EXT2_COMPRBLK_FL) {
 		if (fs->super->s_feature_incompat &
@@ -2158,6 +2215,9 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
 	if (ext2fs_inode_has_valid_blocks2(fs, inode)) {
 		if (extent_fs && (inode->i_flags & EXT4_EXTENTS_FL))
 			check_blocks_extents(ctx, pctx, &pb);
+		else if (inlinedata_fs &&
+			 (inode->i_flags & EXT4_INLINE_DATA_FL))
+			check_blocks_inline_data(ctx, pctx, &pb);
 		else {
 			pctx->errcode = ext2fs_block_iterate3(fs, ino,
 						pb.is_dir ? BLOCK_FLAG_HOLE : 0,
@@ -2200,7 +2260,8 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
 		}
 	}
 
-	if (!pb.num_blocks && pb.is_dir) {
+	if (!pb.num_blocks && pb.is_dir &&
+	    !(inode->i_flags & EXT4_INLINE_DATA_FL)) {
 		if (fix_problem(ctx, PR_1_ZERO_LENGTH_DIR, pctx)) {
 			e2fsck_clear_inode(ctx, ino, inode, 0, "check_blocks");
 			ctx->fs_directory_count--;
@@ -2226,7 +2287,9 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
 #endif
 	if (pb.is_dir) {
 		int nblock = inode->i_size >> EXT2_BLOCK_SIZE_BITS(fs->super);
-		if (inode->i_size & (fs->blocksize - 1))
+		if (inode->i_flags & EXT4_INLINE_DATA_FL)
+			;
+		else if (inode->i_size & (fs->blocksize - 1))
 			bad_size = 5;
 		else if (nblock > (pb.last_block + 1))
 			bad_size = 1;
diff --git a/lib/ext2fs/dblist_dir.c b/lib/ext2fs/dblist_dir.c
index d4d5111..6282ab4 100644
--- a/lib/ext2fs/dblist_dir.c
+++ b/lib/ext2fs/dblist_dir.c
@@ -72,8 +72,14 @@ static int db_dir_proc(ext2_filsys fs, struct ext2_db_entry2 *db_info,
 	ctx->dir = db_info->ino;
 	ctx->errcode = 0;
 
-	ret = ext2fs_process_dir_block(fs, &db_info->blk,
-				       db_info->blockcnt, 0, 0, priv_data);
+	if (ext2fs_inode_has_inline_data(fs, ctx->dir))
+		ret = ext2fs_inline_data_iterate(fs, ctx->dir, 0, 0,
+						 ext2fs_process_dir_inline_data,
+						 priv_data);
+	else
+		ret = ext2fs_process_dir_block(fs, &db_info->blk,
+					       db_info->blockcnt,
+					       0, 0, priv_data);
 	if ((ret & BLOCK_ABORT) && !ctx->errcode)
 		return DBLIST_ABORT;
 	return 0;
-- 
1.7.4.1


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

* [PATCH 18/21 v5] e2fsck: check inline_data in pass2
  2012-09-22  4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
                   ` (16 preceding siblings ...)
  2012-09-22  4:01 ` [PATCH 17/21 v5] e2fsck: check inline_data in pass1 Zheng Liu
@ 2012-09-22  4:01 ` Zheng Liu
  2012-09-22  4:01 ` [PATCH 19/21 v5] e2fsck: check inline_data in pass3 Zheng Liu
                   ` (2 subsequent siblings)
  20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22  4:01 UTC (permalink / raw)
  To: linux-ext4; +Cc: tytso, Zheng Liu

From: Zheng Liu <wenqing.lz@taobao.com>

Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 e2fsck/pass2.c |  123 +++++++++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 95 insertions(+), 28 deletions(-)

diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c
index e28af61..fd48ca5 100644
--- a/e2fsck/pass2.c
+++ b/e2fsck/pass2.c
@@ -725,6 +725,15 @@ static void salvage_directory(ext2_filsys fs,
 	}
 }
 
+static int is_last_entry(ext2_filsys fs, ext2_ino_t ino,
+			 unsigned int offset, int csum_size)
+{
+	if (ext2fs_inode_has_inline_data(fs, ino))
+		return (offset < ext2fs_get_inline_data_size(fs, ino));
+	else
+		return (offset < fs->blocksize - csum_size);
+}
+
 static int check_dir_block(ext2_filsys fs,
 			   struct ext2_db_entry2 *db,
 			   void *priv_data)
@@ -733,7 +742,7 @@ static int check_dir_block(ext2_filsys fs,
 #ifdef ENABLE_HTREE
 	struct dx_dirblock_info	*dx_db = 0;
 #endif /* ENABLE_HTREE */
-	struct ext2_dir_entry 	*dirent, *prev;
+	struct ext2_dir_entry 	*dirent, *prev, dot, dotdot;
 	ext2_dirhash_t		hash;
 	unsigned int		offset = 0;
 	int			dir_modified = 0;
@@ -756,6 +765,8 @@ static int check_dir_block(ext2_filsys fs,
 	int	dx_csum_size = 0, de_csum_size = 0;
 	int	failed_csum = 0;
 	int	is_leaf = 1;
+	int	inline_data = 0;
+	int	filetype = 0;
 
 	cd = (struct check_dir_struct *) priv_data;
 	buf = cd->buf;
@@ -773,6 +784,10 @@ static int check_dir_block(ext2_filsys fs,
 		de_csum_size = sizeof(struct ext2_dir_entry_tail);
 	}
 
+	if (EXT2_HAS_INCOMPAT_FEATURE(fs->super,
+				      EXT2_FEATURE_INCOMPAT_FILETYPE))
+		filetype = EXT2_FT_DIR << 8;
+
 	/*
 	 * Make sure the inode is still in use (could have been
 	 * deleted in the duplicate/bad blocks pass.
@@ -787,7 +802,11 @@ static int check_dir_block(ext2_filsys fs,
 	cd->pctx.dirent = 0;
 	cd->pctx.num = 0;
 
-	if (db->blk == 0) {
+	if (EXT2_HAS_INCOMPAT_FEATURE(fs->super,
+				      EXT4_FEATURE_INCOMPAT_INLINE_DATA))
+		inline_data = ext2fs_inode_has_inline_data(fs, ino);
+
+	if (db->blk == 0 && !inline_data) {
 		if (allocate_dir_block(ctx, db, buf, &cd->pctx))
 			return 0;
 		block_nr = db->blk;
@@ -808,7 +827,11 @@ static int check_dir_block(ext2_filsys fs,
 #endif
 
 	ehandler_operation(_("reading directory block"));
-	cd->pctx.errcode = ext2fs_read_dir_block4(fs, block_nr, buf, 0, ino);
+	if (inline_data)
+		cd->pctx.errcode = ext2fs_read_inline_data(fs, ino, buf);
+	else
+		cd->pctx.errcode = ext2fs_read_dir_block4(fs, block_nr,
+							  buf, 0, ino);
 	ehandler_operation(0);
 	if (cd->pctx.errcode == EXT2_ET_DIR_CORRUPTED)
 		cd->pctx.errcode = 0; /* We'll handle this ourselves */
@@ -879,7 +902,7 @@ out_htree:
 #endif /* ENABLE_HTREE */
 
 	/* Verify checksum. */
-	if (is_leaf && de_csum_size) {
+	if (is_leaf && de_csum_size && !inline_data) {
 		/* No space for csum?  Rebuild dirs in pass 3A. */
 		if (!ext2fs_dirent_has_tail(fs, (struct ext2_dir_entry *)buf)) {
 			de_csum_size = 0;
@@ -917,20 +940,44 @@ skip_checksum:
 		ext2_ino_t first_unused_inode;
 
 		problem = 0;
-		dirent = (struct ext2_dir_entry *) (buf + offset);
-		(void) ext2fs_get_rec_len(fs, dirent, &rec_len);
-		cd->pctx.dirent = dirent;
-		cd->pctx.num = offset;
-		if (((offset + rec_len) > fs->blocksize) ||
-		    (rec_len < 12) ||
-		    ((rec_len % 4) != 0) ||
-		    (((dirent->name_len & (unsigned) 0xFF)+8) > rec_len)) {
-			if (fix_problem(ctx, PR_2_DIR_CORRUPTED, &cd->pctx)) {
-				salvage_directory(fs, dirent, prev, &offset);
-				dir_modified++;
-				continue;
-			} else
-				goto abort_free_dict;
+		if (!inline_data || dot_state > 1) {
+			dirent = (struct ext2_dir_entry *) (buf + offset);
+			(void) ext2fs_get_rec_len(fs, dirent, &rec_len);
+			cd->pctx.dirent = dirent;
+			cd->pctx.num = offset;
+			if (((offset + rec_len) > fs->blocksize) ||
+			    (rec_len < 12) ||
+			    ((rec_len % 4) != 0) ||
+			    (((dirent->name_len & (unsigned) 0xFF)+8) > rec_len)) {
+				if (fix_problem(ctx, PR_2_DIR_CORRUPTED, &cd->pctx)) {
+					salvage_directory(fs, dirent, prev, &offset);
+					dir_modified++;
+					continue;
+				} else
+					goto abort_free_dict;
+			}
+		} else {
+			if (dot_state == 0) {
+				memset(&dot, 0, sizeof(dot));
+				dirent = &dot;
+				dirent->inode = ino;
+				dirent->rec_len = EXT2_DIR_REC_LEN(1);
+				dirent->name_len = 1 | filetype;
+				dirent->name[0] = '.';
+			} else if (dot_state == 1) {
+				memset(&dotdot, 0, sizeof(dotdot));
+				dirent = &dotdot;
+				dirent->inode =
+					((struct ext2_dir_entry *)buf)->inode;
+				dirent->rec_len = EXT2_DIR_REC_LEN(2);
+				dirent->name_len = 2 | filetype;
+				dirent->name[0] = '.';
+				dirent->name[1] = '.';
+			} else {
+				fatal_error(ctx, _("Can not continue."));
+			}
+			cd->pctx.dirent = dirent;
+			cd->pctx.num = offset;
 		}
 
 		if (dot_state == 0) {
@@ -1171,9 +1218,14 @@ skip_checksum:
 		prev = dirent;
 		if (dir_modified)
 			(void) ext2fs_get_rec_len(fs, dirent, &rec_len);
-		offset += rec_len;
+		if (!inline_data || dot_state > 1) {
+			offset += rec_len;
+		} else {
+			if (dot_state == 1)
+				offset = 4;
+		}
 		dot_state++;
-	} while (offset < fs->blocksize - de_csum_size);
+	} while (is_last_entry(fs, ino, offset, de_csum_size));
 #if 0
 	printf("\n");
 #endif
@@ -1191,12 +1243,23 @@ skip_checksum:
 	}
 #endif /* ENABLE_HTREE */
 
-	if (offset != fs->blocksize - de_csum_size) {
-		cd->pctx.num = rec_len - (fs->blocksize - de_csum_size) +
-			       offset;
-		if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) {
-			dirent->rec_len = cd->pctx.num;
-			dir_modified++;
+	if (inline_data) {
+		if (offset != ext2fs_get_inline_data_size(fs, ino)) {
+			cd->pctx.num = rec_len + offset -
+				ext2fs_get_inline_data_size(fs, ino);
+			if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) {
+				dirent->rec_len = cd->pctx.num;
+				dir_modified++;
+			}
+		}
+	} else {
+		if (offset != fs->blocksize - de_csum_size) {
+			cd->pctx.num = rec_len - (fs->blocksize - de_csum_size) +
+				       offset;
+			if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) {
+				dirent->rec_len = cd->pctx.num;
+				dir_modified++;
+			}
 		}
 	}
 	if (dir_modified) {
@@ -1210,8 +1273,12 @@ skip_checksum:
 write_and_fix:
 		if (e2fsck_dir_will_be_rehashed(ctx, ino))
 			ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
-		cd->pctx.errcode = ext2fs_write_dir_block4(fs, block_nr, buf,
-							   0, ino);
+		if (inline_data)
+			cd->pctx.errcode = ext2fs_write_inline_data(fs, ino,
+								    buf);
+		else
+			cd->pctx.errcode = ext2fs_write_dir_block4(fs, block_nr,
+								   buf, 0, ino);
 		if (e2fsck_dir_will_be_rehashed(ctx, ino))
 			ctx->fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
 		if (cd->pctx.errcode) {
-- 
1.7.4.1


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

* [PATCH 19/21 v5] e2fsck: check inline_data in pass3
  2012-09-22  4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
                   ` (17 preceding siblings ...)
  2012-09-22  4:01 ` [PATCH 18/21 v5] e2fsck: check inline_data in pass2 Zheng Liu
@ 2012-09-22  4:01 ` Zheng Liu
  2012-09-22  4:01 ` [PATCH 20/21 v5] tests: change result in f_bad_disconnected_inode Zheng Liu
  2012-09-22  4:01 ` [PATCH 21/21 v5] mke2fs: enable inline_data feature on ext4dev filesystem Zheng Liu
  20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22  4:01 UTC (permalink / raw)
  To: linux-ext4; +Cc: tytso, Zheng Liu

From: Zheng Liu <wenqing.lz@taobao.com>

Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 e2fsck/pass3.c  |    8 ++++++++
 e2fsck/rehash.c |    3 ++-
 2 files changed, 10 insertions(+), 1 deletions(-)

diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c
index a379e9b..85b3f65 100644
--- a/e2fsck/pass3.c
+++ b/e2fsck/pass3.c
@@ -787,6 +787,14 @@ errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
 	es.ctx = ctx;
 	es.dir = dir;
 
+	if (ext2fs_inode_has_inline_data(fs, dir)) {
+		retval = ext2fs_convert_inline_data(fs, dir, &es);
+		if (retval)
+			return retval;
+
+		return 0;
+	}
+
 	retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND,
 				       0, expand_dir_proc, &es);
 
diff --git a/e2fsck/rehash.c b/e2fsck/rehash.c
index 347f1b0..a54c6b4 100644
--- a/e2fsck/rehash.c
+++ b/e2fsck/rehash.c
@@ -940,7 +940,8 @@ void e2fsck_rehash_directories(e2fsck_t ctx)
 #if 0
 		fix_problem(ctx, PR_3A_OPTIMIZE_DIR, &pctx);
 #endif
-		pctx.errcode = e2fsck_rehash_dir(ctx, ino);
+		if (!ext2fs_inode_has_inline_data(ctx->fs, ino))
+			pctx.errcode = e2fsck_rehash_dir(ctx, ino);
 		if (pctx.errcode) {
 			end_problem_latch(ctx, PR_LATCH_OPTIMIZE_DIR);
 			fix_problem(ctx, PR_3A_OPTIMIZE_DIR_ERR, &pctx);
-- 
1.7.4.1


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

* [PATCH 20/21 v5] tests: change result in f_bad_disconnected_inode
  2012-09-22  4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
                   ` (18 preceding siblings ...)
  2012-09-22  4:01 ` [PATCH 19/21 v5] e2fsck: check inline_data in pass3 Zheng Liu
@ 2012-09-22  4:01 ` Zheng Liu
  2012-09-22  4:01 ` [PATCH 21/21 v5] mke2fs: enable inline_data feature on ext4dev filesystem Zheng Liu
  20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22  4:01 UTC (permalink / raw)
  To: linux-ext4; +Cc: tytso, Zheng Liu

From: Zheng Liu <wenqing.lz@taobao.com>

In this test, inode flag is some random data, and when we apply inline data
patch set we should need to handle it.

Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 tests/f_bad_disconnected_inode/expect.1 |    9 +++++++++
 1 files changed, 9 insertions(+), 0 deletions(-)

diff --git a/tests/f_bad_disconnected_inode/expect.1 b/tests/f_bad_disconnected_inode/expect.1
index 11862f6..9f9b447 100644
--- a/tests/f_bad_disconnected_inode/expect.1
+++ b/tests/f_bad_disconnected_inode/expect.1
@@ -2,9 +2,18 @@ Pass 1: Checking inodes, blocks, and sizes
 Inode 1 has EXTENTS_FL flag set on filesystem without extents support.
 Clear? yes
 
+Inode 14 has INLINE_DATA_FL flag on filesystem without inline data support.
+Clear? yes
+
+Inode 15 has INLINE_DATA_FL flag on filesystem without inline data support.
+Clear? yes
+
 Inode 15 has EXTENTS_FL flag set on filesystem without extents support.
 Clear? yes
 
+Inode 16 has INLINE_DATA_FL flag on filesystem without inline data support.
+Clear? yes
+
 Inode 16 has EXTENTS_FL flag set on filesystem without extents support.
 Clear? yes
 
-- 
1.7.4.1


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

* [PATCH 21/21 v5] mke2fs: enable inline_data feature on ext4dev filesystem
  2012-09-22  4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
                   ` (19 preceding siblings ...)
  2012-09-22  4:01 ` [PATCH 20/21 v5] tests: change result in f_bad_disconnected_inode Zheng Liu
@ 2012-09-22  4:01 ` Zheng Liu
  20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22  4:01 UTC (permalink / raw)
  To: linux-ext4; +Cc: tytso, Zheng Liu

From: Zheng Liu <wenqing.lz@taobao.com>

Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 misc/mke2fs.conf.in |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/misc/mke2fs.conf.in b/misc/mke2fs.conf.in
index 178733f..4c5dba7 100644
--- a/misc/mke2fs.conf.in
+++ b/misc/mke2fs.conf.in
@@ -16,7 +16,7 @@
 		inode_size = 256
 	}
 	ext4dev = {
-		features = has_journal,extent,huge_file,flex_bg,metadata_csum,64bit,dir_nlink,extra_isize
+		features = has_journal,extent,huge_file,flex_bg,metadata_csum,inline_data,64bit,dir_nlink,extra_isize
 		inode_size = 256
 		options = test_fs=1
 	}
-- 
1.7.4.1


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

* Re: [PATCH 16/21 v5] e2fsck: add problem descriptions and check inline data feature
  2012-09-22  4:01 ` [PATCH 16/21 v5] e2fsck: add problem descriptions and check inline data feature Zheng Liu
@ 2012-10-14 13:22   ` Theodore Ts'o
  2012-10-14 23:34     ` Zheng Liu
  0 siblings, 1 reply; 24+ messages in thread
From: Theodore Ts'o @ 2012-10-14 13:22 UTC (permalink / raw)
  To: Zheng Liu; +Cc: linux-ext4, Zheng Liu

Hi Zheng,

I was trying to apply these patches to the e2fsprogs pu branch, and as
a matter of course, I ran checkpatch on the patch series.  The reason
why it's useful is because it finds stuff like this:

WARNING: trailing semicolon indicates no statements, indent implies otherwise
#156: FILE: lib/ext2fs/inline_data.c:567:
+     if (retval);
+     	 return pass;

ERROR: trailing statements should be on next line
#156: FILE: lib/ext2fs/inline_data.c:567:
+     if (retval);

> +int ext2fs_inline_data_header_check(ext2_filsys fs, ext2_ino_t ino)
> +{
> +	struct ext2_inode_large *inode;
> +	struct inline_data data;
> +	errcode_t retval = 0;
> +	int pass = 0;
> +
> +	retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
> +	if (retval);
> +		return pass;

This means the rest of ext2fs_inline_data_header_check() isn't getting
executed, since the "return pass;" statement would get executed
unconditionally.  I didn't try it, but I suspect "make gcc-wall"
probably would have turned up this typo as well.

I'll fix this in my tree on the pu branch; I'm still looking over the
rest of the patches, but I thought it would be good to point this out
first.

Cheers,

					- Ted

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

* Re: [PATCH 16/21 v5] e2fsck: add problem descriptions and check inline data feature
  2012-10-14 13:22   ` Theodore Ts'o
@ 2012-10-14 23:34     ` Zheng Liu
  0 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-10-14 23:34 UTC (permalink / raw)
  To: Theodore Ts'o; +Cc: linux-ext4, Zheng Liu

On Sun, Oct 14, 2012 at 09:22:10AM -0400, Theodore Ts'o wrote:
> Hi Zheng,
> 
> I was trying to apply these patches to the e2fsprogs pu branch, and as
> a matter of course, I ran checkpatch on the patch series.  The reason
> why it's useful is because it finds stuff like this:
> 
> WARNING: trailing semicolon indicates no statements, indent implies otherwise
> #156: FILE: lib/ext2fs/inline_data.c:567:
> +     if (retval);
> +     	 return pass;
> 
> ERROR: trailing statements should be on next line
> #156: FILE: lib/ext2fs/inline_data.c:567:
> +     if (retval);
> 
> > +int ext2fs_inline_data_header_check(ext2_filsys fs, ext2_ino_t ino)
> > +{
> > +	struct ext2_inode_large *inode;
> > +	struct inline_data data;
> > +	errcode_t retval = 0;
> > +	int pass = 0;
> > +
> > +	retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
> > +	if (retval);
> > +		return pass;
> 
> This means the rest of ext2fs_inline_data_header_check() isn't getting
> executed, since the "return pass;" statement would get executed
> unconditionally.  I didn't try it, but I suspect "make gcc-wall"
> probably would have turned up this typo as well.
> 
> I'll fix this in my tree on the pu branch; I'm still looking over the
> rest of the patches, but I thought it would be good to point this out
> first.

Oops, it's my fault.  Thanks for pointing it out.

Regards,
Zheng

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

end of thread, other threads:[~2012-10-14 23:23 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-09-22  4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
2012-09-22  4:00 ` [PATCH 01/21 v5] libext2fs: add INLINE_DATA into EXT2_LIB_SOFTSUPP_INCOMPAT Zheng Liu
2012-09-22  4:00 ` [PATCH 02/21 v5] libext2fs: add function to check inline_data flag for an inode Zheng Liu
2012-09-22  4:00 ` [PATCH 03/21 v5] libext2fs: add functions to operate extend attribute Zheng Liu
2012-09-22  4:00 ` [PATCH 04/21 v5] libext2fs: handle inline data in dir iterator function Zheng Liu
2012-09-22  4:00 ` [PATCH 05/21 v5] libext2fs: handle inline_data in block " Zheng Liu
2012-09-22  4:00 ` [PATCH 06/21 v5] debugfs: make stat command support inline data Zheng Liu
2012-09-22  4:00 ` [PATCH 07/21 v5] libext2fs: handle inline data when expanding directory Zheng Liu
2012-09-22  4:00 ` [PATCH 08/21 v5] debugfs: make lsdel command support inline data Zheng Liu
2012-09-22  4:00 ` [PATCH 09/21 v5] libext2fs: handle inline data in read/write function Zheng Liu
2012-09-22  4:00 ` [PATCH 10/21 v5] debugfs: handle inline_data feature in dirsearch command Zheng Liu
2012-09-22  4:00 ` [PATCH 11/21 v5] debugfs: handle inline_data feature in bmap command Zheng Liu
2012-09-22  4:01 ` [PATCH 12/21 v5] debugfs: handle inline_data in punch command Zheng Liu
2012-09-22  4:01 ` [PATCH 13/21 v5] libext2fs: add inline_data feature into EXT2_LIB_FEATURE_INCOMPAT_SUPP Zheng Liu
2012-09-22  4:01 ` [PATCH 14/21 v5] mke2fs: add inline_data support in mke2fs Zheng Liu
2012-09-22  4:01 ` [PATCH 15/21 v5] tune2fs: add inline_data feature in tune2fs Zheng Liu
2012-09-22  4:01 ` [PATCH 16/21 v5] e2fsck: add problem descriptions and check inline data feature Zheng Liu
2012-10-14 13:22   ` Theodore Ts'o
2012-10-14 23:34     ` Zheng Liu
2012-09-22  4:01 ` [PATCH 17/21 v5] e2fsck: check inline_data in pass1 Zheng Liu
2012-09-22  4:01 ` [PATCH 18/21 v5] e2fsck: check inline_data in pass2 Zheng Liu
2012-09-22  4:01 ` [PATCH 19/21 v5] e2fsck: check inline_data in pass3 Zheng Liu
2012-09-22  4:01 ` [PATCH 20/21 v5] tests: change result in f_bad_disconnected_inode Zheng Liu
2012-09-22  4:01 ` [PATCH 21/21 v5] mke2fs: enable inline_data feature on ext4dev filesystem Zheng Liu

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