Re: [PATCH 6/9] nilfs2: use modification cache to improve performance
On Tue, 24 Feb 2015 20:01:41 +0100, Andreas Rohner wrote: This patch adds a small cache to accumulate the small decrements of the number of live blocks in a segment usage entry. If for example a large file is deleted, the segment usage entry has to be updated for every single block. But for every decrement, a MDT write lock has to be aquired, which blocks the entire SUFILE and effectively turns this lock into a global lock for the whole file system. The cache tries to ameliorate this situation by adding up the decrements and increments for a given number of segments and applying the changes all at once. Because the changes are accumulated in memory and not immediately written to the SUFILE, the afore mentioned lock only needs to be aquired, if the cache is full or at the end of the respective operation. To effectively get the pointer to the modification cache from the high level operations down to the update of the individual blocks in nilfs_dat_commit_end(), a new pointer b_private was added to struct nilfs_bmap. Signed-off-by: Andreas Rohner andreas.roh...@gmx.net --- fs/nilfs2/bmap.c| 76 + fs/nilfs2/bmap.h| 11 +++- fs/nilfs2/btree.c | 2 +- fs/nilfs2/direct.c | 2 +- fs/nilfs2/inode.c | 22 +--- fs/nilfs2/segment.c | 26 +++--- fs/nilfs2/segment.h | 3 +++ 7 files changed, 132 insertions(+), 10 deletions(-) diff --git a/fs/nilfs2/bmap.c b/fs/nilfs2/bmap.c index ecd62ba..927acb7 100644 --- a/fs/nilfs2/bmap.c +++ b/fs/nilfs2/bmap.c @@ -288,6 +288,43 @@ int nilfs_bmap_truncate(struct nilfs_bmap *bmap, unsigned long key) } /** + * nilfs_bmap_truncate_with_mc - truncate a bmap to a specified key + * @bmap: bmap + * @mc: modification cache + * @key: key + * + * Description: nilfs_bmap_truncate_with_mc() removes key-record pairs whose + * keys are greater than or equal to @key from @bmap. It has the same + * functionality as nilfs_bmap_truncate(), but allows the passing + * of a modification cache to update segment usage information. + * + * Return Value: On success, 0 is returned. On error, one of the following + * negative error codes is returned. + * + * %-EIO - I/O error. + * + * %-ENOMEM - Insufficient amount of memory available. + */ +int nilfs_bmap_truncate_with_mc(struct nilfs_bmap *bmap, + struct nilfs_sufile_mod_cache *mc, + unsigned long key) +{ + int ret; + + down_write(bmap-b_sem); + + bmap-b_private = mc; + + ret = nilfs_bmap_do_truncate(bmap, key); + + bmap-b_private = NULL; + + up_write(bmap-b_sem); + + return nilfs_bmap_convert_error(bmap, __func__, ret); +} + +/** * nilfs_bmap_clear - free resources a bmap holds * @bmap: bmap * @@ -328,6 +365,43 @@ int nilfs_bmap_propagate(struct nilfs_bmap *bmap, struct buffer_head *bh) } /** + * nilfs_bmap_propagate_with_mc - propagate dirty state + * @bmap: bmap + * @mc: modification cache + * @bh: buffer head + * + * Description: nilfs_bmap_propagate_with_mc() marks the buffers that directly + * or indirectly refer to the block specified by @bh dirty. It has + * the same functionality as nilfs_bmap_propagate(), but allows the passing + * of a modification cache to update segment usage information. + * + * Return Value: On success, 0 is returned. On error, one of the following + * negative error codes is returned. + * + * %-EIO - I/O error. + * + * %-ENOMEM - Insufficient amount of memory available. + */ +int nilfs_bmap_propagate_with_mc(struct nilfs_bmap *bmap, + struct nilfs_sufile_mod_cache *mc, + struct buffer_head *bh) +{ + int ret; + + down_write(bmap-b_sem); + + bmap-b_private = mc; + + ret = bmap-b_ops-bop_propagate(bmap, bh); + + bmap-b_private = NULL; + + up_write(bmap-b_sem); + + return nilfs_bmap_convert_error(bmap, __func__, ret); +} These bmap functions are really bad. The mod cache argument has no meaning with regard to block mapping operation. I really hope we don't have to add these variants by hiding the cache in sufile. + +/** * nilfs_bmap_lookup_dirty_buffers - * @bmap: bmap * @listp: pointer to buffer head list @@ -490,6 +564,7 @@ int nilfs_bmap_read(struct nilfs_bmap *bmap, struct nilfs_inode *raw_inode) init_rwsem(bmap-b_sem); bmap-b_state = 0; + bmap-b_private = NULL; bmap-b_inode = NILFS_BMAP_I(bmap)-vfs_inode; switch (bmap-b_inode-i_ino) { case NILFS_DAT_INO: @@ -551,6 +626,7 @@ void nilfs_bmap_init_gc(struct nilfs_bmap *bmap) bmap-b_last_allocated_key = 0; bmap-b_last_allocated_ptr = NILFS_BMAP_INVALID_PTR; bmap-b_state = 0; + bmap-b_private = NULL; nilfs_btree_init_gc(bmap); } diff --git a/fs/nilfs2/bmap.h b/fs/nilfs2/bmap.h
[PATCH 6/9] nilfs2: use modification cache to improve performance
This patch adds a small cache to accumulate the small decrements of the number of live blocks in a segment usage entry. If for example a large file is deleted, the segment usage entry has to be updated for every single block. But for every decrement, a MDT write lock has to be aquired, which blocks the entire SUFILE and effectively turns this lock into a global lock for the whole file system. The cache tries to ameliorate this situation by adding up the decrements and increments for a given number of segments and applying the changes all at once. Because the changes are accumulated in memory and not immediately written to the SUFILE, the afore mentioned lock only needs to be aquired, if the cache is full or at the end of the respective operation. To effectively get the pointer to the modification cache from the high level operations down to the update of the individual blocks in nilfs_dat_commit_end(), a new pointer b_private was added to struct nilfs_bmap. Signed-off-by: Andreas Rohner andreas.roh...@gmx.net --- fs/nilfs2/bmap.c| 76 + fs/nilfs2/bmap.h| 11 +++- fs/nilfs2/btree.c | 2 +- fs/nilfs2/direct.c | 2 +- fs/nilfs2/inode.c | 22 +--- fs/nilfs2/segment.c | 26 +++--- fs/nilfs2/segment.h | 3 +++ 7 files changed, 132 insertions(+), 10 deletions(-) diff --git a/fs/nilfs2/bmap.c b/fs/nilfs2/bmap.c index ecd62ba..927acb7 100644 --- a/fs/nilfs2/bmap.c +++ b/fs/nilfs2/bmap.c @@ -288,6 +288,43 @@ int nilfs_bmap_truncate(struct nilfs_bmap *bmap, unsigned long key) } /** + * nilfs_bmap_truncate_with_mc - truncate a bmap to a specified key + * @bmap: bmap + * @mc: modification cache + * @key: key + * + * Description: nilfs_bmap_truncate_with_mc() removes key-record pairs whose + * keys are greater than or equal to @key from @bmap. It has the same + * functionality as nilfs_bmap_truncate(), but allows the passing + * of a modification cache to update segment usage information. + * + * Return Value: On success, 0 is returned. On error, one of the following + * negative error codes is returned. + * + * %-EIO - I/O error. + * + * %-ENOMEM - Insufficient amount of memory available. + */ +int nilfs_bmap_truncate_with_mc(struct nilfs_bmap *bmap, + struct nilfs_sufile_mod_cache *mc, + unsigned long key) +{ + int ret; + + down_write(bmap-b_sem); + + bmap-b_private = mc; + + ret = nilfs_bmap_do_truncate(bmap, key); + + bmap-b_private = NULL; + + up_write(bmap-b_sem); + + return nilfs_bmap_convert_error(bmap, __func__, ret); +} + +/** * nilfs_bmap_clear - free resources a bmap holds * @bmap: bmap * @@ -328,6 +365,43 @@ int nilfs_bmap_propagate(struct nilfs_bmap *bmap, struct buffer_head *bh) } /** + * nilfs_bmap_propagate_with_mc - propagate dirty state + * @bmap: bmap + * @mc: modification cache + * @bh: buffer head + * + * Description: nilfs_bmap_propagate_with_mc() marks the buffers that directly + * or indirectly refer to the block specified by @bh dirty. It has + * the same functionality as nilfs_bmap_propagate(), but allows the passing + * of a modification cache to update segment usage information. + * + * Return Value: On success, 0 is returned. On error, one of the following + * negative error codes is returned. + * + * %-EIO - I/O error. + * + * %-ENOMEM - Insufficient amount of memory available. + */ +int nilfs_bmap_propagate_with_mc(struct nilfs_bmap *bmap, +struct nilfs_sufile_mod_cache *mc, +struct buffer_head *bh) +{ + int ret; + + down_write(bmap-b_sem); + + bmap-b_private = mc; + + ret = bmap-b_ops-bop_propagate(bmap, bh); + + bmap-b_private = NULL; + + up_write(bmap-b_sem); + + return nilfs_bmap_convert_error(bmap, __func__, ret); +} + +/** * nilfs_bmap_lookup_dirty_buffers - * @bmap: bmap * @listp: pointer to buffer head list @@ -490,6 +564,7 @@ int nilfs_bmap_read(struct nilfs_bmap *bmap, struct nilfs_inode *raw_inode) init_rwsem(bmap-b_sem); bmap-b_state = 0; + bmap-b_private = NULL; bmap-b_inode = NILFS_BMAP_I(bmap)-vfs_inode; switch (bmap-b_inode-i_ino) { case NILFS_DAT_INO: @@ -551,6 +626,7 @@ void nilfs_bmap_init_gc(struct nilfs_bmap *bmap) bmap-b_last_allocated_key = 0; bmap-b_last_allocated_ptr = NILFS_BMAP_INVALID_PTR; bmap-b_state = 0; + bmap-b_private = NULL; nilfs_btree_init_gc(bmap); } diff --git a/fs/nilfs2/bmap.h b/fs/nilfs2/bmap.h index 718c814..a8b935a 100644 --- a/fs/nilfs2/bmap.h +++ b/fs/nilfs2/bmap.h @@ -36,6 +36,7 @@ struct nilfs_bmap; +struct nilfs_sufile_mod_cache; /** * union nilfs_bmap_ptr_req - request for bmap ptr @@ -106,6 +107,7 @@ static inline int nilfs_bmap_is_new_ptr(unsigned long ptr) * @b_ptr_type: pointer type * @b_state: state *