Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
fork

Configure Feed

Select the types of activity you want to include in your feed.

ext4: make xattr inode reads faster

ext4_xattr_inode_read() currently reads each block sequentially while
waiting for io operation to complete before moving on to the next
block. This prevents request merging in block layer.

Add a ext4_bread_batch() function that starts reads for all blocks
then optionally waits for them to complete. A similar logic is used
in ext4_find_entry(), so update that code to use the new function.

Signed-off-by: Tahsin Erdogan <tahsin@google.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>

authored by

Tahsin Erdogan and committed by
Theodore Ts'o
9699d4f9 ec000220

+93 -49
+2
fs/ext4/ext4.h
··· 2461 2461 int ext4_inode_is_fast_symlink(struct inode *inode); 2462 2462 struct buffer_head *ext4_getblk(handle_t *, struct inode *, ext4_lblk_t, int); 2463 2463 struct buffer_head *ext4_bread(handle_t *, struct inode *, ext4_lblk_t, int); 2464 + int ext4_bread_batch(struct inode *inode, ext4_lblk_t block, int bh_count, 2465 + bool wait, struct buffer_head **bhs); 2464 2466 int ext4_get_block_unwritten(struct inode *inode, sector_t iblock, 2465 2467 struct buffer_head *bh_result, int create); 2466 2468 int ext4_get_block(struct inode *inode, sector_t iblock,
+44
fs/ext4/inode.c
··· 1015 1015 return ERR_PTR(-EIO); 1016 1016 } 1017 1017 1018 + /* Read a contiguous batch of blocks. */ 1019 + int ext4_bread_batch(struct inode *inode, ext4_lblk_t block, int bh_count, 1020 + bool wait, struct buffer_head **bhs) 1021 + { 1022 + int i, err; 1023 + 1024 + for (i = 0; i < bh_count; i++) { 1025 + bhs[i] = ext4_getblk(NULL, inode, block + i, 0 /* map_flags */); 1026 + if (IS_ERR(bhs[i])) { 1027 + err = PTR_ERR(bhs[i]); 1028 + bh_count = i; 1029 + goto out_brelse; 1030 + } 1031 + } 1032 + 1033 + for (i = 0; i < bh_count; i++) 1034 + /* Note that NULL bhs[i] is valid because of holes. */ 1035 + if (bhs[i] && !buffer_uptodate(bhs[i])) 1036 + ll_rw_block(REQ_OP_READ, REQ_META | REQ_PRIO, 1, 1037 + &bhs[i]); 1038 + 1039 + if (!wait) 1040 + return 0; 1041 + 1042 + for (i = 0; i < bh_count; i++) 1043 + if (bhs[i]) 1044 + wait_on_buffer(bhs[i]); 1045 + 1046 + for (i = 0; i < bh_count; i++) { 1047 + if (bhs[i] && !buffer_uptodate(bhs[i])) { 1048 + err = -EIO; 1049 + goto out_brelse; 1050 + } 1051 + } 1052 + return 0; 1053 + 1054 + out_brelse: 1055 + for (i = 0; i < bh_count; i++) { 1056 + brelse(bhs[i]); 1057 + bhs[i] = NULL; 1058 + } 1059 + return err; 1060 + } 1061 + 1018 1062 int ext4_walk_page_buffers(handle_t *handle, 1019 1063 struct buffer_head *head, 1020 1064 unsigned from,
+14 -29
fs/ext4/namei.c
··· 1342 1342 struct super_block *sb; 1343 1343 struct buffer_head *bh_use[NAMEI_RA_SIZE]; 1344 1344 struct buffer_head *bh, *ret = NULL; 1345 - ext4_lblk_t start, block, b; 1345 + ext4_lblk_t start, block; 1346 1346 const u8 *name = d_name->name; 1347 - int ra_max = 0; /* Number of bh's in the readahead 1347 + size_t ra_max = 0; /* Number of bh's in the readahead 1348 1348 buffer, bh_use[] */ 1349 - int ra_ptr = 0; /* Current index into readahead 1349 + size_t ra_ptr = 0; /* Current index into readahead 1350 1350 buffer */ 1351 - int num = 0; 1352 1351 ext4_lblk_t nblocks; 1353 1352 int i, namelen, retval; 1354 1353 struct ext4_filename fname; ··· 1410 1411 if (ra_ptr >= ra_max) { 1411 1412 /* Refill the readahead buffer */ 1412 1413 ra_ptr = 0; 1413 - b = block; 1414 - for (ra_max = 0; ra_max < NAMEI_RA_SIZE; ra_max++) { 1415 - /* 1416 - * Terminate if we reach the end of the 1417 - * directory and must wrap, or if our 1418 - * search has finished at this block. 1419 - */ 1420 - if (b >= nblocks || (num && block == start)) { 1421 - bh_use[ra_max] = NULL; 1422 - break; 1423 - } 1424 - num++; 1425 - bh = ext4_getblk(NULL, dir, b++, 0); 1426 - if (IS_ERR(bh)) { 1427 - if (ra_max == 0) { 1428 - ret = bh; 1429 - goto cleanup_and_exit; 1430 - } 1431 - break; 1432 - } 1433 - bh_use[ra_max] = bh; 1434 - if (bh) 1435 - ll_rw_block(REQ_OP_READ, 1436 - REQ_META | REQ_PRIO, 1437 - 1, &bh); 1414 + if (block < start) 1415 + ra_max = start - block; 1416 + else 1417 + ra_max = nblocks - block; 1418 + ra_max = min(ra_max, ARRAY_SIZE(bh_use)); 1419 + retval = ext4_bread_batch(dir, block, ra_max, 1420 + false /* wait */, bh_use); 1421 + if (retval) { 1422 + ret = ERR_PTR(retval); 1423 + ra_max = 0; 1424 + goto cleanup_and_exit; 1438 1425 } 1439 1426 } 1440 1427 if ((bh = bh_use[ra_ptr++]) == NULL)
+33 -20
fs/ext4/xattr.c
··· 317 317 */ 318 318 static int ext4_xattr_inode_read(struct inode *ea_inode, void *buf, size_t size) 319 319 { 320 - unsigned long block = 0; 321 - struct buffer_head *bh; 322 - int blocksize = ea_inode->i_sb->s_blocksize; 323 - size_t csize, copied = 0; 324 - void *copy_pos = buf; 320 + int blocksize = 1 << ea_inode->i_blkbits; 321 + int bh_count = (size + blocksize - 1) >> ea_inode->i_blkbits; 322 + int tail_size = (size % blocksize) ?: blocksize; 323 + struct buffer_head *bhs_inline[8]; 324 + struct buffer_head **bhs = bhs_inline; 325 + int i, ret; 325 326 326 - while (copied < size) { 327 - csize = (size - copied) > blocksize ? blocksize : size - copied; 328 - bh = ext4_bread(NULL, ea_inode, block, 0); 329 - if (IS_ERR(bh)) 330 - return PTR_ERR(bh); 331 - if (!bh) 332 - return -EFSCORRUPTED; 333 - 334 - memcpy(copy_pos, bh->b_data, csize); 335 - brelse(bh); 336 - 337 - copy_pos += csize; 338 - block += 1; 339 - copied += csize; 327 + if (bh_count > ARRAY_SIZE(bhs_inline)) { 328 + bhs = kmalloc_array(bh_count, sizeof(*bhs), GFP_NOFS); 329 + if (!bhs) 330 + return -ENOMEM; 340 331 } 341 - return 0; 332 + 333 + ret = ext4_bread_batch(ea_inode, 0 /* block */, bh_count, 334 + true /* wait */, bhs); 335 + if (ret) 336 + goto free_bhs; 337 + 338 + for (i = 0; i < bh_count; i++) { 339 + /* There shouldn't be any holes in ea_inode. */ 340 + if (!bhs[i]) { 341 + ret = -EFSCORRUPTED; 342 + goto put_bhs; 343 + } 344 + memcpy((char *)buf + blocksize * i, bhs[i]->b_data, 345 + i < bh_count - 1 ? blocksize : tail_size); 346 + } 347 + ret = 0; 348 + put_bhs: 349 + for (i = 0; i < bh_count; i++) 350 + brelse(bhs[i]); 351 + free_bhs: 352 + if (bhs != bhs_inline) 353 + kfree(bhs); 354 + return ret; 342 355 } 343 356 344 357 static int ext4_xattr_inode_iget(struct inode *parent, unsigned long ea_ino,