static void process_suspend_info(struct mddev *mddev, int slot, sector_t lo, sector_t hi) { struct md_cluster_info *cinfo = mddev->cluster_info; struct suspend_info *s; if (!hi) { remove_suspend_info(mddev, slot); set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); md_wakeup_thread(mddev->thread); return; } s = kzalloc(sizeof(struct suspend_info), GFP_KERNEL); if (!s) return; s->slot = slot; s->lo = lo; s->hi = hi; mddev->pers->quiesce(mddev, 1); mddev->pers->quiesce(mddev, 0); spin_lock_irq(&cinfo->suspend_lock); /* Remove existing entry (if exists) before adding */ __remove_suspend_info(cinfo, slot); list_add(&s->list, &cinfo->suspend_list); spin_unlock_irq(&cinfo->suspend_lock); mddev->pers->quiesce(mddev, 2); }
/* * The BAST function for the ack lock resource * This function wakes up the receive thread in * order to receive and process the message. */ static void ack_bast(void *arg, int mode) { struct dlm_lock_resource *res = (struct dlm_lock_resource *)arg; struct md_cluster_info *cinfo = res->mddev->cluster_info; if (mode == DLM_LOCK_EX) md_wakeup_thread(cinfo->recv_thread); }
static void process_metadata_update(struct mddev *mddev, struct cluster_msg *msg) { struct md_cluster_info *cinfo = mddev->cluster_info; mddev->good_device_nr = le32_to_cpu(msg->raid_slot); set_bit(MD_RELOAD_SB, &mddev->flags); dlm_lock_sync(cinfo->no_new_dev_lockres, DLM_LOCK_CR); md_wakeup_thread(mddev->thread); }
static void recover_bitmaps(struct md_thread *thread) { struct mddev *mddev = thread->mddev; struct md_cluster_info *cinfo = mddev->cluster_info; struct dlm_lock_resource *bm_lockres; char str[64]; int slot, ret; struct suspend_info *s, *tmp; sector_t lo, hi; while (cinfo->recovery_map) { slot = fls64((u64)cinfo->recovery_map) - 1; /* Clear suspend_area associated with the bitmap */ spin_lock_irq(&cinfo->suspend_lock); list_for_each_entry_safe(s, tmp, &cinfo->suspend_list, list) if (slot == s->slot) { list_del(&s->list); kfree(s); } spin_unlock_irq(&cinfo->suspend_lock); snprintf(str, 64, "bitmap%04d", slot); bm_lockres = lockres_init(mddev, str, NULL, 1); if (!bm_lockres) { pr_err("md-cluster: Cannot initialize bitmaps\n"); goto clear_bit; } ret = dlm_lock_sync(bm_lockres, DLM_LOCK_PW); if (ret) { pr_err("md-cluster: Could not DLM lock %s: %d\n", str, ret); goto clear_bit; } ret = bitmap_copy_from_slot(mddev, slot, &lo, &hi, true); if (ret) { pr_err("md-cluster: Could not copy data from bitmap %d\n", slot); goto dlm_unlock; } if (hi > 0) { if (lo < mddev->recovery_cp) mddev->recovery_cp = lo; /* wake up thread to continue resync in case resync * is not finished */ if (mddev->recovery_cp != MaxSector) { set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); md_wakeup_thread(mddev->thread); } } dlm_unlock: dlm_unlock_sync(bm_lockres); clear_bit: lockres_free(bm_lockres); clear_bit(slot, &cinfo->recovery_map); } }
static void multipath_reschedule_retry (struct multipath_bh *mp_bh) { unsigned long flags; mddev_t *mddev = mp_bh->mddev; multipath_conf_t *conf = mddev_to_conf(mddev); spin_lock_irqsave(&conf->device_lock, flags); list_add(&mp_bh->retry_list, &conf->retry_list); spin_unlock_irqrestore(&conf->device_lock, flags); md_wakeup_thread(mddev->thread); }
static void load_bitmaps(struct mddev *mddev, int total_slots) { struct md_cluster_info *cinfo = mddev->cluster_info; /* load all the node's bitmap info for resync */ if (gather_all_resync_info(mddev, total_slots)) pr_err("md-cluster: failed to gather all resyn infos\n"); set_bit(MD_CLUSTER_ALREADY_IN_CLUSTER, &cinfo->state); /* wake up recv thread in case something need to be handled */ if (test_and_clear_bit(MD_CLUSTER_PENDING_RECV_EVENT, &cinfo->state)) md_wakeup_thread(cinfo->recv_thread); }
/* * The BAST function for the ack lock resource * This function wakes up the receive thread in * order to receive and process the message. */ static void ack_bast(void *arg, int mode) { struct dlm_lock_resource *res = arg; struct md_cluster_info *cinfo = res->mddev->cluster_info; if (mode == DLM_LOCK_EX) { if (test_bit(MD_CLUSTER_ALREADY_IN_CLUSTER, &cinfo->state)) md_wakeup_thread(cinfo->recv_thread); else set_bit(MD_CLUSTER_PENDING_RECV_EVENT, &cinfo->state); } }
static void process_suspend_info(struct mddev *mddev, int slot, sector_t lo, sector_t hi) { struct md_cluster_info *cinfo = mddev->cluster_info; struct suspend_info *s; if (!hi) { remove_suspend_info(mddev, slot); set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); md_wakeup_thread(mddev->thread); return; } /* * The bitmaps are not same for different nodes * if RESYNCING is happening in one node, then * the node which received the RESYNCING message * probably will perform resync with the region * [lo, hi] again, so we could reduce resync time * a lot if we can ensure that the bitmaps among * different nodes are match up well. * * sync_low/hi is used to record the region which * arrived in the previous RESYNCING message, * * Call bitmap_sync_with_cluster to clear * NEEDED_MASK and set RESYNC_MASK since * resync thread is running in another node, * so we don't need to do the resync again * with the same section */ bitmap_sync_with_cluster(mddev, cinfo->sync_low, cinfo->sync_hi, lo, hi); cinfo->sync_low = lo; cinfo->sync_hi = hi; s = kzalloc(sizeof(struct suspend_info), GFP_KERNEL); if (!s) return; s->slot = slot; s->lo = lo; s->hi = hi; mddev->pers->quiesce(mddev, 1); mddev->pers->quiesce(mddev, 0); spin_lock_irq(&cinfo->suspend_lock); /* Remove existing entry (if exists) before adding */ __remove_suspend_info(cinfo, slot); list_add(&s->list, &cinfo->suspend_list); spin_unlock_irq(&cinfo->suspend_lock); mddev->pers->quiesce(mddev, 2); }
static void multipath_reschedule_retry (struct multipath_bh *mp_bh) { unsigned long flags; mddev_t *mddev = mp_bh->mddev; spin_lock_irqsave(&retry_list_lock, flags); if (multipath_retry_list == NULL) multipath_retry_tail = &multipath_retry_list; *multipath_retry_tail = mp_bh; multipath_retry_tail = &mp_bh->next_mp; mp_bh->next_mp = NULL; spin_unlock_irqrestore(&retry_list_lock, flags); md_wakeup_thread(mddev->thread); }
static void process_remove_disk(struct mddev *mddev, struct cluster_msg *msg) { struct md_rdev *rdev = md_find_rdev_nr_rcu(mddev, le32_to_cpu(msg->raid_slot)); if (rdev) { set_bit(ClusterRemove, &rdev->flags); set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); md_wakeup_thread(mddev->thread); } else pr_warn("%s: %d Could not find disk(%d) to REMOVE\n", __func__, __LINE__, le32_to_cpu(msg->raid_slot)); }
static void __recover_slot(struct mddev *mddev, int slot) { struct md_cluster_info *cinfo = mddev->cluster_info; set_bit(slot, &cinfo->recovery_map); if (!cinfo->recovery_thread) { cinfo->recovery_thread = md_register_thread(recover_bitmaps, mddev, "recover"); if (!cinfo->recovery_thread) { pr_warn("md-cluster: Could not create recovery thread\n"); return; } } md_wakeup_thread(cinfo->recovery_thread); }
/* * write out a page to a file */ static int write_page(struct bitmap *bitmap, struct page *page, int wait) { int ret = -ENOMEM; if (bitmap->file == NULL) return write_sb_page(bitmap->mddev, bitmap->offset, page, wait); flush_dcache_page(page); /* make sure visible to anyone reading the file */ if (wait) lock_page(page); else { if (TestSetPageLocked(page)) return -EAGAIN; /* already locked */ if (PageWriteback(page)) { unlock_page(page); return -EAGAIN; } } ret = page->mapping->a_ops->prepare_write(bitmap->file, page, 0, PAGE_SIZE); if (!ret) ret = page->mapping->a_ops->commit_write(bitmap->file, page, 0, PAGE_SIZE); if (ret) { unlock_page(page); return ret; } set_page_dirty(page); /* force it to be written out */ if (!wait) { /* add to list to be waited for by daemon */ struct page_list *item = mempool_alloc(bitmap->write_pool, GFP_NOIO); item->page = page; get_page(page); spin_lock(&bitmap->write_lock); list_add(&item->list, &bitmap->complete_pages); spin_unlock(&bitmap->write_lock); md_wakeup_thread(bitmap->writeback_daemon); } return write_one_page(page, wait); }
static void recover_slot(void *arg, struct dlm_slot *slot) { struct mddev *mddev = arg; struct md_cluster_info *cinfo = mddev->cluster_info; pr_info("md-cluster: %s Node %d/%d down. My slot: %d. Initiating recovery.\n", mddev->bitmap_info.cluster_name, slot->nodeid, slot->slot, cinfo->slot_number); set_bit(slot->slot - 1, &cinfo->recovery_map); if (!cinfo->recovery_thread) { cinfo->recovery_thread = md_register_thread(recover_bitmaps, mddev, "recover"); if (!cinfo->recovery_thread) { pr_warn("md-cluster: Could not create recovery thread\n"); return; } } md_wakeup_thread(cinfo->recovery_thread); }
/* * bitmap_init_from_disk -- called at bitmap_create time to initialize * the in-memory bitmap from the on-disk bitmap -- also, sets up the * memory mapping of the bitmap file * Special cases: * if there's no bitmap file, or if the bitmap file had been * previously kicked from the array, we mark all the bits as * 1's in order to cause a full resync. * * We ignore all bits for sectors that end earlier than 'start'. * This is used when reading an out-of-date bitmap... */ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) { unsigned long i, chunks, index, oldindex, bit; struct page *page = NULL, *oldpage = NULL; unsigned long num_pages, bit_cnt = 0; struct file *file; unsigned long bytes, offset; int outofdate; int ret = -ENOSPC; void *paddr; chunks = bitmap->chunks; file = bitmap->file; BUG_ON(!file && !bitmap->offset); #ifdef INJECT_FAULTS_3 outofdate = 1; #else outofdate = bitmap->flags & BITMAP_STALE; #endif if (outofdate) printk(KERN_INFO "%s: bitmap file is out of date, doing full " "recovery\n", bmname(bitmap)); bytes = (chunks + 7) / 8; num_pages = (bytes + sizeof(bitmap_super_t) + PAGE_SIZE - 1) / PAGE_SIZE; if (file && i_size_read(file->f_mapping->host) < bytes + sizeof(bitmap_super_t)) { printk(KERN_INFO "%s: bitmap file too short %lu < %lu\n", bmname(bitmap), (unsigned long) i_size_read(file->f_mapping->host), bytes + sizeof(bitmap_super_t)); goto out; } ret = -ENOMEM; bitmap->filemap = kmalloc(sizeof(struct page *) * num_pages, GFP_KERNEL); if (!bitmap->filemap) goto out; /* We need 4 bits per page, rounded up to a multiple of sizeof(unsigned long) */ bitmap->filemap_attr = kzalloc( roundup( DIV_ROUND_UP(num_pages*4, 8), sizeof(unsigned long)), GFP_KERNEL); if (!bitmap->filemap_attr) goto out; oldindex = ~0L; for (i = 0; i < chunks; i++) { int b; index = file_page_index(i); bit = file_page_offset(i); if (index != oldindex) { /* this is a new page, read it in */ int count; /* unmap the old page, we're done with it */ if (index == num_pages-1) count = bytes + sizeof(bitmap_super_t) - index * PAGE_SIZE; else count = PAGE_SIZE; if (index == 0) { /* * if we're here then the superblock page * contains some bits (PAGE_SIZE != sizeof sb) * we've already read it in, so just use it */ page = bitmap->sb_page; offset = sizeof(bitmap_super_t); } else if (file) { page = read_page(file, index, bitmap, count); offset = 0; } else { page = read_sb_page(bitmap->mddev, bitmap->offset, index); offset = 0; } if (IS_ERR(page)) { /* read error */ ret = PTR_ERR(page); goto out; } oldindex = index; oldpage = page; if (outofdate) { /* * if bitmap is out of date, dirty the * whole page and write it out */ paddr = kmap_atomic(page, KM_USER0); memset(paddr + offset, 0xff, PAGE_SIZE - offset); kunmap_atomic(paddr, KM_USER0); ret = write_page(bitmap, page, 1); if (ret) { /* release, page not in filemap yet */ put_page(page); goto out; } } bitmap->filemap[bitmap->file_pages++] = page; bitmap->last_page_size = count; } paddr = kmap_atomic(page, KM_USER0); if (bitmap->flags & BITMAP_HOSTENDIAN) b = test_bit(bit, paddr); else b = ext2_test_bit(bit, paddr); kunmap_atomic(paddr, KM_USER0); if (b) { /* if the disk bit is set, set the memory bit */ bitmap_set_memory_bits(bitmap, i << CHUNK_BLOCK_SHIFT(bitmap), ((i+1) << (CHUNK_BLOCK_SHIFT(bitmap)) >= start) ); bit_cnt++; set_page_attr(bitmap, page, BITMAP_PAGE_CLEAN); } } /* everything went OK */ ret = 0; bitmap_mask_state(bitmap, BITMAP_STALE, MASK_UNSET); if (bit_cnt) { /* Kick recovery if any bits were set */ set_bit(MD_RECOVERY_NEEDED, &bitmap->mddev->recovery); md_wakeup_thread(bitmap->mddev->thread); } out: printk(KERN_INFO "%s: bitmap initialized from disk: " "read %lu/%lu pages, set %lu bits, status: %d\n", bmname(bitmap), bitmap->file_pages, num_pages, bit_cnt, ret); return ret; }