71 return (1); |
68 return (1); |
72 else |
69 else |
73 return (0); |
70 return (0); |
74 } |
71 } |
75 |
72 |
|
73 void |
|
74 namespace_clear(libzfs_handle_t *hdl) |
|
75 { |
|
76 if (hdl->libzfs_ns_avl) { |
|
77 uu_avl_walk_t *walk; |
|
78 config_node_t *cn; |
|
79 |
|
80 if ((walk = uu_avl_walk_start(hdl->libzfs_ns_avl, |
|
81 UU_WALK_ROBUST)) == NULL) |
|
82 return; |
|
83 |
|
84 while ((cn = uu_avl_walk_next(walk)) != NULL) { |
|
85 uu_avl_remove(hdl->libzfs_ns_avl, cn); |
|
86 nvlist_free(cn->cn_config); |
|
87 free(cn->cn_name); |
|
88 free(cn); |
|
89 } |
|
90 |
|
91 uu_avl_walk_end(walk); |
|
92 |
|
93 uu_avl_destroy(hdl->libzfs_ns_avl); |
|
94 hdl->libzfs_ns_avl = NULL; |
|
95 } |
|
96 |
|
97 if (hdl->libzfs_ns_avlpool) { |
|
98 uu_avl_pool_destroy(hdl->libzfs_ns_avlpool); |
|
99 hdl->libzfs_ns_avlpool = NULL; |
|
100 } |
|
101 } |
|
102 |
76 /* |
103 /* |
77 * Loads the pool namespace, or re-loads it if the cache has changed. |
104 * Loads the pool namespace, or re-loads it if the cache has changed. |
78 */ |
105 */ |
79 static void |
106 static int |
80 namespace_reload() |
107 namespace_reload(libzfs_handle_t *hdl) |
81 { |
108 { |
82 nvlist_t *config; |
109 nvlist_t *config; |
83 config_node_t *cn; |
110 config_node_t *cn; |
84 nvpair_t *elem; |
111 nvpair_t *elem; |
85 zfs_cmd_t zc = { 0 }; |
112 zfs_cmd_t zc = { 0 }; |
86 uu_avl_walk_t *walk; |
113 uu_avl_walk_t *walk; |
87 |
114 |
88 if (namespace_generation == 0) { |
115 if (hdl->libzfs_ns_gen == 0) { |
89 /* |
116 /* |
90 * This is the first time we've accessed the configuration |
117 * This is the first time we've accessed the configuration |
91 * cache. Initialize the AVL tree and then fall through to the |
118 * cache. Initialize the AVL tree and then fall through to the |
92 * common code. |
119 * common code. |
93 */ |
120 */ |
94 uu_avl_pool_t *pool; |
121 if ((hdl->libzfs_ns_avlpool = uu_avl_pool_create("config_pool", |
95 |
|
96 if ((pool = uu_avl_pool_create("config_pool", |
|
97 sizeof (config_node_t), |
122 sizeof (config_node_t), |
98 offsetof(config_node_t, cn_avl), |
123 offsetof(config_node_t, cn_avl), |
99 config_node_compare, UU_DEFAULT)) == NULL) |
124 config_node_compare, UU_DEFAULT)) == NULL) |
100 no_memory(); |
125 return (no_memory(hdl)); |
101 |
126 |
102 if ((namespace_avl = uu_avl_create(pool, NULL, |
127 if ((hdl->libzfs_ns_avl = uu_avl_create(hdl->libzfs_ns_avlpool, |
103 UU_DEFAULT)) == NULL) |
128 NULL, UU_DEFAULT)) == NULL) |
104 no_memory(); |
129 return (no_memory(hdl)); |
105 } |
130 } |
106 |
131 |
107 /* |
132 /* |
108 * Issue the ZFS_IOC_POOL_CONFIGS ioctl. |
133 * Issue the ZFS_IOC_POOL_CONFIGS ioctl. |
109 * This can fail for one of two reasons: |
134 * This can fail for one of two reasons: |
112 * ENOMEM The zc_config_dst buffer isn't large enough to |
137 * ENOMEM The zc_config_dst buffer isn't large enough to |
113 * hold the config; zc_config_dst_size will have |
138 * hold the config; zc_config_dst_size will have |
114 * been modified to tell us how much to allocate. |
139 * been modified to tell us how much to allocate. |
115 */ |
140 */ |
116 zc.zc_config_dst_size = 1024; |
141 zc.zc_config_dst_size = 1024; |
117 zc.zc_config_dst = (uint64_t)(uintptr_t) |
142 if ((zc.zc_config_dst = (uint64_t)(uintptr_t) |
118 zfs_malloc(zc.zc_config_dst_size); |
143 zfs_alloc(hdl, zc.zc_config_dst_size)) == NULL) |
|
144 return (-1); |
119 for (;;) { |
145 for (;;) { |
120 zc.zc_cookie = namespace_generation; |
146 zc.zc_cookie = hdl->libzfs_ns_gen; |
121 if (zfs_ioctl(ZFS_IOC_POOL_CONFIGS, &zc) != 0) { |
147 if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_CONFIGS, &zc) != 0) { |
122 switch (errno) { |
148 switch (errno) { |
123 case EEXIST: |
149 case EEXIST: |
124 /* |
150 /* |
125 * The namespace hasn't changed. |
151 * The namespace hasn't changed. |
126 */ |
152 */ |
127 free((void *)(uintptr_t)zc.zc_config_dst); |
153 free((void *)(uintptr_t)zc.zc_config_dst); |
128 return; |
154 return (0); |
129 |
155 |
130 case ENOMEM: |
156 case ENOMEM: |
131 free((void *)(uintptr_t)zc.zc_config_dst); |
157 free((void *)(uintptr_t)zc.zc_config_dst); |
132 zc.zc_config_dst = (uint64_t)(uintptr_t) |
158 if ((zc.zc_config_dst = (uint64_t)(uintptr_t) |
133 zfs_malloc(zc.zc_config_dst_size); |
159 zfs_alloc(hdl, zc.zc_config_dst_size)) |
|
160 == NULL) |
|
161 return (-1); |
134 break; |
162 break; |
135 |
163 |
136 default: |
164 default: |
137 zfs_baderror(errno); |
165 return (zfs_standard_error(hdl, errno, |
|
166 dgettext(TEXT_DOMAIN, "failed to read " |
|
167 "pool configuration"))); |
138 } |
168 } |
139 } else { |
169 } else { |
140 namespace_generation = zc.zc_cookie; |
170 hdl->libzfs_ns_gen = zc.zc_cookie; |
141 break; |
171 break; |
142 } |
172 } |
143 } |
173 } |
144 |
174 |
145 verify(nvlist_unpack((void *)(uintptr_t)zc.zc_config_dst, |
175 if (nvlist_unpack((void *)(uintptr_t)zc.zc_config_dst, |
146 zc.zc_config_dst_size, &config, 0) == 0); |
176 zc.zc_config_dst_size, &config, 0) != 0) |
|
177 return (no_memory(hdl)); |
147 |
178 |
148 free((void *)(uintptr_t)zc.zc_config_dst); |
179 free((void *)(uintptr_t)zc.zc_config_dst); |
149 |
180 |
150 /* |
181 /* |
151 * Clear out any existing configuration information. |
182 * Clear out any existing configuration information. |
152 */ |
183 */ |
153 if ((walk = uu_avl_walk_start(namespace_avl, UU_WALK_ROBUST)) == NULL) |
184 if ((walk = uu_avl_walk_start(hdl->libzfs_ns_avl, |
154 no_memory(); |
185 UU_WALK_ROBUST)) == NULL) { |
|
186 nvlist_free(config); |
|
187 return (no_memory(hdl)); |
|
188 } |
155 |
189 |
156 while ((cn = uu_avl_walk_next(walk)) != NULL) { |
190 while ((cn = uu_avl_walk_next(walk)) != NULL) { |
157 uu_avl_remove(namespace_avl, cn); |
191 uu_avl_remove(hdl->libzfs_ns_avl, cn); |
158 nvlist_free(cn->cn_config); |
192 nvlist_free(cn->cn_config); |
159 free(cn->cn_name); |
193 free(cn->cn_name); |
160 free(cn); |
194 free(cn); |
161 } |
195 } |
|
196 |
|
197 uu_avl_walk_end(walk); |
162 |
198 |
163 elem = NULL; |
199 elem = NULL; |
164 while ((elem = nvlist_next_nvpair(config, elem)) != NULL) { |
200 while ((elem = nvlist_next_nvpair(config, elem)) != NULL) { |
165 nvlist_t *child; |
201 nvlist_t *child; |
166 uu_avl_index_t where; |
202 uu_avl_index_t where; |
167 |
203 |
168 cn = zfs_malloc(sizeof (config_node_t)); |
204 if ((cn = zfs_alloc(hdl, sizeof (config_node_t))) == NULL) { |
169 cn->cn_name = zfs_strdup(nvpair_name(elem)); |
205 nvlist_free(config); |
|
206 return (-1); |
|
207 } |
|
208 |
|
209 if ((cn->cn_name = zfs_strdup(hdl, |
|
210 nvpair_name(elem))) == NULL) { |
|
211 free(cn); |
|
212 return (-1); |
|
213 } |
170 |
214 |
171 verify(nvpair_value_nvlist(elem, &child) == 0); |
215 verify(nvpair_value_nvlist(elem, &child) == 0); |
172 verify(nvlist_dup(child, &cn->cn_config, 0) == 0); |
216 if (nvlist_dup(child, &cn->cn_config, 0) != 0) { |
173 verify(uu_avl_find(namespace_avl, cn, NULL, &where) == NULL); |
217 nvlist_free(config); |
174 |
218 return (no_memory(hdl)); |
175 uu_avl_insert(namespace_avl, cn, where); |
219 } |
|
220 verify(uu_avl_find(hdl->libzfs_ns_avl, cn, NULL, &where) |
|
221 == NULL); |
|
222 |
|
223 uu_avl_insert(hdl->libzfs_ns_avl, cn, where); |
176 } |
224 } |
177 |
225 |
178 nvlist_free(config); |
226 nvlist_free(config); |
|
227 return (0); |
179 } |
228 } |
180 |
229 |
181 /* |
230 /* |
182 * Retrive the configuration for the given pool. The configuration is a nvlist |
231 * Retrive the configuration for the given pool. The configuration is a nvlist |
183 * describing the vdevs, as well as the statistics associated with each one. |
232 * describing the vdevs, as well as the statistics associated with each one. |
207 |
256 |
208 if (zhp->zpool_config_size == 0) |
257 if (zhp->zpool_config_size == 0) |
209 zhp->zpool_config_size = 1 << 16; |
258 zhp->zpool_config_size = 1 << 16; |
210 |
259 |
211 zc.zc_config_dst_size = zhp->zpool_config_size; |
260 zc.zc_config_dst_size = zhp->zpool_config_size; |
212 zc.zc_config_dst = (uint64_t)(uintptr_t) |
261 if ((zc.zc_config_dst = (uint64_t)(uintptr_t) |
213 zfs_malloc(zc.zc_config_dst_size); |
262 zfs_alloc(zhp->zpool_hdl, zc.zc_config_dst_size)) == NULL) |
|
263 return (-1); |
214 |
264 |
215 for (;;) { |
265 for (;;) { |
216 if (zfs_ioctl(ZFS_IOC_POOL_STATS, &zc) == 0) { |
266 if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_STATS, |
|
267 &zc) == 0) { |
217 /* |
268 /* |
218 * The real error is returned in the zc_cookie field. |
269 * The real error is returned in the zc_cookie field. |
219 */ |
270 */ |
220 error = zc.zc_cookie; |
271 error = errno = zc.zc_cookie; |
221 break; |
272 break; |
222 } |
273 } |
223 |
274 |
224 if (errno == ENOMEM) { |
275 if (errno == ENOMEM) { |
225 free((void *)(uintptr_t)zc.zc_config_dst); |
276 free((void *)(uintptr_t)zc.zc_config_dst); |
226 zc.zc_config_dst = (uint64_t)(uintptr_t) |
277 if ((zc.zc_config_dst = (uint64_t)(uintptr_t) |
227 zfs_malloc(zc.zc_config_dst_size); |
278 zfs_alloc(zhp->zpool_hdl, |
|
279 zc.zc_config_dst_size)) == NULL) |
|
280 return (-1); |
228 } else { |
281 } else { |
229 free((void *)(uintptr_t)zc.zc_config_dst); |
282 free((void *)(uintptr_t)zc.zc_config_dst); |
230 return (errno); |
283 return (-1); |
231 } |
284 } |
232 } |
285 } |
233 |
286 |
234 verify(nvlist_unpack((void *)(uintptr_t)zc.zc_config_dst, |
287 if (nvlist_unpack((void *)(uintptr_t)zc.zc_config_dst, |
235 zc.zc_config_dst_size, &config, 0) == 0); |
288 zc.zc_config_dst_size, &config, 0) != 0) { |
|
289 free((void *)(uintptr_t)zc.zc_config_dst); |
|
290 return (no_memory(zhp->zpool_hdl)); |
|
291 } |
236 |
292 |
237 zhp->zpool_config_size = zc.zc_config_dst_size; |
293 zhp->zpool_config_size = zc.zc_config_dst_size; |
238 free((void *)(uintptr_t)zc.zc_config_dst); |
294 free((void *)(uintptr_t)zc.zc_config_dst); |
239 |
295 |
240 set_pool_health(config); |
296 if (set_pool_health(config) != 0) |
|
297 return (no_memory(zhp->zpool_hdl)); |
241 |
298 |
242 if (zhp->zpool_config != NULL) { |
299 if (zhp->zpool_config != NULL) { |
243 uint64_t oldtxg, newtxg; |
300 uint64_t oldtxg, newtxg; |
244 |
301 |
245 verify(nvlist_lookup_uint64(zhp->zpool_config, |
302 verify(nvlist_lookup_uint64(zhp->zpool_config, |
258 } |
315 } |
259 } |
316 } |
260 |
317 |
261 zhp->zpool_config = config; |
318 zhp->zpool_config = config; |
262 |
319 |
263 return (error); |
320 return (error ? -1 : 0); |
264 } |
321 } |
265 |
322 |
266 /* |
323 /* |
267 * Iterate over all pools in the system. |
324 * Iterate over all pools in the system. |
268 */ |
325 */ |
269 int |
326 int |
270 zpool_iter(zpool_iter_f func, void *data) |
327 zpool_iter(libzfs_handle_t *hdl, zpool_iter_f func, void *data) |
271 { |
328 { |
272 config_node_t *cn; |
329 config_node_t *cn; |
273 zpool_handle_t *zhp; |
330 zpool_handle_t *zhp; |
274 int ret; |
331 int ret; |
275 |
332 |
276 namespace_reload(); |
333 if (namespace_reload(hdl) != 0) |
277 |
334 return (-1); |
278 for (cn = uu_avl_first(namespace_avl); cn != NULL; |
335 |
279 cn = uu_avl_next(namespace_avl, cn)) { |
336 for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL; |
280 |
337 cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) { |
281 if ((zhp = zpool_open_silent(cn->cn_name)) == NULL) |
338 |
|
339 if ((zhp = zpool_open_silent(hdl, cn->cn_name)) == NULL) |
282 continue; |
340 continue; |
283 |
341 |
284 if ((ret = func(zhp, data)) != 0) |
342 if ((ret = func(zhp, data)) != 0) |
285 return (ret); |
343 return (ret); |
286 } |
344 } |
291 /* |
349 /* |
292 * Iterate over root datasets, calling the given function for each. The zfs |
350 * Iterate over root datasets, calling the given function for each. The zfs |
293 * handle passed each time must be explicitly closed by the callback. |
351 * handle passed each time must be explicitly closed by the callback. |
294 */ |
352 */ |
295 int |
353 int |
296 zfs_iter_root(zfs_iter_f func, void *data) |
354 zfs_iter_root(libzfs_handle_t *hdl, zfs_iter_f func, void *data) |
297 { |
355 { |
298 config_node_t *cn; |
356 config_node_t *cn; |
299 zfs_handle_t *zhp; |
357 zfs_handle_t *zhp; |
300 int ret; |
358 int ret; |
301 |
359 |
302 namespace_reload(); |
360 if (namespace_reload(hdl) != 0) |
303 |
361 return (-1); |
304 for (cn = uu_avl_first(namespace_avl); cn != NULL; |
362 |
305 cn = uu_avl_next(namespace_avl, cn)) { |
363 for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL; |
306 |
364 cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) { |
307 if ((zhp = make_dataset_handle(cn->cn_name)) == NULL) |
365 |
|
366 if ((zhp = make_dataset_handle(hdl, cn->cn_name)) == NULL) |
308 continue; |
367 continue; |
309 |
368 |
310 if ((ret = func(zhp, data)) != 0) |
369 if ((ret = func(zhp, data)) != 0) |
311 return (ret); |
370 return (ret); |
312 } |
371 } |