|
@@ -2968,6 +2968,86 @@ err:
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
+static int check_offsets_and_sizes(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
|
|
|
+{
|
|
|
+ sector_t capacity = drbd_get_capacity(bdev->md_bdev);
|
|
|
+ struct drbd_md *in_core = &bdev->md;
|
|
|
+ s32 on_disk_al_sect;
|
|
|
+ s32 on_disk_bm_sect;
|
|
|
+
|
|
|
+ /* The on-disk size of the activity log, calculated from offsets, and
|
|
|
+ * the size of the activity log calculated from the stripe settings,
|
|
|
+ * should match.
|
|
|
+ * Though we could relax this a bit: it is ok, if the striped activity log
|
|
|
+ * fits in the available on-disk activity log size.
|
|
|
+ * Right now, that would break how resize is implemented.
|
|
|
+ * TODO: make drbd_determine_dev_size() (and the drbdmeta tool) aware
|
|
|
+ * of possible unused padding space in the on disk layout. */
|
|
|
+ if (in_core->al_offset < 0) {
|
|
|
+ if (in_core->bm_offset > in_core->al_offset)
|
|
|
+ goto err;
|
|
|
+ on_disk_al_sect = -in_core->al_offset;
|
|
|
+ on_disk_bm_sect = in_core->al_offset - in_core->bm_offset;
|
|
|
+ } else {
|
|
|
+ if (in_core->al_offset != MD_4kB_SECT)
|
|
|
+ goto err;
|
|
|
+ if (in_core->bm_offset < in_core->al_offset + in_core->al_size_4k * MD_4kB_SECT)
|
|
|
+ goto err;
|
|
|
+
|
|
|
+ on_disk_al_sect = in_core->bm_offset - MD_4kB_SECT;
|
|
|
+ on_disk_bm_sect = in_core->md_size_sect - in_core->bm_offset;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* old fixed size meta data is exactly that: fixed. */
|
|
|
+ if (in_core->meta_dev_idx >= 0) {
|
|
|
+ if (in_core->md_size_sect != MD_128MB_SECT
|
|
|
+ || in_core->al_offset != MD_4kB_SECT
|
|
|
+ || in_core->bm_offset != MD_4kB_SECT + MD_32kB_SECT
|
|
|
+ || in_core->al_stripes != 1
|
|
|
+ || in_core->al_stripe_size_4k != MD_32kB_SECT/8)
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (capacity < in_core->md_size_sect)
|
|
|
+ goto err;
|
|
|
+ if (capacity - in_core->md_size_sect < drbd_md_first_sector(bdev))
|
|
|
+ goto err;
|
|
|
+
|
|
|
+ /* should be aligned, and at least 32k */
|
|
|
+ if ((on_disk_al_sect & 7) || (on_disk_al_sect < MD_32kB_SECT))
|
|
|
+ goto err;
|
|
|
+
|
|
|
+ /* should fit (for now: exactly) into the available on-disk space;
|
|
|
+ * overflow prevention is in check_activity_log_stripe_size() above. */
|
|
|
+ if (on_disk_al_sect != in_core->al_size_4k * MD_4kB_SECT)
|
|
|
+ goto err;
|
|
|
+
|
|
|
+ /* again, should be aligned */
|
|
|
+ if (in_core->bm_offset & 7)
|
|
|
+ goto err;
|
|
|
+
|
|
|
+ /* FIXME check for device grow with flex external meta data? */
|
|
|
+
|
|
|
+ /* can the available bitmap space cover the last agreed device size? */
|
|
|
+ if (on_disk_bm_sect < (in_core->la_size_sect+7)/MD_4kB_SECT/8/512)
|
|
|
+ goto err;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+
|
|
|
+err:
|
|
|
+ dev_err(DEV, "meta data offsets don't make sense: idx=%d "
|
|
|
+ "al_s=%u, al_sz4k=%u, al_offset=%d, bm_offset=%d, "
|
|
|
+ "md_size_sect=%u, la_size=%llu, md_capacity=%llu\n",
|
|
|
+ in_core->meta_dev_idx,
|
|
|
+ in_core->al_stripes, in_core->al_stripe_size_4k,
|
|
|
+ in_core->al_offset, in_core->bm_offset, in_core->md_size_sect,
|
|
|
+ (unsigned long long)in_core->la_size_sect,
|
|
|
+ (unsigned long long)capacity);
|
|
|
+
|
|
|
+ return -EINVAL;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
/**
|
|
|
* drbd_md_read() - Reads in the meta data super block
|
|
|
* @mdev: DRBD device.
|
|
@@ -2976,7 +3056,8 @@ err:
|
|
|
* Return NO_ERROR on success, and an enum drbd_ret_code in case
|
|
|
* something goes wrong.
|
|
|
*
|
|
|
- * Called exactly once during drbd_adm_attach()
|
|
|
+ * Called exactly once during drbd_adm_attach(), while still being D_DISKLESS,
|
|
|
+ * even before @bdev is assigned to @mdev->ldev.
|
|
|
*/
|
|
|
int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
|
|
|
{
|
|
@@ -2984,14 +3065,15 @@ int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
|
|
|
u32 magic, flags;
|
|
|
int i, rv = NO_ERROR;
|
|
|
|
|
|
- if (!get_ldev_if_state(mdev, D_ATTACHING))
|
|
|
- return ERR_IO_MD_DISK;
|
|
|
+ if (mdev->state.disk != D_DISKLESS)
|
|
|
+ return ERR_DISK_CONFIGURED;
|
|
|
|
|
|
buffer = drbd_md_get_buffer(mdev);
|
|
|
if (!buffer)
|
|
|
- goto out;
|
|
|
+ return ERR_NOMEM;
|
|
|
|
|
|
- /* First, figure out where our meta data superblock is located. */
|
|
|
+ /* First, figure out where our meta data superblock is located,
|
|
|
+ * and read it. */
|
|
|
bdev->md.meta_dev_idx = bdev->disk_conf->meta_dev_idx;
|
|
|
bdev->md.md_offset = drbd_md_ss(bdev);
|
|
|
|
|
@@ -3022,14 +3104,29 @@ int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
|
|
|
goto err;
|
|
|
}
|
|
|
|
|
|
- if (check_activity_log_stripe_size(mdev, buffer, &bdev->md))
|
|
|
+ if (be32_to_cpu(buffer->bm_bytes_per_bit) != BM_BLOCK_SIZE) {
|
|
|
+ dev_err(DEV, "unexpected bm_bytes_per_bit: %u (expected %u)\n",
|
|
|
+ be32_to_cpu(buffer->bm_bytes_per_bit), BM_BLOCK_SIZE);
|
|
|
goto err;
|
|
|
+ }
|
|
|
|
|
|
- if (be32_to_cpu(buffer->al_offset) != bdev->md.al_offset) {
|
|
|
- dev_err(DEV, "unexpected al_offset: %d (expected %d)\n",
|
|
|
- be32_to_cpu(buffer->al_offset), bdev->md.al_offset);
|
|
|
+
|
|
|
+ /* convert to in_core endian */
|
|
|
+ bdev->md.la_size_sect = be64_to_cpu(buffer->la_size_sect);
|
|
|
+ for (i = UI_CURRENT; i < UI_SIZE; i++)
|
|
|
+ bdev->md.uuid[i] = be64_to_cpu(buffer->uuid[i]);
|
|
|
+ bdev->md.flags = be32_to_cpu(buffer->flags);
|
|
|
+ bdev->md.device_uuid = be64_to_cpu(buffer->device_uuid);
|
|
|
+
|
|
|
+ bdev->md.md_size_sect = be32_to_cpu(buffer->md_size_sect);
|
|
|
+ bdev->md.al_offset = be32_to_cpu(buffer->al_offset);
|
|
|
+ bdev->md.bm_offset = be32_to_cpu(buffer->bm_offset);
|
|
|
+
|
|
|
+ if (check_activity_log_stripe_size(mdev, buffer, &bdev->md))
|
|
|
goto err;
|
|
|
- }
|
|
|
+ if (check_offsets_and_sizes(mdev, bdev))
|
|
|
+ goto err;
|
|
|
+
|
|
|
if (be32_to_cpu(buffer->bm_offset) != bdev->md.bm_offset) {
|
|
|
dev_err(DEV, "unexpected bm_offset: %d (expected %d)\n",
|
|
|
be32_to_cpu(buffer->bm_offset), bdev->md.bm_offset);
|
|
@@ -3041,20 +3138,8 @@ int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
|
|
|
goto err;
|
|
|
}
|
|
|
|
|
|
- if (be32_to_cpu(buffer->bm_bytes_per_bit) != BM_BLOCK_SIZE) {
|
|
|
- dev_err(DEV, "unexpected bm_bytes_per_bit: %u (expected %u)\n",
|
|
|
- be32_to_cpu(buffer->bm_bytes_per_bit), BM_BLOCK_SIZE);
|
|
|
- goto err;
|
|
|
- }
|
|
|
-
|
|
|
rv = NO_ERROR;
|
|
|
|
|
|
- bdev->md.la_size_sect = be64_to_cpu(buffer->la_size_sect);
|
|
|
- for (i = UI_CURRENT; i < UI_SIZE; i++)
|
|
|
- bdev->md.uuid[i] = be64_to_cpu(buffer->uuid[i]);
|
|
|
- bdev->md.flags = be32_to_cpu(buffer->flags);
|
|
|
- bdev->md.device_uuid = be64_to_cpu(buffer->device_uuid);
|
|
|
-
|
|
|
spin_lock_irq(&mdev->tconn->req_lock);
|
|
|
if (mdev->state.conn < C_CONNECTED) {
|
|
|
unsigned int peer;
|
|
@@ -3066,8 +3151,6 @@ int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
|
|
|
|
|
|
err:
|
|
|
drbd_md_put_buffer(mdev);
|
|
|
- out:
|
|
|
- put_ldev(mdev);
|
|
|
|
|
|
return rv;
|
|
|
}
|