Skip to content

Commit

Permalink
Add ddt_object_count() error handling
Browse files Browse the repository at this point in the history
The interface for the ddt_zap_count() function assumes it can
never fail.  However, internally ddt_zap_count() is implemented
with zap_count() which can potentially fail.  Now because there
was no way to return the error to the caller a VERIFY was used
to ensure this case never happens.

Unfortunately, it has been observed that pools can be damaged in
such a way that zap_count() fails.  The result is that the pool can
not be imported without hitting the VERIFY and crashing the system.

This patch reworks ddt_object_count() so the error can be safely
caught and returned to the caller.  This allows a pool which has
be damaged in this way to be safely rewound for import.

Signed-off-by: Brian Behlendorf <[email protected]>
Closes openzfs#910
  • Loading branch information
behlendorf committed Oct 29, 2012
1 parent 178e73b commit e8fd45a
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 19 deletions.
4 changes: 3 additions & 1 deletion cmd/zdb/zdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -698,7 +698,9 @@ dump_ddt(ddt_t *ddt, enum ddt_type type, enum ddt_class class)
return;
ASSERT(error == 0);

if ((count = ddt_object_count(ddt, type, class)) == 0)
error = ddt_object_count(ddt, type, class, &count);
ASSERT(error == 0);
if (count == 0)
return;

dspace = doi.doi_physical_blocks_512 << 9;
Expand Down
6 changes: 3 additions & 3 deletions include/sys/ddt.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ typedef struct ddt_ops {
dmu_tx_t *tx);
int (*ddt_op_walk)(objset_t *os, uint64_t object, ddt_entry_t *dde,
uint64_t *walk);
uint64_t (*ddt_op_count)(objset_t *os, uint64_t object);
int (*ddt_op_count)(objset_t *os, uint64_t object, uint64_t *count);
} ddt_ops_t;

#define DDT_NAMELEN 80
Expand All @@ -172,8 +172,8 @@ extern void ddt_object_name(ddt_t *ddt, enum ddt_type type,
enum ddt_class class, char *name);
extern int ddt_object_walk(ddt_t *ddt, enum ddt_type type,
enum ddt_class class, uint64_t *walk, ddt_entry_t *dde);
extern uint64_t ddt_object_count(ddt_t *ddt, enum ddt_type type,
enum ddt_class class);
extern int ddt_object_count(ddt_t *ddt, enum ddt_type type,
enum ddt_class class, uint64_t *count);
extern int ddt_object_info(ddt_t *ddt, enum ddt_type type,
enum ddt_class class, dmu_object_info_t *);
extern boolean_t ddt_object_exists(ddt_t *ddt, enum ddt_type type,
Expand Down
27 changes: 19 additions & 8 deletions module/zfs/ddt.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,14 @@ ddt_object_destroy(ddt_t *ddt, enum ddt_type type, enum ddt_class class,
spa_t *spa = ddt->ddt_spa;
objset_t *os = ddt->ddt_os;
uint64_t *objectp = &ddt->ddt_object[type][class];
uint64_t count;
char name[DDT_NAMELEN];

ddt_object_name(ddt, type, class, name);

ASSERT(*objectp != 0);
ASSERT(ddt_object_count(ddt, type, class) == 0);
ASSERT(ddt_histogram_empty(&ddt->ddt_histogram[type][class]));
VERIFY(ddt_object_count(ddt, type, class, &count) == 0 && count == 0);
VERIFY(zap_remove(os, DMU_POOL_DIRECTORY_OBJECT, name, tx) == 0);
VERIFY(zap_remove(os, spa->spa_ddt_stat_object, name, tx) == 0);
VERIFY(ddt_ops[type]->ddt_op_destroy(os, *objectp, tx) == 0);
Expand All @@ -102,6 +103,7 @@ ddt_object_load(ddt_t *ddt, enum ddt_type type, enum ddt_class class)
{
ddt_object_t *ddo = &ddt->ddt_object_stats[type][class];
dmu_object_info_t doi;
uint64_t count;
char name[DDT_NAMELEN];
int error;

Expand All @@ -124,7 +126,11 @@ ddt_object_load(ddt_t *ddt, enum ddt_type type, enum ddt_class class)
if (error)
return (error);

ddo->ddo_count = ddt_object_count(ddt, type, class);
error = ddt_object_count(ddt, type, class, &count);
if (error)
return (error);

ddo->ddo_count = count;
ddo->ddo_dspace = doi.doi_physical_blocks_512 << 9;
ddo->ddo_mspace = doi.doi_fill_count * doi.doi_data_block_size;

Expand All @@ -138,6 +144,7 @@ ddt_object_sync(ddt_t *ddt, enum ddt_type type, enum ddt_class class,
{
ddt_object_t *ddo = &ddt->ddt_object_stats[type][class];
dmu_object_info_t doi;
uint64_t count;
char name[DDT_NAMELEN];

ddt_object_name(ddt, type, class, name);
Expand All @@ -150,8 +157,9 @@ ddt_object_sync(ddt_t *ddt, enum ddt_type type, enum ddt_class class,
* Cache DDT statistics; this is the only time they'll change.
*/
VERIFY(ddt_object_info(ddt, type, class, &doi) == 0);
VERIFY(ddt_object_count(ddt, type, class, &count) == 0);

ddo->ddo_count = ddt_object_count(ddt, type, class);
ddo->ddo_count = count;
ddo->ddo_dspace = doi.doi_physical_blocks_512 << 9;
ddo->ddo_mspace = doi.doi_fill_count * doi.doi_data_block_size;
}
Expand Down Expand Up @@ -208,13 +216,14 @@ ddt_object_walk(ddt_t *ddt, enum ddt_type type, enum ddt_class class,
ddt->ddt_object[type][class], dde, walk));
}

uint64_t
ddt_object_count(ddt_t *ddt, enum ddt_type type, enum ddt_class class)
int
ddt_object_count(ddt_t *ddt, enum ddt_type type, enum ddt_class class,
uint64_t *count)
{
ASSERT(ddt_object_exists(ddt, type, class));

return (ddt_ops[type]->ddt_op_count(ddt->ddt_os,
ddt->ddt_object[type][class]));
ddt->ddt_object[type][class], count));
}

int
Expand Down Expand Up @@ -1124,11 +1133,13 @@ ddt_sync_table(ddt_t *ddt, dmu_tx_t *tx, uint64_t txg)
}

for (type = 0; type < DDT_TYPES; type++) {
uint64_t count = 0;
uint64_t add, count = 0;
for (class = 0; class < DDT_CLASSES; class++) {
if (ddt_object_exists(ddt, type, class)) {
ddt_object_sync(ddt, type, class, tx);
count += ddt_object_count(ddt, type, class);
VERIFY(ddt_object_count(ddt, type, class,
&add) == 0);
count += add;
}
}
for (class = 0; class < DDT_CLASSES; class++) {
Expand Down
10 changes: 3 additions & 7 deletions module/zfs/ddt_zap.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,14 +138,10 @@ ddt_zap_walk(objset_t *os, uint64_t object, ddt_entry_t *dde, uint64_t *walk)
return (error);
}

static uint64_t
ddt_zap_count(objset_t *os, uint64_t object)
static int
ddt_zap_count(objset_t *os, uint64_t object, uint64_t *count)
{
uint64_t count = 0;

VERIFY(zap_count(os, object, &count) == 0);

return (count);
return zap_count(os, object, count);
}

const ddt_ops_t ddt_zap_ops = {
Expand Down

0 comments on commit e8fd45a

Please sign in to comment.