md-bitmap: don't use ->index for pages backing the bitmap file
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
This commit is contained in:
parent
f5f2d5ac9f
commit
d7038f9518
|
@ -157,12 +157,9 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -279,7 +276,8 @@ 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;
|
||||
|
||||
|
@ -287,7 +285,7 @@ static void write_sb_page(struct bitmap *bitmap, struct page *page, int wait)
|
|||
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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -419,12 +416,21 @@ out:
|
|||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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++) {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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)
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue