blob: 1eb434306162a5b9c48ce011d3c9ec01965e31bc [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0-or-later
#include <linux/blkdev.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/timer.h>
#include <linux/sched.h>
#include <linux/list.h>
#include <linux/file.h>
#include <linux/seq_file.h>
#include <trace/events/block.h>
#include "md.h"
#include "md-bitmap.h"
/*
* #### Background
*
* Redundant data is used to enhance data fault tolerance, and the storage
* methods for redundant data vary depending on the RAID levels. And it's
* important to maintain the consistency of redundant data.
*
* Bitmap is used to record which data blocks have been synchronized and which
* ones need to be resynchronized or recovered. Each bit in the bitmap
* represents a segment of data in the array. When a bit is set, it indicates
* that the multiple redundant copies of that data segment may not be
* consistent. Data synchronization can be performed based on the bitmap after
* power failure or readding a disk. If there is no bitmap, a full disk
* synchronization is required.
*
* #### Key Features
*
* - IO fastpath is lockless, if user issues lots of write IO to the same
* bitmap bit in a short time, only the first write has additional overhead
* to update bitmap bit, no additional overhead for the following writes;
* - support only resync or recover written data, means in the case creating
* new array or replacing with a new disk, there is no need to do a full disk
* resync/recovery;
*
* #### Key Concept
*
* ##### State Machine
*
* Each bit is one byte, contain 6 different states, see llbitmap_state. And
* there are total 8 different actions, see llbitmap_action, can change state:
*
* llbitmap state machine: transitions between states
*
* | | Startwrite | Startsync | Endsync | Abortsync|
* | --------- | ---------- | --------- | ------- | ------- |
* | Unwritten | Dirty | x | x | x |
* | Clean | Dirty | x | x | x |
* | Dirty | x | x | x | x |
* | NeedSync | x | Syncing | x | x |
* | Syncing | x | Syncing | Dirty | NeedSync |
*
* | | Reload | Daemon | Discard | Stale |
* | --------- | -------- | ------ | --------- | --------- |
* | Unwritten | x | x | x | x |
* | Clean | x | x | Unwritten | NeedSync |
* | Dirty | NeedSync | Clean | Unwritten | NeedSync |
* | NeedSync | x | x | Unwritten | x |
* | Syncing | NeedSync | x | Unwritten | NeedSync |
*
* Typical scenarios:
*
* 1) Create new array
* All bits will be set to Unwritten by default, if --assume-clean is set,
* all bits will be set to Clean instead.
*
* 2) write data, raid1/raid10 have full copy of data, while raid456 doesn't and
* rely on xor data
*
* 2.1) write new data to raid1/raid10:
* Unwritten --StartWrite--> Dirty
*
* 2.2) write new data to raid456:
* Unwritten --StartWrite--> NeedSync
*
* Because the initial recover for raid456 is skipped, the xor data is not built
* yet, the bit must be set to NeedSync first and after lazy initial recover is
* finished, the bit will finally set to Dirty(see 5.1 and 5.4);
*
* 2.3) cover write
* Clean --StartWrite--> Dirty
*
* 3) daemon, if the array is not degraded:
* Dirty --Daemon--> Clean
*
* 4) discard
* {Clean, Dirty, NeedSync, Syncing} --Discard--> Unwritten
*
* 5) resync and recover
*
* 5.1) common process
* NeedSync --Startsync--> Syncing --Endsync--> Dirty --Daemon--> Clean
*
* 5.2) resync after power failure
* Dirty --Reload--> NeedSync
*
* 5.3) recover while replacing with a new disk
* By default, the old bitmap framework will recover all data, and llbitmap
* implements this by a new helper, see llbitmap_skip_sync_blocks:
*
* skip recover for bits other than dirty or clean;
*
* 5.4) lazy initial recover for raid5:
* By default, the old bitmap framework will only allow new recover when there
* are spares(new disk), a new recovery flag MD_RECOVERY_LAZY_RECOVER is added
* to perform raid456 lazy recover for set bits(from 2.2).
*
* 6. special handling for degraded array:
*
* - Dirty bits will never be cleared, daemon will just do nothing, so that if
* a disk is readded, Clean bits can be skipped with recovery;
* - Dirty bits will convert to Syncing from start write, to do data recovery
* for new added disks;
* - New write will convert bits to NeedSync directly;
*
* ##### Bitmap IO
*
* ##### Chunksize
*
* The default bitmap size is 128k, incluing 1k bitmap super block, and
* the default size of segment of data in the array each bit(chunksize) is 64k,
* and chunksize will adjust to twice the old size each time if the total number
* bits is not less than 127k.(see llbitmap_init)
*
* ##### READ
*
* While creating bitmap, all pages will be allocated and read for llbitmap,
* there won't be read afterwards
*
* ##### WRITE
*
* WRITE IO is divided into logical_block_size of the array, the dirty state
* of each block is tracked independently, for example:
*
* each page is 4k, contain 8 blocks; each block is 512 bytes contain 512 bit;
*
* | page0 | page1 | ... | page 31 |
* | |
* | \-----------------------\
* | |
* | block0 | block1 | ... | block 8|
* | |
* | \-----------------\
* | |
* | bit0 | bit1 | ... | bit511 |
*
* From IO path, if one bit is changed to Dirty or NeedSync, the corresponding
* subpage will be marked dirty, such block must write first before the IO is
* issued. This behaviour will affect IO performance, to reduce the impact, if
* multiple bits are changed in the same block in a short time, all bits in this
* block will be changed to Dirty/NeedSync, so that there won't be any overhead
* until daemon clears dirty bits.
*
* ##### Dirty Bits synchronization
*
* IO fast path will set bits to dirty, and those dirty bits will be cleared
* by daemon after IO is done. llbitmap_page_ctl is used to synchronize between
* IO path and daemon;
*
* IO path:
* 1) try to grab a reference, if succeed, set expire time after 5s and return;
* 2) if failed to grab a reference, wait for daemon to finish clearing dirty
* bits;
*
* Daemon (Daemon will be woken up every daemon_sleep seconds):
* For each page:
* 1) check if page expired, if not skip this page; for expired page:
* 2) suspend the page and wait for inflight write IO to be done;
* 3) change dirty page to clean;
* 4) resume the page;
*/
#define BITMAP_DATA_OFFSET 1024
/* 64k is the max IO size of sync IO for raid1/raid10 */
#define MIN_CHUNK_SIZE (64 * 2)
/* By default, daemon will be woken up every 30s */
#define DEFAULT_DAEMON_SLEEP 30
/*
* Dirtied bits that have not been accessed for more than 5s will be cleared
* by daemon.
*/
#define DEFAULT_BARRIER_IDLE 5
enum llbitmap_state {
/* No valid data, init state after assemble the array */
BitUnwritten = 0,
/* data is consistent */
BitClean,
/* data will be consistent after IO is done, set directly for writes */
BitDirty,
/*
* data need to be resynchronized:
* 1) set directly for writes if array is degraded, prevent full disk
* synchronization after readding a disk;
* 2) reassemble the array after power failure, and dirty bits are
* found after reloading the bitmap;
* 3) set for first write for raid5, to build initial xor data lazily
*/
BitNeedSync,
/* data is synchronizing */
BitSyncing,
BitStateCount,
BitNone = 0xff,
};
enum llbitmap_action {
/* User write new data, this is the only action from IO fast path */
BitmapActionStartwrite = 0,
/* Start recovery */
BitmapActionStartsync,
/* Finish recovery */
BitmapActionEndsync,
/* Failed recovery */
BitmapActionAbortsync,
/* Reassemble the array */
BitmapActionReload,
/* Daemon thread is trying to clear dirty bits */
BitmapActionDaemon,
/* Data is deleted */
BitmapActionDiscard,
/*
* Bitmap is stale, mark all bits in addition to BitUnwritten to
* BitNeedSync.
*/
BitmapActionStale,
BitmapActionCount,
/* Init state is BitUnwritten */
BitmapActionInit,
};
enum llbitmap_page_state {
LLPageFlush = 0,
LLPageDirty,
};
struct llbitmap_page_ctl {
char *state;
struct page *page;
unsigned long expire;
unsigned long flags;
wait_queue_head_t wait;
struct percpu_ref active;
/* Per block size dirty state, maximum 64k page / 1 sector = 128 */
unsigned long dirty[];
};
struct llbitmap {
struct mddev *mddev;
struct llbitmap_page_ctl **pctl;
unsigned int nr_pages;
unsigned int io_size;
unsigned int blocks_per_page;
/* shift of one chunk */
unsigned long chunkshift;
/* size of one chunk in sector */
unsigned long chunksize;
/* total number of chunks */
unsigned long chunks;
unsigned long last_end_sync;
/*
* time in seconds that dirty bits will be cleared if the page is not
* accessed.
*/
unsigned long barrier_idle;
/* fires on first BitDirty state */
struct timer_list pending_timer;
struct work_struct daemon_work;
unsigned long flags;
__u64 events_cleared;
/* for slow disks */
atomic_t behind_writes;
wait_queue_head_t behind_wait;
};
struct llbitmap_unplug_work {
struct work_struct work;
struct llbitmap *llbitmap;
struct completion *done;
};
static struct workqueue_struct *md_llbitmap_io_wq;
static struct workqueue_struct *md_llbitmap_unplug_wq;
static char state_machine[BitStateCount][BitmapActionCount] = {
[BitUnwritten] = {
[BitmapActionStartwrite] = BitDirty,
[BitmapActionStartsync] = BitNone,
[BitmapActionEndsync] = BitNone,
[BitmapActionAbortsync] = BitNone,
[BitmapActionReload] = BitNone,
[BitmapActionDaemon] = BitNone,
[BitmapActionDiscard] = BitNone,
[BitmapActionStale] = BitNone,
},
[BitClean] = {
[BitmapActionStartwrite] = BitDirty,
[BitmapActionStartsync] = BitNone,
[BitmapActionEndsync] = BitNone,
[BitmapActionAbortsync] = BitNone,
[BitmapActionReload] = BitNone,
[BitmapActionDaemon] = BitNone,
[BitmapActionDiscard] = BitUnwritten,
[BitmapActionStale] = BitNeedSync,
},
[BitDirty] = {
[BitmapActionStartwrite] = BitNone,
[BitmapActionStartsync] = BitNone,
[BitmapActionEndsync] = BitNone,
[BitmapActionAbortsync] = BitNone,
[BitmapActionReload] = BitNeedSync,
[BitmapActionDaemon] = BitClean,
[BitmapActionDiscard] = BitUnwritten,
[BitmapActionStale] = BitNeedSync,
},
[BitNeedSync] = {
[BitmapActionStartwrite] = BitNone,
[BitmapActionStartsync] = BitSyncing,
[BitmapActionEndsync] = BitNone,
[BitmapActionAbortsync] = BitNone,
[BitmapActionReload] = BitNone,
[BitmapActionDaemon] = BitNone,
[BitmapActionDiscard] = BitUnwritten,
[BitmapActionStale] = BitNone,
},
[BitSyncing] = {
[BitmapActionStartwrite] = BitNone,
[BitmapActionStartsync] = BitSyncing,
[BitmapActionEndsync] = BitDirty,
[BitmapActionAbortsync] = BitNeedSync,
[BitmapActionReload] = BitNeedSync,
[BitmapActionDaemon] = BitNone,
[BitmapActionDiscard] = BitUnwritten,
[BitmapActionStale] = BitNeedSync,
},
};
static void __llbitmap_flush(struct mddev *mddev);
static enum llbitmap_state llbitmap_read(struct llbitmap *llbitmap, loff_t pos)
{
unsigned int idx;
unsigned int offset;
pos += BITMAP_DATA_OFFSET;
idx = pos >> PAGE_SHIFT;
offset = offset_in_page(pos);
return llbitmap->pctl[idx]->state[offset];
}
/* set all the bits in the subpage as dirty */
static void llbitmap_infect_dirty_bits(struct llbitmap *llbitmap,
struct llbitmap_page_ctl *pctl,
unsigned int block)
{
bool level_456 = raid_is_456(llbitmap->mddev);
unsigned int io_size = llbitmap->io_size;
int pos;
for (pos = block * io_size; pos < (block + 1) * io_size; pos++) {
switch (pctl->state[pos]) {
case BitUnwritten:
pctl->state[pos] = level_456 ? BitNeedSync : BitDirty;
break;
case BitClean:
pctl->state[pos] = BitDirty;
break;
};
}
}
static void llbitmap_set_page_dirty(struct llbitmap *llbitmap, int idx,
int offset)
{
struct llbitmap_page_ctl *pctl = llbitmap->pctl[idx];
unsigned int io_size = llbitmap->io_size;
int block = offset / io_size;
int pos;
if (!test_bit(LLPageDirty, &pctl->flags))
set_bit(LLPageDirty, &pctl->flags);
/*
* For degraded array, dirty bits will never be cleared, and we must
* resync all the dirty bits, hence skip infect new dirty bits to
* prevent resync unnecessary data.
*/
if (llbitmap->mddev->degraded) {
set_bit(block, pctl->dirty);
return;
}
/*
* The subpage usually contains a total of 512 bits. If any single bit
* within the subpage is marked as dirty, the entire sector will be
* written. To avoid impacting write performance, when multiple bits
* within the same sector are modified within llbitmap->barrier_idle,
* all bits in the sector will be collectively marked as dirty at once.
*/
if (test_and_set_bit(block, pctl->dirty)) {
llbitmap_infect_dirty_bits(llbitmap, pctl, block);
return;
}
for (pos = block * io_size; pos < (block + 1) * io_size; pos++) {
if (pos == offset)
continue;
if (pctl->state[pos] == BitDirty ||
pctl->state[pos] == BitNeedSync) {
llbitmap_infect_dirty_bits(llbitmap, pctl, block);
return;
}
}
}
static void llbitmap_write(struct llbitmap *llbitmap, enum llbitmap_state state,
loff_t pos)
{
unsigned int idx;
unsigned int bit;
pos += BITMAP_DATA_OFFSET;
idx = pos >> PAGE_SHIFT;
bit = offset_in_page(pos);
llbitmap->pctl[idx]->state[bit] = state;
if (state == BitDirty || state == BitNeedSync)
llbitmap_set_page_dirty(llbitmap, idx, bit);
}
static struct page *llbitmap_read_page(struct llbitmap *llbitmap, int idx)
{
struct mddev *mddev = llbitmap->mddev;
struct page *page = NULL;
struct md_rdev *rdev;
if (llbitmap->pctl && llbitmap->pctl[idx])
page = llbitmap->pctl[idx]->page;
if (page)
return page;
page = alloc_page(GFP_KERNEL | __GFP_ZERO);
if (!page)
return ERR_PTR(-ENOMEM);
rdev_for_each(rdev, mddev) {
sector_t sector;
if (rdev->raid_disk < 0 || test_bit(Faulty, &rdev->flags))
continue;
sector = mddev->bitmap_info.offset +
(idx << PAGE_SECTORS_SHIFT);
if (sync_page_io(rdev, sector, PAGE_SIZE, page, REQ_OP_READ,
true))
return page;
md_error(mddev, rdev);
}
__free_page(page);
return ERR_PTR(-EIO);
}
static void llbitmap_write_page(struct llbitmap *llbitmap, int idx)
{
struct page *page = llbitmap->pctl[idx]->page;
struct mddev *mddev = llbitmap->mddev;
struct md_rdev *rdev;
int block;
for (block = 0; block < llbitmap->blocks_per_page; block++) {
struct llbitmap_page_ctl *pctl = llbitmap->pctl[idx];
if (!test_and_clear_bit(block, pctl->dirty))
continue;
rdev_for_each(rdev, mddev) {
sector_t sector;
sector_t bit_sector = llbitmap->io_size >> SECTOR_SHIFT;
if (rdev->raid_disk < 0 || test_bit(Faulty, &rdev->flags))
continue;
sector = mddev->bitmap_info.offset + rdev->sb_start +
(idx << PAGE_SECTORS_SHIFT) +
block * bit_sector;
md_write_metadata(mddev, rdev, sector,
llbitmap->io_size, page,
block * llbitmap->io_size);
}
}
}
static void active_release(struct percpu_ref *ref)
{
struct llbitmap_page_ctl *pctl =
container_of(ref, struct llbitmap_page_ctl, active);
wake_up(&pctl->wait);
}
static void llbitmap_free_pages(struct llbitmap *llbitmap)
{
int i;
if (!llbitmap->pctl)
return;
for (i = 0; i < llbitmap->nr_pages; i++) {
struct llbitmap_page_ctl *pctl = llbitmap->pctl[i];
if (!pctl || !pctl->page)
break;
__free_page(pctl->page);
percpu_ref_exit(&pctl->active);
}
kfree(llbitmap->pctl[0]);
kfree(llbitmap->pctl);
llbitmap->pctl = NULL;
}
static int llbitmap_cache_pages(struct llbitmap *llbitmap)
{
struct llbitmap_page_ctl *pctl;
unsigned int nr_pages = DIV_ROUND_UP(llbitmap->chunks +
BITMAP_DATA_OFFSET, PAGE_SIZE);
unsigned int size = struct_size(pctl, dirty, BITS_TO_LONGS(
llbitmap->blocks_per_page));
int i;
llbitmap->pctl = kmalloc_array(nr_pages, sizeof(void *),
GFP_KERNEL | __GFP_ZERO);
if (!llbitmap->pctl)
return -ENOMEM;
size = round_up(size, cache_line_size());
pctl = kmalloc_array(nr_pages, size, GFP_KERNEL | __GFP_ZERO);
if (!pctl) {
kfree(llbitmap->pctl);
return -ENOMEM;
}
llbitmap->nr_pages = nr_pages;
for (i = 0; i < nr_pages; i++, pctl = (void *)pctl + size) {
struct page *page = llbitmap_read_page(llbitmap, i);
llbitmap->pctl[i] = pctl;
if (IS_ERR(page)) {
llbitmap_free_pages(llbitmap);
return PTR_ERR(page);
}
if (percpu_ref_init(&pctl->active, active_release,
PERCPU_REF_ALLOW_REINIT, GFP_KERNEL)) {
__free_page(page);
llbitmap_free_pages(llbitmap);
return -ENOMEM;
}
pctl->page = page;
pctl->state = page_address(page);
init_waitqueue_head(&pctl->wait);
}
return 0;
}
static void llbitmap_init_state(struct llbitmap *llbitmap)
{
enum llbitmap_state state = BitUnwritten;
unsigned long i;
if (test_and_clear_bit(BITMAP_CLEAN, &llbitmap->flags))
state = BitClean;
for (i = 0; i < llbitmap->chunks; i++)
llbitmap_write(llbitmap, state, i);
}
/* The return value is only used from resync, where @start == @end. */
static enum llbitmap_state llbitmap_state_machine(struct llbitmap *llbitmap,
unsigned long start,
unsigned long end,
enum llbitmap_action action)
{
struct mddev *mddev = llbitmap->mddev;
enum llbitmap_state state = BitNone;
bool level_456 = raid_is_456(llbitmap->mddev);
bool need_resync = false;
bool need_recovery = false;
if (test_bit(BITMAP_WRITE_ERROR, &llbitmap->flags))
return BitNone;
if (action == BitmapActionInit) {
llbitmap_init_state(llbitmap);
return BitNone;
}
while (start <= end) {
enum llbitmap_state c = llbitmap_read(llbitmap, start);
if (c < 0 || c >= BitStateCount) {
pr_err("%s: invalid bit %lu state %d action %d, forcing resync\n",
__func__, start, c, action);
state = BitNeedSync;
goto write_bitmap;
}
if (c == BitNeedSync)
need_resync = !mddev->degraded;
state = state_machine[c][action];
write_bitmap:
if (unlikely(mddev->degraded)) {
/* For degraded array, mark new data as need sync. */
if (state == BitDirty &&
action == BitmapActionStartwrite)
state = BitNeedSync;
/*
* For degraded array, resync dirty data as well, noted
* if array is still degraded after resync is done, all
* new data will still be dirty until array is clean.
*/
else if (c == BitDirty &&
action == BitmapActionStartsync)
state = BitSyncing;
} else if (c == BitUnwritten && state == BitDirty &&
action == BitmapActionStartwrite && level_456) {
/* Delay raid456 initial recovery to first write. */
state = BitNeedSync;
}
if (state == BitNone) {
start++;
continue;
}
llbitmap_write(llbitmap, state, start);
if (state == BitNeedSync)
need_resync = !mddev->degraded;
else if (state == BitDirty &&
!timer_pending(&llbitmap->pending_timer))
mod_timer(&llbitmap->pending_timer,
jiffies + mddev->bitmap_info.daemon_sleep * HZ);
start++;
}
if (need_resync && level_456)
need_recovery = true;
if (need_recovery) {
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
set_bit(MD_RECOVERY_LAZY_RECOVER, &mddev->recovery);
md_wakeup_thread(mddev->thread);
} else if (need_resync) {
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
set_bit(MD_RECOVERY_SYNC, &mddev->recovery);
md_wakeup_thread(mddev->thread);
}
return state;
}
static void llbitmap_raise_barrier(struct llbitmap *llbitmap, int page_idx)
{
struct llbitmap_page_ctl *pctl = llbitmap->pctl[page_idx];
retry:
if (likely(percpu_ref_tryget_live(&pctl->active))) {
WRITE_ONCE(pctl->expire, jiffies + llbitmap->barrier_idle * HZ);
return;
}
wait_event(pctl->wait, !percpu_ref_is_dying(&pctl->active));
goto retry;
}
static void llbitmap_release_barrier(struct llbitmap *llbitmap, int page_idx)
{
struct llbitmap_page_ctl *pctl = llbitmap->pctl[page_idx];
percpu_ref_put(&pctl->active);
}
static int llbitmap_suspend_timeout(struct llbitmap *llbitmap, int page_idx)
{
struct llbitmap_page_ctl *pctl = llbitmap->pctl[page_idx];
percpu_ref_kill(&pctl->active);
if (!wait_event_timeout(pctl->wait, percpu_ref_is_zero(&pctl->active),
llbitmap->mddev->bitmap_info.daemon_sleep * HZ))
return -ETIMEDOUT;
return 0;
}
static void llbitmap_resume(struct llbitmap *llbitmap, int page_idx)
{
struct llbitmap_page_ctl *pctl = llbitmap->pctl[page_idx];
pctl->expire = LONG_MAX;
percpu_ref_resurrect(&pctl->active);
wake_up(&pctl->wait);
}
static int llbitmap_check_support(struct mddev *mddev)
{
if (test_bit(MD_HAS_JOURNAL, &mddev->flags)) {
pr_notice("md/llbitmap: %s: array with journal cannot have bitmap\n",
mdname(mddev));
return -EBUSY;
}
if (mddev->bitmap_info.space == 0) {
if (mddev->bitmap_info.default_space == 0) {
pr_notice("md/llbitmap: %s: no space for bitmap\n",
mdname(mddev));
return -ENOSPC;
}
}
if (!mddev->persistent) {
pr_notice("md/llbitmap: %s: array must be persistent\n",
mdname(mddev));
return -EOPNOTSUPP;
}
if (mddev->bitmap_info.file) {
pr_notice("md/llbitmap: %s: doesn't support bitmap file\n",
mdname(mddev));
return -EOPNOTSUPP;
}
if (mddev->bitmap_info.external) {
pr_notice("md/llbitmap: %s: doesn't support external metadata\n",
mdname(mddev));
return -EOPNOTSUPP;
}
if (mddev_is_dm(mddev)) {
pr_notice("md/llbitmap: %s: doesn't support dm-raid\n",
mdname(mddev));
return -EOPNOTSUPP;
}
return 0;
}
static int llbitmap_init(struct llbitmap *llbitmap)
{
struct mddev *mddev = llbitmap->mddev;
sector_t blocks = mddev->resync_max_sectors;
unsigned long chunksize = MIN_CHUNK_SIZE;
unsigned long chunks = DIV_ROUND_UP(blocks, chunksize);
unsigned long space = mddev->bitmap_info.space << SECTOR_SHIFT;
int ret;
while (chunks > space) {
chunksize = chunksize << 1;
chunks = DIV_ROUND_UP_SECTOR_T(blocks, chunksize);
}
llbitmap->barrier_idle = DEFAULT_BARRIER_IDLE;
llbitmap->chunkshift = ffz(~chunksize);
llbitmap->chunksize = chunksize;
llbitmap->chunks = chunks;
mddev->bitmap_info.daemon_sleep = DEFAULT_DAEMON_SLEEP;
ret = llbitmap_cache_pages(llbitmap);
if (ret)
return ret;
llbitmap_state_machine(llbitmap, 0, llbitmap->chunks - 1,
BitmapActionInit);
/* flush initial llbitmap to disk */
__llbitmap_flush(mddev);
return 0;
}
static int llbitmap_read_sb(struct llbitmap *llbitmap)
{
struct mddev *mddev = llbitmap->mddev;
unsigned long daemon_sleep;
unsigned long chunksize;
unsigned long events;
struct page *sb_page;
bitmap_super_t *sb;
int ret = -EINVAL;
if (!mddev->bitmap_info.offset) {
pr_err("md/llbitmap: %s: no super block found", mdname(mddev));
return -EINVAL;
}
sb_page = llbitmap_read_page(llbitmap, 0);
if (IS_ERR(sb_page)) {
pr_err("md/llbitmap: %s: read super block failed",
mdname(mddev));
return -EIO;
}
sb = kmap_local_page(sb_page);
if (sb->magic != cpu_to_le32(BITMAP_MAGIC)) {
pr_err("md/llbitmap: %s: invalid super block magic number",
mdname(mddev));
goto out_put_page;
}
if (sb->version != cpu_to_le32(BITMAP_MAJOR_LOCKLESS)) {
pr_err("md/llbitmap: %s: invalid super block version",
mdname(mddev));
goto out_put_page;
}
if (memcmp(sb->uuid, mddev->uuid, 16)) {
pr_err("md/llbitmap: %s: bitmap superblock UUID mismatch\n",
mdname(mddev));
goto out_put_page;
}
if (mddev->bitmap_info.space == 0) {
int room = le32_to_cpu(sb->sectors_reserved);
if (room)
mddev->bitmap_info.space = room;
else
mddev->bitmap_info.space = mddev->bitmap_info.default_space;
}
llbitmap->flags = le32_to_cpu(sb->state);
if (test_and_clear_bit(BITMAP_FIRST_USE, &llbitmap->flags)) {
ret = llbitmap_init(llbitmap);
goto out_put_page;
}
chunksize = le32_to_cpu(sb->chunksize);
if (!is_power_of_2(chunksize)) {
pr_err("md/llbitmap: %s: chunksize not a power of 2",
mdname(mddev));
goto out_put_page;
}
if (chunksize < DIV_ROUND_UP_SECTOR_T(mddev->resync_max_sectors,
mddev->bitmap_info.space << SECTOR_SHIFT)) {
pr_err("md/llbitmap: %s: chunksize too small %lu < %llu / %lu",
mdname(mddev), chunksize, mddev->resync_max_sectors,
mddev->bitmap_info.space);
goto out_put_page;
}
daemon_sleep = le32_to_cpu(sb->daemon_sleep);
if (daemon_sleep < 1 || daemon_sleep > MAX_SCHEDULE_TIMEOUT / HZ) {
pr_err("md/llbitmap: %s: daemon sleep %lu period out of range",
mdname(mddev), daemon_sleep);
goto out_put_page;
}
events = le64_to_cpu(sb->events);
if (events < mddev->events) {
pr_warn("md/llbitmap :%s: bitmap file is out of date (%lu < %llu) -- forcing full recovery",
mdname(mddev), events, mddev->events);
set_bit(BITMAP_STALE, &llbitmap->flags);
}
sb->sync_size = cpu_to_le64(mddev->resync_max_sectors);
mddev->bitmap_info.chunksize = chunksize;
mddev->bitmap_info.daemon_sleep = daemon_sleep;
llbitmap->barrier_idle = DEFAULT_BARRIER_IDLE;
llbitmap->chunksize = chunksize;
llbitmap->chunks = DIV_ROUND_UP_SECTOR_T(mddev->resync_max_sectors, chunksize);
llbitmap->chunkshift = ffz(~chunksize);
ret = llbitmap_cache_pages(llbitmap);
out_put_page:
__free_page(sb_page);
kunmap_local(sb);
return ret;
}
static void llbitmap_pending_timer_fn(struct timer_list *pending_timer)
{
struct llbitmap *llbitmap =
container_of(pending_timer, struct llbitmap, pending_timer);
if (work_busy(&llbitmap->daemon_work)) {
pr_warn("md/llbitmap: %s daemon_work not finished in %lu seconds\n",
mdname(llbitmap->mddev),
llbitmap->mddev->bitmap_info.daemon_sleep);
set_bit(BITMAP_DAEMON_BUSY, &llbitmap->flags);
return;
}
queue_work(md_llbitmap_io_wq, &llbitmap->daemon_work);
}
static void md_llbitmap_daemon_fn(struct work_struct *work)
{
struct llbitmap *llbitmap =
container_of(work, struct llbitmap, daemon_work);
unsigned long start;
unsigned long end;
bool restart;
int idx;
if (llbitmap->mddev->degraded)
return;
retry:
start = 0;
end = min(llbitmap->chunks, PAGE_SIZE - BITMAP_DATA_OFFSET) - 1;
restart = false;
for (idx = 0; idx < llbitmap->nr_pages; idx++) {
struct llbitmap_page_ctl *pctl = llbitmap->pctl[idx];
if (idx > 0) {
start = end + 1;
end = min(end + PAGE_SIZE, llbitmap->chunks - 1);
}
if (!test_bit(LLPageFlush, &pctl->flags) &&
time_before(jiffies, pctl->expire)) {
restart = true;
continue;
}
if (llbitmap_suspend_timeout(llbitmap, idx) < 0) {
pr_warn("md/llbitmap: %s: %s waiting for page %d timeout\n",
mdname(llbitmap->mddev), __func__, idx);
continue;
}
llbitmap_state_machine(llbitmap, start, end, BitmapActionDaemon);
llbitmap_resume(llbitmap, idx);
}
/*
* If the daemon took a long time to finish, retry to prevent missing
* clearing dirty bits.
*/
if (test_and_clear_bit(BITMAP_DAEMON_BUSY, &llbitmap->flags))
goto retry;
/* If some page is dirty but not expired, setup timer again */
if (restart)
mod_timer(&llbitmap->pending_timer,
jiffies + llbitmap->mddev->bitmap_info.daemon_sleep * HZ);
}
static int llbitmap_create(struct mddev *mddev)
{
struct llbitmap *llbitmap;
int ret;
ret = llbitmap_check_support(mddev);
if (ret)
return ret;
llbitmap = kzalloc(sizeof(*llbitmap), GFP_KERNEL);
if (!llbitmap)
return -ENOMEM;
llbitmap->mddev = mddev;
llbitmap->io_size = bdev_logical_block_size(mddev->gendisk->part0);
llbitmap->blocks_per_page = PAGE_SIZE / llbitmap->io_size;
timer_setup(&llbitmap->pending_timer, llbitmap_pending_timer_fn, 0);
INIT_WORK(&llbitmap->daemon_work, md_llbitmap_daemon_fn);
atomic_set(&llbitmap->behind_writes, 0);
init_waitqueue_head(&llbitmap->behind_wait);
mutex_lock(&mddev->bitmap_info.mutex);
mddev->bitmap = llbitmap;
ret = llbitmap_read_sb(llbitmap);
mutex_unlock(&mddev->bitmap_info.mutex);
if (ret) {
kfree(llbitmap);
mddev->bitmap = NULL;
}
return ret;
}
static int llbitmap_resize(struct mddev *mddev, sector_t blocks, int chunksize)
{
struct llbitmap *llbitmap = mddev->bitmap;
unsigned long chunks;
if (chunksize == 0)
chunksize = llbitmap->chunksize;
/* If there is enough space, leave the chunksize unchanged. */
chunks = DIV_ROUND_UP_SECTOR_T(blocks, chunksize);
while (chunks > mddev->bitmap_info.space << SECTOR_SHIFT) {
chunksize = chunksize << 1;
chunks = DIV_ROUND_UP_SECTOR_T(blocks, chunksize);
}
llbitmap->chunkshift = ffz(~chunksize);
llbitmap->chunksize = chunksize;
llbitmap->chunks = chunks;
return 0;
}
static int llbitmap_load(struct mddev *mddev)
{
enum llbitmap_action action = BitmapActionReload;
struct llbitmap *llbitmap = mddev->bitmap;
if (test_and_clear_bit(BITMAP_STALE, &llbitmap->flags))
action = BitmapActionStale;
llbitmap_state_machine(llbitmap, 0, llbitmap->chunks - 1, action);
return 0;
}
static void llbitmap_destroy(struct mddev *mddev)
{
struct llbitmap *llbitmap = mddev->bitmap;
if (!llbitmap)
return;
mutex_lock(&mddev->bitmap_info.mutex);
timer_delete_sync(&llbitmap->pending_timer);
flush_workqueue(md_llbitmap_io_wq);
flush_workqueue(md_llbitmap_unplug_wq);
mddev->bitmap = NULL;
llbitmap_free_pages(llbitmap);
kfree(llbitmap);
mutex_unlock(&mddev->bitmap_info.mutex);
}
static void llbitmap_start_write(struct mddev *mddev, sector_t offset,
unsigned long sectors)
{
struct llbitmap *llbitmap = mddev->bitmap;
unsigned long start = offset >> llbitmap->chunkshift;
unsigned long end = (offset + sectors - 1) >> llbitmap->chunkshift;
int page_start = (start + BITMAP_DATA_OFFSET) >> PAGE_SHIFT;
int page_end = (end + BITMAP_DATA_OFFSET) >> PAGE_SHIFT;
llbitmap_state_machine(llbitmap, start, end, BitmapActionStartwrite);
while (page_start <= page_end) {
llbitmap_raise_barrier(llbitmap, page_start);
page_start++;
}
}
static void llbitmap_end_write(struct mddev *mddev, sector_t offset,
unsigned long sectors)
{
struct llbitmap *llbitmap = mddev->bitmap;
unsigned long start = offset >> llbitmap->chunkshift;
unsigned long end = (offset + sectors - 1) >> llbitmap->chunkshift;
int page_start = (start + BITMAP_DATA_OFFSET) >> PAGE_SHIFT;
int page_end = (end + BITMAP_DATA_OFFSET) >> PAGE_SHIFT;
while (page_start <= page_end) {
llbitmap_release_barrier(llbitmap, page_start);
page_start++;
}
}
static void llbitmap_start_discard(struct mddev *mddev, sector_t offset,
unsigned long sectors)
{
struct llbitmap *llbitmap = mddev->bitmap;
unsigned long start = DIV_ROUND_UP_SECTOR_T(offset, llbitmap->chunksize);
unsigned long end = (offset + sectors - 1) >> llbitmap->chunkshift;
int page_start = (start + BITMAP_DATA_OFFSET) >> PAGE_SHIFT;
int page_end = (end + BITMAP_DATA_OFFSET) >> PAGE_SHIFT;
llbitmap_state_machine(llbitmap, start, end, BitmapActionDiscard);
while (page_start <= page_end) {
llbitmap_raise_barrier(llbitmap, page_start);
page_start++;
}
}
static void llbitmap_end_discard(struct mddev *mddev, sector_t offset,
unsigned long sectors)
{
struct llbitmap *llbitmap = mddev->bitmap;
unsigned long start = DIV_ROUND_UP_SECTOR_T(offset, llbitmap->chunksize);
unsigned long end = (offset + sectors - 1) >> llbitmap->chunkshift;
int page_start = (start + BITMAP_DATA_OFFSET) >> PAGE_SHIFT;
int page_end = (end + BITMAP_DATA_OFFSET) >> PAGE_SHIFT;
while (page_start <= page_end) {
llbitmap_release_barrier(llbitmap, page_start);
page_start++;
}
}
static void llbitmap_unplug_fn(struct work_struct *work)
{
struct llbitmap_unplug_work *unplug_work =
container_of(work, struct llbitmap_unplug_work, work);
struct llbitmap *llbitmap = unplug_work->llbitmap;
struct blk_plug plug;
int i;
blk_start_plug(&plug);
for (i = 0; i < llbitmap->nr_pages; i++) {
if (!test_bit(LLPageDirty, &llbitmap->pctl[i]->flags) ||
!test_and_clear_bit(LLPageDirty, &llbitmap->pctl[i]->flags))
continue;
llbitmap_write_page(llbitmap, i);
}
blk_finish_plug(&plug);
md_super_wait(llbitmap->mddev);
complete(unplug_work->done);
}
static bool llbitmap_dirty(struct llbitmap *llbitmap)
{
int i;
for (i = 0; i < llbitmap->nr_pages; i++)
if (test_bit(LLPageDirty, &llbitmap->pctl[i]->flags))
return true;
return false;
}
static void llbitmap_unplug(struct mddev *mddev, bool sync)
{
DECLARE_COMPLETION_ONSTACK(done);
struct llbitmap *llbitmap = mddev->bitmap;
struct llbitmap_unplug_work unplug_work = {
.llbitmap = llbitmap,
.done = &done,
};
if (!llbitmap_dirty(llbitmap))
return;
/*
* Issue new bitmap IO under submit_bio() context will deadlock:
* - the bio will wait for bitmap bio to be done, before it can be
* issued;
* - bitmap bio will be added to current->bio_list and wait for this
* bio to be issued;
*/
INIT_WORK_ONSTACK(&unplug_work.work, llbitmap_unplug_fn);
queue_work(md_llbitmap_unplug_wq, &unplug_work.work);
wait_for_completion(&done);
destroy_work_on_stack(&unplug_work.work);
}
/*
* Force to write all bitmap pages to disk, called when stopping the array, or
* every daemon_sleep seconds when sync_thread is running.
*/
static void __llbitmap_flush(struct mddev *mddev)
{
struct llbitmap *llbitmap = mddev->bitmap;
struct blk_plug plug;
int i;
blk_start_plug(&plug);
for (i = 0; i < llbitmap->nr_pages; i++) {
struct llbitmap_page_ctl *pctl = llbitmap->pctl[i];
/* mark all blocks as dirty */
set_bit(LLPageDirty, &pctl->flags);
bitmap_fill(pctl->dirty, llbitmap->blocks_per_page);
llbitmap_write_page(llbitmap, i);
}
blk_finish_plug(&plug);
md_super_wait(llbitmap->mddev);
}
static void llbitmap_flush(struct mddev *mddev)
{
struct llbitmap *llbitmap = mddev->bitmap;
int i;
for (i = 0; i < llbitmap->nr_pages; i++)
set_bit(LLPageFlush, &llbitmap->pctl[i]->flags);
timer_delete_sync(&llbitmap->pending_timer);
queue_work(md_llbitmap_io_wq, &llbitmap->daemon_work);
flush_work(&llbitmap->daemon_work);
__llbitmap_flush(mddev);
}
/* This is used for raid5 lazy initial recovery */
static bool llbitmap_blocks_synced(struct mddev *mddev, sector_t offset)
{
struct llbitmap *llbitmap = mddev->bitmap;
unsigned long p = offset >> llbitmap->chunkshift;
enum llbitmap_state c = llbitmap_read(llbitmap, p);
return c == BitClean || c == BitDirty;
}
static sector_t llbitmap_skip_sync_blocks(struct mddev *mddev, sector_t offset)
{
struct llbitmap *llbitmap = mddev->bitmap;
unsigned long p = offset >> llbitmap->chunkshift;
int blocks = llbitmap->chunksize - (offset & (llbitmap->chunksize - 1));
enum llbitmap_state c = llbitmap_read(llbitmap, p);
/* always skip unwritten blocks */
if (c == BitUnwritten)
return blocks;
/* For degraded array, don't skip */
if (mddev->degraded)
return 0;
/* For resync also skip clean/dirty blocks */
if ((c == BitClean || c == BitDirty) &&
test_bit(MD_RECOVERY_SYNC, &mddev->recovery) &&
!test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
return blocks;
return 0;
}
static bool llbitmap_start_sync(struct mddev *mddev, sector_t offset,
sector_t *blocks, bool degraded)
{
struct llbitmap *llbitmap = mddev->bitmap;
unsigned long p = offset >> llbitmap->chunkshift;
/*
* Handle one bit at a time, this is much simpler. And it doesn't matter
* if md_do_sync() loop more times.
*/
*blocks = llbitmap->chunksize - (offset & (llbitmap->chunksize - 1));
return llbitmap_state_machine(llbitmap, p, p,
BitmapActionStartsync) == BitSyncing;
}
/* Something is wrong, sync_thread stop at @offset */
static void llbitmap_end_sync(struct mddev *mddev, sector_t offset,
sector_t *blocks)
{
struct llbitmap *llbitmap = mddev->bitmap;
unsigned long p = offset >> llbitmap->chunkshift;
*blocks = llbitmap->chunksize - (offset & (llbitmap->chunksize - 1));
llbitmap_state_machine(llbitmap, p, llbitmap->chunks - 1,
BitmapActionAbortsync);
}
/* A full sync_thread is finished */
static void llbitmap_close_sync(struct mddev *mddev)
{
struct llbitmap *llbitmap = mddev->bitmap;
int i;
for (i = 0; i < llbitmap->nr_pages; i++) {
struct llbitmap_page_ctl *pctl = llbitmap->pctl[i];
/* let daemon_fn clear dirty bits immediately */
WRITE_ONCE(pctl->expire, jiffies);
}
llbitmap_state_machine(llbitmap, 0, llbitmap->chunks - 1,
BitmapActionEndsync);
}
/*
* sync_thread have reached @sector, update metadata every daemon_sleep seconds,
* just in case sync_thread have to restart after power failure.
*/
static void llbitmap_cond_end_sync(struct mddev *mddev, sector_t sector,
bool force)
{
struct llbitmap *llbitmap = mddev->bitmap;
if (sector == 0) {
llbitmap->last_end_sync = jiffies;
return;
}
if (time_before(jiffies, llbitmap->last_end_sync +
HZ * mddev->bitmap_info.daemon_sleep))
return;
wait_event(mddev->recovery_wait, !atomic_read(&mddev->recovery_active));
mddev->curr_resync_completed = sector;
set_bit(MD_SB_CHANGE_CLEAN, &mddev->sb_flags);
llbitmap_state_machine(llbitmap, 0, sector >> llbitmap->chunkshift,
BitmapActionEndsync);
__llbitmap_flush(mddev);
llbitmap->last_end_sync = jiffies;
sysfs_notify_dirent_safe(mddev->sysfs_completed);
}
static bool llbitmap_enabled(void *data, bool flush)
{
struct llbitmap *llbitmap = data;
return llbitmap && !test_bit(BITMAP_WRITE_ERROR, &llbitmap->flags);
}
static void llbitmap_dirty_bits(struct mddev *mddev, unsigned long s,
unsigned long e)
{
llbitmap_state_machine(mddev->bitmap, s, e, BitmapActionStartwrite);
}
static void llbitmap_write_sb(struct llbitmap *llbitmap)
{
int nr_blocks = DIV_ROUND_UP(BITMAP_DATA_OFFSET, llbitmap->io_size);
bitmap_fill(llbitmap->pctl[0]->dirty, nr_blocks);
llbitmap_write_page(llbitmap, 0);
md_super_wait(llbitmap->mddev);
}
static void llbitmap_update_sb(void *data)
{
struct llbitmap *llbitmap = data;
struct mddev *mddev = llbitmap->mddev;
struct page *sb_page;
bitmap_super_t *sb;
if (test_bit(BITMAP_WRITE_ERROR, &llbitmap->flags))
return;
sb_page = llbitmap_read_page(llbitmap, 0);
if (IS_ERR(sb_page)) {
pr_err("%s: %s: read super block failed", __func__,
mdname(mddev));
set_bit(BITMAP_WRITE_ERROR, &llbitmap->flags);
return;
}
if (mddev->events < llbitmap->events_cleared)
llbitmap->events_cleared = mddev->events;
sb = kmap_local_page(sb_page);
sb->events = cpu_to_le64(mddev->events);
sb->state = cpu_to_le32(llbitmap->flags);
sb->chunksize = cpu_to_le32(llbitmap->chunksize);
sb->sync_size = cpu_to_le64(mddev->resync_max_sectors);
sb->events_cleared = cpu_to_le64(llbitmap->events_cleared);
sb->sectors_reserved = cpu_to_le32(mddev->bitmap_info.space);
sb->daemon_sleep = cpu_to_le32(mddev->bitmap_info.daemon_sleep);
kunmap_local(sb);
llbitmap_write_sb(llbitmap);
}
static int llbitmap_get_stats(void *data, struct md_bitmap_stats *stats)
{
struct llbitmap *llbitmap = data;
memset(stats, 0, sizeof(*stats));
stats->missing_pages = 0;
stats->pages = llbitmap->nr_pages;
stats->file_pages = llbitmap->nr_pages;
stats->behind_writes = atomic_read(&llbitmap->behind_writes);
stats->behind_wait = wq_has_sleeper(&llbitmap->behind_wait);
stats->events_cleared = llbitmap->events_cleared;
return 0;
}
/* just flag all pages as needing to be written */
static void llbitmap_write_all(struct mddev *mddev)
{
int i;
struct llbitmap *llbitmap = mddev->bitmap;
for (i = 0; i < llbitmap->nr_pages; i++) {
struct llbitmap_page_ctl *pctl = llbitmap->pctl[i];
set_bit(LLPageDirty, &pctl->flags);
bitmap_fill(pctl->dirty, llbitmap->blocks_per_page);
}
}
static void llbitmap_start_behind_write(struct mddev *mddev)
{
struct llbitmap *llbitmap = mddev->bitmap;
atomic_inc(&llbitmap->behind_writes);
}
static void llbitmap_end_behind_write(struct mddev *mddev)
{
struct llbitmap *llbitmap = mddev->bitmap;
if (atomic_dec_and_test(&llbitmap->behind_writes))
wake_up(&llbitmap->behind_wait);
}
static void llbitmap_wait_behind_writes(struct mddev *mddev)
{
struct llbitmap *llbitmap = mddev->bitmap;
if (!llbitmap)
return;
wait_event(llbitmap->behind_wait,
atomic_read(&llbitmap->behind_writes) == 0);
}
static ssize_t bits_show(struct mddev *mddev, char *page)
{
struct llbitmap *llbitmap;
int bits[BitStateCount] = {0};
loff_t start = 0;
mutex_lock(&mddev->bitmap_info.mutex);
llbitmap = mddev->bitmap;
if (!llbitmap || !llbitmap->pctl) {
mutex_unlock(&mddev->bitmap_info.mutex);
return sprintf(page, "no bitmap\n");
}
if (test_bit(BITMAP_WRITE_ERROR, &llbitmap->flags)) {
mutex_unlock(&mddev->bitmap_info.mutex);
return sprintf(page, "bitmap io error\n");
}
while (start < llbitmap->chunks) {
enum llbitmap_state c = llbitmap_read(llbitmap, start);
if (c < 0 || c >= BitStateCount)
pr_err("%s: invalid bit %llu state %d\n",
__func__, start, c);
else
bits[c]++;
start++;
}
mutex_unlock(&mddev->bitmap_info.mutex);
return sprintf(page, "unwritten %d\nclean %d\ndirty %d\nneed sync %d\nsyncing %d\n",
bits[BitUnwritten], bits[BitClean], bits[BitDirty],
bits[BitNeedSync], bits[BitSyncing]);
}
static struct md_sysfs_entry llbitmap_bits = __ATTR_RO(bits);
static ssize_t metadata_show(struct mddev *mddev, char *page)
{
struct llbitmap *llbitmap;
ssize_t ret;
mutex_lock(&mddev->bitmap_info.mutex);
llbitmap = mddev->bitmap;
if (!llbitmap) {
mutex_unlock(&mddev->bitmap_info.mutex);
return sprintf(page, "no bitmap\n");
}
ret = sprintf(page, "chunksize %lu\nchunkshift %lu\nchunks %lu\noffset %llu\ndaemon_sleep %lu\n",
llbitmap->chunksize, llbitmap->chunkshift,
llbitmap->chunks, mddev->bitmap_info.offset,
llbitmap->mddev->bitmap_info.daemon_sleep);
mutex_unlock(&mddev->bitmap_info.mutex);
return ret;
}
static struct md_sysfs_entry llbitmap_metadata = __ATTR_RO(metadata);
static ssize_t
daemon_sleep_show(struct mddev *mddev, char *page)
{
return sprintf(page, "%lu\n", mddev->bitmap_info.daemon_sleep);
}
static ssize_t
daemon_sleep_store(struct mddev *mddev, const char *buf, size_t len)
{
unsigned long timeout;
int rv = kstrtoul(buf, 10, &timeout);
if (rv)
return rv;
mddev->bitmap_info.daemon_sleep = timeout;
return len;
}
static struct md_sysfs_entry llbitmap_daemon_sleep = __ATTR_RW(daemon_sleep);
static ssize_t
barrier_idle_show(struct mddev *mddev, char *page)
{
struct llbitmap *llbitmap = mddev->bitmap;
return sprintf(page, "%lu\n", llbitmap->barrier_idle);
}
static ssize_t
barrier_idle_store(struct mddev *mddev, const char *buf, size_t len)
{
struct llbitmap *llbitmap = mddev->bitmap;
unsigned long timeout;
int rv = kstrtoul(buf, 10, &timeout);
if (rv)
return rv;
llbitmap->barrier_idle = timeout;
return len;
}
static struct md_sysfs_entry llbitmap_barrier_idle = __ATTR_RW(barrier_idle);
static struct attribute *md_llbitmap_attrs[] = {
&llbitmap_bits.attr,
&llbitmap_metadata.attr,
&llbitmap_daemon_sleep.attr,
&llbitmap_barrier_idle.attr,
NULL
};
static struct attribute_group md_llbitmap_group = {
.name = "llbitmap",
.attrs = md_llbitmap_attrs,
};
static struct bitmap_operations llbitmap_ops = {
.head = {
.type = MD_BITMAP,
.id = ID_LLBITMAP,
.name = "llbitmap",
},
.enabled = llbitmap_enabled,
.create = llbitmap_create,
.resize = llbitmap_resize,
.load = llbitmap_load,
.destroy = llbitmap_destroy,
.start_write = llbitmap_start_write,
.end_write = llbitmap_end_write,
.start_discard = llbitmap_start_discard,
.end_discard = llbitmap_end_discard,
.unplug = llbitmap_unplug,
.flush = llbitmap_flush,
.start_behind_write = llbitmap_start_behind_write,
.end_behind_write = llbitmap_end_behind_write,
.wait_behind_writes = llbitmap_wait_behind_writes,
.blocks_synced = llbitmap_blocks_synced,
.skip_sync_blocks = llbitmap_skip_sync_blocks,
.start_sync = llbitmap_start_sync,
.end_sync = llbitmap_end_sync,
.close_sync = llbitmap_close_sync,
.cond_end_sync = llbitmap_cond_end_sync,
.update_sb = llbitmap_update_sb,
.get_stats = llbitmap_get_stats,
.dirty_bits = llbitmap_dirty_bits,
.write_all = llbitmap_write_all,
.group = &md_llbitmap_group,
};
int md_llbitmap_init(void)
{
md_llbitmap_io_wq = alloc_workqueue("md_llbitmap_io",
WQ_MEM_RECLAIM | WQ_UNBOUND, 0);
if (!md_llbitmap_io_wq)
return -ENOMEM;
md_llbitmap_unplug_wq = alloc_workqueue("md_llbitmap_unplug",
WQ_MEM_RECLAIM | WQ_UNBOUND, 0);
if (!md_llbitmap_unplug_wq) {
destroy_workqueue(md_llbitmap_io_wq);
md_llbitmap_io_wq = NULL;
return -ENOMEM;
}
return register_md_submodule(&llbitmap_ops.head);
}
void md_llbitmap_exit(void)
{
destroy_workqueue(md_llbitmap_io_wq);
md_llbitmap_io_wq = NULL;
destroy_workqueue(md_llbitmap_unplug_wq);
md_llbitmap_unplug_wq = NULL;
unregister_md_submodule(&llbitmap_ops.head);
}