mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-22 02:27:36 +03:00
Update core ZFS code from build 121 to build 141.
This commit is contained in:
@@ -19,15 +19,13 @@
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
|
||||
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _LIBNVPAIR_H
|
||||
#define _LIBNVPAIR_H
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include <sys/nvpair.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
@@ -40,6 +38,7 @@ extern "C" {
|
||||
void nvlist_print(FILE *, nvlist_t *);
|
||||
int nvpair_value_match(nvpair_t *, int, char *, char **);
|
||||
int nvpair_value_match_regex(nvpair_t *, int, char *, regex_t *, char **);
|
||||
void dump_nvlist(nvlist_t *, int);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
+152
-3
@@ -19,14 +19,13 @@
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
|
||||
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <strings.h>
|
||||
#include <libintl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/inttypes.h>
|
||||
#include "libnvpair.h"
|
||||
@@ -272,6 +271,156 @@ nvlist_print(FILE *fp, nvlist_t *nvl)
|
||||
nvlist_print_with_indent(fp, nvl, 0);
|
||||
}
|
||||
|
||||
|
||||
#define NVP(elem, type, vtype, ptype, format) { \
|
||||
vtype value; \
|
||||
\
|
||||
(void) nvpair_value_##type(elem, &value); \
|
||||
(void) printf("%*s%s: " format "\n", indent, "", \
|
||||
nvpair_name(elem), (ptype)value); \
|
||||
}
|
||||
|
||||
#define NVPA(elem, type, vtype, ptype, format) { \
|
||||
uint_t i, count; \
|
||||
vtype *value; \
|
||||
\
|
||||
(void) nvpair_value_##type(elem, &value, &count); \
|
||||
for (i = 0; i < count; i++) { \
|
||||
(void) printf("%*s%s[%d]: " format "\n", indent, "", \
|
||||
nvpair_name(elem), i, (ptype)value[i]); \
|
||||
} \
|
||||
}
|
||||
|
||||
/*
|
||||
* Similar to nvlist_print() but handles arrays slightly differently.
|
||||
*/
|
||||
void
|
||||
dump_nvlist(nvlist_t *list, int indent)
|
||||
{
|
||||
nvpair_t *elem = NULL;
|
||||
boolean_t bool_value;
|
||||
nvlist_t *nvlist_value;
|
||||
nvlist_t **nvlist_array_value;
|
||||
uint_t i, count;
|
||||
|
||||
if (list == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
while ((elem = nvlist_next_nvpair(list, elem)) != NULL) {
|
||||
switch (nvpair_type(elem)) {
|
||||
case DATA_TYPE_BOOLEAN_VALUE:
|
||||
(void) nvpair_value_boolean_value(elem, &bool_value);
|
||||
(void) printf("%*s%s: %s\n", indent, "",
|
||||
nvpair_name(elem), bool_value ? "true" : "false");
|
||||
break;
|
||||
|
||||
case DATA_TYPE_BYTE:
|
||||
NVP(elem, byte, uchar_t, int, "%u");
|
||||
break;
|
||||
|
||||
case DATA_TYPE_INT8:
|
||||
NVP(elem, int8, int8_t, int, "%d");
|
||||
break;
|
||||
|
||||
case DATA_TYPE_UINT8:
|
||||
NVP(elem, uint8, uint8_t, int, "%u");
|
||||
break;
|
||||
|
||||
case DATA_TYPE_INT16:
|
||||
NVP(elem, int16, int16_t, int, "%d");
|
||||
break;
|
||||
|
||||
case DATA_TYPE_UINT16:
|
||||
NVP(elem, uint16, uint16_t, int, "%u");
|
||||
break;
|
||||
|
||||
case DATA_TYPE_INT32:
|
||||
NVP(elem, int32, int32_t, long, "%ld");
|
||||
break;
|
||||
|
||||
case DATA_TYPE_UINT32:
|
||||
NVP(elem, uint32, uint32_t, ulong_t, "%lu");
|
||||
break;
|
||||
|
||||
case DATA_TYPE_INT64:
|
||||
NVP(elem, int64, int64_t, longlong_t, "%lld");
|
||||
break;
|
||||
|
||||
case DATA_TYPE_UINT64:
|
||||
NVP(elem, uint64, uint64_t, u_longlong_t, "%llu");
|
||||
break;
|
||||
|
||||
case DATA_TYPE_STRING:
|
||||
NVP(elem, string, char *, char *, "'%s'");
|
||||
break;
|
||||
|
||||
case DATA_TYPE_BYTE_ARRAY:
|
||||
NVPA(elem, byte_array, uchar_t, int, "%u");
|
||||
break;
|
||||
|
||||
case DATA_TYPE_INT8_ARRAY:
|
||||
NVPA(elem, int8_array, int8_t, int, "%d");
|
||||
break;
|
||||
|
||||
case DATA_TYPE_UINT8_ARRAY:
|
||||
NVPA(elem, uint8_array, uint8_t, int, "%u");
|
||||
break;
|
||||
|
||||
case DATA_TYPE_INT16_ARRAY:
|
||||
NVPA(elem, int16_array, int16_t, int, "%d");
|
||||
break;
|
||||
|
||||
case DATA_TYPE_UINT16_ARRAY:
|
||||
NVPA(elem, uint16_array, uint16_t, int, "%u");
|
||||
break;
|
||||
|
||||
case DATA_TYPE_INT32_ARRAY:
|
||||
NVPA(elem, int32_array, int32_t, long, "%ld");
|
||||
break;
|
||||
|
||||
case DATA_TYPE_UINT32_ARRAY:
|
||||
NVPA(elem, uint32_array, uint32_t, ulong_t, "%lu");
|
||||
break;
|
||||
|
||||
case DATA_TYPE_INT64_ARRAY:
|
||||
NVPA(elem, int64_array, int64_t, longlong_t, "%lld");
|
||||
break;
|
||||
|
||||
case DATA_TYPE_UINT64_ARRAY:
|
||||
NVPA(elem, uint64_array, uint64_t, u_longlong_t,
|
||||
"%llu");
|
||||
break;
|
||||
|
||||
case DATA_TYPE_STRING_ARRAY:
|
||||
NVPA(elem, string_array, char *, char *, "'%s'");
|
||||
break;
|
||||
|
||||
case DATA_TYPE_NVLIST:
|
||||
(void) nvpair_value_nvlist(elem, &nvlist_value);
|
||||
(void) printf("%*s%s:\n", indent, "",
|
||||
nvpair_name(elem));
|
||||
dump_nvlist(nvlist_value, indent + 4);
|
||||
break;
|
||||
|
||||
case DATA_TYPE_NVLIST_ARRAY:
|
||||
(void) nvpair_value_nvlist_array(elem,
|
||||
&nvlist_array_value, &count);
|
||||
for (i = 0; i < count; i++) {
|
||||
(void) printf("%*s%s[%u]:\n", indent, "",
|
||||
nvpair_name(elem), i);
|
||||
dump_nvlist(nvlist_array_value[i], indent + 4);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
(void) printf(dgettext(TEXT_DOMAIN, "bad config type "
|
||||
"%d for %s\n"), nvpair_type(elem),
|
||||
nvpair_name(elem));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine if string 'value' matches 'nvp' value. The 'value' string is
|
||||
* converted, depending on the type of 'nvp', prior to match. For numeric
|
||||
|
||||
+121
-41
@@ -20,8 +20,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _LIBZFS_H
|
||||
@@ -66,7 +65,6 @@ enum {
|
||||
EZFS_BADSTREAM, /* bad backup stream */
|
||||
EZFS_DSREADONLY, /* dataset is readonly */
|
||||
EZFS_VOLTOOBIG, /* volume is too large for 32-bit system */
|
||||
EZFS_VOLHASDATA, /* volume already contains data */
|
||||
EZFS_INVALIDNAME, /* invalid dataset name */
|
||||
EZFS_BADRESTORE, /* unable to restore to destination */
|
||||
EZFS_BADBACKUP, /* backup failed */
|
||||
@@ -85,17 +83,15 @@ enum {
|
||||
EZFS_UMOUNTFAILED, /* failed to unmount dataset */
|
||||
EZFS_UNSHARENFSFAILED, /* unshare(1M) failed */
|
||||
EZFS_SHARENFSFAILED, /* share(1M) failed */
|
||||
EZFS_DEVLINKS, /* failed to create zvol links */
|
||||
EZFS_PERM, /* permission denied */
|
||||
EZFS_NOSPC, /* out of space */
|
||||
EZFS_FAULT, /* bad address */
|
||||
EZFS_IO, /* I/O error */
|
||||
EZFS_INTR, /* signal received */
|
||||
EZFS_ISSPARE, /* device is a hot spare */
|
||||
EZFS_INVALCONFIG, /* invalid vdev configuration */
|
||||
EZFS_RECURSIVE, /* recursive dependency */
|
||||
EZFS_NOHISTORY, /* no history object */
|
||||
EZFS_UNSHAREISCSIFAILED, /* iscsitgtd failed request to unshare */
|
||||
EZFS_SHAREISCSIFAILED, /* iscsitgtd failed request to share */
|
||||
EZFS_POOLPROPS, /* couldn't retrieve pool props */
|
||||
EZFS_POOL_NOTSUP, /* ops not supported for this type of pool */
|
||||
EZFS_POOL_INVALARG, /* invalid argument for this pool operation */
|
||||
@@ -103,7 +99,6 @@ enum {
|
||||
EZFS_OPENFAILED, /* open of device failed */
|
||||
EZFS_NOCAP, /* couldn't get capacity */
|
||||
EZFS_LABELFAILED, /* write of label failed */
|
||||
EZFS_ISCSISVCUNAVAIL, /* iscsi service unavailable */
|
||||
EZFS_BADWHO, /* invalid permission who */
|
||||
EZFS_BADPERM, /* invalid permission */
|
||||
EZFS_BADPERMSET, /* invalid permission set name */
|
||||
@@ -119,6 +114,12 @@ enum {
|
||||
EZFS_UNPLAYED_LOGS, /* log device has unplayed logs */
|
||||
EZFS_REFTAG_RELE, /* snapshot release: tag not found */
|
||||
EZFS_REFTAG_HOLD, /* snapshot hold: tag already exists */
|
||||
EZFS_TAGTOOLONG, /* snapshot hold/rele: tag too long */
|
||||
EZFS_PIPEFAILED, /* pipe create failed */
|
||||
EZFS_THREADCREATEFAILED, /* thread create failed */
|
||||
EZFS_POSTSPLIT_ONLINE, /* onlining a disk after splitting it */
|
||||
EZFS_SCRUBBING, /* currently scrubbing */
|
||||
EZFS_NO_SCRUB, /* no active scrub */
|
||||
EZFS_UNKNOWN
|
||||
};
|
||||
|
||||
@@ -213,11 +214,19 @@ extern int zpool_create(libzfs_handle_t *, const char *, nvlist_t *,
|
||||
extern int zpool_destroy(zpool_handle_t *);
|
||||
extern int zpool_add(zpool_handle_t *, nvlist_t *);
|
||||
|
||||
typedef struct splitflags {
|
||||
/* do not split, but return the config that would be split off */
|
||||
int dryrun : 1;
|
||||
|
||||
/* after splitting, import the pool */
|
||||
int import : 1;
|
||||
} splitflags_t;
|
||||
|
||||
/*
|
||||
* Functions to manipulate pool and vdev state
|
||||
*/
|
||||
extern int zpool_scrub(zpool_handle_t *, pool_scrub_type_t);
|
||||
extern int zpool_clear(zpool_handle_t *, const char *);
|
||||
extern int zpool_scan(zpool_handle_t *, pool_scan_func_t);
|
||||
extern int zpool_clear(zpool_handle_t *, const char *, nvlist_t *);
|
||||
|
||||
extern int zpool_vdev_online(zpool_handle_t *, const char *, int,
|
||||
vdev_state_t *);
|
||||
@@ -226,9 +235,11 @@ extern int zpool_vdev_attach(zpool_handle_t *, const char *,
|
||||
const char *, nvlist_t *, int);
|
||||
extern int zpool_vdev_detach(zpool_handle_t *, const char *);
|
||||
extern int zpool_vdev_remove(zpool_handle_t *, const char *);
|
||||
extern int zpool_vdev_split(zpool_handle_t *, char *, nvlist_t **, nvlist_t *,
|
||||
splitflags_t);
|
||||
|
||||
extern int zpool_vdev_fault(zpool_handle_t *, uint64_t);
|
||||
extern int zpool_vdev_degrade(zpool_handle_t *, uint64_t);
|
||||
extern int zpool_vdev_fault(zpool_handle_t *, uint64_t, vdev_aux_t);
|
||||
extern int zpool_vdev_degrade(zpool_handle_t *, uint64_t, vdev_aux_t);
|
||||
extern int zpool_vdev_clear(zpool_handle_t *, uint64_t);
|
||||
|
||||
extern nvlist_t *zpool_find_vdev(zpool_handle_t *, const char *, boolean_t *,
|
||||
@@ -298,6 +309,7 @@ typedef enum {
|
||||
|
||||
extern zpool_status_t zpool_get_status(zpool_handle_t *, char **);
|
||||
extern zpool_status_t zpool_import_status(nvlist_t *, char **);
|
||||
extern void zpool_dump_ddt(const ddt_stat_t *dds, const ddt_histogram_t *ddh);
|
||||
|
||||
/*
|
||||
* Statistics and configuration functions.
|
||||
@@ -319,23 +331,38 @@ extern int zpool_import_props(libzfs_handle_t *, nvlist_t *, const char *,
|
||||
/*
|
||||
* Search for pools to import
|
||||
*/
|
||||
|
||||
typedef struct importargs {
|
||||
char **path; /* a list of paths to search */
|
||||
int paths; /* number of paths to search */
|
||||
char *poolname; /* name of a pool to find */
|
||||
uint64_t guid; /* guid of a pool to find */
|
||||
char *cachefile; /* cachefile to use for import */
|
||||
int can_be_active : 1; /* can the pool be active? */
|
||||
int unique : 1; /* does 'poolname' already exist? */
|
||||
int exists : 1; /* set on return if pool already exists */
|
||||
} importargs_t;
|
||||
|
||||
extern nvlist_t *zpool_search_import(libzfs_handle_t *, importargs_t *);
|
||||
|
||||
/* legacy pool search routines */
|
||||
extern nvlist_t *zpool_find_import(libzfs_handle_t *, int, char **);
|
||||
extern nvlist_t *zpool_find_import_cached(libzfs_handle_t *, const char *,
|
||||
char *, uint64_t);
|
||||
extern nvlist_t *zpool_find_import_byname(libzfs_handle_t *, int, char **,
|
||||
char *);
|
||||
extern nvlist_t *zpool_find_import_byguid(libzfs_handle_t *, int, char **,
|
||||
uint64_t);
|
||||
extern nvlist_t *zpool_find_import_activeok(libzfs_handle_t *, int, char **);
|
||||
|
||||
/*
|
||||
* Miscellaneous pool functions
|
||||
*/
|
||||
struct zfs_cmd;
|
||||
|
||||
extern char *zpool_vdev_name(libzfs_handle_t *, zpool_handle_t *, nvlist_t *);
|
||||
extern const char *zfs_history_event_names[LOG_END];
|
||||
|
||||
extern char *zpool_vdev_name(libzfs_handle_t *, zpool_handle_t *, nvlist_t *,
|
||||
boolean_t verbose);
|
||||
extern int zpool_upgrade(zpool_handle_t *, uint64_t);
|
||||
extern int zpool_get_history(zpool_handle_t *, nvlist_t **);
|
||||
extern int zpool_history_unpack(char *, uint64_t, uint64_t *,
|
||||
nvlist_t ***, uint_t *);
|
||||
extern void zpool_set_history_str(const char *subcommand, int argc,
|
||||
char **argv, char *history_str);
|
||||
extern int zpool_stage_history(libzfs_handle_t *, const char *);
|
||||
@@ -343,6 +370,8 @@ extern void zpool_obj_to_path(zpool_handle_t *, uint64_t, uint64_t, char *,
|
||||
size_t len);
|
||||
extern int zfs_ioctl(libzfs_handle_t *, int, struct zfs_cmd *);
|
||||
extern int zpool_get_physpath(zpool_handle_t *, char *, size_t);
|
||||
extern void zpool_explain_recover(libzfs_handle_t *, const char *, int,
|
||||
nvlist_t *);
|
||||
|
||||
/*
|
||||
* Basic handle manipulations. These functions do not create or destroy the
|
||||
@@ -374,6 +403,8 @@ extern const char *zfs_prop_to_name(zfs_prop_t);
|
||||
extern int zfs_prop_set(zfs_handle_t *, const char *, const char *);
|
||||
extern int zfs_prop_get(zfs_handle_t *, zfs_prop_t, char *, size_t,
|
||||
zprop_source_t *, char *, size_t, boolean_t);
|
||||
extern int zfs_prop_get_recvd(zfs_handle_t *, const char *, char *, size_t,
|
||||
boolean_t);
|
||||
extern int zfs_prop_get_numeric(zfs_handle_t *, zfs_prop_t, uint64_t *,
|
||||
zprop_source_t *, char *, size_t);
|
||||
extern int zfs_prop_get_userquota_int(zfs_handle_t *zhp, const char *propname,
|
||||
@@ -381,10 +412,11 @@ extern int zfs_prop_get_userquota_int(zfs_handle_t *zhp, const char *propname,
|
||||
extern int zfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname,
|
||||
char *propbuf, int proplen, boolean_t literal);
|
||||
extern uint64_t zfs_prop_get_int(zfs_handle_t *, zfs_prop_t);
|
||||
extern int zfs_prop_inherit(zfs_handle_t *, const char *);
|
||||
extern int zfs_prop_inherit(zfs_handle_t *, const char *, boolean_t);
|
||||
extern const char *zfs_prop_values(zfs_prop_t);
|
||||
extern int zfs_prop_is_string(zfs_prop_t prop);
|
||||
extern nvlist_t *zfs_get_user_props(zfs_handle_t *);
|
||||
extern nvlist_t *zfs_get_recvd_props(zfs_handle_t *);
|
||||
|
||||
typedef struct zprop_list {
|
||||
int pl_prop;
|
||||
@@ -392,10 +424,11 @@ typedef struct zprop_list {
|
||||
struct zprop_list *pl_next;
|
||||
boolean_t pl_all;
|
||||
size_t pl_width;
|
||||
size_t pl_recvd_width;
|
||||
boolean_t pl_fixed;
|
||||
} zprop_list_t;
|
||||
|
||||
extern int zfs_expand_proplist(zfs_handle_t *, zprop_list_t **);
|
||||
extern int zfs_expand_proplist(zfs_handle_t *, zprop_list_t **, boolean_t);
|
||||
extern void zfs_prune_proplist(zfs_handle_t *, uint8_t *);
|
||||
|
||||
#define ZFS_MOUNTPOINT_NONE "none"
|
||||
@@ -419,13 +452,24 @@ extern int zprop_get_list(libzfs_handle_t *, char *, zprop_list_t **,
|
||||
zfs_type_t);
|
||||
extern void zprop_free_list(zprop_list_t *);
|
||||
|
||||
#define ZFS_GET_NCOLS 5
|
||||
|
||||
typedef enum {
|
||||
GET_COL_NONE,
|
||||
GET_COL_NAME,
|
||||
GET_COL_PROPERTY,
|
||||
GET_COL_VALUE,
|
||||
GET_COL_RECVD,
|
||||
GET_COL_SOURCE
|
||||
} zfs_get_column_t;
|
||||
|
||||
/*
|
||||
* Functions for printing zfs or zpool properties
|
||||
*/
|
||||
typedef struct zprop_get_cbdata {
|
||||
int cb_sources;
|
||||
int cb_columns[4];
|
||||
int cb_colwidths[5];
|
||||
zfs_get_column_t cb_columns[ZFS_GET_NCOLS];
|
||||
int cb_colwidths[ZFS_GET_NCOLS + 1];
|
||||
boolean_t cb_scripted;
|
||||
boolean_t cb_literal;
|
||||
boolean_t cb_first;
|
||||
@@ -434,12 +478,8 @@ typedef struct zprop_get_cbdata {
|
||||
} zprop_get_cbdata_t;
|
||||
|
||||
void zprop_print_one_property(const char *, zprop_get_cbdata_t *,
|
||||
const char *, const char *, zprop_source_t, const char *);
|
||||
|
||||
#define GET_COL_NAME 1
|
||||
#define GET_COL_PROPERTY 2
|
||||
#define GET_COL_VALUE 3
|
||||
#define GET_COL_SOURCE 4
|
||||
const char *, const char *, zprop_source_t, const char *,
|
||||
const char *);
|
||||
|
||||
/*
|
||||
* Iterator functions.
|
||||
@@ -450,6 +490,7 @@ extern int zfs_iter_children(zfs_handle_t *, zfs_iter_f, void *);
|
||||
extern int zfs_iter_dependents(zfs_handle_t *, boolean_t, zfs_iter_f, void *);
|
||||
extern int zfs_iter_filesystems(zfs_handle_t *, zfs_iter_f, void *);
|
||||
extern int zfs_iter_snapshots(zfs_handle_t *, zfs_iter_f, void *);
|
||||
extern int zfs_iter_snapshots_sorted(zfs_handle_t *, zfs_iter_f, void *);
|
||||
|
||||
/*
|
||||
* Functions to create and destroy datasets.
|
||||
@@ -463,11 +504,42 @@ extern int zfs_clone(zfs_handle_t *, const char *, nvlist_t *);
|
||||
extern int zfs_snapshot(libzfs_handle_t *, const char *, boolean_t, nvlist_t *);
|
||||
extern int zfs_rollback(zfs_handle_t *, zfs_handle_t *, boolean_t);
|
||||
extern int zfs_rename(zfs_handle_t *, const char *, boolean_t);
|
||||
extern int zfs_send(zfs_handle_t *, const char *, const char *,
|
||||
boolean_t, boolean_t, boolean_t, boolean_t, int);
|
||||
|
||||
typedef struct sendflags {
|
||||
/* print informational messages (ie, -v was specified) */
|
||||
int verbose : 1;
|
||||
|
||||
/* recursive send (ie, -R) */
|
||||
int replicate : 1;
|
||||
|
||||
/* for incrementals, do all intermediate snapshots */
|
||||
int doall : 1; /* (ie, -I) */
|
||||
|
||||
/* if dataset is a clone, do incremental from its origin */
|
||||
int fromorigin : 1;
|
||||
|
||||
/* do deduplication */
|
||||
int dedup : 1;
|
||||
|
||||
/* send properties (ie, -p) */
|
||||
int props : 1;
|
||||
} sendflags_t;
|
||||
|
||||
typedef boolean_t (snapfilter_cb_t)(zfs_handle_t *, void *);
|
||||
|
||||
extern int zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
|
||||
sendflags_t flags, int outfd, snapfilter_cb_t filter_func,
|
||||
void *cb_arg, nvlist_t **debugnvp);
|
||||
|
||||
extern int zfs_promote(zfs_handle_t *);
|
||||
extern int zfs_hold(zfs_handle_t *, const char *, const char *, boolean_t);
|
||||
extern int zfs_hold(zfs_handle_t *, const char *, const char *, boolean_t,
|
||||
boolean_t, boolean_t);
|
||||
extern int zfs_hold_range(zfs_handle_t *, const char *, const char *,
|
||||
const char *, boolean_t, boolean_t, snapfilter_cb_t, void *);
|
||||
extern int zfs_release(zfs_handle_t *, const char *, const char *, boolean_t);
|
||||
extern int zfs_release_range(zfs_handle_t *, const char *, const char *,
|
||||
const char *, boolean_t);
|
||||
extern uint64_t zvol_volsize_to_reservation(uint64_t, nvlist_t *);
|
||||
|
||||
typedef int (*zfs_userspace_cb_t)(void *arg, const char *domain,
|
||||
uid_t rid, uint64_t space);
|
||||
@@ -482,6 +554,12 @@ typedef struct recvflags {
|
||||
/* the destination is a prefix, not the exact fs (ie, -d) */
|
||||
int isprefix : 1;
|
||||
|
||||
/*
|
||||
* Only the tail of the sent snapshot path is appended to the
|
||||
* destination to determine the received snapshot name (ie, -e).
|
||||
*/
|
||||
int istail : 1;
|
||||
|
||||
/* do not actually do the recv, just check if it would work (ie, -n) */
|
||||
int dryrun : 1;
|
||||
|
||||
@@ -542,10 +620,6 @@ extern int zfs_unshareall_nfs(zfs_handle_t *);
|
||||
extern int zfs_unshareall_smb(zfs_handle_t *);
|
||||
extern int zfs_unshareall_bypath(zfs_handle_t *, const char *);
|
||||
extern int zfs_unshareall(zfs_handle_t *);
|
||||
extern boolean_t zfs_is_shared_iscsi(zfs_handle_t *);
|
||||
extern int zfs_share_iscsi(zfs_handle_t *);
|
||||
extern int zfs_unshare_iscsi(zfs_handle_t *);
|
||||
extern int zfs_iscsi_perm_check(libzfs_handle_t *, char *, ucred_t *);
|
||||
extern int zfs_deleg_share_nfs(libzfs_handle_t *, char *, char *, char *,
|
||||
void *, void *, int, zfs_share_op_t);
|
||||
|
||||
@@ -571,15 +645,10 @@ extern int zpool_in_use(libzfs_handle_t *, int, pool_state_t *, char **,
|
||||
boolean_t *);
|
||||
|
||||
/*
|
||||
* ftyp special. Read the label from a given device.
|
||||
* Label manipulation.
|
||||
*/
|
||||
extern int zpool_read_label(int, nvlist_t **);
|
||||
|
||||
/*
|
||||
* Create and remove zvol /dev links.
|
||||
*/
|
||||
extern int zpool_create_zvol_links(zpool_handle_t *);
|
||||
extern int zpool_remove_zvol_links(zpool_handle_t *);
|
||||
extern int zpool_clear_label(int);
|
||||
|
||||
/* is this zvol valid for use as a dump device? */
|
||||
extern int zvol_check_dump_config(char *);
|
||||
@@ -600,6 +669,17 @@ int zfs_smb_acl_rename(libzfs_handle_t *, char *, char *, char *, char *);
|
||||
extern int zpool_enable_datasets(zpool_handle_t *, const char *, int);
|
||||
extern int zpool_disable_datasets(zpool_handle_t *, boolean_t);
|
||||
|
||||
/*
|
||||
* Mappings between vdev and FRU.
|
||||
*/
|
||||
extern void libzfs_fru_refresh(libzfs_handle_t *);
|
||||
extern const char *libzfs_fru_lookup(libzfs_handle_t *, const char *);
|
||||
extern const char *libzfs_fru_devpath(libzfs_handle_t *, const char *);
|
||||
extern boolean_t libzfs_fru_compare(libzfs_handle_t *, const char *,
|
||||
const char *);
|
||||
extern boolean_t libzfs_fru_notself(libzfs_handle_t *, const char *);
|
||||
extern int zpool_fru_set(zpool_handle_t *, uint64_t, const char *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
|
||||
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
#include <sys/dmu.h>
|
||||
#include <sys/fs/zfs.h>
|
||||
#include <sys/zfs_ioctl.h>
|
||||
#include <sys/zfs_acl.h>
|
||||
#include <sys/spa.h>
|
||||
#include <sys/nvpair.h>
|
||||
|
||||
@@ -38,6 +37,8 @@
|
||||
#include <libzfs.h>
|
||||
#include <libshare.h>
|
||||
|
||||
#include <fm/libtopo.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -47,6 +48,13 @@ extern "C" {
|
||||
#endif
|
||||
#define VERIFY verify
|
||||
|
||||
typedef struct libzfs_fru {
|
||||
char *zf_device;
|
||||
char *zf_fru;
|
||||
struct libzfs_fru *zf_chain;
|
||||
struct libzfs_fru *zf_next;
|
||||
} libzfs_fru_t;
|
||||
|
||||
struct libzfs_handle {
|
||||
int libzfs_error;
|
||||
int libzfs_fd;
|
||||
@@ -65,7 +73,13 @@ struct libzfs_handle {
|
||||
uint_t libzfs_shareflags;
|
||||
boolean_t libzfs_mnttab_enable;
|
||||
avl_tree_t libzfs_mnttab_cache;
|
||||
int libzfs_pool_iter;
|
||||
topo_hdl_t *libzfs_topo_hdl;
|
||||
libzfs_fru_t **libzfs_fru_hash;
|
||||
libzfs_fru_t *libzfs_fru_list;
|
||||
char libzfs_chassis_id[256];
|
||||
};
|
||||
|
||||
#define ZFSSHARE_MISS 0x01 /* Didn't find entry in cache */
|
||||
|
||||
struct zfs_handle {
|
||||
@@ -77,6 +91,7 @@ struct zfs_handle {
|
||||
dmu_objset_stats_t zfs_dmustats;
|
||||
nvlist_t *zfs_props;
|
||||
nvlist_t *zfs_user_props;
|
||||
nvlist_t *zfs_recvd_props;
|
||||
boolean_t zfs_mntcheck;
|
||||
char *zfs_mntopts;
|
||||
uint8_t *zfs_props_table;
|
||||
@@ -112,7 +127,6 @@ typedef enum {
|
||||
*/
|
||||
typedef enum {
|
||||
SHARED_NOT_SHARED = 0x0,
|
||||
SHARED_ISCSI = 0x1,
|
||||
SHARED_NFS = 0x2,
|
||||
SHARED_SMB = 0x4
|
||||
} zfs_share_type_t;
|
||||
@@ -172,9 +186,6 @@ zfs_handle_t *make_dataset_handle(libzfs_handle_t *, const char *);
|
||||
|
||||
int zpool_open_silent(libzfs_handle_t *, const char *, zpool_handle_t **);
|
||||
|
||||
int zvol_create_link(libzfs_handle_t *, const char *);
|
||||
int zvol_remove_link(libzfs_handle_t *, const char *);
|
||||
int zpool_iter_zvol(zpool_handle_t *, int (*)(const char *, void *), void *);
|
||||
boolean_t zpool_name_valid(libzfs_handle_t *, boolean_t, const char *);
|
||||
|
||||
void namespace_clear(libzfs_handle_t *);
|
||||
@@ -189,6 +200,9 @@ extern int zfs_parse_options(char *, zfs_share_proto_t);
|
||||
|
||||
extern int zfs_unshare_proto(zfs_handle_t *,
|
||||
const char *, zfs_share_proto_t *);
|
||||
|
||||
extern void libzfs_fru_clear(libzfs_handle_t *, boolean_t);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
|
||||
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*
|
||||
* Portions Copyright 2007 Ramprakash Jelari
|
||||
@@ -116,32 +116,7 @@ changelist_prefix(prop_changelist_t *clp)
|
||||
if (getzoneid() == GLOBAL_ZONEID && cn->cn_zoned)
|
||||
continue;
|
||||
|
||||
if (ZFS_IS_VOLUME(cn->cn_handle)) {
|
||||
switch (clp->cl_realprop) {
|
||||
case ZFS_PROP_NAME:
|
||||
/*
|
||||
* If this was a rename, unshare the zvol, and
|
||||
* remove the /dev/zvol links.
|
||||
*/
|
||||
(void) zfs_unshare_iscsi(cn->cn_handle);
|
||||
|
||||
if (zvol_remove_link(cn->cn_handle->zfs_hdl,
|
||||
cn->cn_handle->zfs_name) != 0) {
|
||||
ret = -1;
|
||||
cn->cn_needpost = B_FALSE;
|
||||
(void) zfs_share_iscsi(cn->cn_handle);
|
||||
}
|
||||
break;
|
||||
|
||||
case ZFS_PROP_VOLSIZE:
|
||||
/*
|
||||
* If this was a change to the volume size, we
|
||||
* need to unshare and reshare the volume.
|
||||
*/
|
||||
(void) zfs_unshare_iscsi(cn->cn_handle);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (!ZFS_IS_VOLUME(cn->cn_handle)) {
|
||||
/*
|
||||
* Do the property specific processing.
|
||||
*/
|
||||
@@ -234,32 +209,8 @@ changelist_postfix(prop_changelist_t *clp)
|
||||
|
||||
zfs_refresh_properties(cn->cn_handle);
|
||||
|
||||
if (ZFS_IS_VOLUME(cn->cn_handle)) {
|
||||
/*
|
||||
* If we're doing a rename, recreate the /dev/zvol
|
||||
* links.
|
||||
*/
|
||||
if (clp->cl_realprop == ZFS_PROP_NAME &&
|
||||
zvol_create_link(cn->cn_handle->zfs_hdl,
|
||||
cn->cn_handle->zfs_name) != 0) {
|
||||
errors++;
|
||||
} else if (cn->cn_shared ||
|
||||
clp->cl_prop == ZFS_PROP_SHAREISCSI) {
|
||||
if (zfs_prop_get(cn->cn_handle,
|
||||
ZFS_PROP_SHAREISCSI, shareopts,
|
||||
sizeof (shareopts), NULL, NULL, 0,
|
||||
B_FALSE) == 0 &&
|
||||
strcmp(shareopts, "off") == 0) {
|
||||
errors +=
|
||||
zfs_unshare_iscsi(cn->cn_handle);
|
||||
} else {
|
||||
errors +=
|
||||
zfs_share_iscsi(cn->cn_handle);
|
||||
}
|
||||
}
|
||||
|
||||
if (ZFS_IS_VOLUME(cn->cn_handle))
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remount if previously mounted or mountpoint was legacy,
|
||||
@@ -658,8 +609,7 @@ changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int gather_flags,
|
||||
|
||||
if (clp->cl_prop != ZFS_PROP_MOUNTPOINT &&
|
||||
clp->cl_prop != ZFS_PROP_SHARENFS &&
|
||||
clp->cl_prop != ZFS_PROP_SHARESMB &&
|
||||
clp->cl_prop != ZFS_PROP_SHAREISCSI)
|
||||
clp->cl_prop != ZFS_PROP_SHARESMB)
|
||||
return (clp);
|
||||
|
||||
/*
|
||||
|
||||
@@ -19,12 +19,10 @@
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
/*
|
||||
* The pool configuration repository is stored in /etc/zfs/zpool.cache as a
|
||||
* single packed nvlist. While it would be nice to just read in this
|
||||
@@ -313,21 +311,33 @@ zpool_iter(libzfs_handle_t *hdl, zpool_iter_f func, void *data)
|
||||
zpool_handle_t *zhp;
|
||||
int ret;
|
||||
|
||||
if (namespace_reload(hdl) != 0)
|
||||
/*
|
||||
* If someone makes a recursive call to zpool_iter(), we want to avoid
|
||||
* refreshing the namespace because that will invalidate the parent
|
||||
* context. We allow recursive calls, but simply re-use the same
|
||||
* namespace AVL tree.
|
||||
*/
|
||||
if (!hdl->libzfs_pool_iter && namespace_reload(hdl) != 0)
|
||||
return (-1);
|
||||
|
||||
hdl->libzfs_pool_iter++;
|
||||
for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL;
|
||||
cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) {
|
||||
|
||||
if (zpool_open_silent(hdl, cn->cn_name, &zhp) != 0)
|
||||
if (zpool_open_silent(hdl, cn->cn_name, &zhp) != 0) {
|
||||
hdl->libzfs_pool_iter--;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (zhp == NULL)
|
||||
continue;
|
||||
|
||||
if ((ret = func(zhp, data)) != 0)
|
||||
if ((ret = func(zhp, data)) != 0) {
|
||||
hdl->libzfs_pool_iter--;
|
||||
return (ret);
|
||||
}
|
||||
}
|
||||
hdl->libzfs_pool_iter--;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
+578
-605
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,452 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <libintl.h>
|
||||
#include <link.h>
|
||||
#include <pthread.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <libzfs.h>
|
||||
|
||||
#include <fm/libtopo.h>
|
||||
#include <sys/fm/protocol.h>
|
||||
#include <sys/systeminfo.h>
|
||||
|
||||
#include "libzfs_impl.h"
|
||||
|
||||
/*
|
||||
* This file is responsible for determining the relationship between I/O
|
||||
* devices paths and physical locations. In the world of MPxIO and external
|
||||
* enclosures, the device path is not synonymous with the physical location.
|
||||
* If you remove a drive and insert it into a different slot, it will end up
|
||||
* with the same path under MPxIO. If you recable storage enclosures, the
|
||||
* device paths may change. All of this makes it difficult to implement the
|
||||
* 'autoreplace' property, which is supposed to automatically manage disk
|
||||
* replacement based on physical slot.
|
||||
*
|
||||
* In order to work around these limitations, we have a per-vdev FRU property
|
||||
* that is the libtopo path (minus disk-specific authority information) to the
|
||||
* physical location of the device on the system. This is an optional
|
||||
* property, and is only needed when using the 'autoreplace' property or when
|
||||
* generating FMA faults against vdevs.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Because the FMA packages depend on ZFS, we have to dlopen() libtopo in case
|
||||
* it is not present. We only need this once per library instance, so it is
|
||||
* not part of the libzfs handle.
|
||||
*/
|
||||
static void *_topo_dlhandle;
|
||||
static topo_hdl_t *(*_topo_open)(int, const char *, int *);
|
||||
static void (*_topo_close)(topo_hdl_t *);
|
||||
static char *(*_topo_snap_hold)(topo_hdl_t *, const char *, int *);
|
||||
static void (*_topo_snap_release)(topo_hdl_t *);
|
||||
static topo_walk_t *(*_topo_walk_init)(topo_hdl_t *, const char *,
|
||||
topo_walk_cb_t, void *, int *);
|
||||
static int (*_topo_walk_step)(topo_walk_t *, int);
|
||||
static void (*_topo_walk_fini)(topo_walk_t *);
|
||||
static void (*_topo_hdl_strfree)(topo_hdl_t *, char *);
|
||||
static char *(*_topo_node_name)(tnode_t *);
|
||||
static int (*_topo_prop_get_string)(tnode_t *, const char *, const char *,
|
||||
char **, int *);
|
||||
static int (*_topo_node_fru)(tnode_t *, nvlist_t **, nvlist_t *, int *);
|
||||
static int (*_topo_fmri_nvl2str)(topo_hdl_t *, nvlist_t *, char **, int *);
|
||||
static int (*_topo_fmri_strcmp_noauth)(topo_hdl_t *, const char *,
|
||||
const char *);
|
||||
|
||||
#define ZFS_FRU_HASH_SIZE 257
|
||||
|
||||
static size_t
|
||||
fru_strhash(const char *key)
|
||||
{
|
||||
ulong_t g, h = 0;
|
||||
const char *p;
|
||||
|
||||
for (p = key; *p != '\0'; p++) {
|
||||
h = (h << 4) + *p;
|
||||
|
||||
if ((g = (h & 0xf0000000)) != 0) {
|
||||
h ^= (g >> 24);
|
||||
h ^= g;
|
||||
}
|
||||
}
|
||||
|
||||
return (h % ZFS_FRU_HASH_SIZE);
|
||||
}
|
||||
|
||||
static int
|
||||
libzfs_fru_gather(topo_hdl_t *thp, tnode_t *tn, void *arg)
|
||||
{
|
||||
libzfs_handle_t *hdl = arg;
|
||||
nvlist_t *fru;
|
||||
char *devpath, *frustr;
|
||||
int err;
|
||||
libzfs_fru_t *frup;
|
||||
size_t idx;
|
||||
|
||||
/*
|
||||
* If this is the chassis node, and we don't yet have the system
|
||||
* chassis ID, then fill in this value now.
|
||||
*/
|
||||
if (hdl->libzfs_chassis_id[0] == '\0' &&
|
||||
strcmp(_topo_node_name(tn), "chassis") == 0) {
|
||||
if (_topo_prop_get_string(tn, FM_FMRI_AUTHORITY,
|
||||
FM_FMRI_AUTH_CHASSIS, &devpath, &err) == 0)
|
||||
(void) strlcpy(hdl->libzfs_chassis_id, devpath,
|
||||
sizeof (hdl->libzfs_chassis_id));
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip non-disk nodes.
|
||||
*/
|
||||
if (strcmp(_topo_node_name(tn), "disk") != 0)
|
||||
return (TOPO_WALK_NEXT);
|
||||
|
||||
/*
|
||||
* Get the devfs path and FRU.
|
||||
*/
|
||||
if (_topo_prop_get_string(tn, "io", "devfs-path", &devpath, &err) != 0)
|
||||
return (TOPO_WALK_NEXT);
|
||||
|
||||
if (libzfs_fru_lookup(hdl, devpath) != NULL) {
|
||||
_topo_hdl_strfree(thp, devpath);
|
||||
return (TOPO_WALK_NEXT);
|
||||
}
|
||||
|
||||
if (_topo_node_fru(tn, &fru, NULL, &err) != 0) {
|
||||
_topo_hdl_strfree(thp, devpath);
|
||||
return (TOPO_WALK_NEXT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert the FRU into a string.
|
||||
*/
|
||||
if (_topo_fmri_nvl2str(thp, fru, &frustr, &err) != 0) {
|
||||
nvlist_free(fru);
|
||||
_topo_hdl_strfree(thp, devpath);
|
||||
return (TOPO_WALK_NEXT);
|
||||
}
|
||||
|
||||
nvlist_free(fru);
|
||||
|
||||
/*
|
||||
* Finally, we have a FRU string and device path. Add it to the hash.
|
||||
*/
|
||||
if ((frup = calloc(sizeof (libzfs_fru_t), 1)) == NULL) {
|
||||
_topo_hdl_strfree(thp, devpath);
|
||||
_topo_hdl_strfree(thp, frustr);
|
||||
return (TOPO_WALK_NEXT);
|
||||
}
|
||||
|
||||
if ((frup->zf_device = strdup(devpath)) == NULL ||
|
||||
(frup->zf_fru = strdup(frustr)) == NULL) {
|
||||
free(frup->zf_device);
|
||||
free(frup);
|
||||
_topo_hdl_strfree(thp, devpath);
|
||||
_topo_hdl_strfree(thp, frustr);
|
||||
return (TOPO_WALK_NEXT);
|
||||
}
|
||||
|
||||
_topo_hdl_strfree(thp, devpath);
|
||||
_topo_hdl_strfree(thp, frustr);
|
||||
|
||||
idx = fru_strhash(frup->zf_device);
|
||||
frup->zf_chain = hdl->libzfs_fru_hash[idx];
|
||||
hdl->libzfs_fru_hash[idx] = frup;
|
||||
frup->zf_next = hdl->libzfs_fru_list;
|
||||
hdl->libzfs_fru_list = frup;
|
||||
|
||||
return (TOPO_WALK_NEXT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called during initialization to setup the dynamic libtopo connection.
|
||||
*/
|
||||
#pragma init(libzfs_init_fru)
|
||||
static void
|
||||
libzfs_init_fru(void)
|
||||
{
|
||||
char path[MAXPATHLEN];
|
||||
char isa[257];
|
||||
|
||||
#if defined(_LP64)
|
||||
if (sysinfo(SI_ARCHITECTURE_64, isa, sizeof (isa)) < 0)
|
||||
isa[0] = '\0';
|
||||
#else
|
||||
isa[0] = '\0';
|
||||
#endif
|
||||
(void) snprintf(path, sizeof (path),
|
||||
"/usr/lib/fm/%s/libtopo.so", isa);
|
||||
|
||||
if ((_topo_dlhandle = dlopen(path, RTLD_LAZY)) == NULL)
|
||||
return;
|
||||
|
||||
_topo_open = (topo_hdl_t *(*)())
|
||||
dlsym(_topo_dlhandle, "topo_open");
|
||||
_topo_close = (void (*)())
|
||||
dlsym(_topo_dlhandle, "topo_close");
|
||||
_topo_snap_hold = (char *(*)())
|
||||
dlsym(_topo_dlhandle, "topo_snap_hold");
|
||||
_topo_snap_release = (void (*)())
|
||||
dlsym(_topo_dlhandle, "topo_snap_release");
|
||||
_topo_walk_init = (topo_walk_t *(*)())
|
||||
dlsym(_topo_dlhandle, "topo_walk_init");
|
||||
_topo_walk_step = (int (*)())
|
||||
dlsym(_topo_dlhandle, "topo_walk_step");
|
||||
_topo_walk_fini = (void (*)())
|
||||
dlsym(_topo_dlhandle, "topo_walk_fini");
|
||||
_topo_hdl_strfree = (void (*)())
|
||||
dlsym(_topo_dlhandle, "topo_hdl_strfree");
|
||||
_topo_node_name = (char *(*)())
|
||||
dlsym(_topo_dlhandle, "topo_node_name");
|
||||
_topo_prop_get_string = (int (*)())
|
||||
dlsym(_topo_dlhandle, "topo_prop_get_string");
|
||||
_topo_node_fru = (int (*)())
|
||||
dlsym(_topo_dlhandle, "topo_node_fru");
|
||||
_topo_fmri_nvl2str = (int (*)())
|
||||
dlsym(_topo_dlhandle, "topo_fmri_nvl2str");
|
||||
_topo_fmri_strcmp_noauth = (int (*)())
|
||||
dlsym(_topo_dlhandle, "topo_fmri_strcmp_noauth");
|
||||
|
||||
if (_topo_open == NULL || _topo_close == NULL ||
|
||||
_topo_snap_hold == NULL || _topo_snap_release == NULL ||
|
||||
_topo_walk_init == NULL || _topo_walk_step == NULL ||
|
||||
_topo_walk_fini == NULL || _topo_hdl_strfree == NULL ||
|
||||
_topo_node_name == NULL || _topo_prop_get_string == NULL ||
|
||||
_topo_node_fru == NULL || _topo_fmri_nvl2str == NULL ||
|
||||
_topo_fmri_strcmp_noauth == NULL) {
|
||||
(void) dlclose(_topo_dlhandle);
|
||||
_topo_dlhandle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Refresh the mappings from device path -> FMRI. We do this by walking the
|
||||
* hc topology looking for disk nodes, and recording the io/devfs-path and FRU.
|
||||
* Note that we strip out the disk-specific authority information (serial,
|
||||
* part, revision, etc) so that we are left with only the identifying
|
||||
* characteristics of the slot (hc path and chassis-id).
|
||||
*/
|
||||
void
|
||||
libzfs_fru_refresh(libzfs_handle_t *hdl)
|
||||
{
|
||||
int err;
|
||||
char *uuid;
|
||||
topo_hdl_t *thp;
|
||||
topo_walk_t *twp;
|
||||
|
||||
if (_topo_dlhandle == NULL)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Clear the FRU hash and initialize our basic structures.
|
||||
*/
|
||||
libzfs_fru_clear(hdl, B_FALSE);
|
||||
|
||||
if ((hdl->libzfs_topo_hdl = _topo_open(TOPO_VERSION,
|
||||
NULL, &err)) == NULL)
|
||||
return;
|
||||
|
||||
thp = hdl->libzfs_topo_hdl;
|
||||
|
||||
if ((uuid = _topo_snap_hold(thp, NULL, &err)) == NULL)
|
||||
return;
|
||||
|
||||
_topo_hdl_strfree(thp, uuid);
|
||||
|
||||
if (hdl->libzfs_fru_hash == NULL &&
|
||||
(hdl->libzfs_fru_hash =
|
||||
calloc(ZFS_FRU_HASH_SIZE * sizeof (void *), 1)) == NULL)
|
||||
return;
|
||||
|
||||
/*
|
||||
* We now have a topo snapshot, so iterate over the hc topology looking
|
||||
* for disks to add to the hash.
|
||||
*/
|
||||
twp = _topo_walk_init(thp, FM_FMRI_SCHEME_HC,
|
||||
libzfs_fru_gather, hdl, &err);
|
||||
if (twp != NULL) {
|
||||
(void) _topo_walk_step(twp, TOPO_WALK_CHILD);
|
||||
_topo_walk_fini(twp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a devfs path, return the FRU for the device, if known. This will
|
||||
* automatically call libzfs_fru_refresh() if it hasn't already been called by
|
||||
* the consumer. The string returned is valid until the next call to
|
||||
* libzfs_fru_refresh().
|
||||
*/
|
||||
const char *
|
||||
libzfs_fru_lookup(libzfs_handle_t *hdl, const char *devpath)
|
||||
{
|
||||
size_t idx = fru_strhash(devpath);
|
||||
libzfs_fru_t *frup;
|
||||
|
||||
if (hdl->libzfs_fru_hash == NULL)
|
||||
libzfs_fru_refresh(hdl);
|
||||
|
||||
if (hdl->libzfs_fru_hash == NULL)
|
||||
return (NULL);
|
||||
|
||||
for (frup = hdl->libzfs_fru_hash[idx]; frup != NULL;
|
||||
frup = frup->zf_chain) {
|
||||
if (strcmp(devpath, frup->zf_device) == 0)
|
||||
return (frup->zf_fru);
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a fru path, return the device path. This will automatically call
|
||||
* libzfs_fru_refresh() if it hasn't already been called by the consumer. The
|
||||
* string returned is valid until the next call to libzfs_fru_refresh().
|
||||
*/
|
||||
const char *
|
||||
libzfs_fru_devpath(libzfs_handle_t *hdl, const char *fru)
|
||||
{
|
||||
libzfs_fru_t *frup;
|
||||
size_t idx;
|
||||
|
||||
if (hdl->libzfs_fru_hash == NULL)
|
||||
libzfs_fru_refresh(hdl);
|
||||
|
||||
if (hdl->libzfs_fru_hash == NULL)
|
||||
return (NULL);
|
||||
|
||||
for (idx = 0; idx < ZFS_FRU_HASH_SIZE; idx++) {
|
||||
for (frup = hdl->libzfs_fru_hash[idx]; frup != NULL;
|
||||
frup = frup->zf_next) {
|
||||
if (_topo_fmri_strcmp_noauth(hdl->libzfs_topo_hdl,
|
||||
fru, frup->zf_fru))
|
||||
return (frup->zf_device);
|
||||
}
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Change the stored FRU for the given vdev.
|
||||
*/
|
||||
int
|
||||
zpool_fru_set(zpool_handle_t *zhp, uint64_t vdev_guid, const char *fru)
|
||||
{
|
||||
zfs_cmd_t zc = { 0 };
|
||||
|
||||
(void) strncpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
|
||||
(void) strncpy(zc.zc_value, fru, sizeof (zc.zc_value));
|
||||
zc.zc_guid = vdev_guid;
|
||||
|
||||
if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SETFRU, &zc) != 0)
|
||||
return (zpool_standard_error_fmt(zhp->zpool_hdl, errno,
|
||||
dgettext(TEXT_DOMAIN, "cannot set FRU")));
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare to two FRUs, ignoring any authority information.
|
||||
*/
|
||||
boolean_t
|
||||
libzfs_fru_compare(libzfs_handle_t *hdl, const char *a, const char *b)
|
||||
{
|
||||
if (hdl->libzfs_fru_hash == NULL)
|
||||
libzfs_fru_refresh(hdl);
|
||||
|
||||
if (hdl->libzfs_fru_hash == NULL)
|
||||
return (strcmp(a, b) == 0);
|
||||
|
||||
return (_topo_fmri_strcmp_noauth(hdl->libzfs_topo_hdl, a, b));
|
||||
}
|
||||
|
||||
/*
|
||||
* This special function checks to see whether the FRU indicates it's supposed
|
||||
* to be in the system chassis, but the chassis-id doesn't match. This can
|
||||
* happen in a clustered case, where both head nodes have the same logical
|
||||
* disk, but opening the device on the other head node is meaningless.
|
||||
*/
|
||||
boolean_t
|
||||
libzfs_fru_notself(libzfs_handle_t *hdl, const char *fru)
|
||||
{
|
||||
const char *chassisid;
|
||||
size_t len;
|
||||
|
||||
if (hdl->libzfs_fru_hash == NULL)
|
||||
libzfs_fru_refresh(hdl);
|
||||
|
||||
if (hdl->libzfs_chassis_id[0] == '\0')
|
||||
return (B_FALSE);
|
||||
|
||||
if (strstr(fru, "/chassis=0/") == NULL)
|
||||
return (B_FALSE);
|
||||
|
||||
if ((chassisid = strstr(fru, ":chassis-id=")) == NULL)
|
||||
return (B_FALSE);
|
||||
|
||||
chassisid += 12;
|
||||
len = strlen(hdl->libzfs_chassis_id);
|
||||
if (strncmp(chassisid, hdl->libzfs_chassis_id, len) == 0 &&
|
||||
(chassisid[len] == '/' || chassisid[len] == ':'))
|
||||
return (B_FALSE);
|
||||
|
||||
return (B_TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear memory associated with the FRU hash.
|
||||
*/
|
||||
void
|
||||
libzfs_fru_clear(libzfs_handle_t *hdl, boolean_t final)
|
||||
{
|
||||
libzfs_fru_t *frup;
|
||||
|
||||
while ((frup = hdl->libzfs_fru_list) != NULL) {
|
||||
hdl->libzfs_fru_list = frup->zf_next;
|
||||
free(frup->zf_device);
|
||||
free(frup->zf_fru);
|
||||
free(frup);
|
||||
}
|
||||
|
||||
hdl->libzfs_fru_list = NULL;
|
||||
|
||||
if (hdl->libzfs_topo_hdl != NULL) {
|
||||
_topo_snap_release(hdl->libzfs_topo_hdl);
|
||||
_topo_close(hdl->libzfs_topo_hdl);
|
||||
hdl->libzfs_topo_hdl = NULL;
|
||||
}
|
||||
|
||||
if (final) {
|
||||
free(hdl->libzfs_fru_hash);
|
||||
} else if (hdl->libzfs_fru_hash != NULL) {
|
||||
bzero(hdl->libzfs_fru_hash,
|
||||
ZFS_FRU_HASH_SIZE * sizeof (void *));
|
||||
}
|
||||
}
|
||||
+440
-73
@@ -19,12 +19,10 @@
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
|
||||
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
/*
|
||||
* Pool import support functions.
|
||||
*
|
||||
@@ -41,15 +39,21 @@
|
||||
* using our derived config, and record the results.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <devid.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <libintl.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/vtoc.h>
|
||||
#include <sys/dktp/fdisk.h>
|
||||
#include <sys/efi_partition.h>
|
||||
#include <thread_pool.h>
|
||||
|
||||
#include <sys/vdev_impl.h>
|
||||
|
||||
@@ -388,8 +392,6 @@ refresh_config(libzfs_handle_t *hdl, nvlist_t *config)
|
||||
}
|
||||
|
||||
if (err) {
|
||||
(void) zpool_standard_error(hdl, errno,
|
||||
dgettext(TEXT_DOMAIN, "cannot discover pools"));
|
||||
zcmd_free_nvlists(&zc);
|
||||
return (NULL);
|
||||
}
|
||||
@@ -403,6 +405,21 @@ refresh_config(libzfs_handle_t *hdl, nvlist_t *config)
|
||||
return (nvl);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine if the vdev id is a hole in the namespace.
|
||||
*/
|
||||
boolean_t
|
||||
vdev_is_hole(uint64_t *hole_array, uint_t holes, uint_t id)
|
||||
{
|
||||
for (int c = 0; c < holes; c++) {
|
||||
|
||||
/* Top-level is a hole */
|
||||
if (hole_array[c] == id)
|
||||
return (B_TRUE);
|
||||
}
|
||||
return (B_FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert our list of pools into the definitive set of configurations. We
|
||||
* start by picking the best config for each toplevel vdev. Once that's done,
|
||||
@@ -425,17 +442,20 @@ get_configs(libzfs_handle_t *hdl, pool_list_t *pl, boolean_t active_ok)
|
||||
uint64_t version, guid;
|
||||
uint_t children = 0;
|
||||
nvlist_t **child = NULL;
|
||||
uint_t holes;
|
||||
uint64_t *hole_array, max_id;
|
||||
uint_t c;
|
||||
boolean_t isactive;
|
||||
uint64_t hostid;
|
||||
nvlist_t *nvl;
|
||||
boolean_t found_one = B_FALSE;
|
||||
boolean_t valid_top_config = B_FALSE;
|
||||
|
||||
if (nvlist_alloc(&ret, 0, 0) != 0)
|
||||
goto nomem;
|
||||
|
||||
for (pe = pl->pools; pe != NULL; pe = pe->pe_next) {
|
||||
uint64_t id;
|
||||
uint64_t id, max_txg = 0;
|
||||
|
||||
if (nvlist_alloc(&config, NV_UNIQUE_NAME, 0) != 0)
|
||||
goto nomem;
|
||||
@@ -463,6 +483,42 @@ get_configs(libzfs_handle_t *hdl, pool_list_t *pl, boolean_t active_ok)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We rely on the fact that the max txg for the
|
||||
* pool will contain the most up-to-date information
|
||||
* about the valid top-levels in the vdev namespace.
|
||||
*/
|
||||
if (best_txg > max_txg) {
|
||||
(void) nvlist_remove(config,
|
||||
ZPOOL_CONFIG_VDEV_CHILDREN,
|
||||
DATA_TYPE_UINT64);
|
||||
(void) nvlist_remove(config,
|
||||
ZPOOL_CONFIG_HOLE_ARRAY,
|
||||
DATA_TYPE_UINT64_ARRAY);
|
||||
|
||||
max_txg = best_txg;
|
||||
hole_array = NULL;
|
||||
holes = 0;
|
||||
max_id = 0;
|
||||
valid_top_config = B_FALSE;
|
||||
|
||||
if (nvlist_lookup_uint64(tmp,
|
||||
ZPOOL_CONFIG_VDEV_CHILDREN, &max_id) == 0) {
|
||||
verify(nvlist_add_uint64(config,
|
||||
ZPOOL_CONFIG_VDEV_CHILDREN,
|
||||
max_id) == 0);
|
||||
valid_top_config = B_TRUE;
|
||||
}
|
||||
|
||||
if (nvlist_lookup_uint64_array(tmp,
|
||||
ZPOOL_CONFIG_HOLE_ARRAY, &hole_array,
|
||||
&holes) == 0) {
|
||||
verify(nvlist_add_uint64_array(config,
|
||||
ZPOOL_CONFIG_HOLE_ARRAY,
|
||||
hole_array, holes) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (!config_seen) {
|
||||
/*
|
||||
* Copy the relevant pieces of data to the pool
|
||||
@@ -522,6 +578,7 @@ get_configs(libzfs_handle_t *hdl, pool_list_t *pl, boolean_t active_ok)
|
||||
ZPOOL_CONFIG_VDEV_TREE, &nvtop) == 0);
|
||||
verify(nvlist_lookup_uint64(nvtop, ZPOOL_CONFIG_ID,
|
||||
&id) == 0);
|
||||
|
||||
if (id >= children) {
|
||||
nvlist_t **newchild;
|
||||
|
||||
@@ -542,9 +599,74 @@ get_configs(libzfs_handle_t *hdl, pool_list_t *pl, boolean_t active_ok)
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have information about all the top-levels then
|
||||
* clean up the nvlist which we've constructed. This
|
||||
* means removing any extraneous devices that are
|
||||
* beyond the valid range or adding devices to the end
|
||||
* of our array which appear to be missing.
|
||||
*/
|
||||
if (valid_top_config) {
|
||||
if (max_id < children) {
|
||||
for (c = max_id; c < children; c++)
|
||||
nvlist_free(child[c]);
|
||||
children = max_id;
|
||||
} else if (max_id > children) {
|
||||
nvlist_t **newchild;
|
||||
|
||||
newchild = zfs_alloc(hdl, (max_id) *
|
||||
sizeof (nvlist_t *));
|
||||
if (newchild == NULL)
|
||||
goto nomem;
|
||||
|
||||
for (c = 0; c < children; c++)
|
||||
newchild[c] = child[c];
|
||||
|
||||
free(child);
|
||||
child = newchild;
|
||||
children = max_id;
|
||||
}
|
||||
}
|
||||
|
||||
verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
|
||||
&guid) == 0);
|
||||
|
||||
/*
|
||||
* The vdev namespace may contain holes as a result of
|
||||
* device removal. We must add them back into the vdev
|
||||
* tree before we process any missing devices.
|
||||
*/
|
||||
if (holes > 0) {
|
||||
ASSERT(valid_top_config);
|
||||
|
||||
for (c = 0; c < children; c++) {
|
||||
nvlist_t *holey;
|
||||
|
||||
if (child[c] != NULL ||
|
||||
!vdev_is_hole(hole_array, holes, c))
|
||||
continue;
|
||||
|
||||
if (nvlist_alloc(&holey, NV_UNIQUE_NAME,
|
||||
0) != 0)
|
||||
goto nomem;
|
||||
|
||||
/*
|
||||
* Holes in the namespace are treated as
|
||||
* "hole" top-level vdevs and have a
|
||||
* special flag set on them.
|
||||
*/
|
||||
if (nvlist_add_string(holey,
|
||||
ZPOOL_CONFIG_TYPE,
|
||||
VDEV_TYPE_HOLE) != 0 ||
|
||||
nvlist_add_uint64(holey,
|
||||
ZPOOL_CONFIG_ID, c) != 0 ||
|
||||
nvlist_add_uint64(holey,
|
||||
ZPOOL_CONFIG_GUID, 0ULL) != 0)
|
||||
goto nomem;
|
||||
child[c] = holey;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Look for any missing top-level vdevs. If this is the case,
|
||||
* create a faked up 'missing' vdev as a placeholder. We cannot
|
||||
@@ -552,7 +674,7 @@ get_configs(libzfs_handle_t *hdl, pool_list_t *pl, boolean_t active_ok)
|
||||
* certain checks to make sure the vdev IDs match their location
|
||||
* in the configuration.
|
||||
*/
|
||||
for (c = 0; c < children; c++)
|
||||
for (c = 0; c < children; c++) {
|
||||
if (child[c] == NULL) {
|
||||
nvlist_t *missing;
|
||||
if (nvlist_alloc(&missing, NV_UNIQUE_NAME,
|
||||
@@ -570,6 +692,7 @@ get_configs(libzfs_handle_t *hdl, pool_list_t *pl, boolean_t active_ok)
|
||||
}
|
||||
child[c] = missing;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Put all of this pool's top-level vdevs into a root vdev.
|
||||
@@ -636,8 +759,11 @@ get_configs(libzfs_handle_t *hdl, pool_list_t *pl, boolean_t active_ok)
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((nvl = refresh_config(hdl, config)) == NULL)
|
||||
goto error;
|
||||
if ((nvl = refresh_config(hdl, config)) == NULL) {
|
||||
nvlist_free(config);
|
||||
config = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
nvlist_free(config);
|
||||
config = nvl;
|
||||
@@ -777,6 +903,212 @@ zpool_read_label(int fd, nvlist_t **config)
|
||||
return (0);
|
||||
}
|
||||
|
||||
typedef struct rdsk_node {
|
||||
char *rn_name;
|
||||
int rn_dfd;
|
||||
libzfs_handle_t *rn_hdl;
|
||||
nvlist_t *rn_config;
|
||||
avl_tree_t *rn_avl;
|
||||
avl_node_t rn_node;
|
||||
boolean_t rn_nozpool;
|
||||
} rdsk_node_t;
|
||||
|
||||
static int
|
||||
slice_cache_compare(const void *arg1, const void *arg2)
|
||||
{
|
||||
const char *nm1 = ((rdsk_node_t *)arg1)->rn_name;
|
||||
const char *nm2 = ((rdsk_node_t *)arg2)->rn_name;
|
||||
char *nm1slice, *nm2slice;
|
||||
int rv;
|
||||
|
||||
/*
|
||||
* slices zero and two are the most likely to provide results,
|
||||
* so put those first
|
||||
*/
|
||||
nm1slice = strstr(nm1, "s0");
|
||||
nm2slice = strstr(nm2, "s0");
|
||||
if (nm1slice && !nm2slice) {
|
||||
return (-1);
|
||||
}
|
||||
if (!nm1slice && nm2slice) {
|
||||
return (1);
|
||||
}
|
||||
nm1slice = strstr(nm1, "s2");
|
||||
nm2slice = strstr(nm2, "s2");
|
||||
if (nm1slice && !nm2slice) {
|
||||
return (-1);
|
||||
}
|
||||
if (!nm1slice && nm2slice) {
|
||||
return (1);
|
||||
}
|
||||
|
||||
rv = strcmp(nm1, nm2);
|
||||
if (rv == 0)
|
||||
return (0);
|
||||
return (rv > 0 ? 1 : -1);
|
||||
}
|
||||
|
||||
static void
|
||||
check_one_slice(avl_tree_t *r, char *diskname, uint_t partno,
|
||||
diskaddr_t size, uint_t blksz)
|
||||
{
|
||||
rdsk_node_t tmpnode;
|
||||
rdsk_node_t *node;
|
||||
char sname[MAXNAMELEN];
|
||||
|
||||
tmpnode.rn_name = &sname[0];
|
||||
(void) snprintf(tmpnode.rn_name, MAXNAMELEN, "%s%u",
|
||||
diskname, partno);
|
||||
/*
|
||||
* protect against division by zero for disk labels that
|
||||
* contain a bogus sector size
|
||||
*/
|
||||
if (blksz == 0)
|
||||
blksz = DEV_BSIZE;
|
||||
/* too small to contain a zpool? */
|
||||
if ((size < (SPA_MINDEVSIZE / blksz)) &&
|
||||
(node = avl_find(r, &tmpnode, NULL)))
|
||||
node->rn_nozpool = B_TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
nozpool_all_slices(avl_tree_t *r, const char *sname)
|
||||
{
|
||||
char diskname[MAXNAMELEN];
|
||||
char *ptr;
|
||||
int i;
|
||||
|
||||
(void) strncpy(diskname, sname, MAXNAMELEN);
|
||||
if (((ptr = strrchr(diskname, 's')) == NULL) &&
|
||||
((ptr = strrchr(diskname, 'p')) == NULL))
|
||||
return;
|
||||
ptr[0] = 's';
|
||||
ptr[1] = '\0';
|
||||
for (i = 0; i < NDKMAP; i++)
|
||||
check_one_slice(r, diskname, i, 0, 1);
|
||||
ptr[0] = 'p';
|
||||
for (i = 0; i <= FD_NUMPART; i++)
|
||||
check_one_slice(r, diskname, i, 0, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
check_slices(avl_tree_t *r, int fd, const char *sname)
|
||||
{
|
||||
struct extvtoc vtoc;
|
||||
struct dk_gpt *gpt;
|
||||
char diskname[MAXNAMELEN];
|
||||
char *ptr;
|
||||
int i;
|
||||
|
||||
(void) strncpy(diskname, sname, MAXNAMELEN);
|
||||
if ((ptr = strrchr(diskname, 's')) == NULL || !isdigit(ptr[1]))
|
||||
return;
|
||||
ptr[1] = '\0';
|
||||
|
||||
if (read_extvtoc(fd, &vtoc) >= 0) {
|
||||
for (i = 0; i < NDKMAP; i++)
|
||||
check_one_slice(r, diskname, i,
|
||||
vtoc.v_part[i].p_size, vtoc.v_sectorsz);
|
||||
} else if (efi_alloc_and_read(fd, &gpt) >= 0) {
|
||||
/*
|
||||
* on x86 we'll still have leftover links that point
|
||||
* to slices s[9-15], so use NDKMAP instead
|
||||
*/
|
||||
for (i = 0; i < NDKMAP; i++)
|
||||
check_one_slice(r, diskname, i,
|
||||
gpt->efi_parts[i].p_size, gpt->efi_lbasize);
|
||||
/* nodes p[1-4] are never used with EFI labels */
|
||||
ptr[0] = 'p';
|
||||
for (i = 1; i <= FD_NUMPART; i++)
|
||||
check_one_slice(r, diskname, i, 0, 1);
|
||||
efi_free(gpt);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
zpool_open_func(void *arg)
|
||||
{
|
||||
rdsk_node_t *rn = arg;
|
||||
struct stat64 statbuf;
|
||||
nvlist_t *config;
|
||||
int fd;
|
||||
|
||||
if (rn->rn_nozpool)
|
||||
return;
|
||||
if ((fd = openat64(rn->rn_dfd, rn->rn_name, O_RDONLY)) < 0) {
|
||||
/* symlink to a device that's no longer there */
|
||||
if (errno == ENOENT)
|
||||
nozpool_all_slices(rn->rn_avl, rn->rn_name);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Ignore failed stats. We only want regular
|
||||
* files, character devs and block devs.
|
||||
*/
|
||||
if (fstat64(fd, &statbuf) != 0 ||
|
||||
(!S_ISREG(statbuf.st_mode) &&
|
||||
!S_ISCHR(statbuf.st_mode) &&
|
||||
!S_ISBLK(statbuf.st_mode))) {
|
||||
(void) close(fd);
|
||||
return;
|
||||
}
|
||||
/* this file is too small to hold a zpool */
|
||||
if (S_ISREG(statbuf.st_mode) &&
|
||||
statbuf.st_size < SPA_MINDEVSIZE) {
|
||||
(void) close(fd);
|
||||
return;
|
||||
} else if (!S_ISREG(statbuf.st_mode)) {
|
||||
/*
|
||||
* Try to read the disk label first so we don't have to
|
||||
* open a bunch of minor nodes that can't have a zpool.
|
||||
*/
|
||||
check_slices(rn->rn_avl, fd, rn->rn_name);
|
||||
}
|
||||
|
||||
if ((zpool_read_label(fd, &config)) != 0) {
|
||||
(void) close(fd);
|
||||
(void) no_memory(rn->rn_hdl);
|
||||
return;
|
||||
}
|
||||
(void) close(fd);
|
||||
|
||||
|
||||
rn->rn_config = config;
|
||||
if (config != NULL) {
|
||||
assert(rn->rn_nozpool == B_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a file descriptor, clear (zero) the label information. This function
|
||||
* is currently only used in the appliance stack as part of the ZFS sysevent
|
||||
* module.
|
||||
*/
|
||||
int
|
||||
zpool_clear_label(int fd)
|
||||
{
|
||||
struct stat64 statbuf;
|
||||
int l;
|
||||
vdev_label_t *label;
|
||||
uint64_t size;
|
||||
|
||||
if (fstat64(fd, &statbuf) == -1)
|
||||
return (0);
|
||||
size = P2ALIGN_TYPED(statbuf.st_size, sizeof (vdev_label_t), uint64_t);
|
||||
|
||||
if ((label = calloc(sizeof (vdev_label_t), 1)) == NULL)
|
||||
return (-1);
|
||||
|
||||
for (l = 0; l < VDEV_LABELS; l++) {
|
||||
if (pwrite64(fd, label, sizeof (vdev_label_t),
|
||||
label_offset(size, l)) != sizeof (vdev_label_t))
|
||||
return (-1);
|
||||
}
|
||||
|
||||
free(label);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a list of directories to search, find all pools stored on disk. This
|
||||
* includes partial pools which are not available to import. If no args are
|
||||
@@ -785,30 +1117,28 @@ zpool_read_label(int fd, nvlist_t **config)
|
||||
* to import a specific pool.
|
||||
*/
|
||||
static nvlist_t *
|
||||
zpool_find_import_impl(libzfs_handle_t *hdl, int argc, char **argv,
|
||||
boolean_t active_ok, char *poolname, uint64_t guid)
|
||||
zpool_find_import_impl(libzfs_handle_t *hdl, importargs_t *iarg)
|
||||
{
|
||||
int i;
|
||||
int i, dirs = iarg->paths;
|
||||
DIR *dirp = NULL;
|
||||
struct dirent64 *dp;
|
||||
char path[MAXPATHLEN];
|
||||
char *end;
|
||||
char *end, **dir = iarg->path;
|
||||
size_t pathleft;
|
||||
struct stat64 statbuf;
|
||||
nvlist_t *ret = NULL, *config;
|
||||
nvlist_t *ret = NULL;
|
||||
static char *default_dir = "/dev/dsk";
|
||||
int fd;
|
||||
pool_list_t pools = { 0 };
|
||||
pool_entry_t *pe, *penext;
|
||||
vdev_entry_t *ve, *venext;
|
||||
config_entry_t *ce, *cenext;
|
||||
name_entry_t *ne, *nenext;
|
||||
avl_tree_t slice_cache;
|
||||
rdsk_node_t *slice;
|
||||
void *cookie;
|
||||
|
||||
verify(poolname == NULL || guid == 0);
|
||||
|
||||
if (argc == 0) {
|
||||
argc = 1;
|
||||
argv = &default_dir;
|
||||
if (dirs == 0) {
|
||||
dirs = 1;
|
||||
dir = &default_dir;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -816,15 +1146,15 @@ zpool_find_import_impl(libzfs_handle_t *hdl, int argc, char **argv,
|
||||
* possible device, organizing the information according to pool GUID
|
||||
* and toplevel GUID.
|
||||
*/
|
||||
for (i = 0; i < argc; i++) {
|
||||
for (i = 0; i < dirs; i++) {
|
||||
tpool_t *t;
|
||||
char *rdsk;
|
||||
int dfd;
|
||||
|
||||
/* use realpath to normalize the path */
|
||||
if (realpath(argv[i], path) == 0) {
|
||||
if (realpath(dir[i], path) == 0) {
|
||||
(void) zfs_error_fmt(hdl, EZFS_BADPATH,
|
||||
dgettext(TEXT_DOMAIN, "cannot open '%s'"),
|
||||
argv[i]);
|
||||
dgettext(TEXT_DOMAIN, "cannot open '%s'"), dir[i]);
|
||||
goto error;
|
||||
}
|
||||
end = &path[strlen(path)];
|
||||
@@ -851,6 +1181,8 @@ zpool_find_import_impl(libzfs_handle_t *hdl, int argc, char **argv,
|
||||
goto error;
|
||||
}
|
||||
|
||||
avl_create(&slice_cache, slice_cache_compare,
|
||||
sizeof (rdsk_node_t), offsetof(rdsk_node_t, rn_node));
|
||||
/*
|
||||
* This is not MT-safe, but we have no MT consumers of libzfs
|
||||
*/
|
||||
@@ -860,46 +1192,53 @@ zpool_find_import_impl(libzfs_handle_t *hdl, int argc, char **argv,
|
||||
(name[1] == 0 || (name[1] == '.' && name[2] == 0)))
|
||||
continue;
|
||||
|
||||
if ((fd = openat64(dfd, name, O_RDONLY)) < 0)
|
||||
continue;
|
||||
slice = zfs_alloc(hdl, sizeof (rdsk_node_t));
|
||||
slice->rn_name = zfs_strdup(hdl, name);
|
||||
slice->rn_avl = &slice_cache;
|
||||
slice->rn_dfd = dfd;
|
||||
slice->rn_hdl = hdl;
|
||||
slice->rn_nozpool = B_FALSE;
|
||||
avl_add(&slice_cache, slice);
|
||||
}
|
||||
/*
|
||||
* create a thread pool to do all of this in parallel;
|
||||
* rn_nozpool is not protected, so this is racy in that
|
||||
* multiple tasks could decide that the same slice can
|
||||
* not hold a zpool, which is benign. Also choose
|
||||
* double the number of processors; we hold a lot of
|
||||
* locks in the kernel, so going beyond this doesn't
|
||||
* buy us much.
|
||||
*/
|
||||
t = tpool_create(1, 2 * sysconf(_SC_NPROCESSORS_ONLN),
|
||||
0, NULL);
|
||||
for (slice = avl_first(&slice_cache); slice;
|
||||
(slice = avl_walk(&slice_cache, slice,
|
||||
AVL_AFTER)))
|
||||
(void) tpool_dispatch(t, zpool_open_func, slice);
|
||||
tpool_wait(t);
|
||||
tpool_destroy(t);
|
||||
|
||||
/*
|
||||
* Ignore failed stats. We only want regular
|
||||
* files, character devs and block devs.
|
||||
*/
|
||||
if (fstat64(fd, &statbuf) != 0 ||
|
||||
(!S_ISREG(statbuf.st_mode) &&
|
||||
!S_ISCHR(statbuf.st_mode) &&
|
||||
!S_ISBLK(statbuf.st_mode))) {
|
||||
(void) close(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((zpool_read_label(fd, &config)) != 0) {
|
||||
(void) close(fd);
|
||||
(void) no_memory(hdl);
|
||||
goto error;
|
||||
}
|
||||
|
||||
(void) close(fd);
|
||||
|
||||
if (config != NULL) {
|
||||
cookie = NULL;
|
||||
while ((slice = avl_destroy_nodes(&slice_cache,
|
||||
&cookie)) != NULL) {
|
||||
if (slice->rn_config != NULL) {
|
||||
nvlist_t *config = slice->rn_config;
|
||||
boolean_t matched = B_TRUE;
|
||||
|
||||
if (poolname != NULL) {
|
||||
if (iarg->poolname != NULL) {
|
||||
char *pname;
|
||||
|
||||
matched = nvlist_lookup_string(config,
|
||||
ZPOOL_CONFIG_POOL_NAME,
|
||||
&pname) == 0 &&
|
||||
strcmp(poolname, pname) == 0;
|
||||
} else if (guid != 0) {
|
||||
strcmp(iarg->poolname, pname) == 0;
|
||||
} else if (iarg->guid != 0) {
|
||||
uint64_t this_guid;
|
||||
|
||||
matched = nvlist_lookup_uint64(config,
|
||||
ZPOOL_CONFIG_POOL_GUID,
|
||||
&this_guid) == 0 &&
|
||||
guid == this_guid;
|
||||
iarg->guid == this_guid;
|
||||
}
|
||||
if (!matched) {
|
||||
nvlist_free(config);
|
||||
@@ -907,17 +1246,20 @@ zpool_find_import_impl(libzfs_handle_t *hdl, int argc, char **argv,
|
||||
continue;
|
||||
}
|
||||
/* use the non-raw path for the config */
|
||||
(void) strlcpy(end, name, pathleft);
|
||||
(void) strlcpy(end, slice->rn_name, pathleft);
|
||||
if (add_config(hdl, &pools, path, config) != 0)
|
||||
goto error;
|
||||
}
|
||||
free(slice->rn_name);
|
||||
free(slice);
|
||||
}
|
||||
avl_destroy(&slice_cache);
|
||||
|
||||
(void) closedir(dirp);
|
||||
dirp = NULL;
|
||||
}
|
||||
|
||||
ret = get_configs(hdl, &pools, active_ok);
|
||||
ret = get_configs(hdl, &pools, iarg->can_be_active);
|
||||
|
||||
error:
|
||||
for (pe = pools.pools; pe != NULL; pe = penext) {
|
||||
@@ -951,27 +1293,12 @@ error:
|
||||
nvlist_t *
|
||||
zpool_find_import(libzfs_handle_t *hdl, int argc, char **argv)
|
||||
{
|
||||
return (zpool_find_import_impl(hdl, argc, argv, B_FALSE, NULL, 0));
|
||||
}
|
||||
importargs_t iarg = { 0 };
|
||||
|
||||
nvlist_t *
|
||||
zpool_find_import_byname(libzfs_handle_t *hdl, int argc, char **argv,
|
||||
char *pool)
|
||||
{
|
||||
return (zpool_find_import_impl(hdl, argc, argv, B_FALSE, pool, 0));
|
||||
}
|
||||
iarg.paths = argc;
|
||||
iarg.path = argv;
|
||||
|
||||
nvlist_t *
|
||||
zpool_find_import_byguid(libzfs_handle_t *hdl, int argc, char **argv,
|
||||
uint64_t guid)
|
||||
{
|
||||
return (zpool_find_import_impl(hdl, argc, argv, B_FALSE, NULL, guid));
|
||||
}
|
||||
|
||||
nvlist_t *
|
||||
zpool_find_import_activeok(libzfs_handle_t *hdl, int argc, char **argv)
|
||||
{
|
||||
return (zpool_find_import_impl(hdl, argc, argv, B_TRUE, NULL, 0));
|
||||
return (zpool_find_import_impl(hdl, &iarg));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1093,6 +1420,46 @@ zpool_find_import_cached(libzfs_handle_t *hdl, const char *cachefile,
|
||||
return (pools);
|
||||
}
|
||||
|
||||
static int
|
||||
name_or_guid_exists(zpool_handle_t *zhp, void *data)
|
||||
{
|
||||
importargs_t *import = data;
|
||||
int found = 0;
|
||||
|
||||
if (import->poolname != NULL) {
|
||||
char *pool_name;
|
||||
|
||||
verify(nvlist_lookup_string(zhp->zpool_config,
|
||||
ZPOOL_CONFIG_POOL_NAME, &pool_name) == 0);
|
||||
if (strcmp(pool_name, import->poolname) == 0)
|
||||
found = 1;
|
||||
} else {
|
||||
uint64_t pool_guid;
|
||||
|
||||
verify(nvlist_lookup_uint64(zhp->zpool_config,
|
||||
ZPOOL_CONFIG_POOL_GUID, &pool_guid) == 0);
|
||||
if (pool_guid == import->guid)
|
||||
found = 1;
|
||||
}
|
||||
|
||||
zpool_close(zhp);
|
||||
return (found);
|
||||
}
|
||||
|
||||
nvlist_t *
|
||||
zpool_search_import(libzfs_handle_t *hdl, importargs_t *import)
|
||||
{
|
||||
verify(import->poolname == NULL || import->guid == 0);
|
||||
|
||||
if (import->unique)
|
||||
import->exists = zpool_iter(hdl, name_or_guid_exists, import);
|
||||
|
||||
if (import->cachefile != NULL)
|
||||
return (zpool_find_import_cached(hdl, import->cachefile,
|
||||
import->poolname, import->guid));
|
||||
|
||||
return (zpool_find_import_impl(hdl, import));
|
||||
}
|
||||
|
||||
boolean_t
|
||||
find_guid(nvlist_t *nv, uint64_t guid)
|
||||
|
||||
+18
-140
@@ -20,8 +20,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -44,17 +43,14 @@
|
||||
*
|
||||
* zfs_is_shared_nfs()
|
||||
* zfs_is_shared_smb()
|
||||
* zfs_is_shared_iscsi()
|
||||
* zfs_share_proto()
|
||||
* zfs_shareall();
|
||||
* zfs_share_iscsi()
|
||||
* zfs_unshare_nfs()
|
||||
* zfs_unshare_smb()
|
||||
* zfs_unshareall_nfs()
|
||||
* zfs_unshareall_smb()
|
||||
* zfs_unshareall()
|
||||
* zfs_unshareall_bypath()
|
||||
* zfs_unshare_iscsi()
|
||||
*
|
||||
* The following functions are available for pool consumers, and will
|
||||
* mount/unmount and share/unshare all datasets within pool:
|
||||
@@ -89,11 +85,6 @@ static int zfs_share_proto(zfs_handle_t *, zfs_share_proto_t *);
|
||||
zfs_share_type_t zfs_is_shared_proto(zfs_handle_t *, char **,
|
||||
zfs_share_proto_t);
|
||||
|
||||
static int (*iscsitgt_zfs_share)(const char *);
|
||||
static int (*iscsitgt_zfs_unshare)(const char *);
|
||||
static int (*iscsitgt_zfs_is_shared)(const char *);
|
||||
static int (*iscsitgt_svc_online)();
|
||||
|
||||
/*
|
||||
* The share protocols table must be in the same order as the zfs_share_prot_t
|
||||
* enum in libzfs_impl.h
|
||||
@@ -125,29 +116,6 @@ zfs_share_proto_t share_all_proto[] = {
|
||||
PROTO_END
|
||||
};
|
||||
|
||||
#pragma init(zfs_iscsi_init)
|
||||
static void
|
||||
zfs_iscsi_init(void)
|
||||
{
|
||||
void *libiscsitgt;
|
||||
|
||||
if ((libiscsitgt = dlopen("/lib/libiscsitgt.so.1",
|
||||
RTLD_LAZY | RTLD_GLOBAL)) == NULL ||
|
||||
(iscsitgt_zfs_share = (int (*)(const char *))dlsym(libiscsitgt,
|
||||
"iscsitgt_zfs_share")) == NULL ||
|
||||
(iscsitgt_zfs_unshare = (int (*)(const char *))dlsym(libiscsitgt,
|
||||
"iscsitgt_zfs_unshare")) == NULL ||
|
||||
(iscsitgt_zfs_is_shared = (int (*)(const char *))dlsym(libiscsitgt,
|
||||
"iscsitgt_zfs_is_shared")) == NULL ||
|
||||
(iscsitgt_svc_online = (int (*)(const char *))dlsym(libiscsitgt,
|
||||
"iscsitgt_svc_online")) == NULL) {
|
||||
iscsitgt_zfs_share = NULL;
|
||||
iscsitgt_zfs_unshare = NULL;
|
||||
iscsitgt_zfs_is_shared = NULL;
|
||||
iscsitgt_svc_online = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Search the sharetab for the given mountpoint and protocol, returning
|
||||
* a zfs_share_type_t value.
|
||||
@@ -345,6 +313,18 @@ zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
|
||||
} else if (errno == EPERM) {
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"Insufficient privileges"));
|
||||
} else if (errno == ENOTSUP) {
|
||||
char buf[256];
|
||||
int spa_version;
|
||||
|
||||
VERIFY(zfs_spa_version(zhp, &spa_version) == 0);
|
||||
(void) snprintf(buf, sizeof (buf),
|
||||
dgettext(TEXT_DOMAIN, "Can't mount a version %lld "
|
||||
"file system on a version %d pool. Pool must be"
|
||||
" upgraded to mount this file system."),
|
||||
(u_longlong_t)zfs_prop_get_int(zhp,
|
||||
ZFS_PROP_VERSION), spa_version);
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, buf));
|
||||
} else {
|
||||
zfs_error_aux(hdl, strerror(errno));
|
||||
}
|
||||
@@ -445,7 +425,7 @@ zfs_is_shared(zfs_handle_t *zhp)
|
||||
zfs_share_proto_t *curr_proto;
|
||||
|
||||
if (ZFS_IS_VOLUME(zhp))
|
||||
return (zfs_is_shared_iscsi(zhp));
|
||||
return (B_FALSE);
|
||||
|
||||
for (curr_proto = share_all_proto; *curr_proto != PROTO_END;
|
||||
curr_proto++)
|
||||
@@ -458,7 +438,7 @@ int
|
||||
zfs_share(zfs_handle_t *zhp)
|
||||
{
|
||||
if (ZFS_IS_VOLUME(zhp))
|
||||
return (zfs_share_iscsi(zhp));
|
||||
return (0);
|
||||
|
||||
return (zfs_share_proto(zhp, share_all_proto));
|
||||
}
|
||||
@@ -467,7 +447,7 @@ int
|
||||
zfs_unshare(zfs_handle_t *zhp)
|
||||
{
|
||||
if (ZFS_IS_VOLUME(zhp))
|
||||
return (zfs_unshare_iscsi(zhp));
|
||||
return (0);
|
||||
|
||||
return (zfs_unshareall(zhp));
|
||||
}
|
||||
@@ -999,81 +979,6 @@ remove_mountpoint(zfs_handle_t *zhp)
|
||||
}
|
||||
}
|
||||
|
||||
boolean_t
|
||||
zfs_is_shared_iscsi(zfs_handle_t *zhp)
|
||||
{
|
||||
|
||||
/*
|
||||
* If iscsi deamon isn't running then we aren't shared
|
||||
*/
|
||||
if (iscsitgt_svc_online && iscsitgt_svc_online() == 1)
|
||||
return (B_FALSE);
|
||||
else
|
||||
return (iscsitgt_zfs_is_shared != NULL &&
|
||||
iscsitgt_zfs_is_shared(zhp->zfs_name) != 0);
|
||||
}
|
||||
|
||||
int
|
||||
zfs_share_iscsi(zfs_handle_t *zhp)
|
||||
{
|
||||
char shareopts[ZFS_MAXPROPLEN];
|
||||
const char *dataset = zhp->zfs_name;
|
||||
libzfs_handle_t *hdl = zhp->zfs_hdl;
|
||||
|
||||
/*
|
||||
* Return success if there are no share options.
|
||||
*/
|
||||
if (zfs_prop_get(zhp, ZFS_PROP_SHAREISCSI, shareopts,
|
||||
sizeof (shareopts), NULL, NULL, 0, B_FALSE) != 0 ||
|
||||
strcmp(shareopts, "off") == 0)
|
||||
return (0);
|
||||
|
||||
if (iscsitgt_zfs_share == NULL || iscsitgt_zfs_share(dataset) != 0) {
|
||||
int error = EZFS_SHAREISCSIFAILED;
|
||||
|
||||
/*
|
||||
* If service isn't availabele and EPERM was
|
||||
* returned then use special error.
|
||||
*/
|
||||
if (iscsitgt_svc_online && errno == EPERM &&
|
||||
(iscsitgt_svc_online() != 0))
|
||||
error = EZFS_ISCSISVCUNAVAIL;
|
||||
|
||||
return (zfs_error_fmt(hdl, error,
|
||||
dgettext(TEXT_DOMAIN, "cannot share '%s'"), dataset));
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
zfs_unshare_iscsi(zfs_handle_t *zhp)
|
||||
{
|
||||
const char *dataset = zfs_get_name(zhp);
|
||||
libzfs_handle_t *hdl = zhp->zfs_hdl;
|
||||
|
||||
/*
|
||||
* Return if the volume is not shared
|
||||
*/
|
||||
if (zfs_is_shared_iscsi(zhp) != SHARED_ISCSI)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* If this fails with ENODEV it indicates that zvol wasn't shared so
|
||||
* we should return success in that case.
|
||||
*/
|
||||
if (iscsitgt_zfs_unshare == NULL ||
|
||||
(iscsitgt_zfs_unshare(dataset) != 0 && errno != ENODEV)) {
|
||||
if (errno == EPERM)
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"Insufficient privileges to unshare iscsi"));
|
||||
return (zfs_error_fmt(hdl, EZFS_UNSHAREISCSIFAILED,
|
||||
dgettext(TEXT_DOMAIN, "cannot unshare '%s'"), dataset));
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
typedef struct mount_cbdata {
|
||||
zfs_handle_t **cb_datasets;
|
||||
int cb_used;
|
||||
@@ -1215,28 +1120,6 @@ out:
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
zvol_cb(const char *dataset, void *data)
|
||||
{
|
||||
libzfs_handle_t *hdl = data;
|
||||
zfs_handle_t *zhp;
|
||||
|
||||
/*
|
||||
* Ignore snapshots and ignore failures from non-existant datasets.
|
||||
*/
|
||||
if (strchr(dataset, '@') != NULL ||
|
||||
(zhp = zfs_open(hdl, dataset, ZFS_TYPE_VOLUME)) == NULL)
|
||||
return (0);
|
||||
|
||||
if (zfs_unshare_iscsi(zhp) != 0)
|
||||
return (-1);
|
||||
|
||||
zfs_close(zhp);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
mountpoint_compare(const void *a, const void *b)
|
||||
{
|
||||
@@ -1246,6 +1129,8 @@ mountpoint_compare(const void *a, const void *b)
|
||||
return (strcmp(mountb, mounta));
|
||||
}
|
||||
|
||||
/* alias for 2002/240 */
|
||||
#pragma weak zpool_unmount_datasets = zpool_disable_datasets
|
||||
/*
|
||||
* Unshare and unmount all datasets within the given pool. We don't want to
|
||||
* rely on traversing the DSL to discover the filesystems within the pool,
|
||||
@@ -1253,7 +1138,6 @@ mountpoint_compare(const void *a, const void *b)
|
||||
* arbitrarily (on I/O error, for example). Instead, we walk /etc/mnttab and
|
||||
* gather all the filesystems that are currently mounted.
|
||||
*/
|
||||
#pragma weak zpool_unmount_datasets = zpool_disable_datasets
|
||||
int
|
||||
zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force)
|
||||
{
|
||||
@@ -1267,12 +1151,6 @@ zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force)
|
||||
int ret = -1;
|
||||
int flags = (force ? MS_FORCE : 0);
|
||||
|
||||
/*
|
||||
* First unshare all zvols.
|
||||
*/
|
||||
if (zpool_iter_zvol(zhp, zvol_cb, hdl) != 0)
|
||||
return (-1);
|
||||
|
||||
namelen = strlen(zhp->zpool_name);
|
||||
|
||||
rewind(hdl->libzfs_mnttab);
|
||||
|
||||
+686
-257
File diff suppressed because it is too large
Load Diff
+1019
-206
File diff suppressed because it is too large
Load Diff
+80
-12
@@ -19,8 +19,7 @@
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -138,7 +137,7 @@ find_vdev_problem(nvlist_t *vdev, int (*func)(uint64_t, uint64_t, uint64_t))
|
||||
if (find_vdev_problem(child[c], func))
|
||||
return (B_TRUE);
|
||||
} else {
|
||||
verify(nvlist_lookup_uint64_array(vdev, ZPOOL_CONFIG_STATS,
|
||||
verify(nvlist_lookup_uint64_array(vdev, ZPOOL_CONFIG_VDEV_STATS,
|
||||
(uint64_t **)&vs, &c) == 0);
|
||||
|
||||
if (func(vs->vs_state, vs->vs_aux,
|
||||
@@ -173,7 +172,8 @@ check_status(nvlist_t *config, boolean_t isimport)
|
||||
{
|
||||
nvlist_t *nvroot;
|
||||
vdev_stat_t *vs;
|
||||
uint_t vsc;
|
||||
pool_scan_stat_t *ps = NULL;
|
||||
uint_t vsc, psc;
|
||||
uint64_t nerr;
|
||||
uint64_t version;
|
||||
uint64_t stateval;
|
||||
@@ -184,15 +184,24 @@ check_status(nvlist_t *config, boolean_t isimport)
|
||||
&version) == 0);
|
||||
verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
|
||||
&nvroot) == 0);
|
||||
verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
|
||||
verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
|
||||
(uint64_t **)&vs, &vsc) == 0);
|
||||
verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
|
||||
&stateval) == 0);
|
||||
(void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, &hostid);
|
||||
|
||||
/*
|
||||
* Currently resilvering a vdev
|
||||
*/
|
||||
(void) nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_SCAN_STATS,
|
||||
(uint64_t **)&ps, &psc);
|
||||
if (ps && ps->pss_func == POOL_SCAN_RESILVER &&
|
||||
ps->pss_state == DSS_SCANNING)
|
||||
return (ZPOOL_STATUS_RESILVERING);
|
||||
|
||||
/*
|
||||
* Pool last accessed by another system.
|
||||
*/
|
||||
(void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, &hostid);
|
||||
if (hostid != 0 && (unsigned long)hostid != gethostid() &&
|
||||
stateval == POOL_STATE_ACTIVE)
|
||||
return (ZPOOL_STATUS_HOSTID_MISMATCH);
|
||||
@@ -288,12 +297,6 @@ check_status(nvlist_t *config, boolean_t isimport)
|
||||
if (find_vdev_problem(nvroot, vdev_removed))
|
||||
return (ZPOOL_STATUS_REMOVED_DEV);
|
||||
|
||||
/*
|
||||
* Currently resilvering
|
||||
*/
|
||||
if (!vs->vs_scrub_complete && vs->vs_scrub_type == POOL_SCRUB_RESILVER)
|
||||
return (ZPOOL_STATUS_RESILVERING);
|
||||
|
||||
/*
|
||||
* Outdated, but usable, version
|
||||
*/
|
||||
@@ -328,3 +331,68 @@ zpool_import_status(nvlist_t *config, char **msgid)
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static void
|
||||
dump_ddt_stat(const ddt_stat_t *dds, int h)
|
||||
{
|
||||
char refcnt[6];
|
||||
char blocks[6], lsize[6], psize[6], dsize[6];
|
||||
char ref_blocks[6], ref_lsize[6], ref_psize[6], ref_dsize[6];
|
||||
|
||||
if (dds == NULL || dds->dds_blocks == 0)
|
||||
return;
|
||||
|
||||
if (h == -1)
|
||||
(void) strcpy(refcnt, "Total");
|
||||
else
|
||||
zfs_nicenum(1ULL << h, refcnt, sizeof (refcnt));
|
||||
|
||||
zfs_nicenum(dds->dds_blocks, blocks, sizeof (blocks));
|
||||
zfs_nicenum(dds->dds_lsize, lsize, sizeof (lsize));
|
||||
zfs_nicenum(dds->dds_psize, psize, sizeof (psize));
|
||||
zfs_nicenum(dds->dds_dsize, dsize, sizeof (dsize));
|
||||
zfs_nicenum(dds->dds_ref_blocks, ref_blocks, sizeof (ref_blocks));
|
||||
zfs_nicenum(dds->dds_ref_lsize, ref_lsize, sizeof (ref_lsize));
|
||||
zfs_nicenum(dds->dds_ref_psize, ref_psize, sizeof (ref_psize));
|
||||
zfs_nicenum(dds->dds_ref_dsize, ref_dsize, sizeof (ref_dsize));
|
||||
|
||||
(void) printf("%6s %6s %5s %5s %5s %6s %5s %5s %5s\n",
|
||||
refcnt,
|
||||
blocks, lsize, psize, dsize,
|
||||
ref_blocks, ref_lsize, ref_psize, ref_dsize);
|
||||
}
|
||||
|
||||
/*
|
||||
* Print the DDT histogram and the column totals.
|
||||
*/
|
||||
void
|
||||
zpool_dump_ddt(const ddt_stat_t *dds_total, const ddt_histogram_t *ddh)
|
||||
{
|
||||
int h;
|
||||
|
||||
(void) printf("\n");
|
||||
|
||||
(void) printf("bucket "
|
||||
" allocated "
|
||||
" referenced \n");
|
||||
(void) printf("______ "
|
||||
"______________________________ "
|
||||
"______________________________\n");
|
||||
|
||||
(void) printf("%6s %6s %5s %5s %5s %6s %5s %5s %5s\n",
|
||||
"refcnt",
|
||||
"blocks", "LSIZE", "PSIZE", "DSIZE",
|
||||
"blocks", "LSIZE", "PSIZE", "DSIZE");
|
||||
|
||||
(void) printf("%6s %6s %5s %5s %5s %6s %5s %5s %5s\n",
|
||||
"------",
|
||||
"------", "-----", "-----", "-----",
|
||||
"------", "-----", "-----", "-----");
|
||||
|
||||
for (h = 0; h < 64; h++)
|
||||
dump_ddt_stat(&ddh->ddh_stat[h], h);
|
||||
|
||||
dump_ddt_stat(dds_total, -1);
|
||||
|
||||
(void) printf("\n");
|
||||
}
|
||||
|
||||
+49
-26
@@ -19,8 +19,7 @@
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -94,8 +93,6 @@ libzfs_error_description(libzfs_handle_t *hdl)
|
||||
case EZFS_VOLTOOBIG:
|
||||
return (dgettext(TEXT_DOMAIN, "volume size exceeds limit for "
|
||||
"this system"));
|
||||
case EZFS_VOLHASDATA:
|
||||
return (dgettext(TEXT_DOMAIN, "volume has data"));
|
||||
case EZFS_INVALIDNAME:
|
||||
return (dgettext(TEXT_DOMAIN, "invalid name"));
|
||||
case EZFS_BADRESTORE:
|
||||
@@ -138,16 +135,12 @@ libzfs_error_description(libzfs_handle_t *hdl)
|
||||
return (dgettext(TEXT_DOMAIN, "smb remove share failed"));
|
||||
case EZFS_SHARESMBFAILED:
|
||||
return (dgettext(TEXT_DOMAIN, "smb add share failed"));
|
||||
case EZFS_ISCSISVCUNAVAIL:
|
||||
return (dgettext(TEXT_DOMAIN,
|
||||
"iscsitgt service need to be enabled by "
|
||||
"a privileged user"));
|
||||
case EZFS_DEVLINKS:
|
||||
return (dgettext(TEXT_DOMAIN, "failed to create /dev links"));
|
||||
case EZFS_PERM:
|
||||
return (dgettext(TEXT_DOMAIN, "permission denied"));
|
||||
case EZFS_NOSPC:
|
||||
return (dgettext(TEXT_DOMAIN, "out of space"));
|
||||
case EZFS_FAULT:
|
||||
return (dgettext(TEXT_DOMAIN, "bad address"));
|
||||
case EZFS_IO:
|
||||
return (dgettext(TEXT_DOMAIN, "I/O error"));
|
||||
case EZFS_INTR:
|
||||
@@ -161,12 +154,6 @@ libzfs_error_description(libzfs_handle_t *hdl)
|
||||
return (dgettext(TEXT_DOMAIN, "recursive dataset dependency"));
|
||||
case EZFS_NOHISTORY:
|
||||
return (dgettext(TEXT_DOMAIN, "no history available"));
|
||||
case EZFS_UNSHAREISCSIFAILED:
|
||||
return (dgettext(TEXT_DOMAIN,
|
||||
"iscsitgtd failed request to unshare"));
|
||||
case EZFS_SHAREISCSIFAILED:
|
||||
return (dgettext(TEXT_DOMAIN,
|
||||
"iscsitgtd failed request to share"));
|
||||
case EZFS_POOLPROPS:
|
||||
return (dgettext(TEXT_DOMAIN, "failed to retrieve "
|
||||
"pool properties"));
|
||||
@@ -218,6 +205,20 @@ libzfs_error_description(libzfs_handle_t *hdl)
|
||||
case EZFS_REFTAG_HOLD:
|
||||
return (dgettext(TEXT_DOMAIN, "tag already exists on this "
|
||||
"dataset"));
|
||||
case EZFS_TAGTOOLONG:
|
||||
return (dgettext(TEXT_DOMAIN, "tag too long"));
|
||||
case EZFS_PIPEFAILED:
|
||||
return (dgettext(TEXT_DOMAIN, "pipe create failed"));
|
||||
case EZFS_THREADCREATEFAILED:
|
||||
return (dgettext(TEXT_DOMAIN, "thread create failed"));
|
||||
case EZFS_POSTSPLIT_ONLINE:
|
||||
return (dgettext(TEXT_DOMAIN, "disk was split from this pool "
|
||||
"into a new one"));
|
||||
case EZFS_SCRUBBING:
|
||||
return (dgettext(TEXT_DOMAIN, "currently scrubbing; "
|
||||
"use 'zpool scrub -s' to cancel current scrub"));
|
||||
case EZFS_NO_SCRUB:
|
||||
return (dgettext(TEXT_DOMAIN, "there is no active scrub"));
|
||||
case EZFS_UNKNOWN:
|
||||
return (dgettext(TEXT_DOMAIN, "unknown error"));
|
||||
default:
|
||||
@@ -306,6 +307,10 @@ zfs_common_error(libzfs_handle_t *hdl, int error, const char *fmt,
|
||||
zfs_verror(hdl, EZFS_IO, fmt, ap);
|
||||
return (-1);
|
||||
|
||||
case EFAULT:
|
||||
zfs_verror(hdl, EZFS_FAULT, fmt, ap);
|
||||
return (-1);
|
||||
|
||||
case EINTR:
|
||||
zfs_verror(hdl, EZFS_INTR, fmt, ap);
|
||||
return (-1);
|
||||
@@ -378,7 +383,7 @@ zfs_standard_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...)
|
||||
zfs_verror(hdl, EZFS_POOLUNAVAIL, fmt, ap);
|
||||
break;
|
||||
default:
|
||||
zfs_error_aux(hdl, strerror(errno));
|
||||
zfs_error_aux(hdl, strerror(error));
|
||||
zfs_verror(hdl, EZFS_UNKNOWN, fmt, ap);
|
||||
break;
|
||||
}
|
||||
@@ -610,6 +615,7 @@ libzfs_fini(libzfs_handle_t *hdl)
|
||||
if (hdl->libzfs_log_str)
|
||||
(void) free(hdl->libzfs_log_str);
|
||||
zpool_free_handles(hdl);
|
||||
libzfs_fru_clear(hdl, B_TRUE);
|
||||
namespace_clear(hdl);
|
||||
libzfs_mnttab_fini(hdl);
|
||||
free(hdl);
|
||||
@@ -686,7 +692,7 @@ int
|
||||
zcmd_alloc_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, size_t len)
|
||||
{
|
||||
if (len == 0)
|
||||
len = 2048;
|
||||
len = 4*1024;
|
||||
zc->zc_nvlist_dst_size = len;
|
||||
if ((zc->zc_nvlist_dst = (uint64_t)(uintptr_t)
|
||||
zfs_alloc(hdl, zc->zc_nvlist_dst_size)) == NULL)
|
||||
@@ -812,6 +818,8 @@ zprop_print_headers(zprop_get_cbdata_t *cbp, zfs_type_t type)
|
||||
"PROPERTY"));
|
||||
cbp->cb_colwidths[GET_COL_VALUE] = strlen(dgettext(TEXT_DOMAIN,
|
||||
"VALUE"));
|
||||
cbp->cb_colwidths[GET_COL_RECVD] = strlen(dgettext(TEXT_DOMAIN,
|
||||
"RECEIVED"));
|
||||
cbp->cb_colwidths[GET_COL_SOURCE] = strlen(dgettext(TEXT_DOMAIN,
|
||||
"SOURCE"));
|
||||
|
||||
@@ -825,7 +833,7 @@ zprop_print_headers(zprop_get_cbdata_t *cbp, zfs_type_t type)
|
||||
* inheriting from the longest name. This is acceptable because in the
|
||||
* majority of cases 'SOURCE' is the last column displayed, and we don't
|
||||
* use the width anyway. Note that the 'VALUE' column can be oversized,
|
||||
* if the name of the property is much longer the any values we find.
|
||||
* if the name of the property is much longer than any values we find.
|
||||
*/
|
||||
for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
|
||||
/*
|
||||
@@ -856,6 +864,11 @@ zprop_print_headers(zprop_get_cbdata_t *cbp, zfs_type_t type)
|
||||
pl->pl_width > cbp->cb_colwidths[GET_COL_VALUE])
|
||||
cbp->cb_colwidths[GET_COL_VALUE] = pl->pl_width;
|
||||
|
||||
/* 'RECEIVED' column. */
|
||||
if (pl != cbp->cb_proplist &&
|
||||
pl->pl_recvd_width > cbp->cb_colwidths[GET_COL_RECVD])
|
||||
cbp->cb_colwidths[GET_COL_RECVD] = pl->pl_recvd_width;
|
||||
|
||||
/*
|
||||
* 'NAME' and 'SOURCE' columns
|
||||
*/
|
||||
@@ -871,7 +884,7 @@ zprop_print_headers(zprop_get_cbdata_t *cbp, zfs_type_t type)
|
||||
/*
|
||||
* Now go through and print the headers.
|
||||
*/
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (i = 0; i < ZFS_GET_NCOLS; i++) {
|
||||
switch (cbp->cb_columns[i]) {
|
||||
case GET_COL_NAME:
|
||||
title = dgettext(TEXT_DOMAIN, "NAME");
|
||||
@@ -882,6 +895,9 @@ zprop_print_headers(zprop_get_cbdata_t *cbp, zfs_type_t type)
|
||||
case GET_COL_VALUE:
|
||||
title = dgettext(TEXT_DOMAIN, "VALUE");
|
||||
break;
|
||||
case GET_COL_RECVD:
|
||||
title = dgettext(TEXT_DOMAIN, "RECEIVED");
|
||||
break;
|
||||
case GET_COL_SOURCE:
|
||||
title = dgettext(TEXT_DOMAIN, "SOURCE");
|
||||
break;
|
||||
@@ -890,7 +906,8 @@ zprop_print_headers(zprop_get_cbdata_t *cbp, zfs_type_t type)
|
||||
}
|
||||
|
||||
if (title != NULL) {
|
||||
if (i == 3 || cbp->cb_columns[i + 1] == 0)
|
||||
if (i == (ZFS_GET_NCOLS - 1) ||
|
||||
cbp->cb_columns[i + 1] == GET_COL_NONE)
|
||||
(void) printf("%s", title);
|
||||
else
|
||||
(void) printf("%-*s ",
|
||||
@@ -908,7 +925,7 @@ zprop_print_headers(zprop_get_cbdata_t *cbp, zfs_type_t type)
|
||||
void
|
||||
zprop_print_one_property(const char *name, zprop_get_cbdata_t *cbp,
|
||||
const char *propname, const char *value, zprop_source_t sourcetype,
|
||||
const char *source)
|
||||
const char *source, const char *recvd_value)
|
||||
{
|
||||
int i;
|
||||
const char *str;
|
||||
@@ -923,7 +940,7 @@ zprop_print_one_property(const char *name, zprop_get_cbdata_t *cbp,
|
||||
if (cbp->cb_first)
|
||||
zprop_print_headers(cbp, cbp->cb_type);
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (i = 0; i < ZFS_GET_NCOLS; i++) {
|
||||
switch (cbp->cb_columns[i]) {
|
||||
case GET_COL_NAME:
|
||||
str = name;
|
||||
@@ -960,14 +977,21 @@ zprop_print_one_property(const char *name, zprop_get_cbdata_t *cbp,
|
||||
"inherited from %s", source);
|
||||
str = buf;
|
||||
break;
|
||||
case ZPROP_SRC_RECEIVED:
|
||||
str = "received";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case GET_COL_RECVD:
|
||||
str = (recvd_value == NULL ? "-" : recvd_value);
|
||||
break;
|
||||
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cbp->cb_columns[i + 1] == 0)
|
||||
if (cbp->cb_columns[i + 1] == GET_COL_NONE)
|
||||
(void) printf("%s", str);
|
||||
else if (cbp->cb_scripted)
|
||||
(void) printf("%s\t", str);
|
||||
@@ -975,7 +999,6 @@ zprop_print_one_property(const char *name, zprop_get_cbdata_t *cbp,
|
||||
(void) printf("%-*s ",
|
||||
cbp->cb_colwidths[cbp->cb_columns[i]],
|
||||
str);
|
||||
|
||||
}
|
||||
|
||||
(void) printf("\n");
|
||||
@@ -1037,7 +1060,7 @@ zfs_nicestrtonum(libzfs_handle_t *hdl, const char *value, uint64_t *num)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Rely on stroull() to process the numeric portion. */
|
||||
/* Rely on strtoull() to process the numeric portion. */
|
||||
errno = 0;
|
||||
*num = strtoull(value, &end, 10);
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
|
||||
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
@@ -75,6 +75,7 @@ extern "C" {
|
||||
#include <sys/u8_textprep.h>
|
||||
#include <sys/sysevent/eventdefs.h>
|
||||
#include <sys/sysevent/dev.h>
|
||||
#include <sys/sunddi.h>
|
||||
|
||||
/*
|
||||
* Debugging
|
||||
@@ -105,21 +106,27 @@ extern void vpanic(const char *, __va_list);
|
||||
|
||||
#define fm_panic panic
|
||||
|
||||
extern int aok;
|
||||
|
||||
/* This definition is copied from assert.h. */
|
||||
#if defined(__STDC__)
|
||||
#if __STDC_VERSION__ - 0 >= 199901L
|
||||
#define verify(EX) (void)((EX) || \
|
||||
#define zverify(EX) (void)((EX) || (aok) || \
|
||||
(__assert_c99(#EX, __FILE__, __LINE__, __func__), 0))
|
||||
#else
|
||||
#define verify(EX) (void)((EX) || (__assert(#EX, __FILE__, __LINE__), 0))
|
||||
#define zverify(EX) (void)((EX) || (aok) || \
|
||||
(__assert(#EX, __FILE__, __LINE__), 0))
|
||||
#endif /* __STDC_VERSION__ - 0 >= 199901L */
|
||||
#else
|
||||
#define verify(EX) (void)((EX) || (_assert("EX", __FILE__, __LINE__), 0))
|
||||
#define zverify(EX) (void)((EX) || (aok) || \
|
||||
(_assert("EX", __FILE__, __LINE__), 0))
|
||||
#endif /* __STDC__ */
|
||||
|
||||
|
||||
#define VERIFY verify
|
||||
#define ASSERT assert
|
||||
#define VERIFY zverify
|
||||
#define ASSERT zverify
|
||||
#undef assert
|
||||
#define assert zverify
|
||||
|
||||
extern void __assert(const char *, const char *, int);
|
||||
|
||||
@@ -130,7 +137,7 @@ extern void __assert(const char *, const char *, int);
|
||||
#define VERIFY3_IMPL(LEFT, OP, RIGHT, TYPE) do { \
|
||||
const TYPE __left = (TYPE)(LEFT); \
|
||||
const TYPE __right = (TYPE)(RIGHT); \
|
||||
if (!(__left OP __right)) { \
|
||||
if (!(__left OP __right) && (!aok)) { \
|
||||
char *__buf = alloca(256); \
|
||||
(void) snprintf(__buf, 256, "%s %s %s (0x%llx %s 0x%llx)", \
|
||||
#LEFT, #OP, #RIGHT, \
|
||||
@@ -196,6 +203,18 @@ typedef struct kthread kthread_t;
|
||||
#define thread_create(stk, stksize, func, arg, len, pp, state, pri) \
|
||||
zk_thread_create(func, arg)
|
||||
#define thread_exit() thr_exit(NULL)
|
||||
#define thread_join(t) panic("libzpool cannot join threads")
|
||||
|
||||
#define newproc(f, a, cid, pri, ctp, pid) (ENOSYS)
|
||||
|
||||
/* in libzpool, p0 exists only to have its address taken */
|
||||
struct proc {
|
||||
uintptr_t this_is_never_used_dont_dereference_it;
|
||||
};
|
||||
|
||||
extern struct proc p0;
|
||||
|
||||
#define PS_NONE -1
|
||||
|
||||
extern kthread_t *zk_thread_create(void (*func)(), void *arg);
|
||||
|
||||
@@ -318,20 +337,27 @@ typedef void (task_func_t)(void *);
|
||||
#define TASKQ_PREPOPULATE 0x0001
|
||||
#define TASKQ_CPR_SAFE 0x0002 /* Use CPR safe protocol */
|
||||
#define TASKQ_DYNAMIC 0x0004 /* Use dynamic thread scheduling */
|
||||
#define TASKQ_THREADS_CPU_PCT 0x0008 /* Use dynamic thread scheduling */
|
||||
#define TASKQ_THREADS_CPU_PCT 0x0008 /* Scale # threads by # cpus */
|
||||
#define TASKQ_DC_BATCH 0x0010 /* Mark threads as batch */
|
||||
|
||||
#define TQ_SLEEP KM_SLEEP /* Can block for memory */
|
||||
#define TQ_NOSLEEP KM_NOSLEEP /* cannot block for memory; may fail */
|
||||
#define TQ_NOQUEUE 0x02 /* Do not enqueue if can't dispatch */
|
||||
#define TQ_NOQUEUE 0x02 /* Do not enqueue if can't dispatch */
|
||||
#define TQ_FRONT 0x08 /* Queue in front */
|
||||
|
||||
extern taskq_t *system_taskq;
|
||||
|
||||
extern taskq_t *taskq_create(const char *, int, pri_t, int, int, uint_t);
|
||||
#define taskq_create_proc(a, b, c, d, e, p, f) \
|
||||
(taskq_create(a, b, c, d, e, f))
|
||||
#define taskq_create_sysdc(a, b, d, e, p, dc, f) \
|
||||
(taskq_create(a, b, maxclsyspri, d, e, f))
|
||||
extern taskqid_t taskq_dispatch(taskq_t *, task_func_t, void *, uint_t);
|
||||
extern void taskq_destroy(taskq_t *);
|
||||
extern void taskq_wait(taskq_t *);
|
||||
extern int taskq_member(taskq_t *, void *);
|
||||
extern void system_taskq_init(void);
|
||||
extern void system_taskq_fini(void);
|
||||
|
||||
#define XVA_MAPSIZE 3
|
||||
#define XVA_MAGIC 0x78766174
|
||||
@@ -345,6 +371,7 @@ typedef struct vnode {
|
||||
char *v_path;
|
||||
} vnode_t;
|
||||
|
||||
#define AV_SCANSTAMP_SZ 32 /* length of anti-virus scanstamp */
|
||||
|
||||
typedef struct xoptattr {
|
||||
timestruc_t xoa_createtime; /* Create time of file */
|
||||
@@ -360,6 +387,8 @@ typedef struct xoptattr {
|
||||
uint8_t xoa_opaque;
|
||||
uint8_t xoa_av_quarantined;
|
||||
uint8_t xoa_av_modified;
|
||||
uint8_t xoa_av_scanstamp[AV_SCANSTAMP_SZ];
|
||||
uint8_t xoa_reparse;
|
||||
} xoptattr_t;
|
||||
|
||||
typedef struct vattr {
|
||||
@@ -406,9 +435,11 @@ typedef struct vsecattr {
|
||||
|
||||
#define CRCREAT 0
|
||||
|
||||
extern int fop_getattr(vnode_t *vp, vattr_t *vap);
|
||||
|
||||
#define VOP_CLOSE(vp, f, c, o, cr, ct) 0
|
||||
#define VOP_PUTPAGE(vp, of, sz, fl, cr, ct) 0
|
||||
#define VOP_GETATTR(vp, vap, fl, cr, ct) ((vap)->va_size = (vp)->v_size, 0)
|
||||
#define VOP_GETATTR(vp, vap, fl, cr, ct) fop_getattr((vp), (vap));
|
||||
|
||||
#define VOP_FSYNC(vp, f, cr, ct) fsync((vp)->v_fd)
|
||||
|
||||
@@ -433,13 +464,18 @@ extern vnode_t *rootdir;
|
||||
/*
|
||||
* Random stuff
|
||||
*/
|
||||
#define lbolt (gethrtime() >> 23)
|
||||
#define lbolt64 (gethrtime() >> 23)
|
||||
#define ddi_get_lbolt() (gethrtime() >> 23)
|
||||
#define ddi_get_lbolt64() (gethrtime() >> 23)
|
||||
#define hz 119 /* frequency when using gethrtime() >> 23 for lbolt */
|
||||
|
||||
extern void delay(clock_t ticks);
|
||||
|
||||
#define gethrestime_sec() time(NULL)
|
||||
#define gethrestime(t) \
|
||||
do {\
|
||||
(t)->tv_sec = gethrestime_sec();\
|
||||
(t)->tv_nsec = 0;\
|
||||
} while (0);
|
||||
|
||||
#define max_ncpus 64
|
||||
|
||||
@@ -490,6 +526,9 @@ typedef struct callb_cpr {
|
||||
#define zone_dataset_visible(x, y) (1)
|
||||
#define INGLOBALZONE(z) (1)
|
||||
|
||||
extern char *kmem_asprintf(const char *fmt, ...);
|
||||
#define strfree(str) kmem_free((str), strlen(str)+1)
|
||||
|
||||
/*
|
||||
* Hostname information
|
||||
*/
|
||||
@@ -497,6 +536,9 @@ extern char hw_serial[]; /* for userland-emulated hostid access */
|
||||
extern int ddi_strtoul(const char *str, char **nptr, int base,
|
||||
unsigned long *result);
|
||||
|
||||
extern int ddi_strtoull(const char *str, char **nptr, int base,
|
||||
u_longlong_t *result);
|
||||
|
||||
/* ZFS Boot Related stuff. */
|
||||
|
||||
struct _buf {
|
||||
|
||||
+63
-3
@@ -19,7 +19,7 @@
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
|
||||
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
* Emulation of kernel services in userland.
|
||||
*/
|
||||
|
||||
int aok;
|
||||
uint64_t physmem;
|
||||
vnode_t *rootdir = (vnode_t *)0xabcd1234;
|
||||
char hw_serial[HW_HOSTID_LEN];
|
||||
@@ -50,6 +51,9 @@ struct utsname utsname = {
|
||||
"userland", "libzpool", "1", "1", "na"
|
||||
};
|
||||
|
||||
/* this only exists to have its address taken */
|
||||
struct proc p0;
|
||||
|
||||
/*
|
||||
* =========================================================================
|
||||
* threads
|
||||
@@ -269,7 +273,7 @@ cv_timedwait(kcondvar_t *cv, kmutex_t *mp, clock_t abstime)
|
||||
clock_t delta;
|
||||
|
||||
top:
|
||||
delta = abstime - lbolt;
|
||||
delta = abstime - ddi_get_lbolt();
|
||||
if (delta <= 0)
|
||||
return (-1);
|
||||
|
||||
@@ -444,6 +448,24 @@ vn_close(vnode_t *vp)
|
||||
umem_free(vp, sizeof (vnode_t));
|
||||
}
|
||||
|
||||
/*
|
||||
* At a minimum we need to update the size since vdev_reopen()
|
||||
* will no longer call vn_openat().
|
||||
*/
|
||||
int
|
||||
fop_getattr(vnode_t *vp, vattr_t *vap)
|
||||
{
|
||||
struct stat64 st;
|
||||
|
||||
if (fstat64(vp->v_fd, &st) == -1) {
|
||||
close(vp->v_fd);
|
||||
return (errno);
|
||||
}
|
||||
|
||||
vap->va_size = st.st_size;
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifdef ZFS_DEBUG
|
||||
|
||||
/*
|
||||
@@ -754,6 +776,17 @@ ddi_strtoul(const char *hw_serial, char **nptr, int base, unsigned long *result)
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
ddi_strtoull(const char *str, char **nptr, int base, u_longlong_t *result)
|
||||
{
|
||||
char *end;
|
||||
|
||||
*result = strtoull(str, &end, base);
|
||||
if (*result == 0)
|
||||
return (errno);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* =========================================================================
|
||||
* kernel emulation setup & teardown
|
||||
@@ -779,7 +812,8 @@ kernel_init(int mode)
|
||||
dprintf("physmem = %llu pages (%.2f GB)\n", physmem,
|
||||
(double)physmem * sysconf(_SC_PAGE_SIZE) / (1ULL << 30));
|
||||
|
||||
(void) snprintf(hw_serial, sizeof (hw_serial), "%ld", gethostid());
|
||||
(void) snprintf(hw_serial, sizeof (hw_serial), "%ld",
|
||||
(mode & FWRITE) ? gethostid() : 0);
|
||||
|
||||
VERIFY((random_fd = open("/dev/random", O_RDONLY)) != -1);
|
||||
VERIFY((urandom_fd = open("/dev/urandom", O_RDONLY)) != -1);
|
||||
@@ -794,6 +828,8 @@ kernel_fini(void)
|
||||
{
|
||||
spa_fini();
|
||||
|
||||
system_taskq_fini();
|
||||
|
||||
close(random_fd);
|
||||
close(urandom_fd);
|
||||
|
||||
@@ -884,3 +920,27 @@ ksiddomain_rele(ksiddomain_t *ksid)
|
||||
spa_strfree(ksid->kd_name);
|
||||
umem_free(ksid, sizeof (ksiddomain_t));
|
||||
}
|
||||
|
||||
/*
|
||||
* Do not change the length of the returned string; it must be freed
|
||||
* with strfree().
|
||||
*/
|
||||
char *
|
||||
kmem_asprintf(const char *fmt, ...)
|
||||
{
|
||||
int size;
|
||||
va_list adx;
|
||||
char *buf;
|
||||
|
||||
va_start(adx, fmt);
|
||||
size = vsnprintf(NULL, 0, fmt, adx) + 1;
|
||||
va_end(adx);
|
||||
|
||||
buf = kmem_alloc(size, KM_SLEEP);
|
||||
|
||||
va_start(adx, fmt);
|
||||
size = vsnprintf(buf, size, fmt, adx);
|
||||
va_end(adx);
|
||||
|
||||
return (buf);
|
||||
}
|
||||
|
||||
+39
-10
@@ -19,7 +19,7 @@
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
|
||||
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
@@ -49,6 +49,8 @@ struct taskq {
|
||||
int tq_nalloc;
|
||||
int tq_minalloc;
|
||||
int tq_maxalloc;
|
||||
kcondvar_t tq_maxalloc_cv;
|
||||
int tq_maxalloc_wait;
|
||||
task_t *tq_freelist;
|
||||
task_t tq_task;
|
||||
};
|
||||
@@ -57,26 +59,36 @@ static task_t *
|
||||
task_alloc(taskq_t *tq, int tqflags)
|
||||
{
|
||||
task_t *t;
|
||||
int rv;
|
||||
|
||||
if ((t = tq->tq_freelist) != NULL && tq->tq_nalloc >= tq->tq_minalloc) {
|
||||
again: if ((t = tq->tq_freelist) != NULL && tq->tq_nalloc >= tq->tq_minalloc) {
|
||||
tq->tq_freelist = t->task_next;
|
||||
} else {
|
||||
mutex_exit(&tq->tq_lock);
|
||||
if (tq->tq_nalloc >= tq->tq_maxalloc) {
|
||||
if (!(tqflags & KM_SLEEP)) {
|
||||
mutex_enter(&tq->tq_lock);
|
||||
if (!(tqflags & KM_SLEEP))
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't want to exceed tq_maxalloc, but we can't
|
||||
* wait for other tasks to complete (and thus free up
|
||||
* task structures) without risking deadlock with
|
||||
* the caller. So, we just delay for one second
|
||||
* to throttle the allocation rate.
|
||||
* to throttle the allocation rate. If we have tasks
|
||||
* complete before one second timeout expires then
|
||||
* taskq_ent_free will signal us and we will
|
||||
* immediately retry the allocation.
|
||||
*/
|
||||
delay(hz);
|
||||
tq->tq_maxalloc_wait++;
|
||||
rv = cv_timedwait(&tq->tq_maxalloc_cv,
|
||||
&tq->tq_lock, ddi_get_lbolt() + hz);
|
||||
tq->tq_maxalloc_wait--;
|
||||
if (rv > 0)
|
||||
goto again; /* signaled */
|
||||
}
|
||||
mutex_exit(&tq->tq_lock);
|
||||
|
||||
t = kmem_alloc(sizeof (task_t), tqflags);
|
||||
|
||||
mutex_enter(&tq->tq_lock);
|
||||
if (t != NULL)
|
||||
tq->tq_nalloc++;
|
||||
@@ -96,6 +108,9 @@ task_free(taskq_t *tq, task_t *t)
|
||||
kmem_free(t, sizeof (task_t));
|
||||
mutex_enter(&tq->tq_lock);
|
||||
}
|
||||
|
||||
if (tq->tq_maxalloc_wait)
|
||||
cv_signal(&tq->tq_maxalloc_cv);
|
||||
}
|
||||
|
||||
taskqid_t
|
||||
@@ -114,8 +129,13 @@ taskq_dispatch(taskq_t *tq, task_func_t func, void *arg, uint_t tqflags)
|
||||
mutex_exit(&tq->tq_lock);
|
||||
return (0);
|
||||
}
|
||||
t->task_next = &tq->tq_task;
|
||||
t->task_prev = tq->tq_task.task_prev;
|
||||
if (tqflags & TQ_FRONT) {
|
||||
t->task_next = tq->tq_task.task_next;
|
||||
t->task_prev = &tq->tq_task;
|
||||
} else {
|
||||
t->task_next = &tq->tq_task;
|
||||
t->task_prev = tq->tq_task.task_prev;
|
||||
}
|
||||
t->task_next->task_prev = t;
|
||||
t->task_prev->task_next = t;
|
||||
t->task_func = func;
|
||||
@@ -191,6 +211,7 @@ taskq_create(const char *name, int nthreads, pri_t pri,
|
||||
mutex_init(&tq->tq_lock, NULL, MUTEX_DEFAULT, NULL);
|
||||
cv_init(&tq->tq_dispatch_cv, NULL, CV_DEFAULT, NULL);
|
||||
cv_init(&tq->tq_wait_cv, NULL, CV_DEFAULT, NULL);
|
||||
cv_init(&tq->tq_maxalloc_cv, NULL, CV_DEFAULT, NULL);
|
||||
tq->tq_flags = flags | TASKQ_ACTIVE;
|
||||
tq->tq_active = nthreads;
|
||||
tq->tq_nthreads = nthreads;
|
||||
@@ -247,6 +268,7 @@ taskq_destroy(taskq_t *tq)
|
||||
mutex_destroy(&tq->tq_lock);
|
||||
cv_destroy(&tq->tq_dispatch_cv);
|
||||
cv_destroy(&tq->tq_wait_cv);
|
||||
cv_destroy(&tq->tq_maxalloc_cv);
|
||||
|
||||
kmem_free(tq, sizeof (taskq_t));
|
||||
}
|
||||
@@ -272,3 +294,10 @@ system_taskq_init(void)
|
||||
system_taskq = taskq_create("system_taskq", 64, minclsyspri, 4, 512,
|
||||
TASKQ_DYNAMIC | TASKQ_PREPOPULATE);
|
||||
}
|
||||
|
||||
void
|
||||
system_taskq_fini(void)
|
||||
{
|
||||
taskq_destroy(system_taskq);
|
||||
system_taskq = NULL; /* defensive */
|
||||
}
|
||||
|
||||
+2
-3
@@ -19,8 +19,7 @@
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
@@ -90,7 +89,7 @@ show_vdev_stats(const char *desc, const char *ctype, nvlist_t *nv, int indent)
|
||||
if (is_log)
|
||||
prefix = "log ";
|
||||
|
||||
if (nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
|
||||
if (nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
|
||||
(uint64_t **)&vs, &c) != 0)
|
||||
vs = &v0;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user