diff options
author | OGAWA Hirofumi <hirofumi@mail.parknet.co.jp> | 2013-01-18 21:30:37 +0900 |
---|---|---|
committer | Daniel Phillips <daniel@tux3.org> | 2013-01-18 21:30:37 +0900 |
commit | bd234d8c596119321785f03856dbe3088c242c9e (patch) | |
tree | b08454a4db3b914a52f8e249b1ee29258b607e51 | |
parent | 52ae813b02f521e5f2185b05fcff119e51693358 (diff) | |
download | linux-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.h | 6 | ||||
-rw-r--r-- | fs/tux3/buffer_writeback.c | 8 | ||||
-rw-r--r-- | fs/tux3/commit.c | 43 | ||||
-rw-r--r-- | fs/tux3/inode.c | 7 | ||||
-rw-r--r-- | fs/tux3/log.c | 58 | ||||
-rw-r--r-- | fs/tux3/tux3.h | 3 | ||||
-rw-r--r-- | fs/tux3/writeback.c | 8 |
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); } |