Re: [PATCH 6/9] nilfs2: use modification cache to improve performance

2015-03-13 Thread Ryusuke Konishi
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

2015-02-24 Thread Andreas Rohner
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
  *