#define BITMAP_MAJOR_LO 3 /* version 4 insists the bitmap is in little-endian order *withversion3,itishost-endianwhichisnon-portable *Version5iscurrentlysetonlyforclustereddevices
*/ #define BITMAP_MAJOR_HI 4 #define BITMAP_MAJOR_CLUSTERED 5 #define BITMAP_MAJOR_HOSTENDIAN 3
/* how many counters per page? */ #define PAGE_COUNTER_RATIO (PAGE_BITS / COUNTER_BITS) /* same, except a shift value for more efficient bitops */ #define PAGE_COUNTER_SHIFT (PAGE_BIT_SHIFT - COUNTER_BIT_SHIFT) /* same, except a mask value for more efficient bitops */ #define PAGE_COUNTER_MASK (PAGE_COUNTER_RATIO - 1)
/* the main bitmap structure - one per mddev */ struct bitmap {
struct bitmap_counts {
spinlock_t lock; struct bitmap_page *bp; /* total number of pages in the bitmap */ unsignedlong pages; /* number of pages not yet allocated */ unsignedlong missing_pages; /* chunksize = 2^chunkshift (for bitops) */ unsignedlong chunkshift; /* total number of data chunks for the array */ unsignedlong chunks;
} counts;
struct mddev *mddev; /* the md device that the bitmap is for */
__u64 events_cleared; int need_sync;
struct bitmap_storage { /* backing disk file */ struct file *file; /* cached copy of the bitmap file superblock */ struct page *sb_page; unsignedlong sb_index; /* list of cache pages for the file */ struct page **filemap; /* attributes associated filemap pages */ unsignedlong *filemap_attr; /* number of pages in the file */ unsignedlong file_pages; /* total bytes in the bitmap */ unsignedlong bytes;
} storage;
unsignedlong flags;
int allclean;
atomic_t behind_writes; /* highest actual value at runtime */ unsignedlong behind_writes_used;
/* *thebitmapdaemon-periodicallywakesupandsweepsthebitmap *file,cleaningupbitsandflushingoutpagestodiskasnecessary
*/ unsignedlong daemon_lastrun; /* jiffies of last run */ /* *whenwelastedcalledend_synctoupdatebitmapwithresync *progress.
*/ unsignedlong last_end_sync;
/* pending writes to the bitmap file */
atomic_t pending_writes;
wait_queue_head_t write_wait;
wait_queue_head_t overflow_wait;
wait_queue_head_t behind_wait;
struct kernfs_node *sysfs_can_clear; /* slot offset for clustered env */ int cluster_slot;
};
staticint __bitmap_resize(struct bitmap *bitmap, sector_t blocks, int chunksize, bool init);
WARN_ON_ONCE(page >= bitmap->pages); if (bitmap->bp[page].hijacked) /* it's hijacked, don't try to alloc */ return0;
if (bitmap->bp[page].map) /* page is already allocated, just return */ return0;
if (!create) return -ENOENT;
/* this page has not been allocated yet */
spin_unlock_irq(&bitmap->lock); /* It is possible that this is being called inside a *prepare_to_wait/finish_waitloopfromraid5c:make_request(). *Ingeneralitisnotpermittedtosleepinthatcontextasit *cancausethelooptospinfreely. *Thatdoesn'tapplyhereaswecanonlyreachthispoint *oncewithanyloop. *Whenthisfunctioncompletes,eitherbp[page].mapor *bp[page].hijacked.Ineithercase,thisfunctionwill *abortbeforegettingtothispointagain.Sothereis *noriskofafree-spin,andsoitissafetoassert *thatsleepinghereisallowed.
*/
sched_annotate_sleep();
mappage = kzalloc(PAGE_SIZE, GFP_NOIO);
spin_lock_irq(&bitmap->lock);
if (mappage == NULL) {
pr_debug("md/bitmap: map page allocation failed, hijacking\n"); /* We don't support hijack for cluster raid */ if (no_hijack) return -ENOMEM; /* failed - set the hijacked flag so that we can use the
* pointer as a counter */ if (!bitmap->bp[page].map)
bitmap->bp[page].hijacked = 1;
} elseif (bitmap->bp[page].map ||
bitmap->bp[page].hijacked) { /* somebody beat us to getting the page */
kfree(mappage);
} else {
/* no page was in place and we have one, so install it */
/* if page is completely empty, put it back on the free list, or dealloc it */ /* if page was hijacked, unmark the flag so it might get alloced next time */ /* Note: lock should be held when calling this */ staticvoid md_bitmap_checkfree(struct bitmap_counts *bitmap, unsignedlong page)
{ char *ptr;
if (bitmap->bp[page].count) /* page is still busy */ return;
/* page is no longer in use, it can be released */
if (bitmap->bp[page].hijacked) { /* page was hijacked, undo this now */
bitmap->bp[page].hijacked = 0;
bitmap->bp[page].map = NULL;
} else { /* normal case, free the page */
ptr = bitmap->bp[page].map;
bitmap->bp[page].map = NULL;
bitmap->missing_pages++;
kfree(ptr);
}
}
/* IO operations when bitmap is stored near all superblocks */
/* choose a good rdev and read the page from there */ staticint read_sb_page(struct mddev *mddev, loff_t offset, struct page *page, unsignedlong index, int size)
{
/* *md_bitmap_wait_writes()shouldbecalledbeforewritinganybitmap *blocks,toensurepreviouswrites,particularlyfrom *md_bitmap_daemon_work(),havecompleted.
*/ staticvoid md_bitmap_wait_writes(struct bitmap *bitmap)
{ if (bitmap->storage.file)
wait_event(bitmap->write_wait,
atomic_read(&bitmap->pending_writes)==0); else /* Note that we ignore the return value. The writes *mighthavefailed,butthatwouldjustmeanthat *somebitswhichshouldbeclearedhaven'tbeen, *whichissafe.Therelevantbitmapblockswill *probablygetwrittenagain,butthereisnogreat *lossiftheyaren't.
*/
md_super_wait(bitmap->mddev);
}
/* update the event counter and sync the superblock to disk */ staticvoid bitmap_update_sb(void *data)
{
bitmap_super_t *sb; struct bitmap *bitmap = data;
if (!bitmap || !bitmap->mddev) /* no bitmap for this array */ return; if (bitmap->mddev->bitmap_info.external) return; if (!bitmap->storage.sb_page) /* no superblock */ return;
sb = kmap_local_page(bitmap->storage.sb_page);
sb->events = cpu_to_le64(bitmap->mddev->events); if (bitmap->mddev->events < bitmap->events_cleared) /* rocking back to read-only */
bitmap->events_cleared = bitmap->mddev->events;
sb->events_cleared = cpu_to_le64(bitmap->events_cleared); /* *clearBITMAP_WRITE_ERRORbittoprotectagainstthecasethat *abitmapwriteerroroccurredbutthelaterwritessucceeded.
*/
sb->state = cpu_to_le32(bitmap->flags & ~BIT(BITMAP_WRITE_ERROR)); /* Just in case these have been changed via sysfs: */
sb->daemon_sleep = cpu_to_le32(bitmap->mddev->bitmap_info.daemon_sleep/HZ);
sb->write_behind = cpu_to_le32(bitmap->mddev->bitmap_info.max_write_behind); /* This might have been changed by a reshape */
sb->sync_size = cpu_to_le64(bitmap->mddev->resync_max_sectors);
sb->chunksize = cpu_to_le32(bitmap->mddev->bitmap_info.chunksize);
sb->nodes = cpu_to_le32(bitmap->mddev->bitmap_info.nodes);
sb->sectors_reserved = cpu_to_le32(bitmap->mddev->
bitmap_info.space);
kunmap_local(sb);
chunksize = bitmap->mddev->bitmap_info.chunksize;
BUG_ON(!chunksize); if (!is_power_of_2(chunksize)) {
kunmap_local(sb);
pr_warn("bitmap chunksize not a power of 2\n"); return -EINVAL;
}
sb->chunksize = cpu_to_le32(chunksize);
/* *on-diskbitmap: * *Useonebitper"chunk"(blockset).WedothediskI/Oonthebitmap *fileapageatatime.There'sasuperblockatthestartofthefile.
*/ /* calculate the index of the page that contains this bit */ staticinlineunsignedlong file_page_index(struct bitmap_storage *store, unsignedlong chunk)
{ if (store->sb_page)
chunk += sizeof(bitmap_super_t) << 3; return chunk >> PAGE_BIT_SHIFT;
}
/* calculate the (bit) offset of this bit within a page */ staticinlineunsignedlong file_page_offset(struct bitmap_storage *store, unsignedlong chunk)
{ if (store->sb_page)
chunk += sizeof(bitmap_super_t) << 3; return chunk & (PAGE_BITS - 1);
}
/* We need 4 bits per page, rounded up to a multiple
* of sizeof(unsigned long) */
store->filemap_attr = kzalloc(
roundup(DIV_ROUND_UP(num_pages*4, 8), sizeof(unsignedlong)),
GFP_KERNEL); if (!store->filemap_attr) return -ENOMEM;
if (bitmap->storage.file) {
pr_warn("%s: kicking failed bitmap file %pD4 from array!\n",
bmname(bitmap), bitmap->storage.file);
} else
pr_warn("%s: disabling internal bitmap due to errors\n",
bmname(bitmap));
}
}
enum bitmap_page_attr {
BITMAP_PAGE_DIRTY = 0, /* there are set bits that need to be synced */
BITMAP_PAGE_PENDING = 1, /* there are bits that are being cleaned.
* i.e. counter is 1 or 2. */
BITMAP_PAGE_NEEDWRITE = 2, /* there are cleared bits that need to be synced */
};
index += store->sb_index; if (mddev_is_clustered(bitmap->mddev))
node_offset = bitmap->cluster_slot * store->file_pages;
page = filemap_get_page(&bitmap->storage, chunk); if (!page) return;
bit = file_page_offset(&bitmap->storage, chunk);
/* set the bit */
kaddr = kmap_local_page(page); if (test_bit(BITMAP_HOSTENDIAN, &bitmap->flags))
set_bit(bit, kaddr); else
set_bit_le(bit, kaddr);
kunmap_local(kaddr);
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, index - node_offset, BITMAP_PAGE_DIRTY);
}
page = filemap_get_page(&bitmap->storage, chunk); if (!page) return -EINVAL;
bit = file_page_offset(&bitmap->storage, chunk);
paddr = kmap_local_page(page); if (test_bit(BITMAP_HOSTENDIAN, &bitmap->flags))
set = test_bit(bit, paddr); else
set = test_bit_le(bit, paddr);
kunmap_local(paddr); return set;
}
/* this gets called when the md device is ready to unplug its underlying *(slave)devicequeues--beforeweletanywritesgodown,weneedto
* sync the dirty pages of the bitmap file to disk */ staticvoid __bitmap_unplug(struct bitmap *bitmap)
{ unsignedlong i; int dirty, need_write; int writing = 0;
if (!__bitmap_enabled(bitmap)) return;
/* look at each page to see if there are any set bits that need to be
* flushed out to disk */ for (i = 0; i < bitmap->storage.file_pages; i++) {
dirty = test_and_clear_page_attr(bitmap, i, BITMAP_PAGE_DIRTY);
need_write = test_and_clear_page_attr(bitmap, i,
BITMAP_PAGE_NEEDWRITE); if (dirty || need_write) { if (!writing) {
md_bitmap_wait_writes(bitmap);
mddev_add_trace_msg(bitmap->mddev, "md bitmap_unplug");
}
clear_page_attr(bitmap, i, BITMAP_PAGE_PENDING);
filemap_write_page(bitmap, i, false);
writing = 1;
}
} if (writing)
md_bitmap_wait_writes(bitmap);
if (test_bit(BITMAP_WRITE_ERROR, &bitmap->flags))
md_bitmap_file_kick(bitmap);
}
if (!file && !mddev->bitmap_info.offset) { /* No permanent bitmap - fill with '1s'. */
store->filemap = NULL;
store->file_pages = 0; for (i = 0; i < chunks ; i++) { /* if the disk bit is set, set the memory bit */ int needed = ((sector_t)(i+1) << (bitmap->counts.chunkshift)
>= start);
md_bitmap_set_memory_bits(bitmap,
(sector_t)i << bitmap->counts.chunkshift,
needed);
} return0;
}
if (file && i_size_read(file->f_mapping->host) < store->bytes) {
pr_warn("%s: bitmap file too short %lu < %lu\n",
bmname(bitmap),
(unsignedlong) i_size_read(file->f_mapping->host),
store->bytes);
ret = -ENOSPC; goto err;
}
if (mddev_is_clustered(mddev))
node_offset = bitmap->cluster_slot * (DIV_ROUND_UP(store->bytes, PAGE_SIZE));
for (i = 0; i < store->file_pages; i++) { struct page *page = store->filemap[i]; int count;
/* unmap the old page, we're done with it */ if (i == store->file_pages - 1)
count = store->bytes - i * PAGE_SIZE; else
count = PAGE_SIZE;
if (file)
ret = read_file_page(file, i, bitmap, count, page); else
ret = read_sb_page(mddev, 0, page, i + node_offset,
count); if (ret) goto err;
}
if (outofdate) {
pr_warn("%s: bitmap file is out of date, doing full recovery\n",
bmname(bitmap));
for (i = 0; i < store->file_pages; i++) { struct page *page = store->filemap[i]; unsignedlong offset = 0; void *paddr;
if (i == 0 && !mddev->bitmap_info.external)
offset = sizeof(bitmap_super_t);
if (was_set) { /* if the disk bit is set, set the memory bit */ int needed = ((sector_t)(i+1) << bitmap->counts.chunkshift
>= start);
md_bitmap_set_memory_bits(bitmap,
(sector_t)i << bitmap->counts.chunkshift,
needed);
bit_cnt++;
}
}
pr_debug("%s: bitmap initialized from disk: read %lu pages, set %lu of %lu bits\n",
bmname(bitmap), store->file_pages,
bit_cnt, chunks);
/* just flag bitmap pages as needing to be written. */ staticvoid bitmap_write_all(struct mddev *mddev)
{ int i; struct bitmap *bitmap = mddev->bitmap;
if (!bitmap || !bitmap->storage.filemap) return;
/* Only one copy, so nothing needed */ if (bitmap->storage.file) return;
for (i = 0; i < bitmap->storage.file_pages; i++)
set_page_attr(bitmap, i, BITMAP_PAGE_NEEDWRITE);
bitmap->allclean = 0;
}
/* Use a mutex to guard daemon_work against *bitmap_destroy.
*/
mutex_lock(&mddev->bitmap_info.mutex);
bitmap = mddev->bitmap; if (bitmap == NULL) {
mutex_unlock(&mddev->bitmap_info.mutex); return;
} if (time_before(jiffies, bitmap->daemon_lastrun
+ mddev->bitmap_info.daemon_sleep)) goto done;
/* Any file-page which is PENDING now needs to be written. *SosetNEEDWRITEnow,thenafterwemakeanylast-minutechanges *wewillwriteit.
*/ for (j = 0; j < bitmap->storage.file_pages; j++) if (test_and_clear_page_attr(bitmap, j,
BITMAP_PAGE_PENDING))
set_page_attr(bitmap, j,
BITMAP_PAGE_NEEDWRITE);
if (bitmap->need_sync &&
mddev->bitmap_info.external == 0) { /* Arrange for superblock update as well as
* other changes */
bitmap_super_t *sb;
bitmap->need_sync = 0; if (bitmap->storage.filemap) {
sb = kmap_local_page(bitmap->storage.sb_page);
sb->events_cleared =
cpu_to_le64(bitmap->events_cleared);
kunmap_local(sb);
set_page_attr(bitmap, 0,
BITMAP_PAGE_NEEDWRITE);
}
} /* Now look at the bitmap counters and if any are '2' or '1', *decrementandhandleaccordingly.
*/
counts = &bitmap->counts;
spin_lock_irq(&counts->lock);
nextpage = 0; for (j = 0; j < counts->chunks; j++) {
bitmap_counter_t *bmc;
sector_t block = (sector_t)j << counts->chunkshift;
if (bitmap->bp[page].hijacked) { /* hijacked pointer */ /* should we use the first or second counter field
* of the hijacked pointer? */ int hi = (pageoff > PAGE_COUNTER_MASK); return &((bitmap_counter_t *)
&bitmap->bp[page].map)[hi];
} else/* page is allocated */ return (bitmap_counter_t *)
&(bitmap->bp[page].map[pageoff]);
}
if (unlikely(COUNTER(*bmc) == COUNTER_MAX)) {
DEFINE_WAIT(__wait); /* note that it is safe to do the prepare_to_wait *afterthetestaslongaswedoitbeforedropping *thespinlock.
*/
prepare_to_wait(&bitmap->overflow_wait, &__wait,
TASK_UNINTERRUPTIBLE);
spin_unlock_irq(&bitmap->counts.lock);
schedule();
finish_wait(&bitmap->overflow_wait, &__wait); continue;
}
if (bitmap == NULL) {/* FIXME or bitmap set as 'failed' */
*blocks = 1024; returntrue; /* always resync if no bitmap */
}
spin_lock_irq(&bitmap->counts.lock);
for (sector = old_lo; sector < new_lo; ) {
__bitmap_end_sync(bitmap, sector, &blocks, false);
sector += blocks;
}
WARN((blocks > new_lo) && old_lo, "alignment is not correct for lo\n");
for (sector = old_hi; sector < new_hi; ) {
bitmap_start_sync(mddev, sector, &blocks, false);
sector += blocks;
}
WARN((blocks > new_hi) && old_hi, "alignment is not correct for hi\n");
}
staticvoid md_bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, int needed)
{ /* For each chunk covered by any of these sectors, set the *counterto2andpossiblysetresync_needed.Theyshouldall *be0atthispoint
*/
md_bitmap_set_memory_bits(bitmap, sec, 1);
md_bitmap_file_set_bit(bitmap, sec); if (sec < bitmap->mddev->resync_offset) /* We are asserting that the array is dirty, *somovetheresync_offsetaddressbackso *thatitisobviousthatitisdirty
*/
bitmap->mddev->resync_offset = sec;
}
}
/* run the daemon_work three time to ensure everything is flushed *thatcanbe
*/
sleep = mddev->bitmap_info.daemon_sleep * 2;
bitmap->daemon_lastrun -= sleep;
bitmap_daemon_work(mddev);
bitmap->daemon_lastrun -= sleep;
bitmap_daemon_work(mddev);
bitmap->daemon_lastrun -= sleep;
bitmap_daemon_work(mddev); if (mddev->bitmap_info.external)
md_super_wait(mddev);
bitmap_update_sb(bitmap);
}
/* wait for behind writes to complete */ if (bitmap && atomic_read(&bitmap->behind_writes) > 0) {
pr_debug("md:%s: behind writes in progress - waiting to stop.\n",
mdname(mddev)); /* need to kick something here to make sure I/O goes? */
wait_event(bitmap->behind_wait,
atomic_read(&bitmap->behind_writes) == 0);
}
}
if (test_bit(MD_HAS_JOURNAL, &mddev->flags)) {
pr_notice("md/raid:%s: array with journal cannot have bitmap\n",
mdname(mddev)); return ERR_PTR(-EBUSY);
}
bitmap = kzalloc(sizeof(*bitmap), GFP_KERNEL); if (!bitmap) return ERR_PTR(-ENOMEM);
if (mddev_is_clustered(mddev))
mddev->cluster_ops->load_bitmaps(mddev, mddev->bitmap_info.nodes);
/* Clear out old bitmap info first: Either there is none, or we *areresumingaftersomeoneelsehaspossiblychangedthings, *soweshouldforgetoldcachedinfo. *Allchunksshouldbeclean,butsomemightneed_sync.
*/ while (sector < mddev->resync_max_sectors) {
sector_t blocks;
bitmap_start_sync(mddev, sector, &blocks, false);
sector += blocks;
}
bitmap_close_sync(mddev);
if (mddev->degraded == 0
|| bitmap->events_cleared == mddev->events) /* no need to keep dirty bits to optimise a
* re-add of a missing device */
start = mddev->resync_offset;
if (test_bit(BITMAP_WRITE_ERROR, &bitmap->flags))
err = -EIO;
out: return err;
}
/* caller need to free returned bitmap with md_bitmap_free() */ staticvoid *bitmap_get_from_slot(struct mddev *mddev, int slot)
{ int rv = 0; struct bitmap *bitmap;
/* Loads the bitmap associated with slot and copies the resync information *toourbitmap
*/ staticint bitmap_copy_from_slot(struct mddev *mddev, int slot, sector_t *low,
sector_t *high, bool clear_bits)
{ int rv = 0, i, j;
sector_t block, lo = 0, hi = 0; struct bitmap_counts *counts; struct bitmap *bitmap;
bitmap = bitmap_get_from_slot(mddev, slot); if (IS_ERR(bitmap)) {
pr_err("%s can't get bitmap from slot %d\n", __func__, slot); return -1;
}
counts = &bitmap->counts; for (j = 0; j < counts->chunks; j++) {
block = (sector_t)j << counts->chunkshift; if (md_bitmap_file_test_bit(bitmap, block)) { if (!lo)
lo = block;
hi = block;
md_bitmap_file_clear_bit(bitmap, block);
md_bitmap_set_memory_bits(mddev->bitmap, block, 1);
md_bitmap_file_set_bit(mddev->bitmap, block);
}
}
if (clear_bits) {
bitmap_update_sb(bitmap); /* BITMAP_PAGE_PENDING is set, but bitmap_unplug needs
* BITMAP_PAGE_DIRTY or _NEEDWRITE to write ... */ for (i = 0; i < bitmap->storage.file_pages; i++) if (test_page_attr(bitmap, i, BITMAP_PAGE_PENDING))
set_page_attr(bitmap, i, BITMAP_PAGE_NEEDWRITE);
__bitmap_unplug(bitmap);
}
__bitmap_unplug(mddev->bitmap);
*low = lo;
*high = hi;
md_bitmap_free(bitmap);
if (chunksize == 0) { /* If there is enough space, leave the chunk size unchanged, *elseincreasebyfactoroftwountilthereisenoughspace.
*/ long bytes; long space = bitmap->mddev->bitmap_info.space;
if (space == 0) { /* We don't know how much space there is, so limit *tocurrentsize-insectors.
*/
bytes = DIV_ROUND_UP(bitmap->counts.chunks, 8); if (!bitmap->mddev->bitmap_info.external)
bytes += sizeof(bitmap_super_t);
space = DIV_ROUND_UP(bytes, 512);
bitmap->mddev->bitmap_info.space = space;
}
chunkshift = bitmap->counts.chunkshift;
chunkshift--; do { /* 'chunkshift' is shift from block size to chunk size */
chunkshift++;
chunks = DIV_ROUND_UP_SECTOR_T(blocks, 1 << chunkshift);
bytes = DIV_ROUND_UP(chunks, 8); if (!bitmap->mddev->bitmap_info.external)
bytes += sizeof(bitmap_super_t);
} while (bytes > (space << 9) && (chunkshift + BITMAP_BLOCK_SHIFT) <
(BITS_PER_BYTE * sizeof(((bitmap_super_t *)0)->chunksize) - 1));
} else
chunkshift = ffz(~chunksize) - BITMAP_BLOCK_SHIFT;
chunks = DIV_ROUND_UP_SECTOR_T(blocks, 1 << chunkshift);
memset(&store, 0, sizeof(store)); if (bitmap->mddev->bitmap_info.offset || bitmap->mddev->bitmap_info.file)
ret = md_bitmap_storage_alloc(&store, chunks,
!bitmap->mddev->bitmap_info.external,
mddev_is_clustered(bitmap->mddev)
? bitmap->cluster_slot : 0); if (ret) {
md_bitmap_file_unmap(&store); goto err;
}
pages = DIV_ROUND_UP(chunks, PAGE_COUNTER_RATIO);
new_bp = kcalloc(pages, sizeof(*new_bp), GFP_KERNEL);
ret = -ENOMEM; if (!new_bp) {
md_bitmap_file_unmap(&store); goto err;
}
if (!init)
bitmap->mddev->pers->quiesce(bitmap->mddev, 1);
/* For cluster raid, need to pre-allocate bitmap */ if (mddev_is_clustered(bitmap->mddev)) { unsignedlong page; for (page = 0; page < pages; page++) {
ret = md_bitmap_checkpage(&bitmap->counts, page, 1, 1); if (ret) { unsignedlong k;
/* deallocate the page memory */ for (k = 0; k < page; k++) {
kfree(new_bp[k].map);
}
kfree(new_bp);
if (bitmap->counts.bp != old_counts.bp) { unsignedlong k; for (k = 0; k < old_counts.pages; k++) if (!old_counts.bp[k].hijacked)
kfree(old_counts.bp[k].map);
kfree(old_counts.bp);
}
if (!init) { int i; while (block < (chunks << chunkshift)) {
bitmap_counter_t *bmc;
bmc = md_bitmap_get_counter(&bitmap->counts, block, &new_blocks, 1); if (bmc) { /* new space. It needs to be resynced, so *wesetNEEDED_MASK.
*/ if (*bmc == 0) {
*bmc = NEEDED_MASK | 2;
md_bitmap_count_page(&bitmap->counts, block, 1);
md_bitmap_set_pending(&bitmap->counts, block);
}
}
block += new_blocks;
} for (i = 0; i < bitmap->storage.file_pages; i++)
set_page_attr(bitmap, i, BITMAP_PAGE_DIRTY);
}
spin_unlock_irq(&bitmap->counts.lock);
if (!init) {
__bitmap_unplug(bitmap);
bitmap->mddev->pers->quiesce(bitmap->mddev, 0);
}
ret = 0;
err: return ret;
}
/* 'bitmap/space' is the space available at 'location' for the *bitmap.Thisallowsthekerneltoknowwhenitissafeto *resizethebitmaptomatcharesizedarray.
*/ static ssize_t
space_show(struct mddev *mddev, char *page)
{ return sprintf(page, "%lu\n", mddev->bitmap_info.space);
}
len = sprintf(page, "%lu", secs); if (jifs)
len += sprintf(page+len, ".%03u", jiffies_to_msecs(jifs));
len += sprintf(page+len, "\n"); return len;
}
static ssize_t
timeout_store(struct mddev *mddev, constchar *buf, size_t len)
{ /* timeout can be set at any time */ unsignedlong timeout; int rv = strict_strtoul_scaled(buf, &timeout, 4); if (rv) return rv;
/* just to make sure we don't overflow... */ if (timeout >= LONG_MAX / HZ) return -EINVAL;
timeout = timeout * HZ / 10000;
if (timeout >= MAX_SCHEDULE_TIMEOUT)
timeout = MAX_SCHEDULE_TIMEOUT-1; if (timeout < 1)
timeout = 1;
rv = mddev_suspend_and_lock(mddev); if (rv) return rv;
/* *Withoutwritemostlydevice,itdoesn'tmakesensetoset *backlogformax_write_behind.
*/
rdev_for_each(rdev, mddev) { if (test_bit(WriteMostly, &rdev->flags)) {
has_write_mostly = true; break;
}
} if (!has_write_mostly) {
pr_warn_ratelimited("%s: can't set backlog, no write mostly device available\n",
mdname(mddev));
mddev_unlock(mddev); return -EINVAL;
}
mddev->bitmap_info.max_write_behind = backlog; if (!backlog && mddev->serial_info_pool) { /* serial_info_pool is not needed if backlog is zero */ if (!mddev->serialize_policy)
mddev_destroy_serial_pool(mddev, NULL);
} elseif (backlog && !mddev->serial_info_pool) { /* serial_info_pool is needed since backlog is not zero */
rdev_for_each(rdev, mddev)
mddev_create_serial_pool(mddev, rdev);
} if (old_mwb != backlog)
bitmap_update_sb(mddev->bitmap);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.