Skip to content

Commit

Permalink
md-bitmap: don't use ->index for pages backing the bitmap file
Browse files Browse the repository at this point in the history
The md driver allocates pages for storing the bitmap file data, which
are not page cache pages, and then stores the page granularity file
offset in page->index, which is a field that isn't really valid except
for page cache pages.

Use a separate index for the superblock, and use the scheme used at
read size to recalculate the index for the bitmap pages instead.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Song Liu <song@kernel.org>
Link: https://lore.kernel.org/r/20230615064840.629492-10-hch@lst.de
  • Loading branch information
Christoph Hellwig authored and liu-song-6 committed Jul 27, 2023
1 parent f5f2d5a commit d7038f9
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 27 deletions.
65 changes: 38 additions & 27 deletions drivers/md/md-bitmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -157,11 +157,8 @@ static int read_sb_page(struct mddev *mddev, loff_t offset,
test_bit(Bitmap_sync, &rdev->flags))
continue;

if (sync_page_io(rdev, sector, iosize, page, REQ_OP_READ,
true)) {
page->index = index;
if (sync_page_io(rdev, sector, iosize, page, REQ_OP_READ, true))
return 0;
}
}
return -EIO;
}
Expand Down Expand Up @@ -225,18 +222,19 @@ static unsigned int bitmap_io_size(unsigned int io_size, unsigned int opt_size,
}

static int __write_sb_page(struct md_rdev *rdev, struct bitmap *bitmap,
struct page *page)
unsigned long pg_index, struct page *page)
{
struct block_device *bdev;
struct mddev *mddev = bitmap->mddev;
struct bitmap_storage *store = &bitmap->storage;
loff_t sboff, offset = mddev->bitmap_info.offset;
sector_t ps, doff;
sector_t ps = pg_index * PAGE_SIZE / SECTOR_SIZE;
unsigned int size = PAGE_SIZE;
unsigned int opt_size = PAGE_SIZE;
sector_t doff;

bdev = (rdev->meta_bdev) ? rdev->meta_bdev : rdev->bdev;
if (page->index == store->file_pages - 1) {
if (pg_index == store->file_pages - 1) {
unsigned int last_page_size = store->bytes & (PAGE_SIZE - 1);

if (last_page_size == 0)
Expand All @@ -245,7 +243,6 @@ static int __write_sb_page(struct md_rdev *rdev, struct bitmap *bitmap,
opt_size = optimal_io_size(bdev, last_page_size, size);
}

ps = page->index * PAGE_SIZE / SECTOR_SIZE;
sboff = rdev->sb_start + offset;
doff = rdev->data_offset;

Expand Down Expand Up @@ -279,15 +276,16 @@ static int __write_sb_page(struct md_rdev *rdev, struct bitmap *bitmap,
return 0;
}

static void write_sb_page(struct bitmap *bitmap, struct page *page, int wait)
static void write_sb_page(struct bitmap *bitmap, unsigned long pg_index,
struct page *page, bool wait)
{
struct mddev *mddev = bitmap->mddev;

do {
struct md_rdev *rdev = NULL;

while ((rdev = next_active_rdev(rdev, mddev)) != NULL) {
if (__write_sb_page(rdev, bitmap, page) < 0) {
if (__write_sb_page(rdev, bitmap, pg_index, page) < 0) {
set_bit(BITMAP_WRITE_ERROR, &bitmap->flags);
return;
}
Expand Down Expand Up @@ -397,7 +395,6 @@ static int read_file_page(struct file *file, unsigned long index,
blk_cur++;
bh = bh->b_this_page;
}
page->index = index;

wait_event(bitmap->write_wait,
atomic_read(&bitmap->pending_writes)==0);
Expand All @@ -419,12 +416,21 @@ static int read_file_page(struct file *file, unsigned long index,
/*
* write out a page to a file
*/
static void write_page(struct bitmap *bitmap, struct page *page, int wait)
static void filemap_write_page(struct bitmap *bitmap, unsigned long pg_index,
bool wait)
{
if (bitmap->storage.file)
struct bitmap_storage *store = &bitmap->storage;
struct page *page = store->filemap[pg_index];

if (mddev_is_clustered(bitmap->mddev)) {
pg_index += bitmap->cluster_slot *
DIV_ROUND_UP(store->bytes, PAGE_SIZE);
}

if (store->file)
write_file_page(bitmap, page, wait);
else
write_sb_page(bitmap, page, wait);
write_sb_page(bitmap, pg_index, page, wait);
}

/*
Expand Down Expand Up @@ -481,7 +487,12 @@ void md_bitmap_update_sb(struct bitmap *bitmap)
sb->sectors_reserved = cpu_to_le32(bitmap->mddev->
bitmap_info.space);
kunmap_atomic(sb);
write_page(bitmap, bitmap->storage.sb_page, 1);

if (bitmap->storage.file)
write_file_page(bitmap, bitmap->storage.sb_page, 1);
else
write_sb_page(bitmap, bitmap->storage.sb_index,
bitmap->storage.sb_page, 1);
}
EXPORT_SYMBOL(md_bitmap_update_sb);

Expand Down Expand Up @@ -533,7 +544,7 @@ static int md_bitmap_new_disk_sb(struct bitmap *bitmap)
bitmap->storage.sb_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
if (bitmap->storage.sb_page == NULL)
return -ENOMEM;
bitmap->storage.sb_page->index = 0;
bitmap->storage.sb_index = 0;

sb = kmap_atomic(bitmap->storage.sb_page);

Expand Down Expand Up @@ -810,7 +821,7 @@ static int md_bitmap_storage_alloc(struct bitmap_storage *store,
if (store->sb_page) {
store->filemap[0] = store->sb_page;
pnum = 1;
store->sb_page->index = offset;
store->sb_index = offset;
}

for ( ; pnum < num_pages; pnum++) {
Expand All @@ -819,7 +830,6 @@ static int md_bitmap_storage_alloc(struct bitmap_storage *store,
store->file_pages = pnum;
return -ENOMEM;
}
store->filemap[pnum]->index = pnum + offset;
}
store->file_pages = pnum;

Expand Down Expand Up @@ -924,6 +934,7 @@ static void md_bitmap_file_set_bit(struct bitmap *bitmap, sector_t block)
void *kaddr;
unsigned long chunk = block >> bitmap->counts.chunkshift;
struct bitmap_storage *store = &bitmap->storage;
unsigned long index = file_page_index(store, chunk);
unsigned long node_offset = 0;

if (mddev_is_clustered(bitmap->mddev))
Expand All @@ -941,9 +952,9 @@ static void md_bitmap_file_set_bit(struct bitmap *bitmap, sector_t block)
else
set_bit_le(bit, kaddr);
kunmap_atomic(kaddr);
pr_debug("set file bit %lu page %lu\n", bit, page->index);
pr_debug("set file bit %lu page %lu\n", bit, index);
/* record page number so it gets flushed to disk when unplug occurs */
set_page_attr(bitmap, page->index - node_offset, BITMAP_PAGE_DIRTY);
set_page_attr(bitmap, index - node_offset, BITMAP_PAGE_DIRTY);
}

static void md_bitmap_file_clear_bit(struct bitmap *bitmap, sector_t block)
Expand All @@ -953,6 +964,7 @@ static void md_bitmap_file_clear_bit(struct bitmap *bitmap, sector_t block)
void *paddr;
unsigned long chunk = block >> bitmap->counts.chunkshift;
struct bitmap_storage *store = &bitmap->storage;
unsigned long index = file_page_index(store, chunk);
unsigned long node_offset = 0;

if (mddev_is_clustered(bitmap->mddev))
Expand All @@ -968,8 +980,8 @@ static void md_bitmap_file_clear_bit(struct bitmap *bitmap, sector_t block)
else
clear_bit_le(bit, paddr);
kunmap_atomic(paddr);
if (!test_page_attr(bitmap, page->index - node_offset, BITMAP_PAGE_NEEDWRITE)) {
set_page_attr(bitmap, page->index - node_offset, BITMAP_PAGE_PENDING);
if (!test_page_attr(bitmap, index - node_offset, BITMAP_PAGE_NEEDWRITE)) {
set_page_attr(bitmap, index - node_offset, BITMAP_PAGE_PENDING);
bitmap->allclean = 0;
}
}
Expand Down Expand Up @@ -1021,7 +1033,7 @@ void md_bitmap_unplug(struct bitmap *bitmap)
"md bitmap_unplug");
}
clear_page_attr(bitmap, i, BITMAP_PAGE_PENDING);
write_page(bitmap, bitmap->storage.filemap[i], 0);
filemap_write_page(bitmap, i, false);
writing = 1;
}
}
Expand Down Expand Up @@ -1153,7 +1165,7 @@ static int md_bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
memset(paddr + offset, 0xff, PAGE_SIZE - offset);
kunmap_atomic(paddr);

write_page(bitmap, page, 1);
filemap_write_page(bitmap, i, true);
if (test_bit(BITMAP_WRITE_ERROR, &bitmap->flags)) {
ret = -EIO;
goto err;
Expand Down Expand Up @@ -1374,9 +1386,8 @@ void md_bitmap_daemon_work(struct mddev *mddev)
break;
if (bitmap->storage.filemap &&
test_and_clear_page_attr(bitmap, j,
BITMAP_PAGE_NEEDWRITE)) {
write_page(bitmap, bitmap->storage.filemap[j], 0);
}
BITMAP_PAGE_NEEDWRITE))
filemap_write_page(bitmap, j, false);
}

done:
Expand Down
1 change: 1 addition & 0 deletions drivers/md/md-bitmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ struct bitmap {
struct file *file; /* backing disk file */
struct page *sb_page; /* cached copy of the bitmap
* file superblock */
unsigned long sb_index;
struct page **filemap; /* list of cache pages for
* the file */
unsigned long *filemap_attr; /* attributes associated
Expand Down

0 comments on commit d7038f9

Please sign in to comment.