* e2fsprogs: Undo I/O manager
@ 2007-05-09 8:12 Aneesh Kumar K.V
[not found] ` <d286e4520f717821cf2363ff3c71a9fff5ecad2f.1178698029.git.aneesh.kumar@linux.vnet.ibm.com>
0 siblings, 1 reply; 7+ messages in thread
From: Aneesh Kumar K.V @ 2007-05-09 8:12 UTC (permalink / raw)
To: linux-ext4, tytso; +Cc: aneesh.kumar
This is a very early prototype of what i working on. I have done only minimal
testing of this. To use one need to use the below steps.
io_manager io_mng = stack_io_manager_init();
stack_push_io_manager(io_mng, unix_io_manager);
stack_push_io_manager(io_mng, undo_io_manager);
flags = EXT2_FLAG_SOFTSUPP_FEATURES | EXT2_FLAG_RW;
retval = ext2fs_open2(dev_name,"tdbfilename=/tmp/test.tdb&",
flags, superblock, block_size,
io_mng, ¤t_fs);
I am sending this across to find out if this is the approach that we want to follow.
-aneesh
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 1/2] Add stack I/O manager.
[not found] ` <d286e4520f717821cf2363ff3c71a9fff5ecad2f.1178698029.git.aneesh.kumar@linux.vnet.ibm.com>
@ 2007-05-09 8:12 ` Aneesh Kumar K.V
[not found] ` <cd9cd245faaef0628edabe875c507543f3195991.1178698029.git.aneesh.kumar@linux.vnet.ibm.com>
` (2 subsequent siblings)
3 siblings, 0 replies; 7+ messages in thread
From: Aneesh Kumar K.V @ 2007-05-09 8:12 UTC (permalink / raw)
To: linux-ext4, tytso; +Cc: aneesh.kumar
From: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
This I/O manager helps in stacking different I/O managers.
For example one can stack the undo I/O manager on top
of Unix I/O manager to achieve the undo functionality.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
---
lib/ext2fs/Makefile.in | 10 +-
lib/ext2fs/ext2_io.h | 4 +
lib/ext2fs/stack_io.c | 419 ++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 431 insertions(+), 2 deletions(-)
create mode 100644 lib/ext2fs/stack_io.c
diff --git a/lib/ext2fs/Makefile.in b/lib/ext2fs/Makefile.in
index 799659e..f5d141a 100644
--- a/lib/ext2fs/Makefile.in
+++ b/lib/ext2fs/Makefile.in
@@ -66,7 +66,8 @@ OBJS= $(DEBUGFS_LIB_OBJS) $(RESIZE_LIB_OBJS) $(E2IMAGE_LIB_OBJS) \
unix_io.o \
unlink.o \
valid_blk.o \
- version.o
+ version.o \
+ stack_io.o
SRCS= ext2_err.c \
$(srcdir)/alloc.c \
@@ -134,7 +135,8 @@ SRCS= ext2_err.c \
$(srcdir)/tst_bitops.c \
$(srcdir)/tst_byteswap.c \
$(srcdir)/tst_getsize.c \
- $(srcdir)/tst_iscan.c
+ $(srcdir)/tst_iscan.c \
+ $(srcdir)/stack_io.c
HFILES= bitops.h ext2fs.h ext2_io.h ext2_fs.h ext2_ext_attr.h ext3_extents.h
HFILES_IN= ext2_err.h ext2_types.h
@@ -550,3 +552,7 @@ tst_iscan.o: $(srcdir)/tst_iscan.c $(srcdir)/ext2_fs.h \
$(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
$(srcdir)/ext2_fs.h $(top_srcdir)/lib/et/com_err.h $(srcdir)/ext2_io.h \
$(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+stack_io.o: $(srcdir)/stack_io.c $(srcdir)/ext2_fs.h \
+ $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
+ $(srcdir)/ext2_fs.h $(top_srcdir)/lib/et/com_err.h $(srcdir)/ext2_io.h \
+ $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
diff --git a/lib/ext2fs/ext2_io.h b/lib/ext2fs/ext2_io.h
index eada278..65a294e 100644
--- a/lib/ext2fs/ext2_io.h
+++ b/lib/ext2fs/ext2_io.h
@@ -96,6 +96,10 @@ extern errcode_t io_channel_write_byte(io_channel channel,
/* unix_io.c */
extern io_manager unix_io_manager;
+/* stack_io.c */
+extern struct struct_io_manager *stack_io_manager_init(void);
+extern errcode_t stack_push_io_manager(struct struct_io_manager *stack,
+ struct struct_io_manager *io);
/* test_io.c */
extern io_manager test_io_manager, test_io_backing_manager;
extern void (*test_io_cb_read_blk)
diff --git a/lib/ext2fs/stack_io.c b/lib/ext2fs/stack_io.c
new file mode 100644
index 0000000..5adfe4d
--- /dev/null
+++ b/lib/ext2fs/stack_io.c
@@ -0,0 +1,419 @@
+/*
+ * stack_io.c --- This is the io manager used to stack different io managers.
+ *
+ * Copyright (C) 1996 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_PRCTL_H
+#include <sys/prctl.h>
+#else
+#define PR_GET_DUMPABLE 3
+#endif
+#if (!defined(HAVE_PRCTL) && defined(linux))
+#include <sys/syscall.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+#include "kernel-list.h"
+
+/*
+ * For checking structure magic numbers...
+ */
+
+#define EXT2_CHECK_MAGIC(struct, code) \
+ if ((struct)->magic != (code)) return (code)
+
+#define EXT2_ET_MAGIC_STACK_IO_CHANNEL (2133571428L)
+
+struct stack_private_data {
+ int magic;
+ struct list_head st_elements;
+};
+
+struct stack_element {
+ struct struct_io_manager *io;
+ struct struct_io_channel *channel;
+ struct list_head list;
+};
+
+
+static errcode_t stack_open(const char *name, int flags, io_channel *channel);
+static errcode_t stack_close(io_channel channel);
+static errcode_t stack_set_blksize(io_channel channel, int blksize);
+static errcode_t stack_read_blk(io_channel channel, unsigned long block,
+ int count, void *data);
+static errcode_t stack_write_blk(io_channel channel, unsigned long block,
+ int count, const void *data);
+static errcode_t stack_flush(io_channel channel);
+static errcode_t stack_write_byte(io_channel channel, unsigned long offset,
+ int count, const void *buf);
+static errcode_t stack_set_option(io_channel channel, const char *option,
+ const char *arg);
+
+static struct struct_io_manager struct_stack_manager = {
+ .magic = EXT2_ET_MAGIC_IO_MANAGER,
+ .name = "Stack I/O Manager",
+ .open = stack_open,
+ .close = stack_close,
+ .set_blksize = stack_set_blksize,
+ .read_blk = stack_read_blk,
+ .write_blk = stack_write_blk,
+ .flush = stack_flush,
+ .write_byte = stack_write_byte,
+ .set_option = stack_set_option,
+};
+
+io_manager stack_io_manager = &struct_stack_manager;
+/* FIXME!! get rid of this. not thread safe */
+static struct stack_private_data private_data;
+struct struct_io_manager *stack_io_manager_init(void)
+{
+
+
+ INIT_LIST_HEAD(&(private_data.st_elements));
+ private_data.magic = EXT2_ET_MAGIC_STACK_IO_CHANNEL;
+
+ return stack_io_manager;
+
+}
+
+errcode_t stack_push_io_manager(struct struct_io_manager *stack, struct struct_io_manager *io)
+{
+ errcode_t retval;
+ (void)(stack);
+ struct stack_element *element;
+ retval = ext2fs_get_mem(sizeof(struct stack_element), &element);
+ if (retval)
+ return retval;
+ element->io = io;
+ list_add(&(element->list), &(private_data.st_elements));
+
+ return 0;
+}
+
+
+static errcode_t stack_open(const char *name, int flags, io_channel *channel)
+{
+ io_channel io = NULL, stack_io_channel = NULL;
+ errcode_t retval;
+ char *value;
+ struct list_head *entry;
+ struct stack_element *element;
+
+ if (name == 0)
+ return EXT2_ET_BAD_DEVICE_NAME;
+ retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
+ if (retval)
+ return retval;
+ memset(io, 0, sizeof(struct struct_io_channel));
+ io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
+
+ io->manager = stack_io_manager;
+ retval = ext2fs_get_mem(strlen(name)+1, &io->name);
+ if (retval)
+ goto cleanup;
+
+ strcpy(io->name, name);
+ io->private_data = &(private_data);
+ io->block_size = 1024;
+ io->read_error = 0;
+ io->write_error = 0;
+ io->refcount = 1;
+
+ /*
+ * Now call all the io managers open routine
+ */
+ list_for_each(entry, &(private_data.st_elements)) {
+
+ element = list_entry(entry, struct stack_element, list);
+ if (element->io) {
+ retval = element->io->open(name, flags,
+ &stack_io_channel);
+ if (retval) {
+ /*
+ * FIXME!! we need cleanup previous
+ * successfull I/O manager open
+ */
+ goto cleanup;
+ }
+ }
+ element->channel = stack_io_channel;
+ }
+
+ *channel = io;
+ return 0;
+
+cleanup:
+ if (io)
+ ext2fs_free_mem(&io);
+ return retval;
+}
+
+static errcode_t stack_io_channel_close(io_channel channel)
+{
+ if (channel && channel->manager->close)
+ return channel->manager->close(channel);
+
+ return 0;
+
+}
+
+static errcode_t stack_close(io_channel channel)
+{
+ struct stack_private_data *data;
+ struct list_head *entry;
+ struct stack_element *element;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct stack_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_STACK_IO_CHANNEL);
+
+ if (--channel->refcount > 0)
+ return 0;
+
+ list_for_each(entry, &(data->st_elements)) {
+ element = list_entry(entry, struct stack_element, list);
+ stack_io_channel_close(element->channel);
+ }
+
+ if (channel->name)
+ ext2fs_free_mem(&channel->name);
+ ext2fs_free_mem(&channel);
+
+ return 0;
+}
+
+static errcode_t stack_io_channel_set_blksize(io_channel channel, int blksize)
+{
+ if (channel && channel->manager->set_blksize)
+ return channel->manager->set_blksize(channel, blksize);
+
+ return 0;
+
+}
+static errcode_t stack_set_blksize(io_channel channel, int blksize)
+{
+ struct stack_private_data *data;
+ struct list_head *entry;
+ struct stack_element *element;
+ errcode_t retval = 0;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct stack_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_STACK_IO_CHANNEL);
+
+ list_for_each(entry, &(data->st_elements)) {
+ element = list_entry(entry, struct stack_element, list);
+ retval = stack_io_channel_set_blksize(element->channel, blksize);
+ if (retval)
+ return retval;
+ }
+
+ channel->block_size = blksize;
+ return retval;
+}
+
+#define list_for_each_prev(pos, head) \
+ for (pos = (head)->prev; pos != (head); \
+ pos = pos->prev)
+
+static errcode_t stack_io_channel_read_blk(io_channel channel,
+ unsigned long block, int count, void *buf)
+{
+ if (channel && channel->manager->read_blk)
+ return channel->manager->read_blk(channel,
+ block, count, buf);
+
+ return 0;
+}
+static errcode_t stack_read_blk(io_channel channel, unsigned long block,
+ int count, void *buf)
+{
+ struct stack_private_data *data;
+ struct list_head *entry;
+ struct stack_element *element;
+ errcode_t retval = 0;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct stack_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_STACK_IO_CHANNEL);
+
+ /*
+ * we should read int the reverse order
+ */
+ list_for_each_prev(entry, &(data->st_elements)) {
+ element = list_entry(entry, struct stack_element, list);
+ retval = stack_io_channel_read_blk(element->channel, block, count, buf);
+ if (retval)
+ return retval;
+ }
+
+ return retval;
+}
+
+static errcode_t stack_io_channel_write_blk(io_channel channel,
+ unsigned long block, int count, const void *buf)
+{
+ if (channel && channel->manager->write_blk)
+ return channel->manager->write_blk(channel,
+ block, count, buf);
+
+ return 0;
+}
+static errcode_t stack_write_blk(io_channel channel, unsigned long block,
+ int count, const void *buf)
+{
+ struct stack_private_data *data;
+ struct list_head *entry;
+ struct stack_element *element;
+ errcode_t retval = 0;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct stack_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_STACK_IO_CHANNEL);
+
+ list_for_each(entry, &(data->st_elements)) {
+ element = list_entry(entry, struct stack_element, list);
+ retval = stack_io_channel_write_blk(element->channel, block, count, buf);
+ if (retval)
+ return retval;
+ }
+
+ return retval;
+}
+
+static errcode_t stack_io_channel_write_byte(io_channel channel,
+ unsigned long offset, int count, const void *buf)
+{
+ if (channel && channel->manager->write_byte)
+ return channel->manager->write_byte(channel,
+ offset, count, buf);
+
+ return 0;
+}
+
+static errcode_t stack_write_byte(io_channel channel, unsigned long offset,
+ int count, const void *buf)
+{
+ struct stack_private_data *data;
+ struct list_head *entry;
+ struct stack_element *element;
+ errcode_t retval = 0;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct stack_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_STACK_IO_CHANNEL);
+
+ list_for_each(entry, &(data->st_elements)) {
+ element = list_entry(entry, struct stack_element, list);
+ retval = stack_io_channel_write_byte(element->channel, offset, count, buf);
+ if (retval)
+ return retval;
+ }
+
+ return retval;
+}
+
+static errcode_t stack_io_channel_flush(io_channel channel)
+{
+ if (channel && channel->manager->flush)
+ return channel->manager->flush(channel);
+
+ return 0;
+
+}
+
+/*
+ * Flush data buffers to disk.
+ */
+static errcode_t stack_flush(io_channel channel)
+{
+ struct stack_private_data *data;
+ struct list_head *entry;
+ struct stack_element *element;
+ errcode_t retval = 0;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct stack_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_STACK_IO_CHANNEL);
+
+ list_for_each(entry, &(data->st_elements)) {
+ element = list_entry(entry, struct stack_element, list);
+ retval = stack_io_channel_flush(element->channel);
+ if (retval)
+ return retval;
+ }
+
+ return retval;
+}
+
+
+static errcode_t stack_io_channel_set_option(io_channel channel,
+ const char *option, const char *arg)
+{
+ if (channel && channel->manager->set_option)
+ return channel->manager->set_option(channel,
+ option, arg);
+
+ return 0;
+
+}
+static errcode_t stack_set_option(io_channel channel, const char *option,
+ const char *arg)
+{
+ struct stack_private_data *data;
+ struct list_head *entry;
+ struct stack_element *element;
+ errcode_t retval = 0;
+ struct struct_io_manager *io_mng;
+ int success;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct stack_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_STACK_IO_CHANNEL);
+
+ list_for_each(entry, &(data->st_elements)) {
+ element = list_entry(entry, struct stack_element, list);
+ retval = stack_io_channel_set_option(element->channel,
+ option, arg);
+ if (retval == 0) {
+ success = 1;
+ continue;
+ }
+
+ if (retval == EXT2_ET_INVALID_ARGUMENT) {
+ /*
+ * this may be the option for some other io manager
+ * if everybody said EXT2_ET_INVALID_ARGUMENT
+ * then we will return that
+ */
+ continue;
+ } else {
+ return retval;
+ }
+ }
+
+ if (success)
+ return 0;
+
+ return retval;
+}
--
1.5.2.rc0.71.g4342-dirty
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 2/2] Add undo I/O manager.
[not found] ` <cd9cd245faaef0628edabe875c507543f3195991.1178698029.git.aneesh.kumar@linux.vnet.ibm.com>
@ 2007-05-09 8:12 ` Aneesh Kumar K.V
0 siblings, 0 replies; 7+ messages in thread
From: Aneesh Kumar K.V @ 2007-05-09 8:12 UTC (permalink / raw)
To: linux-ext4, tytso; +Cc: aneesh.kumar
From: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
This I/O manager saves the contents of the location being overwritten
to a tdb database. This helps in undoing the changes done to the
file system.
This can be stacked over unix I/O manager to get the undo functionality.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
---
lib/ext2fs/Makefile.in | 10 +-
lib/ext2fs/ext2_io.h | 3 +
lib/ext2fs/undo_io.c | 443 ++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 454 insertions(+), 2 deletions(-)
create mode 100644 lib/ext2fs/undo_io.c
diff --git a/lib/ext2fs/Makefile.in b/lib/ext2fs/Makefile.in
index f5d141a..669d4e7 100644
--- a/lib/ext2fs/Makefile.in
+++ b/lib/ext2fs/Makefile.in
@@ -67,7 +67,8 @@ OBJS= $(DEBUGFS_LIB_OBJS) $(RESIZE_LIB_OBJS) $(E2IMAGE_LIB_OBJS) \
unlink.o \
valid_blk.o \
version.o \
- stack_io.o
+ stack_io.o \
+ undo_io.o
SRCS= ext2_err.c \
$(srcdir)/alloc.c \
@@ -136,7 +137,8 @@ SRCS= ext2_err.c \
$(srcdir)/tst_byteswap.c \
$(srcdir)/tst_getsize.c \
$(srcdir)/tst_iscan.c \
- $(srcdir)/stack_io.c
+ $(srcdir)/stack_io.c \
+ $(srcdir)/undo_io.c
HFILES= bitops.h ext2fs.h ext2_io.h ext2_fs.h ext2_ext_attr.h ext3_extents.h
HFILES_IN= ext2_err.h ext2_types.h
@@ -556,3 +558,7 @@ stack_io.o: $(srcdir)/stack_io.c $(srcdir)/ext2_fs.h \
$(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
$(srcdir)/ext2_fs.h $(top_srcdir)/lib/et/com_err.h $(srcdir)/ext2_io.h \
$(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+undo_io.o: $(srcdir)/undo_io.c $(srcdir)/ext2_fs.h \
+ $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
+ $(srcdir)/ext2_fs.h $(top_srcdir)/lib/et/com_err.h $(srcdir)/ext2_io.h \
+ $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
diff --git a/lib/ext2fs/ext2_io.h b/lib/ext2fs/ext2_io.h
index 65a294e..78ea27c 100644
--- a/lib/ext2fs/ext2_io.h
+++ b/lib/ext2fs/ext2_io.h
@@ -100,6 +100,9 @@ extern io_manager unix_io_manager;
extern struct struct_io_manager *stack_io_manager_init(void);
extern errcode_t stack_push_io_manager(struct struct_io_manager *stack,
struct struct_io_manager *io);
+/* undo_io.c */
+extern io_manager undo_io_manager;
+
/* test_io.c */
extern io_manager test_io_manager, test_io_backing_manager;
extern void (*test_io_cb_read_blk)
diff --git a/lib/ext2fs/undo_io.c b/lib/ext2fs/undo_io.c
new file mode 100644
index 0000000..01fa34f
--- /dev/null
+++ b/lib/ext2fs/undo_io.c
@@ -0,0 +1,443 @@
+/*
+ * undo_io.c --- This is the undo io manager that copies the old data that
+ * copies the old data being overwritten into a tdb database
+ *
+ * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+ * 2002 by Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#define _LARGEFILE_SOURCE
+#define _LARGEFILE64_SOURCE
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#ifdef __linux__
+#include <sys/utsname.h>
+#endif
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+
+#include <tdb.h>
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+/*
+ * For checking structure magic numbers...
+ */
+
+#define EXT2_CHECK_MAGIC(struct, code) \
+ if ((struct)->magic != (code)) return (code)
+
+
+struct undo_private_data {
+ int magic;
+ TDB_CONTEXT *tdb;
+ char *tdb_file;
+
+ /* device from from which data should be read */
+ int dev;
+
+ /* to support offset in unix I/O manager */
+ ext2_loff_t offset;
+};
+
+static errcode_t undo_open(const char *name, int flags, io_channel *channel);
+static errcode_t undo_close(io_channel channel);
+static errcode_t undo_set_blksize(io_channel channel, int blksize);
+static errcode_t undo_read_blk(io_channel channel, unsigned long block,
+ int count, void *data);
+static errcode_t undo_write_blk(io_channel channel, unsigned long block,
+ int count, const void *data);
+static errcode_t undo_flush(io_channel channel);
+static errcode_t undo_write_byte(io_channel channel, unsigned long offset,
+ int size, const void *data);
+static errcode_t undo_set_option(io_channel channel, const char *option,
+ const char *arg);
+
+static struct struct_io_manager struct_undo_manager = {
+ EXT2_ET_MAGIC_IO_MANAGER,
+ "Undo I/O Manager",
+ undo_open,
+ undo_close,
+ undo_set_blksize,
+ undo_read_blk,
+ undo_write_blk,
+ undo_flush,
+ undo_write_byte,
+ undo_set_option
+};
+
+io_manager undo_io_manager = &struct_undo_manager;
+
+static int is_trans_overlapping(TDB_CONTEXT *tdb,
+ ext2_loff_t *location, int *size)
+{
+
+ ext2_loff_t req_loc, cur_loc;
+ int req_size, cur_size;
+ TDB_DATA key, data;
+
+restart:
+ req_loc = *location;
+ req_size = *size;
+
+ /* loop through the existing entries and find if they overlap */
+ for (key = tdb_firstkey(tdb); key.dptr; key = tdb_nextkey(tdb, key)) {
+ data = tdb_fetch(tdb, key);
+ /*
+ * we are not interested in the data
+ */
+ free(data.dptr);
+
+ cur_loc = *(ext2_loff_t *)key.dptr;
+ cur_size = data.dsize;
+
+ if (req_loc < cur_loc)
+ continue;
+
+ if(req_loc >= cur_loc + cur_size)
+ continue;
+
+ if (req_loc + req_size < cur_loc + cur_size) {
+ /*
+ * The old entry completely overlap
+ * with the new entry. So no need
+ * to add new entries
+ */
+ return 1;
+ }
+
+ /*
+ * We have partial overlapping entry
+ * update location and new size
+ */
+
+ *location = cur_loc + cur_size;
+ *size = req_loc + req_size - (*location);
+ /*
+ * Now we need to check whether the new value of
+ * location and size are overlapping
+ */
+ goto restart;
+ }
+
+ /* Not a overlapping entry */
+ return 0;
+
+}
+
+static errcode_t undo_write_tdb(struct undo_private_data * data,
+ ext2_loff_t location, int size)
+
+{
+ TDB_DATA tdb_key, tdb_data;
+ errcode_t retval = 0;
+ int actual = 0;
+ ext2_loff_t cur_loc ;
+
+ if (data->tdb == NULL) {
+ /*
+ * Transaction database not initialized
+ */
+ return 0;
+ }
+
+ if (is_trans_overlapping(data->tdb, &location, &size)) {
+ /*
+ * Already we have the original contents
+ * in the database. So skip this write
+ */
+ return 0;
+ }
+
+ tdb_key.dptr = (unsigned char *)&location;
+ tdb_key.dsize = sizeof(location);
+
+ retval = ext2fs_get_mem(size, &(tdb_data.dptr));
+ if (retval) {
+ return retval;
+ }
+
+ if ((cur_loc = ext2fs_llseek(data->dev, 0, SEEK_CUR)) == -1) {
+ retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
+ goto error_out_lseek;
+ }
+
+ if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
+ retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
+ goto error_out_lseek;
+ }
+
+ actual = read(data->dev, tdb_data.dptr, size);
+ if (actual != size) {
+ /*
+ * eventhough it is read we still are doing a write
+ * so return error that is related to write
+ */
+ retval = EXT2_ET_SHORT_WRITE;
+ goto error_out;
+ }
+
+ tdb_data.dsize = size;
+
+#ifdef DEBUG
+ printf("Printing with key %lld data %x and size %d\n", location, tdb_data.dptr, size);
+#endif
+ // I have libtdb1. Enable after rebasing to latest e2fsprogs that has this API
+ //tdb_transaction_start(data->tdb);
+
+ retval = tdb_store(data->tdb, tdb_key, tdb_data, TDB_INSERT);
+ if (retval == -1) {
+ /* FIXME!! Not sure what should be the error */
+ //tdb_transaction_cancel(data->tdb);
+ retval = EXT2_ET_SHORT_WRITE;
+ goto error_out;
+
+ }
+ //tdb_transaction_commit(data->tdb);
+
+error_out:
+ /* Move the location back */
+ if (ext2fs_llseek(data->dev, cur_loc, SEEK_SET) != cur_loc) {
+ retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
+ goto error_out;
+ }
+
+error_out_lseek:
+ free(tdb_data.dptr);
+ return retval;
+
+}
+
+static void undo_setup_tdb(char *tdb_file,
+ struct undo_private_data *data)
+{
+ errcode_t retval;
+
+ data->tdb = tdb_open(tdb_file, 0, TDB_CLEAR_IF_FIRST,
+ O_RDWR | O_CREAT | O_TRUNC, 0600);
+ return;
+
+}
+static errcode_t undo_open(const char *name, int flags, io_channel *channel)
+{
+ io_channel io = NULL;
+ struct undo_private_data *data = NULL;
+ errcode_t retval;
+ int open_flags;
+ struct stat st;
+
+ if (name == 0)
+ return EXT2_ET_BAD_DEVICE_NAME;
+ retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
+ if (retval)
+ return retval;
+ memset(io, 0, sizeof(struct struct_io_channel));
+ io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
+ retval = ext2fs_get_mem(sizeof(struct undo_private_data), &data);
+ if (retval)
+ goto cleanup;
+
+ io->manager = undo_io_manager;
+ retval = ext2fs_get_mem(strlen(name)+1, &io->name);
+ if (retval)
+ goto cleanup;
+
+ strcpy(io->name, name);
+ io->private_data = data;
+ io->block_size = 1024;
+ io->read_error = 0;
+ io->write_error = 0;
+ io->refcount = 1;
+
+ memset(data, 0, sizeof(struct undo_private_data));
+ data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL;
+
+#ifdef HAVE_OPEN64
+ data->dev = open64(io->name, O_RDONLY);
+#else
+ data->dev = open(io->name, O_RDONLY);
+#endif
+ if (data->dev < 0) {
+ retval = errno;
+ goto cleanup;
+ }
+
+ *channel = io;
+ return 0;
+
+cleanup:
+ if (data) {
+ ext2fs_free_mem(&data);
+ }
+ if (io)
+ ext2fs_free_mem(&io);
+ return retval;
+}
+
+static errcode_t undo_close(io_channel channel)
+{
+ struct undo_private_data *data;
+ errcode_t retval = 0;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct undo_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
+
+ if (--channel->refcount > 0)
+ return 0;
+
+ if (data->tdb)
+ tdb_close(data->tdb);
+
+ if (close(data->dev) < 0)
+ retval = errno;
+
+ ext2fs_free_mem(&channel->private_data);
+ if (channel->name)
+ ext2fs_free_mem(&channel->name);
+ ext2fs_free_mem(&channel);
+
+ return retval;
+}
+
+static errcode_t undo_set_blksize(io_channel channel, int blksize)
+{
+ struct undo_private_data *data;
+ errcode_t retval;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct undo_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
+
+ channel->block_size = blksize;
+ return 0;
+}
+
+
+static errcode_t undo_read_blk(io_channel channel, unsigned long block,
+ int count, void *buf)
+{
+ return 0;
+}
+
+static errcode_t undo_write_blk(io_channel channel, unsigned long block,
+ int count, const void *buf)
+{
+ struct undo_private_data *data;
+ errcode_t retval = 0;
+ ssize_t size;
+ ext2_loff_t location;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct undo_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
+
+
+ if (count == 1)
+ size = channel->block_size;
+ else {
+ if (count < 0)
+ size = -count;
+ else
+ size = count * channel->block_size;
+ }
+
+ location = ((ext2_loff_t) block * channel->block_size) + data->offset;
+
+ retval = undo_write_tdb(data, location, size);
+ if (retval) {
+ return retval;
+ }
+
+ return 0;
+
+}
+
+static errcode_t undo_write_byte(io_channel channel, unsigned long offset,
+ int size, const void *buf)
+{
+ struct undo_private_data *data;
+ errcode_t retval = 0;
+ ssize_t actual;
+ ext2_loff_t location;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct undo_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
+
+ location = offset + data->offset;
+ retval = undo_write_tdb(data, location, size);
+ if (retval)
+ return retval;
+
+ return 0;
+}
+
+/*
+ * Flush data buffers to disk.
+ */
+static errcode_t undo_flush(io_channel channel)
+{
+ return 0;
+}
+
+static errcode_t undo_set_option(io_channel channel, const char *option,
+ const char *arg)
+{
+ struct undo_private_data *data;
+ unsigned long tmp;
+ char *end;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct undo_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
+
+ if (!strcmp(option, "offset")) {
+ if (!arg)
+ return EXT2_ET_INVALID_ARGUMENT;
+
+ tmp = strtoul(arg, &end, 0);
+ if (*end)
+ return EXT2_ET_INVALID_ARGUMENT;
+ data->offset = tmp;
+ return 0;
+ }
+
+ if (!strcmp(option, "tdbfilename")) {
+ if (!arg)
+ return EXT2_ET_INVALID_ARGUMENT;
+
+ data->tdb_file = strdup(arg);
+ /*
+ * Initialize the database context
+ * We need to do it in set_option because when
+ * undo_open is called we don't have the
+ * tdb file name set.
+ */
+ undo_setup_tdb(data->tdb_file, data);
+ return 0;
+ }
+ return EXT2_ET_INVALID_ARGUMENT;
+}
--
1.5.2.rc0.71.g4342-dirty
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 1/2] Add stack I/O manager.
[not found] ` <d286e4520f717821cf2363ff3c71a9fff5ecad2f.1178698029.git.aneesh.kumar@linux.vnet.ibm.com>
2007-05-09 8:12 ` [PATCH 1/2] Add stack " Aneesh Kumar K.V
[not found] ` <cd9cd245faaef0628edabe875c507543f3195991.1178698029.git.aneesh.kumar@linux.vnet.ibm.com>
@ 2007-05-09 8:29 ` Aneesh Kumar K.V
2007-05-19 3:31 ` Theodore Tso
3 siblings, 0 replies; 7+ messages in thread
From: Aneesh Kumar K.V @ 2007-05-09 8:29 UTC (permalink / raw)
To: linux-ext4, tytso; +Cc: aneesh.kumar
This I/O manager helps in stacking different I/O managers.
For example one can stack the undo I/O manager on top
of Unix I/O manager to achieve the undo functionality.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
---
lib/ext2fs/Makefile.in | 10 +-
lib/ext2fs/ext2_io.h | 4 +
lib/ext2fs/stack_io.c | 419 ++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 431 insertions(+), 2 deletions(-)
create mode 100644 lib/ext2fs/stack_io.c
diff --git a/lib/ext2fs/Makefile.in b/lib/ext2fs/Makefile.in
index 799659e..f5d141a 100644
--- a/lib/ext2fs/Makefile.in
+++ b/lib/ext2fs/Makefile.in
@@ -66,7 +66,8 @@ OBJS= $(DEBUGFS_LIB_OBJS) $(RESIZE_LIB_OBJS) $(E2IMAGE_LIB_OBJS) \
unix_io.o \
unlink.o \
valid_blk.o \
- version.o
+ version.o \
+ stack_io.o
SRCS= ext2_err.c \
$(srcdir)/alloc.c \
@@ -134,7 +135,8 @@ SRCS= ext2_err.c \
$(srcdir)/tst_bitops.c \
$(srcdir)/tst_byteswap.c \
$(srcdir)/tst_getsize.c \
- $(srcdir)/tst_iscan.c
+ $(srcdir)/tst_iscan.c \
+ $(srcdir)/stack_io.c
HFILES= bitops.h ext2fs.h ext2_io.h ext2_fs.h ext2_ext_attr.h ext3_extents.h
HFILES_IN= ext2_err.h ext2_types.h
@@ -550,3 +552,7 @@ tst_iscan.o: $(srcdir)/tst_iscan.c $(srcdir)/ext2_fs.h \
$(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
$(srcdir)/ext2_fs.h $(top_srcdir)/lib/et/com_err.h $(srcdir)/ext2_io.h \
$(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+stack_io.o: $(srcdir)/stack_io.c $(srcdir)/ext2_fs.h \
+ $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
+ $(srcdir)/ext2_fs.h $(top_srcdir)/lib/et/com_err.h $(srcdir)/ext2_io.h \
+ $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
diff --git a/lib/ext2fs/ext2_io.h b/lib/ext2fs/ext2_io.h
index eada278..65a294e 100644
--- a/lib/ext2fs/ext2_io.h
+++ b/lib/ext2fs/ext2_io.h
@@ -96,6 +96,10 @@ extern errcode_t io_channel_write_byte(io_channel channel,
/* unix_io.c */
extern io_manager unix_io_manager;
+/* stack_io.c */
+extern struct struct_io_manager *stack_io_manager_init(void);
+extern errcode_t stack_push_io_manager(struct struct_io_manager *stack,
+ struct struct_io_manager *io);
/* test_io.c */
extern io_manager test_io_manager, test_io_backing_manager;
extern void (*test_io_cb_read_blk)
diff --git a/lib/ext2fs/stack_io.c b/lib/ext2fs/stack_io.c
new file mode 100644
index 0000000..5adfe4d
--- /dev/null
+++ b/lib/ext2fs/stack_io.c
@@ -0,0 +1,419 @@
+/*
+ * stack_io.c --- This is the io manager used to stack different io managers.
+ *
+ * Copyright (C) 1996 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_PRCTL_H
+#include <sys/prctl.h>
+#else
+#define PR_GET_DUMPABLE 3
+#endif
+#if (!defined(HAVE_PRCTL) && defined(linux))
+#include <sys/syscall.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+#include "kernel-list.h"
+
+/*
+ * For checking structure magic numbers...
+ */
+
+#define EXT2_CHECK_MAGIC(struct, code) \
+ if ((struct)->magic != (code)) return (code)
+
+#define EXT2_ET_MAGIC_STACK_IO_CHANNEL (2133571428L)
+
+struct stack_private_data {
+ int magic;
+ struct list_head st_elements;
+};
+
+struct stack_element {
+ struct struct_io_manager *io;
+ struct struct_io_channel *channel;
+ struct list_head list;
+};
+
+
+static errcode_t stack_open(const char *name, int flags, io_channel *channel);
+static errcode_t stack_close(io_channel channel);
+static errcode_t stack_set_blksize(io_channel channel, int blksize);
+static errcode_t stack_read_blk(io_channel channel, unsigned long block,
+ int count, void *data);
+static errcode_t stack_write_blk(io_channel channel, unsigned long block,
+ int count, const void *data);
+static errcode_t stack_flush(io_channel channel);
+static errcode_t stack_write_byte(io_channel channel, unsigned long offset,
+ int count, const void *buf);
+static errcode_t stack_set_option(io_channel channel, const char *option,
+ const char *arg);
+
+static struct struct_io_manager struct_stack_manager = {
+ .magic = EXT2_ET_MAGIC_IO_MANAGER,
+ .name = "Stack I/O Manager",
+ .open = stack_open,
+ .close = stack_close,
+ .set_blksize = stack_set_blksize,
+ .read_blk = stack_read_blk,
+ .write_blk = stack_write_blk,
+ .flush = stack_flush,
+ .write_byte = stack_write_byte,
+ .set_option = stack_set_option,
+};
+
+io_manager stack_io_manager = &struct_stack_manager;
+/* FIXME!! get rid of this. not thread safe */
+static struct stack_private_data private_data;
+struct struct_io_manager *stack_io_manager_init(void)
+{
+
+
+ INIT_LIST_HEAD(&(private_data.st_elements));
+ private_data.magic = EXT2_ET_MAGIC_STACK_IO_CHANNEL;
+
+ return stack_io_manager;
+
+}
+
+errcode_t stack_push_io_manager(struct struct_io_manager *stack, struct struct_io_manager *io)
+{
+ errcode_t retval;
+ (void)(stack);
+ struct stack_element *element;
+ retval = ext2fs_get_mem(sizeof(struct stack_element), &element);
+ if (retval)
+ return retval;
+ element->io = io;
+ list_add(&(element->list), &(private_data.st_elements));
+
+ return 0;
+}
+
+
+static errcode_t stack_open(const char *name, int flags, io_channel *channel)
+{
+ io_channel io = NULL, stack_io_channel = NULL;
+ errcode_t retval;
+ char *value;
+ struct list_head *entry;
+ struct stack_element *element;
+
+ if (name == 0)
+ return EXT2_ET_BAD_DEVICE_NAME;
+ retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
+ if (retval)
+ return retval;
+ memset(io, 0, sizeof(struct struct_io_channel));
+ io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
+
+ io->manager = stack_io_manager;
+ retval = ext2fs_get_mem(strlen(name)+1, &io->name);
+ if (retval)
+ goto cleanup;
+
+ strcpy(io->name, name);
+ io->private_data = &(private_data);
+ io->block_size = 1024;
+ io->read_error = 0;
+ io->write_error = 0;
+ io->refcount = 1;
+
+ /*
+ * Now call all the io managers open routine
+ */
+ list_for_each(entry, &(private_data.st_elements)) {
+
+ element = list_entry(entry, struct stack_element, list);
+ if (element->io) {
+ retval = element->io->open(name, flags,
+ &stack_io_channel);
+ if (retval) {
+ /*
+ * FIXME!! we need cleanup previous
+ * successfull I/O manager open
+ */
+ goto cleanup;
+ }
+ }
+ element->channel = stack_io_channel;
+ }
+
+ *channel = io;
+ return 0;
+
+cleanup:
+ if (io)
+ ext2fs_free_mem(&io);
+ return retval;
+}
+
+static errcode_t stack_io_channel_close(io_channel channel)
+{
+ if (channel && channel->manager->close)
+ return channel->manager->close(channel);
+
+ return 0;
+
+}
+
+static errcode_t stack_close(io_channel channel)
+{
+ struct stack_private_data *data;
+ struct list_head *entry;
+ struct stack_element *element;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct stack_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_STACK_IO_CHANNEL);
+
+ if (--channel->refcount > 0)
+ return 0;
+
+ list_for_each(entry, &(data->st_elements)) {
+ element = list_entry(entry, struct stack_element, list);
+ stack_io_channel_close(element->channel);
+ }
+
+ if (channel->name)
+ ext2fs_free_mem(&channel->name);
+ ext2fs_free_mem(&channel);
+
+ return 0;
+}
+
+static errcode_t stack_io_channel_set_blksize(io_channel channel, int blksize)
+{
+ if (channel && channel->manager->set_blksize)
+ return channel->manager->set_blksize(channel, blksize);
+
+ return 0;
+
+}
+static errcode_t stack_set_blksize(io_channel channel, int blksize)
+{
+ struct stack_private_data *data;
+ struct list_head *entry;
+ struct stack_element *element;
+ errcode_t retval = 0;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct stack_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_STACK_IO_CHANNEL);
+
+ list_for_each(entry, &(data->st_elements)) {
+ element = list_entry(entry, struct stack_element, list);
+ retval = stack_io_channel_set_blksize(element->channel, blksize);
+ if (retval)
+ return retval;
+ }
+
+ channel->block_size = blksize;
+ return retval;
+}
+
+#define list_for_each_prev(pos, head) \
+ for (pos = (head)->prev; pos != (head); \
+ pos = pos->prev)
+
+static errcode_t stack_io_channel_read_blk(io_channel channel,
+ unsigned long block, int count, void *buf)
+{
+ if (channel && channel->manager->read_blk)
+ return channel->manager->read_blk(channel,
+ block, count, buf);
+
+ return 0;
+}
+static errcode_t stack_read_blk(io_channel channel, unsigned long block,
+ int count, void *buf)
+{
+ struct stack_private_data *data;
+ struct list_head *entry;
+ struct stack_element *element;
+ errcode_t retval = 0;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct stack_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_STACK_IO_CHANNEL);
+
+ /*
+ * we should read int the reverse order
+ */
+ list_for_each_prev(entry, &(data->st_elements)) {
+ element = list_entry(entry, struct stack_element, list);
+ retval = stack_io_channel_read_blk(element->channel, block, count, buf);
+ if (retval)
+ return retval;
+ }
+
+ return retval;
+}
+
+static errcode_t stack_io_channel_write_blk(io_channel channel,
+ unsigned long block, int count, const void *buf)
+{
+ if (channel && channel->manager->write_blk)
+ return channel->manager->write_blk(channel,
+ block, count, buf);
+
+ return 0;
+}
+static errcode_t stack_write_blk(io_channel channel, unsigned long block,
+ int count, const void *buf)
+{
+ struct stack_private_data *data;
+ struct list_head *entry;
+ struct stack_element *element;
+ errcode_t retval = 0;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct stack_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_STACK_IO_CHANNEL);
+
+ list_for_each(entry, &(data->st_elements)) {
+ element = list_entry(entry, struct stack_element, list);
+ retval = stack_io_channel_write_blk(element->channel, block, count, buf);
+ if (retval)
+ return retval;
+ }
+
+ return retval;
+}
+
+static errcode_t stack_io_channel_write_byte(io_channel channel,
+ unsigned long offset, int count, const void *buf)
+{
+ if (channel && channel->manager->write_byte)
+ return channel->manager->write_byte(channel,
+ offset, count, buf);
+
+ return 0;
+}
+
+static errcode_t stack_write_byte(io_channel channel, unsigned long offset,
+ int count, const void *buf)
+{
+ struct stack_private_data *data;
+ struct list_head *entry;
+ struct stack_element *element;
+ errcode_t retval = 0;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct stack_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_STACK_IO_CHANNEL);
+
+ list_for_each(entry, &(data->st_elements)) {
+ element = list_entry(entry, struct stack_element, list);
+ retval = stack_io_channel_write_byte(element->channel, offset, count, buf);
+ if (retval)
+ return retval;
+ }
+
+ return retval;
+}
+
+static errcode_t stack_io_channel_flush(io_channel channel)
+{
+ if (channel && channel->manager->flush)
+ return channel->manager->flush(channel);
+
+ return 0;
+
+}
+
+/*
+ * Flush data buffers to disk.
+ */
+static errcode_t stack_flush(io_channel channel)
+{
+ struct stack_private_data *data;
+ struct list_head *entry;
+ struct stack_element *element;
+ errcode_t retval = 0;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct stack_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_STACK_IO_CHANNEL);
+
+ list_for_each(entry, &(data->st_elements)) {
+ element = list_entry(entry, struct stack_element, list);
+ retval = stack_io_channel_flush(element->channel);
+ if (retval)
+ return retval;
+ }
+
+ return retval;
+}
+
+
+static errcode_t stack_io_channel_set_option(io_channel channel,
+ const char *option, const char *arg)
+{
+ if (channel && channel->manager->set_option)
+ return channel->manager->set_option(channel,
+ option, arg);
+
+ return 0;
+
+}
+static errcode_t stack_set_option(io_channel channel, const char *option,
+ const char *arg)
+{
+ struct stack_private_data *data;
+ struct list_head *entry;
+ struct stack_element *element;
+ errcode_t retval = 0;
+ struct struct_io_manager *io_mng;
+ int success;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct stack_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_STACK_IO_CHANNEL);
+
+ list_for_each(entry, &(data->st_elements)) {
+ element = list_entry(entry, struct stack_element, list);
+ retval = stack_io_channel_set_option(element->channel,
+ option, arg);
+ if (retval == 0) {
+ success = 1;
+ continue;
+ }
+
+ if (retval == EXT2_ET_INVALID_ARGUMENT) {
+ /*
+ * this may be the option for some other io manager
+ * if everybody said EXT2_ET_INVALID_ARGUMENT
+ * then we will return that
+ */
+ continue;
+ } else {
+ return retval;
+ }
+ }
+
+ if (success)
+ return 0;
+
+ return retval;
+}
--
1.5.2.rc0.71.g4342-dirty
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 1/2] Add stack I/O manager.
[not found] ` <d286e4520f717821cf2363ff3c71a9fff5ecad2f.1178698029.git.aneesh.kumar@linux.vnet.ibm.com>
` (2 preceding siblings ...)
2007-05-09 8:29 ` [PATCH 1/2] Add stack " Aneesh Kumar K.V
@ 2007-05-19 3:31 ` Theodore Tso
2007-05-21 10:27 ` Aneesh Kumar K.V
3 siblings, 1 reply; 7+ messages in thread
From: Theodore Tso @ 2007-05-19 3:31 UTC (permalink / raw)
To: Aneesh Kumar K.V; +Cc: linux-ext4
On Wed, May 09, 2007 at 01:42:17PM +0530, Aneesh Kumar K.V wrote:
> From: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
>
> This I/O manager helps in stacking different I/O managers.
> For example one can stack the undo I/O manager on top
> of Unix I/O manager to achieve the undo functionality.
This is probably more generality than is strictly necessary; and the
place where the excess generality gets messy is the fact that you make
the stacking layer responsible for calling all of the io manager's
open routines (which is still a FIXME). So I would flush the stack_io
layer entirely.
What I would recommend as the fast and dirty approach. Basically, ape
the approach used by test_io layer _exactly_, except instead of using
a global variable test_io_backing_manager, you provide a function
which sets the static variable, undo_io_backing_manager. This
variable is used only by the subsequent call to the ->open method,
which just like test_io simply passes the name down to the backing
manager specified in the static variable. Then just make the undo_io
manager work the way test_io does, where does its thing, and then it
calls the appropriate function in its private->real io_channel.
Basically, make undo_io responsible for calling the next io_manager
down in the chain, This is workable because we don't need to
initialize the tdb file until we first try to write to the io_channel,
and ext2fs_open() only needs to do read operations, so we can set the
tdb filename via an optoin after ext2fs_open() returns.
I could imagine a more complicated approach where we still wouldn't
have a stacking layer, but have an integrated parsing layer which
would have registered names for each of the io_managers. It would
then take the part of the name before the colon, and treat it as the
type (i.e., "file"), and the part after the colon and pass it to the
relevant's io_manager (i.e., "/dev/sda4"). So you could pass in a
name like "file:/dev/sda4".
For the test_io manager, since it doesn't need any arguments, it could
just take the part after the colon, and use it to pass back to the
parsing layer. So names to test_io manager would look like this:
"test:file:/dev/sda4".
For managers that need two names, we would have to do something a bit
more complicated, like this: "undo:/var/undo/tdbfile#file:/dev/sda4".
But basically, we still make the stacking up to the individual
io_manager. The main advantage with this approach is that all of the
stacking is done via the ASCII string provided by the user, and
there's no need for any special ad-hoc options.
On the other hand, arguably, you want the program decided where to put
the undo file, so that it can be found automatically by e2fsck. So
the fast-and-dirty approach might be the better one anyway --- it
certainly is easier!
Regards,
- Ted
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 1/2] Add stack I/O manager.
2007-05-19 3:31 ` Theodore Tso
@ 2007-05-21 10:27 ` Aneesh Kumar K.V
2007-05-21 15:12 ` Theodore Tso
0 siblings, 1 reply; 7+ messages in thread
From: Aneesh Kumar K.V @ 2007-05-21 10:27 UTC (permalink / raw)
To: Theodore Tso; +Cc: linux-ext4
Theodore Tso wrote:
> On Wed, May 09, 2007 at 01:42:17PM +0530, Aneesh Kumar K.V wrote:
>> From: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
>>
>> This I/O manager helps in stacking different I/O managers.
>> For example one can stack the undo I/O manager on top
>> of Unix I/O manager to achieve the undo functionality.
>
> This is probably more generality than is strictly necessary; and the
> place where the excess generality gets messy is the fact that you make
> the stacking layer responsible for calling all of the io manager's
> open routines (which is still a FIXME). So I would flush the stack_io
> layer entirely.
Can't we address the FIXME by calling the respective close routine in
the failure case.
One thing i didn't like with the stack_io was, we will be opening the
device at each stacked I/O manager layer; which i also think is okey
provided we expect to use these I/O managers independently
>
> What I would recommend as the fast and dirty approach. Basically, ape
> the approach used by test_io layer _exactly_, except instead of using
> a global variable test_io_backing_manager, you provide a function
> which sets the static variable, undo_io_backing_manager. This
> variable is used only by the subsequent call to the ->open method,
> which just like test_io simply passes the name down to the backing
> manager specified in the static variable. Then just make the undo_io
> manager work the way test_io does, where does its thing, and then it
> calls the appropriate function in its private->real io_channel.
> Basically, make undo_io responsible for calling the next io_manager
> down in the chain, This is workable because we don't need to
> initialize the tdb file until we first try to write to the io_channel,
> and ext2fs_open() only needs to do read operations, so we can set the
> tdb filename via an optoin after ext2fs_open() returns.
>
One thing i was confused about was the usage of read_blk, write_blk etc
pointers in test_private_data. With respect to undo I/O manager do i
need to provide them ?. If we really need them, then i was thinking a
generic stacking layer as i send in the patches would be better. That
means any pluggable functionality that we achieve right now by setting
test_io_cb_read_blk etc will be implemented as a I/O manager that does
the particular task. Later we stack all these I/O manager to get the
full functionality.
-aneesh
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 1/2] Add stack I/O manager.
2007-05-21 10:27 ` Aneesh Kumar K.V
@ 2007-05-21 15:12 ` Theodore Tso
0 siblings, 0 replies; 7+ messages in thread
From: Theodore Tso @ 2007-05-21 15:12 UTC (permalink / raw)
To: Aneesh Kumar K.V; +Cc: linux-ext4
On Mon, May 21, 2007 at 03:57:26PM +0530, Aneesh Kumar K.V wrote:
> Can't we address the FIXME by calling the respective close routine in
> the failure case.
You can but it doesn't address the biggest problem, which is if you're
going to add all of this extra complexity, we might as well deal with
the name parsing issue. In your stacking I/O layer, you pass the same
name to all of the stacked modules. That's not necessarily the right
thing to do. It works for test_io because it doesn't need a name
parameter (it just passes the name straight down to the its
lower-layer module). It mostly works for the undo_io layer because
while the tdb pathname could be the passed in open argument, it's
ext2fs_openfs() is openfs, and you don't have to give it its tdb name
until after the ext2fs_openfs() succeeds, and you can pass it down as
an option.
In general, though, you need to worry about what sub-parts of the name
you need to pass down to each of the stacked modules. So the stack_io
layer adds a lot of complexity, but it's not a fully general solution.
So if it's not fully general, maybe something that's simpler is
sufficient, since in truth we probably don't need unlimited levels of
stacking.
> One thing i was confused about was the usage of read_blk, write_blk etc
> pointers in test_private_data. With respect to undo I/O manager do i
> need to provide them ?. If we really need them, then i was thinking a
> generic stacking layer as i send in the patches would be better. That
> means any pluggable functionality that we achieve right now by setting
> test_io_cb_read_blk etc will be implemented as a I/O manager that does
> the particular task. Later we stack all these I/O manager to get the
> full functionality.
The read_blk, write_blk, etc. pointers in test_private_data() are
specific to the test_io layer. That's part of the value-add which the
test_io module provides, and no, the undo I/O manager doesn't need
them. It's just there as part of what the user of the test i/o
manager might want to use, by allowing some arbitrary callback
function to be called for each test i/o. The main place I've used it
is when I want to set effectively a watchpoint on e2fsck, because I'm
trying to figure out which part of e2fsck is reading or writing a
particular block, and I want to dump out the contents of that block
when it reads/writes it. The fastest way to do that is to add a
callback function that tests for the block number, and when it is
triggered, I can have the debugging function print out some or all of
the contents the block. So that's strictly a test i/o manager thing;
the undo i/o manager wouldn't need this at all!
Regards,
- Ted
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2007-05-21 15:12 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-05-09 8:12 e2fsprogs: Undo I/O manager Aneesh Kumar K.V
[not found] ` <d286e4520f717821cf2363ff3c71a9fff5ecad2f.1178698029.git.aneesh.kumar@linux.vnet.ibm.com>
2007-05-09 8:12 ` [PATCH 1/2] Add stack " Aneesh Kumar K.V
[not found] ` <cd9cd245faaef0628edabe875c507543f3195991.1178698029.git.aneesh.kumar@linux.vnet.ibm.com>
2007-05-09 8:12 ` [PATCH 2/2] Add undo " Aneesh Kumar K.V
2007-05-09 8:29 ` [PATCH 1/2] Add stack " Aneesh Kumar K.V
2007-05-19 3:31 ` Theodore Tso
2007-05-21 10:27 ` Aneesh Kumar K.V
2007-05-21 15:12 ` Theodore Tso
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).