* [PATCH 01/21 v5] libext2fs: add INLINE_DATA into EXT2_LIB_SOFTSUPP_INCOMPAT
2012-09-22 4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
@ 2012-09-22 4:00 ` Zheng Liu
2012-09-22 4:00 ` [PATCH 02/21 v5] libext2fs: add function to check inline_data flag for an inode Zheng Liu
` (19 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22 4:00 UTC (permalink / raw)
To: linux-ext4; +Cc: tytso, Zheng Liu
From: Zheng Liu <wenqing.lz@taobao.com>
EXT4_FEATURE_INCOMPAT_INLINE_DATA flag is added into EXT2_LIB_SOFTSUPP_INCOMPAT
due to we still need to take a long time to test inline_data feature.
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
lib/ext2fs/ext2fs.h | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 9927875..1cd53f0 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -602,7 +602,7 @@ typedef struct ext2_icount *ext2_icount_t;
* These features are only allowed if EXT2_FLAG_SOFTSUPP_FEATURES is passed
* to ext2fs_openfs()
*/
-#define EXT2_LIB_SOFTSUPP_INCOMPAT (0)
+#define EXT2_LIB_SOFTSUPP_INCOMPAT (EXT4_FEATURE_INCOMPAT_INLINE_DATA)
#define EXT2_LIB_SOFTSUPP_RO_COMPAT (EXT4_FEATURE_RO_COMPAT_REPLICA)
--
1.7.4.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 02/21 v5] libext2fs: add function to check inline_data flag for an inode
2012-09-22 4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
2012-09-22 4:00 ` [PATCH 01/21 v5] libext2fs: add INLINE_DATA into EXT2_LIB_SOFTSUPP_INCOMPAT Zheng Liu
@ 2012-09-22 4:00 ` Zheng Liu
2012-09-22 4:00 ` [PATCH 03/21 v5] libext2fs: add functions to operate extend attribute Zheng Liu
` (18 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22 4:00 UTC (permalink / raw)
To: linux-ext4; +Cc: tytso, Zheng Liu
From: Zheng Liu <wenqing.lz@taobao.com>
A new file called `inline_data.c' is created, and a function called
`ext2fs_inode_has_inline_data' is defined to check whether an inode
has inline data or not.
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
lib/ext2fs/Makefile.in | 8 ++++++++
lib/ext2fs/Makefile.pq | 1 +
lib/ext2fs/ext2fs.h | 3 +++
lib/ext2fs/inline_data.c | 30 ++++++++++++++++++++++++++++++
4 files changed, 42 insertions(+), 0 deletions(-)
create mode 100644 lib/ext2fs/inline_data.c
diff --git a/lib/ext2fs/Makefile.in b/lib/ext2fs/Makefile.in
index 8930fdb..7201fa2 100644
--- a/lib/ext2fs/Makefile.in
+++ b/lib/ext2fs/Makefile.in
@@ -59,6 +59,7 @@ OBJS= $(DEBUGFS_LIB_OBJS) $(RESIZE_LIB_OBJS) $(E2IMAGE_LIB_OBJS) \
ind_block.o \
initialize.o \
inline.o \
+ inline_data.o \
inode.o \
io_manager.o \
ismounted.o \
@@ -132,6 +133,7 @@ SRCS= ext2_err.c \
$(srcdir)/ind_block.c \
$(srcdir)/initialize.c \
$(srcdir)/inline.c \
+ $(srcdir)/inline_data.c \
$(srcdir)/inode.c \
$(srcdir)/inode_io.c \
$(srcdir)/imager.c \
@@ -743,6 +745,12 @@ inline.o: $(srcdir)/inline.c $(top_builddir)/lib/config.h \
$(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
$(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
$(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
+inline_data.o: $(srcdir)/inline_data.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/ext2_fs.h \
+ $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
+ $(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
inode.o: $(srcdir)/inode.c $(top_builddir)/lib/config.h \
$(top_builddir)/lib/dirpaths.h $(srcdir)/ext2_fs.h \
$(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fsP.h \
diff --git a/lib/ext2fs/Makefile.pq b/lib/ext2fs/Makefile.pq
index 2f7b654..89082a7 100644
--- a/lib/ext2fs/Makefile.pq
+++ b/lib/ext2fs/Makefile.pq
@@ -27,6 +27,7 @@ OBJS= alloc.obj \
icount.obj \
initialize.obj \
inline.obj \
+ inline_data.obj \
inode.obj \
ismounted.obj \
link.obj \
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 1cd53f0..8714f58 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -1320,6 +1320,9 @@ extern errcode_t ext2fs_icount_store(ext2_icount_t icount, ext2_ino_t ino,
extern ext2_ino_t ext2fs_get_icount_size(ext2_icount_t icount);
errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *);
+/* inline_data.c */
+extern int ext2fs_inode_has_inline_data(ext2_filsys fs, ext2_ino_t ino);
+
/* inode.c */
extern errcode_t ext2fs_flush_icache(ext2_filsys fs);
extern errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan,
diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c
new file mode 100644
index 0000000..0341ee3
--- /dev/null
+++ b/lib/ext2fs/inline_data.c
@@ -0,0 +1,30 @@
+/*
+ * inline_data.c --- data in inode
+ *
+ * Copyright (C) 2012 Zheng Liu <wenqing.lz@taobao.com>
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU library
+ * General Public License, version 2.
+ * %End-Header%
+ */
+
+#include "config.h"
+#include <stdio.h>
+
+#include "ext2_fs.h"
+
+#include "ext2fs.h"
+#include "ext2fsP.h"
+
+int ext2fs_inode_has_inline_data(ext2_filsys fs, ext2_ino_t ino)
+{
+ struct ext2_inode inode;
+ errcode_t retval;
+
+ retval = ext2fs_read_inode(fs, ino, &inode);
+ if (retval)
+ return 0;
+
+ return (inode.i_flags & EXT4_INLINE_DATA_FL);
+}
--
1.7.4.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 03/21 v5] libext2fs: add functions to operate extend attribute
2012-09-22 4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
2012-09-22 4:00 ` [PATCH 01/21 v5] libext2fs: add INLINE_DATA into EXT2_LIB_SOFTSUPP_INCOMPAT Zheng Liu
2012-09-22 4:00 ` [PATCH 02/21 v5] libext2fs: add function to check inline_data flag for an inode Zheng Liu
@ 2012-09-22 4:00 ` Zheng Liu
2012-09-22 4:00 ` [PATCH 04/21 v5] libext2fs: handle inline data in dir iterator function Zheng Liu
` (17 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22 4:00 UTC (permalink / raw)
To: linux-ext4; +Cc: tytso, Zheng Liu
From: Zheng Liu <wenqing.lz@taobao.com>
We need to define some functions to operate extend attribte due to inline data
needs to change it.
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
lib/ext2fs/ext2_ext_attr.h | 30 ++++++++
lib/ext2fs/ext2fs.h | 13 ++++
lib/ext2fs/ext_attr.c | 169 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 212 insertions(+), 0 deletions(-)
diff --git a/lib/ext2fs/ext2_ext_attr.h b/lib/ext2fs/ext2_ext_attr.h
index bbb0aaa..de60097 100644
--- a/lib/ext2fs/ext2_ext_attr.h
+++ b/lib/ext2fs/ext2_ext_attr.h
@@ -15,6 +15,10 @@
/* Maximum number of references to one attribute block */
#define EXT2_EXT_ATTR_REFCOUNT_MAX 1024
+/* Name indexes */
+#define EXT4_EXT_ATTR_INDEX_SYSTEM 7
+#define EXT4_EXT_ATTR_SYSTEM_DATA "data"
+
struct ext2_ext_attr_header {
__u32 h_magic; /* magic number for identification */
__u32 h_refcount; /* reference count */
@@ -25,6 +29,10 @@ struct ext2_ext_attr_header {
__u32 h_reserved[3]; /* zero right now */
};
+struct ext2_ext_attr_ibody_header {
+ __u32 h_magic;
+};
+
struct ext2_ext_attr_entry {
__u8 e_name_len; /* length of name */
__u8 e_name_index; /* attribute name index */
@@ -57,6 +65,28 @@ struct ext2_ext_attr_entry {
#define EXT2_XATTR_SIZE(size) \
(((size) + EXT2_EXT_ATTR_ROUND) & ~EXT2_EXT_ATTR_ROUND)
+#define IHDR(inode) \
+ ((struct ext2_ext_attr_ibody_header *) \
+ ((void *)inode + \
+ EXT2_GOOD_OLD_INODE_SIZE + \
+ inode->i_extra_isize))
+#define IFIRST(hdr) ((struct ext2_ext_attr_entry *)((hdr)+1))
+
+struct ext2_ext_attr_info {
+ int name_index;
+ const char *name;
+ const void *value;
+ size_t value_len;
+};
+
+struct ext2_ext_attr_search {
+ struct ext2_ext_attr_entry *first;
+ void *base;
+ void *end;
+ struct ext2_ext_attr_entry *here;
+ int not_found;
+};
+
#ifdef __KERNEL__
# ifdef CONFIG_EXT2_FS_EXT_ATTR
extern int ext2_get_ext_attr(struct inode *, const char *, char *, size_t, int);
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 8714f58..b076c3c 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -1132,6 +1132,19 @@ extern errcode_t ext2fs_adjust_ea_refcount3(ext2_filsys fs, blk64_t blk,
char *block_buf,
int adjust, __u32 *newcount,
ext2_ino_t inum);
+extern errcode_t ext2fs_ibody_find_ext_attr(ext2_filsys fs,
+ struct ext2_inode_large *inode,
+ struct ext2_ext_attr_info *i,
+ struct ext2_ext_attr_search *s);
+extern errcode_t ext2fs_find_entry_ext_attr(struct ext2_ext_attr_entry **pentry,
+ int name_index, const char *name,
+ size_t size, int sorted);
+extern errcode_t ext2fs_set_entry_ext_attr(struct ext2_ext_attr_info *i,
+ struct ext2_ext_attr_search *s);
+extern int ext2fs_ibody_get_ext_attr(ext2_filsys fs,
+ struct ext2_inode_large *inode,
+ int name_index, const char *name,
+ void *buffer, size_t buf_len);
/* extent.c */
extern errcode_t ext2fs_extent_header_verify(void *ptr, int size);
diff --git a/lib/ext2fs/ext_attr.c b/lib/ext2fs/ext_attr.c
index 9649a14..c663f31 100644
--- a/lib/ext2fs/ext_attr.c
+++ b/lib/ext2fs/ext_attr.c
@@ -186,3 +186,172 @@ errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
return ext2fs_adjust_ea_refcount2(fs, blk, block_buf, adjust,
newcount);
}
+
+errcode_t ext2fs_find_entry_ext_attr(struct ext2_ext_attr_entry **pentry,
+ int name_index, const char *name,
+ size_t size, int sorted)
+{
+ struct ext2_ext_attr_entry *entry;
+ size_t name_len;
+ int cmp;
+
+ name_len = strlen(name);
+ for (entry = *pentry; !EXT2_EXT_IS_LAST_ENTRY(entry);
+ entry = EXT2_EXT_ATTR_NEXT(entry)) {
+ cmp = name_index - entry->e_name_index;
+ if (!cmp)
+ cmp = name_len - entry->e_name_len;
+ if (!cmp)
+ cmp = memcmp(name, EXT2_EXT_ATTR_NAME(entry),
+ name_len);
+ if (!cmp)
+ break;
+ }
+ *pentry = entry;
+
+ return cmp;
+}
+
+errcode_t ext2fs_ibody_find_ext_attr(ext2_filsys fs,
+ struct ext2_inode_large *inode,
+ struct ext2_ext_attr_info *i,
+ struct ext2_ext_attr_search *s)
+{
+ struct ext2_ext_attr_ibody_header *header;
+ int error;
+
+ if (inode->i_extra_isize == 0)
+ return 0;
+ header = IHDR(inode);
+ s->base = s->first = IFIRST(header);
+ s->here = s->first;
+ s->end = (void *)inode + EXT2_INODE_SIZE(fs->super);
+ error = ext2fs_find_entry_ext_attr(&s->here, i->name_index,
+ i->name, s->end -
+ (void *)s->base, 0);
+ s->not_found = error;
+ return 0;
+}
+
+extern int ext2fs_ibody_get_ext_attr(ext2_filsys fs,
+ struct ext2_inode_large *inode,
+ int name_index, const char *name,
+ void *buffer, size_t buf_len)
+{
+ struct ext2_ext_attr_ibody_header *header;
+ struct ext2_ext_attr_entry *entry;
+ size_t size;
+ void *end;
+ int error;
+
+ header = IHDR(inode);
+ entry = IFIRST(header);
+ end = (void *)inode + EXT2_INODE_SIZE(fs->super);
+ error = ext2fs_find_entry_ext_attr(&entry, name_index, name,
+ end - (void *)entry, 0);
+ if (error)
+ return error;
+ size = ext2fs_le32_to_cpu(entry->e_value_size);
+ if (buffer) {
+ if (size > buf_len)
+ return error;
+ memcpy(buffer, (void *)IFIRST(header) +
+ ext2fs_le16_to_cpu(entry->e_value_offs), size);
+ }
+ error = size;
+
+ return error;
+}
+
+errcode_t ext2fs_set_entry_ext_attr(struct ext2_ext_attr_info *i,
+ struct ext2_ext_attr_search *s)
+{
+ struct ext2_ext_attr_entry *last;
+ size_t free, min_offs = s->end - s->base, name_len = strlen(i->name);
+
+ last = s->first;
+ for (; !EXT2_EXT_IS_LAST_ENTRY(last); last = EXT2_EXT_ATTR_NEXT(last)) {
+ if (!last->e_value_block && last->e_value_size) {
+ size_t offs = ext2fs_le16_to_cpu(last->e_value_offs);
+ if (offs < min_offs)
+ min_offs = offs;
+ }
+ }
+ free = min_offs - ((void *)last - s->base) - sizeof(__u32);
+ if (!s->not_found) {
+ if (!s->here->e_value_block & s->here->e_value_size) {
+ size_t size = ext2fs_le32_to_cpu(s->here->e_value_size);
+ free += EXT2_EXT_ATTR_SIZE(size);
+ }
+ free += EXT2_EXT_ATTR_LEN(name_len);
+ }
+ if (i->value) {
+ if (free < EXT2_EXT_ATTR_SIZE(i->value_len) ||
+ free < EXT2_EXT_ATTR_LEN(name_len) +
+ EXT2_EXT_ATTR_SIZE(i->value_len))
+ return -1;
+ }
+ if (i->value && s->not_found) {
+ size_t size = EXT2_EXT_ATTR_LEN(name_len);
+ size_t rest = (void *)last - (void *)s->here + sizeof(__u32);
+ memmove((void *)s->here + size, s->here, rest);
+ memset(s->here, 0, size);
+ s->here->e_name_index = i->name_index;
+ s->here->e_name_len = name_len;
+ memcpy(EXT2_EXT_ATTR_NAME(s->here),
+ EXT2_EXT_ATTR_NAME(i), name_len);
+ } else {
+ if (!s->here->e_value_block && s->here->e_value_size) {
+ void *first_val = s->base + min_offs;
+ size_t offs = ext2fs_le16_to_cpu(s->here->e_value_offs);
+ void *val = s->base + offs;
+ size_t size = EXT2_EXT_ATTR_SIZE(
+ ext2fs_le32_to_cpu(s->here->e_value_size));
+
+ if (i->value && size == EXT2_EXT_ATTR_SIZE(i->value_len)) {
+ s->here->e_value_size =
+ ext2fs_cpu_to_le32(i->value_len);
+ memset(val + size - EXT2_EXT_ATTR_PAD, 0,
+ EXT2_EXT_ATTR_PAD);
+ memcpy(val, i->value, i->value_len);
+ return 0;
+ }
+
+ memmove(first_val + size, first_val, val - first_val);
+ memset(first_val, 0, size);
+ s->here->e_value_size = 0;
+ s->here->e_value_offs = 0;
+ min_offs += size;
+
+ last = s->first;
+ while (!EXT2_EXT_IS_LAST_ENTRY(last)) {
+ size_t o = ext2fs_le16_to_cpu(last->e_value_offs);
+ if (!last->e_value_block &&
+ last->e_value_size && o < offs)
+ last->e_value_offs =
+ ext2fs_cpu_to_le16(o + size);
+ last = EXT2_EXT_ATTR_NEXT(last);
+ }
+ }
+ if (!i->value) {
+ size_t size = EXT2_EXT_ATTR_LEN(name_len);
+ last = (struct ext2_ext_attr_entry *)last - size;
+ memmove(s->here, (void *)s->here + size,
+ (void *)last - (void *)s->here + sizeof(__u32));
+ memset(last, 0, size);
+ }
+ }
+
+ if (i->value) {
+ s->here->e_value_size = ext2fs_cpu_to_le32(i->value_len);
+ if (i->value_len) {
+ size_t size = EXT2_EXT_ATTR_SIZE(i->value_len);
+ void *val = s->base + min_offs - size;
+ s->here->e_value_offs = ext2fs_cpu_to_le16(min_offs - size);
+ memset(val + size - EXT2_EXT_ATTR_PAD, 0,
+ EXT2_EXT_ATTR_PAD);
+ memcpy(val, i->value, i->value_len);
+ }
+ }
+ return 0;
+}
--
1.7.4.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 04/21 v5] libext2fs: handle inline data in dir iterator function
2012-09-22 4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
` (2 preceding siblings ...)
2012-09-22 4:00 ` [PATCH 03/21 v5] libext2fs: add functions to operate extend attribute Zheng Liu
@ 2012-09-22 4:00 ` Zheng Liu
2012-09-22 4:00 ` [PATCH 05/21 v5] libext2fs: handle inline_data in block " Zheng Liu
` (16 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22 4:00 UTC (permalink / raw)
To: linux-ext4; +Cc: tytso, Zheng Liu
From: Zheng Liu <wenqing.lz@taobao.com>
Inline_data is handled in dir iterator because a lot of commands use this
function to traverse directory entries debugfs. We need to handle inline_data
individually because inline_data is saved in two places. One is in i_block, and
another is in ibody extend attribute.
After adding these functions, some commands in debugfs can support inline_data
feature as below:
- ncheck
- chroot
- cd
- ls
- pwd
- link*
- unlink
* If inline_data doesn't expand to ibody extend attribute, link command will
allocate a new block for this inode instead of using extend attribute when we
exhaust all space of i_block.
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
lib/ext2fs/dir_iterate.c | 101 +++++++++++++++++++++++++++++++++-
lib/ext2fs/ext2_err.et.in | 6 ++
lib/ext2fs/ext2_fs.h | 7 +++
lib/ext2fs/ext2fs.h | 11 ++++
lib/ext2fs/ext2fsP.h | 7 +++
lib/ext2fs/inline_data.c | 132 +++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 262 insertions(+), 2 deletions(-)
diff --git a/lib/ext2fs/dir_iterate.c b/lib/ext2fs/dir_iterate.c
index c24015c..7b82fb1 100644
--- a/lib/ext2fs/dir_iterate.c
+++ b/lib/ext2fs/dir_iterate.c
@@ -123,8 +123,14 @@ errcode_t ext2fs_dir_iterate2(ext2_filsys fs,
ctx.func = func;
ctx.priv_data = priv_data;
ctx.errcode = 0;
- retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_READ_ONLY, 0,
- ext2fs_process_dir_block, &ctx);
+ if (ext2fs_inode_has_inline_data(fs, dir))
+ retval = ext2fs_inline_data_iterate(fs, dir,
+ BLOCK_FLAG_READ_ONLY, 0,
+ ext2fs_process_dir_inline_data,
+ &ctx);
+ else
+ retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_READ_ONLY, 0,
+ ext2fs_process_dir_block, &ctx);
if (!block_buf)
ext2fs_free_mem(&ctx.buf);
if (retval)
@@ -275,3 +281,94 @@ next:
return 0;
}
+int ext2fs_process_dir_inline_data(ext2_filsys fs,
+ void *buf,
+ int buf_len,
+ e2_blkcnt_t blockcnt,
+ struct ext2_inode_large *inode,
+ void *priv_data)
+{
+ struct dir_context *ctx = (struct dir_context *) priv_data;
+ unsigned int offset = 0;
+ unsigned int next_real_entry = 0;
+ int ret = 0;
+ int changed = 0;
+ int do_abort = 0;
+ unsigned int rec_len, size;
+ int entry;
+ struct ext2_dir_entry *dirent;
+
+ if (blockcnt < 0)
+ return 0;
+
+ entry = blockcnt ? DIRENT_OTHER_FILE : DIRENT_DOT_FILE;
+
+ while (offset < buf_len) {
+ dirent = (struct ext2_dir_entry *) (buf + offset);
+ if (ext2fs_get_rec_len(fs, dirent, &rec_len))
+ return BLOCK_ABORT;
+ if (((offset + rec_len) > buf_len) ||
+ (rec_len < 8) ||
+ ((rec_len % 4) != 0) ||
+ ((((unsigned) dirent->name_len & 0xFF)+8) > rec_len)) {
+ ctx->errcode = EXT2_ET_DIR_CORRUPTED;
+ return BLOCK_ABORT;
+ }
+ if (!dirent->inode &&
+ !(ctx->flags & DIRENT_FLAG_INCLUDE_EMPTY))
+ goto next;
+
+ ret = (ctx->func)(ctx->dir,
+ (next_real_entry > offset) ?
+ DIRENT_DELETED_FILE : entry,
+ dirent, offset,
+ buf_len, buf,
+ ctx->priv_data);
+ if (entry < DIRENT_OTHER_FILE)
+ entry++;
+
+ if (ret & DIRENT_CHANGED) {
+ dirent->rec_len = rec_len;
+ changed++;
+ }
+ if (ret & DIRENT_ABORT) {
+ do_abort++;
+ break;
+ }
+next:
+ if (next_real_entry == offset)
+ next_real_entry += rec_len;
+
+ if (ctx->flags & DIRENT_FLAG_INCLUDE_REMOVED) {
+ size = ((dirent->name_len & 0xFF) + 11) & ~3;
+
+ if (rec_len != size) {
+ unsigned int final_offset;
+
+ final_offset = offset + rec_len;
+ offset += size;
+ while (offset < final_offset &&
+ !ext2fs_validate_entry(fs, buf,
+ offset,
+ final_offset))
+ offset += 4;
+ continue;
+ }
+ }
+ offset += rec_len;
+ }
+
+ if (changed) {
+ /* change parent ino */
+ if (buf_len == EXT2_DIR_REC_LEN(2))
+ ((struct ext2_dir_entry *)inode->i_block)->inode =
+ dirent->inode;
+ ctx->errcode = ext2fs_write_inode_full(fs, ctx->dir, (void *)inode,
+ EXT2_INODE_SIZE(fs->super));
+ if (ctx->errcode)
+ return BLOCK_ABORT;
+ }
+ if (do_abort)
+ return BLOCK_ABORT;
+ return 0;
+}
diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in
index c99a167..537d840 100644
--- a/lib/ext2fs/ext2_err.et.in
+++ b/lib/ext2fs/ext2_err.et.in
@@ -68,6 +68,9 @@ ec EXT2_ET_MAGIC_EXTENT_HANDLE,
ec EXT2_ET_BAD_MAGIC,
"Bad magic number in super-block"
+ec EXT2_ET_BAD_EXT_ATTR_MAGIC,
+ "Bad magic number in extend attribute"
+
ec EXT2_ET_REV_TOO_HIGH,
"Filesystem revision too high"
@@ -473,4 +476,7 @@ ec EXT2_ET_UNKNOWN_CSUM,
ec EXT2_ET_MMP_CSUM_INVALID,
"MMP block checksum does not match MMP block"
+ec EXT2_ET_BAD_EXTRA_SIZE,
+ "Bad inode extra isizevalue"
+
end
diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
index 5b6e315..4201c71 100644
--- a/lib/ext2fs/ext2_fs.h
+++ b/lib/ext2fs/ext2_fs.h
@@ -905,4 +905,11 @@ struct mmp_struct {
*/
#define EXT4_MMP_MIN_CHECK_INTERVAL 5
+struct inline_data {
+ __u16 inline_off;
+ __u16 inline_size;
+};
+
+#define EXT4_MIN_INLINE_DATA_SIZE ((sizeof(__u32) * EXT2_N_BLOCKS))
+
#endif /* _LINUX_EXT2_FS_H */
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index b076c3c..b0efda6 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -1335,6 +1335,17 @@ errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *);
/* inline_data.c */
extern int ext2fs_inode_has_inline_data(ext2_filsys fs, ext2_ino_t ino);
+extern int ext2fs_inline_data_iterate(ext2_filsys fs,
+ ext2_ino_t ino,
+ int flags,
+ char *block_buf,
+ int (*func)(ext2_filsys fs,
+ void *buf,
+ int buf_len,
+ e2_blkcnt_t blockcnt,
+ struct ext2_inode_large *inode,
+ void *priv_data),
+ void *priv_data);
/* inode.c */
extern errcode_t ext2fs_flush_icache(ext2_filsys fs);
diff --git a/lib/ext2fs/ext2fsP.h b/lib/ext2fs/ext2fsP.h
index 3de9278..742ddf6 100644
--- a/lib/ext2fs/ext2fsP.h
+++ b/lib/ext2fs/ext2fsP.h
@@ -87,6 +87,13 @@ extern int ext2fs_process_dir_block(ext2_filsys fs,
int ref_offset,
void *priv_data);
+extern int ext2fs_process_dir_inline_data(ext2_filsys fs,
+ void *buf,
+ int buf_len,
+ e2_blkcnt_t blockcnt,
+ struct ext2_inode_large *inode,
+ void *priv_data);
+
/* Generic numeric progress meter */
struct ext2fs_numeric_progress_struct {
diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c
index 0341ee3..2be1a61 100644
--- a/lib/ext2fs/inline_data.c
+++ b/lib/ext2fs/inline_data.c
@@ -13,10 +13,60 @@
#include <stdio.h>
#include "ext2_fs.h"
+#include "ext2_ext_attr.h"
#include "ext2fs.h"
#include "ext2fsP.h"
+#define EXT4_INLINE_DATA_DOTDOT_SIZE (4)
+
+static int ext2fs_iget_extra_inode(ext2_filsys fs, struct ext2_inode_large *inode,
+ struct inline_data *data);
+static void *ext2fs_get_inline_xattr_pos(struct ext2_inode_large *inode,
+ struct inline_data *data);
+
+static int ext2fs_iget_extra_inode(ext2_filsys fs, struct ext2_inode_large *inode,
+ struct inline_data *data)
+{
+ struct ext2_ext_attr_ibody_header *header;
+ struct ext2_ext_attr_search s = {
+ .not_found = -1,
+ };
+ struct ext2_ext_attr_info i = {
+ .name_index = EXT4_EXT_ATTR_INDEX_SYSTEM,
+ .name = EXT4_EXT_ATTR_SYSTEM_DATA,
+ };
+
+ data->inline_off = 0;
+ if (inode->i_extra_isize > (EXT2_INODE_SIZE(fs->super) -
+ EXT2_GOOD_OLD_INODE_SIZE))
+ return EXT2_ET_BAD_EXTRA_SIZE;
+
+ (void)ext2fs_ibody_find_ext_attr(fs, inode, &i, &s);
+
+ if (!s.not_found) {
+ data->inline_off = (__u16)((void *)s.here - (void *)inode);
+ data->inline_size = EXT4_MIN_INLINE_DATA_SIZE +
+ s.here->e_value_size;
+ return 0;
+ }
+
+ return EXT2_ET_BAD_EXT_ATTR_MAGIC;
+}
+
+static void *ext2fs_get_inline_xattr_pos(struct ext2_inode_large *inode,
+ struct inline_data *data)
+{
+ struct ext2_ext_attr_entry *entry;
+ struct ext2_ext_attr_ibody_header *header;
+
+ header = IHDR(inode);
+ entry = (struct ext2_ext_attr_entry *)
+ ((void *)inode + data->inline_off);
+
+ return (void *)IFIRST(header) + entry->e_value_offs;
+}
+
int ext2fs_inode_has_inline_data(ext2_filsys fs, ext2_ino_t ino)
{
struct ext2_inode inode;
@@ -28,3 +78,85 @@ int ext2fs_inode_has_inline_data(ext2_filsys fs, ext2_ino_t ino)
return (inode.i_flags & EXT4_INLINE_DATA_FL);
}
+
+int ext2fs_inline_data_iterate(ext2_filsys fs,
+ ext2_ino_t ino,
+ int flags,
+ char *block_buf,
+ int (*func)(ext2_filsys fs,
+ void *buf,
+ int buf_len,
+ e2_blkcnt_t blockcnt,
+ struct ext2_inode_large *inode,
+ void *priv_data),
+ void *priv_data)
+{
+ struct dir_context *ctx;
+ struct ext2_inode_large *inode;
+ struct ext2_dir_entry dirent;
+ struct inline_data data;
+ errcode_t retval = 0;
+ e2_blkcnt_t blockcnt = 0;
+ void *inline_start;
+ int inline_size;
+
+ ctx = (struct dir_context *)priv_data;
+
+ retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
+ if (retval)
+ return retval;
+
+ retval = ext2fs_read_inode_full(fs, ino, (void *)inode,
+ EXT2_INODE_SIZE(fs->super));
+ if (retval)
+ goto out;
+
+ if (inode->i_size == 0)
+ goto out;
+
+ /* we first check '.' and '..' dir */
+ dirent.inode = ino;
+ dirent.name_len = 1;
+ ext2fs_set_rec_len(fs, EXT2_DIR_REC_LEN(2), &dirent);
+ dirent.name[0] = '.';
+ dirent.name[1] = '\0';
+ retval |= (*func)(fs, (void *)&dirent, dirent.rec_len, blockcnt++,
+ inode, priv_data);
+ if (retval & BLOCK_ABORT)
+ goto out;
+
+ dirent.inode = (__u32)*inode->i_block;
+ dirent.name_len = 2;
+ ext2fs_set_rec_len(fs, EXT2_DIR_REC_LEN(3), &dirent);
+ dirent.name[0] = '.';
+ dirent.name[1] = '.';
+ dirent.name[2] = '\0';
+ retval |= (*func)(fs, (void *)&dirent, dirent.rec_len, blockcnt++,
+ inode, priv_data);
+ if (retval & BLOCK_ABORT)
+ goto out;
+
+ inline_start = (void *)inode->i_block + EXT4_INLINE_DATA_DOTDOT_SIZE;
+ inline_size = EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DATA_DOTDOT_SIZE;
+ retval |= (*func)(fs, inline_start, inline_size, blockcnt++,
+ inode, priv_data);
+ if (retval & BLOCK_ABORT)
+ goto out;
+
+ retval = ext2fs_iget_extra_inode(fs, inode, &data);
+ if (retval)
+ goto out;
+ if (data.inline_size > EXT4_MIN_INLINE_DATA_SIZE) {
+ inline_start = ext2fs_get_inline_xattr_pos(inode, &data);
+ inline_size = data.inline_size - EXT4_MIN_INLINE_DATA_SIZE;
+ retval |= (*func)(fs, inline_start, inline_size, blockcnt++,
+ inode, priv_data);
+ if (retval & BLOCK_ABORT)
+ goto out;
+ }
+
+out:
+ retval |= BLOCK_ERROR;
+ ext2fs_free_mem(&inode);
+ return retval & BLOCK_ERROR ? ctx->errcode : 0;
+}
--
1.7.4.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 05/21 v5] libext2fs: handle inline_data in block iterator function
2012-09-22 4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
` (3 preceding siblings ...)
2012-09-22 4:00 ` [PATCH 04/21 v5] libext2fs: handle inline data in dir iterator function Zheng Liu
@ 2012-09-22 4:00 ` Zheng Liu
2012-09-22 4:00 ` [PATCH 06/21 v5] debugfs: make stat command support inline data Zheng Liu
` (15 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22 4:00 UTC (permalink / raw)
To: linux-ext4; +Cc: tytso, Zheng Liu
From: Zheng Liu <wenqing.lz@taobao.com>
We needn't traverse blocks for an inode which has inline data because no block
belongs to it. After appling this patch, the following commands in debugfs can
handle inline_data feature:
- icheck
- blocks
- filefrag
In some places, block iterator functions are used to traverse blocks of
directory. In this case, we need to check whether inode has inline_data flag or
not, and handle it manually.
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
lib/ext2fs/block.c | 7 +++++++
1 files changed, 7 insertions(+), 0 deletions(-)
diff --git a/lib/ext2fs/block.c b/lib/ext2fs/block.c
index 68dcb03..4abcedf 100644
--- a/lib/ext2fs/block.c
+++ b/lib/ext2fs/block.c
@@ -345,6 +345,13 @@ errcode_t ext2fs_block_iterate3(ext2_filsys fs,
return ctx.errcode;
/*
+ * If an inode has inline data, we needn't traverse its blocks
+ * because no block belong to this inode.
+ */
+ if (inode.i_flags & EXT4_INLINE_DATA_FL)
+ return ctx.errcode;
+
+ /*
* Check to see if we need to limit large files
*/
if (flags & BLOCK_FLAG_NO_LARGE) {
--
1.7.4.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 06/21 v5] debugfs: make stat command support inline data
2012-09-22 4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
` (4 preceding siblings ...)
2012-09-22 4:00 ` [PATCH 05/21 v5] libext2fs: handle inline_data in block " Zheng Liu
@ 2012-09-22 4:00 ` Zheng Liu
2012-09-22 4:00 ` [PATCH 07/21 v5] libext2fs: handle inline data when expanding directory Zheng Liu
` (14 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22 4:00 UTC (permalink / raw)
To: linux-ext4; +Cc: tytso, Zheng Liu
From: Zheng Liu <wenqing.lz@taobao.com>
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
debugfs/debugfs.c | 13 ++++++++++++-
lib/ext2fs/ext2fs.h | 1 +
lib/ext2fs/inline_data.c | 30 ++++++++++++++++++++++++++++++
3 files changed, 43 insertions(+), 1 deletions(-)
diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c
index aec61ab..2099478 100644
--- a/debugfs/debugfs.c
+++ b/debugfs/debugfs.c
@@ -706,6 +706,15 @@ static void dump_extents(FILE *f, const char *prefix, ext2_ino_t ino,
fprintf(f, "\n");
}
+void dump_inline_data(FILE *out, const char *prefix, ext2_ino_t inode_num)
+{
+ int size;
+
+ fprintf(out, "%sINLINE DATA:\n%s", prefix, prefix);
+ size = ext2fs_get_inline_data_size(current_fs, inode_num);
+ fprintf(out, " The size of inline data: %d", size);
+}
+
void internal_dump_inode(FILE *out, const char *prefix,
ext2_ino_t inode_num, struct ext2_inode *inode,
int do_dump_blocks)
@@ -836,7 +845,9 @@ void internal_dump_inode(FILE *out, const char *prefix,
fprintf(out, "%sDevice major/minor number: %02d:%02d (hex %02x:%02x)\n",
devnote, major, minor, major, minor);
} else if (do_dump_blocks) {
- if (inode->i_flags & EXT4_EXTENTS_FL)
+ if (inode->i_flags & EXT4_INLINE_DATA_FL)
+ dump_inline_data(out, prefix, inode_num);
+ else if (inode->i_flags & EXT4_EXTENTS_FL)
dump_extents(out, prefix, inode_num,
DUMP_LEAF_EXTENTS|DUMP_NODE_EXTENTS, 0, 0);
else
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 51dbad4..25a8e98 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -1331,6 +1331,7 @@ errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *);
/* inline_data.c */
extern int ext2fs_inode_has_inline_data(ext2_filsys fs, ext2_ino_t ino);
+extern int ext2fs_get_inline_data_size(ext2_filsys fs, ext2_ino_t ino);
extern int ext2fs_inline_data_iterate(ext2_filsys fs,
ext2_ino_t ino,
int flags,
diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c
index 0652079..5570aa0 100644
--- a/lib/ext2fs/inline_data.c
+++ b/lib/ext2fs/inline_data.c
@@ -79,6 +79,36 @@ int ext2fs_inode_has_inline_data(ext2_filsys fs, ext2_ino_t ino)
return (inode.i_flags & EXT4_INLINE_DATA_FL);
}
+int ext2fs_get_inline_data_size(ext2_filsys fs, ext2_ino_t ino)
+{
+ struct inline_data data;
+ struct ext2_inode_large *inode;
+ errcode_t retval = 0;
+ int inline_size = 0;
+
+ if (!ext2fs_inode_has_inline_data(fs, ino))
+ return 0;
+
+ retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
+ if (retval)
+ return 0;
+
+ retval = ext2fs_read_inode_full(fs, ino, (void *)inode,
+ EXT2_INODE_SIZE(fs->super));
+ if (retval)
+ goto out;
+
+ retval = ext2fs_iget_extra_inode(fs, inode, &data);
+ if (retval)
+ goto out;
+
+ inline_size = data.inline_size;
+
+out:
+ ext2fs_free_mem(&inode);
+ return inline_size;
+}
+
int ext2fs_inline_data_iterate(ext2_filsys fs,
ext2_ino_t ino,
int flags,
--
1.7.4.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 07/21 v5] libext2fs: handle inline data when expanding directory
2012-09-22 4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
` (5 preceding siblings ...)
2012-09-22 4:00 ` [PATCH 06/21 v5] debugfs: make stat command support inline data Zheng Liu
@ 2012-09-22 4:00 ` Zheng Liu
2012-09-22 4:00 ` [PATCH 08/21 v5] debugfs: make lsdel command support inline data Zheng Liu
` (13 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22 4:00 UTC (permalink / raw)
To: linux-ext4; +Cc: tytso, Zheng Liu
From: Zheng Liu <wenqing.lz@taobao.com>
When inline space is filled up, we need to allocate a new block for this inode.
So a new function called `ext2fs_convert_inline_data' is define to handle it.
`expand_dir_struct' is exported to libext2fs because we need to change its
status. After adding it, the following commands in debugfs can handle
inline_data feature:
- mkdir
- expand_dir
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
lib/ext2fs/expanddir.c | 18 ++-
lib/ext2fs/ext2fs.h | 4 +
lib/ext2fs/ext2fsP.h | 11 ++
lib/ext2fs/ext_attr.c | 6 +-
lib/ext2fs/inline_data.c | 337 ++++++++++++++++++++++++++++++++++++++++++++++
lib/ext2fs/mkdir.c | 18 +++-
6 files changed, 383 insertions(+), 11 deletions(-)
diff --git a/lib/ext2fs/expanddir.c b/lib/ext2fs/expanddir.c
index 22558d6..b5e790b 100644
--- a/lib/ext2fs/expanddir.c
+++ b/lib/ext2fs/expanddir.c
@@ -19,13 +19,7 @@
#include "ext2_fs.h"
#include "ext2fs.h"
-struct expand_dir_struct {
- int done;
- int newblocks;
- blk64_t goal;
- errcode_t err;
- ext2_ino_t dir;
-};
+#include "ext2fsP.h"
static int expand_dir_proc(ext2_filsys fs,
blk64_t *blocknr,
@@ -114,6 +108,16 @@ errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir)
es.newblocks = 0;
es.dir = dir;
+ if (ext2fs_inode_has_inline_data(fs, dir)) {
+ retval = ext2fs_convert_inline_data(fs, dir, &es);
+ if (retval)
+ return retval;
+ if (!es.done)
+ return EXT2_ET_EXPAND_DIR_ERR;
+
+ return 0;
+ }
+
retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND,
0, expand_dir_proc, &es);
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 6c2393e..91da02c 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -1347,6 +1347,10 @@ extern int ext2fs_inline_data_iterate(ext2_filsys fs,
struct ext2_inode_large *inode,
void *priv_data),
void *priv_data);
+extern errcode_t ext2fs_inline_data_mkdir(ext2_filsys fs, ext2_ino_t parent,
+ ext2_ino_t ino, const char *name);
+extern errcode_t ext2fs_convert_inline_data(ext2_filsys fs, ext2_ino_t ino,
+ void *priv_data);
/* inode.c */
extern errcode_t ext2fs_flush_icache(ext2_filsys fs);
diff --git a/lib/ext2fs/ext2fsP.h b/lib/ext2fs/ext2fsP.h
index 742ddf6..503ebbf 100644
--- a/lib/ext2fs/ext2fsP.h
+++ b/lib/ext2fs/ext2fsP.h
@@ -62,6 +62,17 @@ struct dir_context {
};
/*
+ * For expanding directory
+ */
+struct expand_dir_struct {
+ int done;
+ int newblocks;
+ blk64_t goal;
+ errcode_t err;
+ ext2_ino_t dir;
+};
+
+/*
* Inode cache structure
*/
struct ext2_inode_cache {
diff --git a/lib/ext2fs/ext_attr.c b/lib/ext2fs/ext_attr.c
index c663f31..5a8d1ca 100644
--- a/lib/ext2fs/ext_attr.c
+++ b/lib/ext2fs/ext_attr.c
@@ -267,7 +267,8 @@ errcode_t ext2fs_set_entry_ext_attr(struct ext2_ext_attr_info *i,
struct ext2_ext_attr_search *s)
{
struct ext2_ext_attr_entry *last;
- size_t free, min_offs = s->end - s->base, name_len = strlen(i->name);
+ size_t free, min_offs = s->end - s->base;
+ size_t name_len = strlen(i->name);
last = s->first;
for (; !EXT2_EXT_IS_LAST_ENTRY(last); last = EXT2_EXT_ATTR_NEXT(last)) {
@@ -298,8 +299,7 @@ errcode_t ext2fs_set_entry_ext_attr(struct ext2_ext_attr_info *i,
memset(s->here, 0, size);
s->here->e_name_index = i->name_index;
s->here->e_name_len = name_len;
- memcpy(EXT2_EXT_ATTR_NAME(s->here),
- EXT2_EXT_ATTR_NAME(i), name_len);
+ memcpy(EXT2_EXT_ATTR_NAME(s->here), i->name, name_len);
} else {
if (!s->here->e_value_block && s->here->e_value_size) {
void *first_val = s->base + min_offs;
diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c
index 3bfe49d..85cfeac 100644
--- a/lib/ext2fs/inline_data.c
+++ b/lib/ext2fs/inline_data.c
@@ -24,6 +24,17 @@ static int ext2fs_iget_extra_inode(ext2_filsys fs, struct ext2_inode_large *inod
struct inline_data *data);
static void *ext2fs_get_inline_xattr_pos(struct ext2_inode_large *inode,
struct inline_data *data);
+static void ext2fs_inline_data_finish_convert(ext2_filsys fs, ext2_ino_t ino,
+ char *target, void *buf,
+ int inline_size);
+static void ext2fs_update_final_de(ext2_filsys fs, void *de_buf,
+ int old_size, int new_size);
+static errcode_t ext2fs_inline_data_destory_data(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode_large *inode,
+ struct inline_data *data);
+static errcode_t ext2fs_create_inline_data(ext2_filsys fs,
+ struct ext2_inode_large *inode,
+ int len);
static int ext2fs_iget_extra_inode(ext2_filsys fs, struct ext2_inode_large *inode,
struct inline_data *data)
@@ -67,6 +78,46 @@ static void *ext2fs_get_inline_xattr_pos(struct ext2_inode_large *inode,
return (void *)IFIRST(header) + entry->e_value_offs;
}
+static errcode_t ext2fs_inline_data_destory_data(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode_large *inode,
+ struct inline_data *data)
+{
+ struct ext2_ext_attr_ibody_header *header;
+ struct ext2_ext_attr_search s = {
+ .not_found = -1,
+ };
+ struct ext2_ext_attr_info i = {
+ .name_index = EXT4_EXT_ATTR_INDEX_SYSTEM,
+ .name = EXT4_EXT_ATTR_SYSTEM_DATA,
+ .value = "",
+ .value_len = 0,
+ };
+ errcode_t retval;
+
+ if (!data->inline_off)
+ return 0;
+
+ if (inode->i_extra_isize > (EXT2_INODE_SIZE(fs->super) -
+ EXT2_GOOD_OLD_INODE_SIZE))
+ return EXT2_ET_BAD_EXTRA_SIZE;
+
+ header = IHDR(inode);
+ if (header->h_magic != EXT2_EXT_ATTR_MAGIC)
+ return EXT2_ET_BAD_EXT_ATTR_MAGIC;
+
+ (void)ext2fs_ibody_find_ext_attr(fs, inode, &i, &s);
+
+ if (!s.not_found) {
+ retval = ext2fs_set_entry_ext_attr(&i, &s);
+ if (retval)
+ return retval;
+ }
+
+ memset((void *)inode->i_block, 0, EXT4_MIN_INLINE_DATA_SIZE);
+
+ return 0;
+}
+
int ext2fs_inode_has_inline_data(ext2_filsys fs, ext2_ino_t ino)
{
struct ext2_inode inode;
@@ -109,6 +160,83 @@ out:
return inline_size;
}
+static void ext2fs_update_final_de(ext2_filsys fs, void *de_buf,
+ int old_size, int new_size)
+{
+ struct ext2_dir_entry *de, *prev_de;
+ void *limit;
+ int de_len;
+
+ de = (struct ext2_dir_entry *)de_buf;
+ if (old_size) {
+ limit = de_buf + old_size;
+ do {
+ prev_de = de;
+ ext2fs_get_rec_len(fs, de, &de_len);
+ de_buf += de_len;
+ de = (struct ext2_dir_entry *)de_buf;
+ } while (de_buf < limit);
+
+ ext2fs_set_rec_len(fs, de_len + new_size - old_size,
+ prev_de);
+ } else {
+ de->inode = 0;
+ ext2fs_set_rec_len(fs, new_size, de);
+ }
+}
+
+static void ext2fs_inline_data_finish_convert(ext2_filsys fs, ext2_ino_t ino,
+ char *target, void *buf,
+ int inline_size)
+{
+ struct ext2_dir_entry *de;
+ struct ext2_dir_entry_tail *t;
+ int header_size = 0;
+ int csum_size = 0;
+ int filetype = 0;
+
+ if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+ csum_size = sizeof(struct ext2_dir_entry_tail);
+
+ /* First create '.' and '..' */
+ if (fs->super->s_feature_incompat &
+ EXT2_FEATURE_INCOMPAT_FILETYPE)
+ filetype = EXT2_FT_DIR << 8;
+
+ de = (struct ext2_dir_entry *)target;
+ de->inode = ino;
+ de->name_len = 1 | filetype;
+ de->name[0] = '.';
+ de->name[1] = '\0';
+ de->rec_len = EXT2_DIR_REC_LEN(1);
+
+ de = (struct ext2_dir_entry *)(target + de->rec_len);
+ de->rec_len = EXT2_DIR_REC_LEN(2);
+ de->inode = ((struct ext2_dir_entry *)buf)->inode;
+ de->name_len = 2 | filetype;
+ de->name[0] = '.';
+ de->name[1] = '.';
+ de->name[2] = '\0';
+
+ de = (struct ext2_dir_entry *)(target +
+ EXT2_DIR_REC_LEN(1) +
+ EXT2_DIR_REC_LEN(2));
+ header_size = (void *)de - (void *)target;
+
+ memcpy((void *)de, buf + EXT4_INLINE_DATA_DOTDOT_SIZE,
+ inline_size - EXT4_INLINE_DATA_DOTDOT_SIZE);
+
+ ext2fs_update_final_de(fs, target,
+ inline_size - EXT4_INLINE_DATA_DOTDOT_SIZE + header_size,
+ fs->blocksize - csum_size);
+
+ if (csum_size) {
+ t = EXT2_DIRENT_TAIL(target, fs->blocksize);
+ ext2fs_initialize_dirent_tail(fs, t);
+ }
+}
+
int ext2fs_inline_data_iterate(ext2_filsys fs,
ext2_ino_t ino,
int flags,
@@ -190,3 +318,212 @@ out:
ext2fs_free_mem(&inode);
return retval & BLOCK_ERROR ? ctx->errcode : 0;
}
+
+errcode_t ext2fs_convert_inline_data(ext2_filsys fs,
+ ext2_ino_t ino,
+ void *priv_data)
+{
+ struct expand_dir_struct *es;
+ struct ext2_inode_large *inode;
+ struct inline_data data;
+ ext2_extent_handle_t handle;
+ errcode_t retval;
+ blk64_t blk;
+ void *inline_start;
+ char *backup_buf;
+ char *blk_buf;
+ int inline_size;
+ int i, limit, r;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ es = (struct expand_dir_struct *)priv_data;
+ retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
+ if (retval)
+ return retval;
+
+ retval = ext2fs_read_inode_full(fs, ino, (void *)inode,
+ EXT2_INODE_SIZE(fs->super));
+ if (retval)
+ goto out;
+
+ retval = ext2fs_iget_extra_inode(fs, inode, &data);
+ if (retval)
+ goto out;
+
+ inline_size = data.inline_size;
+ retval = ext2fs_get_mem(inline_size, &backup_buf);
+ if (retval)
+ goto out;
+
+ memcpy(backup_buf, (void *)inode->i_block, EXT4_MIN_INLINE_DATA_SIZE);
+ if (inline_size > EXT4_MIN_INLINE_DATA_SIZE)
+ memcpy(backup_buf + EXT4_MIN_INLINE_DATA_SIZE,
+ ext2fs_get_inline_xattr_pos(inode, &data),
+ inline_size - EXT4_MIN_INLINE_DATA_SIZE);
+
+ /* clear the entry and the flag in dir now */
+ retval = ext2fs_inline_data_destory_data(fs, ino, inode, &data);
+ if (retval)
+ goto out1;
+
+ if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) {
+ if (LINUX_S_ISDIR(inode->i_mode) ||
+ LINUX_S_ISREG(inode->i_mode) ||
+ LINUX_S_ISLNK(inode->i_mode))
+ inode->i_flags |= EXT4_EXTENTS_FL;
+ }
+
+ inode->i_flags &= ~EXT4_INLINE_DATA_FL;
+
+ retval = ext2fs_new_block2(fs, 0, 0, &blk);
+ if (retval)
+ goto out1;
+
+ ext2fs_iblk_set(fs, (void*)inode, 1);
+ if (!(fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS))
+ inode->i_block[0] = blk;
+ inode->i_size = fs->blocksize;
+
+ retval = ext2fs_get_mem(fs->blocksize, &blk_buf);
+ if (retval)
+ goto out1;
+
+ memset(blk_buf, 0, sizeof(fs->blocksize));
+ if (LINUX_S_ISDIR(inode->i_mode)) {
+ /* set the final dir entry to cover the whole block */
+ ext2fs_inline_data_finish_convert(fs, ino, blk_buf, backup_buf,
+ inline_size);
+ } else {
+ memcpy(blk_buf, backup_buf, inline_size);
+ }
+
+ retval = ext2fs_write_dir_block4(fs, blk, blk_buf, 0, ino);
+ if (retval)
+ goto out2;
+ retval = ext2fs_write_inode_full(fs, ino, (void *)inode,
+ EXT2_INODE_SIZE(fs->super));
+ if (retval)
+ goto out2;
+
+ if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) {
+ retval = ext2fs_extent_open2(fs, ino, (void *)inode, &handle);
+ if (retval)
+ goto out2;
+ retval = ext2fs_extent_set_bmap(handle, 0, blk, 0);
+ ext2fs_extent_free(handle);
+ if (retval)
+ goto out2;
+ }
+
+ ext2fs_block_alloc_stats2(fs, blk, +1);
+
+out2:
+ ext2fs_free_mem(&blk_buf);
+out1:
+ ext2fs_free_mem(&backup_buf);
+out:
+ ext2fs_free_mem(&inode);
+
+ if (retval) {
+ es->err = retval;
+ } else {
+ es->done = 1;
+ es->newblocks++;
+ es->goal = blk;
+ }
+ return retval;
+}
+
+static errcode_t ext2fs_create_inline_data(ext2_filsys fs,
+ struct ext2_inode_large *inode,
+ int len)
+{
+ struct ext2_ext_attr_ibody_header *header;
+ struct ext2_ext_attr_search s = {
+ .not_found = -1,
+ };
+ struct ext2_ext_attr_info i = {
+ .name_index = EXT4_EXT_ATTR_INDEX_SYSTEM,
+ .name = EXT4_EXT_ATTR_SYSTEM_DATA,
+ };
+ void *buf;
+ errcode_t ret;
+
+ if (len > EXT4_MIN_INLINE_DATA_SIZE) {
+ i.value_len = len - EXT4_MIN_INLINE_DATA_SIZE;
+ ret = ext2fs_get_mem(i.value_len, &buf);
+ if (ret)
+ return ret;
+ memset(buf, 0, i.value_len);
+ i.value = buf;
+ } else {
+ i.value = "";
+ i.value_len = 0;
+ }
+
+ (void) ext2fs_ibody_find_ext_attr(fs, inode, &i, &s);
+ ret = ext2fs_set_entry_ext_attr(&i, &s);
+ if (ret)
+ return -1;
+
+ header = IHDR(inode);
+ if (!EXT2_EXT_IS_LAST_ENTRY(s.first))
+ header->h_magic = ext2fs_cpu_to_le32(EXT2_EXT_ATTR_MAGIC);
+ else
+ header->h_magic = ext2fs_cpu_to_le32(0);
+
+ return 0;
+}
+
+errcode_t ext2fs_inline_data_mkdir(ext2_filsys fs, ext2_ino_t parent,
+ ext2_ino_t ino, const char *name)
+{
+ struct ext2_inode_large *inode;
+ struct ext2_dir_entry *de;
+ errcode_t retval = 0;
+ char *buf;
+ int inline_size = EXT4_MIN_INLINE_DATA_SIZE;
+ __u32 t = fs->now ? fs->now : time(NULL);
+
+ retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
+ if (retval)
+ return retval;
+ memset(inode, 0, EXT2_INODE_SIZE(fs->super));
+
+ inode->i_extra_isize = sizeof(struct ext2_inode_large) -
+ EXT2_GOOD_OLD_INODE_SIZE;
+ /* prepare inline data*/
+ retval = ext2fs_create_inline_data(fs, inode, inline_size);
+ if (retval)
+ goto out;
+
+ de = (struct ext2_dir_entry *)inode->i_block;
+ de->inode = parent;
+
+ de = (struct ext2_dir_entry *)((void *)de + EXT4_INLINE_DATA_DOTDOT_SIZE);
+ de->inode = 0;
+ de->rec_len = inline_size - EXT4_INLINE_DATA_DOTDOT_SIZE;
+
+ inode->i_mode = LINUX_S_IFDIR | (0777 & ~fs->umask);
+ inode->i_uid = inode->i_gid = 0;
+ inode->i_links_count = 2;
+ inode->i_size = inline_size;
+ inode->i_flags &= ~EXT4_EXTENTS_FL;
+ inode->i_flags |= EXT4_INLINE_DATA_FL;
+ if (!inode->i_ctime)
+ inode->i_ctime = t;
+ if (!inode->i_mtime)
+ inode->i_mtime = t;
+ if (!inode->i_atime)
+ inode->i_atime = t;
+ if (!inode->i_crtime)
+ inode->i_crtime = t;
+
+ retval = ext2fs_write_inode_full(fs, ino, (void *)inode,
+ EXT2_INODE_SIZE(fs->super));
+
+out:
+ ext2fs_free_mem(&inode);
+ return retval;
+}
diff --git a/lib/ext2fs/mkdir.c b/lib/ext2fs/mkdir.c
index 4a85439..3bbe808 100644
--- a/lib/ext2fs/mkdir.c
+++ b/lib/ext2fs/mkdir.c
@@ -41,6 +41,7 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
ext2_ino_t scratch_ino;
blk64_t blk;
char *block = 0;
+ int inline_data = 0;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
@@ -54,6 +55,15 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
goto cleanup;
}
+ if (fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_INLINE_DATA &&
+ ino > EXT2_FIRST_INO(fs->super) && strcmp("lost+found", name) != 0) {
+ retval = ext2fs_inline_data_mkdir(fs, parent, ino, name);
+ if (retval)
+ goto cleanup;
+ inline_data = 1;
+ goto make_link;
+ }
+
/*
* Allocate a data block for the directory
*/
@@ -114,6 +124,7 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
goto cleanup;
}
+make_link:
/*
* Link the directory into the filesystem hierarchy
*/
@@ -136,6 +147,10 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
* Update parent inode's counts
*/
if (parent != ino) {
+ /* Reload parent inode due to inline data */
+ retval = ext2fs_read_inode(fs, parent, &parent_inode);
+ if (retval)
+ goto cleanup;
parent_inode.i_links_count++;
retval = ext2fs_write_inode(fs, parent, &parent_inode);
if (retval)
@@ -145,7 +160,8 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
/*
* Update accounting....
*/
- ext2fs_block_alloc_stats2(fs, blk, +1);
+ if (!inline_data)
+ ext2fs_block_alloc_stats2(fs, blk, +1);
ext2fs_inode_alloc_stats2(fs, ino, +1, 1);
cleanup:
--
1.7.4.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 08/21 v5] debugfs: make lsdel command support inline data
2012-09-22 4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
` (6 preceding siblings ...)
2012-09-22 4:00 ` [PATCH 07/21 v5] libext2fs: handle inline data when expanding directory Zheng Liu
@ 2012-09-22 4:00 ` Zheng Liu
2012-09-22 4:00 ` [PATCH 09/21 v5] libext2fs: handle inline data in read/write function Zheng Liu
` (12 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22 4:00 UTC (permalink / raw)
To: linux-ext4; +Cc: tytso, Zheng Liu
From: Zheng Liu <wenqing.lz@taobao.com>
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
debugfs/lsdel.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/debugfs/lsdel.c b/debugfs/lsdel.c
index bed0ce6..71546c7 100644
--- a/debugfs/lsdel.c
+++ b/debugfs/lsdel.c
@@ -149,7 +149,8 @@ void do_lsdel(int argc, char **argv)
"while calling ext2fs_block_iterate2");
goto next;
}
- if (lsd.free_blocks && !lsd.bad_blocks) {
+ if (lsd.free_blocks && !lsd.bad_blocks ||
+ inode.i_flags & EXT4_INLINE_DATA_FL) {
if (num_delarray >= max_delarray) {
max_delarray += 50;
delarray = realloc(delarray,
--
1.7.4.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 09/21 v5] libext2fs: handle inline data in read/write function
2012-09-22 4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
` (7 preceding siblings ...)
2012-09-22 4:00 ` [PATCH 08/21 v5] debugfs: make lsdel command support inline data Zheng Liu
@ 2012-09-22 4:00 ` Zheng Liu
2012-09-22 4:00 ` [PATCH 10/21 v5] debugfs: handle inline_data feature in dirsearch command Zheng Liu
` (11 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22 4:00 UTC (permalink / raw)
To: linux-ext4; +Cc: tytso, Zheng Liu
From: Zheng Liu <wenqing.lz@taobao.com>
Ext2fs_read/write_inline_data functions copy inline_data from/to user's buffer
directly. When we want to write some data to a file with inline_data,
ext2fs_try_to_write_inline_data is called. In this function, it firstly check
the length of data. If the data can be saved in innode, this function will
create a new extend attribute to record information of inline_data, and copy all
data into this inode.
The following commands in debugfs can handle inline_data feature after
applying this patch:
- dump
- cat
- rdump
- write
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
lib/ext2fs/ext2_err.et.in | 3 +
lib/ext2fs/ext2fs.h | 7 ++
lib/ext2fs/fileio.c | 19 +++++-
lib/ext2fs/inline_data.c | 170 +++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 198 insertions(+), 1 deletions(-)
diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in
index 537d840..17de695 100644
--- a/lib/ext2fs/ext2_err.et.in
+++ b/lib/ext2fs/ext2_err.et.in
@@ -476,6 +476,9 @@ ec EXT2_ET_UNKNOWN_CSUM,
ec EXT2_ET_MMP_CSUM_INVALID,
"MMP block checksum does not match MMP block"
+ec EXT2_ET_INLINE_DATA_NO_SPACE,
+ "No free space in inline data"
+
ec EXT2_ET_BAD_EXTRA_SIZE,
"Bad inode extra isizevalue"
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 779eca5..801e2dd 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -1347,6 +1347,13 @@ extern errcode_t ext2fs_inline_data_mkdir(ext2_filsys fs, ext2_ino_t parent,
ext2_ino_t ino, const char *name);
extern errcode_t ext2fs_convert_inline_data(ext2_filsys fs, ext2_ino_t ino,
void *priv_data);
+extern errcode_t ext2fs_read_inline_data(ext2_filsys fs, ext2_ino_t ino,
+ char *buf);
+extern errcode_t ext2fs_write_inline_data(ext2_filsys fs, ext2_ino_t ino,
+ char *buf);
+extern errcode_t ext2fs_try_to_write_inline_data(ext2_filsys fs, ext2_ino_t ino,
+ const void *buf, unsigned int nbytes,
+ unsigned int *written);
/* inode.c */
extern errcode_t ext2fs_flush_icache(ext2_filsys fs);
diff --git a/lib/ext2fs/fileio.c b/lib/ext2fs/fileio.c
index 1f7002c..d751666 100644
--- a/lib/ext2fs/fileio.c
+++ b/lib/ext2fs/fileio.c
@@ -163,7 +163,8 @@ static errcode_t sync_buffer_position(ext2_file_t file)
b = file->pos / file->fs->blocksize;
if (b != file->blockno) {
- retval = ext2fs_file_flush(file);
+ if (!ext2fs_inode_has_inline_data(file->fs, file->ino))
+ retval = ext2fs_file_flush(file);
if (retval)
return retval;
file->flags &= ~EXT2_FILE_BUF_VALID;
@@ -186,6 +187,12 @@ static errcode_t load_buffer(ext2_file_t file, int dontfill)
ext2_filsys fs = file->fs;
errcode_t retval;
+ /* We first handle inline_data */
+ if (file->inode.i_flags & EXT4_INLINE_DATA_FL) {
+ retval = ext2fs_read_inline_data(fs, file->ino, file->buf);
+ return retval;
+ }
+
if (!(file->flags & EXT2_FILE_BUF_VALID)) {
retval = ext2fs_bmap2(fs, file->ino, &file->inode,
BMAP_BUFFER, 0, file->blockno, 0,
@@ -280,6 +287,16 @@ errcode_t ext2fs_file_write(ext2_file_t file, const void *buf,
if (!(file->flags & EXT2_FILE_WRITE))
return EXT2_ET_FILE_RO;
+ if (fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_INLINE_DATA) {
+ retval = ext2fs_try_to_write_inline_data(fs, file->ino, buf,
+ nbytes, written);
+ if (!retval)
+ return retval;
+ if (retval != EXT2_ET_INLINE_DATA_NO_SPACE)
+ return retval;
+ retval = 0;
+ }
+
while (nbytes > 0) {
retval = sync_buffer_position(file);
if (retval)
diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c
index ef7b216..a847b68 100644
--- a/lib/ext2fs/inline_data.c
+++ b/lib/ext2fs/inline_data.c
@@ -24,6 +24,7 @@ static int ext2fs_iget_extra_inode(ext2_filsys fs, struct ext2_inode_large *inod
struct inline_data *data);
static void *ext2fs_get_inline_xattr_pos(struct ext2_inode_large *inode,
struct inline_data *data);
+static int ext2fs_get_max_inline_size(ext2_filsys fs, struct ext2_inode_large *inode);
static void ext2fs_inline_data_finish_convert(ext2_filsys fs, ext2_ino_t ino,
char *target, void *buf,
int inline_size);
@@ -314,6 +315,73 @@ out:
return retval & BLOCK_ERROR ? ctx->errcode : 0;
}
+errcode_t ext2fs_read_inline_data(ext2_filsys fs, ext2_ino_t ino, char *buf)
+{
+ struct ext2_inode_large *inode;
+ struct inline_data data;
+ errcode_t retval = 0;
+ int inline_size;
+
+ retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
+ if (retval)
+ return retval;
+
+ retval = ext2fs_read_inode_full(fs, ino, (void *)inode,
+ EXT2_INODE_SIZE(fs->super));
+ if (retval)
+ goto err;
+
+ retval = ext2fs_iget_extra_inode(fs, inode, &data);
+ if (retval)
+ goto err;
+
+ inline_size = data.inline_size;
+
+ memcpy(buf, (void *)inode->i_block, EXT4_MIN_INLINE_DATA_SIZE);
+ if (inline_size > EXT4_MIN_INLINE_DATA_SIZE)
+ memcpy(buf + EXT4_MIN_INLINE_DATA_SIZE,
+ ext2fs_get_inline_xattr_pos(inode, &data),
+ inline_size - EXT4_MIN_INLINE_DATA_SIZE);
+
+err:
+ ext2fs_free_mem(&inode);
+ return retval;
+}
+
+errcode_t ext2fs_write_inline_data(ext2_filsys fs, ext2_ino_t ino, char *buf)
+{
+ struct ext2_inode_large *inode;
+ struct inline_data data;
+ errcode_t retval = 0;
+ int inline_size;
+
+ retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
+ if (retval)
+ return retval;
+
+ retval = ext2fs_read_inode_full(fs, ino, (void *)inode,
+ EXT2_INODE_SIZE(fs->super));
+ if (retval)
+ goto err;
+
+ retval = ext2fs_iget_extra_inode(fs, inode, &data);
+ if (retval)
+ goto err;
+
+ inline_size = data.inline_size;
+
+ memcpy((void *)inode->i_block, buf, EXT4_MIN_INLINE_DATA_SIZE);
+ if (inline_size > EXT4_MIN_INLINE_DATA_SIZE)
+ memcpy(ext2fs_get_inline_xattr_pos(inode, &data),
+ buf + EXT4_MIN_INLINE_DATA_SIZE,
+ inline_size - EXT4_MIN_INLINE_DATA_SIZE);
+
+ retval = ext2fs_write_inode_full(fs, ino, (void *)inode,
+ EXT2_INODE_SIZE(fs->super));
+err:
+ ext2fs_free_mem(&inode);
+ return retval;
+}
errcode_t ext2fs_convert_inline_data(ext2_filsys fs,
ext2_ino_t ino,
void *priv_data)
@@ -519,3 +587,105 @@ out:
ext2fs_free_mem(&inode);
return retval;
}
+
+static int ext2fs_get_max_inline_size(ext2_filsys fs, struct ext2_inode_large *inode)
+{
+ struct ext2_ext_attr_entry *entry;
+ struct ext2_ext_attr_ibody_header *header;
+ struct inline_data data;
+ errcode_t retval = 0;
+ int free, min_offs;
+
+ min_offs = EXT2_INODE_SIZE(fs->super) -
+ EXT2_GOOD_OLD_INODE_SIZE -
+ inode->i_extra_isize -
+ sizeof(struct ext2_ext_attr_ibody_header);
+
+ header = IHDR(inode);
+ entry = IFIRST(header);
+
+ for (; !EXT2_EXT_IS_LAST_ENTRY(entry);
+ entry = EXT2_EXT_ATTR_NEXT(entry)) {
+ if (!entry->e_value_block && entry->e_value_size) {
+ size_t offs = ext2fs_le16_to_cpu(entry->e_value_offs);
+ if (offs < min_offs)
+ min_offs = offs;
+ }
+ }
+ free = min_offs -
+ ((void *)entry - (void *)IFIRST(header)) - sizeof(__u32);
+
+ /*
+ * We try to get inline data offset, but maybe it doesn't be
+ * created. So we ignore this error.
+ */
+ retval = ext2fs_iget_extra_inode(fs, inode, &data);
+ if (retval && retval != EXT2_ET_BAD_EXT_ATTR_MAGIC)
+ return 0;
+
+ if (data.inline_off) {
+ entry = (struct ext2_ext_attr_entry *)
+ ((void *)inode + data.inline_off);
+ free += ext2fs_le32_to_cpu(entry->e_value_size);
+ goto out;
+ }
+
+ free -= EXT2_EXT_ATTR_LEN(strlen(EXT4_EXT_ATTR_SYSTEM_DATA));
+
+ if (free > EXT2_EXT_ATTR_ROUND)
+ free = EXT2_EXT_ATTR_SIZE(free - EXT2_EXT_ATTR_ROUND);
+ else
+ free = 0;
+
+out:
+ return free + EXT4_MIN_INLINE_DATA_SIZE;
+}
+
+errcode_t ext2fs_try_to_write_inline_data(ext2_filsys fs, ext2_ino_t ino,
+ const void *buf, unsigned int nbytes,
+ unsigned int *written)
+{
+ struct ext2_inode_large *inode;
+ struct inline_data data;
+ errcode_t retval = 0;
+ int inline_size = 0;
+
+ retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
+ if (retval)
+ return retval;
+ retval = ext2fs_read_inode_full(fs, ino, (void *)inode,
+ EXT2_INODE_SIZE(fs->super));
+ if (retval)
+ goto out;
+
+ if (nbytes > ext2fs_get_max_inline_size(fs, inode)) {
+ retval = EXT2_ET_INLINE_DATA_NO_SPACE;
+ goto out;
+ }
+
+ retval = ext2fs_create_inline_data(fs, inode, nbytes);
+ if (retval)
+ goto out;
+
+ retval = ext2fs_iget_extra_inode(fs, inode, &data);
+ if (retval)
+ goto out;
+
+ inline_size = data.inline_size;
+
+ memcpy((void *)inode->i_block, buf, EXT4_MIN_INLINE_DATA_SIZE);
+ if (inline_size > EXT4_MIN_INLINE_DATA_SIZE)
+ memcpy(ext2fs_get_inline_xattr_pos(inode, &data),
+ buf + EXT4_MIN_INLINE_DATA_SIZE,
+ inline_size - EXT4_MIN_INLINE_DATA_SIZE);
+
+ inode->i_flags &= ~EXT4_EXTENTS_FL;
+ inode->i_flags |= EXT4_INLINE_DATA_FL;
+
+ retval = ext2fs_write_inode_full(fs, ino, (void *)inode,
+ EXT2_INODE_SIZE(fs->super));
+
+out:
+ ext2fs_free_mem(&inode);
+ return retval;
+}
--
1.7.4.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 10/21 v5] debugfs: handle inline_data feature in dirsearch command
2012-09-22 4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
` (8 preceding siblings ...)
2012-09-22 4:00 ` [PATCH 09/21 v5] libext2fs: handle inline data in read/write function Zheng Liu
@ 2012-09-22 4:00 ` Zheng Liu
2012-09-22 4:00 ` [PATCH 11/21 v5] debugfs: handle inline_data feature in bmap command Zheng Liu
` (10 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22 4:00 UTC (permalink / raw)
To: linux-ext4; +Cc: tytso, Zheng Liu
From: Zheng Liu <wenqing.lz@taobao.com>
Inode with inline_data hasn't any blocks. So we need to handle it in a new
function.
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
debugfs/htree.c | 7 ++++
lib/ext2fs/ext2fs.h | 2 +
lib/ext2fs/inline_data.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 98 insertions(+), 0 deletions(-)
diff --git a/debugfs/htree.c b/debugfs/htree.c
index 1932962..eb71a40 100644
--- a/debugfs/htree.c
+++ b/debugfs/htree.c
@@ -374,9 +374,16 @@ void do_dirsearch(int argc, char *argv[])
pb.search_name = argv[2];
pb.len = strlen(pb.search_name);
+ if (ext2fs_inode_has_inline_data(current_fs, inode)) {
+ ext2fs_inline_data_dirsearch(current_fs, inode,
+ argv[2], strlen(argv[2]));
+ goto out;
+ }
+
ext2fs_block_iterate3(current_fs, inode, BLOCK_FLAG_READ_ONLY, 0,
search_dir_block, &pb);
+out:
free(pb.buf);
}
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 801e2dd..9b7d608 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -1354,6 +1354,8 @@ extern errcode_t ext2fs_write_inline_data(ext2_filsys fs, ext2_ino_t ino,
extern errcode_t ext2fs_try_to_write_inline_data(ext2_filsys fs, ext2_ino_t ino,
const void *buf, unsigned int nbytes,
unsigned int *written);
+extern errcode_t ext2fs_inline_data_dirsearch(ext2_filsys fs, ext2_ino_t ino,
+ const char *name, size_t namelen);
/* inode.c */
extern errcode_t ext2fs_flush_icache(ext2_filsys fs);
diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c
index a847b68..402bc10 100644
--- a/lib/ext2fs/inline_data.c
+++ b/lib/ext2fs/inline_data.c
@@ -36,6 +36,8 @@ static int ext2fs_inline_data_destory_data(ext2_filsys fs, ext2_ino_t ino,
static errcode_t ext2fs_create_inline_data(ext2_filsys fs,
struct ext2_inode_large *inode,
int len);
+static int do_search_dir(ext2_filsys fs, void *start, int size,
+ const char *name, size_t len);
static int ext2fs_iget_extra_inode(ext2_filsys fs, struct ext2_inode_large *inode,
struct inline_data *data)
@@ -117,6 +119,93 @@ static int ext2fs_inline_data_destory_data(ext2_filsys fs, ext2_ino_t ino,
return 0;
}
+static int do_search_dir(ext2_filsys fs, void *start, int size,
+ const char *name, size_t len)
+{
+ struct ext2_dir_entry *de;
+ unsigned offset = 0;
+ unsigned rec_len;
+ errcode_t errcode;
+
+ while (offset < len) {
+ de = (struct ext2_dir_entry *)(start + offset);
+ errcode = ext2fs_get_rec_len(fs, de, &rec_len);
+ if (errcode) {
+ com_err("search_dir_inline_data", errcode,
+ "while getting rec_len for inline data");
+ return errcode;
+ }
+ if (de->inode &&
+ len == (de->name_len & 0xFF) &&
+ strncmp(name, de->name, len) == 0) {
+ printf("Entry found at inline data\n");
+ return 1;
+ }
+ offset += rec_len;
+ }
+ return 0;
+}
+
+errcode_t ext2fs_inline_data_dirsearch(ext2_filsys fs, ext2_ino_t ino,
+ const char *name, size_t namelen)
+{
+ struct ext2_inode_large *inode;
+ struct ext2_dir_entry dirent;
+ struct inline_data data;
+ unsigned int offset = 0;
+ unsigned int rec_len;
+ void *inline_start;
+ int inline_size;
+ errcode_t retval = 0;
+
+ retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
+ if (retval)
+ return retval;
+
+ retval = ext2fs_read_inode_full(fs, ino, (void *)inode,
+ EXT2_INODE_SIZE(fs->super));
+ if (retval)
+ goto out;
+
+ /* check '.' and '..' firstly */
+ dirent.inode = ino;
+ dirent.name_len = 1;
+ ext2fs_set_rec_len(fs, EXT2_DIR_REC_LEN(2), &dirent);
+ dirent.name[0] = '.';
+ retval = do_search_dir(fs, (void *)&dirent, dirent.rec_len, name, namelen);
+ if (retval)
+ goto out;
+
+ dirent.inode = ((struct ext2_dir_entry *)inode->i_block)->inode;
+ dirent.name_len = 2;
+ ext2fs_set_rec_len(fs, EXT2_DIR_REC_LEN(3), &dirent);
+ dirent.name[0] = '.';
+ dirent.name[1] = '.';
+ retval = do_search_dir(fs, (void *)&dirent, dirent.rec_len, name, namelen);
+ if (retval)
+ goto out;
+
+ inline_start = (void *)inode->i_block + EXT4_INLINE_DATA_DOTDOT_SIZE;
+ inline_size = EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DATA_DOTDOT_SIZE;
+ retval = do_search_dir(fs, inline_start, inline_size, name, namelen);
+ if (retval)
+ goto out;
+
+ retval = ext2fs_iget_extra_inode(fs, inode, &data);
+ if (retval)
+ goto out;
+ if (data.inline_size == EXT4_MIN_INLINE_DATA_SIZE)
+ goto out;
+
+ inline_start = ext2fs_get_inline_xattr_pos(inode, &data);
+ inline_size = data.inline_size - EXT4_MIN_INLINE_DATA_SIZE;
+ retval = do_search_dir(fs, inline_start, inline_size, name, namelen);
+
+out:
+ ext2fs_free_mem(&inode);
+ return retval;
+}
+
int ext2fs_inode_has_inline_data(ext2_filsys fs, ext2_ino_t ino)
{
struct ext2_inode inode;
--
1.7.4.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 11/21 v5] debugfs: handle inline_data feature in bmap command
2012-09-22 4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
` (9 preceding siblings ...)
2012-09-22 4:00 ` [PATCH 10/21 v5] debugfs: handle inline_data feature in dirsearch command Zheng Liu
@ 2012-09-22 4:00 ` Zheng Liu
2012-09-22 4:01 ` [PATCH 12/21 v5] debugfs: handle inline_data in punch command Zheng Liu
` (9 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22 4:00 UTC (permalink / raw)
To: linux-ext4; +Cc: tytso, Zheng Liu
From: Zheng Liu <wenqing.lz@taobao.com>
If an inode has inline data, bmap command will return the physical block of this
inode.
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
lib/ext2fs/bmap.c | 15 +++++++++++++++
1 files changed, 15 insertions(+), 0 deletions(-)
diff --git a/lib/ext2fs/bmap.c b/lib/ext2fs/bmap.c
index 16d51e0..4746a1f 100644
--- a/lib/ext2fs/bmap.c
+++ b/lib/ext2fs/bmap.c
@@ -264,6 +264,21 @@ errcode_t ext2fs_bmap2(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode,
block_buf = buf;
}
+ if (inode->i_flags & EXT4_INLINE_DATA_FL) {
+ unsigned long group, block, offset;
+
+ group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
+ if (group > fs->group_desc_count)
+ return EXT2_ET_BAD_INODE_NUM;
+ offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
+ EXT2_INODE_SIZE(fs->super);
+ block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super);
+ if (!ext2fs_inode_table_loc(fs, (unsigned) group))
+ return EXT2_ET_MISSING_INODE_TABLE;
+ *phys_blk = ext2fs_inode_table_loc(fs, group) + block;
+ goto done;
+ }
+
if (inode->i_flags & EXT4_EXTENTS_FL) {
retval = ext2fs_extent_open2(fs, ino, inode, &handle);
if (retval)
--
1.7.4.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 12/21 v5] debugfs: handle inline_data in punch command
2012-09-22 4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
` (10 preceding siblings ...)
2012-09-22 4:00 ` [PATCH 11/21 v5] debugfs: handle inline_data feature in bmap command Zheng Liu
@ 2012-09-22 4:01 ` Zheng Liu
2012-09-22 4:01 ` [PATCH 13/21 v5] libext2fs: add inline_data feature into EXT2_LIB_FEATURE_INCOMPAT_SUPP Zheng Liu
` (8 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22 4:01 UTC (permalink / raw)
To: linux-ext4; +Cc: tytso, Zheng Liu
From: Zheng Liu <wenqing.lz@taobao.com>
Now punch command only can truncate an inode with inline_data.
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
lib/ext2fs/ext2fs.h | 2 +
lib/ext2fs/inline_data.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++
lib/ext2fs/punch.c | 10 +++++-
3 files changed, 91 insertions(+), 1 deletions(-)
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index b451a4a..4e467a0 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -1360,6 +1360,8 @@ extern errcode_t ext2fs_try_to_write_inline_data(ext2_filsys fs, ext2_ino_t ino,
unsigned int *written);
extern errcode_t ext2fs_inline_data_dirsearch(ext2_filsys fs, ext2_ino_t ino,
const char *name, size_t namelen);
+extern errcode_t ext2fs_punch_inline_data(ext2_filsys fs, ext2_ino_t ino,
+ blk64_t start, blk64_t end);
/* inode.c */
extern errcode_t ext2fs_flush_icache(ext2_filsys fs);
diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c
index db33ddd..229e723 100644
--- a/lib/ext2fs/inline_data.c
+++ b/lib/ext2fs/inline_data.c
@@ -476,6 +476,86 @@ err:
ext2fs_free_mem(&inode);
return retval;
}
+
+errcode_t ext2fs_punch_inline_data(ext2_filsys fs, ext2_ino_t ino,
+ blk64_t start, blk64_t end)
+{
+ struct ext2_inode_large *inode;
+ struct inline_data data;
+ errcode_t retval = 0;
+ void *value;
+ int inline_size, value_len;
+
+ retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
+ if (retval)
+ return retval;
+
+ retval = ext2fs_read_inode_full(fs, ino, (void *)inode,
+ EXT2_INODE_SIZE(fs->super));
+ if (retval)
+ goto out;
+
+ retval = ext2fs_iget_extra_inode(fs, inode, &data);
+ if (retval)
+ goto out;
+ inline_size = data.inline_size;
+
+ if (start > inline_size)
+ goto out;
+
+ if (start < inline_size) {
+ struct ext2_ext_attr_ibody_header *header;
+ struct ext2_ext_attr_search s = {
+ .not_found = -1,
+ };
+ struct ext2_ext_attr_info i = {
+ .name_index = EXT4_EXT_ATTR_INDEX_SYSTEM,
+ .name = EXT4_EXT_ATTR_SYSTEM_DATA,
+ };
+
+ if (!data.inline_off)
+ goto out;
+
+ if (inode->i_extra_isize > (EXT2_INODE_SIZE(fs->super) -
+ EXT2_GOOD_OLD_INODE_SIZE)) {
+ retval = EXT2_ET_BAD_EXTRA_SIZE;
+ goto out;
+ }
+
+ (void)ext2fs_ibody_find_ext_attr(fs, inode, &i, &s);
+
+ value_len = ext2fs_le32_to_cpu(s.here->e_value_size);
+
+ retval = ext2fs_get_mem(s.here->e_value_size, &value);
+ if (retval)
+ goto out;
+
+ retval = ext2fs_ibody_get_ext_attr(fs, inode, i.name_index,
+ i.name, value, value_len);
+
+ if (!s.not_found) {
+ i.value = value;
+ i.value_len = start > EXT4_MIN_INLINE_DATA_SIZE ?
+ start - EXT4_MIN_INLINE_DATA_SIZE : 0;
+ }
+ retval = ext2fs_set_entry_ext_attr(&i, &s);
+ if (retval)
+ goto out;
+ }
+
+ if (start < EXT4_MIN_INLINE_DATA_SIZE) {
+ memset((void *)inode->i_block + start, 0,
+ EXT4_MIN_INLINE_DATA_SIZE - start);
+ }
+
+ inode->i_size = start;
+ retval = ext2fs_write_inode_full(fs, ino, (void *)inode,
+ EXT2_INODE_SIZE(fs->super));
+out:
+ ext2fs_free_mem(&inode);
+ return retval;
+}
+
errcode_t ext2fs_convert_inline_data(ext2_filsys fs,
ext2_ino_t ino,
void *priv_data)
diff --git a/lib/ext2fs/punch.c b/lib/ext2fs/punch.c
index b53653a..4b8d51c 100644
--- a/lib/ext2fs/punch.c
+++ b/lib/ext2fs/punch.c
@@ -307,7 +307,15 @@ extern errcode_t ext2fs_punch(ext2_filsys fs, ext2_ino_t ino,
return retval;
inode = &inode_buf;
}
- if (inode->i_flags & EXT4_EXTENTS_FL)
+ if (inode->i_flags & EXT4_INLINE_DATA_FL) {
+ /* punching hole for inline_data is not supported */
+ if (end != ~0)
+ retval = EXT2_ET_OP_NOT_SUPPORTED;
+ else
+ retval = ext2fs_punch_inline_data(fs, ino, start, end);
+
+ return retval;
+ } else if (inode->i_flags & EXT4_EXTENTS_FL)
retval = ext2fs_punch_extent(fs, ino, inode, start, end);
else {
blk_t count;
--
1.7.4.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 13/21 v5] libext2fs: add inline_data feature into EXT2_LIB_FEATURE_INCOMPAT_SUPP
2012-09-22 4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
` (11 preceding siblings ...)
2012-09-22 4:01 ` [PATCH 12/21 v5] debugfs: handle inline_data in punch command Zheng Liu
@ 2012-09-22 4:01 ` Zheng Liu
2012-09-22 4:01 ` [PATCH 14/21 v5] mke2fs: add inline_data support in mke2fs Zheng Liu
` (7 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22 4:01 UTC (permalink / raw)
To: linux-ext4; +Cc: tytso, Zheng Liu
From: Zheng Liu <wenqing.lz@taobao.com>
let e2fsprogs support inline_data feature.
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
lib/ext2fs/ext2fs.h | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index dd1c94c..d1f4218 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -586,7 +586,8 @@ typedef struct ext2_icount *ext2_icount_t;
EXT3_FEATURE_INCOMPAT_EXTENTS|\
EXT4_FEATURE_INCOMPAT_FLEX_BG|\
EXT4_LIB_INCOMPAT_MMP|\
- EXT4_FEATURE_INCOMPAT_64BIT)
+ EXT4_FEATURE_INCOMPAT_64BIT|\
+ EXT4_FEATURE_INCOMPAT_INLINE_DATA)
#define EXT2_LIB_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|\
EXT4_FEATURE_RO_COMPAT_HUGE_FILE|\
--
1.7.4.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 14/21 v5] mke2fs: add inline_data support in mke2fs
2012-09-22 4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
` (12 preceding siblings ...)
2012-09-22 4:01 ` [PATCH 13/21 v5] libext2fs: add inline_data feature into EXT2_LIB_FEATURE_INCOMPAT_SUPP Zheng Liu
@ 2012-09-22 4:01 ` Zheng Liu
2012-09-22 4:01 ` [PATCH 15/21 v5] tune2fs: add inline_data feature in tune2fs Zheng Liu
` (6 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22 4:01 UTC (permalink / raw)
To: linux-ext4; +Cc: tytso, Zheng Liu
From: Zheng Liu <wenqing.lz@taobao.com>
Ext_attr feature not enabled, inline_data feature doesn't be specified.
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
misc/mke2fs.8.in | 3 +++
misc/mke2fs.c | 14 +++++++++++++-
2 files changed, 16 insertions(+), 1 deletions(-)
diff --git a/misc/mke2fs.8.in b/misc/mke2fs.8.in
index 6d443a2..bfe6c94 100644
--- a/misc/mke2fs.8.in
+++ b/misc/mke2fs.8.in
@@ -551,6 +551,9 @@ option).
@JDEV@must be created with the same
@JDEV@block size as the filesystems that will be using it.
.TP
+.B inline_data
+Allow data to be stored in inode
+.TP
.B large_file
Filesystem can contain files that are greater than 2GB. (Modern kernels
set this feature automatically when a file > 2GB is created.)
diff --git a/misc/mke2fs.c b/misc/mke2fs.c
index 072e656..19c23c1 100644
--- a/misc/mke2fs.c
+++ b/misc/mke2fs.c
@@ -883,7 +883,8 @@ static __u32 ok_features[3] = {
EXT2_FEATURE_INCOMPAT_META_BG|
EXT4_FEATURE_INCOMPAT_FLEX_BG|
EXT4_FEATURE_INCOMPAT_MMP |
- EXT4_FEATURE_INCOMPAT_64BIT,
+ EXT4_FEATURE_INCOMPAT_64BIT|
+ EXT4_FEATURE_INCOMPAT_INLINE_DATA,
/* R/O compat */
EXT2_FEATURE_RO_COMPAT_LARGE_FILE|
EXT4_FEATURE_RO_COMPAT_HUGE_FILE|
@@ -1956,6 +1957,17 @@ profile_error:
exit(1);
}
+ /* Since inline_data depends on ext_attr, we would ask it to be
+ * enabled.
+ */
+ if ((fs_param.s_feature_incompat & EXT4_FEATURE_INCOMPAT_INLINE_DATA) &&
+ !(fs_param.s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
+ com_err(program_name, 0,
+ _("Ext_attr feature not enabled, so inline_data "
+ "feature doesn't be specified"));
+ exit(1);
+ }
+
if (fs_param.s_blocks_per_group) {
if (fs_param.s_blocks_per_group < 256 ||
fs_param.s_blocks_per_group > 8 * (unsigned) blocksize) {
--
1.7.4.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 15/21 v5] tune2fs: add inline_data feature in tune2fs
2012-09-22 4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
` (13 preceding siblings ...)
2012-09-22 4:01 ` [PATCH 14/21 v5] mke2fs: add inline_data support in mke2fs Zheng Liu
@ 2012-09-22 4:01 ` Zheng Liu
2012-09-22 4:01 ` [PATCH 16/21 v5] e2fsck: add problem descriptions and check inline data feature Zheng Liu
` (5 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22 4:01 UTC (permalink / raw)
To: linux-ext4; +Cc: tytso, Zheng Liu
From: Zheng Liu <wenqing.lz@taobao.com>
Inline_data feature can be set when ext_attr feature is enabled. Now this
feature only can be enabled because we may be out of space when disabling
it. If this feature is disabled, we need to allocate a block for every
file and directory, and it might exhaust all space.
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
misc/tune2fs.8.in | 5 +++++
misc/tune2fs.c | 17 ++++++++++++++++-
2 files changed, 21 insertions(+), 1 deletions(-)
diff --git a/misc/tune2fs.8.in b/misc/tune2fs.8.in
index 55c6dd9..b768fff 100644
--- a/misc/tune2fs.8.in
+++ b/misc/tune2fs.8.in
@@ -531,6 +531,11 @@ Setting the filesystem feature is equivalent to using the
.B \-j
option.
.TP
+.B inline_data
+Allow data to be stored in inode.
+.B Tune2fs
+only supports setting this filesystem feature.
+.TP
.B large_file
Filesystem can contain files that are greater than 2GB. (Modern kernels
set this feature automatically when a file > 2GB is created.)
diff --git a/misc/tune2fs.c b/misc/tune2fs.c
index b290c46..e9a0e85 100644
--- a/misc/tune2fs.c
+++ b/misc/tune2fs.c
@@ -137,7 +137,8 @@ static __u32 ok_features[3] = {
EXT2_FEATURE_INCOMPAT_FILETYPE |
EXT3_FEATURE_INCOMPAT_EXTENTS |
EXT4_FEATURE_INCOMPAT_FLEX_BG |
- EXT4_FEATURE_INCOMPAT_MMP,
+ EXT4_FEATURE_INCOMPAT_MMP |
+ EXT4_FEATURE_INCOMPAT_INLINE_DATA,
/* R/O compat */
EXT2_FEATURE_RO_COMPAT_LARGE_FILE |
EXT4_FEATURE_RO_COMPAT_HUGE_FILE|
@@ -992,6 +993,20 @@ mmp_error:
disable_uninit_bg(fs,
EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
+ if (FEATURE_ON(E2P_FEATURE_INCOMPAT,
+ EXT4_FEATURE_INCOMPAT_INLINE_DATA)) {
+ /* Inline_data feature cannot be enabled if ext_attr is
+ * disabled.
+ */
+ if (!(fs->super->s_feature_compat &
+ EXT2_FEATURE_COMPAT_EXT_ATTR)) {
+ fputs(_("The inline_data feature cannot "
+ "be set if ext_attr feature is disabled.\n"),
+ stderr);
+ return 1;
+ }
+ }
+
if (FEATURE_ON(E2P_FEATURE_RO_INCOMPAT,
EXT4_FEATURE_RO_COMPAT_QUOTA)) {
/*
--
1.7.4.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 16/21 v5] e2fsck: add problem descriptions and check inline data feature
2012-09-22 4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
` (14 preceding siblings ...)
2012-09-22 4:01 ` [PATCH 15/21 v5] tune2fs: add inline_data feature in tune2fs Zheng Liu
@ 2012-09-22 4:01 ` Zheng Liu
2012-10-14 13:22 ` Theodore Ts'o
2012-09-22 4:01 ` [PATCH 17/21 v5] e2fsck: check inline_data in pass1 Zheng Liu
` (4 subsequent siblings)
20 siblings, 1 reply; 24+ messages in thread
From: Zheng Liu @ 2012-09-22 4:01 UTC (permalink / raw)
To: linux-ext4; +Cc: tytso, Zheng Liu
From: Zheng Liu <wenqing.lz@taobao.com>
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
e2fsck/pass1.c | 33 ++++++++++++++++++++++++++++++++-
e2fsck/problem.c | 15 +++++++++++++++
e2fsck/problem.h | 9 +++++++++
lib/ext2fs/ext2fs.h | 1 +
lib/ext2fs/inline_data.c | 28 ++++++++++++++++++++++++++++
5 files changed, 85 insertions(+), 1 deletions(-)
diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index a4bd956..1a12ed3 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -593,7 +593,7 @@ void e2fsck_pass1(e2fsck_t ctx)
struct ext2_super_block *sb = ctx->fs->super;
const char *old_op;
unsigned int save_type;
- int imagic_fs, extent_fs;
+ int imagic_fs, extent_fs, inlinedata_fs;
int busted_fs_time = 0;
int inode_size;
int failed_csum = 0;
@@ -627,6 +627,8 @@ void e2fsck_pass1(e2fsck_t ctx)
imagic_fs = (sb->s_feature_compat & EXT2_FEATURE_COMPAT_IMAGIC_INODES);
extent_fs = (sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS);
+ inlinedata_fs = (sb->s_feature_incompat &
+ EXT4_FEATURE_INCOMPAT_INLINE_DATA);
/*
* Allocate bitmaps structures
@@ -758,6 +760,20 @@ void e2fsck_pass1(e2fsck_t ctx)
ext2fs_mark_block_bitmap2(ctx->block_found_map,
fs->super->s_mmp_block);
+ /*
+ * If INLINE_DATA feature is set and EXT_ATTR feature missing,
+ * EXT_ATTR needs to be set because INLINE_DATA depends on it and
+ * this feature is enabled on default.
+ */
+ if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR) &&
+ inlinedata_fs) {
+ if (fix_problem(ctx, PR_1_INLINE_DATA_AND_EXT_ATTR, &pctx)) {
+ fs->super->s_feature_compat |=
+ EXT2_FEATURE_COMPAT_EXT_ATTR;
+ ext2fs_mark_super_dirty(fs);
+ }
+ }
+
/* Set up ctx->lost_and_found if possible */
(void) e2fsck_get_lost_and_found(ctx, 0);
@@ -809,6 +825,21 @@ void e2fsck_pass1(e2fsck_t ctx)
}
}
+ /* Test for incrrect inline_data flags settings. */
+ if ((inode->i_flags & EXT4_INLINE_DATA_FL) && !inlinedata_fs &&
+ (ino >= EXT2_FIRST_INODE(fs->super))) {
+ if (ext2fs_inline_data_header_check(fs, ino) &&
+ !fix_problem(ctx, PR_1_INLINE_DATA_FEATURE, &pctx)) {
+ sb->s_feature_incompat |=
+ EXT4_FEATURE_INCOMPAT_INLINE_DATA;
+ ext2fs_mark_super_dirty(fs);
+ inlinedata_fs = 1;
+ } else if (!fix_problem(ctx, PR_1_INLINE_DATA_SET, &pctx)) {
+ e2fsck_clear_inode(ctx, ino, inode, 0, "pass1");
+ continue;
+ }
+ }
+
/*
* Test for incorrect extent flag settings.
*
diff --git a/e2fsck/problem.c b/e2fsck/problem.c
index 78b05bb..ae99d6c 100644
--- a/e2fsck/problem.c
+++ b/e2fsck/problem.c
@@ -1000,6 +1000,21 @@ static struct e2fsck_problem problem_table[] = {
"@i %i does not match. "),
PROMPT_FIX, 0 },
+ /* INLINE_DATA feature is set, but EXT_ATTR missing */
+ { PR_1_INLINE_DATA_AND_EXT_ATTR,
+ N_("INLINE_DATA feature is set in @S, but EXT_ATTR feature missing\n"),
+ PROMPT_FIX, 0 },
+
+ /* Inode has inline data, but superblock is missing INLINE_DATA feature. */
+ { PR_1_INLINE_DATA_FEATURE,
+ N_("@i %i has inline data, but @S is missing INLINE_DATA feature\n"),
+ PROMPT_CLEAR, PR_PREEN_OK },
+
+ /* INLINE_DATA feature is set in a non-inline-data filesystem */
+ { PR_1_INLINE_DATA_SET,
+ N_("@i %i has INLINE_DATA_FL flag on @f without inline data support.\n"),
+ PROMPT_CLEAR, 0 },
+
/* Pass 1b errors */
/* Pass 1B: Rescan for duplicate/bad blocks */
diff --git a/e2fsck/problem.h b/e2fsck/problem.h
index 5caade4..2713f6c 100644
--- a/e2fsck/problem.h
+++ b/e2fsck/problem.h
@@ -586,6 +586,15 @@ struct problem_context {
/* ea block passes checks, but checksum invalid */
#define PR_1_EA_BLOCK_ONLY_CSUM_INVALID 0x01006C
+/* INLINE_DATA feature is set, but EXT_ATTR missing */
+#define PR_1_INLINE_DATA_AND_EXT_ATTR 0x01006D
+
+/* Inode has inline data, but superblock is missing INLINE_DATA feature. */
+#define PR_1_INLINE_DATA_FEATURE 0x01006E
+
+/* INLINE_DATA feature is set in a non-inline-data filesystem */
+#define PR_1_INLINE_DATA_SET 0x01006F
+
/*
* Pass 1b errors
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index d1f4218..a4a3d06 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -1344,6 +1344,7 @@ extern int ext2fs_inline_data_iterate(ext2_filsys fs,
struct ext2_inode_large *inode,
void *priv_data),
void *priv_data);
+extern int ext2fs_inline_data_header_check(ext2_filsys fs, ext2_ino_t ino);
extern errcode_t ext2fs_inline_data_mkdir(ext2_filsys fs, ext2_ino_t parent,
ext2_ino_t ino, const char *name);
extern errcode_t ext2fs_convert_inline_data(ext2_filsys fs, ext2_ino_t ino,
diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c
index 4a98a37..d98b6c7 100644
--- a/lib/ext2fs/inline_data.c
+++ b/lib/ext2fs/inline_data.c
@@ -541,6 +541,34 @@ out:
return retval;
}
+int ext2fs_inline_data_header_check(ext2_filsys fs, ext2_ino_t ino)
+{
+ struct ext2_inode_large *inode;
+ struct inline_data data;
+ errcode_t retval = 0;
+ int pass = 0;
+
+ retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
+ if (retval);
+ return pass;
+
+ retval = ext2fs_read_inode_full(fs, ino, (void *)inode,
+ EXT2_INODE_SIZE(fs->super));
+ if (retval)
+ goto err;
+
+ retval = ext2fs_iget_extra_inode(fs, inode, &data);
+ if (retval)
+ goto err;
+
+ if (data.inline_off != 0)
+ pass = 1;
+
+err:
+ ext2fs_free_mem(&inode);
+ return pass;
+}
+
errcode_t ext2fs_convert_inline_data(ext2_filsys fs,
ext2_ino_t ino,
void *priv_data)
--
1.7.4.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* Re: [PATCH 16/21 v5] e2fsck: add problem descriptions and check inline data feature
2012-09-22 4:01 ` [PATCH 16/21 v5] e2fsck: add problem descriptions and check inline data feature Zheng Liu
@ 2012-10-14 13:22 ` Theodore Ts'o
2012-10-14 23:34 ` Zheng Liu
0 siblings, 1 reply; 24+ messages in thread
From: Theodore Ts'o @ 2012-10-14 13:22 UTC (permalink / raw)
To: Zheng Liu; +Cc: linux-ext4, Zheng Liu
Hi Zheng,
I was trying to apply these patches to the e2fsprogs pu branch, and as
a matter of course, I ran checkpatch on the patch series. The reason
why it's useful is because it finds stuff like this:
WARNING: trailing semicolon indicates no statements, indent implies otherwise
#156: FILE: lib/ext2fs/inline_data.c:567:
+ if (retval);
+ return pass;
ERROR: trailing statements should be on next line
#156: FILE: lib/ext2fs/inline_data.c:567:
+ if (retval);
> +int ext2fs_inline_data_header_check(ext2_filsys fs, ext2_ino_t ino)
> +{
> + struct ext2_inode_large *inode;
> + struct inline_data data;
> + errcode_t retval = 0;
> + int pass = 0;
> +
> + retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
> + if (retval);
> + return pass;
This means the rest of ext2fs_inline_data_header_check() isn't getting
executed, since the "return pass;" statement would get executed
unconditionally. I didn't try it, but I suspect "make gcc-wall"
probably would have turned up this typo as well.
I'll fix this in my tree on the pu branch; I'm still looking over the
rest of the patches, but I thought it would be good to point this out
first.
Cheers,
- Ted
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 16/21 v5] e2fsck: add problem descriptions and check inline data feature
2012-10-14 13:22 ` Theodore Ts'o
@ 2012-10-14 23:34 ` Zheng Liu
0 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-10-14 23:34 UTC (permalink / raw)
To: Theodore Ts'o; +Cc: linux-ext4, Zheng Liu
On Sun, Oct 14, 2012 at 09:22:10AM -0400, Theodore Ts'o wrote:
> Hi Zheng,
>
> I was trying to apply these patches to the e2fsprogs pu branch, and as
> a matter of course, I ran checkpatch on the patch series. The reason
> why it's useful is because it finds stuff like this:
>
> WARNING: trailing semicolon indicates no statements, indent implies otherwise
> #156: FILE: lib/ext2fs/inline_data.c:567:
> + if (retval);
> + return pass;
>
> ERROR: trailing statements should be on next line
> #156: FILE: lib/ext2fs/inline_data.c:567:
> + if (retval);
>
> > +int ext2fs_inline_data_header_check(ext2_filsys fs, ext2_ino_t ino)
> > +{
> > + struct ext2_inode_large *inode;
> > + struct inline_data data;
> > + errcode_t retval = 0;
> > + int pass = 0;
> > +
> > + retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
> > + if (retval);
> > + return pass;
>
> This means the rest of ext2fs_inline_data_header_check() isn't getting
> executed, since the "return pass;" statement would get executed
> unconditionally. I didn't try it, but I suspect "make gcc-wall"
> probably would have turned up this typo as well.
>
> I'll fix this in my tree on the pu branch; I'm still looking over the
> rest of the patches, but I thought it would be good to point this out
> first.
Oops, it's my fault. Thanks for pointing it out.
Regards,
Zheng
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH 17/21 v5] e2fsck: check inline_data in pass1
2012-09-22 4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
` (15 preceding siblings ...)
2012-09-22 4:01 ` [PATCH 16/21 v5] e2fsck: add problem descriptions and check inline data feature Zheng Liu
@ 2012-09-22 4:01 ` Zheng Liu
2012-09-22 4:01 ` [PATCH 18/21 v5] e2fsck: check inline_data in pass2 Zheng Liu
` (3 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22 4:01 UTC (permalink / raw)
To: linux-ext4; +Cc: tytso, Zheng Liu
From: Zheng Liu <wenqing.lz@taobao.com>
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
e2fsck/pass1.c | 71 ++++++++++++++++++++++++++++++++++++++++++++--
lib/ext2fs/dblist_dir.c | 10 +++++-
2 files changed, 75 insertions(+), 6 deletions(-)
diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index 1a12ed3..41352c7 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -202,6 +202,16 @@ int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino,
return i;
}
+ if (inode->i_flags & EXT4_INLINE_DATA_FL) {
+ int inline_size;
+
+ inline_size = ext2fs_get_inline_data_size(fs, ino);
+ if (inline_size == inode->i_size)
+ return 1;
+ else
+ return 0;
+ }
+
blocks = ext2fs_inode_data_blocks2(fs, inode);
if (blocks) {
if ((inode->i_size >= fs->blocksize) ||
@@ -304,6 +314,16 @@ static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx)
goto fix;
}
+ /*
+ * Don't do the following checks for inline_data because
+ * other checks ensure that the content of inline data
+ * is corrent.
+ */
+ if (strncmp(EXT2_EXT_ATTR_NAME(entry),
+ EXT4_EXT_ATTR_SYSTEM_DATA,
+ strlen(EXT4_EXT_ATTR_SYSTEM_DATA)) == 0)
+ goto next;
+
/* attribute len eats this space */
remain -= EXT2_EXT_ATTR_SIZE(entry->e_name_len);
@@ -331,6 +351,7 @@ static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx)
goto fix;
}
+next:
remain -= entry->e_value_size;
entry = EXT2_EXT_ATTR_NEXT(entry);
@@ -408,6 +429,7 @@ static void check_is_really_dir(e2fsck_t ctx, struct problem_context *pctx,
blk64_t blk;
unsigned int i, rec_len, not_device = 0;
int extent_fs;
+ int inlinedata_fs;
/*
* If the mode looks OK, we believe it. If the first block in
@@ -435,11 +457,19 @@ static void check_is_really_dir(e2fsck_t ctx, struct problem_context *pctx,
* For extent mapped files, we don't do any sanity checking:
* just try to get the phys block of logical block 0 and run
* with it.
+ *
+ * For inline_data files, we just skip it because, in e2fsck
+ * pass1, we cannot get parent inode of a inode. So we have
+ * no way to determine the inode is a directory or not.
*/
extent_fs = (ctx->fs->super->s_feature_incompat &
EXT3_FEATURE_INCOMPAT_EXTENTS);
- if (extent_fs && (inode->i_flags & EXT4_EXTENTS_FL)) {
+ inlinedata_fs = (ctx->fs->super->s_feature_incompat &
+ EXT4_FEATURE_INCOMPAT_INLINE_DATA);
+ if (inlinedata_fs && (inode->i_flags & EXT4_INLINE_DATA_FL))
+ return;
+ else if (extent_fs && (inode->i_flags & EXT4_EXTENTS_FL)) {
/* extent mapped */
if (ext2fs_bmap2(ctx->fs, pctx->ino, inode, 0, 0, 0, 0,
&blk))
@@ -1206,7 +1236,8 @@ void e2fsck_pass1(e2fsck_t ctx)
ctx->fs_sockets_count++;
} else
mark_inode_bad(ctx, ino);
- if (!(inode->i_flags & EXT4_EXTENTS_FL)) {
+ if (!(inode->i_flags & EXT4_EXTENTS_FL) &&
+ !(inode->i_flags & EXT4_INLINE_DATA_FL)) {
if (inode->i_block[EXT2_IND_BLOCK])
ctx->fs_ind_count++;
if (inode->i_block[EXT2_DIND_BLOCK])
@@ -1215,6 +1246,7 @@ void e2fsck_pass1(e2fsck_t ctx)
ctx->fs_tind_count++;
}
if (!(inode->i_flags & EXT4_EXTENTS_FL) &&
+ !(inode->i_flags & EXT4_INLINE_DATA_FL) &&
(inode->i_block[EXT2_IND_BLOCK] ||
inode->i_block[EXT2_DIND_BLOCK] ||
inode->i_block[EXT2_TIND_BLOCK] ||
@@ -2099,6 +2131,28 @@ static void check_blocks_extents(e2fsck_t ctx, struct problem_context *pctx,
}
/*
+ * In fact we needn't check blocks for a inode that has inline data because
+ * this inode doesn't have any blocks. In this function, all we need to do
+ * is add this inode into dblist when it is a directory.
+ */
+static void check_blocks_inline_data(e2fsck_t ctx,
+ struct problem_context *pctx,
+ struct process_block_struct *pb)
+{
+ if (!pb->is_dir)
+ return;
+
+ pctx->errcode = ext2fs_add_dir_block2(ctx->fs->dblist,
+ pb->ino, 0, 0);
+ if (pctx->errcode) {
+ pctx->blk = 0;
+ pctx->num = 0;
+ fix_problem(ctx, PR_1_ADD_DBLOCK, pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ }
+}
+
+/*
* This subroutine is called on each inode to account for all of the
* blocks used by that inode.
*/
@@ -2112,6 +2166,7 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
int bad_size = 0;
int dirty_inode = 0;
int extent_fs;
+ int inlinedata_fs;
__u64 size;
pb.ino = ino;
@@ -2135,6 +2190,8 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
extent_fs = (ctx->fs->super->s_feature_incompat &
EXT3_FEATURE_INCOMPAT_EXTENTS);
+ inlinedata_fs = (ctx->fs->super->s_feature_incompat &
+ EXT4_FEATURE_INCOMPAT_INLINE_DATA);
if (inode->i_flags & EXT2_COMPRBLK_FL) {
if (fs->super->s_feature_incompat &
@@ -2158,6 +2215,9 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
if (ext2fs_inode_has_valid_blocks2(fs, inode)) {
if (extent_fs && (inode->i_flags & EXT4_EXTENTS_FL))
check_blocks_extents(ctx, pctx, &pb);
+ else if (inlinedata_fs &&
+ (inode->i_flags & EXT4_INLINE_DATA_FL))
+ check_blocks_inline_data(ctx, pctx, &pb);
else {
pctx->errcode = ext2fs_block_iterate3(fs, ino,
pb.is_dir ? BLOCK_FLAG_HOLE : 0,
@@ -2200,7 +2260,8 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
}
}
- if (!pb.num_blocks && pb.is_dir) {
+ if (!pb.num_blocks && pb.is_dir &&
+ !(inode->i_flags & EXT4_INLINE_DATA_FL)) {
if (fix_problem(ctx, PR_1_ZERO_LENGTH_DIR, pctx)) {
e2fsck_clear_inode(ctx, ino, inode, 0, "check_blocks");
ctx->fs_directory_count--;
@@ -2226,7 +2287,9 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
#endif
if (pb.is_dir) {
int nblock = inode->i_size >> EXT2_BLOCK_SIZE_BITS(fs->super);
- if (inode->i_size & (fs->blocksize - 1))
+ if (inode->i_flags & EXT4_INLINE_DATA_FL)
+ ;
+ else if (inode->i_size & (fs->blocksize - 1))
bad_size = 5;
else if (nblock > (pb.last_block + 1))
bad_size = 1;
diff --git a/lib/ext2fs/dblist_dir.c b/lib/ext2fs/dblist_dir.c
index d4d5111..6282ab4 100644
--- a/lib/ext2fs/dblist_dir.c
+++ b/lib/ext2fs/dblist_dir.c
@@ -72,8 +72,14 @@ static int db_dir_proc(ext2_filsys fs, struct ext2_db_entry2 *db_info,
ctx->dir = db_info->ino;
ctx->errcode = 0;
- ret = ext2fs_process_dir_block(fs, &db_info->blk,
- db_info->blockcnt, 0, 0, priv_data);
+ if (ext2fs_inode_has_inline_data(fs, ctx->dir))
+ ret = ext2fs_inline_data_iterate(fs, ctx->dir, 0, 0,
+ ext2fs_process_dir_inline_data,
+ priv_data);
+ else
+ ret = ext2fs_process_dir_block(fs, &db_info->blk,
+ db_info->blockcnt,
+ 0, 0, priv_data);
if ((ret & BLOCK_ABORT) && !ctx->errcode)
return DBLIST_ABORT;
return 0;
--
1.7.4.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 18/21 v5] e2fsck: check inline_data in pass2
2012-09-22 4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
` (16 preceding siblings ...)
2012-09-22 4:01 ` [PATCH 17/21 v5] e2fsck: check inline_data in pass1 Zheng Liu
@ 2012-09-22 4:01 ` Zheng Liu
2012-09-22 4:01 ` [PATCH 19/21 v5] e2fsck: check inline_data in pass3 Zheng Liu
` (2 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22 4:01 UTC (permalink / raw)
To: linux-ext4; +Cc: tytso, Zheng Liu
From: Zheng Liu <wenqing.lz@taobao.com>
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
e2fsck/pass2.c | 123 +++++++++++++++++++++++++++++++++++++++++++-------------
1 files changed, 95 insertions(+), 28 deletions(-)
diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c
index e28af61..fd48ca5 100644
--- a/e2fsck/pass2.c
+++ b/e2fsck/pass2.c
@@ -725,6 +725,15 @@ static void salvage_directory(ext2_filsys fs,
}
}
+static int is_last_entry(ext2_filsys fs, ext2_ino_t ino,
+ unsigned int offset, int csum_size)
+{
+ if (ext2fs_inode_has_inline_data(fs, ino))
+ return (offset < ext2fs_get_inline_data_size(fs, ino));
+ else
+ return (offset < fs->blocksize - csum_size);
+}
+
static int check_dir_block(ext2_filsys fs,
struct ext2_db_entry2 *db,
void *priv_data)
@@ -733,7 +742,7 @@ static int check_dir_block(ext2_filsys fs,
#ifdef ENABLE_HTREE
struct dx_dirblock_info *dx_db = 0;
#endif /* ENABLE_HTREE */
- struct ext2_dir_entry *dirent, *prev;
+ struct ext2_dir_entry *dirent, *prev, dot, dotdot;
ext2_dirhash_t hash;
unsigned int offset = 0;
int dir_modified = 0;
@@ -756,6 +765,8 @@ static int check_dir_block(ext2_filsys fs,
int dx_csum_size = 0, de_csum_size = 0;
int failed_csum = 0;
int is_leaf = 1;
+ int inline_data = 0;
+ int filetype = 0;
cd = (struct check_dir_struct *) priv_data;
buf = cd->buf;
@@ -773,6 +784,10 @@ static int check_dir_block(ext2_filsys fs,
de_csum_size = sizeof(struct ext2_dir_entry_tail);
}
+ if (EXT2_HAS_INCOMPAT_FEATURE(fs->super,
+ EXT2_FEATURE_INCOMPAT_FILETYPE))
+ filetype = EXT2_FT_DIR << 8;
+
/*
* Make sure the inode is still in use (could have been
* deleted in the duplicate/bad blocks pass.
@@ -787,7 +802,11 @@ static int check_dir_block(ext2_filsys fs,
cd->pctx.dirent = 0;
cd->pctx.num = 0;
- if (db->blk == 0) {
+ if (EXT2_HAS_INCOMPAT_FEATURE(fs->super,
+ EXT4_FEATURE_INCOMPAT_INLINE_DATA))
+ inline_data = ext2fs_inode_has_inline_data(fs, ino);
+
+ if (db->blk == 0 && !inline_data) {
if (allocate_dir_block(ctx, db, buf, &cd->pctx))
return 0;
block_nr = db->blk;
@@ -808,7 +827,11 @@ static int check_dir_block(ext2_filsys fs,
#endif
ehandler_operation(_("reading directory block"));
- cd->pctx.errcode = ext2fs_read_dir_block4(fs, block_nr, buf, 0, ino);
+ if (inline_data)
+ cd->pctx.errcode = ext2fs_read_inline_data(fs, ino, buf);
+ else
+ cd->pctx.errcode = ext2fs_read_dir_block4(fs, block_nr,
+ buf, 0, ino);
ehandler_operation(0);
if (cd->pctx.errcode == EXT2_ET_DIR_CORRUPTED)
cd->pctx.errcode = 0; /* We'll handle this ourselves */
@@ -879,7 +902,7 @@ out_htree:
#endif /* ENABLE_HTREE */
/* Verify checksum. */
- if (is_leaf && de_csum_size) {
+ if (is_leaf && de_csum_size && !inline_data) {
/* No space for csum? Rebuild dirs in pass 3A. */
if (!ext2fs_dirent_has_tail(fs, (struct ext2_dir_entry *)buf)) {
de_csum_size = 0;
@@ -917,20 +940,44 @@ skip_checksum:
ext2_ino_t first_unused_inode;
problem = 0;
- dirent = (struct ext2_dir_entry *) (buf + offset);
- (void) ext2fs_get_rec_len(fs, dirent, &rec_len);
- cd->pctx.dirent = dirent;
- cd->pctx.num = offset;
- if (((offset + rec_len) > fs->blocksize) ||
- (rec_len < 12) ||
- ((rec_len % 4) != 0) ||
- (((dirent->name_len & (unsigned) 0xFF)+8) > rec_len)) {
- if (fix_problem(ctx, PR_2_DIR_CORRUPTED, &cd->pctx)) {
- salvage_directory(fs, dirent, prev, &offset);
- dir_modified++;
- continue;
- } else
- goto abort_free_dict;
+ if (!inline_data || dot_state > 1) {
+ dirent = (struct ext2_dir_entry *) (buf + offset);
+ (void) ext2fs_get_rec_len(fs, dirent, &rec_len);
+ cd->pctx.dirent = dirent;
+ cd->pctx.num = offset;
+ if (((offset + rec_len) > fs->blocksize) ||
+ (rec_len < 12) ||
+ ((rec_len % 4) != 0) ||
+ (((dirent->name_len & (unsigned) 0xFF)+8) > rec_len)) {
+ if (fix_problem(ctx, PR_2_DIR_CORRUPTED, &cd->pctx)) {
+ salvage_directory(fs, dirent, prev, &offset);
+ dir_modified++;
+ continue;
+ } else
+ goto abort_free_dict;
+ }
+ } else {
+ if (dot_state == 0) {
+ memset(&dot, 0, sizeof(dot));
+ dirent = ˙
+ dirent->inode = ino;
+ dirent->rec_len = EXT2_DIR_REC_LEN(1);
+ dirent->name_len = 1 | filetype;
+ dirent->name[0] = '.';
+ } else if (dot_state == 1) {
+ memset(&dotdot, 0, sizeof(dotdot));
+ dirent = &dotdot;
+ dirent->inode =
+ ((struct ext2_dir_entry *)buf)->inode;
+ dirent->rec_len = EXT2_DIR_REC_LEN(2);
+ dirent->name_len = 2 | filetype;
+ dirent->name[0] = '.';
+ dirent->name[1] = '.';
+ } else {
+ fatal_error(ctx, _("Can not continue."));
+ }
+ cd->pctx.dirent = dirent;
+ cd->pctx.num = offset;
}
if (dot_state == 0) {
@@ -1171,9 +1218,14 @@ skip_checksum:
prev = dirent;
if (dir_modified)
(void) ext2fs_get_rec_len(fs, dirent, &rec_len);
- offset += rec_len;
+ if (!inline_data || dot_state > 1) {
+ offset += rec_len;
+ } else {
+ if (dot_state == 1)
+ offset = 4;
+ }
dot_state++;
- } while (offset < fs->blocksize - de_csum_size);
+ } while (is_last_entry(fs, ino, offset, de_csum_size));
#if 0
printf("\n");
#endif
@@ -1191,12 +1243,23 @@ skip_checksum:
}
#endif /* ENABLE_HTREE */
- if (offset != fs->blocksize - de_csum_size) {
- cd->pctx.num = rec_len - (fs->blocksize - de_csum_size) +
- offset;
- if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) {
- dirent->rec_len = cd->pctx.num;
- dir_modified++;
+ if (inline_data) {
+ if (offset != ext2fs_get_inline_data_size(fs, ino)) {
+ cd->pctx.num = rec_len + offset -
+ ext2fs_get_inline_data_size(fs, ino);
+ if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) {
+ dirent->rec_len = cd->pctx.num;
+ dir_modified++;
+ }
+ }
+ } else {
+ if (offset != fs->blocksize - de_csum_size) {
+ cd->pctx.num = rec_len - (fs->blocksize - de_csum_size) +
+ offset;
+ if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) {
+ dirent->rec_len = cd->pctx.num;
+ dir_modified++;
+ }
}
}
if (dir_modified) {
@@ -1210,8 +1273,12 @@ skip_checksum:
write_and_fix:
if (e2fsck_dir_will_be_rehashed(ctx, ino))
ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
- cd->pctx.errcode = ext2fs_write_dir_block4(fs, block_nr, buf,
- 0, ino);
+ if (inline_data)
+ cd->pctx.errcode = ext2fs_write_inline_data(fs, ino,
+ buf);
+ else
+ cd->pctx.errcode = ext2fs_write_dir_block4(fs, block_nr,
+ buf, 0, ino);
if (e2fsck_dir_will_be_rehashed(ctx, ino))
ctx->fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
if (cd->pctx.errcode) {
--
1.7.4.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 19/21 v5] e2fsck: check inline_data in pass3
2012-09-22 4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
` (17 preceding siblings ...)
2012-09-22 4:01 ` [PATCH 18/21 v5] e2fsck: check inline_data in pass2 Zheng Liu
@ 2012-09-22 4:01 ` Zheng Liu
2012-09-22 4:01 ` [PATCH 20/21 v5] tests: change result in f_bad_disconnected_inode Zheng Liu
2012-09-22 4:01 ` [PATCH 21/21 v5] mke2fs: enable inline_data feature on ext4dev filesystem Zheng Liu
20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22 4:01 UTC (permalink / raw)
To: linux-ext4; +Cc: tytso, Zheng Liu
From: Zheng Liu <wenqing.lz@taobao.com>
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
e2fsck/pass3.c | 8 ++++++++
e2fsck/rehash.c | 3 ++-
2 files changed, 10 insertions(+), 1 deletions(-)
diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c
index a379e9b..85b3f65 100644
--- a/e2fsck/pass3.c
+++ b/e2fsck/pass3.c
@@ -787,6 +787,14 @@ errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
es.ctx = ctx;
es.dir = dir;
+ if (ext2fs_inode_has_inline_data(fs, dir)) {
+ retval = ext2fs_convert_inline_data(fs, dir, &es);
+ if (retval)
+ return retval;
+
+ return 0;
+ }
+
retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND,
0, expand_dir_proc, &es);
diff --git a/e2fsck/rehash.c b/e2fsck/rehash.c
index 347f1b0..a54c6b4 100644
--- a/e2fsck/rehash.c
+++ b/e2fsck/rehash.c
@@ -940,7 +940,8 @@ void e2fsck_rehash_directories(e2fsck_t ctx)
#if 0
fix_problem(ctx, PR_3A_OPTIMIZE_DIR, &pctx);
#endif
- pctx.errcode = e2fsck_rehash_dir(ctx, ino);
+ if (!ext2fs_inode_has_inline_data(ctx->fs, ino))
+ pctx.errcode = e2fsck_rehash_dir(ctx, ino);
if (pctx.errcode) {
end_problem_latch(ctx, PR_LATCH_OPTIMIZE_DIR);
fix_problem(ctx, PR_3A_OPTIMIZE_DIR_ERR, &pctx);
--
1.7.4.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 20/21 v5] tests: change result in f_bad_disconnected_inode
2012-09-22 4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
` (18 preceding siblings ...)
2012-09-22 4:01 ` [PATCH 19/21 v5] e2fsck: check inline_data in pass3 Zheng Liu
@ 2012-09-22 4:01 ` Zheng Liu
2012-09-22 4:01 ` [PATCH 21/21 v5] mke2fs: enable inline_data feature on ext4dev filesystem Zheng Liu
20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22 4:01 UTC (permalink / raw)
To: linux-ext4; +Cc: tytso, Zheng Liu
From: Zheng Liu <wenqing.lz@taobao.com>
In this test, inode flag is some random data, and when we apply inline data
patch set we should need to handle it.
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
tests/f_bad_disconnected_inode/expect.1 | 9 +++++++++
1 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/tests/f_bad_disconnected_inode/expect.1 b/tests/f_bad_disconnected_inode/expect.1
index 11862f6..9f9b447 100644
--- a/tests/f_bad_disconnected_inode/expect.1
+++ b/tests/f_bad_disconnected_inode/expect.1
@@ -2,9 +2,18 @@ Pass 1: Checking inodes, blocks, and sizes
Inode 1 has EXTENTS_FL flag set on filesystem without extents support.
Clear? yes
+Inode 14 has INLINE_DATA_FL flag on filesystem without inline data support.
+Clear? yes
+
+Inode 15 has INLINE_DATA_FL flag on filesystem without inline data support.
+Clear? yes
+
Inode 15 has EXTENTS_FL flag set on filesystem without extents support.
Clear? yes
+Inode 16 has INLINE_DATA_FL flag on filesystem without inline data support.
+Clear? yes
+
Inode 16 has EXTENTS_FL flag set on filesystem without extents support.
Clear? yes
--
1.7.4.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 21/21 v5] mke2fs: enable inline_data feature on ext4dev filesystem
2012-09-22 4:00 [PATCH 00/21 v5] e2fsprogs: make e2fsprogs support inline data Zheng Liu
` (19 preceding siblings ...)
2012-09-22 4:01 ` [PATCH 20/21 v5] tests: change result in f_bad_disconnected_inode Zheng Liu
@ 2012-09-22 4:01 ` Zheng Liu
20 siblings, 0 replies; 24+ messages in thread
From: Zheng Liu @ 2012-09-22 4:01 UTC (permalink / raw)
To: linux-ext4; +Cc: tytso, Zheng Liu
From: Zheng Liu <wenqing.lz@taobao.com>
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
misc/mke2fs.conf.in | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/misc/mke2fs.conf.in b/misc/mke2fs.conf.in
index 178733f..4c5dba7 100644
--- a/misc/mke2fs.conf.in
+++ b/misc/mke2fs.conf.in
@@ -16,7 +16,7 @@
inode_size = 256
}
ext4dev = {
- features = has_journal,extent,huge_file,flex_bg,metadata_csum,64bit,dir_nlink,extra_isize
+ features = has_journal,extent,huge_file,flex_bg,metadata_csum,inline_data,64bit,dir_nlink,extra_isize
inode_size = 256
options = test_fs=1
}
--
1.7.4.1
^ permalink raw reply related [flat|nested] 24+ messages in thread