Skip to content

Commit

Permalink
Device removal panics on 32-bit systems
Browse files Browse the repository at this point in the history
The issue is caused by an incorrect usage of the sizeof() operator
in vdev_obsolete_sm_object(): on 64-bit systems this is not an issue
since both "uint64_t" and "uint64_t*" are 8 bytes in size. However on
32-bit systems pointers are 4 bytes long which is not supported by
zap_lookup_impl(). Trying to remove a top-level vdev on a 32-bit system
will cause the following failure:

VERIFY3(0 == vdev_obsolete_sm_object(vd, &obsolete_sm_object)) failed (0 == 22)
PANIC at vdev_indirect.c:833:vdev_indirect_sync_obsolete()
Showing stack for process 1315
CPU: 6 PID: 1315 Comm: txg_sync Tainted: P           OE   4.4.69+ #2
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-2.fc27 04/01/2014
 c1abc6e7 0ae10898 00000286 d4ac3bc0 c14397bc da4cd7d8 d4ac3bf0 d4ac3bd0
 d790e7ce d7911cc1 00000523 d4ac3d00 d790e7d7 d7911ce4 da4cd7d8 00000341
 da4ce664 da4cd8c0 da33fa6e 49524556 28335946 3d3d2030 65647620 626f5f76
Call Trace:
 [<>] dump_stack+0x58/0x7c
 [<>] spl_dumpstack+0x23/0x27 [spl]
 [<>] spl_panic.cold.0+0x5/0x41 [spl]
 [<>] ? dbuf_rele+0x3e/0x90 [zfs]
 [<>] ? zap_lookup_norm+0xbe/0xe0 [zfs]
 [<>] ? zap_lookup+0x57/0x70 [zfs]
 [<>] ? vdev_obsolete_sm_object+0x102/0x12b [zfs]
 [<>] vdev_indirect_sync_obsolete+0x3e1/0x64d [zfs]
 [<>] ? txg_verify+0x1d/0x160 [zfs]
 [<>] ? dmu_tx_create_dd+0x80/0xc0 [zfs]
 [<>] vdev_sync+0xbf/0x550 [zfs]
 [<>] ? mutex_lock+0x10/0x30
 [<>] ? txg_list_remove+0x9f/0x1a0 [zfs]
 [<>] ? zap_contains+0x4d/0x70 [zfs]
 [<>] spa_sync+0x9f1/0x1b10 [zfs]
 ...
 [<>] ? kthread_stop+0x110/0x110

This commit simply corrects the "integer_size" parameter used to lookup
the vdev's ZAP object.

Reviewed-by: Giuseppe Di Natale <guss80@gmail.com>
Reviewed-by: Igor Kozhukhov <igor@dilos.org>
Reviewed-by: George Melikov <mail@gmelikov.ru>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: loli10K <ezomori.nozomu@gmail.com>
Closes #8790
  • Loading branch information
loli10K authored and lundman committed Jun 17, 2019
1 parent b5a3ba5 commit 0a10bb0
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 23 deletions.
20 changes: 13 additions & 7 deletions cmd/zdb/zdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -696,19 +696,20 @@ get_metaslab_refcount(vdev_t *vd)
static int
get_obsolete_refcount(vdev_t *vd)
{
uint64_t obsolete_sm_object;
int refcount = 0;

uint64_t obsolete_sm_obj = vdev_obsolete_sm_object(vd);
if (vd->vdev_top == vd && obsolete_sm_obj != 0) {
VERIFY0(vdev_obsolete_sm_object(vd, &obsolete_sm_object));
if (vd->vdev_top == vd && obsolete_sm_object != 0) {
dmu_object_info_t doi;
VERIFY0(dmu_object_info(vd->vdev_spa->spa_meta_objset,
obsolete_sm_obj, &doi));
obsolete_sm_object, &doi));
if (doi.doi_bonus_size == sizeof (space_map_phys_t)) {
refcount++;
}
} else {
ASSERT3P(vd->vdev_obsolete_sm, ==, NULL);
ASSERT3U(obsolete_sm_obj, ==, 0);
ASSERT3U(obsolete_sm_object, ==, 0);
}
for (unsigned c = 0; c < vd->vdev_children; c++) {
refcount += get_obsolete_refcount(vd->vdev_child[c]);
Expand Down Expand Up @@ -1047,7 +1048,8 @@ print_vdev_indirect(vdev_t *vd)
}
(void) printf("\n");

uint64_t obsolete_sm_object = vdev_obsolete_sm_object(vd);
uint64_t obsolete_sm_object;
VERIFY0(vdev_obsolete_sm_object(vd, &obsolete_sm_object));
if (obsolete_sm_object != 0) {
objset_t *mos = vd->vdev_spa->spa_meta_objset;
(void) printf("obsolete space map object %llu:\n",
Expand Down Expand Up @@ -3508,9 +3510,11 @@ zdb_load_obsolete_counts(vdev_t *vd)
spa_t *spa = vd->vdev_spa;
spa_condensing_indirect_phys_t *scip =
&spa->spa_condensing_indirect_phys;
uint64_t obsolete_sm_object;
uint32_t *counts;

EQUIV(vdev_obsolete_sm_object(vd) != 0, vd->vdev_obsolete_sm != NULL);
VERIFY0(vdev_obsolete_sm_object(vd, &obsolete_sm_object));
EQUIV(obsolete_sm_object != 0, vd->vdev_obsolete_sm != NULL);
counts = vdev_indirect_mapping_load_obsolete_counts(vim);
if (vd->vdev_obsolete_sm != NULL) {
vdev_indirect_mapping_load_obsolete_spacemap(vim, counts,
Expand Down Expand Up @@ -4432,7 +4436,9 @@ verify_device_removal_feature_counts(spa_t *spa)
ASSERT(vic->vic_mapping_object != 0);
precise_vdev_count++;
}
if (vdev_obsolete_sm_object(vd) != 0) {
uint64_t obsolete_sm_object;
VERIFY0(vdev_obsolete_sm_object(vd, &obsolete_sm_object));
if (obsolete_sm_object != 0) {
ASSERT(vic->vic_mapping_object != 0);
obsolete_sm_count++;
}
Expand Down
2 changes: 1 addition & 1 deletion include/sys/vdev_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,7 @@ extern int zfs_vdev_cache_size;
extern void vdev_indirect_sync_obsolete(vdev_t *vd, dmu_tx_t *tx);
extern boolean_t vdev_indirect_should_condense(vdev_t *vd);
extern void spa_condense_indirect_start_sync(vdev_t *vd, dmu_tx_t *tx);
extern int vdev_obsolete_sm_object(vdev_t *vd);
extern int vdev_obsolete_sm_object(vdev_t *vd, uint64_t *);
extern boolean_t vdev_obsolete_counts_are_precise(vdev_t *vd);

/*
Expand Down
4 changes: 3 additions & 1 deletion module/zfs/spa.c
Original file line number Diff line number Diff line change
Expand Up @@ -8284,7 +8284,9 @@ vdev_indirect_state_sync_verify(vdev_t *vd)
ASSERT(vib != NULL);
}

if (vdev_obsolete_sm_object(vd) != 0) {
uint64_t obsolete_sm_object = 0;
ASSERT0(vdev_obsolete_sm_object(vd, &obsolete_sm_object));
if (obsolete_sm_object != 0) {
ASSERT(vd->vdev_obsolete_sm != NULL);
ASSERT(vd->vdev_removing ||
vd->vdev_ops == &vdev_indirect_ops);
Expand Down
5 changes: 3 additions & 2 deletions module/zfs/vdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -3004,8 +3004,9 @@ vdev_load(vdev_t *vd)
return (error);
}

uint64_t obsolete_sm_object = vdev_obsolete_sm_object(vd);
if (obsolete_sm_object != 0) {
uint64_t obsolete_sm_object;
error = vdev_obsolete_sm_object(vd, &obsolete_sm_object);
if (error == 0 && obsolete_sm_object != 0) {
objset_t *mos = vd->vdev_spa->spa_meta_objset;
ASSERT(vd->vdev_asize != 0);
ASSERT3P(vd->vdev_obsolete_sm, ==, NULL);
Expand Down
28 changes: 17 additions & 11 deletions module/zfs/vdev_indirect.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

/*
* Copyright (c) 2014, 2017 by Delphix. All rights reserved.
* Copyright (c) 2019, loli10K <ezomori.nozomu@gmail.com>. All rights reserved.
*/

#include <sys/zfs_context.h>
Expand Down Expand Up @@ -397,8 +398,10 @@ vdev_indirect_should_condense(vdev_t *vd)
* If nothing new has been marked obsolete, there is no
* point in condensing.
*/
ASSERTV(uint64_t obsolete_sm_obj);
ASSERT0(vdev_obsolete_sm_object(vd, &obsolete_sm_obj));
if (vd->vdev_obsolete_sm == NULL) {
ASSERT0(vdev_obsolete_sm_object(vd));
ASSERT0(obsolete_sm_obj);
return (B_FALSE);
}

Expand Down Expand Up @@ -741,7 +744,8 @@ spa_condense_indirect_start_sync(vdev_t *vd, dmu_tx_t *tx)
ASSERT(spa_feature_is_active(spa, SPA_FEATURE_OBSOLETE_COUNTS));
ASSERT(vdev_indirect_mapping_num_entries(vd->vdev_indirect_mapping));

uint64_t obsolete_sm_obj = vdev_obsolete_sm_object(vd);
uint64_t obsolete_sm_obj;
VERIFY0(vdev_obsolete_sm_object(vd, &obsolete_sm_obj));
ASSERT(obsolete_sm_obj != 0);

scip->scip_vdev = vd->vdev_id;
Expand Down Expand Up @@ -793,7 +797,9 @@ vdev_indirect_sync_obsolete(vdev_t *vd, dmu_tx_t *tx)
ASSERT(vd->vdev_removing || vd->vdev_ops == &vdev_indirect_ops);
ASSERT(spa_feature_is_enabled(spa, SPA_FEATURE_OBSOLETE_COUNTS));

if (vdev_obsolete_sm_object(vd) == 0) {
uint64_t obsolete_sm_object;
VERIFY0(vdev_obsolete_sm_object(vd, &obsolete_sm_object));
if (obsolete_sm_object == 0) {
uint64_t obsolete_sm_object =
space_map_alloc(spa->spa_meta_objset,
vdev_standard_sm_blksz, tx);
Expand All @@ -802,7 +808,7 @@ vdev_indirect_sync_obsolete(vdev_t *vd, dmu_tx_t *tx)
VERIFY0(zap_add(vd->vdev_spa->spa_meta_objset, vd->vdev_top_zap,
VDEV_TOP_ZAP_INDIRECT_OBSOLETE_SM,
sizeof (obsolete_sm_object), 1, &obsolete_sm_object, tx));
ASSERT3U(vdev_obsolete_sm_object(vd), !=, 0);
ASSERT0(vdev_obsolete_sm_object(vd, &obsolete_sm_object));

spa_feature_incr(spa, SPA_FEATURE_OBSOLETE_COUNTS, tx);
VERIFY0(space_map_open(&vd->vdev_obsolete_sm,
Expand Down Expand Up @@ -863,19 +869,19 @@ spa_start_indirect_condensing_thread(spa_t *spa)
* exist yet.
*/
int
vdev_obsolete_sm_object(vdev_t *vd)
vdev_obsolete_sm_object(vdev_t *vd, uint64_t *sm_obj)
{
ASSERT0(spa_config_held(vd->vdev_spa, SCL_ALL, RW_WRITER));
if (vd->vdev_top_zap == 0) {
return (0);
}

uint64_t sm_obj = 0;
ASSERTV(int err = )
zap_lookup(vd->vdev_spa->spa_meta_objset, vd->vdev_top_zap,
VDEV_TOP_ZAP_INDIRECT_OBSOLETE_SM, sizeof (sm_obj), 1, &sm_obj);

ASSERT(err == 0 || err == ENOENT);
int error = zap_lookup(vd->vdev_spa->spa_meta_objset, vd->vdev_top_zap,
VDEV_TOP_ZAP_INDIRECT_OBSOLETE_SM, sizeof (uint64_t), 1, sm_obj);
if (error == ENOENT) {
*sm_obj = 0;
error = 0;
}

return (sm_obj);
}
Expand Down
4 changes: 3 additions & 1 deletion module/zfs/vdev_removal.c
Original file line number Diff line number Diff line change
Expand Up @@ -1556,7 +1556,9 @@ spa_vdev_remove_cancel_sync(void *arg, dmu_tx_t *tx)
VDEV_TOP_ZAP_OBSOLETE_COUNTS_ARE_PRECISE, tx));
}

if (vdev_obsolete_sm_object(vd) != 0) {
uint64_t obsolete_sm_object;
VERIFY0(vdev_obsolete_sm_object(vd, &obsolete_sm_object));
if (obsolete_sm_object != 0) {
ASSERT(vd->vdev_obsolete_sm != NULL);
ASSERT3U(vdev_obsolete_sm_object(vd), ==,
space_map_object(vd->vdev_obsolete_sm));
Expand Down

0 comments on commit 0a10bb0

Please sign in to comment.