linux-ext4.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v1 00/22] e2fsprogs: inline data refinement patch set
@ 2013-08-02  9:49 Zheng Liu
  2013-08-02  9:49 ` [PATCH v1 01/22] libext2fs: add INLINE_DATA into EXT2_LIB_SOFTSUPP_INCOMPAT Zheng Liu
                   ` (21 more replies)
  0 siblings, 22 replies; 67+ messages in thread
From: Zheng Liu @ 2013-08-02  9:49 UTC (permalink / raw)
  To: linux-ext4; +Cc: Zheng Liu, Theodore Ts'o

Hi all,

== Intro ==
Here's my first to refine the inline data patch set for e2fsprogs.  This
patch set has slept on my own tree for a very long time.  Sorry for my
late.

As Ted suggested, I revise the interface of libext2fs.  Now the following
interfaces are exported in libext2fs.  In ext_attr.c file three new
functions are added:
 * ext2fs_ext_attr_ibody_find()
   This function tries to find an EA entry in an inode.  It just gets the
   start entry and end entry, and calls ext2fs_ext_attr_find_entry() to
   find that entry that we want to search.

 * ext2fs_ext_attr_find_entry()
   This function traverses the entries to find an entry.

 * ext2fs_ext_attr_set_entry()
   This function tries to set an entry in an inode.

In inline_data.c file there are some functions that need to be exported:
 * ext2fs_inode_has_inline_data()
   This function determine whether EXT4_INLINE_DATA_FL flag is set or not.

 * ext2fs_inline_data_get_size()
   It returns the size of inline data.

 * ext2fs_inline_data_iterate()
   It is used to traverse the directory entries of a directory with
   inline data.

 * ext2fs_inline_data_check()
   This function is used by e2fsck to make sure that the inline data is
   valid.

 * ext2fs_inline_data_create()
   It tries to create inline data in an inode.

 * ext2fs_read_inline_data()
   Read inline data from an inode and copy them to buffer.

 * ext2fs_write_inline_data()
   Write the data to an inode.

 * ext2fs_try_to_write_inline_data()
   Try to write the data to an inode if the size of data is smaller
   than the size of inline data.  Otherwise, it returns
   EXT2_ET_INLINE_DATA_NO_SPACE.

== Changelog ==
v1:
 * Revise the interfaces of liext2fs.

 * Implement ext2fs_punch_inline_data in lib/ext2fs/punch.c.  Now if you
   want to truncate an inode with inline data, you need to call
   ext2fs_punch(), and it will handle inline data.

 * Remove ext2fs_inline_data_dirsearch() function.  Now we don't support
   dirsearch command for an inode with inline data in debugfs.

 * Ext2fs_mkdir() refinement.  Now if we want to create a directory with
   inline data, we just need to call ext2fs_mkdir().  This function will
   try to create a new directory with inline data if inline_data feature
   is enabled.

 * Fix big-endian bug in some functions.  When ext2fs_read_inode() tries
   to read an inode into memory, it will handle big-endian by itself.
   Thus, we don't need to handle it manually.

 * Fix a bug in e2fsck/pass3.  When we try to expand a 'lost+found' dir,
   we don't need to handle inline data because this dir shouldn't have
   this flag.

== TODO ==
 * Rebase against the latest e2fsprogs/master branch.

Here is the original Ted's git repo which tracks all original patches
[1].  I fork this repo in github.com and here is the url [2].  These
patches are against *e2fsprogs/pu* branch.

1. https://github.com/tytso/e2fsprogs-inline-patch-queue
2. https://github.com/gnehzuil/e2fsprogs-inline-patch-queue

Comments and feedbacks are all welcome.

Thanks,
						- Zheng

Zheng Liu (22):
  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 on extended attribute
  libext2fs: handle inline data in dir iterator function
  libext2fs: handle inline_data in block iterator function
  debugfs: make stat command support inline data
  debugfs: make mkdir and expanddir command support inline data
  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
  libext2fs: add a unit test for inline data

 debugfs/debugfs.c                       |   11 +
 debugfs/htree.c                         |    4 +
 debugfs/lsdel.c                         |    3 +-
 e2fsck/pass1.c                          |  103 +++-
 e2fsck/pass2.c                          |  123 +++-
 e2fsck/pass3.c                          |   12 +
 e2fsck/problem.c                        |   15 +
 e2fsck/problem.h                        |    9 +
 e2fsck/rehash.c                         |    3 +-
 lib/ext2fs/Makefile.in                  |   16 +-
 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                |  102 +++-
 lib/ext2fs/expanddir.c                  |   18 +-
 lib/ext2fs/ext2_err.et.in               |   12 +
 lib/ext2fs/ext2_ext_attr.h              |   31 +
 lib/ext2fs/ext2_fs.h                    |    8 +
 lib/ext2fs/ext2fs.h                     |   42 +-
 lib/ext2fs/ext2fsP.h                    |   27 +
 lib/ext2fs/ext_attr.c                   |  186 ++++++
 lib/ext2fs/fileio.c                     |   19 +-
 lib/ext2fs/inline_data.c                |  966 +++++++++++++++++++++++++++++++
 lib/ext2fs/mkdir.c                      |  102 +++-
 lib/ext2fs/newdir.c                     |   33 ++
 lib/ext2fs/punch.c                      |   59 +-
 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 +
 33 files changed, 1908 insertions(+), 79 deletions(-)
 create mode 100644 lib/ext2fs/inline_data.c

-- 
1.7.9.7


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

* [PATCH v1 01/22] libext2fs: add INLINE_DATA into EXT2_LIB_SOFTSUPP_INCOMPAT
  2013-08-02  9:49 [PATCH v1 00/22] e2fsprogs: inline data refinement patch set Zheng Liu
@ 2013-08-02  9:49 ` Zheng Liu
  2013-10-13  3:21   ` Theodore Ts'o
  2013-08-02  9:49 ` [PATCH v1 02/22] libext2fs: add function to check inline_data flag for an inode Zheng Liu
                   ` (20 subsequent siblings)
  21 siblings, 1 reply; 67+ messages in thread
From: Zheng Liu @ 2013-08-02  9:49 UTC (permalink / raw)
  To: linux-ext4; +Cc: Theodore Ts'o, 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: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 lib/ext2fs/ext2fs.h |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 6923f34..100270c 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -604,7 +604,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.9.7


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

* [PATCH v1 02/22] libext2fs: add function to check inline_data flag for an inode
  2013-08-02  9:49 [PATCH v1 00/22] e2fsprogs: inline data refinement patch set Zheng Liu
  2013-08-02  9:49 ` [PATCH v1 01/22] libext2fs: add INLINE_DATA into EXT2_LIB_SOFTSUPP_INCOMPAT Zheng Liu
@ 2013-08-02  9:49 ` Zheng Liu
  2013-08-02  9:49 ` [PATCH v1 03/22] libext2fs: add functions to operate on extended attribute Zheng Liu
                   ` (19 subsequent siblings)
  21 siblings, 0 replies; 67+ messages in thread
From: Zheng Liu @ 2013-08-02  9:49 UTC (permalink / raw)
  To: linux-ext4; +Cc: Theodore Ts'o, 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: Theodore Ts'o <tytso@mit.edu>
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 |   31 +++++++++++++++++++++++++++++++
 4 files changed, 43 insertions(+)
 create mode 100644 lib/ext2fs/inline_data.c

diff --git a/lib/ext2fs/Makefile.in b/lib/ext2fs/Makefile.in
index dc7b0d1..001c222 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 \
@@ -133,6 +134,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 \
@@ -757,6 +759,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 100270c..3346c00 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -1333,6 +1333,9 @@ errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *);
 extern errcode_t ext2fs_get_memalign(unsigned long size,
 				     unsigned long align, void *ptr);
 
+/* inline_data.c */
+extern int ext2fs_inode_has_inline_data(ext2_filsys fs, ext2_ino_t ino);
+
 /* inode.c */
 extern void ext2fs_free_inode_cache(struct ext2_inode_cache *icache);
 extern errcode_t ext2fs_flush_icache(ext2_filsys fs);
diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c
new file mode 100644
index 0000000..fcf82b5
--- /dev/null
+++ b/lib/ext2fs/inline_data.c
@@ -0,0 +1,31 @@
+/*
+ * 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 <time.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.9.7


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

* [PATCH v1 03/22] libext2fs: add functions to operate on extended attribute
  2013-08-02  9:49 [PATCH v1 00/22] e2fsprogs: inline data refinement patch set Zheng Liu
  2013-08-02  9:49 ` [PATCH v1 01/22] libext2fs: add INLINE_DATA into EXT2_LIB_SOFTSUPP_INCOMPAT Zheng Liu
  2013-08-02  9:49 ` [PATCH v1 02/22] libext2fs: add function to check inline_data flag for an inode Zheng Liu
@ 2013-08-02  9:49 ` Zheng Liu
  2013-08-05 17:34   ` Darrick J. Wong
  2013-10-11 22:51   ` Darrick J. Wong
  2013-08-02  9:49 ` [PATCH v1 04/22] libext2fs: handle inline data in dir iterator function Zheng Liu
                   ` (18 subsequent siblings)
  21 siblings, 2 replies; 67+ messages in thread
From: Zheng Liu @ 2013-08-02  9:49 UTC (permalink / raw)
  To: linux-ext4; +Cc: Zheng Liu, Theodore Ts'o

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

We need to define some functions to operate extended attribute in order
to support inline data.

Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
---
 lib/ext2fs/ext2_err.et.in  |    3 +
 lib/ext2fs/ext2_ext_attr.h |   31 ++++++++
 lib/ext2fs/ext2fs.h        |    9 +++
 lib/ext2fs/ext_attr.c      |  186 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 229 insertions(+)

diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in
index d20c6b7..7e6d6e5 100644
--- a/lib/ext2fs/ext2_err.et.in
+++ b/lib/ext2fs/ext2_err.et.in
@@ -476,4 +476,7 @@ ec	EXT2_ET_MMP_CSUM_INVALID,
 ec	EXT2_ET_FILE_EXISTS,
 	"Ext2 file already exists"
 
+ec	EXT2_ET_EXT_ATTR_CURRUPTED,
+	"Extended attribute currupted"
+
 	end
diff --git a/lib/ext2fs/ext2_ext_attr.h b/lib/ext2fs/ext2_ext_attr.h
index bbb0aaa..99ad849 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,29 @@ 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 *) \
+		((char *)inode + \
+		EXT2_GOOD_OLD_INODE_SIZE + \
+		inode->i_extra_isize))
+#define IFIRST(hdr) ((struct ext2_ext_attr_entry *)((hdr)+1))
+#define EXT2_ZERO_EXT_ATTR_VALUE ((void *)-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 3346c00..8c30197 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -1136,6 +1136,15 @@ 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_ext_attr_ibody_find(ext2_filsys fs,
+					    struct ext2_inode_large *inode,
+					    struct ext2_ext_attr_info *i,
+					    struct ext2_ext_attr_search *s);
+extern errcode_t ext2fs_ext_attr_find_entry(struct ext2_ext_attr_entry **pentry,
+					    int name_index, const char *name,
+					    size_t size, int sorted);
+extern errcode_t ext2fs_ext_attr_set_entry(struct ext2_ext_attr_info *i,
+					   struct ext2_ext_attr_search *s);
 
 /* 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..6d55340 100644
--- a/lib/ext2fs/ext_attr.c
+++ b/lib/ext2fs/ext_attr.c
@@ -186,3 +186,189 @@ errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
 	return ext2fs_adjust_ea_refcount2(fs, blk, block_buf, adjust,
 					  newcount);
 }
+
+static errcode_t
+ext2fs_ext_attr_check_names(struct ext2_ext_attr_entry *entry, void *end)
+{
+	while (!EXT2_EXT_IS_LAST_ENTRY(entry)) {
+		struct ext2_ext_attr_entry *next = EXT2_EXT_ATTR_NEXT(entry);
+		if ((void *)next >= end)
+			return EXT2_ET_EXT_ATTR_CURRUPTED;
+		entry = next;
+	}
+	return 0;
+}
+
+static inline errcode_t
+ext2fs_ext_attr_check_entry(struct ext2_ext_attr_entry *entry, size_t size)
+{
+	size_t value_size = entry->e_value_size;
+
+	if (entry->e_value_block != 0 || value_size > size ||
+	    entry->e_value_offs + value_size > size)
+		return EXT2_ET_EXT_ATTR_CURRUPTED;
+	return 0;
+}
+
+errcode_t ext2fs_ext_attr_find_entry(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 = 1;
+
+	if (name == NULL)
+		return EXT2_ET_INVALID_ARGUMENT;
+	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 <= 0 && (sorted || cmp == 0))
+			break;
+	}
+	*pentry = entry;
+	if (!cmp && ext2fs_ext_attr_check_entry(entry, size))
+		return EXT2_ET_EXT_ATTR_CURRUPTED;
+	return cmp ? ENODATA : 0;
+}
+
+errcode_t ext2fs_ext_attr_ibody_find(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;
+	errcode_t error;
+
+	if (inode->i_extra_isize == 0)
+		return 0;
+	header = IHDR(inode);
+	s->base = s->first = IFIRST(header);
+	s->here = s->first;
+	s->end = (char *)inode + EXT2_INODE_SIZE(fs->super);
+
+	error = ext2fs_ext_attr_check_names(IFIRST(header), s->end);
+	if (error)
+		return error;
+	/* Find the named attribute. */
+	error = ext2fs_ext_attr_find_entry(&s->here, i->name_index,
+					   i->name, (char *)s->end -
+					   (char *)s->base, 0);
+	if (error && error != ENODATA)
+		return error;
+	s->not_found = error;
+	return 0;
+}
+
+errcode_t ext2fs_ext_attr_set_entry(struct ext2_ext_attr_info *i,
+				    struct ext2_ext_attr_search *s)
+{
+	struct ext2_ext_attr_entry *last;
+	size_t freesize, min_offs = (char *)s->end - (char *)s->base;
+	size_t name_len = strlen(i->name);
+
+	/* Compute min_offs and last. */
+	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 = last->e_value_offs;
+			if (offs < min_offs)
+				min_offs = offs;
+		}
+	}
+	freesize = min_offs - ((char *)last - (char *)s->base) - sizeof(__u32);
+	if (!s->not_found) {
+		if (!s->here->e_value_block && s->here->e_value_size) {
+			size_t size = s->here->e_value_size;
+			freesize += EXT2_EXT_ATTR_SIZE(size);
+		}
+		freesize += EXT2_EXT_ATTR_LEN(name_len);
+	}
+	if (i->value) {
+		if (freesize < EXT2_EXT_ATTR_SIZE(i->value_len) ||
+		    freesize < EXT2_EXT_ATTR_LEN(name_len) +
+			   EXT2_EXT_ATTR_SIZE(i->value_len))
+			return ENOSPC;
+	}
+
+	if (i->value && s->not_found) {
+		/* Insert the new name. */
+		size_t size = EXT2_EXT_ATTR_LEN(name_len);
+		size_t rest = (char *)last - (char *)s->here + sizeof(__u32);
+		memmove((char *)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), i->name, name_len);
+	} else {
+		if (!s->here->e_value_block && s->here->e_value_size) {
+			char *first_val = (char *) s->base + min_offs;
+			size_t offs = s->here->e_value_offs;
+			char *val = (char *)s->base + offs;
+			size_t size = EXT2_EXT_ATTR_SIZE(s->here->e_value_size);
+
+			if (i->value && size == EXT2_EXT_ATTR_SIZE(i->value_len)) {
+				/* The old and the new value have the same
+				 * size. Just replace. */
+				s->here->e_value_size = i->value_len;
+				if (i->value == EXT2_ZERO_EXT_ATTR_VALUE) {
+					memset(val, 0, size);
+				} else {
+					memset(val + size - EXT2_EXT_ATTR_PAD, 0,
+						EXT2_EXT_ATTR_PAD);
+					memcpy(val, i->value, i->value_len);
+				}
+				return 0;
+			}
+
+			/* Remove the old value. */
+			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;
+
+			/* Adjust all value offsets. */
+			last = s->first;
+			while (!EXT2_EXT_IS_LAST_ENTRY(last)) {
+				size_t o = last->e_value_offs;
+				if (!last->e_value_block &&
+				    last->e_value_size && o < offs)
+					last->e_value_offs = o + size;
+				last = EXT2_EXT_ATTR_NEXT(last);
+			}
+		}
+		if (!i->value) {
+			/* Remove the old name. */
+			size_t size = EXT2_EXT_ATTR_LEN(name_len);
+			last = (struct ext2_ext_attr_entry *)last - size;
+			memmove(s->here, (char *)s->here + size,
+				(char *)last - (char *)s->here + sizeof(__u32));
+			memset(last, 0, size);
+		}
+	}
+
+	if (i->value) {
+		/* Insert the new value. */
+		s->here->e_value_size = i->value_len;
+		if (i->value_len) {
+			size_t size = EXT2_EXT_ATTR_SIZE(i->value_len);
+			char *val = (char *)s->base + min_offs - size;
+			s->here->e_value_offs = min_offs - size;
+			if (i->value == EXT2_ZERO_EXT_ATTR_VALUE) {
+				memset(val, 0, size);
+			} else {
+				memset(val + size - EXT2_EXT_ATTR_PAD, 0,
+					EXT2_EXT_ATTR_PAD);
+				memcpy(val, i->value, i->value_len);
+			}
+		}
+	}
+	return 0;
+}
-- 
1.7.9.7


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

* [PATCH v1 04/22] libext2fs: handle inline data in dir iterator function
  2013-08-02  9:49 [PATCH v1 00/22] e2fsprogs: inline data refinement patch set Zheng Liu
                   ` (2 preceding siblings ...)
  2013-08-02  9:49 ` [PATCH v1 03/22] libext2fs: add functions to operate on extended attribute Zheng Liu
@ 2013-08-02  9:49 ` Zheng Liu
  2013-10-11 23:33   ` Darrick J. Wong
                     ` (2 more replies)
  2013-08-02  9:49 ` [PATCH v1 05/22] libext2fs: handle inline_data in block " Zheng Liu
                   ` (17 subsequent siblings)
  21 siblings, 3 replies; 67+ messages in thread
From: Zheng Liu @ 2013-08-02  9:49 UTC (permalink / raw)
  To: linux-ext4; +Cc: Theodore Ts'o, 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 in 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 extended attribute.

After applied this commit, the following commands in debugfs can
support the inline_data feature:
	- ncheck
	- chroot
	- cd
	- ls
	- pwd
	- link*
	- unlink

* If inline_data doesn't expand to ibody extended 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: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 lib/ext2fs/dir_iterate.c  |  102 ++++++++++++++++++++++++++++++++++-
 lib/ext2fs/ext2_err.et.in |    6 +++
 lib/ext2fs/ext2_fs.h      |    8 +++
 lib/ext2fs/ext2fs.h       |   11 ++++
 lib/ext2fs/ext2fsP.h      |   11 ++++
 lib/ext2fs/inline_data.c  |  132 +++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 268 insertions(+), 2 deletions(-)

diff --git a/lib/ext2fs/dir_iterate.c b/lib/ext2fs/dir_iterate.c
index 1a4bf5c..7d5b1da 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)
@@ -282,3 +288,95 @@ next:
 	return 0;
 }
 
+int ext2fs_process_dir_inline_data(ext2_filsys	fs,
+				   char		*buf,
+				   unsigned 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) {
+			if (ext2fs_get_rec_len(fs, dirent, &rec_len))
+				return BLOCK_ABORT;
+			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 7e6d6e5..8a19cab 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"
 
@@ -479,4 +482,7 @@ ec	EXT2_ET_FILE_EXISTS,
 ec	EXT2_ET_EXT_ATTR_CURRUPTED,
 	"Extended attribute currupted"
 
+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 0c0bbcb..d49b95c 100644
--- a/lib/ext2fs/ext2_fs.h
+++ b/lib/ext2fs/ext2_fs.h
@@ -906,4 +906,12 @@ 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))
+#define EXT4_INLINE_DATA_DOTDOT_SIZE	(4)
+
 #endif	/* _LINUX_EXT2_FS_H */
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 8c30197..7b05b48 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -1344,6 +1344,17 @@ extern errcode_t ext2fs_get_memalign(unsigned long size,
 
 /* inline_data.c */
 extern int ext2fs_inode_has_inline_data(ext2_filsys fs, ext2_ino_t ino);
+extern errcode_t ext2fs_inline_data_iterate(ext2_filsys fs,
+				      ext2_ino_t ino,
+				      int flags,
+				      char *block_buf,
+				      int (*func)(ext2_filsys fs,
+						  char *buf,
+						  unsigned int buf_len,
+						  e2_blkcnt_t blockcnt,
+						  struct ext2_inode_large *inode,
+						  void *priv_data),
+				      void *priv_data);
 
 /* inode.c */
 extern void ext2fs_free_inode_cache(struct ext2_inode_cache *icache);
diff --git a/lib/ext2fs/ext2fsP.h b/lib/ext2fs/ext2fsP.h
index 3de9278..e86d452 100644
--- a/lib/ext2fs/ext2fsP.h
+++ b/lib/ext2fs/ext2fsP.h
@@ -87,6 +87,17 @@ 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,
+					  char		*buf,
+					  unsigned int	buf_len,
+					  e2_blkcnt_t	blockcnt,
+					  struct ext2_inode_large *inode,
+					  void		*priv_data);
+
+extern errcode_t ext2fs_inline_data_find(ext2_filsys fs,
+					 struct ext2_inode_large *inode,
+					 struct inline_data *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 fcf82b5..922c959 100644
--- a/lib/ext2fs/inline_data.c
+++ b/lib/ext2fs/inline_data.c
@@ -14,10 +14,60 @@
 #include <time.h>
 
 #include "ext2_fs.h"
+#include "ext2_ext_attr.h"
 
 #include "ext2fs.h"
 #include "ext2fsP.h"
 
+static void *ext2fs_get_inline_xattr_pos(struct ext2_inode_large *inode,
+					 struct inline_data *data);
+
+errcode_t ext2fs_inline_data_find(ext2_filsys fs,
+				  struct ext2_inode_large *inode,
+				  struct inline_data *data)
+{
+	errcode_t retval;
+
+	struct ext2_ext_attr_search s = {
+		.not_found = ENODATA,
+	};
+	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;
+
+	retval = ext2fs_ext_attr_ibody_find(fs, inode, &i, &s);
+	if (retval)
+		return retval;
+
+	if (!s.not_found) {
+		data->inline_off = (__u16)((char *)s.here - (char *)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 *)
+			((char *)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;
@@ -29,3 +79,85 @@ int ext2fs_inode_has_inline_data(ext2_filsys fs, ext2_ino_t ino)
 
 	return (inode.i_flags & EXT4_INLINE_DATA_FL);
 }
+
+errcode_t ext2fs_inline_data_iterate(ext2_filsys fs,
+			       ext2_ino_t ino,
+			       int flags,
+			       char *block_buf,
+			       int (*func)(ext2_filsys fs,
+					   char *buf,
+					   unsigned 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 = (char *)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_inline_data_find(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.9.7


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

* [PATCH v1 05/22] libext2fs: handle inline_data in block iterator function
  2013-08-02  9:49 [PATCH v1 00/22] e2fsprogs: inline data refinement patch set Zheng Liu
                   ` (3 preceding siblings ...)
  2013-08-02  9:49 ` [PATCH v1 04/22] libext2fs: handle inline data in dir iterator function Zheng Liu
@ 2013-08-02  9:49 ` Zheng Liu
  2013-10-13  3:55   ` Theodore Ts'o
  2013-08-02  9:49 ` [PATCH v1 06/22] debugfs: make stat command support inline data Zheng Liu
                   ` (16 subsequent siblings)
  21 siblings, 1 reply; 67+ messages in thread
From: Zheng Liu @ 2013-08-02  9:49 UTC (permalink / raw)
  To: linux-ext4; +Cc: Theodore Ts'o, 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 applied 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: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 lib/ext2fs/block.c |    7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/lib/ext2fs/block.c b/lib/ext2fs/block.c
index b8c6879..b194ca8 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.9.7


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

* [PATCH v1 06/22] debugfs: make stat command support inline data
  2013-08-02  9:49 [PATCH v1 00/22] e2fsprogs: inline data refinement patch set Zheng Liu
                   ` (4 preceding siblings ...)
  2013-08-02  9:49 ` [PATCH v1 05/22] libext2fs: handle inline_data in block " Zheng Liu
@ 2013-08-02  9:49 ` Zheng Liu
  2013-10-11 23:43   ` Darrick J. Wong
  2013-08-02  9:49 ` [PATCH v1 07/22] debugfs: make mkdir and expanddir " Zheng Liu
                   ` (15 subsequent siblings)
  21 siblings, 1 reply; 67+ messages in thread
From: Zheng Liu @ 2013-08-02  9:49 UTC (permalink / raw)
  To: linux-ext4; +Cc: Theodore Ts'o, Zheng Liu

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

If there is an inode with inline data, we just print the size of inline
data in stat command.

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 debugfs/debugfs.c        |   11 +++++++++++
 lib/ext2fs/ext2fs.h      |    1 +
 lib/ext2fs/inline_data.c |   27 +++++++++++++++++++++++++++
 3 files changed, 39 insertions(+)

diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c
index 969dbe0..2837ee6 100644
--- a/debugfs/debugfs.c
+++ b/debugfs/debugfs.c
@@ -704,6 +704,15 @@ static void dump_extents(FILE *f, const char *prefix, ext2_ino_t ino,
 		fprintf(f, "\n");
 }
 
+static 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_inline_data_get_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)
@@ -837,6 +846,8 @@ void internal_dump_inode(FILE *out, const char *prefix,
 		if (inode->i_flags & EXT4_EXTENTS_FL)
 			dump_extents(out, prefix, inode_num,
 				     DUMP_LEAF_EXTENTS|DUMP_NODE_EXTENTS, 0, 0);
+		else if (inode->i_flags & EXT4_INLINE_DATA_FL)
+			dump_inline_data(out, prefix, inode_num);
 		else
 			dump_blocks(out, prefix, inode_num);
 	}
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 7b05b48..6e3bf6e 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -1344,6 +1344,7 @@ extern errcode_t ext2fs_get_memalign(unsigned long size,
 
 /* inline_data.c */
 extern int ext2fs_inode_has_inline_data(ext2_filsys fs, ext2_ino_t ino);
+extern int ext2fs_inline_data_get_size(ext2_filsys fs, ext2_ino_t ino);
 extern errcode_t 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 922c959..1220418 100644
--- a/lib/ext2fs/inline_data.c
+++ b/lib/ext2fs/inline_data.c
@@ -80,6 +80,33 @@ 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_get_size(ext2_filsys fs, ext2_ino_t ino)
+{
+	struct ext2_inode_large *inode;
+	struct inline_data data;
+	errcode_t retval = 0;
+	int size = 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;
+
+	if (inode->i_flags & EXT4_INLINE_DATA_FL) {
+		retval = ext2fs_inline_data_find(fs, inode, &data);
+		if (retval)
+			goto out;
+		size = data.inline_size;
+	}
+
+out:
+	ext2fs_free_mem(&inode);
+	return size;
+}
+
 errcode_t ext2fs_inline_data_iterate(ext2_filsys fs,
 			       ext2_ino_t ino,
 			       int flags,
-- 
1.7.9.7


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

* [PATCH v1 07/22] debugfs: make mkdir and expanddir command support inline data
  2013-08-02  9:49 [PATCH v1 00/22] e2fsprogs: inline data refinement patch set Zheng Liu
                   ` (5 preceding siblings ...)
  2013-08-02  9:49 ` [PATCH v1 06/22] debugfs: make stat command support inline data Zheng Liu
@ 2013-08-02  9:49 ` Zheng Liu
  2013-10-12  0:21   ` Darrick J. Wong
  2013-08-02  9:49 ` [PATCH v1 08/22] debugfs: make lsdel " Zheng Liu
                   ` (14 subsequent siblings)
  21 siblings, 1 reply; 67+ messages in thread
From: Zheng Liu @ 2013-08-02  9:49 UTC (permalink / raw)
  To: linux-ext4; +Cc: Theodore Ts'o, Zheng Liu

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

This commit tries to make mkdir and expanddir command support inline
date feature.

In ext2fs_expand_dir() function ext2fs_inline_data_convert() will be
called to expand a directory with inline data.  It tries to allocate
a block and copy all directory entries into it.

In ext2fs_mkdir() it calls ext2fs_new_dir_inline_data() function to
create a new directory with inline data.

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 lib/ext2fs/expanddir.c   |   18 +--
 lib/ext2fs/ext2fs.h      |    5 +
 lib/ext2fs/ext2fsP.h     |   13 +++
 lib/ext2fs/inline_data.c |  280 ++++++++++++++++++++++++++++++++++++++++++++++
 lib/ext2fs/mkdir.c       |  102 +++++++++++++----
 lib/ext2fs/newdir.c      |   33 ++++++
 6 files changed, 420 insertions(+), 31 deletions(-)

diff --git a/lib/ext2fs/expanddir.c b/lib/ext2fs/expanddir.c
index 22558d6..9696b61 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_inline_data_convert(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 6e3bf6e..934dbd0 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -1356,6 +1356,9 @@ extern errcode_t ext2fs_inline_data_iterate(ext2_filsys fs,
 						  struct ext2_inode_large *inode,
 						  void *priv_data),
 				      void *priv_data);
+extern errcode_t ext2fs_inline_data_create(ext2_filsys fs,
+					   struct ext2_inode_large *inode,
+					   unsigned int len);
 
 /* inode.c */
 extern void ext2fs_free_inode_cache(struct ext2_inode_cache *icache);
@@ -1430,6 +1433,8 @@ int ext2fs_native_flag(void);
 /* newdir.c */
 extern errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
 				ext2_ino_t parent_ino, char **block);
+extern errcode_t ext2fs_new_dir_inline_data(ext2_filsys fs, ext2_ino_t dir_ino,
+				ext2_ino_t parent_ino, struct ext2_inode *inode);
 
 /* mkdir.c */
 extern errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
diff --git a/lib/ext2fs/ext2fsP.h b/lib/ext2fs/ext2fsP.h
index e86d452..ed89272 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 {
@@ -97,6 +108,8 @@ extern int ext2fs_process_dir_inline_data(ext2_filsys	fs,
 extern errcode_t ext2fs_inline_data_find(ext2_filsys fs,
 					 struct ext2_inode_large *inode,
 					 struct inline_data *data);
+extern errcode_t ext2fs_inline_data_convert(ext2_filsys fs, ext2_ino_t ino,
+					    void *priv_data);
 
 /* Generic numeric progress meter */
 
diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c
index 1220418..c936e28 100644
--- a/lib/ext2fs/inline_data.c
+++ b/lib/ext2fs/inline_data.c
@@ -21,6 +21,14 @@
 
 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, char *buf,
+					      int inline_size);
+static void ext2fs_update_final_de(ext2_filsys fs, char *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);
 
 errcode_t ext2fs_inline_data_find(ext2_filsys fs,
 				  struct ext2_inode_large *inode,
@@ -68,6 +76,48 @@ 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 = ENODATA,
+	};
+	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;
+
+	retval = ext2fs_ext_attr_ibody_find(fs, inode, &i, &s);
+	if (retval)
+		return retval;
+
+	if (!s.not_found) {
+		retval = ext2fs_ext_attr_set_entry(&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;
@@ -107,6 +157,83 @@ out:
 	return size;
 }
 
+static void ext2fs_update_final_de(ext2_filsys fs, char *de_buf,
+				   int old_size, int new_size)
+{
+	struct ext2_dir_entry *de, *prev_de;
+	char *limit;
+	unsigned 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, char *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 = (char *)de - (char *)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);
+	}
+}
+
 errcode_t ext2fs_inline_data_iterate(ext2_filsys fs,
 			       ext2_ino_t ino,
 			       int flags,
@@ -188,3 +315,156 @@ out:
 	ext2fs_free_mem(&inode);
 	return retval & BLOCK_ERROR ? ctx->errcode : 0;
 }
+
+errcode_t ext2fs_inline_data_convert(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;
+	char *backup_buf;
+	char *blk_buf;
+	unsigned int inline_size;
+
+	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_inline_data_find(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;
+}
+
+errcode_t ext2fs_inline_data_create(ext2_filsys fs,
+				    struct ext2_inode_large *inode,
+				    unsigned int len)
+{
+	struct ext2_ext_attr_ibody_header *header;
+	struct ext2_ext_attr_search s = {
+		.not_found = ENODATA,
+	};
+	struct ext2_ext_attr_info i = {
+		.name_index = EXT4_EXT_ATTR_INDEX_SYSTEM,
+		.name = EXT4_EXT_ATTR_SYSTEM_DATA,
+	};
+	void *buf;
+	errcode_t retval;
+
+	if (len > EXT4_MIN_INLINE_DATA_SIZE) {
+		i.value = EXT2_ZERO_EXT_ATTR_VALUE;
+		i.value_len = len - EXT4_MIN_INLINE_DATA_SIZE;
+	} else {
+		i.value = "";
+		i.value_len = 0;
+	}
+
+	retval = ext2fs_ext_attr_ibody_find(fs, inode, &i, &s);
+	if (retval)
+		return retval;
+	retval = ext2fs_ext_attr_set_entry(&i, &s);
+	if (retval)
+		return retval;
+
+	header = IHDR(inode);
+	if (!EXT2_EXT_IS_LAST_ENTRY(s.first))
+		header->h_magic = EXT2_EXT_ATTR_MAGIC;
+	else
+		header->h_magic = 0;
+
+	return 0;
+}
diff --git a/lib/ext2fs/mkdir.c b/lib/ext2fs/mkdir.c
index 4a85439..a6aeb0d 100644
--- a/lib/ext2fs/mkdir.c
+++ b/lib/ext2fs/mkdir.c
@@ -36,11 +36,13 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
 {
 	ext2_extent_handle_t	handle;
 	errcode_t		retval;
-	struct ext2_inode	parent_inode, inode;
+	struct ext2_inode	parent_inode, *inode = NULL;
+	struct ext2_inode_large *large_inode = NULL;
 	ext2_ino_t		ino = 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);
 
@@ -55,16 +57,38 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
 	}
 
 	/*
+	 * We try to create a new directory with inline data if this feature
+	 * is enabled.  Here we don't try to do this if ino < first_ino or
+	 * the directory name is 'lost+found'.
+	 */
+	if (fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_INLINE_DATA &&
+	    ino >= EXT2_FIRST_INO(fs->super) && strcmp("lost+found", name) != 0)
+		inline_data = 1;
+
+	/*
 	 * Allocate a data block for the directory
 	 */
-	retval = ext2fs_new_block2(fs, 0, 0, &blk);
+	if (!inline_data) {
+		retval = ext2fs_new_block2(fs, 0, 0, &blk);
+		if (retval)
+			goto cleanup;
+	}
+
+	/*
+	 * Allocate a new inode structuure
+	 */
+	retval = ext2fs_get_memzero(EXT2_INODE_SIZE(fs->super), &large_inode);
 	if (retval)
 		goto cleanup;
+	inode = (struct ext2_inode *) large_inode;
 
 	/*
 	 * Create a scratch template for the directory
 	 */
-	retval = ext2fs_new_dir_block(fs, ino, parent, &block);
+	if (inline_data)
+		retval = ext2fs_new_dir_inline_data(fs, ino, parent, inode);
+	else
+		retval = ext2fs_new_dir_block(fs, ino, parent, &block);
 	if (retval)
 		goto cleanup;
 
@@ -81,37 +105,61 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
 	/*
 	 * Create the inode structure....
 	 */
-	memset(&inode, 0, sizeof(struct ext2_inode));
-	inode.i_mode = LINUX_S_IFDIR | (0777 & ~fs->umask);
-	inode.i_uid = inode.i_gid = 0;
-	ext2fs_iblk_set(fs, &inode, 1);
-	if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS)
-		inode.i_flags |= EXT4_EXTENTS_FL;
+	inode->i_mode = LINUX_S_IFDIR | (0777 & ~fs->umask);
+	inode->i_uid = inode->i_gid = 0;
+	ext2fs_iblk_set(fs, inode, 1);
+	if (inline_data)
+		inode->i_flags |= EXT4_INLINE_DATA_FL;
+	else if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS)
+		inode->i_flags |= EXT4_EXTENTS_FL;
 	else
-		inode.i_block[0] = blk;
-	inode.i_links_count = 2;
-	inode.i_size = fs->blocksize;
+		inode->i_block[0] = blk;
+	inode->i_links_count = 2;
 
 	/*
 	 * Write out the inode and inode data block.  The inode generation
 	 * number is assigned by write_new_inode, which means that the call
 	 * to write_dir_block must come after that.
+	 *
+	 * If we try to create an new inode with inline data, we should call
+	 * ext2fs_write_inode_full to avoid to initialize extra part.
 	 */
-	retval = ext2fs_write_new_inode(fs, ino, &inode);
-	if (retval)
-		goto cleanup;
-	retval = ext2fs_write_dir_block4(fs, blk, block, 0, ino);
-	if (retval)
-		goto cleanup;
+	if (inline_data) {
+		__u32 t = fs->now ? fs->now : time(NULL);
+
+		inode->i_size = EXT4_MIN_INLINE_DATA_SIZE;
+		inode->i_blocks = 0;
+		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 (!large_inode->i_crtime)
+			large_inode->i_crtime = t;
+		retval = ext2fs_write_inode_full(fs, ino, inode,
+						 EXT2_INODE_SIZE(fs->super));
+		if (retval)
+			goto cleanup;
+	} else {
+		inode->i_size = fs->blocksize;
 
-	if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) {
-		retval = ext2fs_extent_open2(fs, ino, &inode, &handle);
+		retval = ext2fs_write_new_inode(fs, ino, inode);
 		if (retval)
 			goto cleanup;
-		retval = ext2fs_extent_set_bmap(handle, 0, blk, 0);
-		ext2fs_extent_free(handle);
+		retval = ext2fs_write_dir_block4(fs, blk, block, 0, ino);
 		if (retval)
 			goto cleanup;
+
+		if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) {
+			retval = ext2fs_extent_open2(fs, ino, inode, &handle);
+			if (retval)
+				goto cleanup;
+			retval = ext2fs_extent_set_bmap(handle, 0, blk, 0);
+			ext2fs_extent_free(handle);
+			if (retval)
+				goto cleanup;
+		}
 	}
 
 	/*
@@ -136,6 +184,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,14 +197,16 @@ 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:
+	if (large_inode)
+		ext2fs_free_mem(&large_inode);
 	if (block)
 		ext2fs_free_mem(&block);
 	return retval;
-
 }
 
 
diff --git a/lib/ext2fs/newdir.c b/lib/ext2fs/newdir.c
index 2cd541d..cec99e9 100644
--- a/lib/ext2fs/newdir.c
+++ b/lib/ext2fs/newdir.c
@@ -87,3 +87,36 @@ errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
 	*block = buf;
 	return 0;
 }
+
+/*
+ * Create new directory in inode
+ */
+errcode_t ext2fs_new_dir_inline_data(ext2_filsys fs,
+				     ext2_ino_t dir_ino,
+				     ext2_ino_t parent_ino,
+				     struct ext2_inode *inode)
+{
+	struct ext2_inode_large *large_inode;
+	struct ext2_dir_entry *dir = NULL;
+	int inline_size = EXT4_MIN_INLINE_DATA_SIZE;
+	errcode_t retval;
+
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+	large_inode = (struct ext2_inode_large *) inode;
+	large_inode->i_extra_isize = sizeof(struct ext2_inode_large) -
+		EXT2_GOOD_OLD_INODE_SIZE;
+	retval = ext2fs_inline_data_create(fs, large_inode, inline_size);
+	if (retval)
+		return retval;
+
+	dir = (struct ext2_dir_entry *) inode->i_block;
+	dir->inode = parent_ino;
+
+	dir = (struct ext2_dir_entry *) ((char *) dir +
+					 EXT4_INLINE_DATA_DOTDOT_SIZE);
+	dir->inode = 0;
+	dir->rec_len = inline_size - EXT4_INLINE_DATA_DOTDOT_SIZE;
+
+	return retval;
+}
-- 
1.7.9.7


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

* [PATCH v1 08/22] debugfs: make lsdel command support inline data
  2013-08-02  9:49 [PATCH v1 00/22] e2fsprogs: inline data refinement patch set Zheng Liu
                   ` (6 preceding siblings ...)
  2013-08-02  9:49 ` [PATCH v1 07/22] debugfs: make mkdir and expanddir " Zheng Liu
@ 2013-08-02  9:49 ` Zheng Liu
  2013-08-02  9:49 ` [PATCH v1 09/22] libext2fs: handle inline data in read/write function Zheng Liu
                   ` (13 subsequent siblings)
  21 siblings, 0 replies; 67+ messages in thread
From: Zheng Liu @ 2013-08-02  9:49 UTC (permalink / raw)
  To: linux-ext4; +Cc: Theodore Ts'o, Zheng Liu

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

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 debugfs/lsdel.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

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


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

* [PATCH v1 09/22] libext2fs: handle inline data in read/write function
  2013-08-02  9:49 [PATCH v1 00/22] e2fsprogs: inline data refinement patch set Zheng Liu
                   ` (7 preceding siblings ...)
  2013-08-02  9:49 ` [PATCH v1 08/22] debugfs: make lsdel " Zheng Liu
@ 2013-08-02  9:49 ` Zheng Liu
  2013-08-02  9:49 ` [PATCH v1 10/22] debugfs: handle inline_data feature in dirsearch command Zheng Liu
                   ` (12 subsequent siblings)
  21 siblings, 0 replies; 67+ messages in thread
From: Zheng Liu @ 2013-08-02  9:49 UTC (permalink / raw)
  To: linux-ext4; +Cc: Theodore Ts'o, 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 inode, 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: Theodore Ts'o <tytso@mit.edu>
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  |  179 ++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 206 insertions(+), 2 deletions(-)

diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in
index 8a19cab..9252692 100644
--- a/lib/ext2fs/ext2_err.et.in
+++ b/lib/ext2fs/ext2_err.et.in
@@ -485,4 +485,7 @@ ec	EXT2_ET_EXT_ATTR_CURRUPTED,
 ec	EXT2_ET_BAD_EXTRA_SIZE,
 	"Bad inode extra isizevalue"
 
+ec	EXT2_ET_INLINE_DATA_NO_SPACE,
+	"No free space in inline data"
+
 	end
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 934dbd0..2804748 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -1359,6 +1359,13 @@ extern errcode_t ext2fs_inline_data_iterate(ext2_filsys fs,
 extern errcode_t ext2fs_inline_data_create(ext2_filsys fs,
 					   struct ext2_inode_large *inode,
 					   unsigned int len);
+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 void ext2fs_free_inode_cache(struct ext2_inode_cache *icache);
diff --git a/lib/ext2fs/fileio.c b/lib/ext2fs/fileio.c
index 1f7002c..89c8ea6 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 (!(file->inode.i_flags & EXT4_INLINE_DATA_FL))
+			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 c936e28..5ca95ee 100644
--- a/lib/ext2fs/inline_data.c
+++ b/lib/ext2fs/inline_data.c
@@ -21,6 +21,8 @@
 
 static void *ext2fs_get_inline_xattr_pos(struct ext2_inode_large *inode,
 					 struct inline_data *data);
+static unsigned 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, char *buf,
 					      int inline_size);
@@ -316,6 +318,74 @@ 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;
+	unsigned 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_inline_data_find(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;
+	unsigned 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_inline_data_find(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_inline_data_convert(ext2_filsys fs,
 				     ext2_ino_t  ino,
 				     void *priv_data)
@@ -430,6 +500,114 @@ out:
 	return retval;
 }
 
+static unsigned 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;
+	size_t freesize, 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 = entry->e_value_offs;
+			if (offs < min_offs)
+				min_offs = offs;
+		}
+	}
+	freesize = min_offs -
+		((char *)entry - (char *)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_inline_data_find(fs, inode, &data);
+	if (retval && retval != EXT2_ET_BAD_EXT_ATTR_MAGIC)
+		return 0;
+
+	if (data.inline_off) {
+		entry = (struct ext2_ext_attr_entry *)
+			((char *)inode + data.inline_off);
+		freesize += entry->e_value_size;
+		goto out;
+	}
+
+	freesize -= EXT2_EXT_ATTR_LEN(strlen(EXT4_EXT_ATTR_SYSTEM_DATA));
+
+	if (freesize > EXT2_EXT_ATTR_ROUND)
+		freesize = EXT2_EXT_ATTR_SIZE(freesize - EXT2_EXT_ATTR_ROUND);
+	else
+		freesize = 0;
+
+out:
+	return freesize + 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;
+	unsigned 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_inline_data_create(fs, inode, nbytes);
+	if (retval)
+		goto out;
+
+	retval = ext2fs_inline_data_find(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),
+		       (const char *) 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));
+
+	if (!retval)
+		*written = nbytes;
+	else
+		*written = 0;
+
+out:
+	ext2fs_free_mem(&inode);
+	return retval;
+}
+
 errcode_t ext2fs_inline_data_create(ext2_filsys fs,
 				    struct ext2_inode_large *inode,
 				    unsigned int len)
@@ -442,7 +620,6 @@ errcode_t ext2fs_inline_data_create(ext2_filsys fs,
 		.name_index = EXT4_EXT_ATTR_INDEX_SYSTEM,
 		.name = EXT4_EXT_ATTR_SYSTEM_DATA,
 	};
-	void *buf;
 	errcode_t retval;
 
 	if (len > EXT4_MIN_INLINE_DATA_SIZE) {
-- 
1.7.9.7


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

* [PATCH v1 10/22] debugfs: handle inline_data feature in dirsearch command
  2013-08-02  9:49 [PATCH v1 00/22] e2fsprogs: inline data refinement patch set Zheng Liu
                   ` (8 preceding siblings ...)
  2013-08-02  9:49 ` [PATCH v1 09/22] libext2fs: handle inline data in read/write function Zheng Liu
@ 2013-08-02  9:49 ` Zheng Liu
  2013-10-12  0:30   ` Darrick J. Wong
  2013-08-02  9:49 ` [PATCH v1 11/22] debugfs: handle inline_data feature in bmap command Zheng Liu
                   ` (11 subsequent siblings)
  21 siblings, 1 reply; 67+ messages in thread
From: Zheng Liu @ 2013-08-02  9:49 UTC (permalink / raw)
  To: linux-ext4; +Cc: Theodore Ts'o, Zheng Liu

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

We don't need to support inline data in dirsearch command.

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 debugfs/htree.c |    4 ++++
 1 file changed, 4 insertions(+)

diff --git a/debugfs/htree.c b/debugfs/htree.c
index d94dbea..b226f1d 100644
--- a/debugfs/htree.c
+++ b/debugfs/htree.c
@@ -387,9 +387,13 @@ 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))
+		goto out;
+
 	ext2fs_block_iterate3(current_fs, inode, BLOCK_FLAG_READ_ONLY, 0,
 			      search_dir_block, &pb);
 
+out:
 	free(pb.buf);
 }
 
-- 
1.7.9.7


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

* [PATCH v1 11/22] debugfs: handle inline_data feature in bmap command
  2013-08-02  9:49 [PATCH v1 00/22] e2fsprogs: inline data refinement patch set Zheng Liu
                   ` (9 preceding siblings ...)
  2013-08-02  9:49 ` [PATCH v1 10/22] debugfs: handle inline_data feature in dirsearch command Zheng Liu
@ 2013-08-02  9:49 ` Zheng Liu
  2013-08-02  9:49 ` [PATCH v1 12/22] debugfs: handle inline_data in punch command Zheng Liu
                   ` (10 subsequent siblings)
  21 siblings, 0 replies; 67+ messages in thread
From: Zheng Liu @ 2013-08-02  9:49 UTC (permalink / raw)
  To: linux-ext4; +Cc: Theodore Ts'o, 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: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 lib/ext2fs/bmap.c |   15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/lib/ext2fs/bmap.c b/lib/ext2fs/bmap.c
index aadd22e..408cd37 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, pblock, 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);
+		pblock = 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) + pblock;
+		goto done;
+	}
+
 	if (inode->i_flags & EXT4_EXTENTS_FL) {
 		retval = ext2fs_extent_open2(fs, ino, inode, &handle);
 		if (retval)
-- 
1.7.9.7


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

* [PATCH v1 12/22] debugfs: handle inline_data in punch command
  2013-08-02  9:49 [PATCH v1 00/22] e2fsprogs: inline data refinement patch set Zheng Liu
                   ` (10 preceding siblings ...)
  2013-08-02  9:49 ` [PATCH v1 11/22] debugfs: handle inline_data feature in bmap command Zheng Liu
@ 2013-08-02  9:49 ` Zheng Liu
  2013-10-12  0:37   ` Darrick J. Wong
  2013-08-02  9:49 ` [PATCH v1 13/22] libext2fs: add inline_data feature into EXT2_LIB_FEATURE_INCOMPAT_SUPP Zheng Liu
                   ` (9 subsequent siblings)
  21 siblings, 1 reply; 67+ messages in thread
From: Zheng Liu @ 2013-08-02  9:49 UTC (permalink / raw)
  To: linux-ext4; +Cc: Theodore Ts'o, Zheng Liu

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

Now punch command only can truncate an inode with inline_data.  The
start block must be 0 because the size of an inode shouldn't be greater
than one block.

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 lib/ext2fs/ext2fsP.h     |    3 +++
 lib/ext2fs/inline_data.c |    9 +++----
 lib/ext2fs/punch.c       |   59 ++++++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 63 insertions(+), 8 deletions(-)

diff --git a/lib/ext2fs/ext2fsP.h b/lib/ext2fs/ext2fsP.h
index ed89272..1e5aa32 100644
--- a/lib/ext2fs/ext2fsP.h
+++ b/lib/ext2fs/ext2fsP.h
@@ -110,6 +110,9 @@ extern errcode_t ext2fs_inline_data_find(ext2_filsys fs,
 					 struct inline_data *data);
 extern errcode_t ext2fs_inline_data_convert(ext2_filsys fs, ext2_ino_t ino,
 					    void *priv_data);
+extern errcode_t ext2fs_inline_data_destory_data(ext2_filsys fs, ext2_ino_t ino,
+					   struct ext2_inode_large *inode,
+					   struct inline_data *data);
 
 /* Generic numeric progress meter */
 
diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c
index 5ca95ee..52ac133 100644
--- a/lib/ext2fs/inline_data.c
+++ b/lib/ext2fs/inline_data.c
@@ -28,9 +28,6 @@ static void ext2fs_inline_data_finish_convert(ext2_filsys fs, ext2_ino_t ino,
 					      int inline_size);
 static void ext2fs_update_final_de(ext2_filsys fs, char *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);
 
 errcode_t ext2fs_inline_data_find(ext2_filsys fs,
 				  struct ext2_inode_large *inode,
@@ -78,9 +75,9 @@ 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)
+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 = {
diff --git a/lib/ext2fs/punch.c b/lib/ext2fs/punch.c
index b53653a..3bfbd4d 100644
--- a/lib/ext2fs/punch.c
+++ b/lib/ext2fs/punch.c
@@ -19,6 +19,7 @@
 
 #include "ext2_fs.h"
 #include "ext2fs.h"
+#include "ext2fsP.h"
 
 #undef PUNCH_DEBUG
 
@@ -281,7 +282,59 @@ errout:
 	ext2fs_extent_free(handle);
 	return retval;
 }
-	
+
+static 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;
+
+	/*
+	 * 'start' must be 0 because here it's a block and the size of
+	 * an inode shouldn't greater than a block.
+	 */
+	if (start != 0)
+		return 0;
+
+	/* Punching hole for inline_data is not supported */
+	if ((unsigned int)end != ~0U)
+		return EXT2_ET_OP_NOT_SUPPORTED;
+
+	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_inline_data_find(fs, inode, &data);
+	if (retval)
+		goto out;
+
+	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;
+	}
+
+	retval = ext2fs_inline_data_destory_data(fs, ino, inode, &data);
+	if (retval)
+		goto out;
+
+	inode->i_size = 0;
+	retval = ext2fs_write_inode_full(fs, ino, (void *)inode,
+					 EXT2_INODE_SIZE(fs->super));
+out:
+	ext2fs_free_mem(&inode);
+	return retval;
+}
+
 /*
  * Deallocate all logical blocks starting at start to end, inclusive.
  * If end is ~0, then this is effectively truncate.
@@ -307,7 +360,9 @@ 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)
+		return ext2fs_punch_inline_data(fs, ino, start, end);
+	else if (inode->i_flags & EXT4_EXTENTS_FL)
 		retval = ext2fs_punch_extent(fs, ino, inode, start, end);
 	else {
 		blk_t	count;
-- 
1.7.9.7


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

* [PATCH v1 13/22] libext2fs: add inline_data feature into EXT2_LIB_FEATURE_INCOMPAT_SUPP
  2013-08-02  9:49 [PATCH v1 00/22] e2fsprogs: inline data refinement patch set Zheng Liu
                   ` (11 preceding siblings ...)
  2013-08-02  9:49 ` [PATCH v1 12/22] debugfs: handle inline_data in punch command Zheng Liu
@ 2013-08-02  9:49 ` Zheng Liu
  2013-08-02  9:49 ` [PATCH v1 14/22] mke2fs: add inline_data support in mke2fs Zheng Liu
                   ` (8 subsequent siblings)
  21 siblings, 0 replies; 67+ messages in thread
From: Zheng Liu @ 2013-08-02  9:49 UTC (permalink / raw)
  To: linux-ext4; +Cc: Theodore Ts'o, Zheng Liu

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

Let e2fsprogs support inline_data feature.

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 lib/ext2fs/ext2fs.h |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 2804748..ab4c70e 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -588,7 +588,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.9.7


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

* [PATCH v1 14/22] mke2fs: add inline_data support in mke2fs
  2013-08-02  9:49 [PATCH v1 00/22] e2fsprogs: inline data refinement patch set Zheng Liu
                   ` (12 preceding siblings ...)
  2013-08-02  9:49 ` [PATCH v1 13/22] libext2fs: add inline_data feature into EXT2_LIB_FEATURE_INCOMPAT_SUPP Zheng Liu
@ 2013-08-02  9:49 ` Zheng Liu
  2013-10-12  0:27   ` Darrick J. Wong
  2013-08-02  9:49 ` [PATCH v1 15/22] tune2fs: add inline_data feature in tune2fs Zheng Liu
                   ` (7 subsequent siblings)
  21 siblings, 1 reply; 67+ messages in thread
From: Zheng Liu @ 2013-08-02  9:49 UTC (permalink / raw)
  To: linux-ext4; +Cc: Theodore Ts'o, Zheng Liu

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

Inline_data feature doesn't be specified without ext_attr.

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 misc/mke2fs.8.in |    3 +++
 misc/mke2fs.c    |   14 +++++++++++++-
 2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/misc/mke2fs.8.in b/misc/mke2fs.8.in
index 023ba49..5731542 100644
--- a/misc/mke2fs.8.in
+++ b/misc/mke2fs.8.in
@@ -578,6 +578,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 a59d24c..cb084ea 100644
--- a/misc/mke2fs.c
+++ b/misc/mke2fs.c
@@ -902,7 +902,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|
@@ -2042,6 +2043,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.9.7


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

* [PATCH v1 15/22] tune2fs: add inline_data feature in tune2fs
  2013-08-02  9:49 [PATCH v1 00/22] e2fsprogs: inline data refinement patch set Zheng Liu
                   ` (13 preceding siblings ...)
  2013-08-02  9:49 ` [PATCH v1 14/22] mke2fs: add inline_data support in mke2fs Zheng Liu
@ 2013-08-02  9:49 ` Zheng Liu
  2013-10-12  0:39   ` Darrick J. Wong
  2013-08-02  9:49 ` [PATCH v1 16/22] e2fsck: add problem descriptions and check inline data feature Zheng Liu
                   ` (6 subsequent siblings)
  21 siblings, 1 reply; 67+ messages in thread
From: Zheng Liu @ 2013-08-02  9:49 UTC (permalink / raw)
  To: linux-ext4; +Cc: Theodore Ts'o, 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: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 misc/tune2fs.8.in |    5 +++++
 misc/tune2fs.c    |   17 ++++++++++++++++-
 2 files changed, 21 insertions(+), 1 deletion(-)

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 7d6520e..f22a736 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|
@@ -995,6 +996,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.9.7


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

* [PATCH v1 16/22] e2fsck: add problem descriptions and check inline data feature
  2013-08-02  9:49 [PATCH v1 00/22] e2fsprogs: inline data refinement patch set Zheng Liu
                   ` (14 preceding siblings ...)
  2013-08-02  9:49 ` [PATCH v1 15/22] tune2fs: add inline_data feature in tune2fs Zheng Liu
@ 2013-08-02  9:49 ` Zheng Liu
  2013-08-02  9:49 ` [PATCH v1 17/22] e2fsck: check inline_data in pass1 Zheng Liu
                   ` (5 subsequent siblings)
  21 siblings, 0 replies; 67+ messages in thread
From: Zheng Liu @ 2013-08-02  9:49 UTC (permalink / raw)
  To: linux-ext4; +Cc: Theodore Ts'o, Zheng Liu

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

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
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 deletion(-)

diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index 1b410be..e6ea460 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -592,7 +592,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;
@@ -626,6 +626,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
@@ -757,6 +759,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);
 
@@ -808,6 +824,21 @@ void e2fsck_pass1(e2fsck_t ctx)
 			}
 		}
 
+		/* Test for incorrect inline_data flags settings. */
+		if ((inode->i_flags & EXT4_INLINE_DATA_FL) && !inlinedata_fs &&
+		    (ino >= EXT2_FIRST_INODE(fs->super))) {
+			if (ext2fs_inline_data_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 76bc1d5..d79115a 100644
--- a/e2fsck/problem.c
+++ b/e2fsck/problem.c
@@ -1008,6 +1008,21 @@ static struct e2fsck_problem problem_table[] = {
 	     "Logical start %b does not match logical start %c at next level.  "),
 	  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 d2b6df4..83257ae 100644
--- a/e2fsck/problem.h
+++ b/e2fsck/problem.h
@@ -589,6 +589,15 @@ struct problem_context {
 /* Index start doesn't match start of next extent down */
 #define PR_1_EXTENT_INDEX_START_INVALID	0x01006D
 
+/* INLINE_DATA feature is set, but EXT_ATTR missing */
+#define PR_1_INLINE_DATA_AND_EXT_ATTR  0x01006E
+
+/* Inode has inline data, but superblock is missing INLINE_DATA feature. */
+#define PR_1_INLINE_DATA_FEATURE       0x01006F
+
+/* INLINE_DATA feature is set in a non-inline-data filesystem */
+#define PR_1_INLINE_DATA_SET	       0x010070
+
 /*
  * Pass 1b errors
  */
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index ab4c70e..fc40ef2 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -1357,6 +1357,7 @@ extern errcode_t ext2fs_inline_data_iterate(ext2_filsys fs,
 						  struct ext2_inode_large *inode,
 						  void *priv_data),
 				      void *priv_data);
+extern int ext2fs_inline_data_check(ext2_filsys fs, ext2_ino_t ino);
 extern errcode_t ext2fs_inline_data_create(ext2_filsys fs,
 					   struct ext2_inode_large *inode,
 					   unsigned int len);
diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c
index 52ac133..1c954a3 100644
--- a/lib/ext2fs/inline_data.c
+++ b/lib/ext2fs/inline_data.c
@@ -383,6 +383,34 @@ err:
 	return retval;
 }
 
+int ext2fs_inline_data_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_inline_data_find(fs, inode, &data);
+	if (retval)
+		goto err;
+
+	if (data.inline_off != 0)
+		pass = 1;
+
+err:
+	ext2fs_free_mem(&inode);
+	return pass;
+}
+
 errcode_t ext2fs_inline_data_convert(ext2_filsys fs,
 				     ext2_ino_t  ino,
 				     void *priv_data)
-- 
1.7.9.7


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

* [PATCH v1 17/22] e2fsck: check inline_data in pass1
  2013-08-02  9:49 [PATCH v1 00/22] e2fsprogs: inline data refinement patch set Zheng Liu
                   ` (15 preceding siblings ...)
  2013-08-02  9:49 ` [PATCH v1 16/22] e2fsck: add problem descriptions and check inline data feature Zheng Liu
@ 2013-08-02  9:49 ` Zheng Liu
  2013-10-12  0:47   ` Darrick J. Wong
  2013-08-02  9:49 ` [PATCH v1 18/22] e2fsck: check inline_data in pass2 Zheng Liu
                   ` (4 subsequent siblings)
  21 siblings, 1 reply; 67+ messages in thread
From: Zheng Liu @ 2013-08-02  9:49 UTC (permalink / raw)
  To: linux-ext4; +Cc: Theodore Ts'o, Zheng Liu

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

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 e2fsck/pass1.c          |   70 ++++++++++++++++++++++++++++++++++++++++++++---
 lib/ext2fs/dblist_dir.c |   10 +++++--
 2 files changed, 74 insertions(+), 6 deletions(-)

diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index e6ea460..4301bb9 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) {
+		unsigned int inline_size;
+
+		inline_size = ext2fs_inline_data_get_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) ||
@@ -303,6 +313,15 @@ 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 the content of inline data right.
+		 */
+		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);
 
@@ -330,6 +349,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);
@@ -407,6 +427,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
@@ -434,11 +455,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))
@@ -1205,7 +1234,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])
@@ -1214,6 +1244,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] ||
@@ -2129,6 +2160,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.
  */
@@ -2142,6 +2195,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;
@@ -2165,6 +2219,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 &
@@ -2188,6 +2244,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,
@@ -2230,7 +2289,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--;
@@ -2256,7 +2316,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.9.7


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

* [PATCH v1 18/22] e2fsck: check inline_data in pass2
  2013-08-02  9:49 [PATCH v1 00/22] e2fsprogs: inline data refinement patch set Zheng Liu
                   ` (16 preceding siblings ...)
  2013-08-02  9:49 ` [PATCH v1 17/22] e2fsck: check inline_data in pass1 Zheng Liu
@ 2013-08-02  9:49 ` Zheng Liu
  2013-08-02  9:49 ` [PATCH v1 19/22] e2fsck: check inline_data in pass3 Zheng Liu
                   ` (3 subsequent siblings)
  21 siblings, 0 replies; 67+ messages in thread
From: Zheng Liu @ 2013-08-02  9:49 UTC (permalink / raw)
  To: linux-ext4; +Cc: Theodore Ts'o, Zheng Liu

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

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 e2fsck/pass2.c |  123 +++++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 95 insertions(+), 28 deletions(-)

diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c
index 257589c..7b66099 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_inline_data_get_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_inline_data_get_size(fs, ino)) {
+			cd->pctx.num = rec_len + offset -
+				ext2fs_inline_data_get_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.9.7


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

* [PATCH v1 19/22] e2fsck: check inline_data in pass3
  2013-08-02  9:49 [PATCH v1 00/22] e2fsprogs: inline data refinement patch set Zheng Liu
                   ` (17 preceding siblings ...)
  2013-08-02  9:49 ` [PATCH v1 18/22] e2fsck: check inline_data in pass2 Zheng Liu
@ 2013-08-02  9:49 ` Zheng Liu
  2013-10-12  0:54   ` Darrick J. Wong
  2013-08-02  9:49 ` [PATCH v1 20/22] tests: change result in f_bad_disconnected_inode Zheng Liu
                   ` (2 subsequent siblings)
  21 siblings, 1 reply; 67+ messages in thread
From: Zheng Liu @ 2013-08-02  9:49 UTC (permalink / raw)
  To: linux-ext4; +Cc: Theodore Ts'o, Zheng Liu

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

In e2fsck_expand_directory() we don't handle a dir with inline data
because when this function is called the directory inode shouldn't
contains inline data.

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 e2fsck/pass3.c  |   12 ++++++++++++
 e2fsck/rehash.c |    3 ++-
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c
index a379e9b..5052345 100644
--- a/e2fsck/pass3.c
+++ b/e2fsck/pass3.c
@@ -787,6 +787,18 @@ errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
 	es.ctx = ctx;
 	es.dir = dir;
 
+	/*
+	 * 'lost+found' dir shouldn't contains inline data.  So we
+	 * need to clear this flag.
+	 */
+	if (ext2fs_inode_has_inline_data(fs, dir)) {
+		retval = ext2fs_read_inode(fs, dir, &inode);
+		if (retval)
+			return retval;
+		inode.i_flags &= ~EXT4_INLINE_DATA_FL;
+		e2fsck_write_inode(ctx, dir, &inode, "clear inline_data flag");
+	}
+
 	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 5592e3f..82aeddd 100644
--- a/e2fsck/rehash.c
+++ b/e2fsck/rehash.c
@@ -937,7 +937,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.9.7


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

* [PATCH v1 20/22] tests: change result in f_bad_disconnected_inode
  2013-08-02  9:49 [PATCH v1 00/22] e2fsprogs: inline data refinement patch set Zheng Liu
                   ` (18 preceding siblings ...)
  2013-08-02  9:49 ` [PATCH v1 19/22] e2fsck: check inline_data in pass3 Zheng Liu
@ 2013-08-02  9:49 ` Zheng Liu
  2013-08-02  9:49 ` [PATCH v1 21/22] mke2fs: enable inline_data feature on ext4dev filesystem Zheng Liu
  2013-08-02  9:49 ` [PATCH v1 22/22] libext2fs: add a unit test for inline data Zheng Liu
  21 siblings, 0 replies; 67+ messages in thread
From: Zheng Liu @ 2013-08-02  9:49 UTC (permalink / raw)
  To: linux-ext4; +Cc: Theodore Ts'o, Zheng Liu

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

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

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 tests/f_bad_disconnected_inode/expect.1 |    9 +++++++++
 1 file changed, 9 insertions(+)

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


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

* [PATCH v1 21/22] mke2fs: enable inline_data feature on ext4dev filesystem
  2013-08-02  9:49 [PATCH v1 00/22] e2fsprogs: inline data refinement patch set Zheng Liu
                   ` (19 preceding siblings ...)
  2013-08-02  9:49 ` [PATCH v1 20/22] tests: change result in f_bad_disconnected_inode Zheng Liu
@ 2013-08-02  9:49 ` Zheng Liu
  2013-08-02  9:49 ` [PATCH v1 22/22] libext2fs: add a unit test for inline data Zheng Liu
  21 siblings, 0 replies; 67+ messages in thread
From: Zheng Liu @ 2013-08-02  9:49 UTC (permalink / raw)
  To: linux-ext4; +Cc: Theodore Ts'o, Zheng Liu

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

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 misc/mke2fs.conf.in |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

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


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

* [PATCH v1 22/22] libext2fs: add a unit test for inline data
  2013-08-02  9:49 [PATCH v1 00/22] e2fsprogs: inline data refinement patch set Zheng Liu
                   ` (20 preceding siblings ...)
  2013-08-02  9:49 ` [PATCH v1 21/22] mke2fs: enable inline_data feature on ext4dev filesystem Zheng Liu
@ 2013-08-02  9:49 ` Zheng Liu
  21 siblings, 0 replies; 67+ messages in thread
From: Zheng Liu @ 2013-08-02  9:49 UTC (permalink / raw)
  To: linux-ext4; +Cc: Theodore Ts'o, Zheng Liu

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

In this unit test, we will test manipulation of regular file and dir
for inline data to make sure all tests pass.

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 lib/ext2fs/Makefile.in   |    8 +-
 lib/ext2fs/inline_data.c |  294 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 301 insertions(+), 1 deletion(-)

diff --git a/lib/ext2fs/Makefile.in b/lib/ext2fs/Makefile.in
index 001c222..6b188b8 100644
--- a/lib/ext2fs/Makefile.in
+++ b/lib/ext2fs/Makefile.in
@@ -390,6 +390,11 @@ tst_inline: $(srcdir)/inline.c $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR)
 	$(Q) $(CC) -o tst_inline $(srcdir)/inline.c $(ALL_CFLAGS) -DDEBUG \
 		$(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR)
 
+tst_inline_data: inline_data.c $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR)
+	$(E) "	LD $@"
+	$(Q) $(CC) -o tst_inline_data $(srcdir)/inline_data.c $(ALL_CFLAGS) \
+	-DDEBUG $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR)
+
 tst_csum: csum.c $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR) $(STATIC_LIBE2P) \
 		$(top_srcdir)/lib/e2p/e2p.h
 	$(E) "	LD $@"
@@ -407,7 +412,7 @@ mkjournal: mkjournal.c $(STATIC_LIBEXT2FS) $(DEPLIBCOM_ERR)
 
 check:: tst_bitops tst_badblocks tst_iscan tst_types tst_icount \
     tst_super_size tst_types tst_inode_size tst_csum tst_crc32c tst_bitmaps \
-    tst_inline
+    tst_inline tst_inline_data
 	LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_bitops
 	LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_badblocks
 	LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_iscan
@@ -417,6 +422,7 @@ check:: tst_bitops tst_badblocks tst_iscan tst_types tst_icount \
 	LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_inode_size
 	LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_csum
 	LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_inline
+	LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_inline_data
 	LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_crc32c
 	LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) \
 		./tst_bitmaps -f $(srcdir)/tst_bitmaps_cmds > tst_bitmaps_out
diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c
index 1c954a3..53bddc7 100644
--- a/lib/ext2fs/inline_data.c
+++ b/lib/ext2fs/inline_data.c
@@ -670,3 +670,297 @@ errcode_t ext2fs_inline_data_create(ext2_filsys fs,
 
 	return 0;
 }
+
+#ifdef DEBUG
+#include "e2p/e2p.h"
+
+/*
+ * The length of buffer is set to 64 because in inode's i_block member it only
+ * can save 60 bytes.  Thus this value can let the data being saved in extra
+ * space.
+ */
+#define BUF_LEN (64)
+
+/*
+ * Test manipulation of regular file.
+ *
+ * In this test case, the following operations are tested:
+ *  - regular file creation with inline_data flag
+ *  - try to write data into inode while the size of data is fit for saving in
+ *    inode
+ *  - read data from inode
+ *  - write data without changing the size of inline data
+ *  - get the size of inline data
+ *  - truncate
+ *  - check header
+ */
+static errcode_t test_file(ext2_filsys fs)
+{
+	ext2_ino_t newfile;
+	errcode_t retval;
+	unsigned int written;
+	struct ext2_inode_large inode;
+	char *buf, *cmpbuf;
+	int inline_size;
+
+	retval = ext2fs_new_inode(fs, 2, 010755, 0, &newfile);
+	if (retval) {
+		com_err("test_file", retval,
+			"While creating a new file");
+		return 1;
+	}
+
+	retval = ext2fs_write_new_inode(fs, newfile, (void *)&inode);
+	if (retval) {
+		com_err("test_file", retval,
+			"While writting a new inode");
+		return 1;
+	}
+
+	retval = ext2fs_get_arrayzero(BUF_LEN, sizeof(char), &buf);
+	if (retval) {
+		com_err("test_file", retval, "While creating buffer");
+		return 1;
+	}
+	memset(buf, 'a', BUF_LEN);
+	retval = ext2fs_try_to_write_inline_data(fs, newfile, buf,
+						 BUF_LEN, &written);
+	if (retval) {
+		com_err("test_file", retval,
+			"While trying to write a regular file");
+		return 1;
+	}
+
+	if (written != BUF_LEN) {
+		printf("inline_data: write a regular file error, written %d "
+		       "should be %d.\n", written, BUF_LEN);
+		return 1;
+	}
+
+	inline_size = ext2fs_inline_data_get_size(fs, newfile);
+	if (inline_size != BUF_LEN) {
+		printf("inline_data: the size of inline data is incorrect\n");
+		return 1;
+	}
+
+	retval = ext2fs_get_arrayzero(BUF_LEN, sizeof(char), &cmpbuf);
+	if (retval) {
+		com_err("test_file", retval, "While creating buffer");
+		return 1;
+	}
+	retval = ext2fs_read_inline_data(fs, newfile, cmpbuf);
+	if (retval) {
+		com_err("test_file", retval, "While reading");
+		return 1;
+	}
+
+	if (memcmp(buf, cmpbuf, BUF_LEN)) {
+		printf("inline_data: read a regular file error\n");
+		return 1;
+	}
+
+	retval = ext2fs_write_inline_data(fs, newfile, buf);
+	if (retval) {
+		printf("inline_data: write a regular file error\n");
+		return 1;
+	}
+
+	retval = ext2fs_punch(fs, newfile, 0, 0, 0, ~0U);
+	if (retval) {
+		printf("inline_data: truncate failed\n");
+		return 1;
+	}
+
+	retval = ext2fs_inline_data_check(fs, newfile);
+	if (retval != 1) {
+		printf("inline_data: header check failed\n");
+		return 1;
+	}
+
+	ext2fs_free_mem(&buf);
+	ext2fs_free_mem(&cmpbuf);
+
+	printf("tst_inline_data(REG): OK\n");
+
+	return 0;
+}
+
+static errcode_t test_create_parent_dir(ext2_filsys fs, ext2_ino_t *ino)
+{
+	const char *test_dir = "test";
+	const char *dot = ".";
+	errcode_t retval;
+	ext2_ino_t dir, tmp;
+
+	/* create a stub directory */
+	retval = ext2fs_mkdir(fs, 11, 11, "stub");
+	if (retval) {
+		com_err("test_dir", retval, "while creating stub dir");
+		return 1;
+	}
+
+	/* create a new empty directory with inline data */
+	retval = ext2fs_mkdir(fs, 11, 0, test_dir);
+	if (retval)
+		return 1;
+
+	/* lookup this new directory */
+	retval = ext2fs_lookup(fs, 11, test_dir,
+			       strlen(test_dir), 0, &dir);
+	if (retval) {
+		com_err("test_create_parent_dir", retval,
+			"while looking up test dir");
+		return 1;
+	}
+
+	/* lookup '.' in this new directory */
+	retval = ext2fs_lookup(fs, dir, dot, strlen(dot), 0, &tmp);
+	if (retval) {
+		com_err("test_create_parent_dir", retval,
+			"while looking up dot dir");
+		return 1;
+	}
+
+	if (tmp != dir) {
+		fprintf(stderr, "inline_data: looking up '.' error\n");
+		return 1;
+	}
+
+	*ino = dir;
+	return 0;
+}
+
+static errcode_t test_manipulate_dirs(ext2_filsys fs, ext2_ino_t parent)
+{
+	errcode_t retval;
+	ext2_ino_t dir = 13, tmp;
+	char name[PATH_MAX];
+	int i;
+
+	/*
+	 * Here we only try to create 4 dirs:
+	 *   4 bytes (parent inode) + 56 bytes
+	 * In ext4 a dir at least need to take 12 bytes.  So it only can
+	 * save 4 dirs in inode's i_block.
+	 */
+	for (i = 0; i < 4; i++) {
+		tmp = 0;
+		snprintf(name, PATH_MAX, "%d", i);
+		retval = ext2fs_mkdir(fs, parent, 0, name);
+		if (retval) {
+			com_err("test_manipulate_dirs", retval,
+				"while making dir %s", name);
+			return 1;
+		}
+
+		retval = ext2fs_lookup(fs, parent, name,
+				       strlen(name), 0, &tmp);
+		if (retval) {
+			com_err("test_manipulate_dirs", retval,
+				"while looking up test dir");
+			return 1;
+		}
+
+		if (tmp != dir) {
+			printf("inline_data: create subdirs failed, "
+			       "dir inode is %d, but now is %d\n", dir, tmp);
+			return 1;
+		}
+
+		dir++;
+	}
+
+	/*
+	 * XXX: In e2fsprogs the size of inline data doesn't expand from i_block
+	 * space to extra space while making a new dir.  If extra space has been
+	 * used while creating a new dir, extra space will be used.  So here
+	 * ext2fs_mkdir() will return EXT2_ET_DIR_NO_SPACE.
+	 */
+	snprintf(name, PATH_MAX, "%d", i);
+	retval = ext2fs_mkdir(fs, parent, 0, name);
+	if (retval != EXT2_ET_DIR_NO_SPACE) {
+		com_err("test_manipulate_dirs", retval,
+			"while making dir %s", name);
+		return 1;
+	}
+
+	retval = ext2fs_expand_dir(fs, parent);
+	if (retval) {
+		com_err("test_maniuplate_dirs", retval,
+			"while expanding test dir");
+		return 1;
+	}
+
+	retval = ext2fs_inline_data_check(fs, parent);
+	if (retval != 1) {
+		printf("inline_data: header check failed\n");
+		return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * Test manipulation of directory.
+ *
+ * In this test case, we first try to create a test dir.  Then we will try to
+ * create, lookup this dir and make sure all tests pass.
+ */
+static errcode_t test_dir(ext2_filsys fs)
+{
+	errcode_t retval;
+	ext2_ino_t dir;
+
+	retval = test_create_parent_dir(fs, &dir);
+	if (retval)
+		return 1;
+
+	retval = test_manipulate_dirs(fs, dir);
+	if (retval)
+		return 1;
+
+	printf("tst_inline_data(DIR): OK\n");
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	struct ext2_super_block param;
+	errcode_t		retval;
+	ext2_filsys		fs;
+	int			i;
+
+	memset(&param, 0, sizeof(param));
+	ext2fs_blocks_count_set(&param, 32768);
+
+	retval = ext2fs_initialize("test fs", EXT2_FLAG_64BITS, &param,
+				   test_io_manager, &fs);
+	if (retval) {
+		com_err("setup", retval,
+			"While initializing filesystem");
+		exit(1);
+	}
+
+	fs->super->s_feature_ro_compat |= EXT2_FEATURE_COMPAT_EXT_ATTR;
+	fs->super->s_feature_incompat |= EXT4_FEATURE_INCOMPAT_INLINE_DATA;
+	fs->super->s_rev_level = EXT2_DYNAMIC_REV;
+	fs->super->s_inode_size = 256;
+
+	retval = ext2fs_allocate_tables(fs);
+	if (retval) {
+		com_err("setup", retval,
+			"while allocating tables for test filesysmte");
+		exit(1);
+	}
+
+	retval = test_file(fs);
+	if (retval)
+		return retval;
+
+	retval = test_dir(fs);
+	if (retval)
+		return retval;
+
+	return 0;
+}
+#endif
-- 
1.7.9.7


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

* Re: [PATCH v1 03/22] libext2fs: add functions to operate on extended attribute
  2013-08-02  9:49 ` [PATCH v1 03/22] libext2fs: add functions to operate on extended attribute Zheng Liu
@ 2013-08-05 17:34   ` Darrick J. Wong
  2013-08-05 23:14     ` Zheng Liu
  2013-10-11 22:51   ` Darrick J. Wong
  1 sibling, 1 reply; 67+ messages in thread
From: Darrick J. Wong @ 2013-08-05 17:34 UTC (permalink / raw)
  To: Zheng Liu; +Cc: linux-ext4, Zheng Liu, Theodore Ts'o

On Fri, Aug 02, 2013 at 05:49:30PM +0800, Zheng Liu wrote:
> From: Zheng Liu <wenqing.lz@taobao.com>
> 
> We need to define some functions to operate extended attribute in order
> to support inline data.
> 
> Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> ---
>  lib/ext2fs/ext2_err.et.in  |    3 +
>  lib/ext2fs/ext2_ext_attr.h |   31 ++++++++
>  lib/ext2fs/ext2fs.h        |    9 +++
>  lib/ext2fs/ext_attr.c      |  186 ++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 229 insertions(+)
> 
> diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in
> index d20c6b7..7e6d6e5 100644
> --- a/lib/ext2fs/ext2_err.et.in
> +++ b/lib/ext2fs/ext2_err.et.in
> @@ -476,4 +476,7 @@ ec	EXT2_ET_MMP_CSUM_INVALID,
>  ec	EXT2_ET_FILE_EXISTS,
>  	"Ext2 file already exists"
>  
> +ec	EXT2_ET_EXT_ATTR_CURRUPTED,
> +	"Extended attribute currupted"

"corrupted".

(Or maybe shorten that to "corrupt"?)

--D
> +
>  	end
> diff --git a/lib/ext2fs/ext2_ext_attr.h b/lib/ext2fs/ext2_ext_attr.h
> index bbb0aaa..99ad849 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,29 @@ 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 *) \
> +		((char *)inode + \
> +		EXT2_GOOD_OLD_INODE_SIZE + \
> +		inode->i_extra_isize))
> +#define IFIRST(hdr) ((struct ext2_ext_attr_entry *)((hdr)+1))
> +#define EXT2_ZERO_EXT_ATTR_VALUE ((void *)-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 3346c00..8c30197 100644
> --- a/lib/ext2fs/ext2fs.h
> +++ b/lib/ext2fs/ext2fs.h
> @@ -1136,6 +1136,15 @@ 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_ext_attr_ibody_find(ext2_filsys fs,
> +					    struct ext2_inode_large *inode,
> +					    struct ext2_ext_attr_info *i,
> +					    struct ext2_ext_attr_search *s);
> +extern errcode_t ext2fs_ext_attr_find_entry(struct ext2_ext_attr_entry **pentry,
> +					    int name_index, const char *name,
> +					    size_t size, int sorted);
> +extern errcode_t ext2fs_ext_attr_set_entry(struct ext2_ext_attr_info *i,
> +					   struct ext2_ext_attr_search *s);
>  
>  /* 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..6d55340 100644
> --- a/lib/ext2fs/ext_attr.c
> +++ b/lib/ext2fs/ext_attr.c
> @@ -186,3 +186,189 @@ errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
>  	return ext2fs_adjust_ea_refcount2(fs, blk, block_buf, adjust,
>  					  newcount);
>  }
> +
> +static errcode_t
> +ext2fs_ext_attr_check_names(struct ext2_ext_attr_entry *entry, void *end)
> +{
> +	while (!EXT2_EXT_IS_LAST_ENTRY(entry)) {
> +		struct ext2_ext_attr_entry *next = EXT2_EXT_ATTR_NEXT(entry);
> +		if ((void *)next >= end)
> +			return EXT2_ET_EXT_ATTR_CURRUPTED;
> +		entry = next;
> +	}
> +	return 0;
> +}
> +
> +static inline errcode_t
> +ext2fs_ext_attr_check_entry(struct ext2_ext_attr_entry *entry, size_t size)
> +{
> +	size_t value_size = entry->e_value_size;
> +
> +	if (entry->e_value_block != 0 || value_size > size ||
> +	    entry->e_value_offs + value_size > size)
> +		return EXT2_ET_EXT_ATTR_CURRUPTED;
> +	return 0;
> +}
> +
> +errcode_t ext2fs_ext_attr_find_entry(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 = 1;
> +
> +	if (name == NULL)
> +		return EXT2_ET_INVALID_ARGUMENT;
> +	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 <= 0 && (sorted || cmp == 0))
> +			break;
> +	}
> +	*pentry = entry;
> +	if (!cmp && ext2fs_ext_attr_check_entry(entry, size))
> +		return EXT2_ET_EXT_ATTR_CURRUPTED;
> +	return cmp ? ENODATA : 0;
> +}
> +
> +errcode_t ext2fs_ext_attr_ibody_find(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;
> +	errcode_t error;
> +
> +	if (inode->i_extra_isize == 0)
> +		return 0;
> +	header = IHDR(inode);
> +	s->base = s->first = IFIRST(header);
> +	s->here = s->first;
> +	s->end = (char *)inode + EXT2_INODE_SIZE(fs->super);
> +
> +	error = ext2fs_ext_attr_check_names(IFIRST(header), s->end);
> +	if (error)
> +		return error;
> +	/* Find the named attribute. */
> +	error = ext2fs_ext_attr_find_entry(&s->here, i->name_index,
> +					   i->name, (char *)s->end -
> +					   (char *)s->base, 0);
> +	if (error && error != ENODATA)
> +		return error;
> +	s->not_found = error;
> +	return 0;
> +}
> +
> +errcode_t ext2fs_ext_attr_set_entry(struct ext2_ext_attr_info *i,
> +				    struct ext2_ext_attr_search *s)
> +{
> +	struct ext2_ext_attr_entry *last;
> +	size_t freesize, min_offs = (char *)s->end - (char *)s->base;
> +	size_t name_len = strlen(i->name);
> +
> +	/* Compute min_offs and last. */
> +	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 = last->e_value_offs;
> +			if (offs < min_offs)
> +				min_offs = offs;
> +		}
> +	}
> +	freesize = min_offs - ((char *)last - (char *)s->base) - sizeof(__u32);
> +	if (!s->not_found) {
> +		if (!s->here->e_value_block && s->here->e_value_size) {
> +			size_t size = s->here->e_value_size;
> +			freesize += EXT2_EXT_ATTR_SIZE(size);
> +		}
> +		freesize += EXT2_EXT_ATTR_LEN(name_len);
> +	}
> +	if (i->value) {
> +		if (freesize < EXT2_EXT_ATTR_SIZE(i->value_len) ||
> +		    freesize < EXT2_EXT_ATTR_LEN(name_len) +
> +			   EXT2_EXT_ATTR_SIZE(i->value_len))
> +			return ENOSPC;
> +	}
> +
> +	if (i->value && s->not_found) {
> +		/* Insert the new name. */
> +		size_t size = EXT2_EXT_ATTR_LEN(name_len);
> +		size_t rest = (char *)last - (char *)s->here + sizeof(__u32);
> +		memmove((char *)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), i->name, name_len);
> +	} else {
> +		if (!s->here->e_value_block && s->here->e_value_size) {
> +			char *first_val = (char *) s->base + min_offs;
> +			size_t offs = s->here->e_value_offs;
> +			char *val = (char *)s->base + offs;
> +			size_t size = EXT2_EXT_ATTR_SIZE(s->here->e_value_size);
> +
> +			if (i->value && size == EXT2_EXT_ATTR_SIZE(i->value_len)) {
> +				/* The old and the new value have the same
> +				 * size. Just replace. */
> +				s->here->e_value_size = i->value_len;
> +				if (i->value == EXT2_ZERO_EXT_ATTR_VALUE) {
> +					memset(val, 0, size);
> +				} else {
> +					memset(val + size - EXT2_EXT_ATTR_PAD, 0,
> +						EXT2_EXT_ATTR_PAD);
> +					memcpy(val, i->value, i->value_len);
> +				}
> +				return 0;
> +			}
> +
> +			/* Remove the old value. */
> +			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;
> +
> +			/* Adjust all value offsets. */
> +			last = s->first;
> +			while (!EXT2_EXT_IS_LAST_ENTRY(last)) {
> +				size_t o = last->e_value_offs;
> +				if (!last->e_value_block &&
> +				    last->e_value_size && o < offs)
> +					last->e_value_offs = o + size;
> +				last = EXT2_EXT_ATTR_NEXT(last);
> +			}
> +		}
> +		if (!i->value) {
> +			/* Remove the old name. */
> +			size_t size = EXT2_EXT_ATTR_LEN(name_len);
> +			last = (struct ext2_ext_attr_entry *)last - size;
> +			memmove(s->here, (char *)s->here + size,
> +				(char *)last - (char *)s->here + sizeof(__u32));
> +			memset(last, 0, size);
> +		}
> +	}
> +
> +	if (i->value) {
> +		/* Insert the new value. */
> +		s->here->e_value_size = i->value_len;
> +		if (i->value_len) {
> +			size_t size = EXT2_EXT_ATTR_SIZE(i->value_len);
> +			char *val = (char *)s->base + min_offs - size;
> +			s->here->e_value_offs = min_offs - size;
> +			if (i->value == EXT2_ZERO_EXT_ATTR_VALUE) {
> +				memset(val, 0, size);
> +			} else {
> +				memset(val + size - EXT2_EXT_ATTR_PAD, 0,
> +					EXT2_EXT_ATTR_PAD);
> +				memcpy(val, i->value, i->value_len);
> +			}
> +		}
> +	}
> +	return 0;
> +}
> -- 
> 1.7.9.7
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v1 03/22] libext2fs: add functions to operate on extended attribute
  2013-08-05 17:34   ` Darrick J. Wong
@ 2013-08-05 23:14     ` Zheng Liu
  2013-10-14  1:55       ` Theodore Ts'o
  0 siblings, 1 reply; 67+ messages in thread
From: Zheng Liu @ 2013-08-05 23:14 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-ext4, Zheng Liu, Theodore Ts'o

On Mon, Aug 05, 2013 at 10:34:52AM -0700, Darrick J. Wong wrote:
> On Fri, Aug 02, 2013 at 05:49:30PM +0800, Zheng Liu wrote:
> > From: Zheng Liu <wenqing.lz@taobao.com>
> > 
> > We need to define some functions to operate extended attribute in order
> > to support inline data.
> > 
> > Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
> > Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> > ---
> >  lib/ext2fs/ext2_err.et.in  |    3 +
> >  lib/ext2fs/ext2_ext_attr.h |   31 ++++++++
> >  lib/ext2fs/ext2fs.h        |    9 +++
> >  lib/ext2fs/ext_attr.c      |  186 ++++++++++++++++++++++++++++++++++++++++++++
> >  4 files changed, 229 insertions(+)
> > 
> > diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in
> > index d20c6b7..7e6d6e5 100644
> > --- a/lib/ext2fs/ext2_err.et.in
> > +++ b/lib/ext2fs/ext2_err.et.in
> > @@ -476,4 +476,7 @@ ec	EXT2_ET_MMP_CSUM_INVALID,
> >  ec	EXT2_ET_FILE_EXISTS,
> >  	"Ext2 file already exists"
> >  
> > +ec	EXT2_ET_EXT_ATTR_CURRUPTED,
> > +	"Extended attribute currupted"
> 
> "corrupted".

Thanks for pointing it out.  Fix it in next spin.

> 
> (Or maybe shorten that to "corrupt"?)

I find the 'CORRUPT' in lib/ext2fs/ext2_err.et.in, and the result are as
below.

$ grep CORRUPT lib/ext2fs/ext2_err.et.in
ec      EXT2_ET_DIR_CORRUPTED,
ec      EXT2_ET_CORRUPT_SUPERBLOCK,
ec      EXT2_ET_RESIZE_INODE_CORRUPT,
ec      EXT2_ET_TDB_ERR_CORRUPT,

It seems that there is no any rule about this.  I am wondering if we
need to rename _DIR_CORRUPTED to _DIR_CORRUPT.  I am ok for using
_CORRUPT or _CORRUPTED.

Regards,
                                                - Zheng

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

* Re: [PATCH v1 03/22] libext2fs: add functions to operate on extended attribute
  2013-08-02  9:49 ` [PATCH v1 03/22] libext2fs: add functions to operate on extended attribute Zheng Liu
  2013-08-05 17:34   ` Darrick J. Wong
@ 2013-10-11 22:51   ` Darrick J. Wong
  2013-10-12  5:51     ` Zheng Liu
  1 sibling, 1 reply; 67+ messages in thread
From: Darrick J. Wong @ 2013-10-11 22:51 UTC (permalink / raw)
  To: Zheng Liu; +Cc: linux-ext4, Zheng Liu, Theodore Ts'o

On Fri, Aug 02, 2013 at 05:49:30PM +0800, Zheng Liu wrote:
> From: Zheng Liu <wenqing.lz@taobao.com>
> 
> We need to define some functions to operate extended attribute in order
> to support inline data.
> 
> Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> ---
>  lib/ext2fs/ext2_err.et.in  |    3 +
>  lib/ext2fs/ext2_ext_attr.h |   31 ++++++++
>  lib/ext2fs/ext2fs.h        |    9 +++
>  lib/ext2fs/ext_attr.c      |  186 ++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 229 insertions(+)
> 
> diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in
> index d20c6b7..7e6d6e5 100644
> --- a/lib/ext2fs/ext2_err.et.in
> +++ b/lib/ext2fs/ext2_err.et.in
> @@ -476,4 +476,7 @@ ec	EXT2_ET_MMP_CSUM_INVALID,
>  ec	EXT2_ET_FILE_EXISTS,
>  	"Ext2 file already exists"
>  
> +ec	EXT2_ET_EXT_ATTR_CURRUPTED,
> +	"Extended attribute currupted"
> +
>  	end
> diff --git a/lib/ext2fs/ext2_ext_attr.h b/lib/ext2fs/ext2_ext_attr.h
> index bbb0aaa..99ad849 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,29 @@ 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 *) \
> +		((char *)inode + \
> +		EXT2_GOOD_OLD_INODE_SIZE + \
> +		inode->i_extra_isize))
> +#define IFIRST(hdr) ((struct ext2_ext_attr_entry *)((hdr)+1))
> +#define EXT2_ZERO_EXT_ATTR_VALUE ((void *)-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 3346c00..8c30197 100644
> --- a/lib/ext2fs/ext2fs.h
> +++ b/lib/ext2fs/ext2fs.h
> @@ -1136,6 +1136,15 @@ 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_ext_attr_ibody_find(ext2_filsys fs,
> +					    struct ext2_inode_large *inode,
> +					    struct ext2_ext_attr_info *i,
> +					    struct ext2_ext_attr_search *s);
> +extern errcode_t ext2fs_ext_attr_find_entry(struct ext2_ext_attr_entry **pentry,
> +					    int name_index, const char *name,
> +					    size_t size, int sorted);
> +extern errcode_t ext2fs_ext_attr_set_entry(struct ext2_ext_attr_info *i,
> +					   struct ext2_ext_attr_search *s);
>  
>  /* 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..6d55340 100644
> --- a/lib/ext2fs/ext_attr.c
> +++ b/lib/ext2fs/ext_attr.c
> @@ -186,3 +186,189 @@ errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
>  	return ext2fs_adjust_ea_refcount2(fs, blk, block_buf, adjust,
>  					  newcount);
>  }
> +
> +static errcode_t
> +ext2fs_ext_attr_check_names(struct ext2_ext_attr_entry *entry, void *end)
> +{
> +	while (!EXT2_EXT_IS_LAST_ENTRY(entry)) {
> +		struct ext2_ext_attr_entry *next = EXT2_EXT_ATTR_NEXT(entry);
> +		if ((void *)next >= end)
> +			return EXT2_ET_EXT_ATTR_CURRUPTED;
> +		entry = next;
> +	}
> +	return 0;
> +}
> +
> +static inline errcode_t
> +ext2fs_ext_attr_check_entry(struct ext2_ext_attr_entry *entry, size_t size)
> +{
> +	size_t value_size = entry->e_value_size;
> +
> +	if (entry->e_value_block != 0 || value_size > size ||
> +	    entry->e_value_offs + value_size > size)
> +		return EXT2_ET_EXT_ATTR_CURRUPTED;
> +	return 0;
> +}
> +
> +errcode_t ext2fs_ext_attr_find_entry(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 = 1;
> +
> +	if (name == NULL)
> +		return EXT2_ET_INVALID_ARGUMENT;
> +	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 <= 0 && (sorted || cmp == 0))
> +			break;
> +	}
> +	*pentry = entry;
> +	if (!cmp && ext2fs_ext_attr_check_entry(entry, size))
> +		return EXT2_ET_EXT_ATTR_CURRUPTED;
> +	return cmp ? ENODATA : 0;
> +}
> +
> +errcode_t ext2fs_ext_attr_ibody_find(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;
> +	errcode_t error;
> +
> +	if (inode->i_extra_isize == 0)
> +		return 0;
> +	header = IHDR(inode);
> +	s->base = s->first = IFIRST(header);
> +	s->here = s->first;
> +	s->end = (char *)inode + EXT2_INODE_SIZE(fs->super);
> +
> +	error = ext2fs_ext_attr_check_names(IFIRST(header), s->end);
> +	if (error)
> +		return error;
> +	/* Find the named attribute. */
> +	error = ext2fs_ext_attr_find_entry(&s->here, i->name_index,
> +					   i->name, (char *)s->end -
> +					   (char *)s->base, 0);
> +	if (error && error != ENODATA)
> +		return error;
> +	s->not_found = error;
> +	return 0;

Huh.  It just occurred to me (yes, after three months, sorry...) that your
patchset doesn't deal with EAs that live in a separate block.  For the purposes
of inline_data I suppose that's sufficient, but if we're going to add an API to
mess with EAs, we ought to be able to handle all of a file's EAs.

The implementation that I wrote for fuse2fs does this, but it has no facility
to ensure that the inline data ends up in the ibody and not the EA block.
Though really, they're written out in array order, so it wouldn't be difficult
to sort before writing, or use some knapsack variant.

I think I might be drifting towards the idea of attaching your patch series to
the end of mine, but as yours is already in -pu I'm open to discussing how to
reconcile our implementations.

I _do_ like the comments you added to ext2fs_ext_attr_set_entry() though. :)

--D

> +}
> +
> +errcode_t ext2fs_ext_attr_set_entry(struct ext2_ext_attr_info *i,
> +				    struct ext2_ext_attr_search *s)
> +{
> +	struct ext2_ext_attr_entry *last;
> +	size_t freesize, min_offs = (char *)s->end - (char *)s->base;
> +	size_t name_len = strlen(i->name);
> +
> +	/* Compute min_offs and last. */
> +	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 = last->e_value_offs;
> +			if (offs < min_offs)
> +				min_offs = offs;
> +		}
> +	}
> +	freesize = min_offs - ((char *)last - (char *)s->base) - sizeof(__u32);
> +	if (!s->not_found) {
> +		if (!s->here->e_value_block && s->here->e_value_size) {
> +			size_t size = s->here->e_value_size;
> +			freesize += EXT2_EXT_ATTR_SIZE(size);
> +		}
> +		freesize += EXT2_EXT_ATTR_LEN(name_len);
> +	}
> +	if (i->value) {
> +		if (freesize < EXT2_EXT_ATTR_SIZE(i->value_len) ||
> +		    freesize < EXT2_EXT_ATTR_LEN(name_len) +
> +			   EXT2_EXT_ATTR_SIZE(i->value_len))
> +			return ENOSPC;
> +	}
> +
> +	if (i->value && s->not_found) {
> +		/* Insert the new name. */
> +		size_t size = EXT2_EXT_ATTR_LEN(name_len);
> +		size_t rest = (char *)last - (char *)s->here + sizeof(__u32);
> +		memmove((char *)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), i->name, name_len);
> +	} else {
> +		if (!s->here->e_value_block && s->here->e_value_size) {
> +			char *first_val = (char *) s->base + min_offs;
> +			size_t offs = s->here->e_value_offs;
> +			char *val = (char *)s->base + offs;
> +			size_t size = EXT2_EXT_ATTR_SIZE(s->here->e_value_size);
> +
> +			if (i->value && size == EXT2_EXT_ATTR_SIZE(i->value_len)) {
> +				/* The old and the new value have the same
> +				 * size. Just replace. */
> +				s->here->e_value_size = i->value_len;
> +				if (i->value == EXT2_ZERO_EXT_ATTR_VALUE) {
> +					memset(val, 0, size);
> +				} else {
> +					memset(val + size - EXT2_EXT_ATTR_PAD, 0,
> +						EXT2_EXT_ATTR_PAD);
> +					memcpy(val, i->value, i->value_len);
> +				}
> +				return 0;
> +			}
> +
> +			/* Remove the old value. */
> +			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;
> +
> +			/* Adjust all value offsets. */
> +			last = s->first;
> +			while (!EXT2_EXT_IS_LAST_ENTRY(last)) {
> +				size_t o = last->e_value_offs;
> +				if (!last->e_value_block &&
> +				    last->e_value_size && o < offs)
> +					last->e_value_offs = o + size;
> +				last = EXT2_EXT_ATTR_NEXT(last);
> +			}
> +		}
> +		if (!i->value) {
> +			/* Remove the old name. */
> +			size_t size = EXT2_EXT_ATTR_LEN(name_len);
> +			last = (struct ext2_ext_attr_entry *)last - size;
> +			memmove(s->here, (char *)s->here + size,
> +				(char *)last - (char *)s->here + sizeof(__u32));
> +			memset(last, 0, size);
> +		}
> +	}
> +
> +	if (i->value) {
> +		/* Insert the new value. */
> +		s->here->e_value_size = i->value_len;
> +		if (i->value_len) {
> +			size_t size = EXT2_EXT_ATTR_SIZE(i->value_len);
> +			char *val = (char *)s->base + min_offs - size;
> +			s->here->e_value_offs = min_offs - size;
> +			if (i->value == EXT2_ZERO_EXT_ATTR_VALUE) {
> +				memset(val, 0, size);
> +			} else {
> +				memset(val + size - EXT2_EXT_ATTR_PAD, 0,
> +					EXT2_EXT_ATTR_PAD);
> +				memcpy(val, i->value, i->value_len);
> +			}
> +		}
> +	}
> +	return 0;
> +}
> -- 
> 1.7.9.7
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v1 04/22] libext2fs: handle inline data in dir iterator function
  2013-08-02  9:49 ` [PATCH v1 04/22] libext2fs: handle inline data in dir iterator function Zheng Liu
@ 2013-10-11 23:33   ` Darrick J. Wong
  2013-10-12  5:55     ` Zheng Liu
  2013-10-13 22:51   ` Theodore Ts'o
  2013-10-14  1:58   ` Theodore Ts'o
  2 siblings, 1 reply; 67+ messages in thread
From: Darrick J. Wong @ 2013-10-11 23:33 UTC (permalink / raw)
  To: Zheng Liu; +Cc: linux-ext4, Theodore Ts'o, Zheng Liu

On Fri, Aug 02, 2013 at 05:49:31PM +0800, Zheng Liu wrote:
> 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 in 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 extended attribute.
> 
> After applied this commit, the following commands in debugfs can
> support the inline_data feature:
> 	- ncheck
> 	- chroot
> 	- cd
> 	- ls
> 	- pwd
> 	- link*
> 	- unlink
> 
> * If inline_data doesn't expand to ibody extended 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: Theodore Ts'o <tytso@mit.edu>
> Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
> ---
>  lib/ext2fs/dir_iterate.c  |  102 ++++++++++++++++++++++++++++++++++-
>  lib/ext2fs/ext2_err.et.in |    6 +++
>  lib/ext2fs/ext2_fs.h      |    8 +++
>  lib/ext2fs/ext2fs.h       |   11 ++++
>  lib/ext2fs/ext2fsP.h      |   11 ++++
>  lib/ext2fs/inline_data.c  |  132 +++++++++++++++++++++++++++++++++++++++++++++
>  6 files changed, 268 insertions(+), 2 deletions(-)
> 
> diff --git a/lib/ext2fs/dir_iterate.c b/lib/ext2fs/dir_iterate.c
> index 1a4bf5c..7d5b1da 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)
> @@ -282,3 +288,95 @@ next:
>  	return 0;
>  }
>  
> +int ext2fs_process_dir_inline_data(ext2_filsys	fs,
> +				   char		*buf,
> +				   unsigned 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) {
> +			if (ext2fs_get_rec_len(fs, dirent, &rec_len))
> +				return BLOCK_ABORT;
> +			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 7e6d6e5..8a19cab 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"

"extended attribute"

> +
>  ec	EXT2_ET_REV_TOO_HIGH,
>  	"Filesystem revision too high"
>  
> @@ -479,4 +482,7 @@ ec	EXT2_ET_FILE_EXISTS,
>  ec	EXT2_ET_EXT_ATTR_CURRUPTED,
>  	"Extended attribute currupted"
>  
> +ec	EXT2_ET_BAD_EXTRA_SIZE,
> +	"Bad inode extra isizevalue"

"i_extra_isize value"

> +
>  	end
> diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
> index 0c0bbcb..d49b95c 100644
> --- a/lib/ext2fs/ext2_fs.h
> +++ b/lib/ext2fs/ext2_fs.h
> @@ -906,4 +906,12 @@ 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))
> +#define EXT4_INLINE_DATA_DOTDOT_SIZE	(4)
> +
>  #endif	/* _LINUX_EXT2_FS_H */
> diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
> index 8c30197..7b05b48 100644
> --- a/lib/ext2fs/ext2fs.h
> +++ b/lib/ext2fs/ext2fs.h
> @@ -1344,6 +1344,17 @@ extern errcode_t ext2fs_get_memalign(unsigned long size,
>  
>  /* inline_data.c */
>  extern int ext2fs_inode_has_inline_data(ext2_filsys fs, ext2_ino_t ino);
> +extern errcode_t ext2fs_inline_data_iterate(ext2_filsys fs,
> +				      ext2_ino_t ino,
> +				      int flags,
> +				      char *block_buf,
> +				      int (*func)(ext2_filsys fs,
> +						  char *buf,
> +						  unsigned int buf_len,
> +						  e2_blkcnt_t blockcnt,
> +						  struct ext2_inode_large *inode,
> +						  void *priv_data),
> +				      void *priv_data);
>  
>  /* inode.c */
>  extern void ext2fs_free_inode_cache(struct ext2_inode_cache *icache);
> diff --git a/lib/ext2fs/ext2fsP.h b/lib/ext2fs/ext2fsP.h
> index 3de9278..e86d452 100644
> --- a/lib/ext2fs/ext2fsP.h
> +++ b/lib/ext2fs/ext2fsP.h
> @@ -87,6 +87,17 @@ 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,
> +					  char		*buf,
> +					  unsigned int	buf_len,
> +					  e2_blkcnt_t	blockcnt,
> +					  struct ext2_inode_large *inode,
> +					  void		*priv_data);
> +
> +extern errcode_t ext2fs_inline_data_find(ext2_filsys fs,
> +					 struct ext2_inode_large *inode,
> +					 struct inline_data *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 fcf82b5..922c959 100644
> --- a/lib/ext2fs/inline_data.c
> +++ b/lib/ext2fs/inline_data.c
> @@ -14,10 +14,60 @@
>  #include <time.h>
>  
>  #include "ext2_fs.h"
> +#include "ext2_ext_attr.h"
>  
>  #include "ext2fs.h"
>  #include "ext2fsP.h"
>  
> +static void *ext2fs_get_inline_xattr_pos(struct ext2_inode_large *inode,
> +					 struct inline_data *data);
> +
> +errcode_t ext2fs_inline_data_find(ext2_filsys fs,
> +				  struct ext2_inode_large *inode,
> +				  struct inline_data *data)
> +{
> +	errcode_t retval;
> +
> +	struct ext2_ext_attr_search s = {
> +		.not_found = ENODATA,
> +	};
> +	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;
> +
> +	retval = ext2fs_ext_attr_ibody_find(fs, inode, &i, &s);
> +	if (retval)
> +		return retval;
> +
> +	if (!s.not_found) {
> +		data->inline_off = (__u16)((char *)s.here - (char *)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 *)
> +			((char *)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;
> @@ -29,3 +79,85 @@ int ext2fs_inode_has_inline_data(ext2_filsys fs, ext2_ino_t ino)
>  
>  	return (inode.i_flags & EXT4_INLINE_DATA_FL);
>  }
> +
> +errcode_t ext2fs_inline_data_iterate(ext2_filsys fs,
> +			       ext2_ino_t ino,
> +			       int flags,
> +			       char *block_buf,
> +			       int (*func)(ext2_filsys fs,
> +					   char *buf,
> +					   unsigned 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;

Perhaps this function should be called ext2fs_inline_dirblock_iterate()?
The name alone makes me think this function could work for regular inline_data
files, if such things ever exist.

--D

> +
> +	inline_start = (char *)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_inline_data_find(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.9.7
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v1 06/22] debugfs: make stat command support inline data
  2013-08-02  9:49 ` [PATCH v1 06/22] debugfs: make stat command support inline data Zheng Liu
@ 2013-10-11 23:43   ` Darrick J. Wong
  2013-10-12  0:07     ` Darrick J. Wong
  0 siblings, 1 reply; 67+ messages in thread
From: Darrick J. Wong @ 2013-10-11 23:43 UTC (permalink / raw)
  To: Zheng Liu; +Cc: linux-ext4, Theodore Ts'o, Zheng Liu

On Fri, Aug 02, 2013 at 05:49:33PM +0800, Zheng Liu wrote:
> From: Zheng Liu <wenqing.lz@taobao.com>
> 
> If there is an inode with inline data, we just print the size of inline
> data in stat command.
> 
> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
> ---
>  debugfs/debugfs.c        |   11 +++++++++++
>  lib/ext2fs/ext2fs.h      |    1 +
>  lib/ext2fs/inline_data.c |   27 +++++++++++++++++++++++++++
>  3 files changed, 39 insertions(+)
> 
> diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c
> index 969dbe0..2837ee6 100644
> --- a/debugfs/debugfs.c
> +++ b/debugfs/debugfs.c
> @@ -704,6 +704,15 @@ static void dump_extents(FILE *f, const char *prefix, ext2_ino_t ino,
>  		fprintf(f, "\n");
>  }
>  
> +static 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_inline_data_get_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)
> @@ -837,6 +846,8 @@ void internal_dump_inode(FILE *out, const char *prefix,
>  		if (inode->i_flags & EXT4_EXTENTS_FL)
>  			dump_extents(out, prefix, inode_num,
>  				     DUMP_LEAF_EXTENTS|DUMP_NODE_EXTENTS, 0, 0);
> +		else if (inode->i_flags & EXT4_INLINE_DATA_FL)
> +			dump_inline_data(out, prefix, inode_num);
>  		else
>  			dump_blocks(out, prefix, inode_num);
>  	}
> diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
> index 7b05b48..6e3bf6e 100644
> --- a/lib/ext2fs/ext2fs.h
> +++ b/lib/ext2fs/ext2fs.h
> @@ -1344,6 +1344,7 @@ extern errcode_t ext2fs_get_memalign(unsigned long size,
>  
>  /* inline_data.c */
>  extern int ext2fs_inode_has_inline_data(ext2_filsys fs, ext2_ino_t ino);
> +extern int ext2fs_inline_data_get_size(ext2_filsys fs, ext2_ino_t ino);
>  extern errcode_t 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 922c959..1220418 100644
> --- a/lib/ext2fs/inline_data.c
> +++ b/lib/ext2fs/inline_data.c
> @@ -80,6 +80,33 @@ 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_get_size(ext2_filsys fs, ext2_ino_t ino)
> +{
> +	struct ext2_inode_large *inode;
> +	struct inline_data data;
> +	errcode_t retval = 0;
> +	int size = 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;
> +
> +	if (inode->i_flags & EXT4_INLINE_DATA_FL) {
> +		retval = ext2fs_inline_data_find(fs, inode, &data);
> +		if (retval)
> +			goto out;
> +		size = data.inline_size;

Doesn't this miss the inline data in i_block?  Afaict ext2fs_inline_data_find
only picks up EA inline data.

--D

> +	}
> +
> +out:
> +	ext2fs_free_mem(&inode);
> +	return size;
> +}
> +
>  errcode_t ext2fs_inline_data_iterate(ext2_filsys fs,
>  			       ext2_ino_t ino,
>  			       int flags,
> -- 
> 1.7.9.7
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v1 06/22] debugfs: make stat command support inline data
  2013-10-11 23:43   ` Darrick J. Wong
@ 2013-10-12  0:07     ` Darrick J. Wong
  0 siblings, 0 replies; 67+ messages in thread
From: Darrick J. Wong @ 2013-10-12  0:07 UTC (permalink / raw)
  To: Zheng Liu; +Cc: linux-ext4, Theodore Ts'o, Zheng Liu

On Fri, Oct 11, 2013 at 04:43:53PM -0700, Darrick J. Wong wrote:
> On Fri, Aug 02, 2013 at 05:49:33PM +0800, Zheng Liu wrote:
> > From: Zheng Liu <wenqing.lz@taobao.com>
> > 
> > If there is an inode with inline data, we just print the size of inline
> > data in stat command.
> > 
> > Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> > Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
> > ---
> >  debugfs/debugfs.c        |   11 +++++++++++
> >  lib/ext2fs/ext2fs.h      |    1 +
> >  lib/ext2fs/inline_data.c |   27 +++++++++++++++++++++++++++
> >  3 files changed, 39 insertions(+)
> > 
> > diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c
> > index 969dbe0..2837ee6 100644
> > --- a/debugfs/debugfs.c
> > +++ b/debugfs/debugfs.c
> > @@ -704,6 +704,15 @@ static void dump_extents(FILE *f, const char *prefix, ext2_ino_t ino,
> >  		fprintf(f, "\n");
> >  }
> >  
> > +static 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_inline_data_get_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)
> > @@ -837,6 +846,8 @@ void internal_dump_inode(FILE *out, const char *prefix,
> >  		if (inode->i_flags & EXT4_EXTENTS_FL)
> >  			dump_extents(out, prefix, inode_num,
> >  				     DUMP_LEAF_EXTENTS|DUMP_NODE_EXTENTS, 0, 0);
> > +		else if (inode->i_flags & EXT4_INLINE_DATA_FL)
> > +			dump_inline_data(out, prefix, inode_num);
> >  		else
> >  			dump_blocks(out, prefix, inode_num);
> >  	}
> > diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
> > index 7b05b48..6e3bf6e 100644
> > --- a/lib/ext2fs/ext2fs.h
> > +++ b/lib/ext2fs/ext2fs.h
> > @@ -1344,6 +1344,7 @@ extern errcode_t ext2fs_get_memalign(unsigned long size,
> >  
> >  /* inline_data.c */
> >  extern int ext2fs_inode_has_inline_data(ext2_filsys fs, ext2_ino_t ino);
> > +extern int ext2fs_inline_data_get_size(ext2_filsys fs, ext2_ino_t ino);
> >  extern errcode_t 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 922c959..1220418 100644
> > --- a/lib/ext2fs/inline_data.c
> > +++ b/lib/ext2fs/inline_data.c
> > @@ -80,6 +80,33 @@ 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_get_size(ext2_filsys fs, ext2_ino_t ino)
> > +{
> > +	struct ext2_inode_large *inode;
> > +	struct inline_data data;
> > +	errcode_t retval = 0;
> > +	int size = 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;
> > +
> > +	if (inode->i_flags & EXT4_INLINE_DATA_FL) {
> > +		retval = ext2fs_inline_data_find(fs, inode, &data);
> > +		if (retval)
> > +			goto out;
> > +		size = data.inline_size;
> 
> Doesn't this miss the inline data in i_block?  Afaict ext2fs_inline_data_find
> only picks up EA inline data.

Never mind, I see that it does pick up both i_block + EA.

--D
> 
> --D
> 
> > +	}
> > +
> > +out:
> > +	ext2fs_free_mem(&inode);
> > +	return size;
> > +}
> > +
> >  errcode_t ext2fs_inline_data_iterate(ext2_filsys fs,
> >  			       ext2_ino_t ino,
> >  			       int flags,
> > -- 
> > 1.7.9.7
> > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v1 07/22] debugfs: make mkdir and expanddir command support inline data
  2013-08-02  9:49 ` [PATCH v1 07/22] debugfs: make mkdir and expanddir " Zheng Liu
@ 2013-10-12  0:21   ` Darrick J. Wong
  2013-10-12  7:15     ` Zheng Liu
  0 siblings, 1 reply; 67+ messages in thread
From: Darrick J. Wong @ 2013-10-12  0:21 UTC (permalink / raw)
  To: Zheng Liu; +Cc: linux-ext4, Theodore Ts'o, Zheng Liu

On Fri, Aug 02, 2013 at 05:49:34PM +0800, Zheng Liu wrote:
> From: Zheng Liu <wenqing.lz@taobao.com>
> 
> This commit tries to make mkdir and expanddir command support inline
> date feature.
> 
> In ext2fs_expand_dir() function ext2fs_inline_data_convert() will be
> called to expand a directory with inline data.  It tries to allocate
> a block and copy all directory entries into it.
> 
> In ext2fs_mkdir() it calls ext2fs_new_dir_inline_data() function to
> create a new directory with inline data.
> 
> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
> ---
>  lib/ext2fs/expanddir.c   |   18 +--
>  lib/ext2fs/ext2fs.h      |    5 +
>  lib/ext2fs/ext2fsP.h     |   13 +++
>  lib/ext2fs/inline_data.c |  280 ++++++++++++++++++++++++++++++++++++++++++++++
>  lib/ext2fs/mkdir.c       |  102 +++++++++++++----
>  lib/ext2fs/newdir.c      |   33 ++++++
>  6 files changed, 420 insertions(+), 31 deletions(-)
> 
> diff --git a/lib/ext2fs/expanddir.c b/lib/ext2fs/expanddir.c
> index 22558d6..9696b61 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_inline_data_convert(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 6e3bf6e..934dbd0 100644
> --- a/lib/ext2fs/ext2fs.h
> +++ b/lib/ext2fs/ext2fs.h
> @@ -1356,6 +1356,9 @@ extern errcode_t ext2fs_inline_data_iterate(ext2_filsys fs,
>  						  struct ext2_inode_large *inode,
>  						  void *priv_data),
>  				      void *priv_data);
> +extern errcode_t ext2fs_inline_data_create(ext2_filsys fs,
> +					   struct ext2_inode_large *inode,
> +					   unsigned int len);
>  
>  /* inode.c */
>  extern void ext2fs_free_inode_cache(struct ext2_inode_cache *icache);
> @@ -1430,6 +1433,8 @@ int ext2fs_native_flag(void);
>  /* newdir.c */
>  extern errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
>  				ext2_ino_t parent_ino, char **block);
> +extern errcode_t ext2fs_new_dir_inline_data(ext2_filsys fs, ext2_ino_t dir_ino,
> +				ext2_ino_t parent_ino, struct ext2_inode *inode);
>  
>  /* mkdir.c */
>  extern errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
> diff --git a/lib/ext2fs/ext2fsP.h b/lib/ext2fs/ext2fsP.h
> index e86d452..ed89272 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 {
> @@ -97,6 +108,8 @@ extern int ext2fs_process_dir_inline_data(ext2_filsys	fs,
>  extern errcode_t ext2fs_inline_data_find(ext2_filsys fs,
>  					 struct ext2_inode_large *inode,
>  					 struct inline_data *data);
> +extern errcode_t ext2fs_inline_data_convert(ext2_filsys fs, ext2_ino_t ino,
> +					    void *priv_data);
>  
>  /* Generic numeric progress meter */
>  
> diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c
> index 1220418..c936e28 100644
> --- a/lib/ext2fs/inline_data.c
> +++ b/lib/ext2fs/inline_data.c
> @@ -21,6 +21,14 @@
>  
>  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, char *buf,
> +					      int inline_size);
> +static void ext2fs_update_final_de(ext2_filsys fs, char *de_buf,
> +				   int old_size, int new_size);
> +static errcode_t ext2fs_inline_data_destory_data(ext2_filsys fs, ext2_ino_t ino,

Do you mean "destroy" and not "destory"?

> +					   struct ext2_inode_large *inode,
> +					   struct inline_data *data);
>  
>  errcode_t ext2fs_inline_data_find(ext2_filsys fs,
>  				  struct ext2_inode_large *inode,
> @@ -68,6 +76,48 @@ 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 = ENODATA,
> +	};
> +	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;
> +
> +	retval = ext2fs_ext_attr_ibody_find(fs, inode, &i, &s);
> +	if (retval)
> +		return retval;
> +
> +	if (!s.not_found) {
> +		retval = ext2fs_ext_attr_set_entry(&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;
> @@ -107,6 +157,83 @@ out:
>  	return size;
>  }
>  
> +static void ext2fs_update_final_de(ext2_filsys fs, char *de_buf,
> +				   int old_size, int new_size)

What does this update?  I think it changes the last dirent's rec_len so that it
covers the rest of the (new) block, but a comment would be helpful.

> +{
> +	struct ext2_dir_entry *de, *prev_de;
> +	char *limit;
> +	unsigned 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, char *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 = (char *)de - (char *)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);
> +	}
> +}
> +
>  errcode_t ext2fs_inline_data_iterate(ext2_filsys fs,
>  			       ext2_ino_t ino,
>  			       int flags,
> @@ -188,3 +315,156 @@ out:
>  	ext2fs_free_mem(&inode);
>  	return retval & BLOCK_ERROR ? ctx->errcode : 0;
>  }
> +
> +errcode_t ext2fs_inline_data_convert(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;
> +	char *backup_buf;
> +	char *blk_buf;
> +	unsigned int inline_size;
> +
> +	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_inline_data_find(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))

This should test the iflag.  Or, maybe it should use ext2fs_bmap2()?

> +		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);

This should only ever be called against directory blocks.  If this is a regular
file or a symlink, it'll probably complain about not finding the checksum
space.

> +	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);

ext2fs_bmap2()?

> +		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;
> +}
> +
> +errcode_t ext2fs_inline_data_create(ext2_filsys fs,
> +				    struct ext2_inode_large *inode,
> +				    unsigned int len)
> +{
> +	struct ext2_ext_attr_ibody_header *header;
> +	struct ext2_ext_attr_search s = {
> +		.not_found = ENODATA,
> +	};
> +	struct ext2_ext_attr_info i = {
> +		.name_index = EXT4_EXT_ATTR_INDEX_SYSTEM,
> +		.name = EXT4_EXT_ATTR_SYSTEM_DATA,
> +	};
> +	void *buf;
> +	errcode_t retval;
> +
> +	if (len > EXT4_MIN_INLINE_DATA_SIZE) {
> +		i.value = EXT2_ZERO_EXT_ATTR_VALUE;
> +		i.value_len = len - EXT4_MIN_INLINE_DATA_SIZE;
> +	} else {
> +		i.value = "";
> +		i.value_len = 0;
> +	}
> +
> +	retval = ext2fs_ext_attr_ibody_find(fs, inode, &i, &s);
> +	if (retval)
> +		return retval;
> +	retval = ext2fs_ext_attr_set_entry(&i, &s);
> +	if (retval)
> +		return retval;
> +
> +	header = IHDR(inode);
> +	if (!EXT2_EXT_IS_LAST_ENTRY(s.first))
> +		header->h_magic = EXT2_EXT_ATTR_MAGIC;
> +	else
> +		header->h_magic = 0;
> +
> +	return 0;
> +}
> diff --git a/lib/ext2fs/mkdir.c b/lib/ext2fs/mkdir.c
> index 4a85439..a6aeb0d 100644
> --- a/lib/ext2fs/mkdir.c
> +++ b/lib/ext2fs/mkdir.c
> @@ -36,11 +36,13 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
>  {
>  	ext2_extent_handle_t	handle;
>  	errcode_t		retval;
> -	struct ext2_inode	parent_inode, inode;
> +	struct ext2_inode	parent_inode, *inode = NULL;
> +	struct ext2_inode_large *large_inode = NULL;
>  	ext2_ino_t		ino = 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);
>  
> @@ -55,16 +57,38 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
>  	}
>  
>  	/*
> +	 * We try to create a new directory with inline data if this feature
> +	 * is enabled.  Here we don't try to do this if ino < first_ino or
> +	 * the directory name is 'lost+found'.
> +	 */
> +	if (fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_INLINE_DATA &&
> +	    ino >= EXT2_FIRST_INO(fs->super) && strcmp("lost+found", name) != 0)
> +		inline_data = 1;

What if I mkdir -p /mnt/sub/dir/lost+found ?

> +
> +	/*
>  	 * Allocate a data block for the directory
>  	 */
> -	retval = ext2fs_new_block2(fs, 0, 0, &blk);
> +	if (!inline_data) {
> +		retval = ext2fs_new_block2(fs, 0, 0, &blk);
> +		if (retval)
> +			goto cleanup;
> +	}
> +
> +	/*
> +	 * Allocate a new inode structuure
> +	 */
> +	retval = ext2fs_get_memzero(EXT2_INODE_SIZE(fs->super), &large_inode);
>  	if (retval)
>  		goto cleanup;
> +	inode = (struct ext2_inode *) large_inode;
>  
>  	/*
>  	 * Create a scratch template for the directory
>  	 */
> -	retval = ext2fs_new_dir_block(fs, ino, parent, &block);
> +	if (inline_data)
> +		retval = ext2fs_new_dir_inline_data(fs, ino, parent, inode);
> +	else
> +		retval = ext2fs_new_dir_block(fs, ino, parent, &block);
>  	if (retval)
>  		goto cleanup;
>  
> @@ -81,37 +105,61 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
>  	/*
>  	 * Create the inode structure....
>  	 */
> -	memset(&inode, 0, sizeof(struct ext2_inode));
> -	inode.i_mode = LINUX_S_IFDIR | (0777 & ~fs->umask);
> -	inode.i_uid = inode.i_gid = 0;
> -	ext2fs_iblk_set(fs, &inode, 1);
> -	if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS)
> -		inode.i_flags |= EXT4_EXTENTS_FL;
> +	inode->i_mode = LINUX_S_IFDIR | (0777 & ~fs->umask);
> +	inode->i_uid = inode->i_gid = 0;
> +	ext2fs_iblk_set(fs, inode, 1);

Just to confirm, i_blocks should be nonzero for inline data?

> +	if (inline_data)
> +		inode->i_flags |= EXT4_INLINE_DATA_FL;
> +	else if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS)
> +		inode->i_flags |= EXT4_EXTENTS_FL;
>  	else
> -		inode.i_block[0] = blk;
> -	inode.i_links_count = 2;
> -	inode.i_size = fs->blocksize;
> +		inode->i_block[0] = blk;
> +	inode->i_links_count = 2;
>  
>  	/*
>  	 * Write out the inode and inode data block.  The inode generation
>  	 * number is assigned by write_new_inode, which means that the call
>  	 * to write_dir_block must come after that.
> +	 *
> +	 * If we try to create an new inode with inline data, we should call
> +	 * ext2fs_write_inode_full to avoid to initialize extra part.
>  	 */
> -	retval = ext2fs_write_new_inode(fs, ino, &inode);
> -	if (retval)
> -		goto cleanup;
> -	retval = ext2fs_write_dir_block4(fs, blk, block, 0, ino);
> -	if (retval)
> -		goto cleanup;
> +	if (inline_data) {
> +		__u32 t = fs->now ? fs->now : time(NULL);
> +
> +		inode->i_size = EXT4_MIN_INLINE_DATA_SIZE;
> +		inode->i_blocks = 0;
> +		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 (!large_inode->i_crtime)
> +			large_inode->i_crtime = t;
> +		retval = ext2fs_write_inode_full(fs, ino, inode,
> +						 EXT2_INODE_SIZE(fs->super));
> +		if (retval)
> +			goto cleanup;
> +	} else {
> +		inode->i_size = fs->blocksize;
>  
> -	if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) {
> -		retval = ext2fs_extent_open2(fs, ino, &inode, &handle);
> +		retval = ext2fs_write_new_inode(fs, ino, inode);
>  		if (retval)
>  			goto cleanup;
> -		retval = ext2fs_extent_set_bmap(handle, 0, blk, 0);
> -		ext2fs_extent_free(handle);
> +		retval = ext2fs_write_dir_block4(fs, blk, block, 0, ino);
>  		if (retval)
>  			goto cleanup;
> +
> +		if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) {

ext2fs_bmap()? Or, test the iflag.

> +			retval = ext2fs_extent_open2(fs, ino, inode, &handle);
> +			if (retval)
> +				goto cleanup;
> +			retval = ext2fs_extent_set_bmap(handle, 0, blk, 0);
> +			ext2fs_extent_free(handle);
> +			if (retval)
> +				goto cleanup;
> +		}
>  	}
>  
>  	/*
> @@ -136,6 +184,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,14 +197,16 @@ 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:
> +	if (large_inode)
> +		ext2fs_free_mem(&large_inode);
>  	if (block)
>  		ext2fs_free_mem(&block);
>  	return retval;
> -
>  }
>  
>  
> diff --git a/lib/ext2fs/newdir.c b/lib/ext2fs/newdir.c
> index 2cd541d..cec99e9 100644
> --- a/lib/ext2fs/newdir.c
> +++ b/lib/ext2fs/newdir.c
> @@ -87,3 +87,36 @@ errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
>  	*block = buf;
>  	return 0;
>  }
> +
> +/*
> + * Create new directory in inode
> + */
> +errcode_t ext2fs_new_dir_inline_data(ext2_filsys fs,
> +				     ext2_ino_t dir_ino,
> +				     ext2_ino_t parent_ino,
> +				     struct ext2_inode *inode)
> +{
> +	struct ext2_inode_large *large_inode;
> +	struct ext2_dir_entry *dir = NULL;
> +	int inline_size = EXT4_MIN_INLINE_DATA_SIZE;
> +	errcode_t retval;
> +
> +	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
> +
> +	large_inode = (struct ext2_inode_large *) inode;
> +	large_inode->i_extra_isize = sizeof(struct ext2_inode_large) -
> +		EXT2_GOOD_OLD_INODE_SIZE;
> +	retval = ext2fs_inline_data_create(fs, large_inode, inline_size);
> +	if (retval)
> +		return retval;
> +
> +	dir = (struct ext2_dir_entry *) inode->i_block;
> +	dir->inode = parent_ino;
> +
> +	dir = (struct ext2_dir_entry *) ((char *) dir +
> +					 EXT4_INLINE_DATA_DOTDOT_SIZE);
> +	dir->inode = 0;
> +	dir->rec_len = inline_size - EXT4_INLINE_DATA_DOTDOT_SIZE;
> +
> +	return retval;
> +}
> -- 
> 1.7.9.7
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v1 14/22] mke2fs: add inline_data support in mke2fs
  2013-08-02  9:49 ` [PATCH v1 14/22] mke2fs: add inline_data support in mke2fs Zheng Liu
@ 2013-10-12  0:27   ` Darrick J. Wong
  2013-10-12  8:08     ` Zheng Liu
  0 siblings, 1 reply; 67+ messages in thread
From: Darrick J. Wong @ 2013-10-12  0:27 UTC (permalink / raw)
  To: Zheng Liu; +Cc: linux-ext4, Theodore Ts'o, Zheng Liu

On Fri, Aug 02, 2013 at 05:49:41PM +0800, Zheng Liu wrote:
> From: Zheng Liu <wenqing.lz@taobao.com>
> 
> Inline_data feature doesn't be specified without ext_attr.
> 
> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
> ---
>  misc/mke2fs.8.in |    3 +++
>  misc/mke2fs.c    |   14 +++++++++++++-
>  2 files changed, 16 insertions(+), 1 deletion(-)
> 
> diff --git a/misc/mke2fs.8.in b/misc/mke2fs.8.in
> index 023ba49..5731542 100644
> --- a/misc/mke2fs.8.in
> +++ b/misc/mke2fs.8.in
> @@ -578,6 +578,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

"..to be stored in the inode and extended attribute areas" ?

> +.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 a59d24c..cb084ea 100644
> --- a/misc/mke2fs.c
> +++ b/misc/mke2fs.c
> @@ -902,7 +902,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|
> @@ -2042,6 +2043,17 @@ profile_error:
>  		exit(1);
>  	}
>  
> +	/* Since inline_data depends on ext_attr, we would ask it to be
> +	 * enabled.

/*
 * Comment
 */

There needs to be an extra newline after the '/*' at the top of that multiline
comment.

> +	 */
> +	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"));

"The inline_data feature requires the ext_attr feature." ?

--D

> +		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.9.7
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v1 10/22] debugfs: handle inline_data feature in dirsearch command
  2013-08-02  9:49 ` [PATCH v1 10/22] debugfs: handle inline_data feature in dirsearch command Zheng Liu
@ 2013-10-12  0:30   ` Darrick J. Wong
  2013-10-12  7:21     ` Zheng Liu
  0 siblings, 1 reply; 67+ messages in thread
From: Darrick J. Wong @ 2013-10-12  0:30 UTC (permalink / raw)
  To: Zheng Liu; +Cc: linux-ext4, Theodore Ts'o, Zheng Liu

On Fri, Aug 02, 2013 at 05:49:37PM +0800, Zheng Liu wrote:
> From: Zheng Liu <wenqing.lz@taobao.com>
> 
> We don't need to support inline data in dirsearch command.

What if I want to dirsearch for a directory entry?  Shouldn't debugfs print
more than nothing?  I don't see why I shouldn't be able to search an inline
directory?

--D
> 
> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
> ---
>  debugfs/htree.c |    4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/debugfs/htree.c b/debugfs/htree.c
> index d94dbea..b226f1d 100644
> --- a/debugfs/htree.c
> +++ b/debugfs/htree.c
> @@ -387,9 +387,13 @@ 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))
> +		goto out;
> +
>  	ext2fs_block_iterate3(current_fs, inode, BLOCK_FLAG_READ_ONLY, 0,
>  			      search_dir_block, &pb);
>  
> +out:
>  	free(pb.buf);
>  }
>  
> -- 
> 1.7.9.7
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v1 12/22] debugfs: handle inline_data in punch command
  2013-08-02  9:49 ` [PATCH v1 12/22] debugfs: handle inline_data in punch command Zheng Liu
@ 2013-10-12  0:37   ` Darrick J. Wong
  2013-10-12  7:22     ` Zheng Liu
  0 siblings, 1 reply; 67+ messages in thread
From: Darrick J. Wong @ 2013-10-12  0:37 UTC (permalink / raw)
  To: Zheng Liu; +Cc: linux-ext4, Theodore Ts'o, Zheng Liu

On Fri, Aug 02, 2013 at 05:49:39PM +0800, Zheng Liu wrote:
> From: Zheng Liu <wenqing.lz@taobao.com>
> 
> Now punch command only can truncate an inode with inline_data.  The
> start block must be 0 because the size of an inode shouldn't be greater
> than one block.
> 
> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
> ---
>  lib/ext2fs/ext2fsP.h     |    3 +++
>  lib/ext2fs/inline_data.c |    9 +++----
>  lib/ext2fs/punch.c       |   59 ++++++++++++++++++++++++++++++++++++++++++++--
>  3 files changed, 63 insertions(+), 8 deletions(-)
> 
> diff --git a/lib/ext2fs/ext2fsP.h b/lib/ext2fs/ext2fsP.h
> index ed89272..1e5aa32 100644
> --- a/lib/ext2fs/ext2fsP.h
> +++ b/lib/ext2fs/ext2fsP.h
> @@ -110,6 +110,9 @@ extern errcode_t ext2fs_inline_data_find(ext2_filsys fs,
>  					 struct inline_data *data);
>  extern errcode_t ext2fs_inline_data_convert(ext2_filsys fs, ext2_ino_t ino,
>  					    void *priv_data);
> +extern errcode_t ext2fs_inline_data_destory_data(ext2_filsys fs, ext2_ino_t ino,

"destroy", not "destory" ?

> +					   struct ext2_inode_large *inode,
> +					   struct inline_data *data);
>  
>  /* Generic numeric progress meter */
>  
> diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c
> index 5ca95ee..52ac133 100644
> --- a/lib/ext2fs/inline_data.c
> +++ b/lib/ext2fs/inline_data.c
> @@ -28,9 +28,6 @@ static void ext2fs_inline_data_finish_convert(ext2_filsys fs, ext2_ino_t ino,
>  					      int inline_size);
>  static void ext2fs_update_final_de(ext2_filsys fs, char *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);
>  
>  errcode_t ext2fs_inline_data_find(ext2_filsys fs,
>  				  struct ext2_inode_large *inode,
> @@ -78,9 +75,9 @@ 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)
> +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 = {
> diff --git a/lib/ext2fs/punch.c b/lib/ext2fs/punch.c
> index b53653a..3bfbd4d 100644
> --- a/lib/ext2fs/punch.c
> +++ b/lib/ext2fs/punch.c
> @@ -19,6 +19,7 @@
>  
>  #include "ext2_fs.h"
>  #include "ext2fs.h"
> +#include "ext2fsP.h"
>  
>  #undef PUNCH_DEBUG
>  
> @@ -281,7 +282,59 @@ errout:
>  	ext2fs_extent_free(handle);
>  	return retval;
>  }
> -	
> +
> +static 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;
> +
> +	/*
> +	 * 'start' must be 0 because here it's a block and the size of
> +	 * an inode shouldn't greater than a block.
> +	 */
> +	if (start != 0)
> +		return 0;
> +
> +	/* Punching hole for inline_data is not supported */
> +	if ((unsigned int)end != ~0U)
> +		return EXT2_ET_OP_NOT_SUPPORTED;

Um... shouldn't this be ~0ULL since end is blk64_t?

For an inline_data file I doubt it matters, but ripping off high bits looks
suspicious to me.

--D

> +
> +	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_inline_data_find(fs, inode, &data);
> +	if (retval)
> +		goto out;
> +
> +	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;
> +	}
> +
> +	retval = ext2fs_inline_data_destory_data(fs, ino, inode, &data);
> +	if (retval)
> +		goto out;
> +
> +	inode->i_size = 0;
> +	retval = ext2fs_write_inode_full(fs, ino, (void *)inode,
> +					 EXT2_INODE_SIZE(fs->super));
> +out:
> +	ext2fs_free_mem(&inode);
> +	return retval;
> +}
> +
>  /*
>   * Deallocate all logical blocks starting at start to end, inclusive.
>   * If end is ~0, then this is effectively truncate.
> @@ -307,7 +360,9 @@ 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)
> +		return ext2fs_punch_inline_data(fs, ino, start, end);
> +	else if (inode->i_flags & EXT4_EXTENTS_FL)
>  		retval = ext2fs_punch_extent(fs, ino, inode, start, end);
>  	else {
>  		blk_t	count;
> -- 
> 1.7.9.7
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v1 15/22] tune2fs: add inline_data feature in tune2fs
  2013-08-02  9:49 ` [PATCH v1 15/22] tune2fs: add inline_data feature in tune2fs Zheng Liu
@ 2013-10-12  0:39   ` Darrick J. Wong
  2013-10-12  8:16     ` Zheng Liu
  0 siblings, 1 reply; 67+ messages in thread
From: Darrick J. Wong @ 2013-10-12  0:39 UTC (permalink / raw)
  To: Zheng Liu; +Cc: linux-ext4, Theodore Ts'o, Zheng Liu

On Fri, Aug 02, 2013 at 05:49:42PM +0800, Zheng Liu wrote:
> 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: Theodore Ts'o <tytso@mit.edu>
> Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
> ---
>  misc/tune2fs.8.in |    5 +++++
>  misc/tune2fs.c    |   17 ++++++++++++++++-
>  2 files changed, 21 insertions(+), 1 deletion(-)
> 
> 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 7d6520e..f22a736 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|
> @@ -995,6 +996,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.
> +		 */

Multiline comment issue.

> +		if (!(fs->super->s_feature_compat &
> +		      EXT2_FEATURE_COMPAT_EXT_ATTR)) {

EXT2_HAS_COMPAT_FEATURE()?

> +			fputs(_("The inline_data feature cannot "
> +				"be set if ext_attr feature is disabled.\n"),
> +				stderr);
> +			return 1;
> +		}
> +	}
> +

Maybe I'm missing something, but I don't see anything prohibiting the user from
disabling inline_data?  Or from doing the conversion?

--D

>  	if (FEATURE_ON(E2P_FEATURE_RO_INCOMPAT,
>  				EXT4_FEATURE_RO_COMPAT_QUOTA)) {
>  		/*
> -- 
> 1.7.9.7
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v1 17/22] e2fsck: check inline_data in pass1
  2013-08-02  9:49 ` [PATCH v1 17/22] e2fsck: check inline_data in pass1 Zheng Liu
@ 2013-10-12  0:47   ` Darrick J. Wong
  2013-10-12  8:17     ` Zheng Liu
  0 siblings, 1 reply; 67+ messages in thread
From: Darrick J. Wong @ 2013-10-12  0:47 UTC (permalink / raw)
  To: Zheng Liu; +Cc: linux-ext4, Theodore Ts'o, Zheng Liu

On Fri, Aug 02, 2013 at 05:49:44PM +0800, Zheng Liu wrote:
> From: Zheng Liu <wenqing.lz@taobao.com>
> 
> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
> ---
>  e2fsck/pass1.c          |   70 ++++++++++++++++++++++++++++++++++++++++++++---
>  lib/ext2fs/dblist_dir.c |   10 +++++--
>  2 files changed, 74 insertions(+), 6 deletions(-)
> 
> diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
> index e6ea460..4301bb9 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) {
> +		unsigned int inline_size;
> +
> +		inline_size = ext2fs_inline_data_get_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) ||
> @@ -303,6 +313,15 @@ 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 the content of inline data right.
> +		 */
> +		if (strncmp(EXT2_EXT_ATTR_NAME(entry),
> +		    EXT4_EXT_ATTR_SYSTEM_DATA,
> +		    strlen(EXT4_EXT_ATTR_SYSTEM_DATA)) == 0)

Please align arguments 2 and 3 with argument 1 of strcmp.

--D
> +			goto next;
> +
>  		/* attribute len eats this space */
>  		remain -= EXT2_EXT_ATTR_SIZE(entry->e_name_len);
>  
> @@ -330,6 +349,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);
> @@ -407,6 +427,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
> @@ -434,11 +455,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))
> @@ -1205,7 +1234,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])
> @@ -1214,6 +1244,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] ||
> @@ -2129,6 +2160,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.
>   */
> @@ -2142,6 +2195,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;
> @@ -2165,6 +2219,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 &
> @@ -2188,6 +2244,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,
> @@ -2230,7 +2289,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--;
> @@ -2256,7 +2316,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.9.7
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v1 19/22] e2fsck: check inline_data in pass3
  2013-08-02  9:49 ` [PATCH v1 19/22] e2fsck: check inline_data in pass3 Zheng Liu
@ 2013-10-12  0:54   ` Darrick J. Wong
  2013-10-12  9:06     ` Zheng Liu
  0 siblings, 1 reply; 67+ messages in thread
From: Darrick J. Wong @ 2013-10-12  0:54 UTC (permalink / raw)
  To: Zheng Liu; +Cc: linux-ext4, Theodore Ts'o, Zheng Liu

On Fri, Aug 02, 2013 at 05:49:46PM +0800, Zheng Liu wrote:
> From: Zheng Liu <wenqing.lz@taobao.com>
> 
> In e2fsck_expand_directory() we don't handle a dir with inline data
> because when this function is called the directory inode shouldn't
> contains inline data.
> 
> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
> ---
>  e2fsck/pass3.c  |   12 ++++++++++++
>  e2fsck/rehash.c |    3 ++-
>  2 files changed, 14 insertions(+), 1 deletion(-)
> 
> diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c
> index a379e9b..5052345 100644
> --- a/e2fsck/pass3.c
> +++ b/e2fsck/pass3.c
> @@ -787,6 +787,18 @@ errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
>  	es.ctx = ctx;
>  	es.dir = dir;
>  
> +	/*
> +	 * 'lost+found' dir shouldn't contains inline data.  So we
> +	 * need to clear this flag.
> +	 */
> +	if (ext2fs_inode_has_inline_data(fs, dir)) {
> +		retval = ext2fs_read_inode(fs, dir, &inode);
> +		if (retval)
> +			return retval;
> +		inode.i_flags &= ~EXT4_INLINE_DATA_FL;
> +		e2fsck_write_inode(ctx, dir, &inode, "clear inline_data flag");
> +	}
> +
>  	retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND,
>  				       0, expand_dir_proc, &es);

Are you saying that lost+found can have inline_data set yet i_blocks is
actually a block map/extent head?  Or are we supposed to zero i_blocks?

If we clear EXT4_INLINE_DATA_FL and then try to iterate blocks, are we setting
ourselves up to read (formerly inline) dirents as a block map and iterate it?

Shouldn't we care if the inode write fails?

--D

>  
> diff --git a/e2fsck/rehash.c b/e2fsck/rehash.c
> index 5592e3f..82aeddd 100644
> --- a/e2fsck/rehash.c
> +++ b/e2fsck/rehash.c
> @@ -937,7 +937,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.9.7
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v1 03/22] libext2fs: add functions to operate on extended attribute
  2013-10-11 22:51   ` Darrick J. Wong
@ 2013-10-12  5:51     ` Zheng Liu
  2013-10-12  8:32       ` Darrick J. Wong
  0 siblings, 1 reply; 67+ messages in thread
From: Zheng Liu @ 2013-10-12  5:51 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-ext4, Zheng Liu, Theodore Ts'o

On Fri, Oct 11, 2013 at 03:51:15PM -0700, Darrick J. Wong wrote:
> On Fri, Aug 02, 2013 at 05:49:30PM +0800, Zheng Liu wrote:
> > From: Zheng Liu <wenqing.lz@taobao.com>
> > 
> > We need to define some functions to operate extended attribute in order
> > to support inline data.
> > 
> > Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
> > Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> > ---
> >  lib/ext2fs/ext2_err.et.in  |    3 +
> >  lib/ext2fs/ext2_ext_attr.h |   31 ++++++++
> >  lib/ext2fs/ext2fs.h        |    9 +++
> >  lib/ext2fs/ext_attr.c      |  186 ++++++++++++++++++++++++++++++++++++++++++++
> >  4 files changed, 229 insertions(+)
> > 
> > diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in
> > index d20c6b7..7e6d6e5 100644
> > --- a/lib/ext2fs/ext2_err.et.in
> > +++ b/lib/ext2fs/ext2_err.et.in
> > @@ -476,4 +476,7 @@ ec	EXT2_ET_MMP_CSUM_INVALID,
> >  ec	EXT2_ET_FILE_EXISTS,
> >  	"Ext2 file already exists"
> >  
> > +ec	EXT2_ET_EXT_ATTR_CURRUPTED,
> > +	"Extended attribute currupted"
> > +
> >  	end
> > diff --git a/lib/ext2fs/ext2_ext_attr.h b/lib/ext2fs/ext2_ext_attr.h
> > index bbb0aaa..99ad849 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,29 @@ 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 *) \
> > +		((char *)inode + \
> > +		EXT2_GOOD_OLD_INODE_SIZE + \
> > +		inode->i_extra_isize))
> > +#define IFIRST(hdr) ((struct ext2_ext_attr_entry *)((hdr)+1))
> > +#define EXT2_ZERO_EXT_ATTR_VALUE ((void *)-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 3346c00..8c30197 100644
> > --- a/lib/ext2fs/ext2fs.h
> > +++ b/lib/ext2fs/ext2fs.h
> > @@ -1136,6 +1136,15 @@ 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_ext_attr_ibody_find(ext2_filsys fs,
> > +					    struct ext2_inode_large *inode,
> > +					    struct ext2_ext_attr_info *i,
> > +					    struct ext2_ext_attr_search *s);
> > +extern errcode_t ext2fs_ext_attr_find_entry(struct ext2_ext_attr_entry **pentry,
> > +					    int name_index, const char *name,
> > +					    size_t size, int sorted);
> > +extern errcode_t ext2fs_ext_attr_set_entry(struct ext2_ext_attr_info *i,
> > +					   struct ext2_ext_attr_search *s);
> >  
> >  /* 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..6d55340 100644
> > --- a/lib/ext2fs/ext_attr.c
> > +++ b/lib/ext2fs/ext_attr.c
> > @@ -186,3 +186,189 @@ errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
> >  	return ext2fs_adjust_ea_refcount2(fs, blk, block_buf, adjust,
> >  					  newcount);
> >  }
> > +
> > +static errcode_t
> > +ext2fs_ext_attr_check_names(struct ext2_ext_attr_entry *entry, void *end)
> > +{
> > +	while (!EXT2_EXT_IS_LAST_ENTRY(entry)) {
> > +		struct ext2_ext_attr_entry *next = EXT2_EXT_ATTR_NEXT(entry);
> > +		if ((void *)next >= end)
> > +			return EXT2_ET_EXT_ATTR_CURRUPTED;
> > +		entry = next;
> > +	}
> > +	return 0;
> > +}
> > +
> > +static inline errcode_t
> > +ext2fs_ext_attr_check_entry(struct ext2_ext_attr_entry *entry, size_t size)
> > +{
> > +	size_t value_size = entry->e_value_size;
> > +
> > +	if (entry->e_value_block != 0 || value_size > size ||
> > +	    entry->e_value_offs + value_size > size)
> > +		return EXT2_ET_EXT_ATTR_CURRUPTED;
> > +	return 0;
> > +}
> > +
> > +errcode_t ext2fs_ext_attr_find_entry(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 = 1;
> > +
> > +	if (name == NULL)
> > +		return EXT2_ET_INVALID_ARGUMENT;
> > +	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 <= 0 && (sorted || cmp == 0))
> > +			break;
> > +	}
> > +	*pentry = entry;
> > +	if (!cmp && ext2fs_ext_attr_check_entry(entry, size))
> > +		return EXT2_ET_EXT_ATTR_CURRUPTED;
> > +	return cmp ? ENODATA : 0;
> > +}
> > +
> > +errcode_t ext2fs_ext_attr_ibody_find(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;
> > +	errcode_t error;
> > +
> > +	if (inode->i_extra_isize == 0)
> > +		return 0;
> > +	header = IHDR(inode);
> > +	s->base = s->first = IFIRST(header);
> > +	s->here = s->first;
> > +	s->end = (char *)inode + EXT2_INODE_SIZE(fs->super);
> > +
> > +	error = ext2fs_ext_attr_check_names(IFIRST(header), s->end);
> > +	if (error)
> > +		return error;
> > +	/* Find the named attribute. */
> > +	error = ext2fs_ext_attr_find_entry(&s->here, i->name_index,
> > +					   i->name, (char *)s->end -
> > +					   (char *)s->base, 0);
> > +	if (error && error != ENODATA)
> > +		return error;
> > +	s->not_found = error;
> > +	return 0;
> 
> Huh.  It just occurred to me (yes, after three months, sorry...) that your
> patchset doesn't deal with EAs that live in a separate block.  For the purposes
> of inline_data I suppose that's sufficient, but if we're going to add an API to
> mess with EAs, we ought to be able to handle all of a file's EAs.
> 
> The implementation that I wrote for fuse2fs does this, but it has no facility
> to ensure that the inline data ends up in the ibody and not the EA block.
> Though really, they're written out in array order, so it wouldn't be difficult
> to sort before writing, or use some knapsack variant.

Sorry, I still havn't had a chance to take a closer look at your patch
set for e2fsprogs.  I will review it ASAP.

> 
> I think I might be drifting towards the idea of attaching your patch series to
> the end of mine, but as yours is already in -pu I'm open to discussing how to
> reconcile our implementations.

I agree with you that we need to reconcile our implementation.  I was
wondering if we really need to add all APIs for EAs in e2fsprogs when I
added these functions.  But now it seems that we do need them.

> 
> I _do_ like the comments you added to ext2fs_ext_attr_set_entry() though. :)

Yes, there is no any difficulty to add this API. :-)

Regards,
                                                - Zheng

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

* Re: [PATCH v1 04/22] libext2fs: handle inline data in dir iterator function
  2013-10-11 23:33   ` Darrick J. Wong
@ 2013-10-12  5:55     ` Zheng Liu
  0 siblings, 0 replies; 67+ messages in thread
From: Zheng Liu @ 2013-10-12  5:55 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-ext4, Theodore Ts'o, Zheng Liu

On Fri, Oct 11, 2013 at 04:33:42PM -0700, Darrick J. Wong wrote:
[..]
> > +errcode_t ext2fs_inline_data_iterate(ext2_filsys fs,
> > +			       ext2_ino_t ino,
> > +			       int flags,
> > +			       char *block_buf,
> > +			       int (*func)(ext2_filsys fs,
> > +					   char *buf,
> > +					   unsigned 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;
> 
> Perhaps this function should be called ext2fs_inline_dirblock_iterate()?
> The name alone makes me think this function could work for regular inline_data
> files, if such things ever exist.

Fair enough.  I will fix it in next version.

Thanks,
                                                - Zheng

> 
> --D
> 
> > +
> > +	inline_start = (char *)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_inline_data_find(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.9.7
> > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v1 07/22] debugfs: make mkdir and expanddir command support inline data
  2013-10-12  0:21   ` Darrick J. Wong
@ 2013-10-12  7:15     ` Zheng Liu
  0 siblings, 0 replies; 67+ messages in thread
From: Zheng Liu @ 2013-10-12  7:15 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-ext4, Theodore Ts'o, Zheng Liu

Good catch!  I will fix the following problems in the next version.

Thanks,
                                                - Zheng

On Fri, Oct 11, 2013 at 05:21:02PM -0700, Darrick J. Wong wrote:
> On Fri, Aug 02, 2013 at 05:49:34PM +0800, Zheng Liu wrote:
> > From: Zheng Liu <wenqing.lz@taobao.com>
> > 
> > This commit tries to make mkdir and expanddir command support inline
> > date feature.
> > 
> > In ext2fs_expand_dir() function ext2fs_inline_data_convert() will be
> > called to expand a directory with inline data.  It tries to allocate
> > a block and copy all directory entries into it.
> > 
> > In ext2fs_mkdir() it calls ext2fs_new_dir_inline_data() function to
> > create a new directory with inline data.
> > 
> > Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> > Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
> > ---
> >  lib/ext2fs/expanddir.c   |   18 +--
> >  lib/ext2fs/ext2fs.h      |    5 +
> >  lib/ext2fs/ext2fsP.h     |   13 +++
> >  lib/ext2fs/inline_data.c |  280 ++++++++++++++++++++++++++++++++++++++++++++++
> >  lib/ext2fs/mkdir.c       |  102 +++++++++++++----
> >  lib/ext2fs/newdir.c      |   33 ++++++
> >  6 files changed, 420 insertions(+), 31 deletions(-)
> > 
> > diff --git a/lib/ext2fs/expanddir.c b/lib/ext2fs/expanddir.c
> > index 22558d6..9696b61 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_inline_data_convert(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 6e3bf6e..934dbd0 100644
> > --- a/lib/ext2fs/ext2fs.h
> > +++ b/lib/ext2fs/ext2fs.h
> > @@ -1356,6 +1356,9 @@ extern errcode_t ext2fs_inline_data_iterate(ext2_filsys fs,
> >  						  struct ext2_inode_large *inode,
> >  						  void *priv_data),
> >  				      void *priv_data);
> > +extern errcode_t ext2fs_inline_data_create(ext2_filsys fs,
> > +					   struct ext2_inode_large *inode,
> > +					   unsigned int len);
> >  
> >  /* inode.c */
> >  extern void ext2fs_free_inode_cache(struct ext2_inode_cache *icache);
> > @@ -1430,6 +1433,8 @@ int ext2fs_native_flag(void);
> >  /* newdir.c */
> >  extern errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
> >  				ext2_ino_t parent_ino, char **block);
> > +extern errcode_t ext2fs_new_dir_inline_data(ext2_filsys fs, ext2_ino_t dir_ino,
> > +				ext2_ino_t parent_ino, struct ext2_inode *inode);
> >  
> >  /* mkdir.c */
> >  extern errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
> > diff --git a/lib/ext2fs/ext2fsP.h b/lib/ext2fs/ext2fsP.h
> > index e86d452..ed89272 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 {
> > @@ -97,6 +108,8 @@ extern int ext2fs_process_dir_inline_data(ext2_filsys	fs,
> >  extern errcode_t ext2fs_inline_data_find(ext2_filsys fs,
> >  					 struct ext2_inode_large *inode,
> >  					 struct inline_data *data);
> > +extern errcode_t ext2fs_inline_data_convert(ext2_filsys fs, ext2_ino_t ino,
> > +					    void *priv_data);
> >  
> >  /* Generic numeric progress meter */
> >  
> > diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c
> > index 1220418..c936e28 100644
> > --- a/lib/ext2fs/inline_data.c
> > +++ b/lib/ext2fs/inline_data.c
> > @@ -21,6 +21,14 @@
> >  
> >  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, char *buf,
> > +					      int inline_size);
> > +static void ext2fs_update_final_de(ext2_filsys fs, char *de_buf,
> > +				   int old_size, int new_size);
> > +static errcode_t ext2fs_inline_data_destory_data(ext2_filsys fs, ext2_ino_t ino,
> 
> Do you mean "destroy" and not "destory"?
> 
> > +					   struct ext2_inode_large *inode,
> > +					   struct inline_data *data);
> >  
> >  errcode_t ext2fs_inline_data_find(ext2_filsys fs,
> >  				  struct ext2_inode_large *inode,
> > @@ -68,6 +76,48 @@ 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 = ENODATA,
> > +	};
> > +	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;
> > +
> > +	retval = ext2fs_ext_attr_ibody_find(fs, inode, &i, &s);
> > +	if (retval)
> > +		return retval;
> > +
> > +	if (!s.not_found) {
> > +		retval = ext2fs_ext_attr_set_entry(&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;
> > @@ -107,6 +157,83 @@ out:
> >  	return size;
> >  }
> >  
> > +static void ext2fs_update_final_de(ext2_filsys fs, char *de_buf,
> > +				   int old_size, int new_size)
> 
> What does this update?  I think it changes the last dirent's rec_len so that it
> covers the rest of the (new) block, but a comment would be helpful.
> 
> > +{
> > +	struct ext2_dir_entry *de, *prev_de;
> > +	char *limit;
> > +	unsigned 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, char *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 = (char *)de - (char *)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);
> > +	}
> > +}
> > +
> >  errcode_t ext2fs_inline_data_iterate(ext2_filsys fs,
> >  			       ext2_ino_t ino,
> >  			       int flags,
> > @@ -188,3 +315,156 @@ out:
> >  	ext2fs_free_mem(&inode);
> >  	return retval & BLOCK_ERROR ? ctx->errcode : 0;
> >  }
> > +
> > +errcode_t ext2fs_inline_data_convert(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;
> > +	char *backup_buf;
> > +	char *blk_buf;
> > +	unsigned int inline_size;
> > +
> > +	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_inline_data_find(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))
> 
> This should test the iflag.  Or, maybe it should use ext2fs_bmap2()?
> 
> > +		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);
> 
> This should only ever be called against directory blocks.  If this is a regular
> file or a symlink, it'll probably complain about not finding the checksum
> space.
> 
> > +	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);
> 
> ext2fs_bmap2()?
> 
> > +		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;
> > +}
> > +
> > +errcode_t ext2fs_inline_data_create(ext2_filsys fs,
> > +				    struct ext2_inode_large *inode,
> > +				    unsigned int len)
> > +{
> > +	struct ext2_ext_attr_ibody_header *header;
> > +	struct ext2_ext_attr_search s = {
> > +		.not_found = ENODATA,
> > +	};
> > +	struct ext2_ext_attr_info i = {
> > +		.name_index = EXT4_EXT_ATTR_INDEX_SYSTEM,
> > +		.name = EXT4_EXT_ATTR_SYSTEM_DATA,
> > +	};
> > +	void *buf;
> > +	errcode_t retval;
> > +
> > +	if (len > EXT4_MIN_INLINE_DATA_SIZE) {
> > +		i.value = EXT2_ZERO_EXT_ATTR_VALUE;
> > +		i.value_len = len - EXT4_MIN_INLINE_DATA_SIZE;
> > +	} else {
> > +		i.value = "";
> > +		i.value_len = 0;
> > +	}
> > +
> > +	retval = ext2fs_ext_attr_ibody_find(fs, inode, &i, &s);
> > +	if (retval)
> > +		return retval;
> > +	retval = ext2fs_ext_attr_set_entry(&i, &s);
> > +	if (retval)
> > +		return retval;
> > +
> > +	header = IHDR(inode);
> > +	if (!EXT2_EXT_IS_LAST_ENTRY(s.first))
> > +		header->h_magic = EXT2_EXT_ATTR_MAGIC;
> > +	else
> > +		header->h_magic = 0;
> > +
> > +	return 0;
> > +}
> > diff --git a/lib/ext2fs/mkdir.c b/lib/ext2fs/mkdir.c
> > index 4a85439..a6aeb0d 100644
> > --- a/lib/ext2fs/mkdir.c
> > +++ b/lib/ext2fs/mkdir.c
> > @@ -36,11 +36,13 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
> >  {
> >  	ext2_extent_handle_t	handle;
> >  	errcode_t		retval;
> > -	struct ext2_inode	parent_inode, inode;
> > +	struct ext2_inode	parent_inode, *inode = NULL;
> > +	struct ext2_inode_large *large_inode = NULL;
> >  	ext2_ino_t		ino = 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);
> >  
> > @@ -55,16 +57,38 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
> >  	}
> >  
> >  	/*
> > +	 * We try to create a new directory with inline data if this feature
> > +	 * is enabled.  Here we don't try to do this if ino < first_ino or
> > +	 * the directory name is 'lost+found'.
> > +	 */
> > +	if (fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_INLINE_DATA &&
> > +	    ino >= EXT2_FIRST_INO(fs->super) && strcmp("lost+found", name) != 0)
> > +		inline_data = 1;
> 
> What if I mkdir -p /mnt/sub/dir/lost+found ?
> 
> > +
> > +	/*
> >  	 * Allocate a data block for the directory
> >  	 */
> > -	retval = ext2fs_new_block2(fs, 0, 0, &blk);
> > +	if (!inline_data) {
> > +		retval = ext2fs_new_block2(fs, 0, 0, &blk);
> > +		if (retval)
> > +			goto cleanup;
> > +	}
> > +
> > +	/*
> > +	 * Allocate a new inode structuure
> > +	 */
> > +	retval = ext2fs_get_memzero(EXT2_INODE_SIZE(fs->super), &large_inode);
> >  	if (retval)
> >  		goto cleanup;
> > +	inode = (struct ext2_inode *) large_inode;
> >  
> >  	/*
> >  	 * Create a scratch template for the directory
> >  	 */
> > -	retval = ext2fs_new_dir_block(fs, ino, parent, &block);
> > +	if (inline_data)
> > +		retval = ext2fs_new_dir_inline_data(fs, ino, parent, inode);
> > +	else
> > +		retval = ext2fs_new_dir_block(fs, ino, parent, &block);
> >  	if (retval)
> >  		goto cleanup;
> >  
> > @@ -81,37 +105,61 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
> >  	/*
> >  	 * Create the inode structure....
> >  	 */
> > -	memset(&inode, 0, sizeof(struct ext2_inode));
> > -	inode.i_mode = LINUX_S_IFDIR | (0777 & ~fs->umask);
> > -	inode.i_uid = inode.i_gid = 0;
> > -	ext2fs_iblk_set(fs, &inode, 1);
> > -	if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS)
> > -		inode.i_flags |= EXT4_EXTENTS_FL;
> > +	inode->i_mode = LINUX_S_IFDIR | (0777 & ~fs->umask);
> > +	inode->i_uid = inode->i_gid = 0;
> > +	ext2fs_iblk_set(fs, inode, 1);
> 
> Just to confirm, i_blocks should be nonzero for inline data?
> 
> > +	if (inline_data)
> > +		inode->i_flags |= EXT4_INLINE_DATA_FL;
> > +	else if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS)
> > +		inode->i_flags |= EXT4_EXTENTS_FL;
> >  	else
> > -		inode.i_block[0] = blk;
> > -	inode.i_links_count = 2;
> > -	inode.i_size = fs->blocksize;
> > +		inode->i_block[0] = blk;
> > +	inode->i_links_count = 2;
> >  
> >  	/*
> >  	 * Write out the inode and inode data block.  The inode generation
> >  	 * number is assigned by write_new_inode, which means that the call
> >  	 * to write_dir_block must come after that.
> > +	 *
> > +	 * If we try to create an new inode with inline data, we should call
> > +	 * ext2fs_write_inode_full to avoid to initialize extra part.
> >  	 */
> > -	retval = ext2fs_write_new_inode(fs, ino, &inode);
> > -	if (retval)
> > -		goto cleanup;
> > -	retval = ext2fs_write_dir_block4(fs, blk, block, 0, ino);
> > -	if (retval)
> > -		goto cleanup;
> > +	if (inline_data) {
> > +		__u32 t = fs->now ? fs->now : time(NULL);
> > +
> > +		inode->i_size = EXT4_MIN_INLINE_DATA_SIZE;
> > +		inode->i_blocks = 0;
> > +		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 (!large_inode->i_crtime)
> > +			large_inode->i_crtime = t;
> > +		retval = ext2fs_write_inode_full(fs, ino, inode,
> > +						 EXT2_INODE_SIZE(fs->super));
> > +		if (retval)
> > +			goto cleanup;
> > +	} else {
> > +		inode->i_size = fs->blocksize;
> >  
> > -	if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) {
> > -		retval = ext2fs_extent_open2(fs, ino, &inode, &handle);
> > +		retval = ext2fs_write_new_inode(fs, ino, inode);
> >  		if (retval)
> >  			goto cleanup;
> > -		retval = ext2fs_extent_set_bmap(handle, 0, blk, 0);
> > -		ext2fs_extent_free(handle);
> > +		retval = ext2fs_write_dir_block4(fs, blk, block, 0, ino);
> >  		if (retval)
> >  			goto cleanup;
> > +
> > +		if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) {
> 
> ext2fs_bmap()? Or, test the iflag.
> 
> > +			retval = ext2fs_extent_open2(fs, ino, inode, &handle);
> > +			if (retval)
> > +				goto cleanup;
> > +			retval = ext2fs_extent_set_bmap(handle, 0, blk, 0);
> > +			ext2fs_extent_free(handle);
> > +			if (retval)
> > +				goto cleanup;
> > +		}
> >  	}
> >  
> >  	/*
> > @@ -136,6 +184,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,14 +197,16 @@ 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:
> > +	if (large_inode)
> > +		ext2fs_free_mem(&large_inode);
> >  	if (block)
> >  		ext2fs_free_mem(&block);
> >  	return retval;
> > -
> >  }
> >  
> >  
> > diff --git a/lib/ext2fs/newdir.c b/lib/ext2fs/newdir.c
> > index 2cd541d..cec99e9 100644
> > --- a/lib/ext2fs/newdir.c
> > +++ b/lib/ext2fs/newdir.c
> > @@ -87,3 +87,36 @@ errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
> >  	*block = buf;
> >  	return 0;
> >  }
> > +
> > +/*
> > + * Create new directory in inode
> > + */
> > +errcode_t ext2fs_new_dir_inline_data(ext2_filsys fs,
> > +				     ext2_ino_t dir_ino,
> > +				     ext2_ino_t parent_ino,
> > +				     struct ext2_inode *inode)
> > +{
> > +	struct ext2_inode_large *large_inode;
> > +	struct ext2_dir_entry *dir = NULL;
> > +	int inline_size = EXT4_MIN_INLINE_DATA_SIZE;
> > +	errcode_t retval;
> > +
> > +	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
> > +
> > +	large_inode = (struct ext2_inode_large *) inode;
> > +	large_inode->i_extra_isize = sizeof(struct ext2_inode_large) -
> > +		EXT2_GOOD_OLD_INODE_SIZE;
> > +	retval = ext2fs_inline_data_create(fs, large_inode, inline_size);
> > +	if (retval)
> > +		return retval;
> > +
> > +	dir = (struct ext2_dir_entry *) inode->i_block;
> > +	dir->inode = parent_ino;
> > +
> > +	dir = (struct ext2_dir_entry *) ((char *) dir +
> > +					 EXT4_INLINE_DATA_DOTDOT_SIZE);
> > +	dir->inode = 0;
> > +	dir->rec_len = inline_size - EXT4_INLINE_DATA_DOTDOT_SIZE;
> > +
> > +	return retval;
> > +}
> > -- 
> > 1.7.9.7
> > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v1 10/22] debugfs: handle inline_data feature in dirsearch command
  2013-10-12  0:30   ` Darrick J. Wong
@ 2013-10-12  7:21     ` Zheng Liu
  0 siblings, 0 replies; 67+ messages in thread
From: Zheng Liu @ 2013-10-12  7:21 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-ext4, Theodore Ts'o, Zheng Liu

On Fri, Oct 11, 2013 at 05:30:36PM -0700, Darrick J. Wong wrote:
> On Fri, Aug 02, 2013 at 05:49:37PM +0800, Zheng Liu wrote:
> > From: Zheng Liu <wenqing.lz@taobao.com>
> > 
> > We don't need to support inline data in dirsearch command.
> 
> What if I want to dirsearch for a directory entry?  Shouldn't debugfs print
> more than nothing?  I don't see why I shouldn't be able to search an inline
> directory?

I have discussed this with Ted [1], and the result shows that making
dirsearch command support inline data is not very useful for libext2fs.
So this time I don't add this support.  Personally, I don't object to
support this.  But, yes, I am convinced by Ted.

1. http://www.spinics.net/lists/linux-ext4/msg38376.html

Thanks,
                                                - Zheng

> 
> --D
> > 
> > Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> > Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
> > ---
> >  debugfs/htree.c |    4 ++++
> >  1 file changed, 4 insertions(+)
> > 
> > diff --git a/debugfs/htree.c b/debugfs/htree.c
> > index d94dbea..b226f1d 100644
> > --- a/debugfs/htree.c
> > +++ b/debugfs/htree.c
> > @@ -387,9 +387,13 @@ 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))
> > +		goto out;
> > +
> >  	ext2fs_block_iterate3(current_fs, inode, BLOCK_FLAG_READ_ONLY, 0,
> >  			      search_dir_block, &pb);
> >  
> > +out:
> >  	free(pb.buf);
> >  }
> >  
> > -- 
> > 1.7.9.7
> > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v1 12/22] debugfs: handle inline_data in punch command
  2013-10-12  0:37   ` Darrick J. Wong
@ 2013-10-12  7:22     ` Zheng Liu
  0 siblings, 0 replies; 67+ messages in thread
From: Zheng Liu @ 2013-10-12  7:22 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-ext4, Theodore Ts'o, Zheng Liu

Good catch!  I will fix these problems.

Thanks,
                                                - Zheng

On Fri, Oct 11, 2013 at 05:37:00PM -0700, Darrick J. Wong wrote:
> On Fri, Aug 02, 2013 at 05:49:39PM +0800, Zheng Liu wrote:
> > From: Zheng Liu <wenqing.lz@taobao.com>
> > 
> > Now punch command only can truncate an inode with inline_data.  The
> > start block must be 0 because the size of an inode shouldn't be greater
> > than one block.
> > 
> > Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> > Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
> > ---
> >  lib/ext2fs/ext2fsP.h     |    3 +++
> >  lib/ext2fs/inline_data.c |    9 +++----
> >  lib/ext2fs/punch.c       |   59 ++++++++++++++++++++++++++++++++++++++++++++--
> >  3 files changed, 63 insertions(+), 8 deletions(-)
> > 
> > diff --git a/lib/ext2fs/ext2fsP.h b/lib/ext2fs/ext2fsP.h
> > index ed89272..1e5aa32 100644
> > --- a/lib/ext2fs/ext2fsP.h
> > +++ b/lib/ext2fs/ext2fsP.h
> > @@ -110,6 +110,9 @@ extern errcode_t ext2fs_inline_data_find(ext2_filsys fs,
> >  					 struct inline_data *data);
> >  extern errcode_t ext2fs_inline_data_convert(ext2_filsys fs, ext2_ino_t ino,
> >  					    void *priv_data);
> > +extern errcode_t ext2fs_inline_data_destory_data(ext2_filsys fs, ext2_ino_t ino,
> 
> "destroy", not "destory" ?
> 
> > +					   struct ext2_inode_large *inode,
> > +					   struct inline_data *data);
> >  
> >  /* Generic numeric progress meter */
> >  
> > diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c
> > index 5ca95ee..52ac133 100644
> > --- a/lib/ext2fs/inline_data.c
> > +++ b/lib/ext2fs/inline_data.c
> > @@ -28,9 +28,6 @@ static void ext2fs_inline_data_finish_convert(ext2_filsys fs, ext2_ino_t ino,
> >  					      int inline_size);
> >  static void ext2fs_update_final_de(ext2_filsys fs, char *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);
> >  
> >  errcode_t ext2fs_inline_data_find(ext2_filsys fs,
> >  				  struct ext2_inode_large *inode,
> > @@ -78,9 +75,9 @@ 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)
> > +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 = {
> > diff --git a/lib/ext2fs/punch.c b/lib/ext2fs/punch.c
> > index b53653a..3bfbd4d 100644
> > --- a/lib/ext2fs/punch.c
> > +++ b/lib/ext2fs/punch.c
> > @@ -19,6 +19,7 @@
> >  
> >  #include "ext2_fs.h"
> >  #include "ext2fs.h"
> > +#include "ext2fsP.h"
> >  
> >  #undef PUNCH_DEBUG
> >  
> > @@ -281,7 +282,59 @@ errout:
> >  	ext2fs_extent_free(handle);
> >  	return retval;
> >  }
> > -	
> > +
> > +static 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;
> > +
> > +	/*
> > +	 * 'start' must be 0 because here it's a block and the size of
> > +	 * an inode shouldn't greater than a block.
> > +	 */
> > +	if (start != 0)
> > +		return 0;
> > +
> > +	/* Punching hole for inline_data is not supported */
> > +	if ((unsigned int)end != ~0U)
> > +		return EXT2_ET_OP_NOT_SUPPORTED;
> 
> Um... shouldn't this be ~0ULL since end is blk64_t?
> 
> For an inline_data file I doubt it matters, but ripping off high bits looks
> suspicious to me.
> 
> --D
> 
> > +
> > +	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_inline_data_find(fs, inode, &data);
> > +	if (retval)
> > +		goto out;
> > +
> > +	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;
> > +	}
> > +
> > +	retval = ext2fs_inline_data_destory_data(fs, ino, inode, &data);
> > +	if (retval)
> > +		goto out;
> > +
> > +	inode->i_size = 0;
> > +	retval = ext2fs_write_inode_full(fs, ino, (void *)inode,
> > +					 EXT2_INODE_SIZE(fs->super));
> > +out:
> > +	ext2fs_free_mem(&inode);
> > +	return retval;
> > +}
> > +
> >  /*
> >   * Deallocate all logical blocks starting at start to end, inclusive.
> >   * If end is ~0, then this is effectively truncate.
> > @@ -307,7 +360,9 @@ 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)
> > +		return ext2fs_punch_inline_data(fs, ino, start, end);
> > +	else if (inode->i_flags & EXT4_EXTENTS_FL)
> >  		retval = ext2fs_punch_extent(fs, ino, inode, start, end);
> >  	else {
> >  		blk_t	count;
> > -- 
> > 1.7.9.7
> > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v1 14/22] mke2fs: add inline_data support in mke2fs
  2013-10-12  0:27   ` Darrick J. Wong
@ 2013-10-12  8:08     ` Zheng Liu
  2013-10-12  8:18       ` Darrick J. Wong
  0 siblings, 1 reply; 67+ messages in thread
From: Zheng Liu @ 2013-10-12  8:08 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-ext4, Theodore Ts'o, Zheng Liu

On Fri, Oct 11, 2013 at 05:27:18PM -0700, Darrick J. Wong wrote:
[...]
> > +	 */
> > +	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"));
> 
> "The inline_data feature requires the ext_attr feature." ?

Ah, I have noticed that now we set xattr handler by default.  So, yes,
inline_data feature doesn't require the ext_attr feature.

Thanks,
                                                - Zheng

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

* Re: [PATCH v1 15/22] tune2fs: add inline_data feature in tune2fs
  2013-10-12  0:39   ` Darrick J. Wong
@ 2013-10-12  8:16     ` Zheng Liu
  2013-10-12  8:23       ` Darrick J. Wong
  0 siblings, 1 reply; 67+ messages in thread
From: Zheng Liu @ 2013-10-12  8:16 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-ext4, Theodore Ts'o, Zheng Liu

On Fri, Oct 11, 2013 at 05:39:45PM -0700, Darrick J. Wong wrote:
> On Fri, Aug 02, 2013 at 05:49:42PM +0800, Zheng Liu wrote:
> > 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: Theodore Ts'o <tytso@mit.edu>
> > Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
> > ---
> >  misc/tune2fs.8.in |    5 +++++
> >  misc/tune2fs.c    |   17 ++++++++++++++++-
> >  2 files changed, 21 insertions(+), 1 deletion(-)
> > 
> > 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 7d6520e..f22a736 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|
> > @@ -995,6 +996,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.
> > +		 */
> 
> Multiline comment issue.
> 
> > +		if (!(fs->super->s_feature_compat &
> > +		      EXT2_FEATURE_COMPAT_EXT_ATTR)) {
> 
> EXT2_HAS_COMPAT_FEATURE()?
> 
> > +			fputs(_("The inline_data feature cannot "
> > +				"be set if ext_attr feature is disabled.\n"),
> > +				stderr);
> > +			return 1;
> > +		}
> > +	}
> > +
> 
> Maybe I'm missing something, but I don't see anything prohibiting the user from
> disabling inline_data?  Or from doing the conversion?

Yes, now in tune2fs we can only enable inline_data feature.  If we want
to disable inline_data, that means that we need to allocate a block for
every inode with inline data, and we could exhaust all disk space.
Another implementation might be just clear inline_data flag from
super_block and doesn't allocate a block for these inodes.  The former
obviously is not a good choice.  But the latter might be better.  I am
really not sure for this.  What do you think?

Thanks,
                                                - Zheng

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

* Re: [PATCH v1 17/22] e2fsck: check inline_data in pass1
  2013-10-12  0:47   ` Darrick J. Wong
@ 2013-10-12  8:17     ` Zheng Liu
  0 siblings, 0 replies; 67+ messages in thread
From: Zheng Liu @ 2013-10-12  8:17 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-ext4, Theodore Ts'o, Zheng Liu

On Fri, Oct 11, 2013 at 05:47:09PM -0700, Darrick J. Wong wrote:
> On Fri, Aug 02, 2013 at 05:49:44PM +0800, Zheng Liu wrote:
> > From: Zheng Liu <wenqing.lz@taobao.com>
> > 
> > Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> > Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
> > ---
> >  e2fsck/pass1.c          |   70 ++++++++++++++++++++++++++++++++++++++++++++---
> >  lib/ext2fs/dblist_dir.c |   10 +++++--
> >  2 files changed, 74 insertions(+), 6 deletions(-)
> > 
> > diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
> > index e6ea460..4301bb9 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) {
> > +		unsigned int inline_size;
> > +
> > +		inline_size = ext2fs_inline_data_get_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) ||
> > @@ -303,6 +313,15 @@ 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 the content of inline data right.
> > +		 */
> > +		if (strncmp(EXT2_EXT_ATTR_NAME(entry),
> > +		    EXT4_EXT_ATTR_SYSTEM_DATA,
> > +		    strlen(EXT4_EXT_ATTR_SYSTEM_DATA)) == 0)
> 
> Please align arguments 2 and 3 with argument 1 of strcmp.

Good catch.  I will fix it.

Thanks,
                                                - Zheng

> 
> --D
> > +			goto next;
> > +
> >  		/* attribute len eats this space */
> >  		remain -= EXT2_EXT_ATTR_SIZE(entry->e_name_len);
> >  
> > @@ -330,6 +349,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);
> > @@ -407,6 +427,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
> > @@ -434,11 +455,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))
> > @@ -1205,7 +1234,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])
> > @@ -1214,6 +1244,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] ||
> > @@ -2129,6 +2160,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.
> >   */
> > @@ -2142,6 +2195,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;
> > @@ -2165,6 +2219,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 &
> > @@ -2188,6 +2244,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,
> > @@ -2230,7 +2289,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--;
> > @@ -2256,7 +2316,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.9.7
> > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v1 14/22] mke2fs: add inline_data support in mke2fs
  2013-10-12  8:08     ` Zheng Liu
@ 2013-10-12  8:18       ` Darrick J. Wong
  2013-10-12  8:31         ` Zheng Liu
  0 siblings, 1 reply; 67+ messages in thread
From: Darrick J. Wong @ 2013-10-12  8:18 UTC (permalink / raw)
  To: linux-ext4, Theodore Ts'o, Zheng Liu

On Sat, Oct 12, 2013 at 04:08:46PM +0800, Zheng Liu wrote:
> On Fri, Oct 11, 2013 at 05:27:18PM -0700, Darrick J. Wong wrote:
> [...]
> > > +	 */
> > > +	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"));
> > 
> > "The inline_data feature requires the ext_attr feature." ?
> 
> Ah, I have noticed that now we set xattr handler by default.  So, yes,
> inline_data feature doesn't require the ext_attr feature.

I think you /do/ still need this check, just in case someone tries to mkfs -O
^ext_attr,inline_data.  Defaults can be overridden.

(I was merely trying to clarify the English in the error message.)

--D
> 
> Thanks,
>                                                 - Zheng

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

* Re: [PATCH v1 15/22] tune2fs: add inline_data feature in tune2fs
  2013-10-12  8:16     ` Zheng Liu
@ 2013-10-12  8:23       ` Darrick J. Wong
  2013-10-12  8:33         ` Zheng Liu
  0 siblings, 1 reply; 67+ messages in thread
From: Darrick J. Wong @ 2013-10-12  8:23 UTC (permalink / raw)
  To: linux-ext4, Theodore Ts'o, Zheng Liu

On Sat, Oct 12, 2013 at 04:16:38PM +0800, Zheng Liu wrote:
> On Fri, Oct 11, 2013 at 05:39:45PM -0700, Darrick J. Wong wrote:
> > On Fri, Aug 02, 2013 at 05:49:42PM +0800, Zheng Liu wrote:
> > > 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: Theodore Ts'o <tytso@mit.edu>
> > > Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
> > > ---
> > >  misc/tune2fs.8.in |    5 +++++
> > >  misc/tune2fs.c    |   17 ++++++++++++++++-
> > >  2 files changed, 21 insertions(+), 1 deletion(-)
> > > 
> > > 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 7d6520e..f22a736 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|
> > > @@ -995,6 +996,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.
> > > +		 */
> > 
> > Multiline comment issue.
> > 
> > > +		if (!(fs->super->s_feature_compat &
> > > +		      EXT2_FEATURE_COMPAT_EXT_ATTR)) {
> > 
> > EXT2_HAS_COMPAT_FEATURE()?
> > 
> > > +			fputs(_("The inline_data feature cannot "
> > > +				"be set if ext_attr feature is disabled.\n"),
> > > +				stderr);
> > > +			return 1;
> > > +		}
> > > +	}
> > > +
> > 
> > Maybe I'm missing something, but I don't see anything prohibiting the user from
> > disabling inline_data?  Or from doing the conversion?
> 
> Yes, now in tune2fs we can only enable inline_data feature.  If we want
> to disable inline_data, that means that we need to allocate a block for
> every inode with inline data, and we could exhaust all disk space.
> Another implementation might be just clear inline_data flag from
> super_block and doesn't allocate a block for these inodes.  The former
> obviously is not a good choice.  But the latter might be better.  I am
> really not sure for this.  What do you think?

I don't think it's a good idea to turn off inline_data once it's been enabled,
just like we don't let people turn off extents...

*Oh*, duh, I didn't notice that INLINE_DATA is *NOT* in the clear_ok_features
list.  Never mind this comment, I'm just making noise.

(The complaints about the comment issue and not using EXT2_HAS_COMPAT_FEATURE
remain.)

--D
> 
> Thanks,
>                                                 - Zheng

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

* Re: [PATCH v1 14/22] mke2fs: add inline_data support in mke2fs
  2013-10-12  8:18       ` Darrick J. Wong
@ 2013-10-12  8:31         ` Zheng Liu
  2013-10-12  8:32           ` Darrick J. Wong
  0 siblings, 1 reply; 67+ messages in thread
From: Zheng Liu @ 2013-10-12  8:31 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-ext4, Theodore Ts'o, Zheng Liu

On Sat, Oct 12, 2013 at 01:18:25AM -0700, Darrick J. Wong wrote:
> On Sat, Oct 12, 2013 at 04:08:46PM +0800, Zheng Liu wrote:
> > On Fri, Oct 11, 2013 at 05:27:18PM -0700, Darrick J. Wong wrote:
> > [...]
> > > > +	 */
> > > > +	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"));
> > > 
> > > "The inline_data feature requires the ext_attr feature." ?
> > 
> > Ah, I have noticed that now we set xattr handler by default.  So, yes,
> > inline_data feature doesn't require the ext_attr feature.
> 
> I think you /do/ still need this check, just in case someone tries to mkfs -O
> ^ext_attr,inline_data.  Defaults can be overridden.

I have tested this ('mkfs -O ^ext_attr,inline_data') just a minute ago,
and it seems that it works well.  BTW, when we use setfattr(1) to set
xattr in a ext4 file system without ext_attr feature, this feature will
be enabled in ext4_xattr_update_super_block().

                                                - Zheng

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

* Re: [PATCH v1 03/22] libext2fs: add functions to operate on extended attribute
  2013-10-12  5:51     ` Zheng Liu
@ 2013-10-12  8:32       ` Darrick J. Wong
  2013-10-12  8:41         ` Zheng Liu
  0 siblings, 1 reply; 67+ messages in thread
From: Darrick J. Wong @ 2013-10-12  8:32 UTC (permalink / raw)
  To: linux-ext4, Zheng Liu, Theodore Ts'o

On Sat, Oct 12, 2013 at 01:51:54PM +0800, Zheng Liu wrote:
> On Fri, Oct 11, 2013 at 03:51:15PM -0700, Darrick J. Wong wrote:
> > On Fri, Aug 02, 2013 at 05:49:30PM +0800, Zheng Liu wrote:
> > > From: Zheng Liu <wenqing.lz@taobao.com>
> > > 
> > > We need to define some functions to operate extended attribute in order
> > > to support inline data.
> > > 
> > > Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
> > > Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> > > ---
> > >  lib/ext2fs/ext2_err.et.in  |    3 +
> > >  lib/ext2fs/ext2_ext_attr.h |   31 ++++++++
> > >  lib/ext2fs/ext2fs.h        |    9 +++
> > >  lib/ext2fs/ext_attr.c      |  186 ++++++++++++++++++++++++++++++++++++++++++++
> > >  4 files changed, 229 insertions(+)
> > > 
> > > diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in
> > > index d20c6b7..7e6d6e5 100644
> > > --- a/lib/ext2fs/ext2_err.et.in
> > > +++ b/lib/ext2fs/ext2_err.et.in
> > > @@ -476,4 +476,7 @@ ec	EXT2_ET_MMP_CSUM_INVALID,
> > >  ec	EXT2_ET_FILE_EXISTS,
> > >  	"Ext2 file already exists"
> > >  
> > > +ec	EXT2_ET_EXT_ATTR_CURRUPTED,
> > > +	"Extended attribute currupted"
> > > +
> > >  	end
> > > diff --git a/lib/ext2fs/ext2_ext_attr.h b/lib/ext2fs/ext2_ext_attr.h
> > > index bbb0aaa..99ad849 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,29 @@ 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 *) \
> > > +		((char *)inode + \
> > > +		EXT2_GOOD_OLD_INODE_SIZE + \
> > > +		inode->i_extra_isize))
> > > +#define IFIRST(hdr) ((struct ext2_ext_attr_entry *)((hdr)+1))
> > > +#define EXT2_ZERO_EXT_ATTR_VALUE ((void *)-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 3346c00..8c30197 100644
> > > --- a/lib/ext2fs/ext2fs.h
> > > +++ b/lib/ext2fs/ext2fs.h
> > > @@ -1136,6 +1136,15 @@ 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_ext_attr_ibody_find(ext2_filsys fs,
> > > +					    struct ext2_inode_large *inode,
> > > +					    struct ext2_ext_attr_info *i,
> > > +					    struct ext2_ext_attr_search *s);
> > > +extern errcode_t ext2fs_ext_attr_find_entry(struct ext2_ext_attr_entry **pentry,
> > > +					    int name_index, const char *name,
> > > +					    size_t size, int sorted);
> > > +extern errcode_t ext2fs_ext_attr_set_entry(struct ext2_ext_attr_info *i,
> > > +					   struct ext2_ext_attr_search *s);
> > >  
> > >  /* 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..6d55340 100644
> > > --- a/lib/ext2fs/ext_attr.c
> > > +++ b/lib/ext2fs/ext_attr.c
> > > @@ -186,3 +186,189 @@ errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
> > >  	return ext2fs_adjust_ea_refcount2(fs, blk, block_buf, adjust,
> > >  					  newcount);
> > >  }
> > > +
> > > +static errcode_t
> > > +ext2fs_ext_attr_check_names(struct ext2_ext_attr_entry *entry, void *end)
> > > +{
> > > +	while (!EXT2_EXT_IS_LAST_ENTRY(entry)) {
> > > +		struct ext2_ext_attr_entry *next = EXT2_EXT_ATTR_NEXT(entry);
> > > +		if ((void *)next >= end)
> > > +			return EXT2_ET_EXT_ATTR_CURRUPTED;
> > > +		entry = next;
> > > +	}
> > > +	return 0;
> > > +}
> > > +
> > > +static inline errcode_t
> > > +ext2fs_ext_attr_check_entry(struct ext2_ext_attr_entry *entry, size_t size)
> > > +{
> > > +	size_t value_size = entry->e_value_size;
> > > +
> > > +	if (entry->e_value_block != 0 || value_size > size ||
> > > +	    entry->e_value_offs + value_size > size)
> > > +		return EXT2_ET_EXT_ATTR_CURRUPTED;
> > > +	return 0;
> > > +}
> > > +
> > > +errcode_t ext2fs_ext_attr_find_entry(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 = 1;
> > > +
> > > +	if (name == NULL)
> > > +		return EXT2_ET_INVALID_ARGUMENT;
> > > +	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 <= 0 && (sorted || cmp == 0))
> > > +			break;
> > > +	}
> > > +	*pentry = entry;
> > > +	if (!cmp && ext2fs_ext_attr_check_entry(entry, size))
> > > +		return EXT2_ET_EXT_ATTR_CURRUPTED;
> > > +	return cmp ? ENODATA : 0;
> > > +}
> > > +
> > > +errcode_t ext2fs_ext_attr_ibody_find(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;
> > > +	errcode_t error;
> > > +
> > > +	if (inode->i_extra_isize == 0)
> > > +		return 0;
> > > +	header = IHDR(inode);
> > > +	s->base = s->first = IFIRST(header);
> > > +	s->here = s->first;
> > > +	s->end = (char *)inode + EXT2_INODE_SIZE(fs->super);
> > > +
> > > +	error = ext2fs_ext_attr_check_names(IFIRST(header), s->end);
> > > +	if (error)
> > > +		return error;
> > > +	/* Find the named attribute. */
> > > +	error = ext2fs_ext_attr_find_entry(&s->here, i->name_index,
> > > +					   i->name, (char *)s->end -
> > > +					   (char *)s->base, 0);
> > > +	if (error && error != ENODATA)
> > > +		return error;
> > > +	s->not_found = error;
> > > +	return 0;
> > 
> > Huh.  It just occurred to me (yes, after three months, sorry...) that your
> > patchset doesn't deal with EAs that live in a separate block.  For the purposes
> > of inline_data I suppose that's sufficient, but if we're going to add an API to
> > mess with EAs, we ought to be able to handle all of a file's EAs.
> > 
> > The implementation that I wrote for fuse2fs does this, but it has no facility
> > to ensure that the inline data ends up in the ibody and not the EA block.
> > Though really, they're written out in array order, so it wouldn't be difficult
> > to sort before writing, or use some knapsack variant.
> 
> Sorry, I still havn't had a chance to take a closer look at your patch
> set for e2fsprogs.  I will review it ASAP.

Ok.  I'm getting ready to re-spam the mailing list with some more fixes, so you
can relax for a day or two.  There were some bugs handling inode_size=128.

(If you want to take a quick look that's fine; I haven't changed the patch
significantly.)

--D
> 
> > 
> > I think I might be drifting towards the idea of attaching your patch series to
> > the end of mine, but as yours is already in -pu I'm open to discussing how to
> > reconcile our implementations.
> 
> I agree with you that we need to reconcile our implementation.  I was
> wondering if we really need to add all APIs for EAs in e2fsprogs when I
> added these functions.  But now it seems that we do need them.
> 
> > 
> > I _do_ like the comments you added to ext2fs_ext_attr_set_entry() though. :)
> 
> Yes, there is no any difficulty to add this API. :-)
> 
> Regards,
>                                                 - Zheng

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

* Re: [PATCH v1 14/22] mke2fs: add inline_data support in mke2fs
  2013-10-12  8:31         ` Zheng Liu
@ 2013-10-12  8:32           ` Darrick J. Wong
  0 siblings, 0 replies; 67+ messages in thread
From: Darrick J. Wong @ 2013-10-12  8:32 UTC (permalink / raw)
  To: linux-ext4, Theodore Ts'o, Zheng Liu

On Sat, Oct 12, 2013 at 04:31:17PM +0800, Zheng Liu wrote:
> On Sat, Oct 12, 2013 at 01:18:25AM -0700, Darrick J. Wong wrote:
> > On Sat, Oct 12, 2013 at 04:08:46PM +0800, Zheng Liu wrote:
> > > On Fri, Oct 11, 2013 at 05:27:18PM -0700, Darrick J. Wong wrote:
> > > [...]
> > > > > +	 */
> > > > > +	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"));
> > > > 
> > > > "The inline_data feature requires the ext_attr feature." ?
> > > 
> > > Ah, I have noticed that now we set xattr handler by default.  So, yes,
> > > inline_data feature doesn't require the ext_attr feature.
> > 
> > I think you /do/ still need this check, just in case someone tries to mkfs -O
> > ^ext_attr,inline_data.  Defaults can be overridden.
> 
> I have tested this ('mkfs -O ^ext_attr,inline_data') just a minute ago,
> and it seems that it works well.  BTW, when we use setfattr(1) to set
> xattr in a ext4 file system without ext_attr feature, this feature will
> be enabled in ext4_xattr_update_super_block().

Oh good!  My mistake, then.  That teaches me to squint at my computer at 1:30
in the morning. :)

--D
> 
>                                                 - Zheng

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

* Re: [PATCH v1 15/22] tune2fs: add inline_data feature in tune2fs
  2013-10-12  8:23       ` Darrick J. Wong
@ 2013-10-12  8:33         ` Zheng Liu
  0 siblings, 0 replies; 67+ messages in thread
From: Zheng Liu @ 2013-10-12  8:33 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-ext4, Theodore Ts'o, Zheng Liu

On Sat, Oct 12, 2013 at 01:23:15AM -0700, Darrick J. Wong wrote:
> On Sat, Oct 12, 2013 at 04:16:38PM +0800, Zheng Liu wrote:
> > On Fri, Oct 11, 2013 at 05:39:45PM -0700, Darrick J. Wong wrote:
> > > On Fri, Aug 02, 2013 at 05:49:42PM +0800, Zheng Liu wrote:
> > > > 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: Theodore Ts'o <tytso@mit.edu>
> > > > Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
> > > > ---
> > > >  misc/tune2fs.8.in |    5 +++++
> > > >  misc/tune2fs.c    |   17 ++++++++++++++++-
> > > >  2 files changed, 21 insertions(+), 1 deletion(-)
> > > > 
> > > > 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 7d6520e..f22a736 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|
> > > > @@ -995,6 +996,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.
> > > > +		 */
> > > 
> > > Multiline comment issue.
> > > 
> > > > +		if (!(fs->super->s_feature_compat &
> > > > +		      EXT2_FEATURE_COMPAT_EXT_ATTR)) {
> > > 
> > > EXT2_HAS_COMPAT_FEATURE()?
> > > 
> > > > +			fputs(_("The inline_data feature cannot "
> > > > +				"be set if ext_attr feature is disabled.\n"),
> > > > +				stderr);
> > > > +			return 1;
> > > > +		}
> > > > +	}
> > > > +
> > > 
> > > Maybe I'm missing something, but I don't see anything prohibiting the user from
> > > disabling inline_data?  Or from doing the conversion?
> > 
> > Yes, now in tune2fs we can only enable inline_data feature.  If we want
> > to disable inline_data, that means that we need to allocate a block for
> > every inode with inline data, and we could exhaust all disk space.
> > Another implementation might be just clear inline_data flag from
> > super_block and doesn't allocate a block for these inodes.  The former
> > obviously is not a good choice.  But the latter might be better.  I am
> > really not sure for this.  What do you think?
> 
> I don't think it's a good idea to turn off inline_data once it's been enabled,
> just like we don't let people turn off extents...
> 
> *Oh*, duh, I didn't notice that INLINE_DATA is *NOT* in the clear_ok_features
> list.  Never mind this comment, I'm just making noise.
> 
> (The complaints about the comment issue and not using EXT2_HAS_COMPAT_FEATURE
> remain.)

Got it. :)

                                                - Zheng

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

* Re: [PATCH v1 03/22] libext2fs: add functions to operate on extended attribute
  2013-10-12  8:32       ` Darrick J. Wong
@ 2013-10-12  8:41         ` Zheng Liu
  2013-10-12  9:02           ` Darrick J. Wong
  0 siblings, 1 reply; 67+ messages in thread
From: Zheng Liu @ 2013-10-12  8:41 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-ext4, Zheng Liu, Theodore Ts'o

On Sat, Oct 12, 2013 at 01:32:00AM -0700, Darrick J. Wong wrote:
> On Sat, Oct 12, 2013 at 01:51:54PM +0800, Zheng Liu wrote:
> > On Fri, Oct 11, 2013 at 03:51:15PM -0700, Darrick J. Wong wrote:
> > > On Fri, Aug 02, 2013 at 05:49:30PM +0800, Zheng Liu wrote:
> > > > From: Zheng Liu <wenqing.lz@taobao.com>
> > > > 
> > > > We need to define some functions to operate extended attribute in order
> > > > to support inline data.
> > > > 
> > > > Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
> > > > Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> > > > ---
> > > >  lib/ext2fs/ext2_err.et.in  |    3 +
> > > >  lib/ext2fs/ext2_ext_attr.h |   31 ++++++++
> > > >  lib/ext2fs/ext2fs.h        |    9 +++
> > > >  lib/ext2fs/ext_attr.c      |  186 ++++++++++++++++++++++++++++++++++++++++++++
> > > >  4 files changed, 229 insertions(+)
> > > > 
> > > > diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in
> > > > index d20c6b7..7e6d6e5 100644
> > > > --- a/lib/ext2fs/ext2_err.et.in
> > > > +++ b/lib/ext2fs/ext2_err.et.in
> > > > @@ -476,4 +476,7 @@ ec	EXT2_ET_MMP_CSUM_INVALID,
> > > >  ec	EXT2_ET_FILE_EXISTS,
> > > >  	"Ext2 file already exists"
> > > >  
> > > > +ec	EXT2_ET_EXT_ATTR_CURRUPTED,
> > > > +	"Extended attribute currupted"
> > > > +
> > > >  	end
> > > > diff --git a/lib/ext2fs/ext2_ext_attr.h b/lib/ext2fs/ext2_ext_attr.h
> > > > index bbb0aaa..99ad849 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,29 @@ 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 *) \
> > > > +		((char *)inode + \
> > > > +		EXT2_GOOD_OLD_INODE_SIZE + \
> > > > +		inode->i_extra_isize))
> > > > +#define IFIRST(hdr) ((struct ext2_ext_attr_entry *)((hdr)+1))
> > > > +#define EXT2_ZERO_EXT_ATTR_VALUE ((void *)-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 3346c00..8c30197 100644
> > > > --- a/lib/ext2fs/ext2fs.h
> > > > +++ b/lib/ext2fs/ext2fs.h
> > > > @@ -1136,6 +1136,15 @@ 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_ext_attr_ibody_find(ext2_filsys fs,
> > > > +					    struct ext2_inode_large *inode,
> > > > +					    struct ext2_ext_attr_info *i,
> > > > +					    struct ext2_ext_attr_search *s);
> > > > +extern errcode_t ext2fs_ext_attr_find_entry(struct ext2_ext_attr_entry **pentry,
> > > > +					    int name_index, const char *name,
> > > > +					    size_t size, int sorted);
> > > > +extern errcode_t ext2fs_ext_attr_set_entry(struct ext2_ext_attr_info *i,
> > > > +					   struct ext2_ext_attr_search *s);
> > > >  
> > > >  /* 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..6d55340 100644
> > > > --- a/lib/ext2fs/ext_attr.c
> > > > +++ b/lib/ext2fs/ext_attr.c
> > > > @@ -186,3 +186,189 @@ errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
> > > >  	return ext2fs_adjust_ea_refcount2(fs, blk, block_buf, adjust,
> > > >  					  newcount);
> > > >  }
> > > > +
> > > > +static errcode_t
> > > > +ext2fs_ext_attr_check_names(struct ext2_ext_attr_entry *entry, void *end)
> > > > +{
> > > > +	while (!EXT2_EXT_IS_LAST_ENTRY(entry)) {
> > > > +		struct ext2_ext_attr_entry *next = EXT2_EXT_ATTR_NEXT(entry);
> > > > +		if ((void *)next >= end)
> > > > +			return EXT2_ET_EXT_ATTR_CURRUPTED;
> > > > +		entry = next;
> > > > +	}
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static inline errcode_t
> > > > +ext2fs_ext_attr_check_entry(struct ext2_ext_attr_entry *entry, size_t size)
> > > > +{
> > > > +	size_t value_size = entry->e_value_size;
> > > > +
> > > > +	if (entry->e_value_block != 0 || value_size > size ||
> > > > +	    entry->e_value_offs + value_size > size)
> > > > +		return EXT2_ET_EXT_ATTR_CURRUPTED;
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +errcode_t ext2fs_ext_attr_find_entry(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 = 1;
> > > > +
> > > > +	if (name == NULL)
> > > > +		return EXT2_ET_INVALID_ARGUMENT;
> > > > +	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 <= 0 && (sorted || cmp == 0))
> > > > +			break;
> > > > +	}
> > > > +	*pentry = entry;
> > > > +	if (!cmp && ext2fs_ext_attr_check_entry(entry, size))
> > > > +		return EXT2_ET_EXT_ATTR_CURRUPTED;
> > > > +	return cmp ? ENODATA : 0;
> > > > +}
> > > > +
> > > > +errcode_t ext2fs_ext_attr_ibody_find(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;
> > > > +	errcode_t error;
> > > > +
> > > > +	if (inode->i_extra_isize == 0)
> > > > +		return 0;
> > > > +	header = IHDR(inode);
> > > > +	s->base = s->first = IFIRST(header);
> > > > +	s->here = s->first;
> > > > +	s->end = (char *)inode + EXT2_INODE_SIZE(fs->super);
> > > > +
> > > > +	error = ext2fs_ext_attr_check_names(IFIRST(header), s->end);
> > > > +	if (error)
> > > > +		return error;
> > > > +	/* Find the named attribute. */
> > > > +	error = ext2fs_ext_attr_find_entry(&s->here, i->name_index,
> > > > +					   i->name, (char *)s->end -
> > > > +					   (char *)s->base, 0);
> > > > +	if (error && error != ENODATA)
> > > > +		return error;
> > > > +	s->not_found = error;
> > > > +	return 0;
> > > 
> > > Huh.  It just occurred to me (yes, after three months, sorry...) that your
> > > patchset doesn't deal with EAs that live in a separate block.  For the purposes
> > > of inline_data I suppose that's sufficient, but if we're going to add an API to
> > > mess with EAs, we ought to be able to handle all of a file's EAs.
> > > 
> > > The implementation that I wrote for fuse2fs does this, but it has no facility
> > > to ensure that the inline data ends up in the ibody and not the EA block.
> > > Though really, they're written out in array order, so it wouldn't be difficult
> > > to sort before writing, or use some knapsack variant.
> > 
> > Sorry, I still havn't had a chance to take a closer look at your patch
> > set for e2fsprogs.  I will review it ASAP.
> 
> Ok.  I'm getting ready to re-spam the mailing list with some more fixes, so you
> can relax for a day or two.  There were some bugs handling inode_size=128.

Welcome to flush my mail box. :-p

                                                - Zheng

> 
> (If you want to take a quick look that's fine; I haven't changed the patch
> significantly.)
> 
> --D
> > 
> > > 
> > > I think I might be drifting towards the idea of attaching your patch series to
> > > the end of mine, but as yours is already in -pu I'm open to discussing how to
> > > reconcile our implementations.
> > 
> > I agree with you that we need to reconcile our implementation.  I was
> > wondering if we really need to add all APIs for EAs in e2fsprogs when I
> > added these functions.  But now it seems that we do need them.
> > 
> > > 
> > > I _do_ like the comments you added to ext2fs_ext_attr_set_entry() though. :)
> > 
> > Yes, there is no any difficulty to add this API. :-)
> > 
> > Regards,
> >                                                 - Zheng
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v1 03/22] libext2fs: add functions to operate on extended attribute
  2013-10-12  8:41         ` Zheng Liu
@ 2013-10-12  9:02           ` Darrick J. Wong
  2013-10-12  9:08             ` Zheng Liu
  0 siblings, 1 reply; 67+ messages in thread
From: Darrick J. Wong @ 2013-10-12  9:02 UTC (permalink / raw)
  To: linux-ext4, Zheng Liu, Theodore Ts'o

On Sat, Oct 12, 2013 at 04:41:11PM +0800, Zheng Liu wrote:
> On Sat, Oct 12, 2013 at 01:32:00AM -0700, Darrick J. Wong wrote:
> > On Sat, Oct 12, 2013 at 01:51:54PM +0800, Zheng Liu wrote:
> > > On Fri, Oct 11, 2013 at 03:51:15PM -0700, Darrick J. Wong wrote:
> > > > On Fri, Aug 02, 2013 at 05:49:30PM +0800, Zheng Liu wrote:
> > > > > From: Zheng Liu <wenqing.lz@taobao.com>
> > > > > 
> > > > > We need to define some functions to operate extended attribute in order
> > > > > to support inline data.
> > > > > 
> > > > > Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
> > > > > Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> > > > > ---
> > > > >  lib/ext2fs/ext2_err.et.in  |    3 +
> > > > >  lib/ext2fs/ext2_ext_attr.h |   31 ++++++++
> > > > >  lib/ext2fs/ext2fs.h        |    9 +++
> > > > >  lib/ext2fs/ext_attr.c      |  186 ++++++++++++++++++++++++++++++++++++++++++++
> > > > >  4 files changed, 229 insertions(+)
> > > > > 
> > > > > diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in
> > > > > index d20c6b7..7e6d6e5 100644
> > > > > --- a/lib/ext2fs/ext2_err.et.in
> > > > > +++ b/lib/ext2fs/ext2_err.et.in
> > > > > @@ -476,4 +476,7 @@ ec	EXT2_ET_MMP_CSUM_INVALID,
> > > > >  ec	EXT2_ET_FILE_EXISTS,
> > > > >  	"Ext2 file already exists"
> > > > >  
> > > > > +ec	EXT2_ET_EXT_ATTR_CURRUPTED,
> > > > > +	"Extended attribute currupted"
> > > > > +
> > > > >  	end
> > > > > diff --git a/lib/ext2fs/ext2_ext_attr.h b/lib/ext2fs/ext2_ext_attr.h
> > > > > index bbb0aaa..99ad849 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,29 @@ 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 *) \
> > > > > +		((char *)inode + \
> > > > > +		EXT2_GOOD_OLD_INODE_SIZE + \
> > > > > +		inode->i_extra_isize))
> > > > > +#define IFIRST(hdr) ((struct ext2_ext_attr_entry *)((hdr)+1))
> > > > > +#define EXT2_ZERO_EXT_ATTR_VALUE ((void *)-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 3346c00..8c30197 100644
> > > > > --- a/lib/ext2fs/ext2fs.h
> > > > > +++ b/lib/ext2fs/ext2fs.h
> > > > > @@ -1136,6 +1136,15 @@ 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_ext_attr_ibody_find(ext2_filsys fs,
> > > > > +					    struct ext2_inode_large *inode,
> > > > > +					    struct ext2_ext_attr_info *i,
> > > > > +					    struct ext2_ext_attr_search *s);
> > > > > +extern errcode_t ext2fs_ext_attr_find_entry(struct ext2_ext_attr_entry **pentry,
> > > > > +					    int name_index, const char *name,
> > > > > +					    size_t size, int sorted);
> > > > > +extern errcode_t ext2fs_ext_attr_set_entry(struct ext2_ext_attr_info *i,
> > > > > +					   struct ext2_ext_attr_search *s);
> > > > >  
> > > > >  /* 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..6d55340 100644
> > > > > --- a/lib/ext2fs/ext_attr.c
> > > > > +++ b/lib/ext2fs/ext_attr.c
> > > > > @@ -186,3 +186,189 @@ errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
> > > > >  	return ext2fs_adjust_ea_refcount2(fs, blk, block_buf, adjust,
> > > > >  					  newcount);
> > > > >  }
> > > > > +
> > > > > +static errcode_t
> > > > > +ext2fs_ext_attr_check_names(struct ext2_ext_attr_entry *entry, void *end)
> > > > > +{
> > > > > +	while (!EXT2_EXT_IS_LAST_ENTRY(entry)) {
> > > > > +		struct ext2_ext_attr_entry *next = EXT2_EXT_ATTR_NEXT(entry);
> > > > > +		if ((void *)next >= end)
> > > > > +			return EXT2_ET_EXT_ATTR_CURRUPTED;
> > > > > +		entry = next;
> > > > > +	}
> > > > > +	return 0;
> > > > > +}
> > > > > +
> > > > > +static inline errcode_t
> > > > > +ext2fs_ext_attr_check_entry(struct ext2_ext_attr_entry *entry, size_t size)
> > > > > +{
> > > > > +	size_t value_size = entry->e_value_size;
> > > > > +
> > > > > +	if (entry->e_value_block != 0 || value_size > size ||
> > > > > +	    entry->e_value_offs + value_size > size)
> > > > > +		return EXT2_ET_EXT_ATTR_CURRUPTED;
> > > > > +	return 0;
> > > > > +}
> > > > > +
> > > > > +errcode_t ext2fs_ext_attr_find_entry(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 = 1;
> > > > > +
> > > > > +	if (name == NULL)
> > > > > +		return EXT2_ET_INVALID_ARGUMENT;
> > > > > +	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 <= 0 && (sorted || cmp == 0))
> > > > > +			break;
> > > > > +	}
> > > > > +	*pentry = entry;
> > > > > +	if (!cmp && ext2fs_ext_attr_check_entry(entry, size))
> > > > > +		return EXT2_ET_EXT_ATTR_CURRUPTED;
> > > > > +	return cmp ? ENODATA : 0;
> > > > > +}
> > > > > +
> > > > > +errcode_t ext2fs_ext_attr_ibody_find(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;
> > > > > +	errcode_t error;
> > > > > +
> > > > > +	if (inode->i_extra_isize == 0)
> > > > > +		return 0;
> > > > > +	header = IHDR(inode);
> > > > > +	s->base = s->first = IFIRST(header);
> > > > > +	s->here = s->first;
> > > > > +	s->end = (char *)inode + EXT2_INODE_SIZE(fs->super);
> > > > > +
> > > > > +	error = ext2fs_ext_attr_check_names(IFIRST(header), s->end);
> > > > > +	if (error)
> > > > > +		return error;
> > > > > +	/* Find the named attribute. */
> > > > > +	error = ext2fs_ext_attr_find_entry(&s->here, i->name_index,
> > > > > +					   i->name, (char *)s->end -
> > > > > +					   (char *)s->base, 0);
> > > > > +	if (error && error != ENODATA)
> > > > > +		return error;
> > > > > +	s->not_found = error;
> > > > > +	return 0;
> > > > 
> > > > Huh.  It just occurred to me (yes, after three months, sorry...) that your
> > > > patchset doesn't deal with EAs that live in a separate block.  For the purposes
> > > > of inline_data I suppose that's sufficient, but if we're going to add an API to
> > > > mess with EAs, we ought to be able to handle all of a file's EAs.
> > > > 
> > > > The implementation that I wrote for fuse2fs does this, but it has no facility
> > > > to ensure that the inline data ends up in the ibody and not the EA block.
> > > > Though really, they're written out in array order, so it wouldn't be difficult
> > > > to sort before writing, or use some knapsack variant.
> > > 
> > > Sorry, I still havn't had a chance to take a closer look at your patch
> > > set for e2fsprogs.  I will review it ASAP.
> > 
> > Ok.  I'm getting ready to re-spam the mailing list with some more fixes, so you
> > can relax for a day or two.  There were some bugs handling inode_size=128.
> 
> Welcome to flush my mail box. :-p

He he he there are 24 of those patches... I got lucky and Ted picked a few more
tonight. :)

--D

Well, if you're curious, here's the latest xattr API patch.  I wonder if the
minimum size of the inode ought to be EXT2_GOOD_OLD_SIZE + i_extra_isize + 8
bytes (to fit the EA magic and the magic zero that says "end of keys")?  But
it's too late at night to think.

From: Darrick J. Wong <darrick.wong@oracle.com>
Subject: [PATCH] libext2fs: support modifying arbitrary extended attributes

Add functions to allow clients to get, set, and remove extended
attributes from any file.  It also supports modifying EAs living in
i_file_acl.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 lib/ext2fs/ext2_err.et.in |   18 +
 lib/ext2fs/ext2fs.h       |   28 ++
 lib/ext2fs/ext_attr.c     |  742 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 788 insertions(+)

diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in
index c547a2c..262f4a4 100644
--- a/lib/ext2fs/ext2_err.et.in
+++ b/lib/ext2fs/ext2_err.et.in
@@ -479,4 +479,22 @@ ec	EXT2_ET_FILE_EXISTS,
 ec	EXT2_ET_BLOCK_BITMAP_CSUM_INVALID,
 	"Block bitmap checksum does not match bitmap"
 
+ec	EXT2_ET_EA_BAD_NAME_LEN,
+	"Extended attribute has an invalid name length"
+
+ec	EXT2_ET_EA_BAD_VALUE_SIZE,
+	"Extended attribute has an invalid value length"
+
+ec	EXT2_ET_BAD_EA_HASH,
+	"Extended attribute has an incorrect hash"
+
+ec	EXT2_ET_BAD_EA_HEADER,
+	"Extended attribute block has a bad header"
+
+ec	EXT2_ET_EA_KEY_NOT_FOUND,
+	"Extended attribute key not found"
+
+ec	EXT2_ET_EA_NO_SPACE,
+	"Insufficient space to store extended attribute data"
+
 	end
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index c280ea0..09d3d4c 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -637,6 +637,13 @@ typedef struct stat ext2fs_struct_stat;
 #define EXT2_FLAG_FLUSH_NO_SYNC          1
 
 /*
+ * Modify and iterate extended attributes
+ */
+struct ext2_xattr_handle;
+#define XATTR_ABORT	1
+#define XATTR_CHANGED	2
+
+/*
  * function prototypes
  */
 static inline int ext2fs_has_group_desc_csum(ext2_filsys fs)
@@ -1145,6 +1152,27 @@ extern errcode_t ext2fs_adjust_ea_refcount3(ext2_filsys fs, blk64_t blk,
 					   char *block_buf,
 					   int adjust, __u32 *newcount,
 					   ext2_ino_t inum);
+errcode_t ext2fs_xattrs_expand(struct ext2_xattr_handle *h,
+			       unsigned int expandby);
+errcode_t ext2fs_xattrs_write(struct ext2_xattr_handle *handle);
+errcode_t ext2fs_xattrs_read(struct ext2_xattr_handle *handle);
+errcode_t ext2fs_xattrs_iterate(struct ext2_xattr_handle *h,
+				int (*func)(char *name, char *value,
+					    void *data),
+				void *data);
+errcode_t ext2fs_xattr_get(struct ext2_xattr_handle *h, const char *key,
+			   void **value, unsigned int *value_len);
+errcode_t ext2fs_xattr_set(struct ext2_xattr_handle *handle,
+			   const char *key,
+			   const void *value,
+			   unsigned int value_len);
+errcode_t ext2fs_xattr_remove(struct ext2_xattr_handle *handle,
+			      const char *key);
+errcode_t ext2fs_xattrs_open(ext2_filsys fs, ext2_ino_t ino,
+			     struct ext2_xattr_handle **handle);
+errcode_t ext2fs_xattrs_close(struct ext2_xattr_handle **handle);
+errcode_t ext2fs_free_ext_attr(ext2_filsys fs, ext2_ino_t ino,
+			       struct ext2_inode_large *inode);
 
 /* 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..59894ab 100644
--- a/lib/ext2fs/ext_attr.c
+++ b/lib/ext2fs/ext_attr.c
@@ -186,3 +186,745 @@ errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
 	return ext2fs_adjust_ea_refcount2(fs, blk, block_buf, adjust,
 					  newcount);
 }
+
+/* Manipulate the contents of extended attribute regions */
+struct ext2_xattr {
+	char *name;
+	void *value;
+	unsigned int value_len;
+};
+
+struct ext2_xattr_handle {
+	ext2_filsys fs;
+	struct ext2_xattr *attrs;
+	unsigned int length;
+	ext2_ino_t ino;
+	int dirty;
+};
+
+errcode_t ext2fs_xattrs_expand(struct ext2_xattr_handle *h,
+			       unsigned int expandby)
+{
+	struct ext2_xattr *new_attrs;
+	errcode_t err;
+
+	err = ext2fs_get_arrayzero(h->length + expandby,
+				   sizeof(struct ext2_xattr), &new_attrs);
+	if (err)
+		return err;
+
+	memcpy(new_attrs, h->attrs, h->length * sizeof(struct ext2_xattr));
+	ext2fs_free_mem(&h->attrs);
+	h->length += expandby;
+	h->attrs = new_attrs;
+
+	return 0;
+}
+
+struct ea_name_index {
+	int index;
+	const char *name;
+};
+
+static struct ea_name_index ea_names[] = {
+	{1, "user."},
+	{2, "system.posix_acl_access"},
+	{3, "system.posix_acl_default"},
+	{4, "trusted."},
+	{6, "security."},
+	{7, "system."},
+	{0, NULL},
+};
+
+static const char *find_ea_prefix(int index)
+{
+	struct ea_name_index *e;
+
+	for (e = ea_names; e->name; e++)
+		if (e->index == index)
+			return e->name;
+
+	return NULL;
+}
+
+static int find_ea_index(const char *fullname, char **name, int *index)
+{
+	struct ea_name_index *e;
+
+	for (e = ea_names; e->name; e++)
+		if (memcmp(fullname, e->name, strlen(e->name)) == 0) {
+			*name = (char *)fullname + strlen(e->name);
+			*index = e->index;
+			return 1;
+		}
+	return 0;
+}
+
+errcode_t ext2fs_free_ext_attr(ext2_filsys fs, ext2_ino_t ino,
+			       struct ext2_inode_large *inode)
+{
+	struct ext2_ext_attr_header *header;
+	void *block_buf = NULL;
+	dgrp_t grp;
+	blk64_t blk, goal;
+	errcode_t err;
+
+	/* Do we already have an EA block? */
+	blk = ext2fs_file_acl_block(fs, (struct ext2_inode *)inode);
+	if (blk == 0)
+		return 0;
+
+	/* Find block, zero it, write back */
+	if ((blk < fs->super->s_first_data_block) ||
+	    (blk >= ext2fs_blocks_count(fs->super))) {
+		err = EXT2_ET_BAD_EA_BLOCK_NUM;
+		goto out;
+	}
+
+	err = ext2fs_get_mem(fs->blocksize, &block_buf);
+	if (err)
+		goto out;
+
+	err = ext2fs_read_ext_attr3(fs, blk, block_buf, ino);
+	if (err)
+		goto out2;
+
+	header = (struct ext2_ext_attr_header *) block_buf;
+	if (header->h_magic != EXT2_EXT_ATTR_MAGIC) {
+		err = EXT2_ET_BAD_EA_HEADER;
+		goto out2;
+	}
+
+	header->h_refcount--;
+	err = ext2fs_write_ext_attr3(fs, blk, block_buf, ino);
+	if (err)
+		goto out2;
+
+	/* Erase link to block */
+	ext2fs_file_acl_block_set(fs, (struct ext2_inode *)inode, 0);
+	if (header->h_refcount == 0)
+		ext2fs_block_alloc_stats2(fs, blk, -1);
+out2:
+	ext2fs_free_mem(&block_buf);
+out:
+	return err;
+}
+
+static errcode_t prep_ea_block_for_write(ext2_filsys fs, ext2_ino_t ino,
+					 struct ext2_inode_large *inode)
+{
+	struct ext2_ext_attr_header *header;
+	void *block_buf = NULL;
+	dgrp_t grp;
+	blk64_t blk, goal;
+	errcode_t err;
+
+	/* Do we already have an EA block? */
+	blk = ext2fs_file_acl_block(fs, (struct ext2_inode *)inode);
+	if (blk != 0) {
+		if ((blk < fs->super->s_first_data_block) ||
+		    (blk >= ext2fs_blocks_count(fs->super))) {
+			err = EXT2_ET_BAD_EA_BLOCK_NUM;
+			goto out;
+		}
+
+		err = ext2fs_get_mem(fs->blocksize, &block_buf);
+		if (err)
+			goto out;
+
+		err = ext2fs_read_ext_attr3(fs, blk, block_buf, ino);
+		if (err)
+			goto out2;
+
+		header = (struct ext2_ext_attr_header *) block_buf;
+		if (header->h_magic != EXT2_EXT_ATTR_MAGIC) {
+			err = EXT2_ET_BAD_EA_HEADER;
+			goto out2;
+		}
+
+		/* Single-user block.  We're done here. */
+		if (header->h_refcount == 1)
+			return 0;
+
+		/* We need to CoW the block. */
+		header->h_refcount--;
+		err = ext2fs_write_ext_attr3(fs, blk, block_buf, ino);
+		if (err)
+			goto out2;
+	} else {
+		/* No block, we must increment i_blocks */
+		err = ext2fs_iblk_add_blocks(fs, (struct ext2_inode *)inode,
+					     1);
+		if (err)
+			goto out;
+	}
+
+	/* Allocate a block */
+	grp = ext2fs_group_of_ino(fs, ino);
+	goal = ext2fs_inode_table_loc(fs, grp);
+	err = ext2fs_alloc_block2(fs, goal, NULL, &blk);
+	if (err)
+		return err;
+	ext2fs_file_acl_block_set(fs, (struct ext2_inode *)inode, blk);
+out2:
+	ext2fs_free_mem(&block_buf);
+out:
+	return err;
+}
+
+
+static errcode_t write_xattrs_to_buffer(struct ext2_xattr_handle *handle,
+					struct ext2_xattr **pos,
+					void *entries_start,
+					unsigned int storage_size,
+					unsigned int value_offset_correction)
+{
+	struct ext2_xattr *x = *pos;
+	struct ext2_ext_attr_entry *e = entries_start;
+	void *end = entries_start + storage_size;
+	char *shortname;
+	unsigned int entry_size, value_size;
+	int idx, ret;
+
+	/* For all remaining x...  */
+	for (; x < handle->attrs + handle->length; x++) {
+		if (!x->name)
+			continue;
+
+		/* Calculate index and shortname position */
+		shortname = x->name;
+		ret = find_ea_index(x->name, &shortname, &idx);
+
+		/* Calculate entry and value size */
+		entry_size = (sizeof(*e) + strlen(shortname) +
+			      EXT2_EXT_ATTR_PAD - 1) &
+			     ~(EXT2_EXT_ATTR_PAD - 1);
+		value_size = ((x->value_len + EXT2_EXT_ATTR_PAD - 1) /
+			      EXT2_EXT_ATTR_PAD) * EXT2_EXT_ATTR_PAD;
+
+		/*
+		 * Would entry collide with value?
+		 * Note that we must leave sufficient room for a (u32)0 to
+		 * mark the end of the entries.
+		 */
+		if ((void *)e + entry_size + sizeof(__u32) > end - value_size)
+			break;
+
+		/* Fill out e appropriately */
+		e->e_name_len = strlen(shortname);
+		e->e_name_index = (ret ? idx : 0);
+		e->e_value_offs = end - value_size - (void *)entries_start +
+				value_offset_correction;
+		e->e_value_block = 0;
+		e->e_value_size = x->value_len;
+
+		/* Store name and value */
+		end -= value_size;
+		memcpy((void *)e + sizeof(*e), shortname, e->e_name_len);
+		memcpy(end, x->value, e->e_value_size);
+
+		e->e_hash = ext2fs_ext_attr_hash_entry(e, end);
+
+		e = EXT2_EXT_ATTR_NEXT(e);
+		*(__u32 *)e = 0;
+	}
+	*pos = x;
+
+	return 0;
+}
+
+errcode_t ext2fs_xattrs_write(struct ext2_xattr_handle *handle)
+{
+	struct ext2_xattr *x;
+	struct ext2_inode_large *inode;
+	void *start, *block_buf = NULL;
+	struct ext2_ext_attr_header *header;
+	__u32 ea_inode_magic;
+	blk64_t blk;
+	unsigned int storage_size;
+	unsigned int i, written;
+	errcode_t err;
+
+	if (!EXT2_HAS_COMPAT_FEATURE(handle->fs->super,
+				     EXT2_FEATURE_COMPAT_EXT_ATTR))
+		return 0;
+
+	i = EXT2_INODE_SIZE(handle->fs->super);
+	if (i < sizeof(*inode))
+		i = sizeof(*inode);
+	err = ext2fs_get_memzero(i, &inode);
+	if (err)
+		return err;
+
+	err = ext2fs_read_inode_full(handle->fs, handle->ino,
+				     (struct ext2_inode *)inode,
+				     EXT2_INODE_SIZE(handle->fs->super));
+	if (err)
+		goto out;
+
+	x = handle->attrs;
+	/* Does the inode have size for EA? */
+	if (EXT2_INODE_SIZE(handle->fs->super) <= EXT2_GOOD_OLD_INODE_SIZE +
+						  inode->i_extra_isize +
+						  sizeof(__u32))
+		goto write_ea_block;
+
+	/* Write the inode EA */
+	ea_inode_magic = EXT2_EXT_ATTR_MAGIC;
+	memcpy(((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
+	       inode->i_extra_isize, &ea_inode_magic, sizeof(__u32));
+	storage_size = EXT2_INODE_SIZE(handle->fs->super) -
+		EXT2_GOOD_OLD_INODE_SIZE - inode->i_extra_isize -
+		sizeof(__u32);
+	start = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
+		inode->i_extra_isize + sizeof(__u32);
+
+	err = write_xattrs_to_buffer(handle, &x, start, storage_size, 0);
+	if (err)
+		goto out;
+
+	/* Are we done? */
+	if (x == handle->attrs + handle->length)
+		goto skip_ea_block;
+
+write_ea_block:
+	/* Write the EA block */
+	err = ext2fs_get_mem(handle->fs->blocksize, &block_buf);
+	if (err)
+		goto out;
+
+	storage_size = handle->fs->blocksize -
+		sizeof(struct ext2_ext_attr_header);
+	start = block_buf + sizeof(struct ext2_ext_attr_header);
+
+	err = write_xattrs_to_buffer(handle, &x, start, storage_size,
+				     (void *)start - block_buf);
+	if (err)
+		goto out2;
+
+	if (x < handle->attrs + handle->length) {
+		err = EXT2_ET_EA_NO_SPACE;
+		goto out2;
+	}
+
+	if (block_buf) {
+		/* Write a header on the EA block */
+		header = block_buf;
+		header->h_magic = EXT2_EXT_ATTR_MAGIC;
+		header->h_refcount = 1;
+		header->h_blocks = 1;
+
+		/* Get a new block for writing */
+		err = prep_ea_block_for_write(handle->fs, handle->ino, inode);
+		if (err)
+			goto out2;
+
+		/* Finally, write the new EA block */
+		blk = ext2fs_file_acl_block(handle->fs,
+					    (struct ext2_inode *)inode);
+		err = ext2fs_write_ext_attr3(handle->fs, blk, block_buf,
+					     handle->ino);
+		if (err)
+			goto out2;
+	}
+
+skip_ea_block:
+	blk = ext2fs_file_acl_block(handle->fs, (struct ext2_inode *)inode);
+	if (!block_buf && blk) {
+		/* xattrs shrunk, free the block */
+		ext2fs_file_acl_block_set(handle->fs,
+					  (struct ext2_inode *)inode, 0);
+		err = ext2fs_iblk_sub_blocks(handle->fs,
+					     (struct ext2_inode *)inode, 1);
+		if (err)
+			goto out;
+		ext2fs_block_alloc_stats2(handle->fs, blk, -1);
+	}
+
+	/* Write the inode */
+	err = ext2fs_write_inode_full(handle->fs, handle->ino,
+				      (struct ext2_inode *)inode,
+				      EXT2_INODE_SIZE(handle->fs->super));
+	if (err)
+		goto out2;
+
+out2:
+	ext2fs_free_mem(&block_buf);
+out:
+	ext2fs_free_mem(&inode);
+	handle->dirty = 0;
+	return err;
+}
+
+static errcode_t read_xattrs_from_buffer(struct ext2_xattr_handle *handle,
+					 struct ext2_ext_attr_entry *entries,
+					 unsigned int storage_size,
+					 void *value_start)
+{
+	struct ext2_xattr *x;
+	struct ext2_ext_attr_entry *entry;
+	const char *prefix;
+	void *ptr;
+	unsigned int remain, prefix_len;
+	errcode_t err;
+
+	x = handle->attrs;
+	while (x->name)
+		x++;
+
+	entry = entries;
+	while (!EXT2_EXT_IS_LAST_ENTRY(entry)) {
+		__u32 hash;
+
+		/* header eats this space */
+		remain -= sizeof(struct ext2_ext_attr_entry);
+
+		/* is attribute name valid? */
+		if (EXT2_EXT_ATTR_SIZE(entry->e_name_len) > remain)
+			return EXT2_ET_EA_BAD_NAME_LEN;
+
+		/* attribute len eats this space */
+		remain -= EXT2_EXT_ATTR_SIZE(entry->e_name_len);
+
+		/* check value size */
+		if (entry->e_value_size > remain)
+			return EXT2_ET_EA_BAD_VALUE_SIZE;
+
+		/* e_value_block must be 0 in inode's ea */
+		if (entry->e_value_block != 0)
+			return EXT2_ET_BAD_EA_BLOCK_NUM;
+
+		hash = ext2fs_ext_attr_hash_entry(entry, value_start +
+							 entry->e_value_offs);
+
+		/* e_hash may be 0 in older inode's ea */
+		if (entry->e_hash != 0 && entry->e_hash != hash)
+			return EXT2_ET_BAD_EA_HASH;
+
+		remain -= entry->e_value_size;
+
+		/* Allocate space for more attrs? */
+		if (x == handle->attrs + handle->length) {
+			err = ext2fs_xattrs_expand(handle, 4);
+			if (err)
+				return err;
+			x = handle->attrs + handle->length - 4;
+		}
+
+		/* Extract name/value */
+		prefix = find_ea_prefix(entry->e_name_index);
+		prefix_len = (prefix ? strlen(prefix) : 0);
+		err = ext2fs_get_memzero(entry->e_name_len + prefix_len + 1,
+					 &x->name);
+		if (err)
+			return err;
+		if (prefix)
+			memcpy(x->name, prefix, prefix_len);
+		if (entry->e_name_len)
+			memcpy(x->name + prefix_len,
+			       (void *)entry + sizeof(*entry),
+			       entry->e_name_len);
+
+		err = ext2fs_get_mem(entry->e_value_size, &x->value);
+		if (err)
+			return err;
+		x->value_len = entry->e_value_size;
+		memcpy(x->value, value_start + entry->e_value_offs,
+		       entry->e_value_size);
+		x++;
+		entry = EXT2_EXT_ATTR_NEXT(entry);
+	}
+
+	return 0;
+}
+
+errcode_t ext2fs_xattrs_read(struct ext2_xattr_handle *handle)
+{
+	struct ext2_xattr *attrs = NULL, *x;
+	unsigned int attrs_len;
+	struct ext2_inode_large *inode;
+	struct ext2_ext_attr_header *header;
+	__u32 ea_inode_magic;
+	unsigned int storage_size;
+	void *start, *block_buf = NULL;
+	blk64_t blk;
+	int i;
+	errcode_t err;
+
+	if (!EXT2_HAS_COMPAT_FEATURE(handle->fs->super,
+				     EXT2_FEATURE_COMPAT_EXT_ATTR))
+		return 0;
+
+	i = EXT2_INODE_SIZE(handle->fs->super);
+	if (i < sizeof(*inode))
+		i = sizeof(*inode);
+	err = ext2fs_get_memzero(i, &inode);
+	if (err)
+		return err;
+
+	err = ext2fs_read_inode_full(handle->fs, handle->ino,
+				     (struct ext2_inode *)inode,
+				     EXT2_INODE_SIZE(handle->fs->super));
+	if (err)
+		goto out;
+
+	/* Does the inode have size for EA? */
+	if (EXT2_INODE_SIZE(handle->fs->super) <= EXT2_GOOD_OLD_INODE_SIZE +
+						  inode->i_extra_isize +
+						  sizeof(__u32))
+		goto read_ea_block;
+
+	/* Look for EA in the inode */
+	memcpy(&ea_inode_magic, ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
+	       inode->i_extra_isize, sizeof(__u32));
+	if (ea_inode_magic == EXT2_EXT_ATTR_MAGIC) {
+		storage_size = EXT2_INODE_SIZE(handle->fs->super) -
+			EXT2_GOOD_OLD_INODE_SIZE - inode->i_extra_isize -
+			sizeof(__u32);
+		start = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
+			inode->i_extra_isize + sizeof(__u32);
+
+		err = read_xattrs_from_buffer(handle, start, storage_size,
+					      start);
+		if (err)
+			goto out;
+	}
+
+read_ea_block:
+	/* Look for EA in a separate EA block */
+	blk = ext2fs_file_acl_block(handle->fs, (struct ext2_inode *)inode);
+	if (blk != 0) {
+		if ((blk < handle->fs->super->s_first_data_block) ||
+		    (blk >= ext2fs_blocks_count(handle->fs->super))) {
+			err = EXT2_ET_BAD_EA_BLOCK_NUM;
+			goto out;
+		}
+
+		err = ext2fs_get_mem(handle->fs->blocksize, &block_buf);
+		if (err)
+			goto out;
+
+		err = ext2fs_read_ext_attr3(handle->fs, blk, block_buf,
+					    handle->ino);
+		if (err)
+			goto out3;
+
+		header = (struct ext2_ext_attr_header *) block_buf;
+		if (header->h_magic != EXT2_EXT_ATTR_MAGIC) {
+			err = EXT2_ET_BAD_EA_HEADER;
+			goto out3;
+		}
+
+		if (header->h_blocks != 1) {
+			err = EXT2_ET_BAD_EA_HEADER;
+			goto out3;
+		}
+
+		/* Read EAs */
+		storage_size = handle->fs->blocksize -
+			sizeof(struct ext2_ext_attr_header);
+		start = block_buf + sizeof(struct ext2_ext_attr_header);
+		err = read_xattrs_from_buffer(handle, start, storage_size,
+					      block_buf);
+		if (err)
+			goto out3;
+
+		ext2fs_free_mem(&block_buf);
+	}
+
+	ext2fs_free_mem(&block_buf);
+	ext2fs_free_mem(&inode);
+	return 0;
+
+out3:
+	ext2fs_free_mem(&block_buf);
+out:
+	ext2fs_free_mem(&inode);
+	return err;
+}
+
+#define XATTR_ABORT	1
+#define XATTR_CHANGED	2
+errcode_t ext2fs_xattrs_iterate(struct ext2_xattr_handle *h,
+				int (*func)(char *name, char *value,
+					    void *data),
+				void *data)
+{
+	struct ext2_xattr *x;
+	errcode_t err;
+	int ret;
+
+	for (x = h->attrs; x < h->attrs + h->length; x++) {
+		if (!x->name)
+			continue;
+
+		ret = func(x->name, x->value, data);
+		if (ret & XATTR_CHANGED)
+			h->dirty = 1;
+		if (ret & XATTR_ABORT)
+			return 0;
+	}
+
+	return 0;
+}
+
+errcode_t ext2fs_xattr_get(struct ext2_xattr_handle *h, const char *key,
+			   void **value, unsigned int *value_len)
+{
+	struct ext2_xattr *x;
+	void *val;
+	errcode_t err;
+
+	for (x = h->attrs; x < h->attrs + h->length; x++) {
+		if (!x->name)
+			continue;
+
+		if (strcmp(x->name, key) == 0) {
+			err = ext2fs_get_mem(x->value_len, &val);
+			if (err)
+				return err;
+			memcpy(val, x->value, x->value_len);
+			*value = val;
+			*value_len = x->value_len;
+			return 0;
+		}
+	}
+
+	return EXT2_ET_EA_KEY_NOT_FOUND;
+}
+
+errcode_t ext2fs_xattr_set(struct ext2_xattr_handle *handle,
+			   const char *key,
+			   const void *value,
+			   unsigned int value_len)
+{
+	struct ext2_xattr *x, *last_empty;
+	char *new_value;
+	errcode_t err;
+
+	last_empty = NULL;
+	for (x = handle->attrs; x < handle->attrs + handle->length; x++) {
+		if (!x->name) {
+			last_empty = x;
+			continue;
+		}
+
+		/* Replace xattr */
+		if (strcmp(x->name, key) == 0) {
+			err = ext2fs_get_mem(value_len, &new_value);
+			if (err)
+				return err;
+			memcpy(new_value, value, value_len);
+			ext2fs_free_mem(&x->value);
+			x->value = new_value;
+			x->value_len = value_len;
+			handle->dirty = 1;
+			return 0;
+		}
+	}
+
+	/* Add attr to empty slot */
+	if (last_empty) {
+		err = ext2fs_get_mem(strlen(key) + 1, &last_empty->name);
+		if (err)
+			return err;
+		strcpy(last_empty->name, key);
+
+		err = ext2fs_get_mem(value_len, &last_empty->value);
+		if (err)
+			return err;
+		memcpy(last_empty->value, value, value_len);
+		last_empty->value_len = value_len;
+		handle->dirty = 1;
+		return 0;
+	}
+
+	/* Expand array, append slot */
+	err = ext2fs_xattrs_expand(handle, 4);
+	if (err)
+		return err;
+
+	x = handle->attrs + handle->length - 4;
+	err = ext2fs_get_mem(strlen(key) + 1, &x->name);
+	if (err)
+		return err;
+	strcpy(x->name, key);
+
+	err = ext2fs_get_mem(value_len, &x->value);
+	if (err)
+		return err;
+	memcpy(x->value, value, value_len);
+	x->value_len = value_len;
+	handle->dirty = 1;
+	return 0;
+}
+
+errcode_t ext2fs_xattr_remove(struct ext2_xattr_handle *handle,
+			      const char *key)
+{
+	struct ext2_xattr *x;
+	errcode_t err;
+
+	for (x = handle->attrs; x < handle->attrs + handle->length; x++) {
+		if (!x->name)
+			continue;
+
+		if (strcmp(x->name, key) == 0) {
+			ext2fs_free_mem(&x->name);
+			ext2fs_free_mem(&x->value);
+			x->value_len = 0;
+			handle->dirty = 1;
+			return 0;
+		}
+	}
+
+	return EXT2_ET_EA_KEY_NOT_FOUND;
+}
+
+errcode_t ext2fs_xattrs_open(ext2_filsys fs, ext2_ino_t ino,
+			     struct ext2_xattr_handle **handle)
+{
+	struct ext2_xattr_handle *h;
+	errcode_t err;
+
+	err = ext2fs_get_memzero(sizeof(*h), &h);
+	if (err)
+		return err;
+
+	h->length = 4;
+	err = ext2fs_get_arrayzero(h->length, sizeof(struct ext2_xattr),
+				   &h->attrs);
+	if (err) {
+		ext2fs_free_mem(&h);
+		return err;
+	}
+	h->ino = ino;
+	h->fs = fs;
+	*handle = h;
+	return 0;
+}
+
+errcode_t ext2fs_xattrs_close(struct ext2_xattr_handle **handle)
+{
+	unsigned int i;
+	struct ext2_xattr_handle *h = *handle;
+	struct ext2_xattr *a = h->attrs;
+	errcode_t err;
+
+	if (h->dirty) {
+		err = ext2fs_xattrs_write(h);
+		if (err)
+			return err;
+	}
+
+	for (i = 0; i < h->length; i++) {
+		if (a[i].name)
+			ext2fs_free_mem(&a[i].name);
+		if (a[i].value)
+			ext2fs_free_mem(&a[i].value);
+	}
+
+	ext2fs_free_mem(&h->attrs);
+	ext2fs_free_mem(handle);
+	return 0;
+}

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

* Re: [PATCH v1 19/22] e2fsck: check inline_data in pass3
  2013-10-12  0:54   ` Darrick J. Wong
@ 2013-10-12  9:06     ` Zheng Liu
  2013-10-12  9:09       ` Darrick J. Wong
  0 siblings, 1 reply; 67+ messages in thread
From: Zheng Liu @ 2013-10-12  9:06 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-ext4, Theodore Ts'o, Zheng Liu

On Fri, Oct 11, 2013 at 05:54:10PM -0700, Darrick J. Wong wrote:
> On Fri, Aug 02, 2013 at 05:49:46PM +0800, Zheng Liu wrote:
> > From: Zheng Liu <wenqing.lz@taobao.com>
> > 
> > In e2fsck_expand_directory() we don't handle a dir with inline data
> > because when this function is called the directory inode shouldn't
> > contains inline data.
> > 
> > Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> > Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
> > ---
> >  e2fsck/pass3.c  |   12 ++++++++++++
> >  e2fsck/rehash.c |    3 ++-
> >  2 files changed, 14 insertions(+), 1 deletion(-)
> > 
> > diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c
> > index a379e9b..5052345 100644
> > --- a/e2fsck/pass3.c
> > +++ b/e2fsck/pass3.c
> > @@ -787,6 +787,18 @@ errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
> >  	es.ctx = ctx;
> >  	es.dir = dir;
> >  
> > +	/*
> > +	 * 'lost+found' dir shouldn't contains inline data.  So we
> > +	 * need to clear this flag.
> > +	 */
> > +	if (ext2fs_inode_has_inline_data(fs, dir)) {
> > +		retval = ext2fs_read_inode(fs, dir, &inode);
> > +		if (retval)
> > +			return retval;
> > +		inode.i_flags &= ~EXT4_INLINE_DATA_FL;
> > +		e2fsck_write_inode(ctx, dir, &inode, "clear inline_data flag");
> > +	}
> > +
> >  	retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND,
> >  				       0, expand_dir_proc, &es);
> 
> Are you saying that lost+found can have inline_data set yet i_blocks is
> actually a block map/extent head?  Or are we supposed to zero i_blocks?
> 
> If we clear EXT4_INLINE_DATA_FL and then try to iterate blocks, are we setting
> ourselves up to read (formerly inline) dirents as a block map and iterate it?
> 
> Shouldn't we care if the inode write fails?

lost+found dir shouldn't have inline_data flag because this is a special
directory that it is preallocated some blocks when it is created because
we need to avoid to allocate some blocks for it when we check a file
system using e2fsck.  So we need to clear inline_data flag if this dir
has this flag.

                                                - Zheng

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

* Re: [PATCH v1 03/22] libext2fs: add functions to operate on extended attribute
  2013-10-12  9:02           ` Darrick J. Wong
@ 2013-10-12  9:08             ` Zheng Liu
  0 siblings, 0 replies; 67+ messages in thread
From: Zheng Liu @ 2013-10-12  9:08 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-ext4, Zheng Liu, Theodore Ts'o

On Sat, Oct 12, 2013 at 02:02:35AM -0700, Darrick J. Wong wrote:
[...]
> > > > Sorry, I still havn't had a chance to take a closer look at your patch
> > > > set for e2fsprogs.  I will review it ASAP.
> > > 
> > > Ok.  I'm getting ready to re-spam the mailing list with some more fixes, so you
> > > can relax for a day or two.  There were some bugs handling inode_size=128.
> > 
> > Welcome to flush my mail box. :-p
> 
> He he he there are 24 of those patches... I got lucky and Ted picked a few more
> tonight. :)

Great!  I will take a closer look at your patch.

Thanks,
                                                - Zheng

> 
> --D
> 
> Well, if you're curious, here's the latest xattr API patch.  I wonder if the
> minimum size of the inode ought to be EXT2_GOOD_OLD_SIZE + i_extra_isize + 8
> bytes (to fit the EA magic and the magic zero that says "end of keys")?  But
> it's too late at night to think.
> 
> From: Darrick J. Wong <darrick.wong@oracle.com>
> Subject: [PATCH] libext2fs: support modifying arbitrary extended attributes
> 
> Add functions to allow clients to get, set, and remove extended
> attributes from any file.  It also supports modifying EAs living in
> i_file_acl.
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
>  lib/ext2fs/ext2_err.et.in |   18 +
>  lib/ext2fs/ext2fs.h       |   28 ++
>  lib/ext2fs/ext_attr.c     |  742 +++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 788 insertions(+)
> 
> diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in
> index c547a2c..262f4a4 100644
> --- a/lib/ext2fs/ext2_err.et.in
> +++ b/lib/ext2fs/ext2_err.et.in
> @@ -479,4 +479,22 @@ ec	EXT2_ET_FILE_EXISTS,
>  ec	EXT2_ET_BLOCK_BITMAP_CSUM_INVALID,
>  	"Block bitmap checksum does not match bitmap"
>  
> +ec	EXT2_ET_EA_BAD_NAME_LEN,
> +	"Extended attribute has an invalid name length"
> +
> +ec	EXT2_ET_EA_BAD_VALUE_SIZE,
> +	"Extended attribute has an invalid value length"
> +
> +ec	EXT2_ET_BAD_EA_HASH,
> +	"Extended attribute has an incorrect hash"
> +
> +ec	EXT2_ET_BAD_EA_HEADER,
> +	"Extended attribute block has a bad header"
> +
> +ec	EXT2_ET_EA_KEY_NOT_FOUND,
> +	"Extended attribute key not found"
> +
> +ec	EXT2_ET_EA_NO_SPACE,
> +	"Insufficient space to store extended attribute data"
> +
>  	end
> diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
> index c280ea0..09d3d4c 100644
> --- a/lib/ext2fs/ext2fs.h
> +++ b/lib/ext2fs/ext2fs.h
> @@ -637,6 +637,13 @@ typedef struct stat ext2fs_struct_stat;
>  #define EXT2_FLAG_FLUSH_NO_SYNC          1
>  
>  /*
> + * Modify and iterate extended attributes
> + */
> +struct ext2_xattr_handle;
> +#define XATTR_ABORT	1
> +#define XATTR_CHANGED	2
> +
> +/*
>   * function prototypes
>   */
>  static inline int ext2fs_has_group_desc_csum(ext2_filsys fs)
> @@ -1145,6 +1152,27 @@ extern errcode_t ext2fs_adjust_ea_refcount3(ext2_filsys fs, blk64_t blk,
>  					   char *block_buf,
>  					   int adjust, __u32 *newcount,
>  					   ext2_ino_t inum);
> +errcode_t ext2fs_xattrs_expand(struct ext2_xattr_handle *h,
> +			       unsigned int expandby);
> +errcode_t ext2fs_xattrs_write(struct ext2_xattr_handle *handle);
> +errcode_t ext2fs_xattrs_read(struct ext2_xattr_handle *handle);
> +errcode_t ext2fs_xattrs_iterate(struct ext2_xattr_handle *h,
> +				int (*func)(char *name, char *value,
> +					    void *data),
> +				void *data);
> +errcode_t ext2fs_xattr_get(struct ext2_xattr_handle *h, const char *key,
> +			   void **value, unsigned int *value_len);
> +errcode_t ext2fs_xattr_set(struct ext2_xattr_handle *handle,
> +			   const char *key,
> +			   const void *value,
> +			   unsigned int value_len);
> +errcode_t ext2fs_xattr_remove(struct ext2_xattr_handle *handle,
> +			      const char *key);
> +errcode_t ext2fs_xattrs_open(ext2_filsys fs, ext2_ino_t ino,
> +			     struct ext2_xattr_handle **handle);
> +errcode_t ext2fs_xattrs_close(struct ext2_xattr_handle **handle);
> +errcode_t ext2fs_free_ext_attr(ext2_filsys fs, ext2_ino_t ino,
> +			       struct ext2_inode_large *inode);
>  
>  /* 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..59894ab 100644
> --- a/lib/ext2fs/ext_attr.c
> +++ b/lib/ext2fs/ext_attr.c
> @@ -186,3 +186,745 @@ errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
>  	return ext2fs_adjust_ea_refcount2(fs, blk, block_buf, adjust,
>  					  newcount);
>  }
> +
> +/* Manipulate the contents of extended attribute regions */
> +struct ext2_xattr {
> +	char *name;
> +	void *value;
> +	unsigned int value_len;
> +};
> +
> +struct ext2_xattr_handle {
> +	ext2_filsys fs;
> +	struct ext2_xattr *attrs;
> +	unsigned int length;
> +	ext2_ino_t ino;
> +	int dirty;
> +};
> +
> +errcode_t ext2fs_xattrs_expand(struct ext2_xattr_handle *h,
> +			       unsigned int expandby)
> +{
> +	struct ext2_xattr *new_attrs;
> +	errcode_t err;
> +
> +	err = ext2fs_get_arrayzero(h->length + expandby,
> +				   sizeof(struct ext2_xattr), &new_attrs);
> +	if (err)
> +		return err;
> +
> +	memcpy(new_attrs, h->attrs, h->length * sizeof(struct ext2_xattr));
> +	ext2fs_free_mem(&h->attrs);
> +	h->length += expandby;
> +	h->attrs = new_attrs;
> +
> +	return 0;
> +}
> +
> +struct ea_name_index {
> +	int index;
> +	const char *name;
> +};
> +
> +static struct ea_name_index ea_names[] = {
> +	{1, "user."},
> +	{2, "system.posix_acl_access"},
> +	{3, "system.posix_acl_default"},
> +	{4, "trusted."},
> +	{6, "security."},
> +	{7, "system."},
> +	{0, NULL},
> +};
> +
> +static const char *find_ea_prefix(int index)
> +{
> +	struct ea_name_index *e;
> +
> +	for (e = ea_names; e->name; e++)
> +		if (e->index == index)
> +			return e->name;
> +
> +	return NULL;
> +}
> +
> +static int find_ea_index(const char *fullname, char **name, int *index)
> +{
> +	struct ea_name_index *e;
> +
> +	for (e = ea_names; e->name; e++)
> +		if (memcmp(fullname, e->name, strlen(e->name)) == 0) {
> +			*name = (char *)fullname + strlen(e->name);
> +			*index = e->index;
> +			return 1;
> +		}
> +	return 0;
> +}
> +
> +errcode_t ext2fs_free_ext_attr(ext2_filsys fs, ext2_ino_t ino,
> +			       struct ext2_inode_large *inode)
> +{
> +	struct ext2_ext_attr_header *header;
> +	void *block_buf = NULL;
> +	dgrp_t grp;
> +	blk64_t blk, goal;
> +	errcode_t err;
> +
> +	/* Do we already have an EA block? */
> +	blk = ext2fs_file_acl_block(fs, (struct ext2_inode *)inode);
> +	if (blk == 0)
> +		return 0;
> +
> +	/* Find block, zero it, write back */
> +	if ((blk < fs->super->s_first_data_block) ||
> +	    (blk >= ext2fs_blocks_count(fs->super))) {
> +		err = EXT2_ET_BAD_EA_BLOCK_NUM;
> +		goto out;
> +	}
> +
> +	err = ext2fs_get_mem(fs->blocksize, &block_buf);
> +	if (err)
> +		goto out;
> +
> +	err = ext2fs_read_ext_attr3(fs, blk, block_buf, ino);
> +	if (err)
> +		goto out2;
> +
> +	header = (struct ext2_ext_attr_header *) block_buf;
> +	if (header->h_magic != EXT2_EXT_ATTR_MAGIC) {
> +		err = EXT2_ET_BAD_EA_HEADER;
> +		goto out2;
> +	}
> +
> +	header->h_refcount--;
> +	err = ext2fs_write_ext_attr3(fs, blk, block_buf, ino);
> +	if (err)
> +		goto out2;
> +
> +	/* Erase link to block */
> +	ext2fs_file_acl_block_set(fs, (struct ext2_inode *)inode, 0);
> +	if (header->h_refcount == 0)
> +		ext2fs_block_alloc_stats2(fs, blk, -1);
> +out2:
> +	ext2fs_free_mem(&block_buf);
> +out:
> +	return err;
> +}
> +
> +static errcode_t prep_ea_block_for_write(ext2_filsys fs, ext2_ino_t ino,
> +					 struct ext2_inode_large *inode)
> +{
> +	struct ext2_ext_attr_header *header;
> +	void *block_buf = NULL;
> +	dgrp_t grp;
> +	blk64_t blk, goal;
> +	errcode_t err;
> +
> +	/* Do we already have an EA block? */
> +	blk = ext2fs_file_acl_block(fs, (struct ext2_inode *)inode);
> +	if (blk != 0) {
> +		if ((blk < fs->super->s_first_data_block) ||
> +		    (blk >= ext2fs_blocks_count(fs->super))) {
> +			err = EXT2_ET_BAD_EA_BLOCK_NUM;
> +			goto out;
> +		}
> +
> +		err = ext2fs_get_mem(fs->blocksize, &block_buf);
> +		if (err)
> +			goto out;
> +
> +		err = ext2fs_read_ext_attr3(fs, blk, block_buf, ino);
> +		if (err)
> +			goto out2;
> +
> +		header = (struct ext2_ext_attr_header *) block_buf;
> +		if (header->h_magic != EXT2_EXT_ATTR_MAGIC) {
> +			err = EXT2_ET_BAD_EA_HEADER;
> +			goto out2;
> +		}
> +
> +		/* Single-user block.  We're done here. */
> +		if (header->h_refcount == 1)
> +			return 0;
> +
> +		/* We need to CoW the block. */
> +		header->h_refcount--;
> +		err = ext2fs_write_ext_attr3(fs, blk, block_buf, ino);
> +		if (err)
> +			goto out2;
> +	} else {
> +		/* No block, we must increment i_blocks */
> +		err = ext2fs_iblk_add_blocks(fs, (struct ext2_inode *)inode,
> +					     1);
> +		if (err)
> +			goto out;
> +	}
> +
> +	/* Allocate a block */
> +	grp = ext2fs_group_of_ino(fs, ino);
> +	goal = ext2fs_inode_table_loc(fs, grp);
> +	err = ext2fs_alloc_block2(fs, goal, NULL, &blk);
> +	if (err)
> +		return err;
> +	ext2fs_file_acl_block_set(fs, (struct ext2_inode *)inode, blk);
> +out2:
> +	ext2fs_free_mem(&block_buf);
> +out:
> +	return err;
> +}
> +
> +
> +static errcode_t write_xattrs_to_buffer(struct ext2_xattr_handle *handle,
> +					struct ext2_xattr **pos,
> +					void *entries_start,
> +					unsigned int storage_size,
> +					unsigned int value_offset_correction)
> +{
> +	struct ext2_xattr *x = *pos;
> +	struct ext2_ext_attr_entry *e = entries_start;
> +	void *end = entries_start + storage_size;
> +	char *shortname;
> +	unsigned int entry_size, value_size;
> +	int idx, ret;
> +
> +	/* For all remaining x...  */
> +	for (; x < handle->attrs + handle->length; x++) {
> +		if (!x->name)
> +			continue;
> +
> +		/* Calculate index and shortname position */
> +		shortname = x->name;
> +		ret = find_ea_index(x->name, &shortname, &idx);
> +
> +		/* Calculate entry and value size */
> +		entry_size = (sizeof(*e) + strlen(shortname) +
> +			      EXT2_EXT_ATTR_PAD - 1) &
> +			     ~(EXT2_EXT_ATTR_PAD - 1);
> +		value_size = ((x->value_len + EXT2_EXT_ATTR_PAD - 1) /
> +			      EXT2_EXT_ATTR_PAD) * EXT2_EXT_ATTR_PAD;
> +
> +		/*
> +		 * Would entry collide with value?
> +		 * Note that we must leave sufficient room for a (u32)0 to
> +		 * mark the end of the entries.
> +		 */
> +		if ((void *)e + entry_size + sizeof(__u32) > end - value_size)
> +			break;
> +
> +		/* Fill out e appropriately */
> +		e->e_name_len = strlen(shortname);
> +		e->e_name_index = (ret ? idx : 0);
> +		e->e_value_offs = end - value_size - (void *)entries_start +
> +				value_offset_correction;
> +		e->e_value_block = 0;
> +		e->e_value_size = x->value_len;
> +
> +		/* Store name and value */
> +		end -= value_size;
> +		memcpy((void *)e + sizeof(*e), shortname, e->e_name_len);
> +		memcpy(end, x->value, e->e_value_size);
> +
> +		e->e_hash = ext2fs_ext_attr_hash_entry(e, end);
> +
> +		e = EXT2_EXT_ATTR_NEXT(e);
> +		*(__u32 *)e = 0;
> +	}
> +	*pos = x;
> +
> +	return 0;
> +}
> +
> +errcode_t ext2fs_xattrs_write(struct ext2_xattr_handle *handle)
> +{
> +	struct ext2_xattr *x;
> +	struct ext2_inode_large *inode;
> +	void *start, *block_buf = NULL;
> +	struct ext2_ext_attr_header *header;
> +	__u32 ea_inode_magic;
> +	blk64_t blk;
> +	unsigned int storage_size;
> +	unsigned int i, written;
> +	errcode_t err;
> +
> +	if (!EXT2_HAS_COMPAT_FEATURE(handle->fs->super,
> +				     EXT2_FEATURE_COMPAT_EXT_ATTR))
> +		return 0;
> +
> +	i = EXT2_INODE_SIZE(handle->fs->super);
> +	if (i < sizeof(*inode))
> +		i = sizeof(*inode);
> +	err = ext2fs_get_memzero(i, &inode);
> +	if (err)
> +		return err;
> +
> +	err = ext2fs_read_inode_full(handle->fs, handle->ino,
> +				     (struct ext2_inode *)inode,
> +				     EXT2_INODE_SIZE(handle->fs->super));
> +	if (err)
> +		goto out;
> +
> +	x = handle->attrs;
> +	/* Does the inode have size for EA? */
> +	if (EXT2_INODE_SIZE(handle->fs->super) <= EXT2_GOOD_OLD_INODE_SIZE +
> +						  inode->i_extra_isize +
> +						  sizeof(__u32))
> +		goto write_ea_block;
> +
> +	/* Write the inode EA */
> +	ea_inode_magic = EXT2_EXT_ATTR_MAGIC;
> +	memcpy(((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
> +	       inode->i_extra_isize, &ea_inode_magic, sizeof(__u32));
> +	storage_size = EXT2_INODE_SIZE(handle->fs->super) -
> +		EXT2_GOOD_OLD_INODE_SIZE - inode->i_extra_isize -
> +		sizeof(__u32);
> +	start = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
> +		inode->i_extra_isize + sizeof(__u32);
> +
> +	err = write_xattrs_to_buffer(handle, &x, start, storage_size, 0);
> +	if (err)
> +		goto out;
> +
> +	/* Are we done? */
> +	if (x == handle->attrs + handle->length)
> +		goto skip_ea_block;
> +
> +write_ea_block:
> +	/* Write the EA block */
> +	err = ext2fs_get_mem(handle->fs->blocksize, &block_buf);
> +	if (err)
> +		goto out;
> +
> +	storage_size = handle->fs->blocksize -
> +		sizeof(struct ext2_ext_attr_header);
> +	start = block_buf + sizeof(struct ext2_ext_attr_header);
> +
> +	err = write_xattrs_to_buffer(handle, &x, start, storage_size,
> +				     (void *)start - block_buf);
> +	if (err)
> +		goto out2;
> +
> +	if (x < handle->attrs + handle->length) {
> +		err = EXT2_ET_EA_NO_SPACE;
> +		goto out2;
> +	}
> +
> +	if (block_buf) {
> +		/* Write a header on the EA block */
> +		header = block_buf;
> +		header->h_magic = EXT2_EXT_ATTR_MAGIC;
> +		header->h_refcount = 1;
> +		header->h_blocks = 1;
> +
> +		/* Get a new block for writing */
> +		err = prep_ea_block_for_write(handle->fs, handle->ino, inode);
> +		if (err)
> +			goto out2;
> +
> +		/* Finally, write the new EA block */
> +		blk = ext2fs_file_acl_block(handle->fs,
> +					    (struct ext2_inode *)inode);
> +		err = ext2fs_write_ext_attr3(handle->fs, blk, block_buf,
> +					     handle->ino);
> +		if (err)
> +			goto out2;
> +	}
> +
> +skip_ea_block:
> +	blk = ext2fs_file_acl_block(handle->fs, (struct ext2_inode *)inode);
> +	if (!block_buf && blk) {
> +		/* xattrs shrunk, free the block */
> +		ext2fs_file_acl_block_set(handle->fs,
> +					  (struct ext2_inode *)inode, 0);
> +		err = ext2fs_iblk_sub_blocks(handle->fs,
> +					     (struct ext2_inode *)inode, 1);
> +		if (err)
> +			goto out;
> +		ext2fs_block_alloc_stats2(handle->fs, blk, -1);
> +	}
> +
> +	/* Write the inode */
> +	err = ext2fs_write_inode_full(handle->fs, handle->ino,
> +				      (struct ext2_inode *)inode,
> +				      EXT2_INODE_SIZE(handle->fs->super));
> +	if (err)
> +		goto out2;
> +
> +out2:
> +	ext2fs_free_mem(&block_buf);
> +out:
> +	ext2fs_free_mem(&inode);
> +	handle->dirty = 0;
> +	return err;
> +}
> +
> +static errcode_t read_xattrs_from_buffer(struct ext2_xattr_handle *handle,
> +					 struct ext2_ext_attr_entry *entries,
> +					 unsigned int storage_size,
> +					 void *value_start)
> +{
> +	struct ext2_xattr *x;
> +	struct ext2_ext_attr_entry *entry;
> +	const char *prefix;
> +	void *ptr;
> +	unsigned int remain, prefix_len;
> +	errcode_t err;
> +
> +	x = handle->attrs;
> +	while (x->name)
> +		x++;
> +
> +	entry = entries;
> +	while (!EXT2_EXT_IS_LAST_ENTRY(entry)) {
> +		__u32 hash;
> +
> +		/* header eats this space */
> +		remain -= sizeof(struct ext2_ext_attr_entry);
> +
> +		/* is attribute name valid? */
> +		if (EXT2_EXT_ATTR_SIZE(entry->e_name_len) > remain)
> +			return EXT2_ET_EA_BAD_NAME_LEN;
> +
> +		/* attribute len eats this space */
> +		remain -= EXT2_EXT_ATTR_SIZE(entry->e_name_len);
> +
> +		/* check value size */
> +		if (entry->e_value_size > remain)
> +			return EXT2_ET_EA_BAD_VALUE_SIZE;
> +
> +		/* e_value_block must be 0 in inode's ea */
> +		if (entry->e_value_block != 0)
> +			return EXT2_ET_BAD_EA_BLOCK_NUM;
> +
> +		hash = ext2fs_ext_attr_hash_entry(entry, value_start +
> +							 entry->e_value_offs);
> +
> +		/* e_hash may be 0 in older inode's ea */
> +		if (entry->e_hash != 0 && entry->e_hash != hash)
> +			return EXT2_ET_BAD_EA_HASH;
> +
> +		remain -= entry->e_value_size;
> +
> +		/* Allocate space for more attrs? */
> +		if (x == handle->attrs + handle->length) {
> +			err = ext2fs_xattrs_expand(handle, 4);
> +			if (err)
> +				return err;
> +			x = handle->attrs + handle->length - 4;
> +		}
> +
> +		/* Extract name/value */
> +		prefix = find_ea_prefix(entry->e_name_index);
> +		prefix_len = (prefix ? strlen(prefix) : 0);
> +		err = ext2fs_get_memzero(entry->e_name_len + prefix_len + 1,
> +					 &x->name);
> +		if (err)
> +			return err;
> +		if (prefix)
> +			memcpy(x->name, prefix, prefix_len);
> +		if (entry->e_name_len)
> +			memcpy(x->name + prefix_len,
> +			       (void *)entry + sizeof(*entry),
> +			       entry->e_name_len);
> +
> +		err = ext2fs_get_mem(entry->e_value_size, &x->value);
> +		if (err)
> +			return err;
> +		x->value_len = entry->e_value_size;
> +		memcpy(x->value, value_start + entry->e_value_offs,
> +		       entry->e_value_size);
> +		x++;
> +		entry = EXT2_EXT_ATTR_NEXT(entry);
> +	}
> +
> +	return 0;
> +}
> +
> +errcode_t ext2fs_xattrs_read(struct ext2_xattr_handle *handle)
> +{
> +	struct ext2_xattr *attrs = NULL, *x;
> +	unsigned int attrs_len;
> +	struct ext2_inode_large *inode;
> +	struct ext2_ext_attr_header *header;
> +	__u32 ea_inode_magic;
> +	unsigned int storage_size;
> +	void *start, *block_buf = NULL;
> +	blk64_t blk;
> +	int i;
> +	errcode_t err;
> +
> +	if (!EXT2_HAS_COMPAT_FEATURE(handle->fs->super,
> +				     EXT2_FEATURE_COMPAT_EXT_ATTR))
> +		return 0;
> +
> +	i = EXT2_INODE_SIZE(handle->fs->super);
> +	if (i < sizeof(*inode))
> +		i = sizeof(*inode);
> +	err = ext2fs_get_memzero(i, &inode);
> +	if (err)
> +		return err;
> +
> +	err = ext2fs_read_inode_full(handle->fs, handle->ino,
> +				     (struct ext2_inode *)inode,
> +				     EXT2_INODE_SIZE(handle->fs->super));
> +	if (err)
> +		goto out;
> +
> +	/* Does the inode have size for EA? */
> +	if (EXT2_INODE_SIZE(handle->fs->super) <= EXT2_GOOD_OLD_INODE_SIZE +
> +						  inode->i_extra_isize +
> +						  sizeof(__u32))
> +		goto read_ea_block;
> +
> +	/* Look for EA in the inode */
> +	memcpy(&ea_inode_magic, ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
> +	       inode->i_extra_isize, sizeof(__u32));
> +	if (ea_inode_magic == EXT2_EXT_ATTR_MAGIC) {
> +		storage_size = EXT2_INODE_SIZE(handle->fs->super) -
> +			EXT2_GOOD_OLD_INODE_SIZE - inode->i_extra_isize -
> +			sizeof(__u32);
> +		start = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
> +			inode->i_extra_isize + sizeof(__u32);
> +
> +		err = read_xattrs_from_buffer(handle, start, storage_size,
> +					      start);
> +		if (err)
> +			goto out;
> +	}
> +
> +read_ea_block:
> +	/* Look for EA in a separate EA block */
> +	blk = ext2fs_file_acl_block(handle->fs, (struct ext2_inode *)inode);
> +	if (blk != 0) {
> +		if ((blk < handle->fs->super->s_first_data_block) ||
> +		    (blk >= ext2fs_blocks_count(handle->fs->super))) {
> +			err = EXT2_ET_BAD_EA_BLOCK_NUM;
> +			goto out;
> +		}
> +
> +		err = ext2fs_get_mem(handle->fs->blocksize, &block_buf);
> +		if (err)
> +			goto out;
> +
> +		err = ext2fs_read_ext_attr3(handle->fs, blk, block_buf,
> +					    handle->ino);
> +		if (err)
> +			goto out3;
> +
> +		header = (struct ext2_ext_attr_header *) block_buf;
> +		if (header->h_magic != EXT2_EXT_ATTR_MAGIC) {
> +			err = EXT2_ET_BAD_EA_HEADER;
> +			goto out3;
> +		}
> +
> +		if (header->h_blocks != 1) {
> +			err = EXT2_ET_BAD_EA_HEADER;
> +			goto out3;
> +		}
> +
> +		/* Read EAs */
> +		storage_size = handle->fs->blocksize -
> +			sizeof(struct ext2_ext_attr_header);
> +		start = block_buf + sizeof(struct ext2_ext_attr_header);
> +		err = read_xattrs_from_buffer(handle, start, storage_size,
> +					      block_buf);
> +		if (err)
> +			goto out3;
> +
> +		ext2fs_free_mem(&block_buf);
> +	}
> +
> +	ext2fs_free_mem(&block_buf);
> +	ext2fs_free_mem(&inode);
> +	return 0;
> +
> +out3:
> +	ext2fs_free_mem(&block_buf);
> +out:
> +	ext2fs_free_mem(&inode);
> +	return err;
> +}
> +
> +#define XATTR_ABORT	1
> +#define XATTR_CHANGED	2
> +errcode_t ext2fs_xattrs_iterate(struct ext2_xattr_handle *h,
> +				int (*func)(char *name, char *value,
> +					    void *data),
> +				void *data)
> +{
> +	struct ext2_xattr *x;
> +	errcode_t err;
> +	int ret;
> +
> +	for (x = h->attrs; x < h->attrs + h->length; x++) {
> +		if (!x->name)
> +			continue;
> +
> +		ret = func(x->name, x->value, data);
> +		if (ret & XATTR_CHANGED)
> +			h->dirty = 1;
> +		if (ret & XATTR_ABORT)
> +			return 0;
> +	}
> +
> +	return 0;
> +}
> +
> +errcode_t ext2fs_xattr_get(struct ext2_xattr_handle *h, const char *key,
> +			   void **value, unsigned int *value_len)
> +{
> +	struct ext2_xattr *x;
> +	void *val;
> +	errcode_t err;
> +
> +	for (x = h->attrs; x < h->attrs + h->length; x++) {
> +		if (!x->name)
> +			continue;
> +
> +		if (strcmp(x->name, key) == 0) {
> +			err = ext2fs_get_mem(x->value_len, &val);
> +			if (err)
> +				return err;
> +			memcpy(val, x->value, x->value_len);
> +			*value = val;
> +			*value_len = x->value_len;
> +			return 0;
> +		}
> +	}
> +
> +	return EXT2_ET_EA_KEY_NOT_FOUND;
> +}
> +
> +errcode_t ext2fs_xattr_set(struct ext2_xattr_handle *handle,
> +			   const char *key,
> +			   const void *value,
> +			   unsigned int value_len)
> +{
> +	struct ext2_xattr *x, *last_empty;
> +	char *new_value;
> +	errcode_t err;
> +
> +	last_empty = NULL;
> +	for (x = handle->attrs; x < handle->attrs + handle->length; x++) {
> +		if (!x->name) {
> +			last_empty = x;
> +			continue;
> +		}
> +
> +		/* Replace xattr */
> +		if (strcmp(x->name, key) == 0) {
> +			err = ext2fs_get_mem(value_len, &new_value);
> +			if (err)
> +				return err;
> +			memcpy(new_value, value, value_len);
> +			ext2fs_free_mem(&x->value);
> +			x->value = new_value;
> +			x->value_len = value_len;
> +			handle->dirty = 1;
> +			return 0;
> +		}
> +	}
> +
> +	/* Add attr to empty slot */
> +	if (last_empty) {
> +		err = ext2fs_get_mem(strlen(key) + 1, &last_empty->name);
> +		if (err)
> +			return err;
> +		strcpy(last_empty->name, key);
> +
> +		err = ext2fs_get_mem(value_len, &last_empty->value);
> +		if (err)
> +			return err;
> +		memcpy(last_empty->value, value, value_len);
> +		last_empty->value_len = value_len;
> +		handle->dirty = 1;
> +		return 0;
> +	}
> +
> +	/* Expand array, append slot */
> +	err = ext2fs_xattrs_expand(handle, 4);
> +	if (err)
> +		return err;
> +
> +	x = handle->attrs + handle->length - 4;
> +	err = ext2fs_get_mem(strlen(key) + 1, &x->name);
> +	if (err)
> +		return err;
> +	strcpy(x->name, key);
> +
> +	err = ext2fs_get_mem(value_len, &x->value);
> +	if (err)
> +		return err;
> +	memcpy(x->value, value, value_len);
> +	x->value_len = value_len;
> +	handle->dirty = 1;
> +	return 0;
> +}
> +
> +errcode_t ext2fs_xattr_remove(struct ext2_xattr_handle *handle,
> +			      const char *key)
> +{
> +	struct ext2_xattr *x;
> +	errcode_t err;
> +
> +	for (x = handle->attrs; x < handle->attrs + handle->length; x++) {
> +		if (!x->name)
> +			continue;
> +
> +		if (strcmp(x->name, key) == 0) {
> +			ext2fs_free_mem(&x->name);
> +			ext2fs_free_mem(&x->value);
> +			x->value_len = 0;
> +			handle->dirty = 1;
> +			return 0;
> +		}
> +	}
> +
> +	return EXT2_ET_EA_KEY_NOT_FOUND;
> +}
> +
> +errcode_t ext2fs_xattrs_open(ext2_filsys fs, ext2_ino_t ino,
> +			     struct ext2_xattr_handle **handle)
> +{
> +	struct ext2_xattr_handle *h;
> +	errcode_t err;
> +
> +	err = ext2fs_get_memzero(sizeof(*h), &h);
> +	if (err)
> +		return err;
> +
> +	h->length = 4;
> +	err = ext2fs_get_arrayzero(h->length, sizeof(struct ext2_xattr),
> +				   &h->attrs);
> +	if (err) {
> +		ext2fs_free_mem(&h);
> +		return err;
> +	}
> +	h->ino = ino;
> +	h->fs = fs;
> +	*handle = h;
> +	return 0;
> +}
> +
> +errcode_t ext2fs_xattrs_close(struct ext2_xattr_handle **handle)
> +{
> +	unsigned int i;
> +	struct ext2_xattr_handle *h = *handle;
> +	struct ext2_xattr *a = h->attrs;
> +	errcode_t err;
> +
> +	if (h->dirty) {
> +		err = ext2fs_xattrs_write(h);
> +		if (err)
> +			return err;
> +	}
> +
> +	for (i = 0; i < h->length; i++) {
> +		if (a[i].name)
> +			ext2fs_free_mem(&a[i].name);
> +		if (a[i].value)
> +			ext2fs_free_mem(&a[i].value);
> +	}
> +
> +	ext2fs_free_mem(&h->attrs);
> +	ext2fs_free_mem(handle);
> +	return 0;
> +}
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v1 19/22] e2fsck: check inline_data in pass3
  2013-10-12  9:06     ` Zheng Liu
@ 2013-10-12  9:09       ` Darrick J. Wong
  2013-10-12  9:17         ` Zheng Liu
  0 siblings, 1 reply; 67+ messages in thread
From: Darrick J. Wong @ 2013-10-12  9:09 UTC (permalink / raw)
  To: linux-ext4, Theodore Ts'o, Zheng Liu

On Sat, Oct 12, 2013 at 05:06:35PM +0800, Zheng Liu wrote:
> On Fri, Oct 11, 2013 at 05:54:10PM -0700, Darrick J. Wong wrote:
> > On Fri, Aug 02, 2013 at 05:49:46PM +0800, Zheng Liu wrote:
> > > From: Zheng Liu <wenqing.lz@taobao.com>
> > > 
> > > In e2fsck_expand_directory() we don't handle a dir with inline data
> > > because when this function is called the directory inode shouldn't
> > > contains inline data.
> > > 
> > > Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> > > Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
> > > ---
> > >  e2fsck/pass3.c  |   12 ++++++++++++
> > >  e2fsck/rehash.c |    3 ++-
> > >  2 files changed, 14 insertions(+), 1 deletion(-)
> > > 
> > > diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c
> > > index a379e9b..5052345 100644
> > > --- a/e2fsck/pass3.c
> > > +++ b/e2fsck/pass3.c
> > > @@ -787,6 +787,18 @@ errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
> > >  	es.ctx = ctx;
> > >  	es.dir = dir;
> > >  
> > > +	/*
> > > +	 * 'lost+found' dir shouldn't contains inline data.  So we
> > > +	 * need to clear this flag.
> > > +	 */
> > > +	if (ext2fs_inode_has_inline_data(fs, dir)) {
> > > +		retval = ext2fs_read_inode(fs, dir, &inode);
> > > +		if (retval)
> > > +			return retval;
> > > +		inode.i_flags &= ~EXT4_INLINE_DATA_FL;
> > > +		e2fsck_write_inode(ctx, dir, &inode, "clear inline_data flag");
> > > +	}
> > > +
> > >  	retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND,
> > >  				       0, expand_dir_proc, &es);
> > 
> > Are you saying that lost+found can have inline_data set yet i_blocks is
> > actually a block map/extent head?  Or are we supposed to zero i_blocks?
> > 
> > If we clear EXT4_INLINE_DATA_FL and then try to iterate blocks, are we setting
> > ourselves up to read (formerly inline) dirents as a block map and iterate it?
> > 
> > Shouldn't we care if the inode write fails?
> 
> lost+found dir shouldn't have inline_data flag because this is a special
> directory that it is preallocated some blocks when it is created because
> we need to avoid to allocate some blocks for it when we check a file
> system using e2fsck.  So we need to clear inline_data flag if this dir
> has this flag.

How does get that flag in the first place?

--D
> 
>                                                 - Zheng

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

* Re: [PATCH v1 19/22] e2fsck: check inline_data in pass3
  2013-10-12  9:09       ` Darrick J. Wong
@ 2013-10-12  9:17         ` Zheng Liu
  2013-10-12  9:22           ` Darrick J. Wong
  0 siblings, 1 reply; 67+ messages in thread
From: Zheng Liu @ 2013-10-12  9:17 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-ext4, Theodore Ts'o, Zheng Liu

On Sat, Oct 12, 2013 at 02:09:35AM -0700, Darrick J. Wong wrote:
> On Sat, Oct 12, 2013 at 05:06:35PM +0800, Zheng Liu wrote:
> > On Fri, Oct 11, 2013 at 05:54:10PM -0700, Darrick J. Wong wrote:
> > > On Fri, Aug 02, 2013 at 05:49:46PM +0800, Zheng Liu wrote:
> > > > From: Zheng Liu <wenqing.lz@taobao.com>
> > > > 
> > > > In e2fsck_expand_directory() we don't handle a dir with inline data
> > > > because when this function is called the directory inode shouldn't
> > > > contains inline data.
> > > > 
> > > > Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> > > > Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
> > > > ---
> > > >  e2fsck/pass3.c  |   12 ++++++++++++
> > > >  e2fsck/rehash.c |    3 ++-
> > > >  2 files changed, 14 insertions(+), 1 deletion(-)
> > > > 
> > > > diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c
> > > > index a379e9b..5052345 100644
> > > > --- a/e2fsck/pass3.c
> > > > +++ b/e2fsck/pass3.c
> > > > @@ -787,6 +787,18 @@ errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
> > > >  	es.ctx = ctx;
> > > >  	es.dir = dir;
> > > >  
> > > > +	/*
> > > > +	 * 'lost+found' dir shouldn't contains inline data.  So we
> > > > +	 * need to clear this flag.
> > > > +	 */
> > > > +	if (ext2fs_inode_has_inline_data(fs, dir)) {
> > > > +		retval = ext2fs_read_inode(fs, dir, &inode);
> > > > +		if (retval)
> > > > +			return retval;
> > > > +		inode.i_flags &= ~EXT4_INLINE_DATA_FL;
> > > > +		e2fsck_write_inode(ctx, dir, &inode, "clear inline_data flag");
> > > > +	}
> > > > +
> > > >  	retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND,
> > > >  				       0, expand_dir_proc, &es);
> > > 
> > > Are you saying that lost+found can have inline_data set yet i_blocks is
> > > actually a block map/extent head?  Or are we supposed to zero i_blocks?
> > > 
> > > If we clear EXT4_INLINE_DATA_FL and then try to iterate blocks, are we setting
> > > ourselves up to read (formerly inline) dirents as a block map and iterate it?
> > > 
> > > Shouldn't we care if the inode write fails?
> > 
> > lost+found dir shouldn't have inline_data flag because this is a special
> > directory that it is preallocated some blocks when it is created because
> > we need to avoid to allocate some blocks for it when we check a file
> > system using e2fsck.  So we need to clear inline_data flag if this dir
> > has this flag.
> 
> How does get that flag in the first place?

Technically, it shouldn't get this flag.  Think about it again, it seems
that we don't need to handle this because it couldn't happen.

                                                - Zheng

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

* Re: [PATCH v1 19/22] e2fsck: check inline_data in pass3
  2013-10-12  9:17         ` Zheng Liu
@ 2013-10-12  9:22           ` Darrick J. Wong
  2013-10-12  9:32             ` Zheng Liu
  0 siblings, 1 reply; 67+ messages in thread
From: Darrick J. Wong @ 2013-10-12  9:22 UTC (permalink / raw)
  To: linux-ext4, Theodore Ts'o, Zheng Liu

On Sat, Oct 12, 2013 at 05:17:55PM +0800, Zheng Liu wrote:
> On Sat, Oct 12, 2013 at 02:09:35AM -0700, Darrick J. Wong wrote:
> > On Sat, Oct 12, 2013 at 05:06:35PM +0800, Zheng Liu wrote:
> > > On Fri, Oct 11, 2013 at 05:54:10PM -0700, Darrick J. Wong wrote:
> > > > On Fri, Aug 02, 2013 at 05:49:46PM +0800, Zheng Liu wrote:
> > > > > From: Zheng Liu <wenqing.lz@taobao.com>
> > > > > 
> > > > > In e2fsck_expand_directory() we don't handle a dir with inline data
> > > > > because when this function is called the directory inode shouldn't
> > > > > contains inline data.
> > > > > 
> > > > > Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> > > > > Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
> > > > > ---
> > > > >  e2fsck/pass3.c  |   12 ++++++++++++
> > > > >  e2fsck/rehash.c |    3 ++-
> > > > >  2 files changed, 14 insertions(+), 1 deletion(-)
> > > > > 
> > > > > diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c
> > > > > index a379e9b..5052345 100644
> > > > > --- a/e2fsck/pass3.c
> > > > > +++ b/e2fsck/pass3.c
> > > > > @@ -787,6 +787,18 @@ errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
> > > > >  	es.ctx = ctx;
> > > > >  	es.dir = dir;
> > > > >  
> > > > > +	/*
> > > > > +	 * 'lost+found' dir shouldn't contains inline data.  So we
> > > > > +	 * need to clear this flag.
> > > > > +	 */
> > > > > +	if (ext2fs_inode_has_inline_data(fs, dir)) {
> > > > > +		retval = ext2fs_read_inode(fs, dir, &inode);
> > > > > +		if (retval)
> > > > > +			return retval;
> > > > > +		inode.i_flags &= ~EXT4_INLINE_DATA_FL;
> > > > > +		e2fsck_write_inode(ctx, dir, &inode, "clear inline_data flag");
> > > > > +	}
> > > > > +
> > > > >  	retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND,
> > > > >  				       0, expand_dir_proc, &es);
> > > > 
> > > > Are you saying that lost+found can have inline_data set yet i_blocks is
> > > > actually a block map/extent head?  Or are we supposed to zero i_blocks?
> > > > 
> > > > If we clear EXT4_INLINE_DATA_FL and then try to iterate blocks, are we setting
> > > > ourselves up to read (formerly inline) dirents as a block map and iterate it?
> > > > 
> > > > Shouldn't we care if the inode write fails?
> > > 
> > > lost+found dir shouldn't have inline_data flag because this is a special
> > > directory that it is preallocated some blocks when it is created because
> > > we need to avoid to allocate some blocks for it when we check a file
> > > system using e2fsck.  So we need to clear inline_data flag if this dir
> > > has this flag.
> > 
> > How does get that flag in the first place?
> 
> Technically, it shouldn't get this flag.  Think about it again, it seems
> that we don't need to handle this because it couldn't happen.

Hmm.  Maybe there should be an explicit entry and fix_problem() for this
condition?  I think there's some function in e2fsck that specifically messes
with lost+found, but I'm going to bed before the parts of my brain that form
English sentences really crashes. 8)

Though I suppose since we're rehashing directories anyway, there might be
no point in pestering the user more.

--D
> 
>                                                 - Zheng

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

* Re: [PATCH v1 19/22] e2fsck: check inline_data in pass3
  2013-10-12  9:22           ` Darrick J. Wong
@ 2013-10-12  9:32             ` Zheng Liu
  0 siblings, 0 replies; 67+ messages in thread
From: Zheng Liu @ 2013-10-12  9:32 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-ext4, Theodore Ts'o, Zheng Liu

On Sat, Oct 12, 2013 at 02:22:43AM -0700, Darrick J. Wong wrote:
> On Sat, Oct 12, 2013 at 05:17:55PM +0800, Zheng Liu wrote:
> > On Sat, Oct 12, 2013 at 02:09:35AM -0700, Darrick J. Wong wrote:
> > > On Sat, Oct 12, 2013 at 05:06:35PM +0800, Zheng Liu wrote:
> > > > On Fri, Oct 11, 2013 at 05:54:10PM -0700, Darrick J. Wong wrote:
> > > > > On Fri, Aug 02, 2013 at 05:49:46PM +0800, Zheng Liu wrote:
> > > > > > From: Zheng Liu <wenqing.lz@taobao.com>
> > > > > > 
> > > > > > In e2fsck_expand_directory() we don't handle a dir with inline data
> > > > > > because when this function is called the directory inode shouldn't
> > > > > > contains inline data.
> > > > > > 
> > > > > > Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> > > > > > Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
> > > > > > ---
> > > > > >  e2fsck/pass3.c  |   12 ++++++++++++
> > > > > >  e2fsck/rehash.c |    3 ++-
> > > > > >  2 files changed, 14 insertions(+), 1 deletion(-)
> > > > > > 
> > > > > > diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c
> > > > > > index a379e9b..5052345 100644
> > > > > > --- a/e2fsck/pass3.c
> > > > > > +++ b/e2fsck/pass3.c
> > > > > > @@ -787,6 +787,18 @@ errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
> > > > > >  	es.ctx = ctx;
> > > > > >  	es.dir = dir;
> > > > > >  
> > > > > > +	/*
> > > > > > +	 * 'lost+found' dir shouldn't contains inline data.  So we
> > > > > > +	 * need to clear this flag.
> > > > > > +	 */
> > > > > > +	if (ext2fs_inode_has_inline_data(fs, dir)) {
> > > > > > +		retval = ext2fs_read_inode(fs, dir, &inode);
> > > > > > +		if (retval)
> > > > > > +			return retval;
> > > > > > +		inode.i_flags &= ~EXT4_INLINE_DATA_FL;
> > > > > > +		e2fsck_write_inode(ctx, dir, &inode, "clear inline_data flag");
> > > > > > +	}
> > > > > > +
> > > > > >  	retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND,
> > > > > >  				       0, expand_dir_proc, &es);
> > > > > 
> > > > > Are you saying that lost+found can have inline_data set yet i_blocks is
> > > > > actually a block map/extent head?  Or are we supposed to zero i_blocks?
> > > > > 
> > > > > If we clear EXT4_INLINE_DATA_FL and then try to iterate blocks, are we setting
> > > > > ourselves up to read (formerly inline) dirents as a block map and iterate it?
> > > > > 
> > > > > Shouldn't we care if the inode write fails?
> > > > 
> > > > lost+found dir shouldn't have inline_data flag because this is a special
> > > > directory that it is preallocated some blocks when it is created because
> > > > we need to avoid to allocate some blocks for it when we check a file
> > > > system using e2fsck.  So we need to clear inline_data flag if this dir
> > > > has this flag.
> > > 
> > > How does get that flag in the first place?
> > 
> > Technically, it shouldn't get this flag.  Think about it again, it seems
> > that we don't need to handle this because it couldn't happen.
> 
> Hmm.  Maybe there should be an explicit entry and fix_problem() for this
> condition?  I think there's some function in e2fsck that specifically messes
> with lost+found, but I'm going to bed before the parts of my brain that form
> English sentences really crashes. 8)

Good idea.  Let me try it.

                                                - Zheng

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

* Re: [PATCH v1 01/22] libext2fs: add INLINE_DATA into EXT2_LIB_SOFTSUPP_INCOMPAT
  2013-08-02  9:49 ` [PATCH v1 01/22] libext2fs: add INLINE_DATA into EXT2_LIB_SOFTSUPP_INCOMPAT Zheng Liu
@ 2013-10-13  3:21   ` Theodore Ts'o
  0 siblings, 0 replies; 67+ messages in thread
From: Theodore Ts'o @ 2013-10-13  3:21 UTC (permalink / raw)
  To: Zheng Liu; +Cc: linux-ext4, Zheng Liu

On Fri, Aug 02, 2013 at 05:49:28PM +0800, Zheng Liu wrote:
> 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: Theodore Ts'o <tytso@mit.edu>
> Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>

Applied to the next branch, thanks.

					- Ted

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

* Re: [PATCH v1 05/22] libext2fs: handle inline_data in block iterator function
  2013-08-02  9:49 ` [PATCH v1 05/22] libext2fs: handle inline_data in block " Zheng Liu
@ 2013-10-13  3:55   ` Theodore Ts'o
  2013-10-14  0:44     ` Theodore Ts'o
  0 siblings, 1 reply; 67+ messages in thread
From: Theodore Ts'o @ 2013-10-13  3:55 UTC (permalink / raw)
  To: Zheng Liu; +Cc: linux-ext4, Zheng Liu

> diff --git a/lib/ext2fs/block.c b/lib/ext2fs/block.c
> index b8c6879..b194ca8 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;

ctx.errcode is guaranteed to be zero here.  So it would be better to
return zero explicitly --- except I wonder if we might be better to
have ext2fs_block_iterate3() return an error code if it is called on a
file that has inline data.  If we did this, then in nearly all of the
places where we call ext2fs_has_inline_data(), the call could be
obviated, and replaced with a check for the error code from
ext2fs_block_iterate3() --- which gets called in nearly every single
place where we call ext2fs_has_inline_data().

I'm not that fond of ext2fs_has_inline_data() because it doesn't
actually do that much, and it also might encourage application
programmers to use it even when they have access to inode data
structure, but instead of doing something like this:

	   if (inode.i_flags & EXT4_INLINE_DATA_FL)

they'll out of laziness, do this instead

	if (ext2fs_has_inline_data(fs, ino)

Which is less efficient, since it means an extra call to
ext2fs_read_inode()

							- Ted

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

* Re: [PATCH v1 04/22] libext2fs: handle inline data in dir iterator function
  2013-08-02  9:49 ` [PATCH v1 04/22] libext2fs: handle inline data in dir iterator function Zheng Liu
  2013-10-11 23:33   ` Darrick J. Wong
@ 2013-10-13 22:51   ` Theodore Ts'o
  2013-10-14  3:07     ` Zheng Liu
  2013-10-14  1:58   ` Theodore Ts'o
  2 siblings, 1 reply; 67+ messages in thread
From: Theodore Ts'o @ 2013-10-13 22:51 UTC (permalink / raw)
  To: Zheng Liu; +Cc: linux-ext4, Zheng Liu

On Fri, Aug 02, 2013 at 05:49:31PM +0800, Zheng Liu wrote:
> +int ext2fs_process_dir_inline_data(ext2_filsys	fs,
> +				   char		*buf,
> +				   unsigned int	buf_len,
> +				   e2_blkcnt_t	blockcnt,
> +				   struct ext2_inode_large *inode,
> +				   void		*priv_data)
> +{

It looks like there is a lot of code in this function which is in
common with ext2fs_process_dir_block(), so I'd suggest refactoring out
the common code to reduce duplication.  This will reduce code size,
and more importantly, improve maintenance of the code.

> +errcode_t ext2fs_inline_data_iterate(ext2_filsys fs,
> +			       ext2_ino_t ino,
> +			       int flags,
> +			       char *block_buf,
> +			       int (*func)(ext2_filsys fs,
> +					   char *buf,
> +					   unsigned int buf_len,
> +					   e2_blkcnt_t blockcnt,
> +					   struct ext2_inode_large *inode,
> +					   void *priv_data),
> +			       void *priv_data)

This function is misnamed, which worries me a little.  First of all,
it only makes sense when called on directories, so some name that
indicates that it is meant to iterate over directories is a good idea.
so some name such as ext2fs_process_inline_data_dir might be a better
choice.

Secondly, it would a really good idea if there was a check to make
sure it was passed an inode number which corresponds to an directory
and that the inline data flag is set.  A little paranoia is really
healthy thing --- if we have some application bug where this function
gets called accidentally on an inappropriate inode, we want to return
a clean error code and not stumble on until something bad happens.

> +	dirent.inode = (__u32)*inode->i_block;

I'd be much happier with:

	dirent.inode = inode->i_block[0];

We shouldn't use casts unless absolutely necessary, and it's not
necessary here.

Also, I suspect we have some byte-swapping problems here.  It doesn't
appear there is any allownaces for byte swapping in the inline data
patches.  Currently, the ext2fs_read_inode() function will take care
of byte swapping i_blocks[], so that will be OK here, but in the case
of an inode with inline data, if we byte swap all of i_blocks[] then
ext2fs_read_inline_data() will malfunction since the data bytes stored
in the rest of i_blocks[] will be byte swapped.  And that would be
wrong.

So I think what you will need to do is to avoid byte swapping the
i_blocks[] array if the inode contains inline_data, and then in the
case where this is a directory, we will need to byte swap i_block[0]
if we are running on a big-endian system.

Cheers,

						- Ted

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

* Re: [PATCH v1 05/22] libext2fs: handle inline_data in block iterator function
  2013-10-13  3:55   ` Theodore Ts'o
@ 2013-10-14  0:44     ` Theodore Ts'o
  2013-10-14  2:49       ` Zheng Liu
  0 siblings, 1 reply; 67+ messages in thread
From: Theodore Ts'o @ 2013-10-14  0:44 UTC (permalink / raw)
  To: Zheng Liu; +Cc: linux-ext4, Zheng Liu

On Sat, Oct 12, 2013 at 11:55:23PM -0400, Theodore Ts'o wrote:
except I wonder if we might be better to
> have ext2fs_block_iterate3() return an error code if it is called on a
> file that has inline data.

Thinking about this some more, I've convinced myself this is what we
really should do.  So I've added the following to the next branch.

       	      	      	   	     - Ted

commit 9d2244320f9ea94f035c16b1146282c6ecf3a68c
Author: Theodore Ts'o <tytso@mit.edu>
Date:   Sun Oct 13 17:42:25 2013 -0400

    libext2fs: handle inline_data in block iterator by returning an error code
    
    An inode with inline data has no data blocks, so we can not iterate
    over such an inode.  Return an error code which indicates this fact;
    callers can use this to determine whether or not the inode has inline
    data, and then call some routine to iterate over the directory intries
    in the line data or read the inline data, as appropriate.
    
    Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>

diff --git a/lib/ext2fs/block.c b/lib/ext2fs/block.c
index b8c6879..601129d 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;
 
 	/*
+	 * An inode with inline data has no blocks over which to
+	 * iterate, so return an error code indicating this fact.
+	 */
+	if (inode.i_flags & EXT4_INLINE_DATA_FL)
+		return EXT2_ET_INLINE_DATA_CANT_ITERATE;
+
+	/*
 	 * Check to see if we need to limit large files
 	 */
 	if (flags & BLOCK_FLAG_NO_LARGE) {
diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in
index c547a2c..5be1f32 100644
--- a/lib/ext2fs/ext2_err.et.in
+++ b/lib/ext2fs/ext2_err.et.in
@@ -479,4 +479,7 @@ ec	EXT2_ET_FILE_EXISTS,
 ec	EXT2_ET_BLOCK_BITMAP_CSUM_INVALID,
 	"Block bitmap checksum does not match bitmap"
 
+ec	EXT2_ET_INLINE_DATA_CANT_ITERATE
+	"Cannot block iterate on an inode containing inline data"
+
 	end

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

* Re: [PATCH v1 03/22] libext2fs: add functions to operate on extended attribute
  2013-08-05 23:14     ` Zheng Liu
@ 2013-10-14  1:55       ` Theodore Ts'o
  2013-10-14  2:41         ` Zheng Liu
  0 siblings, 1 reply; 67+ messages in thread
From: Theodore Ts'o @ 2013-10-14  1:55 UTC (permalink / raw)
  To: Darrick J. Wong, linux-ext4, Zheng Liu

On Tue, Aug 06, 2013 at 07:14:34AM +0800, Zheng Liu wrote:
> > > +ec	EXT2_ET_EXT_ATTR_CURRUPTED,
> > > +	"Extended attribute currupted"
> > 
> > "corrupted".
> 
> Thanks for pointing it out.  Fix it in next spin.
> 
> > (Or maybe shorten that to "corrupt"?)
> 
> I find the 'CORRUPT' in lib/ext2fs/ext2_err.et.in, and the result are as
> below.
> 
> It seems that there is no any rule about this.  I am wondering if we
> need to rename _DIR_CORRUPTED to _DIR_CORRUPT.  I am ok for using
> _CORRUPT or _CORRUPTED.

We shouldn't change existing error codes since that will break
backwards compatibility.  My preference for the new error code is:

ec	  EXT2_ET_EXT_ATTR_CORRUPT,
	  "Corrupt Extended attribute"

							- Ted

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

* Re: [PATCH v1 04/22] libext2fs: handle inline data in dir iterator function
  2013-08-02  9:49 ` [PATCH v1 04/22] libext2fs: handle inline data in dir iterator function Zheng Liu
  2013-10-11 23:33   ` Darrick J. Wong
  2013-10-13 22:51   ` Theodore Ts'o
@ 2013-10-14  1:58   ` Theodore Ts'o
  2 siblings, 0 replies; 67+ messages in thread
From: Theodore Ts'o @ 2013-10-14  1:58 UTC (permalink / raw)
  To: Zheng Liu; +Cc: linux-ext4, Zheng Liu

On Fri, Aug 02, 2013 at 05:49:31PM +0800, Zheng Liu wrote:
> diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in
> index 7e6d6e5..8a19cab 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"

Error cods MUST always be added at the end of the error code table.
Otherwise, the error code numbers will change, and that will break the
ABI --- i.e.,

#define EXT2_ET_REV_TOO_HIGH                     (2133571348L)

might turn into 

#define EXT2_ET_REV_TOO_HIGH                     (2133571349L)

and that will cause no end of confusion when older applications link
with a newer version of the libext2fs shared library.

						- Ted

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

* Re: [PATCH v1 03/22] libext2fs: add functions to operate on extended attribute
  2013-10-14  1:55       ` Theodore Ts'o
@ 2013-10-14  2:41         ` Zheng Liu
  0 siblings, 0 replies; 67+ messages in thread
From: Zheng Liu @ 2013-10-14  2:41 UTC (permalink / raw)
  To: Theodore Ts'o; +Cc: Darrick J. Wong, linux-ext4, Zheng Liu

On Sun, Oct 13, 2013 at 09:55:26PM -0400, Theodore Ts'o wrote:
> On Tue, Aug 06, 2013 at 07:14:34AM +0800, Zheng Liu wrote:
> > > > +ec	EXT2_ET_EXT_ATTR_CURRUPTED,
> > > > +	"Extended attribute currupted"
> > > 
> > > "corrupted".
> > 
> > Thanks for pointing it out.  Fix it in next spin.
> > 
> > > (Or maybe shorten that to "corrupt"?)
> > 
> > I find the 'CORRUPT' in lib/ext2fs/ext2_err.et.in, and the result are as
> > below.
> > 
> > It seems that there is no any rule about this.  I am wondering if we
> > need to rename _DIR_CORRUPTED to _DIR_CORRUPT.  I am ok for using
> > _CORRUPT or _CORRUPTED.
> 
> We shouldn't change existing error codes since that will break
> backwards compatibility.  My preference for the new error code is:
> 
> ec	  EXT2_ET_EXT_ATTR_CORRUPT,
> 	  "Corrupt Extended attribute"

Got it.

Thanks,
                                                - Zheng

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

* Re: [PATCH v1 05/22] libext2fs: handle inline_data in block iterator function
  2013-10-14  0:44     ` Theodore Ts'o
@ 2013-10-14  2:49       ` Zheng Liu
  0 siblings, 0 replies; 67+ messages in thread
From: Zheng Liu @ 2013-10-14  2:49 UTC (permalink / raw)
  To: Theodore Ts'o; +Cc: linux-ext4, Zheng Liu

On Sun, Oct 13, 2013 at 08:44:07PM -0400, Theodore Ts'o wrote:
> On Sat, Oct 12, 2013 at 11:55:23PM -0400, Theodore Ts'o wrote:
> except I wonder if we might be better to
> > have ext2fs_block_iterate3() return an error code if it is called on a
> > file that has inline data.
> 
> Thinking about this some more, I've convinced myself this is what we
> really should do.  So I've added the following to the next branch.

Sorry for my late reply.  Yes, this is better.  I will add this patch
into my inline data patch set.

Thanks,
                                                - Zheng

> 
>        	      	      	   	     - Ted
> 
> commit 9d2244320f9ea94f035c16b1146282c6ecf3a68c
> Author: Theodore Ts'o <tytso@mit.edu>
> Date:   Sun Oct 13 17:42:25 2013 -0400
> 
>     libext2fs: handle inline_data in block iterator by returning an error code
>     
>     An inode with inline data has no data blocks, so we can not iterate
>     over such an inode.  Return an error code which indicates this fact;
>     callers can use this to determine whether or not the inode has inline
>     data, and then call some routine to iterate over the directory intries
>     in the line data or read the inline data, as appropriate.
>     
>     Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
> 
> diff --git a/lib/ext2fs/block.c b/lib/ext2fs/block.c
> index b8c6879..601129d 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;
>  
>  	/*
> +	 * An inode with inline data has no blocks over which to
> +	 * iterate, so return an error code indicating this fact.
> +	 */
> +	if (inode.i_flags & EXT4_INLINE_DATA_FL)
> +		return EXT2_ET_INLINE_DATA_CANT_ITERATE;
> +
> +	/*
>  	 * Check to see if we need to limit large files
>  	 */
>  	if (flags & BLOCK_FLAG_NO_LARGE) {
> diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in
> index c547a2c..5be1f32 100644
> --- a/lib/ext2fs/ext2_err.et.in
> +++ b/lib/ext2fs/ext2_err.et.in
> @@ -479,4 +479,7 @@ ec	EXT2_ET_FILE_EXISTS,
>  ec	EXT2_ET_BLOCK_BITMAP_CSUM_INVALID,
>  	"Block bitmap checksum does not match bitmap"
>  
> +ec	EXT2_ET_INLINE_DATA_CANT_ITERATE
> +	"Cannot block iterate on an inode containing inline data"
> +
>  	end

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

* Re: [PATCH v1 04/22] libext2fs: handle inline data in dir iterator function
  2013-10-13 22:51   ` Theodore Ts'o
@ 2013-10-14  3:07     ` Zheng Liu
  0 siblings, 0 replies; 67+ messages in thread
From: Zheng Liu @ 2013-10-14  3:07 UTC (permalink / raw)
  To: Theodore Ts'o; +Cc: linux-ext4, Zheng Liu

On Sun, Oct 13, 2013 at 06:51:12PM -0400, Theodore Ts'o wrote:
> On Fri, Aug 02, 2013 at 05:49:31PM +0800, Zheng Liu wrote:
> > +int ext2fs_process_dir_inline_data(ext2_filsys	fs,
> > +				   char		*buf,
> > +				   unsigned int	buf_len,
> > +				   e2_blkcnt_t	blockcnt,
> > +				   struct ext2_inode_large *inode,
> > +				   void		*priv_data)
> > +{
> 
> It looks like there is a lot of code in this function which is in
> common with ext2fs_process_dir_block(), so I'd suggest refactoring out
> the common code to reduce duplication.  This will reduce code size,
> and more importantly, improve maintenance of the code.
> 
> > +errcode_t ext2fs_inline_data_iterate(ext2_filsys fs,
> > +			       ext2_ino_t ino,
> > +			       int flags,
> > +			       char *block_buf,
> > +			       int (*func)(ext2_filsys fs,
> > +					   char *buf,
> > +					   unsigned int buf_len,
> > +					   e2_blkcnt_t blockcnt,
> > +					   struct ext2_inode_large *inode,
> > +					   void *priv_data),
> > +			       void *priv_data)
> 
> This function is misnamed, which worries me a little.  First of all,
> it only makes sense when called on directories, so some name that
> indicates that it is meant to iterate over directories is a good idea.
> so some name such as ext2fs_process_inline_data_dir might be a better
> choice.

Yes, Darrick has pointed it out.  I will fix it in next version.

> 
> Secondly, it would a really good idea if there was a check to make
> sure it was passed an inode number which corresponds to an directory
> and that the inline data flag is set.  A little paranoia is really
> healthy thing --- if we have some application bug where this function
> gets called accidentally on an inappropriate inode, we want to return
> a clean error code and not stumble on until something bad happens.
> 
> > +	dirent.inode = (__u32)*inode->i_block;
> 
> I'd be much happier with:
> 
> 	dirent.inode = inode->i_block[0];
> 
> We shouldn't use casts unless absolutely necessary, and it's not
> necessary here.
> 
> Also, I suspect we have some byte-swapping problems here.  It doesn't
> appear there is any allownaces for byte swapping in the inline data
> patches.  Currently, the ext2fs_read_inode() function will take care
> of byte swapping i_blocks[], so that will be OK here, but in the case
> of an inode with inline data, if we byte swap all of i_blocks[] then
> ext2fs_read_inline_data() will malfunction since the data bytes stored
> in the rest of i_blocks[] will be byte swapped.  And that would be
> wrong.
> 
> So I think what you will need to do is to avoid byte swapping the
> i_blocks[] array if the inode contains inline_data, and then in the
> case where this is a directory, we will need to byte swap i_block[0]
> if we are running on a big-endian system.

Yes, I have noticed that we only byte swap i_block[0], and the following
things don't be swapped.  So I will fix it.

Thanks,
                                                - Zheng

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

end of thread, other threads:[~2013-10-14  3:05 UTC | newest]

Thread overview: 67+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-08-02  9:49 [PATCH v1 00/22] e2fsprogs: inline data refinement patch set Zheng Liu
2013-08-02  9:49 ` [PATCH v1 01/22] libext2fs: add INLINE_DATA into EXT2_LIB_SOFTSUPP_INCOMPAT Zheng Liu
2013-10-13  3:21   ` Theodore Ts'o
2013-08-02  9:49 ` [PATCH v1 02/22] libext2fs: add function to check inline_data flag for an inode Zheng Liu
2013-08-02  9:49 ` [PATCH v1 03/22] libext2fs: add functions to operate on extended attribute Zheng Liu
2013-08-05 17:34   ` Darrick J. Wong
2013-08-05 23:14     ` Zheng Liu
2013-10-14  1:55       ` Theodore Ts'o
2013-10-14  2:41         ` Zheng Liu
2013-10-11 22:51   ` Darrick J. Wong
2013-10-12  5:51     ` Zheng Liu
2013-10-12  8:32       ` Darrick J. Wong
2013-10-12  8:41         ` Zheng Liu
2013-10-12  9:02           ` Darrick J. Wong
2013-10-12  9:08             ` Zheng Liu
2013-08-02  9:49 ` [PATCH v1 04/22] libext2fs: handle inline data in dir iterator function Zheng Liu
2013-10-11 23:33   ` Darrick J. Wong
2013-10-12  5:55     ` Zheng Liu
2013-10-13 22:51   ` Theodore Ts'o
2013-10-14  3:07     ` Zheng Liu
2013-10-14  1:58   ` Theodore Ts'o
2013-08-02  9:49 ` [PATCH v1 05/22] libext2fs: handle inline_data in block " Zheng Liu
2013-10-13  3:55   ` Theodore Ts'o
2013-10-14  0:44     ` Theodore Ts'o
2013-10-14  2:49       ` Zheng Liu
2013-08-02  9:49 ` [PATCH v1 06/22] debugfs: make stat command support inline data Zheng Liu
2013-10-11 23:43   ` Darrick J. Wong
2013-10-12  0:07     ` Darrick J. Wong
2013-08-02  9:49 ` [PATCH v1 07/22] debugfs: make mkdir and expanddir " Zheng Liu
2013-10-12  0:21   ` Darrick J. Wong
2013-10-12  7:15     ` Zheng Liu
2013-08-02  9:49 ` [PATCH v1 08/22] debugfs: make lsdel " Zheng Liu
2013-08-02  9:49 ` [PATCH v1 09/22] libext2fs: handle inline data in read/write function Zheng Liu
2013-08-02  9:49 ` [PATCH v1 10/22] debugfs: handle inline_data feature in dirsearch command Zheng Liu
2013-10-12  0:30   ` Darrick J. Wong
2013-10-12  7:21     ` Zheng Liu
2013-08-02  9:49 ` [PATCH v1 11/22] debugfs: handle inline_data feature in bmap command Zheng Liu
2013-08-02  9:49 ` [PATCH v1 12/22] debugfs: handle inline_data in punch command Zheng Liu
2013-10-12  0:37   ` Darrick J. Wong
2013-10-12  7:22     ` Zheng Liu
2013-08-02  9:49 ` [PATCH v1 13/22] libext2fs: add inline_data feature into EXT2_LIB_FEATURE_INCOMPAT_SUPP Zheng Liu
2013-08-02  9:49 ` [PATCH v1 14/22] mke2fs: add inline_data support in mke2fs Zheng Liu
2013-10-12  0:27   ` Darrick J. Wong
2013-10-12  8:08     ` Zheng Liu
2013-10-12  8:18       ` Darrick J. Wong
2013-10-12  8:31         ` Zheng Liu
2013-10-12  8:32           ` Darrick J. Wong
2013-08-02  9:49 ` [PATCH v1 15/22] tune2fs: add inline_data feature in tune2fs Zheng Liu
2013-10-12  0:39   ` Darrick J. Wong
2013-10-12  8:16     ` Zheng Liu
2013-10-12  8:23       ` Darrick J. Wong
2013-10-12  8:33         ` Zheng Liu
2013-08-02  9:49 ` [PATCH v1 16/22] e2fsck: add problem descriptions and check inline data feature Zheng Liu
2013-08-02  9:49 ` [PATCH v1 17/22] e2fsck: check inline_data in pass1 Zheng Liu
2013-10-12  0:47   ` Darrick J. Wong
2013-10-12  8:17     ` Zheng Liu
2013-08-02  9:49 ` [PATCH v1 18/22] e2fsck: check inline_data in pass2 Zheng Liu
2013-08-02  9:49 ` [PATCH v1 19/22] e2fsck: check inline_data in pass3 Zheng Liu
2013-10-12  0:54   ` Darrick J. Wong
2013-10-12  9:06     ` Zheng Liu
2013-10-12  9:09       ` Darrick J. Wong
2013-10-12  9:17         ` Zheng Liu
2013-10-12  9:22           ` Darrick J. Wong
2013-10-12  9:32             ` Zheng Liu
2013-08-02  9:49 ` [PATCH v1 20/22] tests: change result in f_bad_disconnected_inode Zheng Liu
2013-08-02  9:49 ` [PATCH v1 21/22] mke2fs: enable inline_data feature on ext4dev filesystem Zheng Liu
2013-08-02  9:49 ` [PATCH v1 22/22] libext2fs: add a unit test for inline data 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).