void drbd_al_begin_io(struct drbd_conf *mdev, sector_t sector) { unsigned int enr = (sector >> (AL_EXTENT_SHIFT-9)); struct lc_element *al_ext; struct update_al_work al_work; D_ASSERT(atomic_read(&mdev->local_cnt) > 0); wait_event(mdev->al_wait, (al_ext = _al_get(mdev, enr))); if (al_ext->lc_number != enr) { /* drbd_al_write_transaction(mdev,al_ext,enr); * recurses into generic_make_request(), which * disallows recursion, bios being serialized on the * current->bio_tail list now. * we have to delegate updates to the activity log * to the worker thread. */ init_completion(&al_work.event); al_work.al_ext = al_ext; al_work.enr = enr; al_work.old_enr = al_ext->lc_number; al_work.w.cb = w_al_write_transaction; drbd_queue_work_front(&mdev->data.work, &al_work.w); wait_for_completion(&al_work.event); mdev->al_writ_cnt++; spin_lock_irq(&mdev->al_lock); lc_changed(mdev->act_log, al_ext); spin_unlock_irq(&mdev->al_lock); wake_up(&mdev->al_wait); } }
/* ATTENTION. The AL's extents are 4MB each, while the extents in the * resync LRU-cache are 16MB each. * The caller of this function has to hold an get_ldev() reference. * * TODO will be obsoleted once we have a caching lru of the on disk bitmap */ STATIC void drbd_try_clear_on_disk_bm(struct drbd_conf *mdev, sector_t sector, int count, int success) { struct lc_element *e; struct update_odbm_work *udw; unsigned int enr; D_ASSERT(atomic_read(&mdev->local_cnt)); /* I simply assume that a sector/size pair never crosses * a 16 MB extent border. (Currently this is true...) */ enr = BM_SECT_TO_EXT(sector); e = lc_get(mdev->resync, enr); if (e) { struct bm_extent *ext = lc_entry(e, struct bm_extent, lce); if (ext->lce.lc_number == enr) { if (success) ext->rs_left -= count; else ext->rs_failed += count; if (ext->rs_left < ext->rs_failed) { dev_err(DEV, "BAD! sector=%llus enr=%u rs_left=%d " "rs_failed=%d count=%d\n", (unsigned long long)sector, ext->lce.lc_number, ext->rs_left, ext->rs_failed, count); dump_stack(); lc_put(mdev->resync, &ext->lce); drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); return; } } else { /* Normally this element should be in the cache, * since drbd_rs_begin_io() pulled it already in. * * But maybe an application write finished, and we set * something outside the resync lru_cache in sync. */ int rs_left = drbd_bm_e_weight(mdev, enr); if (ext->flags != 0) { dev_warn(DEV, "changing resync lce: %d[%u;%02lx]" " -> %d[%u;00]\n", ext->lce.lc_number, ext->rs_left, ext->flags, enr, rs_left); ext->flags = 0; } if (ext->rs_failed) { dev_warn(DEV, "Kicking resync_lru element enr=%u " "out with rs_failed=%d\n", ext->lce.lc_number, ext->rs_failed); } ext->rs_left = rs_left; ext->rs_failed = success ? 0 : count; lc_changed(mdev->resync, &ext->lce); } lc_put(mdev->resync, &ext->lce); /* no race, we are within the al_lock! */ if (ext->rs_left == ext->rs_failed) { ext->rs_failed = 0; udw = kmalloc(sizeof(*udw), GFP_ATOMIC); if (udw) { udw->enr = ext->lce.lc_number; udw->w.cb = w_update_odbm; drbd_queue_work_front(&mdev->data.work, &udw->w); } else { dev_warn(DEV, "Could not kmalloc an udw\n"); } } } else {