[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1324219484-22443-4-git-send-email-wenqing.lz@taobao.com>
Date: Sun, 18 Dec 2011 22:44:42 +0800
From: Zheng Liu <gnehzuil.liu@...il.com>
To: linux-ext4@...r.kernel.org
Cc: Zheng Liu <wenqing.lz@...bao.com>
Subject: [PATCH 3/5] debugfs: make debugfs to support inline data
From: Zheng Liu <wenqing.lz@...bao.com>
Let debugfs to support inline data in read-only mode.
Signed-off-by: Zheng Liu <wenqing.lz@...bao.com>
---
debugfs/debugfs.c | 4 +
debugfs/dump.c | 26 +++++
debugfs/htree.c | 6 +-
lib/ext2fs/Makefile.in | 5 +
lib/ext2fs/Makefile.pq | 1 +
lib/ext2fs/block.c | 15 +++
lib/ext2fs/ext2_ext_attr.h | 4 +
lib/ext2fs/ext2_fs.h | 8 ++
lib/ext2fs/ext2fs.h | 11 ++
lib/ext2fs/inline_data.c | 224 ++++++++++++++++++++++++++++++++++++++++++++
10 files changed, 302 insertions(+), 2 deletions(-)
create mode 100644 lib/ext2fs/inline_data.c
diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c
index b7ff00d..c7837ed 100644
--- a/debugfs/debugfs.c
+++ b/debugfs/debugfs.c
@@ -800,6 +800,10 @@ void internal_dump_inode(FILE *out, const char *prefix,
if (inode->i_dtime)
fprintf(out, "%sdtime: 0x%08x -- %s", prefix, inode->i_dtime,
time_to_string(inode->i_dtime));
+ if (inode->i_flags & EXT4_INLINE_DATA_FL) {
+ fprintf(out, "Inode has inline data\n");
+ return;
+ }
if (EXT2_INODE_SIZE(current_fs->super) > EXT2_GOOD_OLD_INODE_SIZE)
internal_dump_inode_extra(out, prefix, inode_num,
(struct ext2_inode_large *) inode);
diff --git a/debugfs/dump.c b/debugfs/dump.c
index a15a0b7..d56f869 100644
--- a/debugfs/dump.c
+++ b/debugfs/dump.c
@@ -113,6 +113,32 @@ static void dump_file(const char *cmdname, ext2_ino_t ino, int fd,
if (debugfs_read_inode(ino, &inode, cmdname))
return;
+ if (inode.i_flags & EXT4_INLINE_DATA_FL) {
+ struct ext2_inode *large_inode;
+ struct inline_data idata;
+ void *inline_start;
+ int inline_size;
+
+ large_inode = (struct ext2_inode *)
+ malloc(EXT2_INODE_SIZE(current_fs->super));
+ ext2fs_read_inode_full(current_fs, ino, large_inode,
+ EXT2_INODE_SIZE(current_fs->super));
+ write(fd, large_inode->i_block, EXT4_MIN_INLINE_DATA_SIZE);
+
+ ext2fs_iget_extra_inode(current_fs, large_inode, &idata);
+ if (idata.inline_off == 0 ||
+ idata.inline_size == EXT4_MIN_INLINE_DATA_SIZE)
+ goto out;
+
+ inline_start = ext2fs_get_inline_xattr_pos(large_inode, &idata);
+ inline_size = idata.inline_size - EXT4_MIN_INLINE_DATA_SIZE;
+ write(fd, inline_start, inline_size);
+
+out:
+ free(large_inode);
+ return;
+ }
+
retval = ext2fs_file_open(current_fs, ino, 0, &e2_file);
if (retval) {
com_err(cmdname, retval, "while opening ext2 file");
diff --git a/debugfs/htree.c b/debugfs/htree.c
index 05745eb..9a850f6 100644
--- a/debugfs/htree.c
+++ b/debugfs/htree.c
@@ -354,8 +354,10 @@ void do_dirsearch(int argc, char *argv[])
pb.search_name = argv[2];
pb.len = strlen(pb.search_name);
- ext2fs_block_iterate3(current_fs, inode, BLOCK_FLAG_READ_ONLY, 0,
- search_dir_block, &pb);
+ if (ext2fs_search_dir_inline_data(current_fs,
+ inode, argv[2], strlen(argv[2])) != 0)
+ ext2fs_block_iterate3(current_fs, inode, BLOCK_FLAG_READ_ONLY, 0,
+ search_dir_block, &pb);
free(pb.buf);
}
diff --git a/lib/ext2fs/Makefile.in b/lib/ext2fs/Makefile.in
index a9795a3..6fd35d9 100644
--- a/lib/ext2fs/Makefile.in
+++ b/lib/ext2fs/Makefile.in
@@ -57,6 +57,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 \
@@ -127,6 +128,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 \
@@ -687,6 +689,9 @@ inline.o: $(srcdir)/inline.c $(top_builddir)/lib/config.h \
$(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
$(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
$(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
+inline_data.o: $(srcdir)/inline_data.c $(top_builddir)/lib/config.h \
+ $(srcdir)/ext2_fs.h $(srcdir)/ext2fs.h $(srcdir)/ext2_ext_attr.h \
+ $(srcdir)/ext2fsP.h
inode.o: $(srcdir)/inode.c $(top_builddir)/lib/config.h \
$(top_builddir)/lib/dirpaths.h $(srcdir)/ext2_fs.h \
$(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fsP.h \
diff --git a/lib/ext2fs/Makefile.pq b/lib/ext2fs/Makefile.pq
index 2f7b654..89082a7 100644
--- a/lib/ext2fs/Makefile.pq
+++ b/lib/ext2fs/Makefile.pq
@@ -27,6 +27,7 @@ OBJS= alloc.obj \
icount.obj \
initialize.obj \
inline.obj \
+ inline_data.obj \
inode.obj \
ismounted.obj \
link.obj \
diff --git a/lib/ext2fs/block.c b/lib/ext2fs/block.c
index 6a5c10d..92083f9 100644
--- a/lib/ext2fs/block.c
+++ b/lib/ext2fs/block.c
@@ -387,6 +387,21 @@ errcode_t ext2fs_block_iterate3(ext2_filsys fs,
}
}
+ if (inode.i_flags & EXT4_INLINE_DATA_FL) {
+ struct ext2_inode *large_inode;
+
+ large_inode = (struct ext2_inode *)
+ malloc(EXT2_INODE_SIZE(fs->super));
+ ext2fs_read_inode_full(fs, ino, large_inode,
+ EXT2_INODE_SIZE(fs->super));
+ ret = ext2fs_find_inline_entry(fs, large_inode, priv_data);
+ free(large_inode);
+ if (ret & BLOCK_ABORT)
+ goto abort_exit;
+ else
+ goto errout;
+ }
+
if (inode.i_flags & EXT4_EXTENTS_FL) {
ext2_extent_handle_t handle;
struct ext2fs_extent extent;
diff --git a/lib/ext2fs/ext2_ext_attr.h b/lib/ext2fs/ext2_ext_attr.h
index ed548d1..78ef7fc 100644
--- a/lib/ext2fs/ext2_ext_attr.h
+++ b/lib/ext2fs/ext2_ext_attr.h
@@ -23,6 +23,10 @@ struct ext2_ext_attr_header {
__u32 h_reserved[4]; /* zero right now */
};
+struct ext2_ext_attr_ibody_header {
+ __u32 h_magic;
+};
+
struct ext2_ext_attr_entry {
__u8 e_name_len; /* length of name */
__u8 e_name_index; /* attribute name index */
diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
index 0a37b57..c7a8380 100644
--- a/lib/ext2fs/ext2_fs.h
+++ b/lib/ext2fs/ext2_fs.h
@@ -300,6 +300,7 @@ struct ext2_dx_countlimit {
#define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */
#define EXT4_EA_INODE_FL 0x00200000 /* Inode used for large EA */
#define EXT4_EOFBLOCKS_FL 0x00400000 /* Blocks allocated beyond EOF */
+#define EXT4_INLINE_DATA_FL 0x00800000 /* Inode has inline data */
#define EXT4_SNAPFILE_FL 0x01000000 /* Inode is a snapshot */
#define EXT4_SNAPFILE_DELETED_FL 0x04000000 /* Snapshot is being deleted */
#define EXT4_SNAPFILE_SHRUNK_FL 0x08000000 /* Snapshot shrink has completed */
@@ -852,4 +853,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 8b94ad0..c17922e 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -1223,6 +1223,17 @@ extern errcode_t ext2fs_initialize(const char *name, int flags,
struct ext2_super_block *param,
io_manager manager, ext2_filsys *ret_fs);
+/* inline_data.c */
+extern errcode_t ext2fs_find_inline_entry(ext2_filsys fs,
+ struct ext2_inode *inode,
+ void *priv_data);
+extern errcode_t ext2fs_search_dir_inline_data(ext2_filsys fs, ext2_ino_t ino,
+ char *search_name, int len);
+extern void *ext2fs_get_inline_xattr_pos(struct ext2_inode *inode,
+ struct inline_data *idata);
+extern void ext2fs_iget_extra_inode(ext2_filsys fs, struct ext2_inode *inode,
+ struct inline_data *idata);
+
/* icount.c */
extern void ext2fs_free_icount(ext2_icount_t icount);
extern errcode_t ext2fs_create_icount_tdb(ext2_filsys fs, char *tdb_dir,
diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c
new file mode 100644
index 0000000..dcf33f9
--- /dev/null
+++ b/lib/ext2fs/inline_data.c
@@ -0,0 +1,224 @@
+/*
+ * inline_data.c --- inode allocates inline data
+ *
+ * Copyright (C) 2011 Zheng Liu <wenqing.lz@...bao.com>
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Libaray
+ * General Public License, version 2.
+ * %End-Header%
+ */
+
+#include "config.h"
+#include <stdio.h>
+
+#include "ext2_fs.h"
+#include "ext2_ext_attr.h"
+
+#include "ext2fs.h"
+#include "ext2fsP.h"
+
+#define EXT4_XATTR_INDEX_SYSTEM_DATA 7
+#define EXT4_XATTR_SYSTEM_DATA_NAME "data"
+
+static int search_dir(ext2_filsys fs, char *start, int size, void *priv_data)
+{
+ struct dir_context *ctx = (struct dir_context *) priv_data;
+ struct ext2_dir_entry *dirent;
+ unsigned int rec_len;
+ int ret;
+ int do_abort = 0;
+ char *dlimit;
+
+ dirent = (struct ext2_dir_entry *) start;
+ dlimit = start + size;
+
+ while ((char *) dirent < dlimit) {
+ if (ext2fs_get_rec_len(fs, dirent, &rec_len))
+ return BLOCK_ABORT;
+ ret = (ctx->func)(ctx->dir, 0, dirent,
+ 0, fs->blocksize, ctx->buf,
+ ctx->priv_data);
+ if (ret & DIRENT_ABORT) {
+ do_abort++;
+ break;
+ }
+ dirent = (struct ext2_dir_entry *) ((char *) dirent + rec_len);
+ }
+
+ if (do_abort)
+ return BLOCK_ABORT;
+
+ return 0;
+}
+
+static int search_dir2(ext2_filsys fs, char *start, int size,
+ char *search_name, int len)
+{
+ struct ext2_dir_entry *dirent;
+ unsigned int rec_len;
+ int ret;
+ int do_abort = 0;
+ char *dlimit;
+
+ dirent = (struct ext2_dir_entry *) start;
+ dlimit = start + size;
+
+ while ((char *) dirent < dlimit) {
+ if (ext2fs_get_rec_len(fs, dirent, &rec_len))
+ return BLOCK_ABORT;
+ if (dirent->inode &&
+ len == (dirent->name_len & 0xFF) &&
+ strncmp(search_name, dirent->name,
+ len) == 0) {
+ printf("Entry found at inline data\n");
+ break;
+ }
+ dirent = (struct ext2_dir_entry *) ((char *) dirent + rec_len);
+ }
+
+ return 0;
+}
+
+void ext2fs_iget_extra_inode(ext2_filsys fs, struct ext2_inode *inode,
+ struct inline_data *idata)
+{
+ struct ext2_inode_large *large_inode;
+ struct ext2_ext_attr_entry *entry;
+ __u32 *magic;
+ char *start, *end;
+ int cmp;
+ unsigned int storage_size;
+
+ large_inode = (struct ext2_inode_large *) inode;
+ idata->inline_off = 0;
+ if (large_inode->i_extra_isize > EXT2_INODE_SIZE(fs->super) -
+ EXT2_GOOD_OLD_INODE_SIZE) {
+ fprintf(stderr, "invalid inode->i_extra_isize (%u)\n",
+ large_inode->i_extra_isize);
+ return;
+ }
+ storage_size = EXT2_INODE_SIZE(fs->super) -
+ EXT2_GOOD_OLD_INODE_SIZE -
+ large_inode->i_extra_isize;
+ magic = (__u32 *)((char *)large_inode + EXT2_GOOD_OLD_INODE_SIZE +
+ large_inode->i_extra_isize);
+ if (*magic == EXT2_EXT_ATTR_MAGIC) {
+ end = (char *) large_inode + EXT2_INODE_SIZE(fs->super);
+ start = (char *) magic + sizeof(__u32);
+ entry = (struct ext2_ext_attr_entry *) start;
+ while (!EXT2_EXT_IS_LAST_ENTRY(entry)) {
+ struct ext2_ext_attr_entry *next =
+ EXT2_EXT_ATTR_NEXT(entry);
+ if (entry->e_value_size > storage_size ||
+ (char *) next >= end) {
+ fprintf(stderr, "invalid inline data\n");
+ return;
+ }
+ cmp = EXT4_XATTR_INDEX_SYSTEM_DATA - entry->e_name_index;
+ if (!cmp)
+ cmp = strlen(EXT4_XATTR_SYSTEM_DATA_NAME) -
+ entry->e_name_len;
+ if (!cmp)
+ cmp = memcmp(EXT4_XATTR_SYSTEM_DATA_NAME,
+ EXT2_EXT_ATTR_NAME(entry),
+ strlen(EXT4_XATTR_SYSTEM_DATA_NAME));
+ if (cmp == 0)
+ break;
+
+ entry = next;
+ }
+
+ if (cmp == 0) {
+ idata->inline_off = (__u16)((void *) entry -
+ (void *) large_inode);
+ idata->inline_size = EXT4_MIN_INLINE_DATA_SIZE +
+ entry->e_value_size;
+ }
+ }
+}
+
+void *ext2fs_get_inline_xattr_pos(struct ext2_inode *inode,
+ struct inline_data *idata)
+{
+ struct ext2_inode_large *large_inode;
+ struct ext2_ext_attr_entry *entry;
+ struct ext2_ext_attr_ibody_header *header;
+
+ large_inode = (struct ext2_inode_large *) inode;
+ header = (struct ext2_ext_attr_ibody_header *)
+ ((void *)large_inode +
+ EXT2_GOOD_OLD_INODE_SIZE +
+ large_inode->i_extra_isize);
+ entry = (struct ext2_ext_attr_entry *)((void *)large_inode +
+ idata->inline_off);
+
+ return (void *)((struct ext2_ext_attr_header *)((header)+1)) +
+ entry->e_value_offs;
+}
+
+errcode_t ext2fs_find_inline_entry(ext2_filsys fs, struct ext2_inode *inode,
+ void *priv_data)
+{
+ struct inline_data idata;
+ void *inline_start;
+ int inline_size;
+ int ret = 0;
+
+ inline_start = inode->i_block;
+ inline_size = EXT4_MIN_INLINE_DATA_SIZE;
+ ret = search_dir(fs, inline_start, inline_size, priv_data);
+ if (ret)
+ return ret;
+
+ ext2fs_iget_extra_inode(fs, inode, &idata);
+ if (idata.inline_off == 0 ||
+ idata.inline_size == EXT4_MIN_INLINE_DATA_SIZE)
+ return -1;
+
+ inline_start = ext2fs_get_inline_xattr_pos(inode, &idata);
+ inline_size = idata.inline_size - EXT4_MIN_INLINE_DATA_SIZE;
+ ret = search_dir(fs, inline_start, inline_size, priv_data);
+
+ return 0;
+}
+
+errcode_t ext2fs_search_dir_inline_data(ext2_filsys fs, ext2_ino_t ino,
+ char *search_name, int len)
+{
+ struct ext2_inode *inode;
+ struct ext2_dir_entry *dirent;
+ struct inline_data idata;
+ unsigned int rec_len;
+ char *dlimit;
+ void *start;
+ int size;
+ int ret = 0;
+
+ inode = (struct ext2_inode *) malloc(EXT2_INODE_SIZE(fs->super));
+ ext2fs_read_inode_full(fs, ino, inode,
+ EXT2_INODE_SIZE(fs->super));
+
+ if (!(inode->i_flags & EXT4_INLINE_DATA_FL))
+ goto out;
+
+ start = inode->i_block;
+ size = EXT4_MIN_INLINE_DATA_SIZE;
+ ret = search_dir2(fs, start, size, search_name, len);
+ if (!ret)
+ goto out;
+
+ ret = 0;
+ ext2fs_iget_extra_inode(fs, inode, &idata);
+ if (idata.inline_off == 0 ||
+ idata.inline_size == EXT4_MIN_INLINE_DATA_SIZE)
+ goto out;
+
+ start = ext2fs_get_inline_xattr_pos(inode, &idata);
+ size = idata.inline_size - EXT4_MIN_INLINE_DATA_SIZE;
+ ret = search_dir2(fs, start, size, search_name, len);
+
+out:
+ free(inode);
+ return ret;
+}
--
1.7.4.1
--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists