2012-04-16 11:33:52

by Zheng Liu

[permalink] [raw]
Subject: [PATCH 00/32] e2fsprogs: make e2fsprogs support inline data

Hi list,

Here is v2 for making e2fsprogs support inline data. Now debugfs supports
inline data in read-write mode. Meanwhile e2fsck has been improved to support
inline data feature.

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

In mke2fs, EXT4_FEATURE_INCOMPAT_INLINE_DATA is set to 0x2000 to consist with
kernel. When making a new ext4 file system with INLINE_DATA feature, mke2fs
will check whether EXT_ATTR is set or not. If it is not set, mke2fs will mark
it automatically because INLINE_DATA depends on it.

In debugfs, it can support inline data in read-write mode. Now there is two
problems that need to be solved. No matter whether the size of data is fit
into inline data or not, 'write' command writes the data into disk blocks
rather than inode itself. 'mkdir' command will expand dir to a new disk block
when inode->i_block has full because Tao found a performance regression when a
huge number of dirs are added and removed in EA space. It causes that the code
in kernel might be changed. So now 'mkdir' cmd doesn't add a new dir entry
in EA space.

TODO list:
* [mke2fs] initialize ROOT dir with inline data flag
* [mke2fs] initialize LOST+FOUND dir with inline data flag
* [debugfs] 'write' cmd writes the data into inode itself
* [debugfs] 'mkdir' cmd add dir entry into EA space

Regards,
Zheng

libext2fs: add EXT4_FEATURE_INCOMPAT_INLINE_DATA flag
mke2fs: make it support inline data feature
libext2fs: add inline_data feature
mke2fs: add inline_data feature in mke2fs's manpage
libext2fs: add ext2fs_find_entry_ext_attr function
libext2fs: add EXT4_INLINE_DATA_FL flag for inode
libext2fs: add data structures for inline data feature
libext2fs: add inline_data file
debugfs: make ncheck cmd support inline data
debugfs: make chroot and cd cmd support inline data
debugfs: make ls cmd support inline data
debugfs: make stat cmd support inline data
debufs: make blocks cmd support inline data
debugfs: make filefrag cmd support inline data
debugfs: make link cmd support inline data
debugfs: make unlink cmd support inline data
debugfs: make mkdir cmd support inline data
debugfs: make rmdir cmd support inline data
debugfs: make rm and kill_file cmd support inline data
debugfs: make pwd cmd support inline data
debugfs: make expand_dir cmd support inline data
debugfs: make lsdel cmd support inline data
debugfs: make undel cmd support inline data
debugfs: make dump and cat cmd support inline data
debugfs: make rdump cmd support inline data
debugfs: make dirsearch cmd support inline data
debugfs: make bma cmd support inline data
e2fsck: add three problem descriptions in pass1
e2fsck: check incorrect inline data flag
e2fsck: make pass1 support inline data
libext2fs: add read/write inline data functions
e2fsck: check inline data in pass2

debugfs/debugfs.c | 25 ++-
debugfs/dump.c | 38 +++-
debugfs/filefrag.c | 30 ++-
debugfs/htree.c | 6 +
debugfs/ls.c | 8 +-
debugfs/lsdel.c | 19 +-
debugfs/ncheck.c | 8 +-
e2fsck/pass1.c | 70 ++++-
e2fsck/pass1b.c | 5 +-
e2fsck/pass2.c | 50 +++-
e2fsck/problem.c | 15 +
e2fsck/problem.h | 9 +
lib/e2p/feature.c | 2 +
lib/ext2fs/Makefile.in | 5 +
lib/ext2fs/Makefile.pq | 1 +
lib/ext2fs/bmap.c | 16 +
lib/ext2fs/dblist_dir.c | 8 +-
lib/ext2fs/dirblock.c | 62 ++++
lib/ext2fs/expanddir.c | 8 +-
lib/ext2fs/ext2_ext_attr.h | 4 +
lib/ext2fs/ext2_fs.h | 9 +
lib/ext2fs/ext2fs.h | 69 ++++-
lib/ext2fs/ext_attr.c | 26 ++
lib/ext2fs/get_pathname.c | 7 +-
lib/ext2fs/inline_data.c | 715 ++++++++++++++++++++++++++++++++++++++++++++
lib/ext2fs/link.c | 9 +-
lib/ext2fs/lookup.c | 6 +-
lib/ext2fs/mkdir.c | 4 +
lib/ext2fs/unlink.c | 9 +-
misc/mke2fs.8.in | 3 +
misc/mke2fs.c | 10 +-
31 files changed, 1197 insertions(+), 59 deletions(-)


2012-04-16 11:33:54

by Zheng Liu

[permalink] [raw]
Subject: [PATCH 01/32] libext2fs: add EXT4_FEATURE_INCOMPAT_INLINE_DATA flag

From: Zheng Liu <[email protected]>

Add EXT4_FEATURE_INCOMPAT_INLINE_DATA flag to support inline
data feature.

Signed-off-by: Zheng Liu <[email protected]>
---
lib/ext2fs/ext2_fs.h | 1 +
lib/ext2fs/ext2fs.h | 6 ++++--
2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
index 20decff..4914946 100644
--- a/lib/ext2fs/ext2_fs.h
+++ b/lib/ext2fs/ext2_fs.h
@@ -721,6 +721,7 @@ struct ext2_super_block {
#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200
#define EXT4_FEATURE_INCOMPAT_EA_INODE 0x0400
#define EXT4_FEATURE_INCOMPAT_DIRDATA 0x1000
+#define EXT4_FEATURE_INCOMPAT_INLINE_DATA 0x2000

#define EXT2_FEATURE_COMPAT_SUPP 0
#define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index fda6ade..89815eb 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -576,7 +576,8 @@ typedef struct ext2_icount *ext2_icount_t;
EXT3_FEATURE_INCOMPAT_EXTENTS|\
EXT4_FEATURE_INCOMPAT_FLEX_BG|\
EXT4_FEATURE_INCOMPAT_MMP|\
- EXT4_FEATURE_INCOMPAT_64BIT)
+ EXT4_FEATURE_INCOMPAT_64BIT|\
+ EXT4_FEATURE_INCOMPAT_INLINE_DATA)
#else
#define EXT2_LIB_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE|\
EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|\
@@ -585,7 +586,8 @@ typedef struct ext2_icount *ext2_icount_t;
EXT3_FEATURE_INCOMPAT_EXTENTS|\
EXT4_FEATURE_INCOMPAT_FLEX_BG|\
EXT4_FEATURE_INCOMPAT_MMP|\
- EXT4_FEATURE_INCOMPAT_64BIT)
+ EXT4_FEATURE_INCOMPAT_64BIT|\
+ EXT4_FEATURE_INCOMPAT_INLINE_DATA)
#endif
#ifdef CONFIG_QUOTA
#define EXT2_LIB_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|\
--
1.7.4.1


2012-04-16 11:33:57

by Zheng Liu

[permalink] [raw]
Subject: [PATCH 03/32] libext2fs: add inline_data feature

From: Zheng Liu <[email protected]>

Add EXT4_FEATURE_INCOMPAT_INLINE_DATA flag into feautre list.

Signed-off-by: Zheng Liu <[email protected]>
---
lib/e2p/feature.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/lib/e2p/feature.c b/lib/e2p/feature.c
index 19e6f0c..aadc03e 100644
--- a/lib/e2p/feature.c
+++ b/lib/e2p/feature.c
@@ -87,6 +87,8 @@ static struct feature feature_list[] = {
"mmp" },
{ E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_FLEX_BG,
"flex_bg"},
+ { E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_INLINE_DATA,
+ "inline_data"},
{ 0, 0, 0 },
};

--
1.7.4.1


2012-04-16 11:33:55

by Zheng Liu

[permalink] [raw]
Subject: [PATCH 02/32] mke2fs: make it support inline data feature

From: Zheng Liu <[email protected]>

EXT2_FEATURE_COMPAT_EXT_ATTR flag will be set when inline_data is set
because inline data feature depends on it.

Signed-off-by: Zheng Liu <[email protected]>
---
misc/mke2fs.c | 10 +++++++++-
1 files changed, 9 insertions(+), 1 deletions(-)

diff --git a/misc/mke2fs.c b/misc/mke2fs.c
index 7ec8cc2..145a6a8 100644
--- a/misc/mke2fs.c
+++ b/misc/mke2fs.c
@@ -856,7 +856,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|
@@ -1922,6 +1923,13 @@ profile_error:
exit(1);
}

+ /* if inline_data is set, ext_attr would be set because inline_data
+ * depends on it.
+ */
+ if ((fs_param.s_feature_incompat & EXT4_FEATURE_INCOMPAT_INLINE_DATA) &&
+ !(fs_param.s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR))
+ fs_param.s_feature_compat |= EXT2_FEATURE_COMPAT_EXT_ATTR;
+
if (fs_param.s_blocks_per_group) {
if (fs_param.s_blocks_per_group < 256 ||
fs_param.s_blocks_per_group > 8 * (unsigned) blocksize) {
--
1.7.4.1


2012-04-16 11:34:00

by Zheng Liu

[permalink] [raw]
Subject: [PATCH 05/32] libext2fs: add ext2fs_find_entry_ext_attr function

From: Zheng Liu <[email protected]>

we need to search extend attributes to get entry of inline data.
Thus, add this function to do this work.

Signed-off-by: Zheng Liu <[email protected]>
---
lib/ext2fs/ext2fs.h | 3 +++
lib/ext2fs/ext_attr.c | 26 ++++++++++++++++++++++++++
2 files changed, 29 insertions(+), 0 deletions(-)

diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 89815eb..a6518be 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -1075,6 +1075,9 @@ extern errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
extern errcode_t ext2fs_adjust_ea_refcount2(ext2_filsys fs, blk64_t blk,
char *block_buf,
int adjust, __u32 *newcount);
+extern errcode_t ext2fs_find_entry_ext_attr(struct ext2_ext_attr_entry **pentry,
+ int name_index, const char *name,
+ size_t size, int sorted);

/* 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 1889824..f027296 100644
--- a/lib/ext2fs/ext_attr.c
+++ b/lib/ext2fs/ext_attr.c
@@ -155,3 +155,29 @@ errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
{
return ext2fs_adjust_ea_refcount(fs, blk, block_buf, adjust, newcount);
}
+
+errcode_t ext2fs_find_entry_ext_attr(struct ext2_ext_attr_entry **pentry,
+ int name_index, const char *name,
+ size_t size, int sorted)
+{
+ struct ext2_ext_attr_entry *entry;
+ size_t name_len;
+ int cmp;
+
+ if (name == NULL)
+ return -1;
+ name_len = strlen(name);
+ entry = *pentry;
+ for (; !EXT2_EXT_IS_LAST_ENTRY(entry); entry = EXT2_EXT_ATTR_NEXT(entry)) {
+ cmp = name_index - entry->e_name_index;
+ if (!cmp)
+ cmp = name_len - entry->e_name_len;
+ if (!cmp)
+ cmp = memcmp(name, EXT2_EXT_ATTR_NAME(entry), name_len);
+ if (!cmp)
+ break;
+ }
+ *pentry = entry;
+
+ return cmp;
+}
--
1.7.4.1


2012-04-16 11:33:59

by Zheng Liu

[permalink] [raw]
Subject: [PATCH 04/32] mke2fs: add inline_data feature in mke2fs's manpage

From: Zheng Liu <[email protected]>

Update mke2fs's manpage.

Signed-off-by: Zheng Liu <[email protected]>
---
misc/mke2fs.8.in | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/misc/mke2fs.8.in b/misc/mke2fs.8.in
index 6d443a2..bfe6c94 100644
--- a/misc/mke2fs.8.in
+++ b/misc/mke2fs.8.in
@@ -551,6 +551,9 @@ option).
@JDEV@must be created with the same
@JDEV@block size as the filesystems that will be using it.
.TP
+.B inline_data
+Allow data to be stored in inode
+.TP
.B large_file
Filesystem can contain files that are greater than 2GB. (Modern kernels
set this feature automatically when a file > 2GB is created.)
--
1.7.4.1


2012-04-16 11:34:02

by Zheng Liu

[permalink] [raw]
Subject: [PATCH 06/32] libext2fs: add EXT4_INLINE_DATA_FL flag for inode

From: Zheng Liu <[email protected]>

Add EXT4_INLINE_DATA_FL flag.

Signed-off-by: Zheng Liu <[email protected]>
---
lib/ext2fs/ext2_fs.h | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
index 4914946..0f0239b 100644
--- a/lib/ext2fs/ext2_fs.h
+++ b/lib/ext2fs/ext2_fs.h
@@ -301,6 +301,7 @@ struct ext2_dx_countlimit {
#define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */
#define EXT4_EA_INODE_FL 0x00200000 /* Inode used for large EA */
/* EXT4_EOFBLOCKS_FL 0x00400000 was here */
+#define EXT4_INLINE_DATA_FL 0x00800000 /* Inode has inline data */
#define EXT4_SNAPFILE_FL 0x01000000 /* Inode is a snapshot */
#define EXT4_SNAPFILE_DELETED_FL 0x04000000 /* Snapshot is being deleted */
#define EXT4_SNAPFILE_SHRUNK_FL 0x08000000 /* Snapshot shrink has completed */
--
1.7.4.1


2012-04-16 11:34:04

by Zheng Liu

[permalink] [raw]
Subject: [PATCH 07/32] libext2fs: add data structures for inline data feature

From: Zheng Liu <[email protected]>

Add ext2_ext_attr_ibody_heaer to check extend attribute.
Add inline_data to indicate the position of inline data in
extend attribute and the size of inline data.

Signed-off-by: Zheng Liu <[email protected]>
---
lib/ext2fs/ext2_ext_attr.h | 4 ++++
lib/ext2fs/ext2_fs.h | 7 +++++++
2 files changed, 11 insertions(+), 0 deletions(-)

diff --git a/lib/ext2fs/ext2_ext_attr.h b/lib/ext2fs/ext2_ext_attr.h
index ed548d1..78ef7fc 100644
--- a/lib/ext2fs/ext2_ext_attr.h
+++ b/lib/ext2fs/ext2_ext_attr.h
@@ -23,6 +23,10 @@ struct ext2_ext_attr_header {
__u32 h_reserved[4]; /* 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 */
diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
index 0f0239b..4a275d9 100644
--- a/lib/ext2fs/ext2_fs.h
+++ b/lib/ext2fs/ext2_fs.h
@@ -855,4 +855,11 @@ struct mmp_struct {
*/
#define EXT4_MMP_MIN_CHECK_INTERVAL 5

+struct inline_data {
+ __u16 inline_off;
+ __u16 inline_size;
+};
+
+#define EXT4_MIN_INLINE_DATA_SIZE ((sizeof(__u32) * EXT2_N_BLOCKS))
+
#endif /* _LINUX_EXT2_FS_H */
--
1.7.4.1


2012-04-16 11:34:06

by Zheng Liu

[permalink] [raw]
Subject: [PATCH 08/32] libext2fs: add inline_data file

From: Zheng Liu <[email protected]>

inline_data.c file is craeted to implement related functions to support
inline_data feature.

Signed-off-by: Zheng Liu <[email protected]>
---
lib/ext2fs/Makefile.in | 5 +
lib/ext2fs/Makefile.pq | 1 +
lib/ext2fs/ext2fs.h | 54 ++++
lib/ext2fs/inline_data.c | 715 ++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 775 insertions(+), 0 deletions(-)
create mode 100644 lib/ext2fs/inline_data.c

diff --git a/lib/ext2fs/Makefile.in b/lib/ext2fs/Makefile.in
index 507a459..af631ce 100644
--- a/lib/ext2fs/Makefile.in
+++ b/lib/ext2fs/Makefile.in
@@ -58,6 +58,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 \
@@ -130,6 +131,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 \
@@ -727,6 +729,9 @@ 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 \
+ $(srcdir)/ext2_fs.h $(srcdir)/ext2fs.h $(srcdir)/ext2_ext_attr.h \
+ $(srcdir)/ext2fsP.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 a6518be..cb1b58e 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -1266,6 +1266,60 @@ extern errcode_t ext2fs_icount_store(ext2_icount_t icount, ext2_ino_t ino,
extern ext2_ino_t ext2fs_get_icount_size(ext2_icount_t icount);
errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *);

+/* inline_data.c */
+extern errcode_t ext2fs_inline_data_iterate(ext2_filsys fs,
+ ext2_ino_t ino,
+ int flags,
+ char *block_buf,
+ int (*func)(struct ext2_dir_entry *dirent,
+ int offset,
+ int blocksize,
+ char *buf,
+ void *priv_data),
+ void *priv_data);
+extern errcode_t ext2fs_inline_data_iterate2(ext2_filsys fs,
+ ext2_ino_t ino,
+ int flags,
+ char *block_buf,
+ int (*func)(ext2_ino_t ino,
+ int entry,
+ struct ext2_dir_entry *dirent,
+ int offset,
+ int blocksize,
+ char *buf,
+ void *priv_data),
+ void *priv_data);
+extern errcode_t ext2fs_inline_data_iterate3(ext2_filsys fs,
+ ext2_ino_t ino,
+ int flags,
+ char *block_buf,
+ const char *name,
+ int namelen,
+ int (*func)(struct ext2_dir_entry *dirent,
+ int offset,
+ int blocksize,
+ char *buf,
+ void *priv_data),
+ void *priv_data);
+extern errcode_t ext2fs_inline_data_search_dir(ext2_filsys fs, ext2_ino_t ino,
+ char *search_name, int len);
+extern errcode_t ext2fs_inline_data_expand_dir(ext2_filsys fs, ext2_ino_t ino,
+ int flags, char *block_buf,
+ int (*func)(ext2_filsys fs,
+ blk64_t *blocknr,
+ e2_blkcnt_t blockcnt,
+ blk64_t ref_blk,
+ int ref_offset,
+ void *priv_data),
+ void *priv_data);
+extern void *ext2fs_get_inline_xattr_pos(struct ext2_inode_large *inode,
+ struct inline_data *idata);
+extern void ext2fs_iget_extra_inode(ext2_filsys fs, struct ext2_inode_large *inode,
+ struct inline_data *idata);
+extern int ext2fs_has_inline_data(ext2_filsys fs, ext2_ino_t ino);
+extern int ext2fs_inline_data_in_extra(ext2_filsys fs, ext2_ino_t ino);
+extern int ext2fs_inline_data_size(ext2_filsys fs, ext2_ino_t ino);
+
/* inode.c */
extern errcode_t ext2fs_flush_icache(ext2_filsys fs);
extern errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan,
diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c
new file mode 100644
index 0000000..4ebd592
--- /dev/null
+++ b/lib/ext2fs/inline_data.c
@@ -0,0 +1,715 @@
+/*
+ * inline_data.c --- data in inode
+ *
+ * Copyright (C) 2012 Zheng Liu <[email protected]>
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Library
+ * General Public License, version 2.
+ * %End-Header%
+ */
+
+#include "config.h"
+#include <stdio.h>
+
+#include "ext2_fs.h"
+#include "ext2_ext_attr.h"
+
+#include "ext2fs.h"
+#include "ext2fsP.h"
+
+#define EXT4_XATTR_SYSTEM_DATA_INDEX 7
+#define EXT4_XATTR_SYSTEM_DATA_NAME "data"
+
+struct inline_data_context {
+ ext2_ino_t ino;
+ int flags;
+ char *buf;
+ int (*func)(ext2_ino_t ino,
+ int entry,
+ struct ext2_dir_entry *dirent,
+ int offset,
+ int blocksize,
+ char *buf,
+ void *priv_data);
+ void *priv_data;
+ errcode_t errcode;
+};
+
+static void inline_data_update_dir_entry(ext2_filsys fs, void *de_buf,
+ int old_size, int new_size)
+{
+ struct ext2_dir_entry *entry, *prev;
+ void *limit;
+ unsigned int de_len;
+
+ entry = (struct ext2_dir_entry *)de_buf;
+ if (old_size) {
+ limit = de_buf + old_size;
+ do {
+ prev = entry;
+ ext2fs_get_rec_len(fs, entry, &de_len);
+ de_buf += de_len;
+ entry = (struct ext2_dir_entry *)de_buf;
+ } while (de_buf < limit);
+
+ ext2fs_set_rec_len(fs, de_len + new_size - old_size, prev);
+ } else {
+ entry->inode = 0;
+ ext2fs_set_rec_len(fs, new_size, entry);
+ }
+}
+
+static int inline_data_destory_data(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode_large *inode,
+ struct inline_data *idata)
+{
+ struct ext2_ext_attr_entry *entry;
+ errcode_t retval;
+ char *start, *end;
+ int cmp;
+ __u32 *magic;
+
+ if (!idata->inline_off)
+ return 0;
+
+ if (inode->i_extra_isize > (EXT2_INODE_SIZE(fs->super) -
+ EXT2_GOOD_OLD_INODE_SIZE)) {
+ fprintf(stderr, "invalid inode->i_extra_isize (%u)\n",
+ inode->i_extra_isize);
+ return -1;
+ }
+
+ magic = (__u32*)((char *)inode + EXT2_GOOD_OLD_INODE_SIZE +
+ inode->i_extra_isize);
+ start = (char *)magic + sizeof(__u32);
+ end = (char *)inode + EXT2_INODE_SIZE(fs->super);
+ entry = (struct ext2_ext_attr_entry *)start;
+
+ cmp = ext2fs_find_entry_ext_attr(&entry, EXT4_XATTR_SYSTEM_DATA_INDEX,
+ EXT4_XATTR_SYSTEM_DATA_NAME,
+ end - start, 0);
+
+ if (!cmp) {
+ entry->e_value_offs = 0;
+ entry->e_value_block = 0;
+ entry->e_value_size = 0;
+ }
+
+ memset((void *)inode->i_block, 0, EXT4_MIN_INLINE_DATA_SIZE);
+
+ 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_write_inode_full(fs, ino, (void *)inode,
+ EXT2_INODE_SIZE(fs->super));
+ if (retval)
+ return retval;
+
+ return 0;
+}
+
+static int inline_data_search_dir(ext2_filsys fs,
+ struct ext2_inode_large *inode,
+ char *start,
+ int size,
+ void *priv_data)
+{
+ struct inline_data_context *ctx;
+ struct ext2_dir_entry *dirent;
+ unsigned int rec_len;
+ unsigned int offset = 0;
+ char *dlimit;
+ int ret;
+ int do_abort = 0;
+ int changed = 0;
+
+ ctx = (struct inline_data_context *)priv_data;
+
+ dirent = (struct ext2_dir_entry *)start;
+ dlimit = start + size;
+
+ while ((char *)dirent < dlimit) {
+ if (ext2fs_get_rec_len(fs, dirent, &rec_len))
+ return BLOCK_ABORT;
+ if (!dirent->inode &&
+ !(ctx->flags & DIRENT_FLAG_INCLUDE_EMPTY))
+ goto next;
+ ret = (ctx->func)(ctx->ino, 0, dirent,
+ offset, size, start,
+ ctx->priv_data);
+
+ if (ret & DIRENT_CHANGED) {
+ if (ext2fs_get_rec_len(fs, dirent, &rec_len))
+ return BLOCK_ABORT;
+ changed++;
+ }
+
+ if (ret & DIRENT_ABORT)
+ do_abort++;
+
+next:
+ dirent = (struct ext2_dir_entry *)((char *)dirent + rec_len);
+ offset += rec_len;
+ }
+
+ if (changed) {
+ ctx->errcode = ext2fs_write_inode_full(fs, ctx->ino, (void *)inode,
+ EXT2_INODE_SIZE(fs->super));
+ if (ctx->errcode)
+ return BLOCK_ABORT;
+ }
+
+ if (do_abort)
+ return BLOCK_ABORT;
+
+ return 0;
+}
+
+static int inline_data_search_dir2(ext2_filsys fs, char *start, int size,
+ char *search_name, int len)
+{
+ struct ext2_dir_entry *dirent;
+ unsigned int rec_len;
+ char *dlimit;
+ int ret;
+ int do_abort = 0;
+
+ dirent = (struct ext2_dir_entry *)start;
+ dlimit = start + size;
+
+ while ((char *)dirent < dlimit) {
+ if (ext2fs_get_rec_len(fs, dirent, &rec_len))
+ return BLOCK_ABORT;
+ if (dirent->inode &&
+ len == (dirent->name_len & 0xFF) &&
+ strncmp(search_name, dirent->name, len) == 0) {
+ printf("Entry found at inline data\n");
+ break;
+ }
+ dirent = (struct ext2_dir_entry *)((char *)dirent + rec_len);
+ }
+
+ return 0;
+}
+
+void *ext2fs_get_inline_xattr_pos(struct ext2_inode_large *inode,
+ struct inline_data *idata)
+{
+ struct ext2_ext_attr_entry *entry;
+ struct ext2_ext_attr_ibody_header *header;
+
+ header = (struct ext2_ext_attr_ibody_header *)
+ ((void *)inode +
+ EXT2_GOOD_OLD_INODE_SIZE +
+ inode->i_extra_isize);
+ entry = (struct ext2_ext_attr_entry *)
+ ((void *)inode + idata->inline_off);
+
+ return (void *)((struct ext2_ext_attr_header *)((header) + 1)) +
+ entry->e_value_offs;
+}
+
+void ext2fs_iget_extra_inode(ext2_filsys fs, struct ext2_inode_large *inode,
+ struct inline_data *idata)
+{
+ struct ext2_ext_attr_entry *entry;
+ char *start, *end;
+ int cmp;
+ __u32 *magic;
+
+ idata->inline_off = 0;
+ if (inode->i_extra_isize > (EXT2_INODE_SIZE(fs->super) -
+ EXT2_GOOD_OLD_INODE_SIZE)) {
+ fprintf(stderr, "invalid inode->i_extra_isize (%u)\n",
+ inode->i_extra_isize);
+ return;
+ }
+
+ magic = (__u32*)((char *)inode + EXT2_GOOD_OLD_INODE_SIZE +
+ inode->i_extra_isize);
+ if (*magic == EXT2_EXT_ATTR_MAGIC) {
+ end = (char *)inode + EXT2_INODE_SIZE(fs->super);
+ start = (char *)magic + sizeof(__u32);
+ entry = (struct ext2_ext_attr_entry *)start;
+
+ cmp = ext2fs_find_entry_ext_attr(&entry, EXT4_XATTR_SYSTEM_DATA_INDEX,
+ EXT4_XATTR_SYSTEM_DATA_NAME,
+ end - start, 0);
+ if (!cmp) {
+ idata->inline_off = (__u16)((void *)entry -
+ (void *)inode);
+ idata->inline_size = EXT4_MIN_INLINE_DATA_SIZE +
+ entry->e_value_size;
+ }
+ }
+}
+
+int ext2fs_has_inline_data(ext2_filsys fs, ext2_ino_t ino)
+{
+ struct ext2_inode *inode;
+ errcode_t retval;
+ __u32 flags;
+
+ retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
+ if (retval)
+ return 0;
+
+ retval = ext2fs_read_inode_full(fs, ino, inode,
+ EXT2_INODE_SIZE(fs->super));
+ if (retval)
+ return 0;
+
+ flags = inode->i_flags;
+ ext2fs_free_mem(&inode);
+
+ return (flags & EXT4_INLINE_DATA_FL);
+}
+
+struct xlate {
+ int (*func)(struct ext2_dir_entry *dirent,
+ int offset,
+ int blocksize,
+ char *buf,
+ void *priv_data);
+ void *real_private;
+};
+
+static int xlate_func(ext2_ino_t dir EXT2FS_ATTR((unused)),
+ int entry EXT2FS_ATTR((unused)),
+ struct ext2_dir_entry *dirent, int offset,
+ int blocksize, char *buf, void *priv_data)
+{
+ struct xlate *xl = (struct xlate *)priv_data;
+
+ return (*xl->func)(dirent, offset, blocksize, buf, xl->real_private);
+}
+
+errcode_t ext2fs_inline_data_iterate(ext2_filsys fs,
+ ext2_ino_t ino,
+ int flags,
+ char *block_buf,
+ int (*func)(struct ext2_dir_entry *dirent,
+ int offset,
+ int blocksize,
+ char *buf,
+ void *priv_data),
+ void *priv_data)
+{
+ struct xlate xl;
+
+ xl.real_private = priv_data;
+ xl.func = func;
+
+ return ext2fs_inline_data_iterate2(fs, ino, flags, block_buf,
+ xlate_func, &xl);
+}
+
+errcode_t ext2fs_inline_data_iterate2(ext2_filsys fs,
+ ext2_ino_t ino, int flags, char *block_buf,
+ int (*func)(ext2_ino_t ino,
+ int entry,
+ struct ext2_dir_entry *dirent,
+ int offset,
+ int blocksize,
+ char *buf,
+ void *priv_data),
+ void *priv_data)
+{
+ struct inline_data_context ctx;
+ struct ext2_inode_large *inode;
+ struct inline_data idata;
+ errcode_t retval;
+ blk64_t blk64;
+ void *inline_start;
+ int inline_size;
+ int ret = 0;
+ int i, limit, r;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ retval = ext2fs_check_directory(fs, ino);
+ if (retval)
+ return retval;
+
+ 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) {
+ ext2fs_free_mem(&inode);
+ return retval;
+ }
+
+ ctx.ino = ino;
+ ctx.flags = flags;
+ ctx.buf = block_buf;
+ ctx.func = func;
+ ctx.priv_data = priv_data;
+ ctx.errcode = 0;
+
+ inline_start = inode->i_block;
+ inline_size = EXT4_MIN_INLINE_DATA_SIZE;
+ ret = inline_data_search_dir(fs, inode, inline_start, inline_size, &ctx);
+ if (ret)
+ goto out;
+
+ ext2fs_iget_extra_inode(fs, inode, &idata);
+ if (idata.inline_size > EXT4_MIN_INLINE_DATA_SIZE) {
+ inline_start = ext2fs_get_inline_xattr_pos(inode, &idata);
+ inline_size = idata.inline_size - EXT4_MIN_INLINE_DATA_SIZE;
+ ret = inline_data_search_dir(fs, inode, inline_start, inline_size, &ctx);
+
+ if (ret)
+ goto out;
+ }
+
+out:
+ return ret & BLOCK_ABORT ? 0 : ret;
+}
+
+errcode_t ext2fs_inline_data_iterate3(ext2_filsys fs,
+ ext2_ino_t ino,
+ int flags,
+ char *block_buf,
+ const char *name,
+ int namelen,
+ int (*func)(struct ext2_dir_entry *dirent,
+ int offset,
+ int blocksize,
+ char *buf,
+ void *priv_data),
+ void *priv_data)
+{
+ struct xlate xl;
+ struct inline_data_context ctx;
+ struct ext2_inode_large *inode;
+ struct inline_data idata;
+ ext2_extent_handle_t handle;
+ errcode_t retval;
+ blk64_t blk;
+ void *inline_start;
+ char *backup_buf;
+ char *blk_buf;
+ int inline_size;
+ int ret = 0;
+ int i, limit, r;
+
+ xl.real_private = priv_data;
+ xl.func = func;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ 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) {
+ ext2fs_free_mem(&inode);
+ return retval;
+ }
+
+ ctx.ino = ino;
+ ctx.flags = flags;
+ ctx.buf = block_buf;
+ ctx.func = xlate_func;
+ ctx.priv_data = &xl;
+ ctx.errcode = 0;
+
+ inline_start = inode->i_block;
+ inline_size = EXT4_MIN_INLINE_DATA_SIZE;
+ ret = inline_data_search_dir(fs, inode, inline_start, inline_size, &ctx);
+ if (ret)
+ goto out;
+
+ ext2fs_iget_extra_inode(fs, inode, &idata);
+ inline_size = idata.inline_size - EXT4_MIN_INLINE_DATA_SIZE;
+ if (inline_size > 0) {
+ inline_start = ext2fs_get_inline_xattr_pos(inode, &idata);
+ ret = inline_data_search_dir(fs, inode, inline_start, inline_size, &ctx);
+ if (ret)
+ goto out;
+ }
+
+ /*
+ * TODO: we should try to expand xattr space firstly. But
+ * when creating too many dirs, Tao got a performance regression.
+ * Thus, it will be discussed and re-designed.
+ */
+
+ /*
+ * The inline space is filled up. So create a new block for it.
+ * As the extent tree will be created, we have to save the inline
+ * dir first.
+ */
+ inline_size = idata.inline_size;
+ retval = ext2fs_get_mem(inline_size, &backup_buf);
+ if (retval) {
+ ret = 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, &idata),
+ inline_size - EXT4_MIN_INLINE_DATA_SIZE);
+
+ /* clear the entry and the flag in dir now */
+ ret = inline_data_destory_data(fs, ino, inode, &idata);
+ if (ret)
+ goto out;
+
+ retval = ext2fs_new_block2(fs, 0, 0, &blk);
+ if (retval)
+ goto out;
+
+ 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 out;
+
+ memcpy(blk_buf, backup_buf, inline_size);
+
+ /* set the final dir entry to cover the whole block */
+ inline_data_update_dir_entry(fs, blk_buf, inline_size, fs->blocksize);
+
+ retval = ext2fs_write_dir_block(fs, blk, blk_buf);
+ if (retval)
+ goto out;
+ retval = ext2fs_write_inode_full(fs, ino, (void *)inode,
+ EXT2_INODE_SIZE(fs->super));
+ if (retval)
+ goto out;
+
+ if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) {
+ retval = ext2fs_extent_open2(fs, ino, (void *)inode, &handle);
+ if (retval)
+ goto out;
+ retval = ext2fs_extent_set_bmap(handle, 0, blk, 0);
+ ext2fs_extent_free(handle);
+ if (retval)
+ goto out;
+ }
+
+ /* Update accouting */
+ ext2fs_block_alloc_stats2(fs, blk, +1);
+
+ /* try to add a new entry */
+ retval = ext2fs_dir_iterate(fs, ino, DIRENT_FLAG_INCLUDE_EMPTY,
+ 0, func, priv_data);
+
+ ext2fs_free_mem(&backup_buf);
+ ext2fs_free_mem(&blk_buf);
+out:
+ ext2fs_free_mem(&inode);
+ return ret & BLOCK_ABORT ? 0 : ret;
+}
+
+errcode_t ext2fs_inline_data_search_dir(ext2_filsys fs, ext2_ino_t ino,
+ char *search_name, int len)
+{
+ struct ext2_inode_large *inode;
+ struct ext2_dir_entry *entry;
+ struct inline_data idata;
+ unsigned int rec_len;
+ errcode_t retval;
+ char *dlimit;
+ void *start;
+ int size;
+ int ret = 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)
+ return retval;
+
+ if (!(inode->i_flags & EXT4_INLINE_DATA_FL))
+ goto out;
+
+ start = inode->i_block;
+ size = EXT4_MIN_INLINE_DATA_SIZE;
+ ret = inline_data_search_dir2(fs, start, size, search_name, len);
+ if (!ret)
+ goto out;
+
+ ret = 0;
+ ext2fs_iget_extra_inode(fs, inode, &idata);
+ if (idata.inline_size == EXT4_MIN_INLINE_DATA_SIZE)
+ goto out;
+
+ start = ext2fs_get_inline_xattr_pos(inode, &idata);
+ size = idata.inline_size - EXT4_MIN_INLINE_DATA_SIZE;
+ ret = inline_data_search_dir2(fs, start, size, search_name, len);
+
+out:
+ ext2fs_free_mem(&inode);
+ return ret;
+}
+
+errcode_t ext2fs_inline_data_header_verify(ext2_filsys fs,
+ struct ext2_inode *inode)
+{
+ struct inline_data idata;
+ int ret = 0;
+
+ ext2fs_iget_extra_inode(fs, (void *)inode, &idata);
+ if (idata.inline_off == 0)
+ ret = -1;
+
+ return ret;
+}
+
+int ext2fs_inline_data_in_extra(ext2_filsys fs, ext2_ino_t ino)
+{
+ struct ext2_inode *inode;
+ struct inline_data idata;
+
+ ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
+ ext2fs_read_inode_full(fs, ino, inode, EXT2_INODE_SIZE(fs->super));
+
+ ext2fs_iget_extra_inode(fs, inode, &idata);
+ ext2fs_free_mem(&inode);
+ if (idata.inline_off == 0 ||
+ idata.inline_size == EXT4_MIN_INLINE_DATA_SIZE)
+ return 0;
+ else
+ return 1;
+}
+
+int ext2fs_inline_data_size(ext2_filsys fs, ext2_ino_t ino)
+{
+ struct ext2_inode *inode;
+ struct inline_data idata;
+
+ inode = (struct ext2_inode *) malloc(EXT2_INODE_SIZE(fs->super));
+ ext2fs_read_inode_full(fs, ino, inode, EXT2_INODE_SIZE(fs->super));
+
+ ext2fs_iget_extra_inode(fs, inode, &idata);
+ free(inode);
+ if (idata.inline_off == 0)
+ return 0;
+ else
+ return idata.inline_size;
+}
+
+errcode_t ext2fs_inline_data_expand_dir(ext2_filsys fs,
+ ext2_ino_t ino,
+ int flags,
+ char *block_buf,
+ int (*func)(ext2_filsys fs,
+ blk64_t *blocknr,
+ e2_blkcnt_t blockcnt,
+ blk64_t ref_blk,
+ int ref_offset,
+ void *priv_data),
+ void *priv_data)
+{
+ struct ext2_inode_large *inode;
+ struct inline_data idata;
+ ext2_extent_handle_t handle;
+ errcode_t retval;
+ blk64_t blk;
+ void *inline_start;
+ char *backup_buf;
+ char *blk_buf;
+ int inline_size;
+ int ret = 0;
+ int i, limit, r;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ 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) {
+ ext2fs_free_mem(&inode);
+ return retval;
+ }
+
+ ext2fs_iget_extra_inode(fs, inode, &idata);
+
+ inline_size = idata.inline_size;
+ retval = ext2fs_get_mem(inline_size, &backup_buf);
+ if (retval) {
+ ret = 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, &idata),
+ inline_size - EXT4_MIN_INLINE_DATA_SIZE);
+
+ /* clear the entry and the flag in dir now */
+ ret = inline_data_destory_data(fs, ino, inode, &idata);
+ if (ret)
+ goto out;
+
+ retval = ext2fs_new_block2(fs, 0, 0, &blk);
+ if (retval)
+ goto out;
+
+ 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 out;
+
+ memcpy(blk_buf, backup_buf, inline_size);
+
+ /* set the final dir entry to cover the whole block */
+ inline_data_update_dir_entry(fs, blk_buf, inline_size, fs->blocksize);
+
+ retval = ext2fs_write_dir_block(fs, blk, blk_buf);
+ if (retval)
+ goto out;
+ retval = ext2fs_write_inode_full(fs, ino, (void *)inode,
+ EXT2_INODE_SIZE(fs->super));
+ if (retval)
+ goto out;
+
+ if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) {
+ retval = ext2fs_extent_open2(fs, ino, (void *)inode, &handle);
+ if (retval)
+ goto out;
+ retval = ext2fs_extent_set_bmap(handle, 0, blk, 0);
+ ext2fs_extent_free(handle);
+ if (retval)
+ goto out;
+ }
+
+ /* Update accouting */
+ ext2fs_block_alloc_stats2(fs, blk, +1);
+
+ /* try to add a new entry */
+ retval = ext2fs_block_iterate3(fs, ino, flags, 0, func, priv_data);
+
+ ext2fs_free_mem(&backup_buf);
+ ext2fs_free_mem(&blk_buf);
+out:
+ ext2fs_free_mem(&inode);
+ return ret & BLOCK_ABORT ? 0 : ret;
+}
--
1.7.4.1


2012-04-16 11:34:12

by Zheng Liu

[permalink] [raw]
Subject: [PATCH 10/32] debugfs: make chroot and cd cmd support inline data

From: Zheng Liu <[email protected]>

Both chroot and cd command call ext2fs_lookup. So we can let it supoort
inline data simultaneously.

Signed-off-by: Zheng Liu <[email protected]>
---
lib/ext2fs/lookup.c | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)

diff --git a/lib/ext2fs/lookup.c b/lib/ext2fs/lookup.c
index 0e66e71..9835082 100644
--- a/lib/ext2fs/lookup.c
+++ b/lib/ext2fs/lookup.c
@@ -60,7 +60,11 @@ errcode_t ext2fs_lookup(ext2_filsys fs, ext2_ino_t dir, const char *name,
ls.inode = inode;
ls.found = 0;

- retval = ext2fs_dir_iterate(fs, dir, 0, buf, lookup_proc, &ls);
+ if (ext2fs_has_inline_data(fs, dir))
+ retval = ext2fs_inline_data_iterate(fs, dir, 0, buf,
+ lookup_proc, &ls);
+ else
+ retval = ext2fs_dir_iterate(fs, dir, 0, buf, lookup_proc, &ls);
if (retval)
return retval;

--
1.7.4.1


2012-04-16 11:34:10

by Zheng Liu

[permalink] [raw]
Subject: [PATCH 09/32] debugfs: make ncheck cmd support inline data

From: Zheng Liu <[email protected]>

when inode has inline data, ext2fs_inline_data_iterate function is called
to traverse dirs.

Signed-off-by: Zheng Liu <[email protected]>
---
debugfs/ncheck.c | 8 ++++++--
1 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/debugfs/ncheck.c b/debugfs/ncheck.c
index 58f3a50..6dda919 100644
--- a/debugfs/ncheck.c
+++ b/debugfs/ncheck.c
@@ -171,8 +171,12 @@ void do_ncheck(int argc, char **argv)
iw.dir = ino;
iw.get_pathname_failed = 0;

- retval = ext2fs_dir_iterate(current_fs, ino, 0, 0,
- ncheck_proc, &iw);
+ if (ext2fs_has_inline_data(current_fs, ino))
+ retval = ext2fs_inline_data_iterate(current_fs, ino, 0,
+ 0, ncheck_proc, &iw);
+ else
+ retval = ext2fs_dir_iterate(current_fs, ino, 0, 0,
+ ncheck_proc, &iw);
ext2fs_free_mem(&iw.parent);
if (retval) {
com_err("ncheck", retval,
--
1.7.4.1


2012-04-16 11:34:15

by Zheng Liu

[permalink] [raw]
Subject: [PATCH 12/32] debugfs: make stat cmd support inline data

From: Zheng Liu <[email protected]>

It only tells the user that this inode contains inline data.

Signed-off-by: Zheng Liu <[email protected]>
---
debugfs/debugfs.c | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c
index 590468d..df9b954 100644
--- a/debugfs/debugfs.c
+++ b/debugfs/debugfs.c
@@ -801,6 +801,10 @@ void internal_dump_inode(FILE *out, const char *prefix,
if (inode->i_dtime)
fprintf(out, "%sdtime: 0x%08x -- %s", prefix, inode->i_dtime,
time_to_string(inode->i_dtime));
+ if (inode->i_flags & EXT4_INLINE_DATA_FL) {
+ fprintf(out, "Inode has inline data\n");
+ return;
+ }
if (EXT2_INODE_SIZE(current_fs->super) > EXT2_GOOD_OLD_INODE_SIZE)
internal_dump_inode_extra(out, prefix, inode_num,
(struct ext2_inode_large *) inode);
--
1.7.4.1


2012-04-16 11:34:14

by Zheng Liu

[permalink] [raw]
Subject: [PATCH 11/32] debugfs: make ls cmd support inline data

From: Zheng Liu <[email protected]>

Signed-off-by: Zheng Liu <[email protected]>
---
debugfs/ls.c | 8 ++++++--
1 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/debugfs/ls.c b/debugfs/ls.c
index b4036de..14e7022 100644
--- a/debugfs/ls.c
+++ b/debugfs/ls.c
@@ -170,8 +170,12 @@ void do_list_dir(int argc, char *argv[])
if (ls.options & DELETED_OPT)
flags |= DIRENT_FLAG_INCLUDE_REMOVED;

- retval = ext2fs_dir_iterate2(current_fs, inode, flags,
- 0, list_dir_proc, &ls);
+ if (ext2fs_has_inline_data(current_fs, inode))
+ retval = ext2fs_inline_data_iterate2(current_fs, inode,flags,
+ 0, list_dir_proc, &ls);
+ else
+ retval = ext2fs_dir_iterate2(current_fs, inode, flags,
+ 0, list_dir_proc, &ls);
fprintf(ls.f, "\n");
close_pager(ls.f);
if (retval)
--
1.7.4.1


2012-04-16 11:34:17

by Zheng Liu

[permalink] [raw]
Subject: [PATCH 13/32] debufs: make blocks cmd support inline data

From: Zheng Liu <[email protected]>

Block entries don't point to blocks. So it doesn't show anything when this
inode has inline data.

Singed-off-by: Zheng Liu <[email protected]>
---
debugfs/debugfs.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c
index df9b954..17e5ec8 100644
--- a/debugfs/debugfs.c
+++ b/debugfs/debugfs.c
@@ -958,6 +958,9 @@ void do_blocks(int argc, char *argv[])
return;
}

+ if (ext2fs_has_inline_data(current_fs, inode))
+ return;
+
ext2fs_block_iterate3(current_fs, inode, BLOCK_FLAG_READ_ONLY, NULL,
print_blocks_proc, NULL);
fputc('\n', stdout);
--
1.7.4.1


2012-04-16 11:34:19

by Zheng Liu

[permalink] [raw]
Subject: [PATCH 14/32] debugfs: make filefrag cmd support inline data

From: Zheng Liu <[email protected]>

Inode with inline data doesn't have any fragmentations.

Signed-off-by: Zheng Liu <[email protected]>
---
debugfs/filefrag.c | 30 ++++++++++++++++++------------
1 files changed, 18 insertions(+), 12 deletions(-)

diff --git a/debugfs/filefrag.c b/debugfs/filefrag.c
index 7f28bc0..c94396c 100644
--- a/debugfs/filefrag.c
+++ b/debugfs/filefrag.c
@@ -153,16 +153,18 @@ static void filefrag(ext2_ino_t ino, struct ext2_inode *inode,
fprintf(fs->f, "\n%s has %llu block(s), i_size is %llu\n",
fs->name, num_blocks, EXT2_I_SIZE(inode));
}
- print_header(fs);
- retval = ext2fs_block_iterate3(current_fs, ino,
- BLOCK_FLAG_READ_ONLY, NULL,
- filefrag_blocks_proc, fs);
- if (retval)
- com_err("ext2fs_block_iterate3", retval, 0);
-
- report_filefrag(fs);
- fprintf(fs->f, "%s: %d contiguous extents%s\n", fs->name, fs->ext,
- LINUX_S_ISDIR(inode->i_mode) ? " (dir)" : "");
+ if (!ext2fs_has_inline_data(current_fs, ino)) {
+ print_header(fs);
+ retval = ext2fs_block_iterate3(current_fs, ino,
+ BLOCK_FLAG_READ_ONLY, NULL,
+ filefrag_blocks_proc, fs);
+ if (retval)
+ com_err("ext2fs_block_iterate3", retval, 0);
+
+ report_filefrag(fs);
+ fprintf(fs->f, "%s: %d contiguous extents%s\n", fs->name, fs->ext,
+ LINUX_S_ISDIR(inode->i_mode) ? " (dir)" : "");
+ }
}

static int filefrag_dir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)),
@@ -240,8 +242,12 @@ static void dir_iterate(ext2_ino_t ino, struct filefrag_struct *fs)
fs->dir_name = fs->name;

while (1) {
- retval = ext2fs_dir_iterate2(current_fs, ino, 0,
- 0, filefrag_dir_proc, fs);
+ if (ext2fs_has_inline_data(current_fs, ino))
+ retval = ext2fs_inline_data_iterate2(current_fs, ino,
+ 0, 0, filefrag_dir_proc, fs);
+ else
+ retval = ext2fs_dir_iterate2(current_fs, ino, 0,
+ 0, filefrag_dir_proc, fs);
if (retval)
com_err("ext2fs_dir_iterate2", retval, 0);
if (p) {
--
1.7.4.1


2012-04-16 11:34:20

by Zheng Liu

[permalink] [raw]
Subject: [PATCH 15/32] debugfs: make link cmd support inline data

From: Zheng Liu <[email protected]>

Signed-off-by: Zheng Liu <[email protected]>
---
lib/ext2fs/link.c | 9 +++++++--
1 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/lib/ext2fs/link.c b/lib/ext2fs/link.c
index 2d03b57..e62567c 100644
--- a/lib/ext2fs/link.c
+++ b/lib/ext2fs/link.c
@@ -131,8 +131,13 @@ errcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name,
ls.blocksize = fs->blocksize;
ls.err = 0;

- retval = ext2fs_dir_iterate(fs, dir, DIRENT_FLAG_INCLUDE_EMPTY,
- 0, link_proc, &ls);
+ if (ext2fs_has_inline_data(fs, dir))
+ retval = ext2fs_inline_data_iterate3(fs, dir,
+ DIRENT_FLAG_INCLUDE_EMPTY, 0, ls.name,
+ ls.namelen, link_proc, &ls);
+ else
+ retval = ext2fs_dir_iterate(fs, dir, DIRENT_FLAG_INCLUDE_EMPTY,
+ 0, link_proc, &ls);
if (retval)
return retval;
if (ls.err)
--
1.7.4.1


2012-04-16 11:34:26

by Zheng Liu

[permalink] [raw]
Subject: [PATCH 18/32] debugfs: make rmdir cmd support inline data

From: Zheng Liu <[email protected]>

Signed-off-by: Zheng Liu <[email protected]>
---
debugfs/debugfs.c | 8 ++++++--
1 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c
index 17e5ec8..7a97c48 100644
--- a/debugfs/debugfs.c
+++ b/debugfs/debugfs.c
@@ -1948,8 +1948,12 @@ void do_rmdir(int argc, char *argv[])
rds.parent = 0;
rds.empty = 1;

- retval = ext2fs_dir_iterate2(current_fs, inode_num, 0,
- 0, rmdir_proc, &rds);
+ if (ext2fs_has_inline_data(current_fs, inode_num))
+ retval = ext2fs_inline_data_iterate2(current_fs, inode_num, 0,
+ 0, rmdir_proc, &rds);
+ else
+ retval = ext2fs_dir_iterate2(current_fs, inode_num, 0,
+ 0, rmdir_proc, &rds);
if (retval) {
com_err(argv[0], retval, "while iterating over directory");
return;
--
1.7.4.1


2012-04-16 11:34:22

by Zheng Liu

[permalink] [raw]
Subject: [PATCH 16/32] debugfs: make unlink cmd support inline data

From: Zheng Liu <[email protected]>

Signed-off-by: Zheng Liu <[email protected]>
---
lib/ext2fs/unlink.c | 9 +++++++--
1 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/lib/ext2fs/unlink.c b/lib/ext2fs/unlink.c
index d2d31cc..6852d4a 100644
--- a/lib/ext2fs/unlink.c
+++ b/lib/ext2fs/unlink.c
@@ -90,8 +90,13 @@ errcode_t ext2fs_unlink(ext2_filsys fs, ext2_ino_t dir,
ls.done = 0;
ls.prev = 0;

- retval = ext2fs_dir_iterate(fs, dir, DIRENT_FLAG_INCLUDE_EMPTY,
- 0, unlink_proc, &ls);
+ if (ext2fs_has_inline_data(fs, dir))
+ retval = ext2fs_inline_data_iterate(fs, dir,
+ DIRENT_FLAG_INCLUDE_EMPTY, 0,
+ unlink_proc, &ls);
+ else
+ retval = ext2fs_dir_iterate(fs, dir, DIRENT_FLAG_INCLUDE_EMPTY,
+ 0, unlink_proc, &ls);
if (retval)
return retval;

--
1.7.4.1


2012-04-16 11:34:24

by Zheng Liu

[permalink] [raw]
Subject: [PATCH 17/32] debugfs: make mkdir cmd support inline data

From: Zheng Liu <[email protected]>

We need to reload inode in ext2fs_mkdir because inode with inline itself
data is modified in ext2fs_link.

Signed-off-by: Zheng Liu <[email protected]>
---
lib/ext2fs/mkdir.c | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/lib/ext2fs/mkdir.c b/lib/ext2fs/mkdir.c
index b12bf2d..d9a8278 100644
--- a/lib/ext2fs/mkdir.c
+++ b/lib/ext2fs/mkdir.c
@@ -134,6 +134,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 */
+ 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)
--
1.7.4.1


2012-04-16 11:34:28

by Zheng Liu

[permalink] [raw]
Subject: [PATCH 19/32] debugfs: make rm and kill_file cmd support inline data

From: Zheng Liu <[email protected]>

rm and kill_file command don't need to release blocks.

Signed-off-by: Zheng Liu <[email protected]>
---
debugfs/debugfs.c | 5 +++--
1 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c
index 7a97c48..517751f 100644
--- a/debugfs/debugfs.c
+++ b/debugfs/debugfs.c
@@ -1841,8 +1841,9 @@ static void kill_file_by_inode(ext2_ino_t inode)
if (!ext2fs_inode_has_valid_blocks2(current_fs, &inode_buf))
return;

- ext2fs_block_iterate3(current_fs, inode, BLOCK_FLAG_READ_ONLY, NULL,
- release_blocks_proc, NULL);
+ if (!ext2fs_has_inline_data(current_fs, inode))
+ ext2fs_block_iterate3(current_fs, inode, BLOCK_FLAG_READ_ONLY,
+ NULL, release_blocks_proc, NULL);
printf("\n");
ext2fs_inode_alloc_stats2(current_fs, inode, -1,
LINUX_S_ISDIR(inode_buf.i_mode));
--
1.7.4.1


2012-04-16 11:34:29

by Zheng Liu

[permalink] [raw]
Subject: [PATCH 20/32] debugfs: make pwd cmd support inline data

From: Zheng Liu <[email protected]>

Signed-off-by: Zheng Liu <[email protected]>
---
lib/ext2fs/get_pathname.c | 7 ++++++-
1 files changed, 6 insertions(+), 1 deletions(-)

diff --git a/lib/ext2fs/get_pathname.c b/lib/ext2fs/get_pathname.c
index 52aea62..f92f17d 100644
--- a/lib/ext2fs/get_pathname.c
+++ b/lib/ext2fs/get_pathname.c
@@ -98,7 +98,12 @@ static errcode_t ext2fs_get_pathname_int(ext2_filsys fs, ext2_ino_t dir,
gp.name = 0;
gp.errcode = 0;

- retval = ext2fs_dir_iterate(fs, dir, 0, buf, get_pathname_proc, &gp);
+ if (ext2fs_has_inline_data(fs, dir))
+ retval = ext2fs_inline_data_iterate(fs, dir, 0, buf,
+ get_pathname_proc, &gp);
+ else
+ retval = ext2fs_dir_iterate(fs, dir, 0, buf,
+ get_pathname_proc, &gp);
if (retval == EXT2_ET_NO_DIRECTORY) {
char tmp[32];

--
1.7.4.1


2012-04-16 11:34:31

by Zheng Liu

[permalink] [raw]
Subject: [PATCH 21/32] debugfs: make expand_dir cmd support inline data

From: Zheng Liu <[email protected]>

Signed-off-by: Zheng Liu <[email protected]>
---
lib/ext2fs/expanddir.c | 8 ++++++--
1 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/lib/ext2fs/expanddir.c b/lib/ext2fs/expanddir.c
index 41c4088..8caa97b 100644
--- a/lib/ext2fs/expanddir.c
+++ b/lib/ext2fs/expanddir.c
@@ -111,8 +111,12 @@ errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir)
es.goal = 0;
es.newblocks = 0;

- retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND,
- 0, expand_dir_proc, &es);
+ if (ext2fs_has_inline_data(fs, dir))
+ retval = ext2fs_inline_data_expand_dir(fs, dir, BLOCK_CHANGED,
+ 0, expand_dir_proc, &es);
+ else
+ retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND,
+ 0, expand_dir_proc, &es);

if (es.err)
return es.err;
--
1.7.4.1


2012-04-16 11:34:38

by Zheng Liu

[permalink] [raw]
Subject: [PATCH 25/32] debugfs: make rdump cmd support inline data

From: Zheng Liu <[email protected]>

Signed-off-by: Zheng Liu <[email protected]>
---
debugfs/dump.c | 8 ++++++--
1 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/debugfs/dump.c b/debugfs/dump.c
index 10ebe7a..84de606 100644
--- a/debugfs/dump.c
+++ b/debugfs/dump.c
@@ -308,8 +308,12 @@ static void rdump_inode(ext2_ino_t ino, struct ext2_inode *inode,
goto errout;
}

- retval = ext2fs_dir_iterate(current_fs, ino, 0, 0,
- rdump_dirent, (void *) fullname);
+ if (ext2fs_has_inline_data(current_fs, ino))
+ retval = ext2fs_inline_data_iterate(current_fs, ino, 0, 0,
+ rdump_dirent, (void *) fullname);
+ else
+ retval = ext2fs_dir_iterate(current_fs, ino, 0, 0,
+ rdump_dirent, (void *) fullname);
if (retval)
com_err("rdump", retval, "while dumping %s", fullname);

--
1.7.4.1


2012-04-16 11:34:33

by Zheng Liu

[permalink] [raw]
Subject: [PATCH 22/32] debugfs: make lsdel cmd support inline data

From: Zheng Liu <[email protected]>

Signed-off-by: Zheng Liu <[email protected]>
---
debugfs/lsdel.c | 19 +++++++++++--------
1 files changed, 11 insertions(+), 8 deletions(-)

diff --git a/debugfs/lsdel.c b/debugfs/lsdel.c
index bed0ce6..ff283cd 100644
--- a/debugfs/lsdel.c
+++ b/debugfs/lsdel.c
@@ -141,15 +141,18 @@ void do_lsdel(int argc, char **argv)
lsd.free_blocks = 0;
lsd.bad_blocks = 0;

- retval = ext2fs_block_iterate3(current_fs, ino,
- BLOCK_FLAG_READ_ONLY, block_buf,
- lsdel_proc, &lsd);
- if (retval) {
- com_err("ls_deleted_inodes", retval,
- "while calling ext2fs_block_iterate2");
- goto next;
+ if (!ext2fs_has_inline_data(current_fs, ino)) {
+ retval = ext2fs_block_iterate3(current_fs, ino,
+ BLOCK_FLAG_READ_ONLY, block_buf,
+ lsdel_proc, &lsd);
+ if (retval) {
+ com_err("ls_deleted_inodes", retval,
+ "while calling ext2fs_block_iterate2");
+ goto next;
+ }
}
- if (lsd.free_blocks && !lsd.bad_blocks) {
+ if (lsd.free_blocks && !lsd.bad_blocks ||
+ ext2fs_has_inline_data(current_fs, ino)) {
if (num_delarray >= max_delarray) {
max_delarray += 50;
delarray = realloc(delarray,
--
1.7.4.1


2012-04-16 11:34:36

by Zheng Liu

[permalink] [raw]
Subject: [PATCH 24/32] debugfs: make dump and cat cmd support inline data

From: Zheng Liu <[email protected]>

dump and cat command use the same function to read data. We can direclty read
the data from inode.

Signed-off-by: Zheng Liu <[email protected]>
---
debugfs/dump.c | 30 ++++++++++++++++++++++++++++++
1 files changed, 30 insertions(+), 0 deletions(-)

diff --git a/debugfs/dump.c b/debugfs/dump.c
index a15a0b7..10ebe7a 100644
--- a/debugfs/dump.c
+++ b/debugfs/dump.c
@@ -113,6 +113,36 @@ static void dump_file(const char *cmdname, ext2_ino_t ino, int fd,
if (debugfs_read_inode(ino, &inode, cmdname))
return;

+ if (ext2fs_has_inline_data(current_fs, ino)) {
+ struct ext2_inode_large *inode;
+ struct inline_data idata;
+ void *inline_start;
+ int inline_size;
+
+ retval = ext2fs_get_mem(EXT2_INODE_SIZE(current_fs->super),
+ &inode);
+ if (retval)
+ return;
+
+ retval = ext2fs_read_inode_full(current_fs, ino, (void *)inode,
+ EXT2_INODE_SIZE(current_fs->super));
+ if (retval)
+ goto out;
+ write(fd, inode->i_block, EXT4_MIN_INLINE_DATA_SIZE);
+
+ ext2fs_iget_extra_inode(current_fs, inode, &idata);
+ if (idata.inline_off == EXT4_MIN_INLINE_DATA_SIZE)
+ goto out;
+
+ inline_start = ext2fs_get_inline_xattr_pos(inode, &idata);
+ inline_size = idata.inline_size - EXT4_MIN_INLINE_DATA_SIZE;
+ write(fd, inline_start, inline_size);
+
+out:
+ ext2fs_free_mem(&inode);
+ return;
+ }
+
retval = ext2fs_file_open(current_fs, ino, 0, &e2_file);
if (retval) {
com_err(cmdname, retval, "while opening ext2 file");
--
1.7.4.1


2012-04-16 11:34:35

by Zheng Liu

[permalink] [raw]
Subject: [PATCH 23/32] debugfs: make undel cmd support inline data

From: Zheng Liu <[email protected]>

Inode with inline data doesn't need to mark blocks.

Signed-off-by: Zheng Liu <[email protected]>
---
debugfs/debugfs.c | 5 +++--
1 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c
index 517751f..b591b9b 100644
--- a/debugfs/debugfs.c
+++ b/debugfs/debugfs.c
@@ -1435,8 +1435,9 @@ void do_undel(int argc, char *argv[])
if (debugfs_write_inode(ino, &inode, argv[0]))
return;

- ext2fs_block_iterate3(current_fs, ino, BLOCK_FLAG_READ_ONLY, NULL,
- mark_blocks_proc, NULL);
+ if (!ext2fs_has_inline_data(current_fs, ino))
+ ext2fs_block_iterate3(current_fs, ino, BLOCK_FLAG_READ_ONLY, NULL,
+ mark_blocks_proc, NULL);

ext2fs_inode_alloc_stats2(current_fs, ino, +1, 0);

--
1.7.4.1


2012-04-16 11:34:40

by Zheng Liu

[permalink] [raw]
Subject: [PATCH 26/32] debugfs: make dirsearch cmd support inline data

From: Zheng Liu <[email protected]>

Signed-off-by: Zheng Liu <[email protected]>
---
debugfs/htree.c | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/debugfs/htree.c b/debugfs/htree.c
index 05745eb..0e77c31 100644
--- a/debugfs/htree.c
+++ b/debugfs/htree.c
@@ -354,9 +354,15 @@ void do_dirsearch(int argc, char *argv[])
pb.search_name = argv[2];
pb.len = strlen(pb.search_name);

+ if (ext2fs_has_inline_data(current_fs, inode))
+ if (ext2fs_inline_data_search_dir(current_fs, inode, argv[2],
+ strlen(argv[2])) == 0)
+ goto out;
+
ext2fs_block_iterate3(current_fs, inode, BLOCK_FLAG_READ_ONLY, 0,
search_dir_block, &pb);

+out:
free(pb.buf);
}

--
1.7.4.1


2012-04-16 11:34:42

by Zheng Liu

[permalink] [raw]
Subject: [PATCH 27/32] debugfs: make bma cmd support inline data

From: Zheng Liu <[email protected]>

Now this command returns inode's phy block when this inode has inline data.

Signed-off-by: Zheng Liu <[email protected]>
---
lib/ext2fs/bmap.c | 16 ++++++++++++++++
1 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/lib/ext2fs/bmap.c b/lib/ext2fs/bmap.c
index 16d51e0..101fe90 100644
--- a/lib/ext2fs/bmap.c
+++ b/lib/ext2fs/bmap.c
@@ -264,6 +264,22 @@ errcode_t ext2fs_bmap2(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode,
block_buf = buf;
}

+ if (inode->i_flags & EXT4_INLINE_DATA_FL) {
+ unsigned long group, block, offset;
+
+ group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
+ if (group > fs->group_desc_count)
+ return EXT2_ET_BAD_INODE_NUM;
+ offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
+ EXT2_INODE_SIZE(fs->super);
+ block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super);
+ if (!ext2fs_inode_table_loc(fs, (unsigned) group))
+ return EXT2_ET_MISSING_INODE_TABLE;
+ *phys_blk = ext2fs_inode_table_loc(fs, group) + block;
+
+ goto done;
+ }
+
if (inode->i_flags & EXT4_EXTENTS_FL) {
retval = ext2fs_extent_open2(fs, ino, inode, &handle);
if (retval)
--
1.7.4.1


2012-04-16 11:34:43

by Zheng Liu

[permalink] [raw]
Subject: [PATCH 28/32] e2fsck: add three problem descriptions in pass1

From: Zheng Liu <[email protected]>

In pass1, we will meet three problems. So add descriptions in problem table.

Signed-off-by: Zheng Liu <[email protected]>
---
e2fsck/problem.c | 15 +++++++++++++++
e2fsck/problem.h | 9 +++++++++
2 files changed, 24 insertions(+), 0 deletions(-)

diff --git a/e2fsck/problem.c b/e2fsck/problem.c
index d51a408..de6153d 100644
--- a/e2fsck/problem.c
+++ b/e2fsck/problem.c
@@ -946,6 +946,21 @@ static struct e2fsck_problem problem_table[] = {
N_("@i %i has zero length extent\n\t(@n logical @b %c, physical @b %b)\n"),
PROMPT_CLEAR, 0 },

+ /* INLINE_DATA is set and EXT_ATTR is not set */
+ { PR_1_INLINE_DATA_AND_EXT_ATTR,
+ N_("INLINE_DATA is set in @S, but it is missing EXT_ATTR feature\n"),
+ PROMPT_FIX, 0 },
+
+ /* Inode has inline data, superblock missing INCOMPAT_INLINE_DATA feature */
+ { PR_1_INLINE_DATA_FEATURE,
+ N_("@i %i is in inline data format, but @S is missing INLINEDATA feature\n"),
+ PROMPT_CLEAR, PR_PREEN_OK },
+
+ /* INLINE_DATA_FL flag set on a non-inline-data filesystem */
+ { PR_1_INLINE_DATA_SET,
+ N_("@i %i has INLINE_DATA_FL flag set 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 07df810..79b6825 100644
--- a/e2fsck/problem.h
+++ b/e2fsck/problem.h
@@ -558,6 +558,15 @@ struct problem_context {
/* Extent has zero length */
#define PR_1_EXTENT_LENGTH_ZERO 0x010066

+/* INLINE_DATA is set and EXT_ATTR is not set */
+#define PR_1_INLINE_DATA_AND_EXT_ATTR 0x010067
+
+/* Inode has inline data, superblock missing INCOMPAT_INLINE_DATA feature */
+#define PR_1_INLINE_DATA_FEATURE 0x010068
+
+/* INLINE_DATA_FL flag set on a non-inline-data capable filesystem */
+#define PR_1_INLINE_DATA_SET 0x010069
+
/*
* Pass 1b errors
*/
--
1.7.4.1


2012-04-16 11:34:45

by Zheng Liu

[permalink] [raw]
Subject: [PATCH 29/32] e2fsck: check incorrect inline data flag

From: Zheng Liu <[email protected]>

First, we need to check whether or not EXT_ATTR feature is set when
INLINE_DATA feature is set. Then we will check inode flag to set
EXT4_INLINE_DATA_FL flag. If the user doesn't set this flag, INLINE_DATA
feature will be clear.

Signed-off-by: Zheng Liu <[email protected]>
---
e2fsck/pass1.c | 33 ++++++++++++++++++++++++++++++++-
1 files changed, 32 insertions(+), 1 deletions(-)

diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index c7645d1..023d8ed 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -559,7 +559,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;

@@ -592,6 +592,7 @@ 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
@@ -722,6 +723,17 @@ void e2fsck_pass1(e2fsck_t ctx)
ext2fs_mark_block_bitmap2(ctx->block_found_map,
fs->super->s_mmp_block);

+ /*
+ * If INLINE_DATA is set and EXT_ATTR doesn't, EXT_ATTR needs to be set
+ * because INLINE_DATA depends on it. So the user need to determine
+ * whether EXT_ATTR is set or not.
+ */
+ 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))
+ ext2fs_mark_super_dirty(fs);
+ }
+
while (1) {
if (ino % (fs->super->s_inodes_per_group * 4) == 1) {
if (e2fsck_mmp_update(fs))
@@ -762,6 +774,25 @@ void e2fsck_pass1(e2fsck_t ctx)
}

/*
+ * Test for incorrect inline data flags settings.
+ *
+ * TODO: check EXT2_ROOT_INO when '/' supports inline data
+ * feature.
+ */
+ if ((inode->i_flags & EXT4_INLINE_DATA_FL) && !inlinedata_fs &&
+ (ino >= EXT2_FIRST_INODE(fs->super))) {
+ if (ext2fs_inline_data_header_verify(fs, inode) == 0 &&
+ 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.
*
* On big-endian machines we must be careful:
--
1.7.4.1


2012-04-16 11:34:50

by Zheng Liu

[permalink] [raw]
Subject: [PATCH 32/32] e2fsck: check inline data in pass2

From: Zheng Liu <[email protected]>

Signed-off-by: Zheng Liu <[email protected]>
---
e2fsck/pass2.c | 50 ++++++++++++++++++++++++++++++++++++++-------
lib/ext2fs/inline_data.c | 4 +-
2 files changed, 44 insertions(+), 10 deletions(-)

diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c
index 882950d..0b902f2 100644
--- a/e2fsck/pass2.c
+++ b/e2fsck/pass2.c
@@ -70,6 +70,7 @@ static int allocate_dir_block(e2fsck_t ctx,
static void clear_htree(e2fsck_t ctx, ext2_ino_t ino);
static int htree_depth(struct dx_dir_info *dx_dir,
struct dx_dirblock_info *dx_db);
+static int is_last_entry(ext2_filsys fs, ext2_ino_t ino, unsigned int offset);
static EXT2_QSORT_TYPE special_dir_block_cmp(const void *a, const void *b);

struct check_dir_struct {
@@ -715,6 +716,7 @@ static int check_dir_block(ext2_filsys fs,
struct dx_dirblock_info *dx_db = 0;
#endif /* ENABLE_HTREE */
struct ext2_dir_entry *dirent, *prev;
+ struct ext2_inode inode;
ext2_dirhash_t hash;
unsigned int offset = 0;
int dir_modified = 0;
@@ -759,7 +761,8 @@ static int check_dir_block(ext2_filsys fs,
cd->pctx.dirent = 0;
cd->pctx.num = 0;

- if (db->blk == 0) {
+ /* We don't need to allocate dir blocks for inline_data dir */
+ if (db->blk == 0 && !ext2fs_has_inline_data(fs, db->ino)) {
if (allocate_dir_block(ctx, db, buf, &cd->pctx))
return 0;
block_nr = db->blk;
@@ -780,7 +783,15 @@ static int check_dir_block(ext2_filsys fs,
#endif

ehandler_operation(_("reading directory block"));
- cd->pctx.errcode = ext2fs_read_dir_block3(fs, block_nr, buf, 0);
+ ext2fs_read_inode(fs, ino, &inode);
+ if (inode.i_flags & EXT4_INLINE_DATA_FL) {
+ cd->pctx.errcode = ext2fs_read_dir_inline_data(fs, ino, buf);
+ if (!cd->pctx.errcode)
+ cd->pctx.errcode = ext2fs_read_dir_inline_data_more(fs,
+ ino, buf);
+ } else {
+ cd->pctx.errcode = ext2fs_read_dir_block3(fs, block_nr, buf, 0);
+ }
ehandler_operation(0);
if (cd->pctx.errcode == EXT2_ET_DIR_CORRUPTED)
cd->pctx.errcode = 0; /* We'll handle this ourselves */
@@ -1107,7 +1118,7 @@ out_htree:
(void) ext2fs_get_rec_len(fs, dirent, &rec_len);
offset += rec_len;
dot_state++;
- } while (offset < fs->blocksize);
+ } while (is_last_entry(fs, ino, offset));
#if 0
printf("\n");
#endif
@@ -1125,14 +1136,29 @@ out_htree:
}
#endif /* ENABLE_HTREE */
if (offset != fs->blocksize) {
- cd->pctx.num = rec_len - fs->blocksize + offset;
- if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) {
- dirent->rec_len = cd->pctx.num;
- dir_modified++;
+ if (!(inode.i_flags & EXT4_INLINE_DATA_FL)) {
+ cd->pctx.errcode = rec_len - fs->blocksize + offset;
+ if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) {
+ dirent->rec_len = cd->pctx.num;
+ dir_modified++;
+ }
+ } else {
+ if (offset != ext2fs_inline_data_size(fs, ino)) {
+ cd->pctx.errcode = rec_len + offset -
+ ext2fs_inline_data_size(fs, ino);
+ if (fix_problem(ctx, PR_2_FINAL_RECLEN,
+ &cd->pctx)) {
+ dirent->rec_len = cd->pctx.num;
+ dir_modified++;
+ }
+ }
}
}
if (dir_modified) {
- cd->pctx.errcode = ext2fs_write_dir_block(fs, block_nr, buf);
+ if (inode.i_flags & EXT4_INLINE_DATA_FL)
+ cd->pctx.errcode = ext2fs_write_dir_inline_data(fs, ino, buf);
+ else
+ cd->pctx.errcode = ext2fs_write_dir_block(fs, block_nr, buf);
if (cd->pctx.errcode) {
if (!fix_problem(ctx, PR_2_WRITE_DIRBLOCK,
&cd->pctx))
@@ -1483,3 +1509,11 @@ static int allocate_dir_block(e2fsck_t ctx,

return 0;
}
+
+static int is_last_entry(ext2_filsys fs, ext2_ino_t ino, unsigned int offset)
+{
+ if (ext2fs_has_inline_data(fs, ino))
+ return (offset < ext2fs_inline_data_size(fs, ino));
+ else
+ return (offset < fs->blocksize);
+}
diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c
index 4ebd592..8dc7b8c 100644
--- a/lib/ext2fs/inline_data.c
+++ b/lib/ext2fs/inline_data.c
@@ -584,7 +584,7 @@ int ext2fs_inline_data_in_extra(ext2_filsys fs, ext2_ino_t ino)
ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
ext2fs_read_inode_full(fs, ino, inode, EXT2_INODE_SIZE(fs->super));

- ext2fs_iget_extra_inode(fs, inode, &idata);
+ ext2fs_iget_extra_inode(fs, (void *)inode, &idata);
ext2fs_free_mem(&inode);
if (idata.inline_off == 0 ||
idata.inline_size == EXT4_MIN_INLINE_DATA_SIZE)
@@ -601,7 +601,7 @@ int ext2fs_inline_data_size(ext2_filsys fs, ext2_ino_t ino)
inode = (struct ext2_inode *) malloc(EXT2_INODE_SIZE(fs->super));
ext2fs_read_inode_full(fs, ino, inode, EXT2_INODE_SIZE(fs->super));

- ext2fs_iget_extra_inode(fs, inode, &idata);
+ ext2fs_iget_extra_inode(fs, (void *)inode, &idata);
free(inode);
if (idata.inline_off == 0)
return 0;
--
1.7.4.1


2012-04-16 11:34:47

by Zheng Liu

[permalink] [raw]
Subject: [PATCH 30/32] e2fsck: make pass1 support inline data

From: Zheng Liu <[email protected]>

Signed-off-by: Zheng Liu <[email protected]>
---
e2fsck/pass1.c | 37 ++++++++++++++++++++++++++++++++++---
e2fsck/pass1b.c | 5 +++--
lib/ext2fs/dblist_dir.c | 8 ++++++--
3 files changed, 43 insertions(+), 7 deletions(-)

diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index 023d8ed..2b1873f 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -304,6 +304,10 @@ static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx)
goto fix;
}

+ /* not do the following checks for inline_data */
+ if (strcmp(EXT2_EXT_ATTR_NAME(entry), "data") == 0)
+ goto next;
+
/* attribute len eats this space */
remain -= EXT2_EXT_ATTR_SIZE(entry->e_name_len);

@@ -331,6 +335,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);
@@ -1158,7 +1163,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])
@@ -1167,6 +1173,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] ||
@@ -1980,6 +1987,22 @@ static void check_blocks_extents(e2fsck_t ctx, struct problem_context *pctx,
ext2fs_extent_free(ehandle);
}

+static void check_blocks_inline_data(e2fsck_t ctx, struct problem_context *pctx,
+ struct process_block_struct *pb)
+{
+ if (pb->is_dir) {
+ 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);
+ /* Should never get here */
+ ctx->flags |= E2F_FLAG_ABORT;
+ }
+ }
+}
+
/*
* This subroutine is called on each inode to account for all of the
* blocks used by that inode.
@@ -1994,6 +2017,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;
@@ -2017,6 +2041,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 &
@@ -2040,6 +2066,8 @@ 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,
@@ -2082,7 +2110,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--;
@@ -2108,7 +2137,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/e2fsck/pass1b.c b/e2fsck/pass1b.c
index 93fb630..6ff2af6 100644
--- a/e2fsck/pass1b.c
+++ b/e2fsck/pass1b.c
@@ -315,8 +315,9 @@ static void pass1b(e2fsck_t ctx, char *block_buf)
pb.inode = &inode;
pb.cur_cluster = ~0;

- if (ext2fs_inode_has_valid_blocks2(fs, &inode) ||
- (ino == EXT2_BAD_INO))
+ if ((ext2fs_inode_has_valid_blocks2(fs, &inode) ||
+ (ino == EXT2_BAD_INO)) &&
+ !(inode.i_flags & EXT4_INLINE_DATA_FL))
pctx.errcode = ext2fs_block_iterate3(fs, ino,
BLOCK_FLAG_READ_ONLY, block_buf,
process_pass1b_block, &pb);
diff --git a/lib/ext2fs/dblist_dir.c b/lib/ext2fs/dblist_dir.c
index d4d5111..cc54d7a 100644
--- a/lib/ext2fs/dblist_dir.c
+++ b/lib/ext2fs/dblist_dir.c
@@ -72,8 +72,12 @@ 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_has_inline_data(fs, ctx->dir))
+ ret = ext2fs_inline_data_iterate2(fs, ctx->dir, 0, NULL,
+ ctx->func, ctx->priv_data);
+ else
+ ret = ext2fs_process_dir_block(fs, &db_info->blk,
+ db_info->blockcnt, 0, 0, priv_data);
if ((ret & BLOCK_ABORT) && !ctx->errcode)
return DBLIST_ABORT;
return 0;
--
1.7.4.1


2012-04-16 11:34:49

by Zheng Liu

[permalink] [raw]
Subject: [PATCH 31/32] libext2fs: add read/write inline data functions

From: Zheng Liu <[email protected]>

Add read/write inline data functions for pass2.

Signed-off-by: Zheng Liu <[email protected]>
---
lib/ext2fs/dirblock.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++
lib/ext2fs/ext2fs.h | 6 ++++
2 files changed, 68 insertions(+), 0 deletions(-)

diff --git a/lib/ext2fs/dirblock.c b/lib/ext2fs/dirblock.c
index cb3a104..8fdffe5 100644
--- a/lib/ext2fs/dirblock.c
+++ b/lib/ext2fs/dirblock.c
@@ -71,6 +71,45 @@ errcode_t ext2fs_read_dir_block(ext2_filsys fs, blk_t block,
return ext2fs_read_dir_block3(fs, block, buf, 0);
}

+errcode_t ext2fs_read_dir_inline_data(ext2_filsys fs, ext2_ino_t ino, void *buf)
+{
+ struct ext2_inode_large *inode;
+ struct inline_data idata;
+
+ ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
+ ext2fs_read_inode_full(fs, ino, (void *)inode, EXT2_INODE_SIZE(fs->super));
+
+ if (!(inode->i_flags & EXT4_INLINE_DATA_FL))
+ return -1;
+
+ memcpy(buf, inode->i_block, EXT4_MIN_INLINE_DATA_SIZE);
+
+ ext2fs_free_mem(&inode);
+ return 0;
+}
+
+errcode_t ext2fs_read_dir_inline_data_more(ext2_filsys fs, ext2_ino_t ino, void *buf)
+{
+ struct ext2_inode_large *inode;
+ struct inline_data idata;
+
+ ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
+ ext2fs_read_inode_full(fs, ino, (void *)inode, EXT2_INODE_SIZE(fs->super));
+
+ if (!(inode->i_flags & EXT4_INLINE_DATA_FL))
+ return -1;
+
+ ext2fs_iget_extra_inode(fs, inode, &idata);
+ if (idata.inline_size == EXT4_MIN_INLINE_DATA_SIZE)
+ return 0;
+
+ memcpy(buf + EXT4_MIN_INLINE_DATA_SIZE,
+ ext2fs_get_inline_xattr_pos(inode, &idata),
+ idata.inline_size - EXT4_MIN_INLINE_DATA_SIZE);
+
+ ext2fs_free_mem(&inode);
+ return 0;
+}

errcode_t ext2fs_write_dir_block3(ext2_filsys fs, blk64_t block,
void *inbuf, int flags EXT2FS_ATTR((unused)))
@@ -125,3 +164,26 @@ errcode_t ext2fs_write_dir_block(ext2_filsys fs, blk_t block,
return ext2fs_write_dir_block3(fs, block, inbuf, 0);
}

+errcode_t ext2fs_write_dir_inline_data(ext2_filsys fs, ext2_ino_t ino, void *buf)
+{
+ struct ext2_inode_large *inode;
+ struct inline_data idata;
+
+ ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
+ ext2fs_read_inode_full(fs, ino, (void *)inode, EXT2_INODE_SIZE(fs->super));
+
+ memcpy(inode->i_block, buf, EXT4_MIN_INLINE_DATA_SIZE);
+
+ ext2fs_iget_extra_inode(fs, inode, &idata);
+ if (idata.inline_size == EXT4_MIN_INLINE_DATA_SIZE)
+ goto out;
+
+ memcpy(ext2fs_get_inline_xattr_pos(inode, &idata),
+ buf + EXT4_MIN_INLINE_DATA_SIZE,
+ idata.inline_size - EXT4_MIN_INLINE_DATA_SIZE);
+
+out:
+ ext2fs_write_inode_full(fs, ino, (void *)inode, EXT2_INODE_SIZE(fs->super));
+ ext2fs_free_mem(&inode);
+ return 0;
+}
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index cb1b58e..dcc9700 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -1009,12 +1009,18 @@ extern errcode_t ext2fs_read_dir_block2(ext2_filsys fs, blk_t block,
void *buf, int flags);
extern errcode_t ext2fs_read_dir_block3(ext2_filsys fs, blk64_t block,
void *buf, int flags);
+extern errcode_t ext2fs_read_dir_inline_data(ext2_filsys fs, ext2_ino_t ino,
+ void *buf);
+extern errcode_t ext2fs_read_dir_inline_data_more(ext2_filsys fs, ext2_ino_t ino,
+ void *buf);
extern errcode_t ext2fs_write_dir_block(ext2_filsys fs, blk_t block,
void *buf);
extern errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block,
void *buf, int flags);
extern errcode_t ext2fs_write_dir_block3(ext2_filsys fs, blk64_t block,
void *buf, int flags);
+extern errcode_t ext2fs_write_dir_inline_data(ext2_filsys fs, ext2_ino_t ino,
+ void *buf);

/* dirhash.c */
extern errcode_t ext2fs_dirhash(int version, const char *name, int len,
--
1.7.4.1


2012-04-16 15:05:12

by Andreas Dilger

[permalink] [raw]
Subject: Re: [PATCH 00/32] e2fsprogs: make e2fsprogs support inline data

On 2012-04-16, at 4:39 AM, Zheng Liu wrote:
> Here is v2 for making e2fsprogs support inline data. Now debugfs
> supports inline data in read-write mode. Meanwhile e2fsck has
> been improved to support inline data feature.
>
> v1->v2:
> * [mke2fs] automatically set EXT_ATTR feature when INLINE_DATA is set
> * [debugfs] supports read-write mode

As with the previous patch series, there is a need to show some
benchmark data that indicates how much improvement this feature
provides. Some examples would include percentage of directories
stored inline (e.g. in a typical distro installation), performance
improvement (e.g. cold-cache filesystem traversal). It is likely
that these improvements will be more visible with bigalloc enabled
for a large cluster size (e.g. space savings).

Without a clear indication of performance improvement, the patch
cannot be included due to added complexity and unclear benefits.

> In mke2fs, EXT4_FEATURE_INCOMPAT_INLINE_DATA is set to 0x2000 to
> consist with kernel. When making a new ext4 file system with
> INLINE_DATA feature, mke2fs will check whether EXT_ATTR is set or
> not. If it is not set, mke2fs will mark it automatically because
> INLINE_DATA depends on it.
>
> In debugfs, it can support inline data in read-write mode. Now
> there is two problems that need to be solved. No matter whether
> the size of data is fit into inline data or not, 'write' command
> writes the data into disk blocks rather than inode itself. 'mkdir'
> command will expand dir to a new disk block when inode->i_block
> has full because Tao found a performance regression when a huge
> number of dirs are added and removed in EA space. It causes that
> the code in kernel might be changed. So now 'mkdir' cmd doesn't
> add a new dir entry in EA space.
>
> TODO list:
> * [mke2fs] initialize ROOT dir with inline data flag
> * [mke2fs] initialize LOST+FOUND dir with inline data flag

Note that it does not make sense to store lost+found inline. It
is purposely created with multiple leaf blocks so that blocks
do not need to be allocated during e2fsck runs. Probably the
same is true for root - it will almost certainly immediately
be moved out of the inode due to file creations.

Cheers, Andreas

> * [debugfs] 'write' cmd writes the data into inode itself
> * [debugfs] 'mkdir' cmd add dir entry into EA space
>
> Regards,
> Zheng
>
> libext2fs: add EXT4_FEATURE_INCOMPAT_INLINE_DATA flag
> mke2fs: make it support inline data feature
> libext2fs: add inline_data feature
> mke2fs: add inline_data feature in mke2fs's manpage
> libext2fs: add ext2fs_find_entry_ext_attr function
> libext2fs: add EXT4_INLINE_DATA_FL flag for inode
> libext2fs: add data structures for inline data feature
> libext2fs: add inline_data file
> debugfs: make ncheck cmd support inline data
> debugfs: make chroot and cd cmd support inline data
> debugfs: make ls cmd support inline data
> debugfs: make stat cmd support inline data
> debufs: make blocks cmd support inline data
> debugfs: make filefrag cmd support inline data
> debugfs: make link cmd support inline data
> debugfs: make unlink cmd support inline data
> debugfs: make mkdir cmd support inline data
> debugfs: make rmdir cmd support inline data
> debugfs: make rm and kill_file cmd support inline data
> debugfs: make pwd cmd support inline data
> debugfs: make expand_dir cmd support inline data
> debugfs: make lsdel cmd support inline data
> debugfs: make undel cmd support inline data
> debugfs: make dump and cat cmd support inline data
> debugfs: make rdump cmd support inline data
> debugfs: make dirsearch cmd support inline data
> debugfs: make bma cmd support inline data
> e2fsck: add three problem descriptions in pass1
> e2fsck: check incorrect inline data flag
> e2fsck: make pass1 support inline data
> libext2fs: add read/write inline data functions
> e2fsck: check inline data in pass2
>
> debugfs/debugfs.c | 25 ++-
> debugfs/dump.c | 38 +++-
> debugfs/filefrag.c | 30 ++-
> debugfs/htree.c | 6 +
> debugfs/ls.c | 8 +-
> debugfs/lsdel.c | 19 +-
> debugfs/ncheck.c | 8 +-
> e2fsck/pass1.c | 70 ++++-
> e2fsck/pass1b.c | 5 +-
> e2fsck/pass2.c | 50 +++-
> e2fsck/problem.c | 15 +
> e2fsck/problem.h | 9 +
> lib/e2p/feature.c | 2 +
> lib/ext2fs/Makefile.in | 5 +
> lib/ext2fs/Makefile.pq | 1 +
> lib/ext2fs/bmap.c | 16 +
> lib/ext2fs/dblist_dir.c | 8 +-
> lib/ext2fs/dirblock.c | 62 ++++
> lib/ext2fs/expanddir.c | 8 +-
> lib/ext2fs/ext2_ext_attr.h | 4 +
> lib/ext2fs/ext2_fs.h | 9 +
> lib/ext2fs/ext2fs.h | 69 ++++-
> lib/ext2fs/ext_attr.c | 26 ++
> lib/ext2fs/get_pathname.c | 7 +-
> lib/ext2fs/inline_data.c | 715 ++++++++++++++++++++++++++++++++++++++++++++
> lib/ext2fs/link.c | 9 +-
> lib/ext2fs/lookup.c | 6 +-
> lib/ext2fs/mkdir.c | 4 +
> lib/ext2fs/unlink.c | 9 +-
> misc/mke2fs.8.in | 3 +
> misc/mke2fs.c | 10 +-
> 31 files changed, 1197 insertions(+), 59 deletions(-)
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html


Cheers, Andreas






2012-04-16 15:10:36

by Tao Ma

[permalink] [raw]
Subject: Re: [PATCH 00/32] e2fsprogs: make e2fsprogs support inline data

On 04/16/2012 11:08 PM, Andreas Dilger wrote:
> On 2012-04-16, at 4:39 AM, Zheng Liu wrote:
>> Here is v2 for making e2fsprogs support inline data. Now debugfs
>> supports inline data in read-write mode. Meanwhile e2fsck has
>> been improved to support inline data feature.
>>
>> v1->v2:
>> * [mke2fs] automatically set EXT_ATTR feature when INLINE_DATA is set
>> * [debugfs] supports read-write mode
>
> As with the previous patch series, there is a need to show some
> benchmark data that indicates how much improvement this feature
> provides. Some examples would include percentage of directories
> stored inline (e.g. in a typical distro installation), performance
> improvement (e.g. cold-cache filesystem traversal). It is likely
> that these improvements will be more visible with bigalloc enabled
> for a large cluster size (e.g. space savings).
yeah, I am doing some benchmark test and collect the data. They will be
available when I send out the new version.
>
> Without a clear indication of performance improvement, the patch
> cannot be included due to added complexity and unclear benefits.
sure, please wait for the kernel patches. :)
>
>> In mke2fs, EXT4_FEATURE_INCOMPAT_INLINE_DATA is set to 0x2000 to
>> consist with kernel. When making a new ext4 file system with
>> INLINE_DATA feature, mke2fs will check whether EXT_ATTR is set or
>> not. If it is not set, mke2fs will mark it automatically because
>> INLINE_DATA depends on it.
>>
>> In debugfs, it can support inline data in read-write mode. Now
>> there is two problems that need to be solved. No matter whether
>> the size of data is fit into inline data or not, 'write' command
>> writes the data into disk blocks rather than inode itself. 'mkdir'
>> command will expand dir to a new disk block when inode->i_block
>> has full because Tao found a performance regression when a huge
>> number of dirs are added and removed in EA space. It causes that
>> the code in kernel might be changed. So now 'mkdir' cmd doesn't
>> add a new dir entry in EA space.
>>
>> TODO list:
>> * [mke2fs] initialize ROOT dir with inline data flag
>> * [mke2fs] initialize LOST+FOUND dir with inline data flag
>
> Note that it does not make sense to store lost+found inline. It
> is purposely created with multiple leaf blocks so that blocks
> do not need to be allocated during e2fsck runs. Probably the
> same is true for root - it will almost certainly immediately
> be moved out of the inode due to file creations.
fair enough.

Thanks
Tao
>
> Cheers, Andreas
>
>> * [debugfs] 'write' cmd writes the data into inode itself
>> * [debugfs] 'mkdir' cmd add dir entry into EA space
>>
>> Regards,
>> Zheng
>>
>> libext2fs: add EXT4_FEATURE_INCOMPAT_INLINE_DATA flag
>> mke2fs: make it support inline data feature
>> libext2fs: add inline_data feature
>> mke2fs: add inline_data feature in mke2fs's manpage
>> libext2fs: add ext2fs_find_entry_ext_attr function
>> libext2fs: add EXT4_INLINE_DATA_FL flag for inode
>> libext2fs: add data structures for inline data feature
>> libext2fs: add inline_data file
>> debugfs: make ncheck cmd support inline data
>> debugfs: make chroot and cd cmd support inline data
>> debugfs: make ls cmd support inline data
>> debugfs: make stat cmd support inline data
>> debufs: make blocks cmd support inline data
>> debugfs: make filefrag cmd support inline data
>> debugfs: make link cmd support inline data
>> debugfs: make unlink cmd support inline data
>> debugfs: make mkdir cmd support inline data
>> debugfs: make rmdir cmd support inline data
>> debugfs: make rm and kill_file cmd support inline data
>> debugfs: make pwd cmd support inline data
>> debugfs: make expand_dir cmd support inline data
>> debugfs: make lsdel cmd support inline data
>> debugfs: make undel cmd support inline data
>> debugfs: make dump and cat cmd support inline data
>> debugfs: make rdump cmd support inline data
>> debugfs: make dirsearch cmd support inline data
>> debugfs: make bma cmd support inline data
>> e2fsck: add three problem descriptions in pass1
>> e2fsck: check incorrect inline data flag
>> e2fsck: make pass1 support inline data
>> libext2fs: add read/write inline data functions
>> e2fsck: check inline data in pass2
>>
>> debugfs/debugfs.c | 25 ++-
>> debugfs/dump.c | 38 +++-
>> debugfs/filefrag.c | 30 ++-
>> debugfs/htree.c | 6 +
>> debugfs/ls.c | 8 +-
>> debugfs/lsdel.c | 19 +-
>> debugfs/ncheck.c | 8 +-
>> e2fsck/pass1.c | 70 ++++-
>> e2fsck/pass1b.c | 5 +-
>> e2fsck/pass2.c | 50 +++-
>> e2fsck/problem.c | 15 +
>> e2fsck/problem.h | 9 +
>> lib/e2p/feature.c | 2 +
>> lib/ext2fs/Makefile.in | 5 +
>> lib/ext2fs/Makefile.pq | 1 +
>> lib/ext2fs/bmap.c | 16 +
>> lib/ext2fs/dblist_dir.c | 8 +-
>> lib/ext2fs/dirblock.c | 62 ++++
>> lib/ext2fs/expanddir.c | 8 +-
>> lib/ext2fs/ext2_ext_attr.h | 4 +
>> lib/ext2fs/ext2_fs.h | 9 +
>> lib/ext2fs/ext2fs.h | 69 ++++-
>> lib/ext2fs/ext_attr.c | 26 ++
>> lib/ext2fs/get_pathname.c | 7 +-
>> lib/ext2fs/inline_data.c | 715 ++++++++++++++++++++++++++++++++++++++++++++
>> lib/ext2fs/link.c | 9 +-
>> lib/ext2fs/lookup.c | 6 +-
>> lib/ext2fs/mkdir.c | 4 +
>> lib/ext2fs/unlink.c | 9 +-
>> misc/mke2fs.8.in | 3 +
>> misc/mke2fs.c | 10 +-
>> 31 files changed, 1197 insertions(+), 59 deletions(-)
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
>> the body of a message to [email protected]
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
>
> Cheers, Andreas
>
>
>
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html