md/bitmap: Optimal last page size
v4 cover md/bitmap: Optimal last page size
From: Jon Derrick <[email protected]>
Currently the last bitmap page write will size itself down to the logical block size. This could cause less performance for devices which have atomic write units larger than the block size, such as many NVMe devices with 4kB write units and 512B block sizes. There is usually a large amount of space after the bitmap and using the optimal I/O size could favor speed over size.
This was tested on an Intel/Solidigm P5520 drive with lba format 512B, optimal I/O size of 4kB, resulting in a > 10x IOPS increase.
See patch 3 log for results.
v3->v4: Fixed reviewers concernsv2->v3: Prep patch added and types fixed
Added helpers for optimal I/O sizes
Jon Derrick (3):
md: Move sb writer loop to its own function
md: Fix types in sb writer
md: Use optimal I/O size for last bitmap page
drivers/md/md-bitmap.c | 142 ++++++++++++++++++++++++----------------- 1 file changed, 82 insertions(+), 60 deletions(-)
Signature · 1 line
2.27.0
PATCH v4 1/3 md: Move sb writer loop to its own function
From: Jon Derrick <[email protected]>
Preparatory patch for optimal I/O size calculation. Move the sb writer loop routine into its own function for clarity.
--- drivers/md/md-bitmap.c | 124 +++++++++++++++++++++-------------------- 1 file changed, 64 insertions(+), 60 deletions(-)
drivers/md/md-bitmap.c +64 -60
@@ -209,76 +209,80 @@ static struct md_rdev *next_active_rdev(struct md_rdev *rdev, struct mddev *mddereturn NULL ; } -static int write_sb_page (struct bitmap *bitmap,struct page *page,int wait) +static int __write_sb_page (struct md_rdev *rdev,struct bitmap *bitmap, +struct page *page) { -struct md_rdev *rdev;struct block_device *bdev;struct mddev *mddev = bitmap->mddev;struct bitmap_storage *store = &bitmap->storage; +loff_t offset = mddev->bitmap_info.offset; +int size =PAGE_SIZE ; + + bdev = (rdev->meta_bdev) ? rdev->meta_bdev : rdev->bdev; +if (page->index == store->file_pages -1 ) { +int last_page_size = store->bytes & (PAGE_SIZE -1 ); + +if (last_page_size ==0 ) + last_page_size =PAGE_SIZE ; + size =roundup (last_page_size, +bdev_logical_block_size (bdev)); + } + +/* Just make sure we aren't corrupting data or metadata */ +if (mddev->external) { +/* Bitmap could be anywhere. */ +if (rdev->sb_start + offset + + (page->index * (PAGE_SIZE /SECTOR_SIZE )) + > rdev->data_offset && + rdev->sb_start + offset + < (rdev->data_offset + mddev->dev_sectors + + (PAGE_SIZE /SECTOR_SIZE ))) +return -EINVAL ; + }else if (offset <0 ) { +/* DATA BITMAP METADATA */ +if (offset + + (long )(page->index * (PAGE_SIZE /SECTOR_SIZE )) + + size /SECTOR_SIZE >0 ) +/* bitmap runs in to metadata */ +return -EINVAL ; + +if (rdev->data_offset + mddev->dev_sectors + > rdev->sb_start + offset) +/* data runs in to bitmap */ +return -EINVAL ; + }else if (rdev->sb_start < rdev->data_offset) { +/* METADATA BITMAP DATA */ +if (rdev->sb_start + offset + + page->index * (PAGE_SIZE /SECTOR_SIZE ) + + size /SECTOR_SIZE > rdev->data_offset) +/* bitmap runs in to data */ +return -EINVAL ; + }else { +/* DATA METADATA BITMAP - no problems */ + } -restart: - rdev =NULL ; -while ((rdev =next_active_rdev (rdev, mddev)) !=NULL ) { -int size =PAGE_SIZE ; -loff_t offset = mddev->bitmap_info.offset; +md_super_write (mddev, rdev, + rdev->sb_start + offset + + page->index * (PAGE_SIZE /SECTOR_SIZE ), + size, page); +return 0 ; +} - bdev = (rdev->meta_bdev) ? rdev->meta_bdev : rdev->bdev; +static int write_sb_page (struct bitmap *bitmap,struct page *page,int wait) +{ +struct md_rdev *rdev; +struct mddev *mddev = bitmap->mddev; +int ret; -if (page->index == store->file_pages-1 ) { -int last_page_size = store->bytes & (PAGE_SIZE -1 ); -if (last_page_size ==0 ) - last_page_size =PAGE_SIZE ; - size =roundup (last_page_size, -bdev_logical_block_size (bdev)); - } -/* Just make sure we aren't corrupting data or -* metadata -*/ -if (mddev->external) { -/* Bitmap could be anywhere. */ -if (rdev->sb_start + offset + (page->index - * (PAGE_SIZE /512 )) - > rdev->data_offset - && - rdev->sb_start + offset - < (rdev->data_offset + mddev->dev_sectors - + (PAGE_SIZE /512 ))) - goto bad_alignment; - }else if (offset <0 ) { -/* DATA BITMAP METADATA */ -if (offset - + (long )(page->index * (PAGE_SIZE /512 )) - + size/512 >0 ) -/* bitmap runs in to metadata */ - goto bad_alignment; -if (rdev->data_offset + mddev->dev_sectors - > rdev->sb_start + offset) -/* data runs in to bitmap */ - goto bad_alignment; - }else if (rdev->sb_start < rdev->data_offset) { -/* METADATA BITMAP DATA */ -if (rdev->sb_start - + offset - + page->index*(PAGE_SIZE /512 ) + size/512 - > rdev->data_offset) -/* bitmap runs in to data */ - goto bad_alignment; - }else { -/* DATA METADATA BITMAP - no problems */ +do { +while ((rdev =next_active_rdev (rdev, mddev)) !=NULL ) { + ret =__write_sb_page (rdev, bitmap, page); +if (ret) +return ret; } -md_super_write (mddev, rdev, - rdev->sb_start + offset - + page->index * (PAGE_SIZE /512 ), - size, - page); - } + }while (wait &&md_super_wait (mddev) <0 ); -if (wait &&md_super_wait (mddev) <0 ) - goto restart;return 0 ; - - bad_alignment: -return -EINVAL ; }static void md_bitmap_file_kick (struct bitmap *bitmap);
Signature · 1 line
2.27.0
kernel test robot
build botRe: [PATCH v4 1/3] md: Move sb writer loop to its own function
Thank you for the patch! Perhaps something to improve:
Hi Jonathan,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on song-md/md-next]
[also build test WARNING on linus/master v6.2 next-20230224] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Jonathan-Derrick/md-Move-sb-writer-loop-to-its-own-function/20230224-035451 base: git://git.kernel.org/pub/scm/linux/kernel/git/song/md.git md-next patch link: https://lore.kernel.org/r/20230223195225.534-2-jonathan.derrick%40linux.dev patch subject: [PATCH v4 1/3] md: Move sb writer loop to its own function config: s390-randconfig-r036-20230223 (https://download.01.org/0day-ci/archive/20230224/[email protected]/config) compiler: clang version 17.0.0 (https://github.com/llvm/llvm-project db89896bbbd2251fff457699635acbbedeead27f)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross
# install s390 cross compiling tool for clang build
# apt-get install binutils-s390x-linux-gnu
# https://github.com/intel-lab-lkp/linux/commit/93818e631c76938f9a3ad87d1baf681645d02ba7
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review Jonathan-Derrick/md-Move-sb-writer-loop-to-its-own-function/20230224-035451 git checkout 93818e631c76938f9a3ad87d1baf681645d02ba7
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=s390 olddefconfig COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=s390 SHELL=/bin/bash
If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <[email protected]>
| Link: https://lore.kernel.org/oe-kbuild-all/[email protected]/
All warnings (new ones prefixed by >>):
In file included from drivers/md/md-bitmap.c:31:
In file included from include/trace/events/block.h:8:
In file included from include/linux/blktrace_api.h:5:
In file included from include/linux/blk-mq.h:8:
In file included from include/linux/scatterlist.h:9:
In file included from arch/s390/include/asm/io.h:75:
include/asm-generic/io.h:547:31: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
val = __raw_readb(PCI_IOBASE + addr);
~~~~~~~~~~ ^
include/asm-generic/io.h:560:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
val = __le16_to_cpu((__le16 __force)__raw_readw(PCI_IOBASE + addr));
~~~~~~~~~~ ^
include/uapi/linux/byteorder/big_endian.h:37:59: note: expanded from macro '__le16_to_cpu'
#define __le16_to_cpu(x) __swab16((__force __u16)(__le16)(x))
^
include/uapi/linux/swab.h:102:54: note: expanded from macro '__swab16'
#define __swab16(x) (__u16)__builtin_bswap16((__u16)(x))
^
In file included from drivers/md/md-bitmap.c:31:
In file included from include/trace/events/block.h:8:
In file included from include/linux/blktrace_api.h:5:
In file included from include/linux/blk-mq.h:8:
In file included from include/linux/scatterlist.h:9:
In file included from arch/s390/include/asm/io.h:75:
include/asm-generic/io.h:573:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
val = __le32_to_cpu((__le32 __force)__raw_readl(PCI_IOBASE + addr));
~~~~~~~~~~ ^
include/uapi/linux/byteorder/big_endian.h:35:59: note: expanded from macro '__le32_to_cpu'
#define __le32_to_cpu(x) __swab32((__force __u32)(__le32)(x))
^
include/uapi/linux/swab.h:115:54: note: expanded from macro '__swab32'
#define __swab32(x) (__u32)__builtin_bswap32((__u32)(x))
^
In file included from drivers/md/md-bitmap.c:31:
In file included from include/trace/events/block.h:8:
In file included from include/linux/blktrace_api.h:5:
In file included from include/linux/blk-mq.h:8:
In file included from include/linux/scatterlist.h:9:
In file included from arch/s390/include/asm/io.h:75:
include/asm-generic/io.h:584:33: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
__raw_writeb(value, PCI_IOBASE + addr);
~~~~~~~~~~ ^
include/asm-generic/io.h:594:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
__raw_writew((u16 __force)cpu_to_le16(value), PCI_IOBASE + addr);
~~~~~~~~~~ ^
include/asm-generic/io.h:604:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
__raw_writel((u32 __force)cpu_to_le32(value), PCI_IOBASE + addr);
~~~~~~~~~~ ^
include/asm-generic/io.h:692:20: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
readsb(PCI_IOBASE + addr, buffer, count);
~~~~~~~~~~ ^
include/asm-generic/io.h:700:20: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
readsw(PCI_IOBASE + addr, buffer, count);
~~~~~~~~~~ ^
include/asm-generic/io.h:708:20: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
readsl(PCI_IOBASE + addr, buffer, count);
~~~~~~~~~~ ^
include/asm-generic/io.h:717:21: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
writesb(PCI_IOBASE + addr, buffer, count);
~~~~~~~~~~ ^
include/asm-generic/io.h:726:21: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
writesw(PCI_IOBASE + addr, buffer, count);
~~~~~~~~~~ ^
include/asm-generic/io.h:735:21: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
writesl(PCI_IOBASE + addr, buffer, count);
~~~~~~~~~~ ^
>> drivers/md/md-bitmap.c:273:18: warning: variable 'rdev' is used uninitialized whenever function 'write_sb_page' is called [-Wsometimes-uninitialized]
struct md_rdev *rdev;
~~~~~~~~~~~~~~~~^~~~
drivers/md/md-bitmap.c:278:35: note: uninitialized use occurs here
while ((rdev = next_active_rdev(rdev, mddev)) != NULL) {
^~~~
drivers/md/md-bitmap.c:273:22: note: initialize the variable 'rdev' to silence this warning
struct md_rdev *rdev;
^
= NULL13 warnings generated.
vim +273 drivers/md/md-bitmap.c
270
271 static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait)
272 {
> 273 struct md_rdev *rdev;
274 struct mddev *mddev = bitmap->mddev;
275 int ret;
276
277 do {
278 while ((rdev = next_active_rdev(rdev, mddev)) != NULL) {
279 ret = __write_sb_page(rdev, bitmap, page);
280 if (ret)
281 return ret;
282 }
283 } while (wait && md_super_wait(mddev) < 0);
284
285 return 0;
286 }
287
Signature · 2 lines
0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests
Re: [PATCH v4 1/3] md: Move sb writer loop to its own function
Quoted 102 lines · kernel test robot
Hi Jonathan,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on song-md/md-next]
[also build test WARNING on linus/master v6.2 next-20230224] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]url: https://github.com/intel-lab-lkp/linux/commits/Jonathan-Derrick/md-Move-sb-writer-loop-to-its-own-function/20230224-035451 base: git://git.kernel.org/pub/scm/linux/kernel/git/song/md.git md-next patch link: https://lore.kernel.org/r/20230223195225.534-2-jonathan.derrick%40linux.dev patch subject: [PATCH v4 1/3] md: Move sb writer loop to its own function config: s390-randconfig-r036-20230223 (https://download.01.org/0day-ci/archive/20230224/[email protected]/config) compiler: clang version 17.0.0 (https://github.com/llvm/llvm-project db89896bbbd2251fff457699635acbbedeead27f)reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross
# install s390 cross compiling tool for clang build
# apt-get install binutils-s390x-linux-gnu
# https://github.com/intel-lab-lkp/linux/commit/93818e631c76938f9a3ad87d1baf681645d02ba7
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review Jonathan-Derrick/md-Move-sb-writer-loop-to-its-own-function/20230224-035451 git checkout93818e631c76938f9a3ad87d1baf681645d02ba7
# save the config file
mkdirbuild_dir&& cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=s390 olddefconfig COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=s390 SHELL=/bin/bashIf you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <[email protected]>
| Link: https://lore.kernel.org/oe-kbuild-all/[email protected]/All warnings (new ones prefixed by >>):
In file included from drivers/md/md-bitmap.c:31: In file included from include/trace/events/block.h:8: In file included from include/linux/blktrace_api.h:5: In file included from include/linux/blk-mq.h:8: In file included from include/linux/scatterlist.h:9: In file included from arch/s390/include/asm/io.h:75: include/asm-generic/io.h:547:31: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] val = __raw_readb(PCI_IOBASE + addr); ~~~~~~~~~~ ^ include/asm-generic/io.h:560:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] val = __le16_to_cpu((__le16 __force)__raw_readw(PCI_IOBASE + addr)); ~~~~~~~~~~ ^ include/uapi/linux/byteorder/big_endian.h:37:59: note: expanded from macro '__le16_to_cpu' #define __le16_to_cpu(x) __swab16((__force __u16)(__le16)(x)) ^ include/uapi/linux/swab.h:102:54: note: expanded from macro '__swab16' #define __swab16(x) (__u16)__builtin_bswap16((__u16)(x)) ^ In file included from drivers/md/md-bitmap.c:31: In file included from include/trace/events/block.h:8: In file included from include/linux/blktrace_api.h:5: In file included from include/linux/blk-mq.h:8: In file included from include/linux/scatterlist.h:9: In file included from arch/s390/include/asm/io.h:75: include/asm-generic/io.h:573:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] val = __le32_to_cpu((__le32 __force)__raw_readl(PCI_IOBASE + addr)); ~~~~~~~~~~ ^ include/uapi/linux/byteorder/big_endian.h:35:59: note: expanded from macro '__le32_to_cpu' #define __le32_to_cpu(x) __swab32((__force __u32)(__le32)(x)) ^ include/uapi/linux/swab.h:115:54: note: expanded from macro '__swab32' #define __swab32(x) (__u32)__builtin_bswap32((__u32)(x)) ^ In file included from drivers/md/md-bitmap.c:31: In file included from include/trace/events/block.h:8: In file included from include/linux/blktrace_api.h:5: In file included from include/linux/blk-mq.h:8: In file included from include/linux/scatterlist.h:9: In file included from arch/s390/include/asm/io.h:75: include/asm-generic/io.h:584:33: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] __raw_writeb(value, PCI_IOBASE + addr); ~~~~~~~~~~ ^ include/asm-generic/io.h:594:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] __raw_writew((u16 __force)cpu_to_le16(value), PCI_IOBASE + addr); ~~~~~~~~~~ ^ include/asm-generic/io.h:604:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] __raw_writel((u32 __force)cpu_to_le32(value), PCI_IOBASE + addr); ~~~~~~~~~~ ^ include/asm-generic/io.h:692:20: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] readsb(PCI_IOBASE + addr, buffer, count); ~~~~~~~~~~ ^ include/asm-generic/io.h:700:20: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] readsw(PCI_IOBASE + addr, buffer, count); ~~~~~~~~~~ ^ include/asm-generic/io.h:708:20: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] readsl(PCI_IOBASE + addr, buffer, count); ~~~~~~~~~~ ^ include/asm-generic/io.h:717:21: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] writesb(PCI_IOBASE + addr, buffer, count); ~~~~~~~~~~ ^ include/asm-generic/io.h:726:21: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] writesw(PCI_IOBASE + addr, buffer, count); ~~~~~~~~~~ ^ include/asm-generic/io.h:735:21: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] writesl(PCI_IOBASE + addr, buffer, count); ~~~~~~~~~~ ^
Quoted 7 lines
Quoted 1 line
Quoted 1 line
drivers/md/md-bitmap.c:273:18: warning: variable 'rdev' is used uninitialized whenever function 'write_sb_page' is called [-Wsometimes-uninitialized]struct md_rdev *rdev; ~~~~~~~~~~~~~~~~^~~~ drivers/md/md-bitmap.c:278:35: note: uninitialized use occurs here while ((rdev = next_active_rdev(rdev, mddev)) != NULL) { ^~~~
drivers/md/md-bitmap.c:273:22: note: initialize the variable 'rdev' to silence this warning
Oops, I missed the rdev = NULL;
V5 incoming
Quoted 27 lines
struct md_rdev *rdev; ^ = NULL13 warnings generated.
vim +273
drivers/md/md-bitmap.c270 271 static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait) 272 {Quoted 1 line
273 struct
md_rdev*rdev;274 struct mddev *mddev = bitmap->mddev; 275 int ret; 276 277 do { 278 while ((rdev = next_active_rdev(rdev, mddev)) != NULL) { 279 ret = __write_sb_page(rdev, bitmap, page); 280 if (ret) 281 return ret; 282 } 283 } while (wait && md_super_wait(mddev) < 0); 284 285 return 0; 286 } 287
PATCH v4 2/3 md: Fix types in sb writer
In reply to Jonathan DerrickFrom: Jon Derrick <[email protected]>
Page->index is a pgoff_t and multiplying could cause overflows on a 32-bit architecture. In the sb writer, this is used to calculate and verify the sector being used, and is multiplied by a sector value. Using sector_t will cast it to a u64 type and is the more appropriate type for the unit. Additionally, the integer size unit is converted to a sector unit in later calculations, and is now corrected to be an unsigned type.
Finally, clean up the calculations using variable aliases to improve readabiliy.
--- drivers/md/md-bitmap.c | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-)
drivers/md/md-bitmap.c +14 -21
@@ -215,12 +215,13 @@ static int __write_sb_page(struct md_rdev *rdev, struct bitmap *bitmap,struct block_device *bdev;struct mddev *mddev = bitmap->mddev;struct bitmap_storage *store = &bitmap->storage; -loff_t offset = mddev->bitmap_info.offset; -int size =PAGE_SIZE ; +sector_t offset = mddev->bitmap_info.offset; +sector_t ps, sboff, doff; +unsigned int size =PAGE_SIZE ; bdev = (rdev->meta_bdev) ? rdev->meta_bdev : rdev->bdev;if (page->index == store->file_pages -1 ) { -int last_page_size = store->bytes & (PAGE_SIZE -1 ); +unsigned int last_page_size = store->bytes & (PAGE_SIZE -1 );if (last_page_size ==0 ) last_page_size =PAGE_SIZE ;
@@ -228,43 +229,35 @@ static int __write_sb_page(struct md_rdev *rdev, struct bitmap *bitmap, bdev_logical_block_size(bdev)); } + ps = page->index *PAGE_SIZE /SECTOR_SIZE ; + sboff = rdev->sb_start + offset; + doff = rdev->data_offset; +/* Just make sure we aren't corrupting data or metadata */ if (mddev->external) {/* Bitmap could be anywhere. */ -if (rdev->sb_start + offset - + (page->index * (PAGE_SIZE /SECTOR_SIZE )) - > rdev->data_offset && - rdev->sb_start + offset - < (rdev->data_offset + mddev->dev_sectors - + (PAGE_SIZE /SECTOR_SIZE ))) +if (sboff + ps > doff && + sboff < (doff + mddev->dev_sectors +PAGE_SIZE /SECTOR_SIZE ))return -EINVAL ; }else if (offset <0 ) {/* DATA BITMAP METADATA */ -if (offset - + (long )(page->index * (PAGE_SIZE /SECTOR_SIZE )) - + size /SECTOR_SIZE >0 ) +if (offset + ps + size /SECTOR_SIZE >0 )/* bitmap runs in to metadata */ return -EINVAL ; -if (rdev->data_offset + mddev->dev_sectors - > rdev->sb_start + offset) +if (doff + mddev->dev_sectors > sboff)/* data runs in to bitmap */ return -EINVAL ; }else if (rdev->sb_start < rdev->data_offset) {/* METADATA BITMAP DATA */ -if (rdev->sb_start + offset - + page->index * (PAGE_SIZE /SECTOR_SIZE ) - + size /SECTOR_SIZE > rdev->data_offset) +if (sboff + ps + size /SECTOR_SIZE > doff)/* bitmap runs in to data */ return -EINVAL ; }else {/* DATA METADATA BITMAP - no problems */ } -md_super_write (mddev, rdev, - rdev->sb_start + offset - + page->index * (PAGE_SIZE /SECTOR_SIZE ), - size, page); +md_super_write (mddev, rdev, sboff + ps, (int ) size, page);return 0 ; }
Signature · 1 line
2.27.0
PATCH v4 3/3 md: Use optimal I/O size for last bitmap page
In reply to Jonathan DerrickFrom: Jon Derrick <[email protected]>
If the bitmap space has enough room, size the I/O for the last bitmap page write to the optimal I/O size for the storage device. The expanded write is checked that it won't overrun the data or metadata.
The drive this was tested against has higher latencies when there are sub-4k writes due to device-side read-mod-writes of its atomic 4k write unit. This change helps increase performance by sizing the last bitmap page I/O for the device's preferred write unit, if it is given.
Example Intel/Solidigm P5520
Raid10, Chunk-size 64M, bitmap-size 57228 bits
$ mdadm --create /dev/md0 --level=10 --raid-devices=4 /dev/nvme{0,1,2,3}n1
--assume-clean --bitmap=internal --bitmap-chunk=64M
$ fio --name=test --direct=1 --filename=/dev/md0 --rw=randwrite --bs=4k --runtime=60Without patch:
write: IOPS=1676, BW=6708KiB/s (6869kB/s)(393MiB/60001msec); 0 zone resets
With patch:
write: IOPS=15.7k, BW=61.4MiB/s (64.4MB/s)(3683MiB/60001msec); 0 zone resets
Biosnoop:
Without patch:
Time Process PID Device LBA Size Lat 1.410377 md0_raid10 6900 nvme0n1 W 16 4096 0.02 1.410387 md0_raid10 6900 nvme2n1 W 16 4096 0.02 1.410374 md0_raid10 6900 nvme3n1 W 16 4096 0.01 1.410381 md0_raid10 6900 nvme1n1 W 16 4096 0.02 1.410411 md0_raid10 6900 nvme1n1 W 115346512 4096 0.01 1.410418 md0_raid10 6900 nvme0n1 W 115346512 4096 0.02 1.410915 md0_raid10 6900 nvme2n1 W 24 3584 0.43 <-- 1.410935 md0_raid10 6900 nvme3n1 W 24 3584 0.45 <-- 1.411124 md0_raid10 6900 nvme1n1 W 24 3584 0.64 <-- 1.411147 md0_raid10 6900 nvme0n1 W 24 3584 0.66 <-- 1.411176 md0_raid10 6900 nvme3n1 W 2019022184 4096 0.01 1.411189 md0_raid10 6900 nvme2n1 W 2019022184 4096 0.02
With patch:
Time Process PID Device LBA Size Lat 5.747193 md0_raid10 727 nvme0n1 W 16 4096 0.01 5.747192 md0_raid10 727 nvme1n1 W 16 4096 0.02 5.747195 md0_raid10 727 nvme3n1 W 16 4096 0.01 5.747202 md0_raid10 727 nvme2n1 W 16 4096 0.02 5.747229 md0_raid10 727 nvme3n1 W 1196223704 4096 0.02 5.747224 md0_raid10 727 nvme0n1 W 1196223704 4096 0.01 5.747279 md0_raid10 727 nvme0n1 W 24 4096 0.01 <-- 5.747279 md0_raid10 727 nvme1n1 W 24 4096 0.02 <-- 5.747284 md0_raid10 727 nvme3n1 W 24 4096 0.02 <-- 5.747291 md0_raid10 727 nvme2n1 W 24 4096 0.02 <-- 5.747314 md0_raid10 727 nvme2n1 W 2234636712 4096 0.01 5.747317 md0_raid10 727 nvme1n1 W 2234636712 4096 0.02
--- drivers/md/md-bitmap.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-)
drivers/md/md-bitmap.c +29 -4
@@ -209,6 +209,28 @@ static struct md_rdev *next_active_rdev(struct md_rdev *rdev, struct mddev *mddereturn NULL ; } +static unsigned int optimal_io_size (struct block_device *bdev, +unsigned int last_page_size, +unsigned int io_size) +{ +if (bdev_io_opt (bdev) >bdev_logical_block_size (bdev)) +return roundup (last_page_size,bdev_io_opt (bdev)); +return io_size; +} + +static unsigned int bitmap_io_size (unsigned int io_size,unsigned int opt_size, +sector_t start,sector_t boundary) +{ +if (io_size != opt_size && + start + opt_size /SECTOR_SIZE <= boundary) +return opt_size; +if (start + io_size /SECTOR_SIZE <= boundary) +return io_size; + +/* Overflows boundary */ +return 0 ; +} +static int __write_sb_page (struct md_rdev *rdev,struct bitmap *bitmap,struct page *page) {
@@ -218,6 +240,7 @@ static int __write_sb_page(struct md_rdev *rdev, struct bitmap *bitmap,sector_t offset = mddev->bitmap_info.offset;sector_t ps, sboff, doff;unsigned int size =PAGE_SIZE ; +unsigned int opt_size =PAGE_SIZE ; bdev = (rdev->meta_bdev) ? rdev->meta_bdev : rdev->bdev;if (page->index == store->file_pages -1 ) {
@@ -225,8 +248,8 @@ static int __write_sb_page(struct md_rdev *rdev, struct bitmap *bitmap,if (last_page_size ==0 ) last_page_size =PAGE_SIZE ; - size =roundup (last_page_size, -bdev_logical_block_size (bdev)); + size =roundup (last_page_size,bdev_logical_block_size (bdev)); + opt_size =optimal_io_size (bdev, last_page_size, size); } ps = page->index *PAGE_SIZE /SECTOR_SIZE ;
@@ -241,7 +264,8 @@ static int __write_sb_page(struct md_rdev *rdev, struct bitmap *bitmap,return -EINVAL ; }else if (offset <0 ) {/* DATA BITMAP METADATA */ -if (offset + ps + size /SECTOR_SIZE >0 ) + size =bitmap_io_size (size, opt_size, offset + ps,0 ); +if (size ==0 )/* bitmap runs in to metadata */ return -EINVAL ;
@@ -250,7 +274,8 @@ static int __write_sb_page(struct md_rdev *rdev, struct bitmap *bitmap,return -EINVAL ; }else if (rdev->sb_start < rdev->data_offset) {/* METADATA BITMAP DATA */ -if (sboff + ps + size /SECTOR_SIZE > doff) + size =bitmap_io_size (size, opt_size, sboff + ps, doff); +if (size ==0 )/* bitmap runs in to data */ return -EINVAL ; }else {
Signature · 1 line
2.27.0