linux-ext4.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Bernd Schubert <bernd.schubert@itwm.fraunhofer.de>
To: linux-ext4@vger.kernel.org
Cc: adilger@whamcloud.com, colyli@gmail.com
Subject: [PATCH 3/3] dx read-ahead: Map blocks with a single semaphore lock
Date: Mon, 20 Jun 2011 22:29:00 +0200	[thread overview]
Message-ID: <20110620202900.2473133.26051.stgit@localhost.localdomain> (raw)
In-Reply-To: <20110620202631.2473133.4166.stgit@localhost.localdomain>

Map all ra-blocks using a single down_read(&EXT4_I(inode)->i_data_sem
as Andreas suggested.

Signed-off-by: Bernd Schubert <bernd.schubert@itwm.fraunhofer.de>
---
 fs/ext4/ext4.h  |    2 +
 fs/ext4/inode.c |   93 +++++++++++++++++++++++++++++++++++++++++++++++--------
 fs/ext4/namei.c |   23 +++++++++-----
 3 files changed, 96 insertions(+), 22 deletions(-)

diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 997323a..213ac7c 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1804,7 +1804,7 @@ struct buffer_head *ext4_getblk(handle_t *, struct inode *,
 						ext4_lblk_t, int, int *);
 struct buffer_head *ext4_bread(handle_t *, struct inode *,
 						ext4_lblk_t, int, int *);
-int ext4_bread_ra(struct inode *inode, ext4_lblk_t block);
+void ext4_bread_ra(struct inode *inode, ext4_lblk_t blocks[], int nblocks);
 int ext4_get_block(struct inode *inode, sector_t iblock,
 				struct buffer_head *bh_result, int create);
 
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 938fb6c..5b325c0 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -1382,6 +1382,36 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
 	return retval;
 }
 
+
+/*
+ * Simplified version to map blocks for read-aheads. We only try
+ * to map existing blocks
+ * NOTE: Should be called with down_read(&EXT4_I(inode)->i_data_sem)
+ */
+int ext4_ra_map_blocks(struct inode *inode, struct ext4_map_blocks *map)
+{
+	int retval;
+
+	map->m_flags = 0;
+	ext_debug("ext4_map_blocks(): inode %lu, flag %d, max_blocks %u,"
+		  "logical block %lu\n", inode->i_ino, flags, map->m_len,
+		  (unsigned long) map->m_lblk);
+
+	if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {
+		retval = ext4_ext_map_blocks(NULL, inode, map, 0);
+	} else {
+		retval = ext4_ind_map_blocks(NULL, inode, map, 0);
+	}
+
+	if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) {
+		int ret = check_block_validity(inode, map);
+		if (ret != 0)
+			return ret;
+	}
+
+	return retval;
+}
+
 /* Maximum number of blocks we map for direct IO at once. */
 #define DIO_MAX_BLOCKS 4096
 
@@ -1491,6 +1521,34 @@ struct buffer_head *ext4_getblk(handle_t *handle, struct inode *inode,
 }
 
 /*
+ * Get an array of buffer heads for read-head.
+ * Blocks that cannot be mapped will be filled into bhs as NULL. The caller
+ * needs to check for that.
+ */
+void ext4_ra_getblks(struct buffer_head *bhs[], struct inode *inode,
+				ext4_lblk_t *blocks, int nblocks)
+{
+	struct ext4_map_blocks map;
+	int err;
+	int i;
+
+	down_read((&EXT4_I(inode)->i_data_sem));
+	for(i = 0; i < nblocks; i++) {
+		map.m_lblk = blocks[i];
+		map.m_len = 1;
+		err = ext4_ra_map_blocks(inode, &map);
+
+		if (err <= 0) {
+			bhs[i] = NULL;
+			continue;
+		}
+
+		bhs[i] = sb_getblk(inode->i_sb, map.m_pblk);
+	}
+	up_read((&EXT4_I(inode)->i_data_sem));
+}
+
+/*
   * Synchronous read of blocks
   */
 struct buffer_head *ext4_bread(handle_t *handle, struct inode *inode,
@@ -1514,26 +1572,35 @@ struct buffer_head *ext4_bread(handle_t *handle, struct inode *inode,
 }
 
 /*
- * Read-ahead blocks
+ * Read-ahead blocks. If something fails we just return silently.
  */
-int ext4_bread_ra(struct inode *inode, ext4_lblk_t block)
+void ext4_bread_ra(struct inode *inode, ext4_lblk_t blocks[], int nblocks)
 {
-	struct buffer_head *bh;
-	int err;
+	int i;
+	size_t size = sizeof(struct buffer_head *) * nblocks;
+	struct buffer_head **bhs = kmalloc(size, GFP_KERNEL);
 
-	bh = ext4_getblk(NULL, inode, block, 0, &err);
-	if (!bh)
-		return -1;
+	if (!bhs)
+		return; /* out of memory */
+
+	ext4_ra_getblks(bhs, inode, blocks, nblocks);
+
+	for (i = 0; i < nblocks; i++) {
+		struct buffer_head *bh = bhs[i];
 
-	if (buffer_uptodate(bh)) {
+		if (!bh)
+			continue;
+
+		if (buffer_uptodate(bh)) {
+			brelse(bh);
+			continue;
+		}
+	
+		ll_rw_block(READA, 1, &bh);
 		brelse(bh);
-		return 0;
 	}
 
-	ll_rw_block(READA, 1, &bh);
-
-	brelse(bh);
-	return 0;
+	kfree(bhs);
 }
 
 
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 9643722..34f6f90 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -51,6 +51,7 @@
 
 #define NAMEI_RA_DX_BLOCKS  32 /* Better use BH_LRU_SIZE? */
 
+
 static struct buffer_head *ext4_append(handle_t *handle,
 					struct inode *inode,
 					ext4_lblk_t *block, int *err)
@@ -336,18 +337,25 @@ struct stats dx_show_entries(struct dx_hash_info *hinfo, struct inode *dir,
 #endif /* DX_DEBUG */
 
 /*
- * Read ahead directory index blocks
+ * Read ahead directory index blocks. Quit silently on errors.
  */
 static void dx_ra_blocks(struct inode *dir, struct dx_entry *entries,
 			 struct dx_entry *at)
 {
-	int i, err = 0;
+	int i;
 	struct dx_entry *first_ra_entry = entries + 1;
 	unsigned num_entries = dx_get_count(entries) - 1;
+	
+	size_t size = sizeof(ext4_lblk_t) * NAMEI_RA_DX_BLOCKS;
+	ext4_lblk_t *blocks = kmalloc(size, GFP_KERNEL);
+	
+	if (!blocks)
+		return; /* out of memory */
 
 	if (num_entries < 2 || num_entries > dx_get_limit(entries)) {
 		dxtrace(printk("dx read-ahead: invalid number of entries:%d\n",
 			       num_entries));
+		kfree(blocks);
 		return;
 	}
 
@@ -370,13 +378,12 @@ static void dx_ra_blocks(struct inode *dir, struct dx_entry *entries,
 	dxtrace(printk("dx read-ahead: %d entries in dir-ino %lu \n",
 			num_entries, dir->i_ino));
 
-	i = 0;
-	do {
-		struct dx_entry *entry = first_ra_entry + i;
+	for(i = 0; i < num_entries; i++)
+		blocks[i] = dx_get_block(first_ra_entry + i);
+
+	ext4_bread_ra(dir, blocks, num_entries);
 
-		err = ext4_bread_ra(dir, dx_get_block(entry));
-		i++;
-	 } while (i < num_entries && !err);
+	kfree(blocks);
 }
 
 /*


      parent reply	other threads:[~2011-06-20 20:29 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-06-20 20:28 [PATCH 0/3] directory index patch set v2 Bernd Schubert
2011-06-20 20:28 ` [PATCH 1/3] ext4: Fix compilation with -DDX_DEBUG v2 Bernd Schubert
     [not found]   ` <4E0012A4.1010608@gmail.com>
2011-06-21 15:26     ` Bernd Schubert
2011-07-16 23:41   ` Ted Ts'o
2011-07-19 15:02     ` Bernd Schubert
2011-07-20 21:25       ` Jan Kara
2011-06-20 20:28 ` [PATCH 2/3] ext4 directory index: read-ahead blocks v2 Bernd Schubert
2011-07-16 23:59   ` Ted Ts'o
2011-07-17  1:02     ` Bernd Schubert
2011-07-17 13:12       ` Theodore Tso
2011-07-18  0:23         ` Ted Ts'o
2011-07-19 14:22           ` Bernd Schubert
2011-06-20 20:29 ` Bernd Schubert [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20110620202900.2473133.26051.stgit@localhost.localdomain \
    --to=bernd.schubert@itwm.fraunhofer.de \
    --cc=adilger@whamcloud.com \
    --cc=colyli@gmail.com \
    --cc=linux-ext4@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).