|
@@ -462,265 +462,6 @@ w_al_write_transaction(struct drbd_work *w, int unused)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-/* FIXME
|
|
|
- * reading of the activity log,
|
|
|
- * and potentially dirtying of the affected bitmap regions,
|
|
|
- * should be done from userland only.
|
|
|
- * DRBD would simply always attach with an empty activity log,
|
|
|
- * and refuse to attach to something that looks like a crashed primary.
|
|
|
- */
|
|
|
-
|
|
|
-/**
|
|
|
- * drbd_al_read_tr() - Read a single transaction from the on disk activity log
|
|
|
- * @mdev: DRBD device.
|
|
|
- * @bdev: Block device to read form.
|
|
|
- * @b: pointer to an al_transaction.
|
|
|
- * @index: On disk slot of the transaction to read.
|
|
|
- *
|
|
|
- * Returns -1 on IO error, 0 on checksum error and 1 upon success.
|
|
|
- */
|
|
|
-static int drbd_al_read_tr(struct drbd_conf *mdev,
|
|
|
- struct drbd_backing_dev *bdev,
|
|
|
- int index)
|
|
|
-{
|
|
|
- struct al_transaction_on_disk *b = page_address(mdev->md_io_page);
|
|
|
- sector_t sector;
|
|
|
- u32 crc;
|
|
|
-
|
|
|
- sector = bdev->md.md_offset
|
|
|
- + bdev->md.al_offset
|
|
|
- + index * (MD_BLOCK_SIZE>>9);
|
|
|
-
|
|
|
- /* Dont process error normally,
|
|
|
- * as this is done before disk is attached! */
|
|
|
- if (drbd_md_sync_page_io(mdev, bdev, sector, READ))
|
|
|
- return -1;
|
|
|
-
|
|
|
- if (!expect(b->magic == cpu_to_be32(DRBD_AL_MAGIC)))
|
|
|
- return 0;
|
|
|
-
|
|
|
- if (!expect(be16_to_cpu(b->n_updates) <= AL_UPDATES_PER_TRANSACTION))
|
|
|
- return 0;
|
|
|
-
|
|
|
- if (!expect(be16_to_cpu(b->context_size) <= DRBD_AL_EXTENTS_MAX))
|
|
|
- return 0;
|
|
|
-
|
|
|
- if (!expect(be16_to_cpu(b->context_start_slot_nr) < DRBD_AL_EXTENTS_MAX))
|
|
|
- return 0;
|
|
|
-
|
|
|
- crc = be32_to_cpu(b->crc32c);
|
|
|
- b->crc32c = 0;
|
|
|
- if (!expect(crc == crc32c(0, b, 4096)))
|
|
|
- return 0;
|
|
|
-
|
|
|
- return 1;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * drbd_al_read_log() - Restores the activity log from its on disk representation.
|
|
|
- * @mdev: DRBD device.
|
|
|
- * @bdev: Block device to read form.
|
|
|
- *
|
|
|
- * Returns 1 on success, returns 0 when reading the log failed due to IO errors.
|
|
|
- */
|
|
|
-int drbd_al_read_log(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
|
|
|
-{
|
|
|
- struct al_transaction_on_disk *b;
|
|
|
- int i;
|
|
|
- int rv;
|
|
|
- int mx;
|
|
|
- int active_extents = 0;
|
|
|
- int transactions = 0;
|
|
|
- int found_valid = 0;
|
|
|
- int found_initialized = 0;
|
|
|
- int from = 0;
|
|
|
- int to = 0;
|
|
|
- u32 from_tnr = 0;
|
|
|
- u32 to_tnr = 0;
|
|
|
- u32 cnr;
|
|
|
-
|
|
|
- /* Note that this is expected to be called with a newly created,
|
|
|
- * clean and all unused activity log of the "expected size".
|
|
|
- */
|
|
|
-
|
|
|
- /* lock out all other meta data io for now,
|
|
|
- * and make sure the page is mapped.
|
|
|
- */
|
|
|
- b = drbd_md_get_buffer(mdev);
|
|
|
- if (!b)
|
|
|
- return 0;
|
|
|
-
|
|
|
- /* Always use the full ringbuffer space for now.
|
|
|
- * possible optimization: read in all of it,
|
|
|
- * then scan the in-memory pages. */
|
|
|
-
|
|
|
- mx = (MD_AL_SECTORS*512/MD_BLOCK_SIZE);
|
|
|
-
|
|
|
- /* Find the valid transaction in the log */
|
|
|
- for (i = 0; i < mx; i++) {
|
|
|
- rv = drbd_al_read_tr(mdev, bdev, i);
|
|
|
- /* invalid data in that block */
|
|
|
- if (rv == 0)
|
|
|
- continue;
|
|
|
- if (be16_to_cpu(b->transaction_type) == AL_TR_INITIALIZED) {
|
|
|
- ++found_initialized;
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- /* IO error */
|
|
|
- if (rv == -1) {
|
|
|
- drbd_md_put_buffer(mdev);
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
- cnr = be32_to_cpu(b->tr_number);
|
|
|
- if (++found_valid == 1) {
|
|
|
- from = i;
|
|
|
- to = i;
|
|
|
- from_tnr = cnr;
|
|
|
- to_tnr = cnr;
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- D_ASSERT(cnr != to_tnr);
|
|
|
- D_ASSERT(cnr != from_tnr);
|
|
|
- if ((int)cnr - (int)from_tnr < 0) {
|
|
|
- D_ASSERT(from_tnr - cnr + i - from == mx);
|
|
|
- from = i;
|
|
|
- from_tnr = cnr;
|
|
|
- }
|
|
|
- if ((int)cnr - (int)to_tnr > 0) {
|
|
|
- D_ASSERT(cnr - to_tnr == i - to);
|
|
|
- to = i;
|
|
|
- to_tnr = cnr;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (!found_valid) {
|
|
|
- if (found_initialized != mx)
|
|
|
- dev_warn(DEV, "No usable activity log found.\n");
|
|
|
- drbd_md_put_buffer(mdev);
|
|
|
- return 1;
|
|
|
- }
|
|
|
-
|
|
|
- /* Read the valid transactions.
|
|
|
- * dev_info(DEV, "Reading from %d to %d.\n",from,to); */
|
|
|
- i = from;
|
|
|
- while (1) {
|
|
|
- struct lc_element *e;
|
|
|
- unsigned j, n, slot, extent_nr;
|
|
|
-
|
|
|
- rv = drbd_al_read_tr(mdev, bdev, i);
|
|
|
- if (!expect(rv != 0))
|
|
|
- goto cancel;
|
|
|
- if (rv == -1) {
|
|
|
- drbd_md_put_buffer(mdev);
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
- /* deal with different transaction types.
|
|
|
- * not yet implemented */
|
|
|
- if (!expect(b->transaction_type == 0))
|
|
|
- goto cancel;
|
|
|
-
|
|
|
- /* on the fly re-create/resize activity log?
|
|
|
- * will be a special transaction type flag. */
|
|
|
- if (!expect(be16_to_cpu(b->context_size) == mdev->act_log->nr_elements))
|
|
|
- goto cancel;
|
|
|
- if (!expect(be16_to_cpu(b->context_start_slot_nr) < mdev->act_log->nr_elements))
|
|
|
- goto cancel;
|
|
|
-
|
|
|
- /* We are the only user of the activity log right now,
|
|
|
- * don't actually need to take that lock. */
|
|
|
- spin_lock_irq(&mdev->al_lock);
|
|
|
-
|
|
|
- /* first, apply the context, ... */
|
|
|
- for (j = 0, slot = be16_to_cpu(b->context_start_slot_nr);
|
|
|
- j < AL_CONTEXT_PER_TRANSACTION &&
|
|
|
- slot < mdev->act_log->nr_elements; j++, slot++) {
|
|
|
- extent_nr = be32_to_cpu(b->context[j]);
|
|
|
- e = lc_element_by_index(mdev->act_log, slot);
|
|
|
- if (e->lc_number != extent_nr) {
|
|
|
- if (extent_nr != LC_FREE)
|
|
|
- active_extents++;
|
|
|
- else
|
|
|
- active_extents--;
|
|
|
- }
|
|
|
- lc_set(mdev->act_log, extent_nr, slot);
|
|
|
- }
|
|
|
-
|
|
|
- /* ... then apply the updates,
|
|
|
- * which override the context information.
|
|
|
- * drbd_al_read_tr already did the rangecheck
|
|
|
- * on n <= AL_UPDATES_PER_TRANSACTION */
|
|
|
- n = be16_to_cpu(b->n_updates);
|
|
|
- for (j = 0; j < n; j++) {
|
|
|
- slot = be16_to_cpu(b->update_slot_nr[j]);
|
|
|
- extent_nr = be32_to_cpu(b->update_extent_nr[j]);
|
|
|
- if (!expect(slot < mdev->act_log->nr_elements))
|
|
|
- break;
|
|
|
- e = lc_element_by_index(mdev->act_log, slot);
|
|
|
- if (e->lc_number != extent_nr) {
|
|
|
- if (extent_nr != LC_FREE)
|
|
|
- active_extents++;
|
|
|
- else
|
|
|
- active_extents--;
|
|
|
- }
|
|
|
- lc_set(mdev->act_log, extent_nr, slot);
|
|
|
- }
|
|
|
- spin_unlock_irq(&mdev->al_lock);
|
|
|
-
|
|
|
- transactions++;
|
|
|
-
|
|
|
-cancel:
|
|
|
- if (i == to)
|
|
|
- break;
|
|
|
- i++;
|
|
|
- if (i >= mx)
|
|
|
- i = 0;
|
|
|
- }
|
|
|
-
|
|
|
- mdev->al_tr_number = to_tnr+1;
|
|
|
- mdev->al_tr_pos = (to + 1) % (MD_AL_SECTORS*512/MD_BLOCK_SIZE);
|
|
|
-
|
|
|
- /* ok, we are done with it */
|
|
|
- drbd_md_put_buffer(mdev);
|
|
|
-
|
|
|
- dev_info(DEV, "Found %d transactions (%d active extents) in activity log.\n",
|
|
|
- transactions, active_extents);
|
|
|
-
|
|
|
- return 1;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * drbd_al_apply_to_bm() - Sets the bitmap to dirty(1) where covered by active AL extents
|
|
|
- * @mdev: DRBD device.
|
|
|
- */
|
|
|
-void drbd_al_apply_to_bm(struct drbd_conf *mdev)
|
|
|
-{
|
|
|
- unsigned int enr;
|
|
|
- unsigned long add = 0;
|
|
|
- char ppb[10];
|
|
|
- int i, tmp;
|
|
|
-
|
|
|
- wait_event(mdev->al_wait, lc_try_lock(mdev->act_log));
|
|
|
-
|
|
|
- for (i = 0; i < mdev->act_log->nr_elements; i++) {
|
|
|
- enr = lc_element_by_index(mdev->act_log, i)->lc_number;
|
|
|
- if (enr == LC_FREE)
|
|
|
- continue;
|
|
|
- tmp = drbd_bm_ALe_set_all(mdev, enr);
|
|
|
- dynamic_dev_dbg(DEV, "AL: set %d bits in extent %u\n", tmp, enr);
|
|
|
- add += tmp;
|
|
|
- }
|
|
|
-
|
|
|
- lc_unlock(mdev->act_log);
|
|
|
- wake_up(&mdev->al_wait);
|
|
|
-
|
|
|
- dev_info(DEV, "Marked additional %s as out-of-sync based on AL.\n",
|
|
|
- ppsize(ppb, Bit2KB(add)));
|
|
|
-}
|
|
|
-
|
|
|
static int _try_lc_del(struct drbd_conf *mdev, struct lc_element *al_ext)
|
|
|
{
|
|
|
int rv;
|