Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 58 additions & 4 deletions cmd/zinject/translate.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,24 @@ compress_slashes(const char *src, char *dest)
*dest = '\0';
}

static boolean_t
path_is_zvol(const char *inpath)
{
char buf[MAXPATHLEN];

/* Resolve symlinks to /dev/zd* device */
if (realpath(inpath, buf) != NULL)
if (strncmp(buf, "/dev/zd", 7) == 0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (strncmp(buf, "/dev/zd", 7) == 0)
if (strncmp(buf, "/dev/" ZVOL_DEV_NAME, 7) == 0)

return (B_TRUE);

return (B_FALSE);
}

/*
* Given a full path to a file, translate into a dataset name and a relative
* path within the dataset. 'dataset' must be at least MAXNAMELEN characters,
* and 'relpath' must be at least MAXPATHLEN characters. We also pass a stat64
* buffer, which we need later to get the object ID.
* Given a full path to a file or zvol device, translate into a dataset name and
* a relative path within the dataset. 'dataset' must be at least MAXNAMELEN
* characters, and 'relpath' must be at least MAXPATHLEN characters. We also
* pass a stat64 buffer, which we need later to get the object ID.
*/
static int
parse_pathname(const char *inpath, char *dataset, char *relpath,
Expand All @@ -98,6 +111,47 @@ parse_pathname(const char *inpath, char *dataset, char *relpath,
return (-1);
}

/* special case: inject errors into zvol */
if (path_is_zvol(inpath)) {
int fd;
char *slash;
int rc;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: missing newline after the declarations.

if ((fd = open(inpath, O_RDONLY|O_CLOEXEC)) == -1 ||
fstat64(fd, statbuf) != 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If fstat64() fails the file won't be closed. Let's simply split this in to two conditional blocks and add the close.

return (-1);
}

/*
* HACK: the zvol's inode will not contain its object number.
* However, it has long been the case that the zvol data is
* object number 1:
*
* Object lvl iblk dblk dsize lsize %full type
* 0 6 128K 16K 11K 16K 6.25 DMU dnode
* 1 2 128K 16K 20.1M 20M 100.00 zvol object
* 2 1 128K 512 0 512 100.00 zvol prop
*
* So we hardcode that in the statbuf inode field as workaround.
*/
statbuf->st_ino = 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
statbuf->st_ino = 1;
statbuf->st_ino = ZVOL_OBJ;


rc = ioctl(fd, BLKZNAME, fullpath);
close(fd);
if (rc != 0)
return (-1);

(void) strcpy(dataset, fullpath);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
(void) strcpy(dataset, fullpath);
(void) strlcpy(dataset, fullpath, MAXNAMELEN);


/*
* fullpath contains string like 'tank/zvol'. Strip off the
* 'tank' and 'zvol' parts.
*/
slash = strchr(fullpath, '/');
*slash = '\0';
(void) strcpy(relpath, slash + 1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should check for NULL here to handle a somehow malformed full dataset name. How about this (untested).

                /*
                 * fullpath contains string like 'tank/zvol'.  Strip off the
                 * leading 'tank' pool name component.
                 */
                slash = strchr(fullpath, '/');
                if (slash == NULL) {
                        (void) fprintf(stderr, "invalid volume name: '%s'\n",
                            fullpath);
                        return (-1);
                }

                (void) strlcpy(relpath, slash + 1, MAXPATHLEN);

                return (0);

return (0);
}

if (getextmntent(fullpath, &mp, statbuf) != 0) {
(void) fprintf(stderr, "cannot find mountpoint for '%s'\n",
fullpath);
Expand Down
195 changes: 140 additions & 55 deletions cmd/zpool/zpool_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1050,6 +1050,9 @@ nice_num_str_nvlist(nvlist_t *item, const char *key, uint64_t value,
case ZFS_NICENUM_BYTES:
zfs_nicenum_format(value, buf, 256, ZFS_NICENUM_BYTES);
break;
case ZFS_NICENUM_RAW:
zfs_nicenum_format(value, buf, 256, ZFS_NICENUM_RAW);
break;
case ZFS_NICENUM_TIME:
zfs_nicenum_format(value, buf, 256, ZFS_NICENUM_TIME);
break;
Expand Down Expand Up @@ -2590,7 +2593,7 @@ typedef struct status_cbdata {
int cb_name_flags;
int cb_namewidth;
boolean_t cb_allpools;
boolean_t cb_verbose;
int cb_verbosity;
boolean_t cb_literal;
boolean_t cb_explain;
boolean_t cb_first;
Expand Down Expand Up @@ -3322,7 +3325,7 @@ print_class_vdevs(zpool_handle_t *zhp, status_cbdata_t *cb, nvlist_t *nv,
nvlist_t **child;
boolean_t printed = B_FALSE;

assert(zhp != NULL || !cb->cb_verbose);
assert(zhp != NULL || cb->cb_verbosity == 0);

if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
&children) != 0)
Expand Down Expand Up @@ -9516,7 +9519,7 @@ class_vdevs_nvlist(zpool_handle_t *zhp, status_cbdata_t *cb, nvlist_t *nv,
if (!cb->cb_flat_vdevs)
class_obj = fnvlist_alloc();

assert(zhp != NULL || !cb->cb_verbose);
assert(zhp != NULL || cb->cb_verbosity == 0);

if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
&children) != 0)
Expand Down Expand Up @@ -9620,57 +9623,96 @@ spares_nvlist(zpool_handle_t *zhp, status_cbdata_t *cb, nvlist_t *nv,
}
}

/*
* Take a uint64 nvpair named 'name' from nverrlist, nicenum-ify it, and
* put it back in 'nverrlist', possibly as a string, with the same 'name'.
*/
static void
convert_nvlist_uint64_to_nicenum(status_cbdata_t *cb, nvlist_t *parent,
const char *name, enum zfs_nicenum_format format)
{
uint64_t val;
nvpair_t *nvp;

if (nvlist_lookup_nvpair(parent, name, &nvp) != 0)
return; /* nothing by that name, ignore */

val = fnvpair_value_uint64(nvp);
nvlist_remove_nvpair(parent, nvp);
nice_num_str_nvlist(parent, name, val,
cb->cb_literal, cb->cb_json_as_int, format);
}

static void
errors_nvlist(zpool_handle_t *zhp, status_cbdata_t *cb, nvlist_t *item)
{
uint64_t nerr;
nvlist_t *config = zpool_get_config(zhp, NULL);
if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
&nerr) == 0) {
nice_num_str_nvlist(item, ZPOOL_CONFIG_ERRCOUNT, nerr,
cb->cb_literal, cb->cb_json_as_int, ZFS_NICENUM_1024);
if (nerr != 0 && cb->cb_verbose) {
nvlist_t *nverrlist = NULL;
if (zpool_get_errlog(zhp, &nverrlist) == 0) {
int i = 0;
int count = 0;
size_t len = MAXPATHLEN * 2;
nvpair_t *elem = NULL;

for (nvpair_t *pair =
nvlist_next_nvpair(nverrlist, NULL);
pair != NULL;
pair = nvlist_next_nvpair(nverrlist, pair))
count++;
char **errl = (char **)malloc(
count * sizeof (char *));

while ((elem = nvlist_next_nvpair(nverrlist,
elem)) != NULL) {
nvlist_t *nv;
uint64_t dsobj, obj;

verify(nvpair_value_nvlist(elem,
&nv) == 0);
verify(nvlist_lookup_uint64(nv,
ZPOOL_ERR_DATASET, &dsobj) == 0);
verify(nvlist_lookup_uint64(nv,
ZPOOL_ERR_OBJECT, &obj) == 0);
errl[i] = safe_malloc(len);
zpool_obj_to_path(zhp, dsobj, obj,
errl[i++], len);
}
nvlist_free(nverrlist);
fnvlist_add_string_array(item, "errlist",
(const char **)errl, count);
for (int i = 0; i < count; ++i)
free(errl[i]);
free(errl);
} else
fnvlist_add_string(item, "errlist",
strerror(errno));
int verbosity = cb->cb_verbosity;
nvlist_t *nverrlist = NULL, *json;
nvpair_t *elem;
char *pathname;
size_t len = MAXPATHLEN * 2;
nvlist_t **ranges;
uint_t count;

if (zpool_get_errlog(zhp, &nverrlist) != 0)
return;

pathname = safe_malloc(len);
json = fnvlist_alloc();

elem = NULL;
while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) {
nvlist_t *nv;
uint64_t dsobj, obj;

verify(nvpair_value_nvlist(elem, &nv) == 0);

dsobj = fnvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET);
obj = fnvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT);

zpool_obj_to_path(zhp, dsobj, obj, pathname, len);

/*
* Each JSON entry is a different file/zvol. If user has
* verbosity = 1, then just make a simple object containing
* the name.
*/
if (verbosity <= 1) {
nvlist_t *nameonly;
nameonly = fnvlist_alloc();
fnvlist_add_string(nameonly, ZPOOL_ERR_NAME, pathname);
fnvlist_add_nvlist(json, pathname, nameonly);
nvlist_free(nameonly);
continue;
}

fnvlist_add_string(nv, ZPOOL_ERR_NAME, pathname);

/* nicenum-ify our nvlist */
convert_nvlist_uint64_to_nicenum(cb, nv, ZPOOL_ERR_OBJECT,
ZFS_NICENUM_RAW);
convert_nvlist_uint64_to_nicenum(cb, nv, ZPOOL_ERR_DATASET,
ZFS_NICENUM_RAW);
convert_nvlist_uint64_to_nicenum(cb, nv, ZPOOL_ERR_BLOCK_SIZE,
ZFS_NICENUM_1024);

if (nvlist_lookup_nvlist_array(nv, ZPOOL_ERR_RANGES, &ranges,
&count) == 0) {
for (uint_t i = 0; i < count; i++) {
convert_nvlist_uint64_to_nicenum(cb, ranges[i],
ZPOOL_ERR_START_BYTE, ZFS_NICENUM_1024);
convert_nvlist_uint64_to_nicenum(cb, ranges[i],
ZPOOL_ERR_END_BYTE, ZFS_NICENUM_1024);
}
}

fnvlist_add_nvlist(json, pathname, nv);
}

/* Place our error list in a top level "errors" JSON object. */
fnvlist_add_nvlist(item, ZPOOL_ERR_JSON, json);
free(pathname);
nvlist_free(nverrlist);
}

static void
Expand Down Expand Up @@ -10341,13 +10383,15 @@ print_checkpoint_status(pool_checkpoint_stat_t *pcs)
space_buf);
}


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: stray extra newline

static void
print_error_log(zpool_handle_t *zhp)
print_error_log(zpool_handle_t *zhp, int verbosity, boolean_t literal)
{
nvlist_t *nverrlist = NULL;
nvpair_t *elem;
char *pathname;
char *pathname, *last_pathname = NULL;
size_t len = MAXPATHLEN * 2;
boolean_t started = B_FALSE;

if (zpool_get_errlog(zhp, &nverrlist) != 0)
return;
Expand All @@ -10367,9 +10411,49 @@ print_error_log(zpool_handle_t *zhp)
verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT,
&obj) == 0);
zpool_obj_to_path(zhp, dsobj, obj, pathname, len);
(void) printf("%7s %s\n", "", pathname);
if (last_pathname == NULL ||
0 != strncmp(pathname, last_pathname, len)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
0 != strncmp(pathname, last_pathname, len)) {
strncmp(pathname, last_pathname, len) != 0) {

Purely for consistency we've tried to avoid the 0 == and 0 != style.

last_pathname = strdup(pathname);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be leaked when the pathname changes.

if (started)
(void) printf("\n");
else
started = B_TRUE;
(void) printf("%7s %s ", "", pathname);
} else if (verbosity > 1) {
(void) printf(",");
}
if (verbosity > 1) {
nvlist_t **arr;
uint_t count;
if (nvlist_lookup_nvlist_array(nv, ZPOOL_ERR_RANGES,
&arr, &count) != 0) {
printf("(no ranges)");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
printf("(no ranges)");
(void) printf("(no ranges)");

continue;
}

for (uint_t i = 0; i < count; i++) {
uint64_t start;
uint64_t end;
start = fnvlist_lookup_uint64(arr[i],
ZPOOL_ERR_START_BYTE);
end = fnvlist_lookup_uint64(arr[i],
ZPOOL_ERR_END_BYTE);
if (literal) {
(void) printf("%lu-%lu", start, end);
} else {
char s1[32], s2[32];
zfs_nicenum(start, s1, sizeof (s1));
zfs_nicenum(end, s2, sizeof (s2));
(void) printf("%s-%s", s1, s2);
}
if (i != count - 1)
printf(",");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
printf(",");
(void) printf(",");

}
}
}
(void) printf("\n");
free(pathname);
free(last_pathname);
nvlist_free(nverrlist);
}

Expand Down Expand Up @@ -11065,14 +11149,15 @@ status_callback(zpool_handle_t *zhp, void *data)
if (nerr == 0) {
(void) printf(gettext(
"errors: No known data errors\n"));
} else if (!cbp->cb_verbose) {
} else if (0 == cbp->cb_verbosity) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
} else if (0 == cbp->cb_verbosity) {
} else if (cbp->cb_verbosity == 0) {

color_start(ANSI_RED);
(void) printf(gettext("errors: %llu data "
"errors, use '-v' for a list\n"),
(u_longlong_t)nerr);
color_end();
} else {
print_error_log(zhp);
print_error_log(zhp, cbp->cb_verbosity,
cbp->cb_literal);
}
}

Expand Down Expand Up @@ -11199,7 +11284,7 @@ zpool_do_status(int argc, char **argv)
get_timestamp_arg(*optarg);
break;
case 'v':
cb.cb_verbose = B_TRUE;
cb.cb_verbosity++;
break;
case 'j':
cb.cb_json = B_TRUE;
Expand Down
13 changes: 0 additions & 13 deletions cmd/zpool/zpool_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,19 +115,6 @@ array64_max(uint64_t array[], unsigned int len)
return (max);
}

/*
* Find highest one bit set.
* Returns bit number + 1 of highest bit that is set, otherwise returns 0.
*/
int
highbit64(uint64_t i)
{
if (i == 0)
return (0);

return (NBBY * sizeof (uint64_t) - __builtin_clzll(i));
}

/*
* Find lowest one bit set.
* Returns bit number + 1 of lowest bit that is set, otherwise returns 0.
Expand Down
1 change: 0 additions & 1 deletion cmd/zpool/zpool_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ void *safe_realloc(void *, size_t);
void zpool_no_memory(void);
uint_t num_logs(nvlist_t *nv);
uint64_t array64_max(uint64_t array[], unsigned int len);
int highbit64(uint64_t i);
int lowbit64(uint64_t i);

/*
Expand Down
Loading
Loading