[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20110620202900.2473133.26051.stgit@localhost.localdomain>
Date: Mon, 20 Jun 2011 22:29:00 +0200
From: Bernd Schubert <bernd.schubert@...m.fraunhofer.de>
To: linux-ext4@...r.kernel.org
Cc: adilger@...mcloud.com, colyli@...il.com
Subject: [PATCH 3/3] dx read-ahead: Map blocks with a single semaphore lock
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@...m.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);
}
/*
--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists