1 /* 2 * 3 * CDDL HEADER START 4 * 5 * The contents of this file are subject to the terms of the 6 * Common Development and Distribution License (the "License"). 7 * You may not use this file except in compliance with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 25 */ 26 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <string.h> 30 #include <errno.h> 31 #include <ctype.h> 32 #include <alloca.h> 33 #include <limits.h> 34 #include <fm/topo_mod.h> 35 #include <sys/param.h> 36 #include <sys/systeminfo.h> 37 #include <sys/fm/protocol.h> 38 #include <sys/stat.h> 39 40 #include <topo_method.h> 41 #include <topo_subr.h> 42 #include <libzfs.h> 43 #include <zfs.h> 44 45 static int zfs_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t, 46 topo_instance_t, void *, void *); 47 static void zfs_rele(topo_mod_t *, tnode_t *); 48 static int zfs_fmri_nvl2str(topo_mod_t *, tnode_t *, topo_version_t, 49 nvlist_t *, nvlist_t **); 50 51 const topo_method_t zfs_methods[] = { 52 { TOPO_METH_NVL2STR, TOPO_METH_NVL2STR_DESC, TOPO_METH_NVL2STR_VERSION, 53 TOPO_STABILITY_INTERNAL, zfs_fmri_nvl2str }, 54 { NULL } 55 }; 56 57 static const topo_modops_t zfs_ops = 58 { zfs_enum, zfs_rele }; 59 static const topo_modinfo_t zfs_info = 60 { ZFS, FM_FMRI_SCHEME_ZFS, ZFS_VERSION, &zfs_ops }; 61 62 static libzfs_handle_t *g_zfs; 63 64 int 65 zfs_init(topo_mod_t *mod, topo_version_t version) 66 { 67 /* 68 * Turn on module debugging output 69 */ 70 if (getenv("TOPOZFSDEBUG")) 71 topo_mod_setdebug(mod); 72 73 topo_mod_dprintf(mod, "initializing zfs builtin\n"); 74 75 if (version != ZFS_VERSION) 76 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 77 78 if (topo_mod_register(mod, &zfs_info, TOPO_VERSION) != 0) { 79 topo_mod_dprintf(mod, "failed to register zfs: " 80 "%s\n", topo_mod_errmsg(mod)); 81 return (-1); /* mod errno already set */ 82 } 83 if (!g_zfs) 84 g_zfs = libzfs_init(); 85 86 return (0); 87 } 88 89 void 90 zfs_fini(topo_mod_t *mod) 91 { 92 if (g_zfs) { 93 libzfs_fini(g_zfs); 94 g_zfs = NULL; 95 } 96 topo_mod_unregister(mod); 97 } 98 99 100 /*ARGSUSED*/ 101 int 102 zfs_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, topo_instance_t min, 103 topo_instance_t max, void *notused1, void *notused2) 104 { 105 /* 106 * Methods are registered, but there is no enumeration. Should 107 * enumeration be added be sure to cater for global vs non-global 108 * zones. 109 */ 110 (void) topo_method_register(mod, pnode, zfs_methods); 111 return (0); 112 } 113 114 /*ARGSUSED*/ 115 static void 116 zfs_rele(topo_mod_t *mp, tnode_t *node) 117 { 118 topo_method_unregister_all(mp, node); 119 } 120 121 typedef struct cbdata { 122 uint64_t cb_guid; 123 zpool_handle_t *cb_pool; 124 } cbdata_t; 125 126 static int 127 find_pool(zpool_handle_t *zhp, void *data) 128 { 129 cbdata_t *cbp = data; 130 131 if (zpool_get_prop_int(zhp, ZPOOL_PROP_GUID, NULL) == cbp->cb_guid) { 132 cbp->cb_pool = zhp; 133 return (1); 134 } 135 136 zpool_close(zhp); 137 138 return (0); 139 } 140 141 static ssize_t 142 fmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen) 143 { 144 uint64_t pool_guid, vdev_guid; 145 cbdata_t cb; 146 ssize_t len; 147 const char *name; 148 char guidbuf[64]; 149 150 (void) nvlist_lookup_uint64(nvl, FM_FMRI_ZFS_POOL, &pool_guid); 151 152 /* 153 * Attempt to convert the pool guid to a name. 154 */ 155 cb.cb_guid = pool_guid; 156 cb.cb_pool = NULL; 157 158 if (g_zfs != NULL && zpool_iter(g_zfs, find_pool, &cb) == 1) { 159 name = zpool_get_name(cb.cb_pool); 160 } else { 161 (void) snprintf(guidbuf, sizeof (guidbuf), "%llx", pool_guid); 162 name = guidbuf; 163 } 164 165 if (nvlist_lookup_uint64(nvl, FM_FMRI_ZFS_VDEV, &vdev_guid) == 0) 166 len = snprintf(buf, buflen, "%s://pool=%s/vdev=%llx", 167 FM_FMRI_SCHEME_ZFS, name, vdev_guid); 168 else 169 len = snprintf(buf, buflen, "%s://pool=%s", 170 FM_FMRI_SCHEME_ZFS, name); 171 172 if (cb.cb_pool) 173 zpool_close(cb.cb_pool); 174 175 return (len); 176 } 177 178 /*ARGSUSED*/ 179 static int 180 zfs_fmri_nvl2str(topo_mod_t *mod, tnode_t *node, topo_version_t version, 181 nvlist_t *nvl, nvlist_t **out) 182 { 183 ssize_t len; 184 char *name = NULL; 185 nvlist_t *fmristr; 186 187 if (version > TOPO_METH_NVL2STR_VERSION) 188 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 189 190 if ((len = fmri_nvl2str(nvl, NULL, 0)) == 0 || 191 (name = topo_mod_alloc(mod, len + 1)) == NULL || 192 fmri_nvl2str(nvl, name, len + 1) == 0) { 193 if (name != NULL) 194 topo_mod_free(mod, name, len + 1); 195 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 196 } 197 198 if (topo_mod_nvalloc(mod, &fmristr, NV_UNIQUE_NAME) != 0) { 199 topo_mod_free(mod, name, len + 1); 200 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 201 } 202 if (nvlist_add_string(fmristr, "fmri-string", name) != 0) { 203 topo_mod_free(mod, name, len + 1); 204 nvlist_free(fmristr); 205 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 206 } 207 topo_mod_free(mod, name, len + 1); 208 *out = fmristr; 209 210 return (0); 211 } 212