[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1341150538-32047-8-git-send-email-wenqing.lz@taobao.com>
Date: Sun, 1 Jul 2012 21:48:30 +0800
From: Zheng Liu <gnehzuil.liu@...il.com>
To: linux-ext4@...r.kernel.org
Cc: Zheng Liu <wenqing.lz@...bao.com>
Subject: [PATCH 07/35 v3] libext2fs: add inline_data file
From: Zheng Liu <wenqing.lz@...bao.com>
inline_data.c file is created to implement related functions to
support inline_data feature.
Signed-off-by: Zheng Liu <wenqing.lz@...bao.com>
---
lib/ext2fs/Makefile.in | 5 +
lib/ext2fs/Makefile.pq | 1 +
lib/ext2fs/ext2fs.h | 57 ++++
lib/ext2fs/inline_data.c | 724 ++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 787 insertions(+), 0 deletions(-)
create mode 100644 lib/ext2fs/inline_data.c
diff --git a/lib/ext2fs/Makefile.in b/lib/ext2fs/Makefile.in
index f9200fa..5b4ec15 100644
--- a/lib/ext2fs/Makefile.in
+++ b/lib/ext2fs/Makefile.in
@@ -58,6 +58,7 @@ OBJS= $(DEBUGFS_LIB_OBJS) $(RESIZE_LIB_OBJS) $(E2IMAGE_LIB_OBJS) \
ind_block.o \
initialize.o \
inline.o \
+ inline_data.o \
inode.o \
io_manager.o \
ismounted.o \
@@ -130,6 +131,7 @@ SRCS= ext2_err.c \
$(srcdir)/ind_block.c \
$(srcdir)/initialize.c \
$(srcdir)/inline.c \
+ $(srcdir)/inline_data.c \
$(srcdir)/inode.c \
$(srcdir)/inode_io.c \
$(srcdir)/imager.c \
@@ -734,6 +736,9 @@ inline.o: $(srcdir)/inline.c $(top_builddir)/lib/config.h \
$(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
$(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
$(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
+inline_data.o: $(srcdir)/inline_data.c $(top_builddir)/lib/config.h \
+ $(srcdir)/ext2_fs.h $(srcdir)/ext2fs.h $(srcdir)/ext2_ext_attr.h \
+ $(srcdir)/ext2fsP.h
inode.o: $(srcdir)/inode.c $(top_builddir)/lib/config.h \
$(top_builddir)/lib/dirpaths.h $(srcdir)/ext2_fs.h \
$(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fsP.h \
diff --git a/lib/ext2fs/Makefile.pq b/lib/ext2fs/Makefile.pq
index 2f7b654..89082a7 100644
--- a/lib/ext2fs/Makefile.pq
+++ b/lib/ext2fs/Makefile.pq
@@ -27,6 +27,7 @@ OBJS= alloc.obj \
icount.obj \
initialize.obj \
inline.obj \
+ inline_data.obj \
inode.obj \
ismounted.obj \
link.obj \
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index fd051b1..bacc14d 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -1329,6 +1329,63 @@ extern errcode_t ext2fs_icount_store(ext2_icount_t icount, ext2_ino_t ino,
extern ext2_ino_t ext2fs_get_icount_size(ext2_icount_t icount);
errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *);
+/* inline_data.c */
+extern errcode_t ext2fs_inline_data_iterate(ext2_filsys fs,
+ ext2_ino_t ino,
+ int flags,
+ char *block_buf,
+ int (*func)(struct ext2_dir_entry *dirent,
+ int offset,
+ int blocksize,
+ char *buf,
+ void *priv_data),
+ void *priv_data);
+extern errcode_t ext2fs_inline_data_iterate2(ext2_filsys fs,
+ ext2_ino_t ino,
+ int flags,
+ char *block_buf,
+ int (*func)(ext2_ino_t ino,
+ int entry,
+ struct ext2_dir_entry *dirent,
+ int offset,
+ int blocksize,
+ char *buf,
+ void *priv_data),
+ void *priv_data);
+extern errcode_t ext2fs_inline_data_iterate3(ext2_filsys fs,
+ ext2_ino_t ino,
+ int flags,
+ char *block_buf,
+ const char *name,
+ int namelen,
+ int (*func)(struct ext2_dir_entry *dirent,
+ int offset,
+ int blocksize,
+ char *buf,
+ void *priv_data),
+ void *priv_data);
+extern errcode_t ext2fs_inline_data_search_dir(ext2_filsys fs, ext2_ino_t ino,
+ char *search_name, int len);
+extern errcode_t ext2fs_inline_data_expand_dir(ext2_filsys fs, ext2_ino_t ino,
+ int flags, char *block_buf,
+ int (*func)(ext2_filsys fs,
+ blk64_t *blocknr,
+ e2_blkcnt_t blockcnt,
+ blk64_t ref_blk,
+ int ref_offset,
+ void *priv_data),
+ void *priv_data);
+extern void *ext2fs_get_inline_xattr_pos(struct ext2_inode_large *inode,
+ struct inline_data *idata);
+extern void ext2fs_iget_extra_inode(ext2_filsys fs, struct ext2_inode_large *inode,
+ struct inline_data *idata);
+extern int ext2fs_has_inline_data(ext2_filsys fs, ext2_ino_t ino);
+extern int ext2fs_inline_data_in_extra(ext2_filsys fs, ext2_ino_t ino);
+extern int ext2fs_inline_data_size(ext2_filsys fs, ext2_ino_t ino);
+extern int inline_data_destory_data(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode_large *inode,
+ struct inline_data *idata);
+
/* 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..59483a6
--- /dev/null
+++ b/lib/ext2fs/inline_data.c
@@ -0,0 +1,724 @@
+/*
+ * inline_data.c --- data in inode
+ *
+ * Copyright (C) 2012 Zheng Liu <wenqing.lz@...bao.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 "ext2_ext_attr.h"
+
+#include "ext2fs.h"
+#include "ext2fsP.h"
+
+#define EXT4_XATTR_SYSTEM_DATA_INDEX 7
+#define EXT4_XATTR_SYSTEM_DATA_NAME "data"
+
+struct inline_data_context {
+ ext2_ino_t ino;
+ int flags;
+ char *buf;
+ int (*func)(ext2_ino_t ino,
+ int entry,
+ struct ext2_dir_entry *dirent,
+ int offset,
+ int blocksize,
+ char *buf,
+ void *priv_data);
+ void *priv_data;
+ errcode_t errcode;
+};
+
+static void inline_data_update_dir_entry(ext2_filsys fs, void *de_buf,
+ int old_size, int new_size)
+{
+ struct ext2_dir_entry *entry, *prev;
+ void *limit;
+ unsigned int de_len;
+
+ entry = (struct ext2_dir_entry *)de_buf;
+ limit = de_buf + old_size;
+ do {
+ prev = entry;
+ ext2fs_get_rec_len(fs, entry, &de_len);
+ de_buf += de_len;
+ entry = (struct ext2_dir_entry *)de_buf;
+ } while (de_buf < limit);
+
+ ext2fs_set_rec_len(fs, de_len + new_size - old_size, prev);
+}
+
+int inline_data_destory_data(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode_large *inode,
+ struct inline_data *idata)
+{
+ struct ext2_ext_attr_entry *entry;
+ errcode_t retval;
+ char *start, *end;
+ int cmp;
+ __u32 *magic;
+
+ if (!idata->inline_off)
+ return 0;
+
+ if (inode->i_extra_isize > (EXT2_INODE_SIZE(fs->super) -
+ EXT2_GOOD_OLD_INODE_SIZE)) {
+ fprintf(stderr, "invalid inode->i_extra_isize (%u)\n",
+ inode->i_extra_isize);
+ return -1;
+ }
+
+ magic = (__u32*)((char *)inode + EXT2_GOOD_OLD_INODE_SIZE +
+ inode->i_extra_isize);
+ start = (char *)magic + sizeof(__u32);
+ end = (char *)inode + EXT2_INODE_SIZE(fs->super);
+ entry = (struct ext2_ext_attr_entry *)start;
+
+ cmp = ext2fs_find_entry_ext_attr(&entry, EXT4_XATTR_SYSTEM_DATA_INDEX,
+ EXT4_XATTR_SYSTEM_DATA_NAME,
+ end - start, 0);
+
+ if (!cmp) {
+ entry->e_value_offs = 0;
+ entry->e_value_block = 0;
+ entry->e_value_size = 0;
+ }
+
+ memset((void *)inode->i_block, 0, EXT4_MIN_INLINE_DATA_SIZE);
+
+ return 0;
+}
+
+static int inline_data_search_dir(ext2_filsys fs,
+ struct ext2_inode_large *inode,
+ char *start,
+ int size,
+ void *priv_data)
+{
+ struct inline_data_context *ctx;
+ struct ext2_dir_entry *dirent;
+ unsigned int rec_len;
+ unsigned int offset = 0;
+ char *dlimit;
+ int ret;
+ int do_abort = 0;
+ int changed = 0;
+
+ ctx = (struct inline_data_context *)priv_data;
+
+ dirent = (struct ext2_dir_entry *)start;
+ dlimit = start + size;
+
+ while ((char *)dirent < dlimit) {
+ if (ext2fs_get_rec_len(fs, dirent, &rec_len))
+ return BLOCK_ABORT;
+ if (!dirent->inode &&
+ !(ctx->flags & DIRENT_FLAG_INCLUDE_EMPTY))
+ goto next;
+ ret = (ctx->func)(ctx->ino, 0, dirent,
+ offset, size, start,
+ ctx->priv_data);
+
+ if (ret & DIRENT_CHANGED) {
+ if (ext2fs_get_rec_len(fs, dirent, &rec_len))
+ return BLOCK_ABORT;
+ changed++;
+ }
+
+ if (ret & DIRENT_ABORT)
+ do_abort++;
+
+next:
+ dirent = (struct ext2_dir_entry *)((char *)dirent + rec_len);
+ offset += rec_len;
+ }
+
+ if (changed) {
+ ctx->errcode = ext2fs_write_inode_full(fs, ctx->ino, (void *)inode,
+ EXT2_INODE_SIZE(fs->super));
+ if (ctx->errcode)
+ return BLOCK_ABORT;
+ }
+
+ if (do_abort)
+ return BLOCK_ABORT;
+
+ return 0;
+}
+
+static int inline_data_search_dir2(ext2_filsys fs, char *start, int size,
+ char *search_name, int len)
+{
+ struct ext2_dir_entry *dirent;
+ unsigned int rec_len;
+ char *dlimit;
+ int ret;
+ int do_abort = 0;
+
+ dirent = (struct ext2_dir_entry *)start;
+ dlimit = start + size;
+
+ while ((char *)dirent < dlimit) {
+ if (ext2fs_get_rec_len(fs, dirent, &rec_len))
+ return BLOCK_ABORT;
+ if (dirent->inode &&
+ len == (dirent->name_len & 0xFF) &&
+ strncmp(search_name, dirent->name, len) == 0) {
+ printf("Entry found at inline data\n");
+ break;
+ }
+ dirent = (struct ext2_dir_entry *)((char *)dirent + rec_len);
+ }
+
+ return 0;
+}
+
+void *ext2fs_get_inline_xattr_pos(struct ext2_inode_large *inode,
+ struct inline_data *idata)
+{
+ struct ext2_ext_attr_entry *entry;
+ struct ext2_ext_attr_ibody_header *header;
+
+ header = (struct ext2_ext_attr_ibody_header *)
+ ((void *)inode +
+ EXT2_GOOD_OLD_INODE_SIZE +
+ inode->i_extra_isize);
+ entry = (struct ext2_ext_attr_entry *)
+ ((void *)inode + idata->inline_off);
+
+ return (void *)((struct ext2_ext_attr_header *)((header) + 1)) +
+ entry->e_value_offs;
+}
+
+void ext2fs_iget_extra_inode(ext2_filsys fs, struct ext2_inode_large *inode,
+ struct inline_data *idata)
+{
+ struct ext2_ext_attr_entry *entry;
+ char *start, *end;
+ int cmp;
+ __u32 *magic;
+
+ idata->inline_off = 0;
+ if (inode->i_extra_isize > (EXT2_INODE_SIZE(fs->super) -
+ EXT2_GOOD_OLD_INODE_SIZE)) {
+ fprintf(stderr, "invalid inode->i_extra_isize (%u)\n",
+ inode->i_extra_isize);
+ return;
+ }
+
+ magic = (__u32*)((char *)inode + EXT2_GOOD_OLD_INODE_SIZE +
+ inode->i_extra_isize);
+ if (*magic == EXT2_EXT_ATTR_MAGIC) {
+ end = (char *)inode + EXT2_INODE_SIZE(fs->super);
+ start = (char *)magic + sizeof(__u32);
+ entry = (struct ext2_ext_attr_entry *)start;
+
+ cmp = ext2fs_find_entry_ext_attr(&entry, EXT4_XATTR_SYSTEM_DATA_INDEX,
+ EXT4_XATTR_SYSTEM_DATA_NAME,
+ end - start, 0);
+ if (!cmp) {
+ idata->inline_off = (__u16)((void *)entry -
+ (void *)inode);
+ idata->inline_size = EXT4_MIN_INLINE_DATA_SIZE +
+ entry->e_value_size;
+ }
+ }
+}
+
+int ext2fs_has_inline_data(ext2_filsys fs, ext2_ino_t ino)
+{
+ struct ext2_inode *inode;
+ errcode_t retval;
+ __u32 flags;
+
+ retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
+ if (retval)
+ return 0;
+
+ retval = ext2fs_read_inode_full(fs, ino, inode,
+ EXT2_INODE_SIZE(fs->super));
+ if (retval)
+ return 0;
+
+ flags = inode->i_flags;
+ ext2fs_free_mem(&inode);
+
+ return (flags & EXT4_INLINE_DATA_FL);
+}
+
+struct xlate {
+ int (*func)(struct ext2_dir_entry *dirent,
+ int offset,
+ int blocksize,
+ char *buf,
+ void *priv_data);
+ void *real_private;
+};
+
+static int xlate_func(ext2_ino_t dir EXT2FS_ATTR((unused)),
+ int entry EXT2FS_ATTR((unused)),
+ struct ext2_dir_entry *dirent, int offset,
+ int blocksize, char *buf, void *priv_data)
+{
+ struct xlate *xl = (struct xlate *)priv_data;
+
+ return (*xl->func)(dirent, offset, blocksize, buf, xl->real_private);
+}
+
+errcode_t ext2fs_inline_data_iterate(ext2_filsys fs,
+ ext2_ino_t ino,
+ int flags,
+ char *block_buf,
+ int (*func)(struct ext2_dir_entry *dirent,
+ int offset,
+ int blocksize,
+ char *buf,
+ void *priv_data),
+ void *priv_data)
+{
+ struct xlate xl;
+
+ xl.real_private = priv_data;
+ xl.func = func;
+
+ return ext2fs_inline_data_iterate2(fs, ino, flags, block_buf,
+ xlate_func, &xl);
+}
+
+errcode_t ext2fs_inline_data_iterate2(ext2_filsys fs,
+ ext2_ino_t ino, int flags, char *block_buf,
+ int (*func)(ext2_ino_t ino,
+ int entry,
+ struct ext2_dir_entry *dirent,
+ int offset,
+ int blocksize,
+ char *buf,
+ void *priv_data),
+ void *priv_data)
+{
+ struct inline_data_context ctx;
+ struct ext2_inode_large *inode;
+ struct inline_data idata;
+ errcode_t retval;
+ blk64_t blk64;
+ void *inline_start;
+ int inline_size;
+ int i, limit, r;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ retval = ext2fs_check_directory(fs, ino);
+ if (retval)
+ return retval;
+
+ retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
+ if (retval)
+ return retval;
+ retval = ext2fs_read_inode_full(fs, ino, (void *)inode,
+ EXT2_INODE_SIZE(fs->super));
+ if (retval) {
+ ext2fs_free_mem(&inode);
+ return retval;
+ }
+
+ if (inode->i_size == 0)
+ goto out;
+
+ ctx.ino = ino;
+ ctx.flags = flags;
+ ctx.buf = block_buf;
+ ctx.func = func;
+ ctx.priv_data = priv_data;
+ ctx.errcode = 0;
+
+ inline_start = inode->i_block;
+ inline_size = EXT4_MIN_INLINE_DATA_SIZE;
+ retval = inline_data_search_dir(fs, inode, inline_start, inline_size, &ctx);
+ if (retval)
+ goto out;
+
+ ext2fs_iget_extra_inode(fs, inode, &idata);
+ if (idata.inline_size > EXT4_MIN_INLINE_DATA_SIZE) {
+ inline_start = ext2fs_get_inline_xattr_pos(inode, &idata);
+ inline_size = idata.inline_size - EXT4_MIN_INLINE_DATA_SIZE;
+ retval = inline_data_search_dir(fs, inode, inline_start, inline_size, &ctx);
+ }
+
+out:
+ ext2fs_free_mem(&inode);
+ return retval & BLOCK_ABORT ? 0 : retval;
+}
+
+errcode_t ext2fs_inline_data_iterate3(ext2_filsys fs,
+ ext2_ino_t ino,
+ int flags,
+ char *block_buf,
+ const char *name,
+ int namelen,
+ int (*func)(struct ext2_dir_entry *dirent,
+ int offset,
+ int blocksize,
+ char *buf,
+ void *priv_data),
+ void *priv_data)
+{
+ struct xlate xl;
+ struct inline_data_context ctx;
+ struct ext2_inode_large *inode;
+ struct inline_data idata;
+ struct ext2_dir_entry_tail *t;
+ 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;
+ int csum_size = 0;
+
+ xl.real_private = priv_data;
+ xl.func = func;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+ csum_size = sizeof(struct ext2_dir_entry_tail);
+
+ retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
+ if (retval)
+ return retval;
+ retval = ext2fs_read_inode_full(fs, ino, (void *)inode,
+ EXT2_INODE_SIZE(fs->super));
+ if (retval) {
+ ext2fs_free_mem(&inode);
+ return retval;
+ }
+
+ ctx.ino = ino;
+ ctx.flags = flags;
+ ctx.buf = block_buf;
+ ctx.func = xlate_func;
+ ctx.priv_data = &xl;
+ ctx.errcode = 0;
+
+ inline_start = inode->i_block;
+ inline_size = EXT4_MIN_INLINE_DATA_SIZE;
+ retval = inline_data_search_dir(fs, inode, inline_start, inline_size, &ctx);
+ if (retval)
+ goto out;
+
+ ext2fs_iget_extra_inode(fs, inode, &idata);
+ inline_size = idata.inline_size - EXT4_MIN_INLINE_DATA_SIZE;
+ if (inline_size > 0) {
+ inline_start = ext2fs_get_inline_xattr_pos(inode, &idata);
+ retval = inline_data_search_dir(fs, inode, inline_start, inline_size, &ctx);
+ if (retval)
+ goto out;
+ }
+
+ /*
+ * The inline space is filled up. So create a new block for it.
+ * As the extent tree se created, we have to save the inline
+ * dir first.
+ */
+ inline_size = idata.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, &idata),
+ inline_size - EXT4_MIN_INLINE_DATA_SIZE);
+
+ /* clear the entry and the flag in dir now */
+ retval = inline_data_destory_data(fs, ino, inode, &idata);
+ if (retval)
+ goto out;
+
+ 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 out;
+
+ ext2fs_iblk_set(fs, (void *)inode, 1);
+ if (!(fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS))
+ inode->i_block[0] = blk;
+ inode->i_size = fs->blocksize;
+
+ retval = ext2fs_get_mem(fs->blocksize, &blk_buf);
+ if (retval)
+ goto out;
+
+ memcpy(blk_buf, backup_buf, inline_size);
+
+ /* set the final dir entry to cover the whole block */
+ inline_data_update_dir_entry(fs, blk_buf, inline_size,
+ fs->blocksize - csum_size);
+
+ if (csum_size) {
+ t = EXT2_DIRENT_TAIL(blk_buf, fs->blocksize);
+ ext2fs_initialize_dirent_tail(fs, t);
+ }
+
+ retval = ext2fs_write_dir_block4(fs, blk, blk_buf, 0, ino);
+ if (retval)
+ goto out;
+ retval = ext2fs_write_inode_full(fs, ino, (void *)inode,
+ EXT2_INODE_SIZE(fs->super));
+ if (retval)
+ goto out;
+
+ if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) {
+ retval = ext2fs_extent_open2(fs, ino, (void *)inode, &handle);
+ if (retval)
+ goto out;
+ retval = ext2fs_extent_set_bmap(handle, 0, blk, 0);
+ ext2fs_extent_free(handle);
+ if (retval)
+ goto out;
+ }
+
+ /* Update accouting */
+ ext2fs_block_alloc_stats2(fs, blk, +1);
+
+ /* try to add a new entry */
+ retval = ext2fs_dir_iterate(fs, ino, DIRENT_FLAG_INCLUDE_EMPTY,
+ 0, func, priv_data);
+
+ ext2fs_free_mem(&backup_buf);
+ ext2fs_free_mem(&blk_buf);
+out:
+ ext2fs_free_mem(&inode);
+ return retval & BLOCK_ABORT ? 0 : retval;
+}
+
+errcode_t ext2fs_inline_data_search_dir(ext2_filsys fs, ext2_ino_t ino,
+ char *search_name, int len)
+{
+ struct ext2_inode_large *inode;
+ struct ext2_dir_entry *entry;
+ struct inline_data idata;
+ unsigned int rec_len;
+ errcode_t retval;
+ char *dlimit;
+ void *start;
+ int size;
+
+ retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
+ if (retval)
+ return retval;
+
+ retval = ext2fs_read_inode_full(fs, ino, (void *)inode,
+ EXT2_INODE_SIZE(fs->super));
+ if (retval)
+ return retval;
+
+ if (!(inode->i_flags & EXT4_INLINE_DATA_FL))
+ goto out;
+
+ start = inode->i_block;
+ size = EXT4_MIN_INLINE_DATA_SIZE;
+ retval = inline_data_search_dir2(fs, start, size, search_name, len);
+ if (!retval)
+ goto out;
+
+ retval = 0;
+ ext2fs_iget_extra_inode(fs, inode, &idata);
+ if (idata.inline_size == EXT4_MIN_INLINE_DATA_SIZE)
+ goto out;
+
+ start = ext2fs_get_inline_xattr_pos(inode, &idata);
+ size = idata.inline_size - EXT4_MIN_INLINE_DATA_SIZE;
+ retval = inline_data_search_dir2(fs, start, size, search_name, len);
+
+out:
+ ext2fs_free_mem(&inode);
+ return retval;
+}
+
+errcode_t ext2fs_inline_data_header_verify(ext2_filsys fs,
+ struct ext2_inode *inode)
+{
+ struct inline_data idata;
+ int ret = 0;
+
+ ext2fs_iget_extra_inode(fs, (void *)inode, &idata);
+ if (idata.inline_off == 0)
+ ret = -1;
+
+ return ret;
+}
+
+int ext2fs_inline_data_in_extra(ext2_filsys fs, ext2_ino_t ino)
+{
+ struct ext2_inode *inode;
+ struct inline_data idata;
+
+ ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
+ ext2fs_read_inode_full(fs, ino, inode, EXT2_INODE_SIZE(fs->super));
+
+ ext2fs_iget_extra_inode(fs, inode, &idata);
+ ext2fs_free_mem(&inode);
+ if (idata.inline_off == 0 ||
+ idata.inline_size == EXT4_MIN_INLINE_DATA_SIZE)
+ return 0;
+ else
+ return 1;
+}
+
+int ext2fs_inline_data_size(ext2_filsys fs, ext2_ino_t ino)
+{
+ struct ext2_inode *inode;
+ struct inline_data idata;
+
+ inode = (struct ext2_inode *) malloc(EXT2_INODE_SIZE(fs->super));
+ ext2fs_read_inode_full(fs, ino, inode, EXT2_INODE_SIZE(fs->super));
+
+ ext2fs_iget_extra_inode(fs, inode, &idata);
+ free(inode);
+ if (idata.inline_off == 0)
+ return 0;
+ else
+ return idata.inline_size;
+}
+
+errcode_t ext2fs_inline_data_expand_dir(ext2_filsys fs,
+ ext2_ino_t ino,
+ int flags,
+ char *block_buf,
+ int (*func)(ext2_filsys fs,
+ blk64_t *blocknr,
+ e2_blkcnt_t blockcnt,
+ blk64_t ref_blk,
+ int ref_offset,
+ void *priv_data),
+ void *priv_data)
+{
+ struct ext2_inode_large *inode;
+ struct inline_data idata;
+ struct ext2_dir_entry_tail *t;
+ 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;
+ int csum_size = 0;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+ csum_size = sizeof(struct ext2_dir_entry_tail);
+
+ retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
+ if (retval)
+ return retval;
+ retval = ext2fs_read_inode_full(fs, ino, (void *)inode,
+ EXT2_INODE_SIZE(fs->super));
+ if (retval) {
+ ext2fs_free_mem(&inode);
+ return retval;
+ }
+
+ ext2fs_iget_extra_inode(fs, inode, &idata);
+
+ inline_size = idata.inline_size;
+ retval = ext2fs_get_mem(inline_size, &backup_buf);
+ if (retval) {
+ goto out;
+ }
+
+ memcpy(backup_buf, (void *)inode->i_block, EXT4_MIN_INLINE_DATA_SIZE);
+ if (inline_size > EXT4_MIN_INLINE_DATA_SIZE)
+ memcpy(backup_buf + EXT4_MIN_INLINE_DATA_SIZE,
+ ext2fs_get_inline_xattr_pos(inode, &idata),
+ inline_size - EXT4_MIN_INLINE_DATA_SIZE);
+
+ /* clear the entry and the flag in dir now */
+ retval = inline_data_destory_data(fs, ino, inode, &idata);
+ if (retval)
+ goto out;
+
+ 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 out;
+
+ ext2fs_iblk_set(fs, (void *)inode, 1);
+ if (!(fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS))
+ inode->i_block[0] = blk;
+ inode->i_size = fs->blocksize;
+
+ retval = ext2fs_get_mem(fs->blocksize, &blk_buf);
+ if (retval)
+ goto out;
+
+ memcpy(blk_buf, backup_buf, inline_size);
+
+ /* set the final dir entry to cover the whole block */
+ inline_data_update_dir_entry(fs, blk_buf, inline_size,
+ fs->blocksize - csum_size);
+
+ if (csum_size) {
+ t = EXT2_DIRENT_TAIL(blk_buf, fs->blocksize);
+ ext2fs_initialize_dirent_tail(fs, t);
+ }
+
+ retval = ext2fs_write_dir_block4(fs, blk, blk_buf, 0, ino);
+ if (retval)
+ goto out;
+ retval = ext2fs_write_inode_full(fs, ino, (void *)inode,
+ EXT2_INODE_SIZE(fs->super));
+ if (retval)
+ goto out;
+
+ if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) {
+ retval = ext2fs_extent_open2(fs, ino, (void *)inode, &handle);
+ if (retval)
+ goto out;
+ retval = ext2fs_extent_set_bmap(handle, 0, blk, 0);
+ ext2fs_extent_free(handle);
+ if (retval)
+ goto out;
+ }
+
+ /* Update accouting */
+ ext2fs_block_alloc_stats2(fs, blk, +1);
+
+ /* try to add a new entry */
+ retval = ext2fs_block_iterate3(fs, ino, flags, 0, func, priv_data);
+
+ ext2fs_free_mem(&backup_buf);
+ ext2fs_free_mem(&blk_buf);
+out:
+ ext2fs_free_mem(&inode);
+ return retval & BLOCK_ABORT ? 0 : retval;
+}
--
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