aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOGAWA Hirofumi <hirofumi@mail.parknet.co.jp>2013-01-18 21:30:37 +0900
committerDaniel Phillips <daniel@tux3.org>2013-01-18 21:30:37 +0900
commitbd234d8c596119321785f03856dbe3088c242c9e (patch)
treeb08454a4db3b914a52f8e249b1ee29258b607e51
parent52ae813b02f521e5f2185b05fcff119e51693358 (diff)
downloadlinux-tux3-bd234d8c596119321785f03856dbe3088c242c9e.tar.gz
tux3: Flush log blocks via flush_list()
Now, we are using blockio() to flush log blocks. It is sync I/O and slow. To optimize it, this patch uses normal way to flush, i.e. flush_list(). To do it, this dirties log buffer at initialization. Then add tux3_logmap_io() as ->io handler for logmap. tux3_logmap_io() takes contiguous index buffers. So, allocate blocks for that, then make logchain for log blocks. Now, we can use tux3_flush_inode_internal() for logmap as usual, and it flushes log blocks asynchronously. The following is result of this optimization. fsstress -s 1000 -l 200 -n 200 -p 3 -d /mnt/fsstress kvm (2 vcpus)/i7-3400M before patch real, sys, user 57.359, 0.416, 2.408 57.294, 0.368, 2.420 57.566, 0.364, 2.408 after patch real, sys, user 54.832, 0.376, 2.444 54.624, 0.468, 2.444 55.781, 0.348, 2.480 Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
-rw-r--r--fs/tux3/buffer.h6
-rw-r--r--fs/tux3/buffer_writeback.c8
-rw-r--r--fs/tux3/commit.c43
-rw-r--r--fs/tux3/inode.c7
-rw-r--r--fs/tux3/log.c58
-rw-r--r--fs/tux3/tux3.h3
-rw-r--r--fs/tux3/writeback.c8
7 files changed, 87 insertions, 46 deletions
diff --git a/fs/tux3/buffer.h b/fs/tux3/buffer.h
index 8e05b50780ee0f..0b3865661a8b49 100644
--- a/fs/tux3/buffer.h
+++ b/fs/tux3/buffer.h
@@ -117,6 +117,10 @@ static inline struct buffer_head *bufvec_contig_buf(struct bufvec *bufvec)
return list_entry(first, struct buffer_head, b_assoc_buffers);
}
+/* buffer for each contiguous buffers */
+#define bufvec_buffer_for_each_contig(b, v) \
+ list_for_each_entry(b, &(v)->contig, b_assoc_buffers)
+
static inline block_t bufvec_contig_index(struct bufvec *bufvec)
{
return bufindex(bufvec_contig_buf(bufvec));
@@ -133,6 +137,8 @@ int bufvec_io(int rw, struct bufvec *bufvec, block_t physical, unsigned count);
int bufvec_contig_add(struct bufvec *bufvec, struct buffer_head *buffer);
int flush_list(struct address_space *mapping, struct tux3_iattr_data *idata,
struct list_head *head);
+int __tux3_volmap_io(int rw, struct bufvec *bufvec, block_t physical,
+ unsigned count);
int tux3_volmap_io(int rw, struct bufvec *bufvec);
/* block_fork.c */
diff --git a/fs/tux3/buffer_writeback.c b/fs/tux3/buffer_writeback.c
index a7de60bebd7d1e..3f3fa134c6fbd0 100644
--- a/fs/tux3/buffer_writeback.c
+++ b/fs/tux3/buffer_writeback.c
@@ -787,6 +787,12 @@ int flush_list(struct address_space *mapping, struct tux3_iattr_data *idata,
/*
* I/O helper for physical index buffers (e.g. buffers on volmap)
*/
+int __tux3_volmap_io(int rw, struct bufvec *bufvec, block_t physical,
+ unsigned count)
+{
+ return blockio_vec(rw, bufvec, physical, count);
+}
+
int tux3_volmap_io(int rw, struct bufvec *bufvec)
{
block_t physical = bufvec_contig_index(bufvec);
@@ -795,5 +801,5 @@ int tux3_volmap_io(int rw, struct bufvec *bufvec)
/* FIXME: For now, this is only for write */
assert(rw == WRITE);
- return blockio_vec(rw, bufvec, physical, count);
+ return __tux3_volmap_io(rw, bufvec, physical, count);
}
diff --git a/fs/tux3/commit.c b/fs/tux3/commit.c
index 3f3846bafc3be4..117a73de512e1c 100644
--- a/fs/tux3/commit.c
+++ b/fs/tux3/commit.c
@@ -296,47 +296,11 @@ static int write_btree(struct sb *sb, unsigned delta)
/* allocate and write log blocks */
static int write_log(struct sb *sb)
{
- unsigned index, logcount;
-
/* Finish to logging in this delta */
log_finish(sb);
+ log_finish_cycle(sb);
- /* FIXME: maybe, we should use bufvec to write log blocks at once */
- for (index = 0; index < sb->lognext; index++) {
- block_t block;
- int err = balloc(sb, 1, &block);
- if (err)
- return err;
- struct buffer_head *buffer = blockget(mapping(sb->logmap), index);
- assert(buffer);
- struct logblock *log = bufdata(buffer);
- assert(log->magic == cpu_to_be16(TUX3_MAGIC_LOG));
- log->logchain = sb->super.logchain;
- err = blockio(WRITE, sb, buffer, block);
- if (err) {
- blockput(buffer);
- bfree(sb, block, 1);
- return err;
- }
-
- /*
- * We can obsolete the log blocks after next rollup
- * by LOG_BFREE_RELOG.
- */
- defer_bfree(&sb->derollup, block, 1);
-
- blockput(buffer);
- trace("logchain %lld", block);
- sb->super.logchain = cpu_to_be64(block);
- }
-
- /* Add count of log on this delta to rollup logcount */
- logcount = be32_to_cpu(sb->super.logcount);
- logcount += log_finish_cycle(sb);
-
- sb->super.logcount = cpu_to_be32(logcount);
-
- return 0;
+ return tux3_flush_inode_internal(sb->logmap, TUX3_INIT_DELTA);
}
/* userland only */
@@ -776,10 +740,13 @@ unsigned tux3_inode_delta(struct inode *inode)
switch (tux_inode(inode)->inum) {
case TUX_VOLMAP_INO:
+ case TUX_LOGMAP_INO:
/*
* Note: volmap are special, and has both of
* TUX3_INIT_DELTA and sb->rollup. So TUX3_INIT_DELTA
* can be incorrect if delta was used for buffer.
+ * Note: logmap is similar to volmap, but it doesn't
+ * have sb->rollup buffers.
*/
delta = TUX3_INIT_DELTA;
break;
diff --git a/fs/tux3/inode.c b/fs/tux3/inode.c
index 2717aa1fdf810c..f2c61057d95cc1 100644
--- a/fs/tux3/inode.c
+++ b/fs/tux3/inode.c
@@ -38,12 +38,12 @@ struct inode *tux_new_volmap(struct sb *sb)
return inode;
}
-/* FIXME: kill this, and use another infrastructure instead of inode */
struct inode *tux_new_logmap(struct sb *sb)
{
struct inode *inode = new_inode(vfs_sb(sb));
if (inode) {
tux_set_inum(inode, TUX_LOGMAP_INO);
+ insert_inode_hash(inode);
tux_setup_inode(inode);
}
return inode;
@@ -906,7 +906,10 @@ static void tux_setup_inode(struct inode *inode)
case TUX_LOGMAP_INO:
inode->i_size = (loff_t)sb->volblocks << sb->blockbits;
inode->i_mapping->a_ops = &tux_vol_aops;
- tux_inode(inode)->io = tux3_volmap_io;
+ if (inum == TUX_VOLMAP_INO)
+ tux_inode(inode)->io = tux3_volmap_io;
+ else
+ tux_inode(inode)->io = tux3_logmap_io;
/* Flushed by tux3_flush_inode_internal() */
tux3_set_inode_no_flush(inode);
break;
diff --git a/fs/tux3/log.c b/fs/tux3/log.c
index ad5930f1bd5003..5dc08075086333 100644
--- a/fs/tux3/log.c
+++ b/fs/tux3/log.c
@@ -5,6 +5,10 @@
#include "tux3.h"
+#ifndef trace
+#define trace trace_on
+#endif
+
/*
* Log cache scheme
*
@@ -132,8 +136,11 @@ static void *log_begin(struct sb *sb, unsigned bytes)
if (sb->logpos + bytes > sb->logtop) {
log_finish(sb);
log_next(sb, 1);
+
*(struct logblock *)bufdata(sb->logbuf) = (struct logblock){
- .magic = cpu_to_be16(TUX3_MAGIC_LOG) };
+ .magic = cpu_to_be16(TUX3_MAGIC_LOG),
+ };
+ tux3_mark_buffer_dirty(sb->logbuf);
}
return sb->logpos;
}
@@ -144,6 +151,55 @@ static void log_end(struct sb *sb, void *pos)
mutex_unlock(&sb->loglock);
}
+/*
+ * Flush log blocks.
+ *
+ * Add log blocks to ->logchain list and adjust ->logcount. Then
+ * flush log blocks at once.
+ */
+int tux3_logmap_io(int rw, struct bufvec *bufvec)
+{
+ struct inode *logmap = bufvec_inode(bufvec);
+ struct sb *sb = tux_sb(logmap->i_sb);
+ unsigned count = bufvec_contig_count(bufvec);
+ block_t block, last;
+ struct buffer_head *buffer;
+ int err;
+
+ assert(rw == WRITE);
+ assert(bufvec_contig_index(bufvec) == 0);
+
+ err = balloc(sb, count, &block);
+ if (err) {
+ assert(err);
+ return err;
+ }
+
+ /*
+ * We can obsolete the log blocks after next rollup
+ * by LOG_BFREE_RELOG.
+ */
+ defer_bfree(&sb->derollup, block, count);
+
+ /* Link log blocks to logchain */
+ last = block;
+ bufvec_buffer_for_each_contig(buffer, bufvec) {
+ struct logblock *log = bufdata(buffer);
+
+ assert(log->magic == cpu_to_be16(TUX3_MAGIC_LOG));
+ log->logchain = sb->super.logchain;
+
+ trace("logchain %lld", last);
+ sb->super.logchain = cpu_to_be64(last);
+ last++;
+ }
+
+ /* Add count of log on this delta to rollup logcount */
+ be32_add_cpu(&sb->super.logcount, count);
+
+ return __tux3_volmap_io(rw, bufvec, block, count);
+}
+
static void log_intent(struct sb *sb, u8 intent)
{
/* Check whether array is uptodate */
diff --git a/fs/tux3/tux3.h b/fs/tux3/tux3.h
index bbd81c4cd4c198..c9df68488bd40e 100644
--- a/fs/tux3/tux3.h
+++ b/fs/tux3/tux3.h
@@ -128,7 +128,7 @@ static inline void *decode48(void *at, u64 *val)
#define TUX_ATABLE_INO 2
#define TUX_ROOTDIR_INO 3
#define TUX_VOLMAP_INO 61 /* This doesn't have entry in ileaf */
-#define TUX_LOGMAP_INO 62 /* FIXME: remove this */
+#define TUX_LOGMAP_INO 62 /* This is volmap for log blocks */
#define TUX_INVALID_INO 63 /* FIXME: just for debugging */
#define TUX_NORMAL_INO 64 /* until this ino, reserved ino */
@@ -797,6 +797,7 @@ void log_next(struct sb *sb, int pin);
void log_drop(struct sb *sb);
void log_finish(struct sb *sb);
int log_finish_cycle(struct sb *sb);
+int tux3_logmap_io(int rw, struct bufvec *bufvec);
void log_balloc(struct sb *sb, block_t block, unsigned count);
void log_bfree(struct sb *sb, block_t block, unsigned count);
void log_bfree_on_rollup(struct sb *sb, block_t block, unsigned count);
diff --git a/fs/tux3/writeback.c b/fs/tux3/writeback.c
index 56c1c9ecbc084e..cf9a6f9a510072 100644
--- a/fs/tux3/writeback.c
+++ b/fs/tux3/writeback.c
@@ -257,7 +257,8 @@ void __tux3_mark_buffer_dirty(struct buffer_head *buffer, unsigned delta)
inode = buffer_inode(buffer);
#ifdef __KERNEL__
- assert(inode == tux_sb(inode->i_sb)->volmap ||
+ assert(tux_inode(inode)->inum == TUX_VOLMAP_INO ||
+ tux_inode(inode)->inum == TUX_LOGMAP_INO ||
PageLocked(buffer->b_page));
#endif
@@ -270,13 +271,14 @@ void __tux3_mark_buffer_dirty(struct buffer_head *buffer, unsigned delta)
/*
* Mark buffer as dirty to flush at delta flush.
*
- * Specified buffer must be for volmap (i.e. no buffer fork, and
+ * Specified buffer must be for volmap/logmap (i.e. no buffer fork, and
* page->mapping is valid). Otherwise this will race with buffer fork.
*/
void tux3_mark_buffer_dirty(struct buffer_head *buffer)
{
struct inode *inode = buffer_inode(buffer);
- assert(inode == tux_sb(inode->i_sb)->volmap); /* must be volmap */
+ assert(tux_inode(inode)->inum == TUX_VOLMAP_INO ||
+ tux_inode(inode)->inum == TUX_LOGMAP_INO);
__tux3_mark_buffer_dirty(buffer, TUX3_INIT_DELTA);
}