Print this page
MFV: illumos-gate@f62db44dbcda5dd786bb821f1e6fd3ca2e6d4391
9616 Bogus error when attempting to set property on read-only pool
Reviewed by: Paul Dagnelie <pcd@delphix.com>
Reviewed by: Matt Ahrens <matt@delphix.com>
Approved by: Robert Mustacchi <rm@joyent.com>
8520 lzc_rollback_to should support rolling back to origin
7198 libzfs should gracefully handle EINVAL from lzc_rollback
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Approved by: Dan McDonald <danmcd@joyent.com>
NEX-16502 libshare needs to support SMB in a zone
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
NEX-15279 support NFS server in zone
NEX-15520 online NFS shares cause zoneadm halt to hang in nfs_export_zone_fini
Portions contributed by: Dan Kruchinin dan.kruchinin@nexenta.com
Portions contributed by: Stepan Zastupov stepan.zastupov@gmail.com
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
NEX-9406 Add a property to show that a dataset has been modified since a snapshot
Reviewed by: Alexey Komarov <alexey.komarov@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-9436 Rate limiting controls (was QoS) per ZFS dataset, updates from demo
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
NEX-8852 Quality-of-Service (QoS) controls per NFS share
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-5795 Rename 'wrc' as 'wbc' in the source and in the tech docs
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
NEX-5060 WBC: Writecache and deduplication should not be used together
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
NEX-4830 writecache=off leaks data on special vdev (the data will never migrate)
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
6298 zfs_create_008_neg and zpool_create_023_neg need to be updated for large block support
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: John Kennedy <john.kennedy@delphix.com>
Approved by: Robert Mustacchi <rm@joyent.com>
2605 want to resume interrupted zfs send
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed by: Paul Dagnelie <pcd@delphix.com>
Reviewed by: Richard Elling <Richard.Elling@RichardElling.com>
Reviewed by: Xin Li <delphij@freebsd.org>
Reviewed by: Arne Jansen <sensille@gmx.net>
Approved by: Dan McDonald <danmcd@omniti.com>
4185 add new cryptographic checksums to ZFS: SHA-512, Skein, Edon-R (fix studio build)
4185 add new cryptographic checksums to ZFS: SHA-512, Skein, Edon-R
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed by: Prakash Surya <prakash.surya@delphix.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
Reviewed by: Richard Lowe <richlowe@richlowe.net>
Approved by: Garrett D'Amore <garrett@damore.org>
5813 zfs_setprop_error(): Handle errno value E2BIG.
Reviewed by: Paul Dagnelie <paul.dagnelie@delphix.com>
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: Prakash Surya <prakash.surya@delphix.com>
Reviewed by: Richard Elling <richard.elling@richardelling.com>
Approved by: Garrett D'Amore <garrett@damore.org>
5745 zfs set allows only one dataset property to be set at a time
Reviewed by: Christopher Siden <christopher.siden@delphix.com>
Reviewed by: George Wilson <george@delphix.com>
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: Bayard Bell <buffer.g.overflow@gmail.com>
Reviewed by: Richard PALO <richard@NetBSD.org>
Reviewed by: Steven Hartland <killing@multiplay.co.uk>
Approved by: Rich Lowe <richlowe@richlowe.net>
NEX-4476 WRC: Allow to use write back cache per tree of datasets
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
Revert "NEX-4476 WRC: Allow to use write back cache per tree of datasets"
This reverts commit fe97b74444278a6f36fec93179133641296312da.
NEX-4476 WRC: Allow to use write back cache per tree of datasets
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
NEX-4043 Renaming of autosnaps is not handled correctly
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
NEX-3669 Faults for fans that don't exist
Reviewed by: Jeffry Molanus <jeffry.molanus@nexenta.com>
NEX-3891 Hide the snapshots that belong to in-kernel autosnap-service
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
Reviewed by: Alek Pinchuk <alek@nexenta.com>
NEX-3558 KRRP Integration
NEX-2848 memory leak in the zfs_release() library call path
NEX-1456 Part 2, port FreeBSD patch - new zfs recv options support
SUP-642 Regression leading to AD usernames not being displayed by zfs userspace command.
re #8279 rb3915 need a mechanism to notify NMS about ZFS config changes (Opened code)
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/lib/libzfs/common/libzfs_dataset.c
+++ new/usr/src/lib/libzfs/common/libzfs_dataset.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
|
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24 + */
25 +
26 +/*
24 27 * Copyright (c) 2013, Joyent, Inc. All rights reserved.
25 28 * Copyright (c) 2011, 2016 by Delphix. All rights reserved.
26 29 * Copyright (c) 2012 DEY Storage Systems, Inc. All rights reserved.
27 30 * Copyright (c) 2011-2012 Pawel Jakub Dawidek. All rights reserved.
28 31 * Copyright (c) 2013 Martin Matuska. All rights reserved.
29 32 * Copyright (c) 2013 Steven Hartland. All rights reserved.
30 33 * Copyright (c) 2014 Integros [integros.com]
31 - * Copyright 2017 Nexenta Systems, Inc.
34 + * Copyright 2018 Nexenta Systems, Inc.
32 35 * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
33 - * Copyright 2017 RackTop Systems.
36 + * Copyright 2017-2018 RackTop Systems.
34 37 */
35 38
36 39 #include <ctype.h>
37 40 #include <errno.h>
38 41 #include <libintl.h>
39 42 #include <math.h>
40 43 #include <stdio.h>
41 44 #include <stdlib.h>
42 45 #include <strings.h>
43 46 #include <unistd.h>
44 47 #include <stddef.h>
45 48 #include <zone.h>
46 49 #include <fcntl.h>
47 50 #include <sys/mntent.h>
48 51 #include <sys/mount.h>
49 52 #include <priv.h>
50 53 #include <pwd.h>
51 54 #include <grp.h>
52 55 #include <stddef.h>
53 56 #include <ucred.h>
54 57 #include <idmap.h>
55 58 #include <aclutils.h>
56 59 #include <directory.h>
|
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
57 60
58 61 #include <sys/dnode.h>
59 62 #include <sys/spa.h>
60 63 #include <sys/zap.h>
61 64 #include <libzfs.h>
62 65
63 66 #include "zfs_namecheck.h"
64 67 #include "zfs_prop.h"
65 68 #include "libzfs_impl.h"
66 69 #include "zfs_deleg.h"
70 +#include "zfs_errno.h"
67 71
68 72 static int userquota_propname_decode(const char *propname, boolean_t zoned,
69 73 zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp);
70 74
71 75 /*
72 76 * Given a single type (not a mask of types), return the type in a human
73 77 * readable form.
74 78 */
75 79 const char *
76 80 zfs_type_to_name(zfs_type_t type)
77 81 {
78 82 switch (type) {
79 83 case ZFS_TYPE_FILESYSTEM:
80 84 return (dgettext(TEXT_DOMAIN, "filesystem"));
81 85 case ZFS_TYPE_SNAPSHOT:
82 86 return (dgettext(TEXT_DOMAIN, "snapshot"));
83 87 case ZFS_TYPE_VOLUME:
84 88 return (dgettext(TEXT_DOMAIN, "volume"));
85 89 case ZFS_TYPE_POOL:
86 90 return (dgettext(TEXT_DOMAIN, "pool"));
87 91 case ZFS_TYPE_BOOKMARK:
88 92 return (dgettext(TEXT_DOMAIN, "bookmark"));
89 93 default:
90 94 assert(!"unhandled zfs_type_t");
91 95 }
92 96
93 97 return (NULL);
94 98 }
95 99
96 100 /*
97 101 * Validate a ZFS path. This is used even before trying to open the dataset, to
98 102 * provide a more meaningful error message. We call zfs_error_aux() to
99 103 * explain exactly why the name was not valid.
100 104 */
101 105 int
102 106 zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type,
103 107 boolean_t modifying)
104 108 {
105 109 namecheck_err_t why;
106 110 char what;
107 111
108 112 if (entity_namecheck(path, &why, &what) != 0) {
109 113 if (hdl != NULL) {
110 114 switch (why) {
111 115 case NAME_ERR_TOOLONG:
112 116 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
113 117 "name is too long"));
114 118 break;
115 119
116 120 case NAME_ERR_LEADING_SLASH:
117 121 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
118 122 "leading slash in name"));
119 123 break;
120 124
121 125 case NAME_ERR_EMPTY_COMPONENT:
122 126 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
123 127 "empty component in name"));
124 128 break;
125 129
126 130 case NAME_ERR_TRAILING_SLASH:
127 131 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
128 132 "trailing slash in name"));
129 133 break;
130 134
131 135 case NAME_ERR_INVALCHAR:
132 136 zfs_error_aux(hdl,
133 137 dgettext(TEXT_DOMAIN, "invalid character "
134 138 "'%c' in name"), what);
135 139 break;
136 140
137 141 case NAME_ERR_MULTIPLE_DELIMITERS:
138 142 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
139 143 "multiple '@' and/or '#' delimiters in "
140 144 "name"));
141 145 break;
142 146
143 147 case NAME_ERR_NOLETTER:
144 148 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
145 149 "pool doesn't begin with a letter"));
146 150 break;
147 151
148 152 case NAME_ERR_RESERVED:
149 153 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
150 154 "name is reserved"));
151 155 break;
152 156
153 157 case NAME_ERR_DISKLIKE:
154 158 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
155 159 "reserved disk name"));
156 160 break;
157 161
158 162 default:
159 163 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
160 164 "(%d) not defined"), why);
161 165 break;
162 166 }
163 167 }
164 168
165 169 return (0);
166 170 }
167 171
168 172 if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') != NULL) {
169 173 if (hdl != NULL)
170 174 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
171 175 "snapshot delimiter '@' is not expected here"));
172 176 return (0);
173 177 }
174 178
175 179 if (type == ZFS_TYPE_SNAPSHOT && strchr(path, '@') == NULL) {
176 180 if (hdl != NULL)
177 181 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
178 182 "missing '@' delimiter in snapshot name"));
179 183 return (0);
180 184 }
181 185
182 186 if (!(type & ZFS_TYPE_BOOKMARK) && strchr(path, '#') != NULL) {
183 187 if (hdl != NULL)
184 188 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
185 189 "bookmark delimiter '#' is not expected here"));
186 190 return (0);
187 191 }
188 192
189 193 if (type == ZFS_TYPE_BOOKMARK && strchr(path, '#') == NULL) {
190 194 if (hdl != NULL)
191 195 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
192 196 "missing '#' delimiter in bookmark name"));
193 197 return (0);
194 198 }
195 199
196 200 if (modifying && strchr(path, '%') != NULL) {
197 201 if (hdl != NULL)
198 202 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
199 203 "invalid character %c in name"), '%');
200 204 return (0);
201 205 }
202 206
203 207 return (-1);
204 208 }
205 209
206 210 int
207 211 zfs_name_valid(const char *name, zfs_type_t type)
208 212 {
209 213 if (type == ZFS_TYPE_POOL)
210 214 return (zpool_name_valid(NULL, B_FALSE, name));
211 215 return (zfs_validate_name(NULL, name, type, B_FALSE));
212 216 }
213 217
214 218 /*
215 219 * This function takes the raw DSL properties, and filters out the user-defined
216 220 * properties into a separate nvlist.
217 221 */
218 222 static nvlist_t *
219 223 process_user_props(zfs_handle_t *zhp, nvlist_t *props)
220 224 {
221 225 libzfs_handle_t *hdl = zhp->zfs_hdl;
222 226 nvpair_t *elem;
223 227 nvlist_t *propval;
224 228 nvlist_t *nvl;
225 229
226 230 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
227 231 (void) no_memory(hdl);
228 232 return (NULL);
229 233 }
230 234
231 235 elem = NULL;
232 236 while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
233 237 if (!zfs_prop_user(nvpair_name(elem)))
234 238 continue;
235 239
236 240 verify(nvpair_value_nvlist(elem, &propval) == 0);
237 241 if (nvlist_add_nvlist(nvl, nvpair_name(elem), propval) != 0) {
238 242 nvlist_free(nvl);
239 243 (void) no_memory(hdl);
240 244 return (NULL);
241 245 }
242 246 }
243 247
244 248 return (nvl);
245 249 }
246 250
247 251 static zpool_handle_t *
248 252 zpool_add_handle(zfs_handle_t *zhp, const char *pool_name)
249 253 {
250 254 libzfs_handle_t *hdl = zhp->zfs_hdl;
251 255 zpool_handle_t *zph;
252 256
253 257 if ((zph = zpool_open_canfail(hdl, pool_name)) != NULL) {
254 258 if (hdl->libzfs_pool_handles != NULL)
255 259 zph->zpool_next = hdl->libzfs_pool_handles;
256 260 hdl->libzfs_pool_handles = zph;
257 261 }
258 262 return (zph);
259 263 }
260 264
261 265 static zpool_handle_t *
262 266 zpool_find_handle(zfs_handle_t *zhp, const char *pool_name, int len)
263 267 {
264 268 libzfs_handle_t *hdl = zhp->zfs_hdl;
265 269 zpool_handle_t *zph = hdl->libzfs_pool_handles;
266 270
267 271 while ((zph != NULL) &&
268 272 (strncmp(pool_name, zpool_get_name(zph), len) != 0))
269 273 zph = zph->zpool_next;
270 274 return (zph);
271 275 }
272 276
273 277 /*
274 278 * Returns a handle to the pool that contains the provided dataset.
275 279 * If a handle to that pool already exists then that handle is returned.
276 280 * Otherwise, a new handle is created and added to the list of handles.
277 281 */
278 282 static zpool_handle_t *
279 283 zpool_handle(zfs_handle_t *zhp)
280 284 {
281 285 char *pool_name;
282 286 int len;
283 287 zpool_handle_t *zph;
284 288
285 289 len = strcspn(zhp->zfs_name, "/@#") + 1;
286 290 pool_name = zfs_alloc(zhp->zfs_hdl, len);
287 291 (void) strlcpy(pool_name, zhp->zfs_name, len);
288 292
289 293 zph = zpool_find_handle(zhp, pool_name, len);
290 294 if (zph == NULL)
291 295 zph = zpool_add_handle(zhp, pool_name);
292 296
293 297 free(pool_name);
294 298 return (zph);
295 299 }
296 300
297 301 void
298 302 zpool_free_handles(libzfs_handle_t *hdl)
299 303 {
300 304 zpool_handle_t *next, *zph = hdl->libzfs_pool_handles;
301 305
302 306 while (zph != NULL) {
303 307 next = zph->zpool_next;
304 308 zpool_close(zph);
305 309 zph = next;
306 310 }
307 311 hdl->libzfs_pool_handles = NULL;
308 312 }
309 313
310 314 /*
311 315 * Utility function to gather stats (objset and zpl) for the given object.
312 316 */
313 317 static int
314 318 get_stats_ioctl(zfs_handle_t *zhp, zfs_cmd_t *zc)
315 319 {
316 320 libzfs_handle_t *hdl = zhp->zfs_hdl;
317 321
318 322 (void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name));
319 323
320 324 while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, zc) != 0) {
321 325 if (errno == ENOMEM) {
322 326 if (zcmd_expand_dst_nvlist(hdl, zc) != 0) {
323 327 return (-1);
324 328 }
325 329 } else {
326 330 return (-1);
327 331 }
328 332 }
329 333 return (0);
330 334 }
331 335
332 336 /*
333 337 * Utility function to get the received properties of the given object.
334 338 */
335 339 static int
336 340 get_recvd_props_ioctl(zfs_handle_t *zhp)
337 341 {
338 342 libzfs_handle_t *hdl = zhp->zfs_hdl;
339 343 nvlist_t *recvdprops;
340 344 zfs_cmd_t zc = { 0 };
341 345 int err;
342 346
343 347 if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
344 348 return (-1);
345 349
346 350 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
347 351
348 352 while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_RECVD_PROPS, &zc) != 0) {
349 353 if (errno == ENOMEM) {
350 354 if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
351 355 return (-1);
352 356 }
353 357 } else {
354 358 zcmd_free_nvlists(&zc);
355 359 return (-1);
356 360 }
357 361 }
358 362
359 363 err = zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &recvdprops);
360 364 zcmd_free_nvlists(&zc);
361 365 if (err != 0)
362 366 return (-1);
363 367
364 368 nvlist_free(zhp->zfs_recvd_props);
365 369 zhp->zfs_recvd_props = recvdprops;
366 370
367 371 return (0);
368 372 }
369 373
370 374 static int
371 375 put_stats_zhdl(zfs_handle_t *zhp, zfs_cmd_t *zc)
372 376 {
373 377 nvlist_t *allprops, *userprops;
374 378
375 379 zhp->zfs_dmustats = zc->zc_objset_stats; /* structure assignment */
376 380
377 381 if (zcmd_read_dst_nvlist(zhp->zfs_hdl, zc, &allprops) != 0) {
378 382 return (-1);
379 383 }
380 384
381 385 /*
382 386 * XXX Why do we store the user props separately, in addition to
383 387 * storing them in zfs_props?
384 388 */
385 389 if ((userprops = process_user_props(zhp, allprops)) == NULL) {
386 390 nvlist_free(allprops);
387 391 return (-1);
388 392 }
389 393
390 394 nvlist_free(zhp->zfs_props);
391 395 nvlist_free(zhp->zfs_user_props);
392 396
393 397 zhp->zfs_props = allprops;
394 398 zhp->zfs_user_props = userprops;
395 399
396 400 return (0);
397 401 }
398 402
399 403 static int
400 404 get_stats(zfs_handle_t *zhp)
401 405 {
402 406 int rc = 0;
403 407 zfs_cmd_t zc = { 0 };
404 408
405 409 if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
406 410 return (-1);
407 411 if (get_stats_ioctl(zhp, &zc) != 0)
408 412 rc = -1;
409 413 else if (put_stats_zhdl(zhp, &zc) != 0)
410 414 rc = -1;
411 415 zcmd_free_nvlists(&zc);
412 416 return (rc);
413 417 }
414 418
415 419 /*
416 420 * Refresh the properties currently stored in the handle.
417 421 */
418 422 void
419 423 zfs_refresh_properties(zfs_handle_t *zhp)
420 424 {
421 425 (void) get_stats(zhp);
422 426 }
423 427
424 428 /*
425 429 * Makes a handle from the given dataset name. Used by zfs_open() and
426 430 * zfs_iter_* to create child handles on the fly.
427 431 */
428 432 static int
429 433 make_dataset_handle_common(zfs_handle_t *zhp, zfs_cmd_t *zc)
430 434 {
431 435 if (put_stats_zhdl(zhp, zc) != 0)
432 436 return (-1);
433 437
434 438 /*
|
↓ open down ↓ |
358 lines elided |
↑ open up ↑ |
435 439 * We've managed to open the dataset and gather statistics. Determine
436 440 * the high-level type.
437 441 */
438 442 if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL)
439 443 zhp->zfs_head_type = ZFS_TYPE_VOLUME;
440 444 else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS)
441 445 zhp->zfs_head_type = ZFS_TYPE_FILESYSTEM;
442 446 else
443 447 abort();
444 448
445 - if (zhp->zfs_dmustats.dds_is_snapshot)
449 + if (zhp->zfs_dmustats.dds_is_autosnapshot)
450 + zhp->zfs_type = ZFS_TYPE_AUTOSNAP;
451 + else if (zhp->zfs_dmustats.dds_is_snapshot)
446 452 zhp->zfs_type = ZFS_TYPE_SNAPSHOT;
447 453 else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL)
448 454 zhp->zfs_type = ZFS_TYPE_VOLUME;
449 455 else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS)
450 456 zhp->zfs_type = ZFS_TYPE_FILESYSTEM;
451 457 else
452 458 abort(); /* we should never see any other types */
453 459
454 460 if ((zhp->zpool_hdl = zpool_handle(zhp)) == NULL)
455 461 return (-1);
456 462
457 463 return (0);
458 464 }
459 465
460 466 zfs_handle_t *
461 467 make_dataset_handle(libzfs_handle_t *hdl, const char *path)
462 468 {
463 469 zfs_cmd_t zc = { 0 };
464 470
465 471 zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
466 472
467 473 if (zhp == NULL)
468 474 return (NULL);
469 475
470 476 zhp->zfs_hdl = hdl;
471 477 (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name));
472 478 if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) {
473 479 free(zhp);
474 480 return (NULL);
475 481 }
476 482 if (get_stats_ioctl(zhp, &zc) == -1) {
477 483 zcmd_free_nvlists(&zc);
478 484 free(zhp);
479 485 return (NULL);
480 486 }
481 487 if (make_dataset_handle_common(zhp, &zc) == -1) {
482 488 free(zhp);
483 489 zhp = NULL;
484 490 }
485 491 zcmd_free_nvlists(&zc);
486 492 return (zhp);
487 493 }
488 494
489 495 zfs_handle_t *
490 496 make_dataset_handle_zc(libzfs_handle_t *hdl, zfs_cmd_t *zc)
491 497 {
492 498 zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
493 499
494 500 if (zhp == NULL)
495 501 return (NULL);
496 502
497 503 zhp->zfs_hdl = hdl;
498 504 (void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name));
499 505 if (make_dataset_handle_common(zhp, zc) == -1) {
500 506 free(zhp);
501 507 return (NULL);
502 508 }
503 509 return (zhp);
504 510 }
505 511
506 512 zfs_handle_t *
507 513 make_dataset_simple_handle_zc(zfs_handle_t *pzhp, zfs_cmd_t *zc)
508 514 {
509 515 zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
510 516
511 517 if (zhp == NULL)
512 518 return (NULL);
513 519
514 520 zhp->zfs_hdl = pzhp->zfs_hdl;
515 521 (void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name));
516 522 zhp->zfs_head_type = pzhp->zfs_type;
517 523 zhp->zfs_type = ZFS_TYPE_SNAPSHOT;
518 524 zhp->zpool_hdl = zpool_handle(zhp);
519 525 return (zhp);
520 526 }
521 527
522 528 zfs_handle_t *
523 529 zfs_handle_dup(zfs_handle_t *zhp_orig)
524 530 {
525 531 zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
526 532
527 533 if (zhp == NULL)
528 534 return (NULL);
529 535
530 536 zhp->zfs_hdl = zhp_orig->zfs_hdl;
531 537 zhp->zpool_hdl = zhp_orig->zpool_hdl;
532 538 (void) strlcpy(zhp->zfs_name, zhp_orig->zfs_name,
533 539 sizeof (zhp->zfs_name));
534 540 zhp->zfs_type = zhp_orig->zfs_type;
535 541 zhp->zfs_head_type = zhp_orig->zfs_head_type;
536 542 zhp->zfs_dmustats = zhp_orig->zfs_dmustats;
537 543 if (zhp_orig->zfs_props != NULL) {
538 544 if (nvlist_dup(zhp_orig->zfs_props, &zhp->zfs_props, 0) != 0) {
539 545 (void) no_memory(zhp->zfs_hdl);
540 546 zfs_close(zhp);
541 547 return (NULL);
542 548 }
543 549 }
544 550 if (zhp_orig->zfs_user_props != NULL) {
545 551 if (nvlist_dup(zhp_orig->zfs_user_props,
546 552 &zhp->zfs_user_props, 0) != 0) {
547 553 (void) no_memory(zhp->zfs_hdl);
548 554 zfs_close(zhp);
549 555 return (NULL);
550 556 }
551 557 }
552 558 if (zhp_orig->zfs_recvd_props != NULL) {
553 559 if (nvlist_dup(zhp_orig->zfs_recvd_props,
554 560 &zhp->zfs_recvd_props, 0)) {
555 561 (void) no_memory(zhp->zfs_hdl);
556 562 zfs_close(zhp);
557 563 return (NULL);
558 564 }
559 565 }
560 566 zhp->zfs_mntcheck = zhp_orig->zfs_mntcheck;
561 567 if (zhp_orig->zfs_mntopts != NULL) {
562 568 zhp->zfs_mntopts = zfs_strdup(zhp_orig->zfs_hdl,
563 569 zhp_orig->zfs_mntopts);
564 570 }
565 571 zhp->zfs_props_table = zhp_orig->zfs_props_table;
566 572 return (zhp);
567 573 }
568 574
569 575 boolean_t
570 576 zfs_bookmark_exists(const char *path)
571 577 {
572 578 nvlist_t *bmarks;
573 579 nvlist_t *props;
574 580 char fsname[ZFS_MAX_DATASET_NAME_LEN];
575 581 char *bmark_name;
576 582 char *pound;
577 583 int err;
578 584 boolean_t rv;
579 585
580 586
581 587 (void) strlcpy(fsname, path, sizeof (fsname));
582 588 pound = strchr(fsname, '#');
583 589 if (pound == NULL)
584 590 return (B_FALSE);
585 591
586 592 *pound = '\0';
587 593 bmark_name = pound + 1;
588 594 props = fnvlist_alloc();
589 595 err = lzc_get_bookmarks(fsname, props, &bmarks);
590 596 nvlist_free(props);
591 597 if (err != 0) {
592 598 nvlist_free(bmarks);
593 599 return (B_FALSE);
594 600 }
595 601
596 602 rv = nvlist_exists(bmarks, bmark_name);
597 603 nvlist_free(bmarks);
598 604 return (rv);
599 605 }
600 606
601 607 zfs_handle_t *
602 608 make_bookmark_handle(zfs_handle_t *parent, const char *path,
603 609 nvlist_t *bmark_props)
604 610 {
605 611 zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
606 612
607 613 if (zhp == NULL)
608 614 return (NULL);
609 615
610 616 /* Fill in the name. */
611 617 zhp->zfs_hdl = parent->zfs_hdl;
612 618 (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name));
613 619
614 620 /* Set the property lists. */
615 621 if (nvlist_dup(bmark_props, &zhp->zfs_props, 0) != 0) {
616 622 free(zhp);
617 623 return (NULL);
618 624 }
619 625
620 626 /* Set the types. */
621 627 zhp->zfs_head_type = parent->zfs_head_type;
622 628 zhp->zfs_type = ZFS_TYPE_BOOKMARK;
623 629
624 630 if ((zhp->zpool_hdl = zpool_handle(zhp)) == NULL) {
625 631 nvlist_free(zhp->zfs_props);
626 632 free(zhp);
627 633 return (NULL);
628 634 }
629 635
630 636 return (zhp);
631 637 }
632 638
633 639 struct zfs_open_bookmarks_cb_data {
634 640 const char *path;
635 641 zfs_handle_t *zhp;
636 642 };
637 643
638 644 static int
639 645 zfs_open_bookmarks_cb(zfs_handle_t *zhp, void *data)
640 646 {
641 647 struct zfs_open_bookmarks_cb_data *dp = data;
642 648
643 649 /*
644 650 * Is it the one we are looking for?
645 651 */
646 652 if (strcmp(dp->path, zfs_get_name(zhp)) == 0) {
647 653 /*
648 654 * We found it. Save it and let the caller know we are done.
649 655 */
650 656 dp->zhp = zhp;
651 657 return (EEXIST);
652 658 }
653 659
654 660 /*
655 661 * Not found. Close the handle and ask for another one.
656 662 */
657 663 zfs_close(zhp);
658 664 return (0);
659 665 }
660 666
661 667 /*
662 668 * Opens the given snapshot, bookmark, filesystem, or volume. The 'types'
663 669 * argument is a mask of acceptable types. The function will print an
664 670 * appropriate error message and return NULL if it can't be opened.
665 671 */
666 672 zfs_handle_t *
667 673 zfs_open(libzfs_handle_t *hdl, const char *path, int types)
668 674 {
669 675 zfs_handle_t *zhp;
670 676 char errbuf[1024];
671 677 char *bookp;
672 678
673 679 (void) snprintf(errbuf, sizeof (errbuf),
674 680 dgettext(TEXT_DOMAIN, "cannot open '%s'"), path);
675 681
676 682 /*
677 683 * Validate the name before we even try to open it.
678 684 */
679 685 if (!zfs_validate_name(hdl, path, types, B_FALSE)) {
680 686 (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
681 687 return (NULL);
682 688 }
683 689
684 690 /*
685 691 * Bookmarks needs to be handled separately.
686 692 */
687 693 bookp = strchr(path, '#');
688 694 if (bookp == NULL) {
689 695 /*
690 696 * Try to get stats for the dataset, which will tell us if it
691 697 * exists.
692 698 */
693 699 errno = 0;
694 700 if ((zhp = make_dataset_handle(hdl, path)) == NULL) {
695 701 (void) zfs_standard_error(hdl, errno, errbuf);
696 702 return (NULL);
697 703 }
698 704 } else {
699 705 char dsname[ZFS_MAX_DATASET_NAME_LEN];
700 706 zfs_handle_t *pzhp;
701 707 struct zfs_open_bookmarks_cb_data cb_data = {path, NULL};
702 708
703 709 /*
704 710 * We need to cut out '#' and everything after '#'
705 711 * to get the parent dataset name only.
706 712 */
707 713 assert(bookp - path < sizeof (dsname));
708 714 (void) strncpy(dsname, path, bookp - path);
709 715 dsname[bookp - path] = '\0';
710 716
711 717 /*
712 718 * Create handle for the parent dataset.
713 719 */
714 720 errno = 0;
715 721 if ((pzhp = make_dataset_handle(hdl, dsname)) == NULL) {
716 722 (void) zfs_standard_error(hdl, errno, errbuf);
717 723 return (NULL);
718 724 }
719 725
720 726 /*
721 727 * Iterate bookmarks to find the right one.
722 728 */
723 729 errno = 0;
724 730 if ((zfs_iter_bookmarks(pzhp, zfs_open_bookmarks_cb,
725 731 &cb_data) == 0) && (cb_data.zhp == NULL)) {
726 732 (void) zfs_error(hdl, EZFS_NOENT, errbuf);
727 733 zfs_close(pzhp);
728 734 return (NULL);
729 735 }
730 736 if (cb_data.zhp == NULL) {
731 737 (void) zfs_standard_error(hdl, errno, errbuf);
732 738 zfs_close(pzhp);
733 739 return (NULL);
734 740 }
735 741 zhp = cb_data.zhp;
736 742
737 743 /*
738 744 * Cleanup.
739 745 */
740 746 zfs_close(pzhp);
741 747 }
742 748
743 749 if (!(types & zhp->zfs_type)) {
744 750 (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
745 751 zfs_close(zhp);
746 752 return (NULL);
747 753 }
748 754
749 755 return (zhp);
750 756 }
751 757
752 758 /*
753 759 * Release a ZFS handle. Nothing to do but free the associated memory.
754 760 */
755 761 void
756 762 zfs_close(zfs_handle_t *zhp)
757 763 {
758 764 if (zhp->zfs_mntopts)
759 765 free(zhp->zfs_mntopts);
760 766 nvlist_free(zhp->zfs_props);
761 767 nvlist_free(zhp->zfs_user_props);
762 768 nvlist_free(zhp->zfs_recvd_props);
763 769 free(zhp);
764 770 }
765 771
766 772 typedef struct mnttab_node {
767 773 struct mnttab mtn_mt;
768 774 avl_node_t mtn_node;
769 775 } mnttab_node_t;
770 776
771 777 static int
772 778 libzfs_mnttab_cache_compare(const void *arg1, const void *arg2)
773 779 {
774 780 const mnttab_node_t *mtn1 = arg1;
775 781 const mnttab_node_t *mtn2 = arg2;
776 782 int rv;
777 783
778 784 rv = strcmp(mtn1->mtn_mt.mnt_special, mtn2->mtn_mt.mnt_special);
779 785
780 786 if (rv == 0)
781 787 return (0);
782 788 return (rv > 0 ? 1 : -1);
783 789 }
784 790
785 791 void
786 792 libzfs_mnttab_init(libzfs_handle_t *hdl)
787 793 {
788 794 assert(avl_numnodes(&hdl->libzfs_mnttab_cache) == 0);
789 795 avl_create(&hdl->libzfs_mnttab_cache, libzfs_mnttab_cache_compare,
790 796 sizeof (mnttab_node_t), offsetof(mnttab_node_t, mtn_node));
791 797 }
792 798
793 799 void
794 800 libzfs_mnttab_update(libzfs_handle_t *hdl)
795 801 {
796 802 struct mnttab entry;
797 803
798 804 rewind(hdl->libzfs_mnttab);
799 805 while (getmntent(hdl->libzfs_mnttab, &entry) == 0) {
800 806 mnttab_node_t *mtn;
801 807
802 808 if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0)
803 809 continue;
804 810 mtn = zfs_alloc(hdl, sizeof (mnttab_node_t));
805 811 mtn->mtn_mt.mnt_special = zfs_strdup(hdl, entry.mnt_special);
806 812 mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, entry.mnt_mountp);
807 813 mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, entry.mnt_fstype);
808 814 mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, entry.mnt_mntopts);
809 815 avl_add(&hdl->libzfs_mnttab_cache, mtn);
810 816 }
811 817 }
812 818
813 819 void
814 820 libzfs_mnttab_fini(libzfs_handle_t *hdl)
815 821 {
816 822 void *cookie = NULL;
817 823 mnttab_node_t *mtn;
818 824
819 825 while ((mtn = avl_destroy_nodes(&hdl->libzfs_mnttab_cache, &cookie))
820 826 != NULL) {
821 827 free(mtn->mtn_mt.mnt_special);
822 828 free(mtn->mtn_mt.mnt_mountp);
823 829 free(mtn->mtn_mt.mnt_fstype);
824 830 free(mtn->mtn_mt.mnt_mntopts);
825 831 free(mtn);
826 832 }
827 833 avl_destroy(&hdl->libzfs_mnttab_cache);
828 834 }
829 835
830 836 void
831 837 libzfs_mnttab_cache(libzfs_handle_t *hdl, boolean_t enable)
832 838 {
833 839 hdl->libzfs_mnttab_enable = enable;
834 840 }
835 841
836 842 int
837 843 libzfs_mnttab_find(libzfs_handle_t *hdl, const char *fsname,
838 844 struct mnttab *entry)
839 845 {
840 846 mnttab_node_t find;
841 847 mnttab_node_t *mtn;
842 848
843 849 if (!hdl->libzfs_mnttab_enable) {
844 850 struct mnttab srch = { 0 };
845 851
846 852 if (avl_numnodes(&hdl->libzfs_mnttab_cache))
847 853 libzfs_mnttab_fini(hdl);
848 854 rewind(hdl->libzfs_mnttab);
849 855 srch.mnt_special = (char *)fsname;
850 856 srch.mnt_fstype = MNTTYPE_ZFS;
851 857 if (getmntany(hdl->libzfs_mnttab, entry, &srch) == 0)
852 858 return (0);
853 859 else
854 860 return (ENOENT);
855 861 }
856 862
857 863 if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0)
858 864 libzfs_mnttab_update(hdl);
859 865
860 866 find.mtn_mt.mnt_special = (char *)fsname;
861 867 mtn = avl_find(&hdl->libzfs_mnttab_cache, &find, NULL);
862 868 if (mtn) {
863 869 *entry = mtn->mtn_mt;
864 870 return (0);
865 871 }
866 872 return (ENOENT);
867 873 }
868 874
869 875 void
870 876 libzfs_mnttab_add(libzfs_handle_t *hdl, const char *special,
871 877 const char *mountp, const char *mntopts)
872 878 {
873 879 mnttab_node_t *mtn;
874 880
875 881 if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0)
876 882 return;
877 883 mtn = zfs_alloc(hdl, sizeof (mnttab_node_t));
878 884 mtn->mtn_mt.mnt_special = zfs_strdup(hdl, special);
879 885 mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, mountp);
880 886 mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, MNTTYPE_ZFS);
881 887 mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, mntopts);
882 888 avl_add(&hdl->libzfs_mnttab_cache, mtn);
883 889 }
884 890
885 891 void
886 892 libzfs_mnttab_remove(libzfs_handle_t *hdl, const char *fsname)
887 893 {
888 894 mnttab_node_t find;
889 895 mnttab_node_t *ret;
890 896
891 897 find.mtn_mt.mnt_special = (char *)fsname;
892 898 if ((ret = avl_find(&hdl->libzfs_mnttab_cache, (void *)&find, NULL))
893 899 != NULL) {
894 900 avl_remove(&hdl->libzfs_mnttab_cache, ret);
895 901 free(ret->mtn_mt.mnt_special);
896 902 free(ret->mtn_mt.mnt_mountp);
897 903 free(ret->mtn_mt.mnt_fstype);
898 904 free(ret->mtn_mt.mnt_mntopts);
899 905 free(ret);
900 906 }
901 907 }
902 908
903 909 int
904 910 zfs_spa_version(zfs_handle_t *zhp, int *spa_version)
905 911 {
906 912 zpool_handle_t *zpool_handle = zhp->zpool_hdl;
907 913
908 914 if (zpool_handle == NULL)
909 915 return (-1);
910 916
911 917 *spa_version = zpool_get_prop_int(zpool_handle,
912 918 ZPOOL_PROP_VERSION, NULL);
913 919 return (0);
914 920 }
915 921
916 922 /*
917 923 * The choice of reservation property depends on the SPA version.
918 924 */
919 925 static int
920 926 zfs_which_resv_prop(zfs_handle_t *zhp, zfs_prop_t *resv_prop)
921 927 {
922 928 int spa_version;
923 929
924 930 if (zfs_spa_version(zhp, &spa_version) < 0)
925 931 return (-1);
926 932
927 933 if (spa_version >= SPA_VERSION_REFRESERVATION)
928 934 *resv_prop = ZFS_PROP_REFRESERVATION;
929 935 else
930 936 *resv_prop = ZFS_PROP_RESERVATION;
931 937
932 938 return (0);
933 939 }
934 940
935 941 /*
936 942 * Given an nvlist of properties to set, validates that they are correct, and
937 943 * parses any numeric properties (index, boolean, etc) if they are specified as
938 944 * strings.
939 945 */
940 946 nvlist_t *
941 947 zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
942 948 uint64_t zoned, zfs_handle_t *zhp, zpool_handle_t *zpool_hdl,
943 949 const char *errbuf)
944 950 {
945 951 nvpair_t *elem;
946 952 uint64_t intval;
947 953 char *strval;
948 954 zfs_prop_t prop;
949 955 nvlist_t *ret;
950 956 int chosen_normal = -1;
951 957 int chosen_utf = -1;
952 958
953 959 if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) {
954 960 (void) no_memory(hdl);
955 961 return (NULL);
956 962 }
957 963
958 964 /*
959 965 * Make sure this property is valid and applies to this type.
960 966 */
961 967
962 968 elem = NULL;
963 969 while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) {
964 970 const char *propname = nvpair_name(elem);
965 971
966 972 prop = zfs_name_to_prop(propname);
967 973 if (prop == ZPROP_INVAL && zfs_prop_user(propname)) {
968 974 /*
969 975 * This is a user property: make sure it's a
970 976 * string, and that it's less than ZAP_MAXNAMELEN.
971 977 */
972 978 if (nvpair_type(elem) != DATA_TYPE_STRING) {
973 979 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
974 980 "'%s' must be a string"), propname);
975 981 (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
976 982 goto error;
977 983 }
978 984
979 985 if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) {
980 986 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
981 987 "property name '%s' is too long"),
982 988 propname);
983 989 (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
984 990 goto error;
985 991 }
986 992
987 993 (void) nvpair_value_string(elem, &strval);
988 994 if (nvlist_add_string(ret, propname, strval) != 0) {
989 995 (void) no_memory(hdl);
990 996 goto error;
991 997 }
992 998 continue;
993 999 }
994 1000
995 1001 /*
996 1002 * Currently, only user properties can be modified on
997 1003 * snapshots.
998 1004 */
999 1005 if (type == ZFS_TYPE_SNAPSHOT) {
1000 1006 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1001 1007 "this property can not be modified for snapshots"));
1002 1008 (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf);
1003 1009 goto error;
1004 1010 }
1005 1011
1006 1012 if (prop == ZPROP_INVAL && zfs_prop_userquota(propname)) {
1007 1013 zfs_userquota_prop_t uqtype;
1008 1014 char newpropname[128];
1009 1015 char domain[128];
1010 1016 uint64_t rid;
1011 1017 uint64_t valary[3];
1012 1018
1013 1019 if (userquota_propname_decode(propname, zoned,
1014 1020 &uqtype, domain, sizeof (domain), &rid) != 0) {
1015 1021 zfs_error_aux(hdl,
1016 1022 dgettext(TEXT_DOMAIN,
1017 1023 "'%s' has an invalid user/group name"),
1018 1024 propname);
1019 1025 (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1020 1026 goto error;
1021 1027 }
1022 1028
1023 1029 if (uqtype != ZFS_PROP_USERQUOTA &&
1024 1030 uqtype != ZFS_PROP_GROUPQUOTA) {
1025 1031 zfs_error_aux(hdl,
1026 1032 dgettext(TEXT_DOMAIN, "'%s' is readonly"),
1027 1033 propname);
1028 1034 (void) zfs_error(hdl, EZFS_PROPREADONLY,
1029 1035 errbuf);
1030 1036 goto error;
1031 1037 }
1032 1038
1033 1039 if (nvpair_type(elem) == DATA_TYPE_STRING) {
1034 1040 (void) nvpair_value_string(elem, &strval);
1035 1041 if (strcmp(strval, "none") == 0) {
1036 1042 intval = 0;
1037 1043 } else if (zfs_nicestrtonum(hdl,
1038 1044 strval, &intval) != 0) {
1039 1045 (void) zfs_error(hdl,
1040 1046 EZFS_BADPROP, errbuf);
1041 1047 goto error;
1042 1048 }
1043 1049 } else if (nvpair_type(elem) ==
1044 1050 DATA_TYPE_UINT64) {
1045 1051 (void) nvpair_value_uint64(elem, &intval);
1046 1052 if (intval == 0) {
1047 1053 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1048 1054 "use 'none' to disable "
1049 1055 "userquota/groupquota"));
1050 1056 goto error;
1051 1057 }
1052 1058 } else {
1053 1059 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1054 1060 "'%s' must be a number"), propname);
1055 1061 (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1056 1062 goto error;
1057 1063 }
1058 1064
1059 1065 /*
1060 1066 * Encode the prop name as
1061 1067 * userquota@<hex-rid>-domain, to make it easy
1062 1068 * for the kernel to decode.
1063 1069 */
1064 1070 (void) snprintf(newpropname, sizeof (newpropname),
1065 1071 "%s%llx-%s", zfs_userquota_prop_prefixes[uqtype],
1066 1072 (longlong_t)rid, domain);
1067 1073 valary[0] = uqtype;
1068 1074 valary[1] = rid;
1069 1075 valary[2] = intval;
1070 1076 if (nvlist_add_uint64_array(ret, newpropname,
1071 1077 valary, 3) != 0) {
1072 1078 (void) no_memory(hdl);
1073 1079 goto error;
1074 1080 }
1075 1081 continue;
1076 1082 } else if (prop == ZPROP_INVAL && zfs_prop_written(propname)) {
1077 1083 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1078 1084 "'%s' is readonly"),
1079 1085 propname);
1080 1086 (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf);
1081 1087 goto error;
1082 1088 }
1083 1089
1084 1090 if (prop == ZPROP_INVAL) {
1085 1091 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1086 1092 "invalid property '%s'"), propname);
1087 1093 (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1088 1094 goto error;
1089 1095 }
1090 1096
1091 1097 if (!zfs_prop_valid_for_type(prop, type)) {
1092 1098 zfs_error_aux(hdl,
1093 1099 dgettext(TEXT_DOMAIN, "'%s' does not "
1094 1100 "apply to datasets of this type"), propname);
1095 1101 (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf);
1096 1102 goto error;
1097 1103 }
1098 1104
1099 1105 if (zfs_prop_readonly(prop) &&
1100 1106 (!zfs_prop_setonce(prop) || zhp != NULL)) {
1101 1107 zfs_error_aux(hdl,
1102 1108 dgettext(TEXT_DOMAIN, "'%s' is readonly"),
1103 1109 propname);
1104 1110 (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf);
1105 1111 goto error;
1106 1112 }
1107 1113
1108 1114 if (zprop_parse_value(hdl, elem, prop, type, ret,
1109 1115 &strval, &intval, errbuf) != 0)
1110 1116 goto error;
1111 1117
1112 1118 /*
1113 1119 * Perform some additional checks for specific properties.
1114 1120 */
1115 1121 switch (prop) {
1116 1122 case ZFS_PROP_VERSION:
1117 1123 {
1118 1124 int version;
1119 1125
1120 1126 if (zhp == NULL)
1121 1127 break;
1122 1128 version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION);
1123 1129 if (intval < version) {
1124 1130 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1125 1131 "Can not downgrade; already at version %u"),
1126 1132 version);
1127 1133 (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1128 1134 goto error;
1129 1135 }
1130 1136 break;
1131 1137 }
1132 1138
1133 1139 case ZFS_PROP_VOLBLOCKSIZE:
1134 1140 case ZFS_PROP_RECORDSIZE:
1135 1141 {
1136 1142 int maxbs = SPA_MAXBLOCKSIZE;
1137 1143 if (zpool_hdl != NULL) {
1138 1144 maxbs = zpool_get_prop_int(zpool_hdl,
1139 1145 ZPOOL_PROP_MAXBLOCKSIZE, NULL);
1140 1146 }
1141 1147 /*
1142 1148 * Volumes are limited to a volblocksize of 128KB,
1143 1149 * because they typically service workloads with
1144 1150 * small random writes, which incur a large performance
1145 1151 * penalty with large blocks.
1146 1152 */
1147 1153 if (prop == ZFS_PROP_VOLBLOCKSIZE)
1148 1154 maxbs = SPA_OLD_MAXBLOCKSIZE;
1149 1155 /*
1150 1156 * The value must be a power of two between
1151 1157 * SPA_MINBLOCKSIZE and maxbs.
1152 1158 */
1153 1159 if (intval < SPA_MINBLOCKSIZE ||
1154 1160 intval > maxbs || !ISP2(intval)) {
1155 1161 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1156 1162 "'%s' must be power of 2 from 512B "
1157 1163 "to %uKB"), propname, maxbs >> 10);
1158 1164 (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1159 1165 goto error;
1160 1166 }
1161 1167 break;
1162 1168 }
1163 1169 case ZFS_PROP_MLSLABEL:
1164 1170 {
1165 1171 /*
1166 1172 * Verify the mlslabel string and convert to
1167 1173 * internal hex label string.
1168 1174 */
1169 1175
1170 1176 m_label_t *new_sl;
1171 1177 char *hex = NULL; /* internal label string */
1172 1178
1173 1179 /* Default value is already OK. */
1174 1180 if (strcasecmp(strval, ZFS_MLSLABEL_DEFAULT) == 0)
1175 1181 break;
1176 1182
1177 1183 /* Verify the label can be converted to binary form */
1178 1184 if (((new_sl = m_label_alloc(MAC_LABEL)) == NULL) ||
1179 1185 (str_to_label(strval, &new_sl, MAC_LABEL,
1180 1186 L_NO_CORRECTION, NULL) == -1)) {
1181 1187 goto badlabel;
1182 1188 }
1183 1189
1184 1190 /* Now translate to hex internal label string */
1185 1191 if (label_to_str(new_sl, &hex, M_INTERNAL,
1186 1192 DEF_NAMES) != 0) {
1187 1193 if (hex)
1188 1194 free(hex);
1189 1195 goto badlabel;
1190 1196 }
1191 1197 m_label_free(new_sl);
1192 1198
1193 1199 /* If string is already in internal form, we're done. */
1194 1200 if (strcmp(strval, hex) == 0) {
1195 1201 free(hex);
1196 1202 break;
1197 1203 }
1198 1204
1199 1205 /* Replace the label string with the internal form. */
1200 1206 (void) nvlist_remove(ret, zfs_prop_to_name(prop),
1201 1207 DATA_TYPE_STRING);
1202 1208 verify(nvlist_add_string(ret, zfs_prop_to_name(prop),
1203 1209 hex) == 0);
1204 1210 free(hex);
1205 1211
1206 1212 break;
1207 1213
1208 1214 badlabel:
1209 1215 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1210 1216 "invalid mlslabel '%s'"), strval);
1211 1217 (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1212 1218 m_label_free(new_sl); /* OK if null */
1213 1219 goto error;
1214 1220
1215 1221 }
1216 1222
1217 1223 case ZFS_PROP_MOUNTPOINT:
1218 1224 {
1219 1225 namecheck_err_t why;
1220 1226
1221 1227 if (strcmp(strval, ZFS_MOUNTPOINT_NONE) == 0 ||
1222 1228 strcmp(strval, ZFS_MOUNTPOINT_LEGACY) == 0)
1223 1229 break;
1224 1230
1225 1231 if (mountpoint_namecheck(strval, &why)) {
1226 1232 switch (why) {
1227 1233 case NAME_ERR_LEADING_SLASH:
1228 1234 zfs_error_aux(hdl,
1229 1235 dgettext(TEXT_DOMAIN,
1230 1236 "'%s' must be an absolute path, "
1231 1237 "'none', or 'legacy'"), propname);
1232 1238 break;
1233 1239 case NAME_ERR_TOOLONG:
1234 1240 zfs_error_aux(hdl,
1235 1241 dgettext(TEXT_DOMAIN,
1236 1242 "component of '%s' is too long"),
1237 1243 propname);
1238 1244 break;
1239 1245
1240 1246 default:
1241 1247 zfs_error_aux(hdl,
1242 1248 dgettext(TEXT_DOMAIN,
1243 1249 "(%d) not defined"),
1244 1250 why);
1245 1251 break;
1246 1252 }
1247 1253 (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1248 1254 goto error;
1249 1255 }
1250 1256 }
1251 1257
1252 1258 /*FALLTHRU*/
1253 1259
1254 1260 case ZFS_PROP_SHARESMB:
|
↓ open down ↓ |
799 lines elided |
↑ open up ↑ |
1255 1261 case ZFS_PROP_SHARENFS:
1256 1262 /*
1257 1263 * For the mountpoint and sharenfs or sharesmb
1258 1264 * properties, check if it can be set in a
1259 1265 * global/non-global zone based on
1260 1266 * the zoned property value:
1261 1267 *
1262 1268 * global zone non-global zone
1263 1269 * --------------------------------------------------
1264 1270 * zoned=on mountpoint (no) mountpoint (yes)
1265 - * sharenfs (no) sharenfs (no)
1271 + * sharenfs (no) sharenfs (yes)
1266 1272 * sharesmb (no) sharesmb (no)
1267 1273 *
1268 1274 * zoned=off mountpoint (yes) N/A
1269 1275 * sharenfs (yes)
1270 1276 * sharesmb (yes)
1271 1277 */
1272 1278 if (zoned) {
1273 1279 if (getzoneid() == GLOBAL_ZONEID) {
1274 1280 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1275 1281 "'%s' cannot be set on "
1276 1282 "dataset in a non-global zone"),
1277 1283 propname);
1278 1284 (void) zfs_error(hdl, EZFS_ZONED,
1279 1285 errbuf);
1280 1286 goto error;
1281 - } else if (prop == ZFS_PROP_SHARENFS ||
1282 - prop == ZFS_PROP_SHARESMB) {
1283 - zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1284 - "'%s' cannot be set in "
1285 - "a non-global zone"), propname);
1286 - (void) zfs_error(hdl, EZFS_ZONED,
1287 - errbuf);
1288 - goto error;
1289 1287 }
1290 1288 } else if (getzoneid() != GLOBAL_ZONEID) {
1291 1289 /*
1292 1290 * If zoned property is 'off', this must be in
1293 1291 * a global zone. If not, something is wrong.
1294 1292 */
1295 1293 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1296 1294 "'%s' cannot be set while dataset "
1297 1295 "'zoned' property is set"), propname);
1298 1296 (void) zfs_error(hdl, EZFS_ZONED, errbuf);
1299 1297 goto error;
1300 1298 }
1301 1299
1302 1300 /*
1303 1301 * At this point, it is legitimate to set the
1304 1302 * property. Now we want to make sure that the
1305 1303 * property value is valid if it is sharenfs.
1306 1304 */
1307 1305 if ((prop == ZFS_PROP_SHARENFS ||
1308 1306 prop == ZFS_PROP_SHARESMB) &&
1309 1307 strcmp(strval, "on") != 0 &&
1310 1308 strcmp(strval, "off") != 0) {
1311 1309 zfs_share_proto_t proto;
1312 1310
1313 1311 if (prop == ZFS_PROP_SHARESMB)
1314 1312 proto = PROTO_SMB;
1315 1313 else
1316 1314 proto = PROTO_NFS;
1317 1315
1318 1316 /*
1319 1317 * Must be an valid sharing protocol
1320 1318 * option string so init the libshare
1321 1319 * in order to enable the parser and
1322 1320 * then parse the options. We use the
1323 1321 * control API since we don't care about
1324 1322 * the current configuration and don't
1325 1323 * want the overhead of loading it
1326 1324 * until we actually do something.
1327 1325 */
1328 1326
1329 1327 if (zfs_init_libshare(hdl,
1330 1328 SA_INIT_CONTROL_API) != SA_OK) {
1331 1329 /*
1332 1330 * An error occurred so we can't do
1333 1331 * anything
1334 1332 */
1335 1333 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1336 1334 "'%s' cannot be set: problem "
1337 1335 "in share initialization"),
1338 1336 propname);
1339 1337 (void) zfs_error(hdl, EZFS_BADPROP,
1340 1338 errbuf);
1341 1339 goto error;
1342 1340 }
1343 1341
1344 1342 if (zfs_parse_options(strval, proto) != SA_OK) {
1345 1343 /*
1346 1344 * There was an error in parsing so
1347 1345 * deal with it by issuing an error
1348 1346 * message and leaving after
1349 1347 * uninitializing the the libshare
1350 1348 * interface.
1351 1349 */
1352 1350 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1353 1351 "'%s' cannot be set to invalid "
1354 1352 "options"), propname);
1355 1353 (void) zfs_error(hdl, EZFS_BADPROP,
1356 1354 errbuf);
1357 1355 zfs_uninit_libshare(hdl);
1358 1356 goto error;
1359 1357 }
1360 1358 zfs_uninit_libshare(hdl);
1361 1359 }
1362 1360
1363 1361 break;
1364 1362
1365 1363 case ZFS_PROP_UTF8ONLY:
1366 1364 chosen_utf = (int)intval;
1367 1365 break;
1368 1366
1369 1367 case ZFS_PROP_NORMALIZE:
1370 1368 chosen_normal = (int)intval;
1371 1369 break;
1372 1370
1373 1371 default:
1374 1372 break;
1375 1373 }
1376 1374
1377 1375 /*
1378 1376 * For changes to existing volumes, we have some additional
1379 1377 * checks to enforce.
1380 1378 */
1381 1379 if (type == ZFS_TYPE_VOLUME && zhp != NULL) {
1382 1380 uint64_t volsize = zfs_prop_get_int(zhp,
1383 1381 ZFS_PROP_VOLSIZE);
1384 1382 uint64_t blocksize = zfs_prop_get_int(zhp,
1385 1383 ZFS_PROP_VOLBLOCKSIZE);
1386 1384 char buf[64];
1387 1385
1388 1386 switch (prop) {
1389 1387 case ZFS_PROP_RESERVATION:
1390 1388 case ZFS_PROP_REFRESERVATION:
1391 1389 if (intval > volsize) {
1392 1390 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1393 1391 "'%s' is greater than current "
1394 1392 "volume size"), propname);
1395 1393 (void) zfs_error(hdl, EZFS_BADPROP,
1396 1394 errbuf);
1397 1395 goto error;
1398 1396 }
1399 1397 break;
1400 1398
1401 1399 case ZFS_PROP_VOLSIZE:
1402 1400 if (intval % blocksize != 0) {
1403 1401 zfs_nicenum(blocksize, buf,
1404 1402 sizeof (buf));
1405 1403 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1406 1404 "'%s' must be a multiple of "
1407 1405 "volume block size (%s)"),
1408 1406 propname, buf);
1409 1407 (void) zfs_error(hdl, EZFS_BADPROP,
1410 1408 errbuf);
1411 1409 goto error;
1412 1410 }
1413 1411
1414 1412 if (intval == 0) {
1415 1413 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1416 1414 "'%s' cannot be zero"),
1417 1415 propname);
1418 1416 (void) zfs_error(hdl, EZFS_BADPROP,
1419 1417 errbuf);
1420 1418 goto error;
1421 1419 }
1422 1420 break;
1423 1421
1424 1422 default:
1425 1423 break;
1426 1424 }
1427 1425 }
1428 1426 }
1429 1427
1430 1428 /*
1431 1429 * If normalization was chosen, but no UTF8 choice was made,
1432 1430 * enforce rejection of non-UTF8 names.
1433 1431 *
1434 1432 * If normalization was chosen, but rejecting non-UTF8 names
1435 1433 * was explicitly not chosen, it is an error.
1436 1434 */
1437 1435 if (chosen_normal > 0 && chosen_utf < 0) {
1438 1436 if (nvlist_add_uint64(ret,
1439 1437 zfs_prop_to_name(ZFS_PROP_UTF8ONLY), 1) != 0) {
1440 1438 (void) no_memory(hdl);
1441 1439 goto error;
1442 1440 }
1443 1441 } else if (chosen_normal > 0 && chosen_utf == 0) {
1444 1442 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1445 1443 "'%s' must be set 'on' if normalization chosen"),
1446 1444 zfs_prop_to_name(ZFS_PROP_UTF8ONLY));
1447 1445 (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1448 1446 goto error;
1449 1447 }
1450 1448 return (ret);
1451 1449
1452 1450 error:
1453 1451 nvlist_free(ret);
1454 1452 return (NULL);
1455 1453 }
1456 1454
1457 1455 int
1458 1456 zfs_add_synthetic_resv(zfs_handle_t *zhp, nvlist_t *nvl)
1459 1457 {
1460 1458 uint64_t old_volsize;
1461 1459 uint64_t new_volsize;
1462 1460 uint64_t old_reservation;
1463 1461 uint64_t new_reservation;
1464 1462 zfs_prop_t resv_prop;
1465 1463 nvlist_t *props;
1466 1464
1467 1465 /*
1468 1466 * If this is an existing volume, and someone is setting the volsize,
1469 1467 * make sure that it matches the reservation, or add it if necessary.
1470 1468 */
1471 1469 old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
1472 1470 if (zfs_which_resv_prop(zhp, &resv_prop) < 0)
1473 1471 return (-1);
1474 1472 old_reservation = zfs_prop_get_int(zhp, resv_prop);
1475 1473
1476 1474 props = fnvlist_alloc();
1477 1475 fnvlist_add_uint64(props, zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
1478 1476 zfs_prop_get_int(zhp, ZFS_PROP_VOLBLOCKSIZE));
1479 1477
1480 1478 if ((zvol_volsize_to_reservation(old_volsize, props) !=
1481 1479 old_reservation) || nvlist_exists(nvl,
1482 1480 zfs_prop_to_name(resv_prop))) {
1483 1481 fnvlist_free(props);
1484 1482 return (0);
1485 1483 }
1486 1484 if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(ZFS_PROP_VOLSIZE),
1487 1485 &new_volsize) != 0) {
1488 1486 fnvlist_free(props);
1489 1487 return (-1);
1490 1488 }
1491 1489 new_reservation = zvol_volsize_to_reservation(new_volsize, props);
1492 1490 fnvlist_free(props);
1493 1491
1494 1492 if (nvlist_add_uint64(nvl, zfs_prop_to_name(resv_prop),
1495 1493 new_reservation) != 0) {
1496 1494 (void) no_memory(zhp->zfs_hdl);
1497 1495 return (-1);
1498 1496 }
1499 1497 return (1);
1500 1498 }
1501 1499
1502 1500 void
1503 1501 zfs_setprop_error(libzfs_handle_t *hdl, zfs_prop_t prop, int err,
1504 1502 char *errbuf)
1505 1503 {
1506 1504 switch (err) {
1507 1505
1508 1506 case ENOSPC:
1509 1507 /*
1510 1508 * For quotas and reservations, ENOSPC indicates
1511 1509 * something different; setting a quota or reservation
1512 1510 * doesn't use any disk space.
1513 1511 */
1514 1512 switch (prop) {
1515 1513 case ZFS_PROP_QUOTA:
1516 1514 case ZFS_PROP_REFQUOTA:
1517 1515 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1518 1516 "size is less than current used or "
1519 1517 "reserved space"));
1520 1518 (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf);
1521 1519 break;
1522 1520
1523 1521 case ZFS_PROP_RESERVATION:
1524 1522 case ZFS_PROP_REFRESERVATION:
1525 1523 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1526 1524 "size is greater than available space"));
1527 1525 (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf);
1528 1526 break;
1529 1527
1530 1528 default:
1531 1529 (void) zfs_standard_error(hdl, err, errbuf);
1532 1530 break;
1533 1531 }
1534 1532 break;
1535 1533
1536 1534 case EBUSY:
1537 1535 (void) zfs_standard_error(hdl, EBUSY, errbuf);
1538 1536 break;
1539 1537
1540 1538 case EROFS:
1541 1539 (void) zfs_error(hdl, EZFS_DSREADONLY, errbuf);
1542 1540 break;
1543 1541
1544 1542 case E2BIG:
1545 1543 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1546 1544 "property value too long"));
1547 1545 (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1548 1546 break;
1549 1547
|
↓ open down ↓ |
251 lines elided |
↑ open up ↑ |
1550 1548 case ENOTSUP:
1551 1549 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1552 1550 "pool and or dataset must be upgraded to set this "
1553 1551 "property or value"));
1554 1552 (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
1555 1553 break;
1556 1554
1557 1555 case ERANGE:
1558 1556 if (prop == ZFS_PROP_COMPRESSION ||
1559 1557 prop == ZFS_PROP_RECORDSIZE) {
1560 - (void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1558 + (void) zfs_error_aux(hdl,
1559 + dgettext(TEXT_DOMAIN,
1561 1560 "property setting is not allowed on "
1562 1561 "bootable datasets"));
1563 1562 (void) zfs_error(hdl, EZFS_NOTSUP, errbuf);
1564 1563 } else if (prop == ZFS_PROP_CHECKSUM ||
1565 1564 prop == ZFS_PROP_DEDUP) {
1566 1565 (void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1567 1566 "property setting is not allowed on "
1568 1567 "root pools"));
1569 1568 (void) zfs_error(hdl, EZFS_NOTSUP, errbuf);
1570 1569 } else {
1571 1570 (void) zfs_standard_error(hdl, err, errbuf);
1572 1571 }
|
↓ open down ↓ |
2 lines elided |
↑ open up ↑ |
1573 1572 break;
1574 1573
1575 1574 case EINVAL:
1576 1575 if (prop == ZPROP_INVAL) {
1577 1576 (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1578 1577 } else {
1579 1578 (void) zfs_standard_error(hdl, err, errbuf);
1580 1579 }
1581 1580 break;
1582 1581
1582 + case EKZFS_WBCCONFLICT:
1583 + if (prop == ZFS_PROP_WBC_MODE || prop == ZFS_PROP_DEDUP) {
1584 + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1585 + "WBC and deduplication cannot be "
1586 + "active simultaneously on the "
1587 + "same dataset"));
1588 + (void) zfs_error(hdl, EZFS_WBCNOTSUP, errbuf);
1589 + } else {
1590 + (void) zfs_standard_error(hdl, err, errbuf);
1591 + }
1592 +
1593 + break;
1594 +
1583 1595 case EOVERFLOW:
1584 1596 /*
1585 1597 * This platform can't address a volume this big.
1586 1598 */
1587 1599 #ifdef _ILP32
1588 1600 if (prop == ZFS_PROP_VOLSIZE) {
1589 1601 (void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf);
1590 1602 break;
1591 1603 }
1592 1604 #endif
1593 1605 /* FALLTHROUGH */
1594 1606 default:
1595 - (void) zfs_standard_error(hdl, err, errbuf);
1607 + if (prop != ZFS_PROP_WBC_MODE) {
1608 + (void) zfs_standard_error(hdl, err, errbuf);
1609 + break;
1610 + }
1611 +
1612 + switch (err) {
1613 + case EINPROGRESS:
1614 + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1615 + "WBC cannot be enabled for the dataset since "
1616 + "the latter is currently in transition to "
1617 + "wbc_mode = off. Try again later"));
1618 + (void) zfs_error(hdl, EZFS_WBCINPROGRESS, errbuf);
1619 + break;
1620 + case EALREADY:
1621 + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1622 + "WBC is already in the requested (on/off) "
1623 + "state, nothing to do"));
1624 + (void) zfs_error(hdl, EZFS_WBCALREADY, errbuf);
1625 + break;
1626 + case EKZFS_WBCNOTSUP:
1627 + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1628 + "feature@wbc is not enabled or "
1629 + "special device (special vdev) is not present"));
1630 + (void) zfs_error(hdl, EZFS_WBCNOTSUP, errbuf);
1631 + break;
1632 + case EKZFS_WBCCHILD:
1633 + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1634 + "a child dataset has this property enabled"));
1635 + (void) zfs_error(hdl, EZFS_WBCCHILD, errbuf);
1636 + break;
1637 + case EKZFS_WBCPARENT:
1638 + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1639 + "a parent dataset has this property enabled"));
1640 + (void) zfs_error(hdl, EZFS_WBCPARENT, errbuf);
1641 + break;
1642 + default:
1643 + (void) zfs_standard_error(hdl, err, errbuf);
1644 + break;
1645 + }
1596 1646 }
1597 1647 }
1598 1648
1599 1649 /*
1600 1650 * Given a property name and value, set the property for the given dataset.
1601 1651 */
1602 1652 int
1603 1653 zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval)
1604 1654 {
1605 1655 int ret = -1;
1606 1656 char errbuf[1024];
1607 1657 libzfs_handle_t *hdl = zhp->zfs_hdl;
1608 1658 nvlist_t *nvl = NULL;
1609 1659
1610 1660 (void) snprintf(errbuf, sizeof (errbuf),
1611 1661 dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
1612 1662 zhp->zfs_name);
1613 1663
1614 1664 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
1615 1665 nvlist_add_string(nvl, propname, propval) != 0) {
1616 1666 (void) no_memory(hdl);
1617 1667 goto error;
1618 1668 }
1619 1669
1620 1670 ret = zfs_prop_set_list(zhp, nvl);
1621 1671
1622 1672 error:
1623 1673 nvlist_free(nvl);
1624 1674 return (ret);
1625 1675 }
1626 1676
1627 1677
1628 1678
1629 1679 /*
1630 1680 * Given an nvlist of property names and values, set the properties for the
1631 1681 * given dataset.
1632 1682 */
1633 1683 int
1634 1684 zfs_prop_set_list(zfs_handle_t *zhp, nvlist_t *props)
1635 1685 {
1636 1686 zfs_cmd_t zc = { 0 };
1637 1687 int ret = -1;
1638 1688 prop_changelist_t **cls = NULL;
1639 1689 int cl_idx;
1640 1690 char errbuf[1024];
1641 1691 libzfs_handle_t *hdl = zhp->zfs_hdl;
1642 1692 nvlist_t *nvl;
1643 1693 int nvl_len;
1644 1694 int added_resv = 0;
1645 1695
1646 1696 (void) snprintf(errbuf, sizeof (errbuf),
1647 1697 dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
1648 1698 zhp->zfs_name);
1649 1699
1650 1700 if ((nvl = zfs_valid_proplist(hdl, zhp->zfs_type, props,
1651 1701 zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, zhp->zpool_hdl,
1652 1702 errbuf)) == NULL)
1653 1703 goto error;
1654 1704
1655 1705 /*
1656 1706 * We have to check for any extra properties which need to be added
1657 1707 * before computing the length of the nvlist.
1658 1708 */
1659 1709 for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL);
1660 1710 elem != NULL;
1661 1711 elem = nvlist_next_nvpair(nvl, elem)) {
1662 1712 if (zfs_name_to_prop(nvpair_name(elem)) == ZFS_PROP_VOLSIZE &&
1663 1713 (added_resv = zfs_add_synthetic_resv(zhp, nvl)) == -1) {
1664 1714 goto error;
1665 1715 }
1666 1716 }
1667 1717 /*
1668 1718 * Check how many properties we're setting and allocate an array to
1669 1719 * store changelist pointers for postfix().
1670 1720 */
1671 1721 nvl_len = 0;
1672 1722 for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL);
1673 1723 elem != NULL;
1674 1724 elem = nvlist_next_nvpair(nvl, elem))
1675 1725 nvl_len++;
1676 1726 if ((cls = calloc(nvl_len, sizeof (prop_changelist_t *))) == NULL)
1677 1727 goto error;
1678 1728
1679 1729 cl_idx = 0;
1680 1730 for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL);
1681 1731 elem != NULL;
1682 1732 elem = nvlist_next_nvpair(nvl, elem)) {
1683 1733
1684 1734 zfs_prop_t prop = zfs_name_to_prop(nvpair_name(elem));
1685 1735
1686 1736 assert(cl_idx < nvl_len);
1687 1737 /*
1688 1738 * We don't want to unmount & remount the dataset when changing
1689 1739 * its canmount property to 'on' or 'noauto'. We only use
1690 1740 * the changelist logic to unmount when setting canmount=off.
1691 1741 */
1692 1742 if (prop != ZFS_PROP_CANMOUNT ||
1693 1743 (fnvpair_value_uint64(elem) == ZFS_CANMOUNT_OFF &&
1694 1744 zfs_is_mounted(zhp, NULL))) {
1695 1745 cls[cl_idx] = changelist_gather(zhp, prop, 0, 0);
1696 1746 if (cls[cl_idx] == NULL)
1697 1747 goto error;
1698 1748 }
1699 1749
1700 1750 if (prop == ZFS_PROP_MOUNTPOINT &&
1701 1751 changelist_haszonedchild(cls[cl_idx])) {
1702 1752 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1703 1753 "child dataset with inherited mountpoint is used "
1704 1754 "in a non-global zone"));
1705 1755 ret = zfs_error(hdl, EZFS_ZONED, errbuf);
1706 1756 goto error;
1707 1757 }
1708 1758
1709 1759 if (cls[cl_idx] != NULL &&
1710 1760 (ret = changelist_prefix(cls[cl_idx])) != 0)
1711 1761 goto error;
1712 1762
1713 1763 cl_idx++;
1714 1764 }
1715 1765 assert(cl_idx == nvl_len);
1716 1766
1717 1767 /*
1718 1768 * Execute the corresponding ioctl() to set this list of properties.
|
↓ open down ↓ |
113 lines elided |
↑ open up ↑ |
1719 1769 */
1720 1770 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
1721 1771
1722 1772 if ((ret = zcmd_write_src_nvlist(hdl, &zc, nvl)) != 0 ||
1723 1773 (ret = zcmd_alloc_dst_nvlist(hdl, &zc, 0)) != 0)
1724 1774 goto error;
1725 1775
1726 1776 ret = zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc);
1727 1777
1728 1778 if (ret != 0) {
1779 + if (zc.zc_nvlist_dst_filled == B_FALSE) {
1780 + (void) zfs_standard_error(hdl, errno, errbuf);
1781 + goto error;
1782 + }
1783 +
1729 1784 /* Get the list of unset properties back and report them. */
1730 1785 nvlist_t *errorprops = NULL;
1731 1786 if (zcmd_read_dst_nvlist(hdl, &zc, &errorprops) != 0)
1732 1787 goto error;
1733 - for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL);
1788 + for (nvpair_t *elem = nvlist_next_nvpair(errorprops, NULL);
1734 1789 elem != NULL;
1735 - elem = nvlist_next_nvpair(nvl, elem)) {
1790 + elem = nvlist_next_nvpair(errorprops, elem)) {
1736 1791 zfs_prop_t prop = zfs_name_to_prop(nvpair_name(elem));
1737 1792 zfs_setprop_error(hdl, prop, errno, errbuf);
1738 1793 }
1739 1794 nvlist_free(errorprops);
1740 1795
1741 1796 if (added_resv && errno == ENOSPC) {
1742 1797 /* clean up the volsize property we tried to set */
1743 1798 uint64_t old_volsize = zfs_prop_get_int(zhp,
1744 1799 ZFS_PROP_VOLSIZE);
1745 1800 nvlist_free(nvl);
1746 1801 nvl = NULL;
1747 1802 zcmd_free_nvlists(&zc);
1748 1803
1749 1804 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
1750 1805 goto error;
1751 1806 if (nvlist_add_uint64(nvl,
1752 1807 zfs_prop_to_name(ZFS_PROP_VOLSIZE),
1753 1808 old_volsize) != 0)
1754 1809 goto error;
1755 1810 if (zcmd_write_src_nvlist(hdl, &zc, nvl) != 0)
1756 1811 goto error;
1757 1812 (void) zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc);
1758 1813 }
1759 1814 } else {
1760 1815 for (cl_idx = 0; cl_idx < nvl_len; cl_idx++) {
1761 1816 if (cls[cl_idx] != NULL) {
1762 1817 int clp_err = changelist_postfix(cls[cl_idx]);
1763 1818 if (clp_err != 0)
1764 1819 ret = clp_err;
1765 1820 }
1766 1821 }
1767 1822
1768 1823 /*
1769 1824 * Refresh the statistics so the new property value
1770 1825 * is reflected.
1771 1826 */
1772 1827 if (ret == 0)
1773 1828 (void) get_stats(zhp);
1774 1829 }
1775 1830
1776 1831 error:
1777 1832 nvlist_free(nvl);
1778 1833 zcmd_free_nvlists(&zc);
1779 1834 if (cls != NULL) {
1780 1835 for (cl_idx = 0; cl_idx < nvl_len; cl_idx++) {
1781 1836 if (cls[cl_idx] != NULL)
1782 1837 changelist_free(cls[cl_idx]);
1783 1838 }
1784 1839 free(cls);
1785 1840 }
1786 1841 return (ret);
1787 1842 }
1788 1843
1789 1844 /*
1790 1845 * Given a property, inherit the value from the parent dataset, or if received
1791 1846 * is TRUE, revert to the received value, if any.
1792 1847 */
1793 1848 int
1794 1849 zfs_prop_inherit(zfs_handle_t *zhp, const char *propname, boolean_t received)
1795 1850 {
1796 1851 zfs_cmd_t zc = { 0 };
1797 1852 int ret;
1798 1853 prop_changelist_t *cl;
1799 1854 libzfs_handle_t *hdl = zhp->zfs_hdl;
1800 1855 char errbuf[1024];
1801 1856 zfs_prop_t prop;
1802 1857
1803 1858 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
1804 1859 "cannot inherit %s for '%s'"), propname, zhp->zfs_name);
1805 1860
1806 1861 zc.zc_cookie = received;
1807 1862 if ((prop = zfs_name_to_prop(propname)) == ZPROP_INVAL) {
1808 1863 /*
1809 1864 * For user properties, the amount of work we have to do is very
1810 1865 * small, so just do it here.
1811 1866 */
1812 1867 if (!zfs_prop_user(propname)) {
1813 1868 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1814 1869 "invalid property"));
1815 1870 return (zfs_error(hdl, EZFS_BADPROP, errbuf));
1816 1871 }
1817 1872
1818 1873 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
1819 1874 (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value));
1820 1875
1821 1876 if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc) != 0)
1822 1877 return (zfs_standard_error(hdl, errno, errbuf));
1823 1878
1824 1879 return (0);
1825 1880 }
1826 1881
|
↓ open down ↓ |
81 lines elided |
↑ open up ↑ |
1827 1882 /*
1828 1883 * Verify that this property is inheritable.
1829 1884 */
1830 1885 if (zfs_prop_readonly(prop))
1831 1886 return (zfs_error(hdl, EZFS_PROPREADONLY, errbuf));
1832 1887
1833 1888 if (!zfs_prop_inheritable(prop) && !received)
1834 1889 return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf));
1835 1890
1836 1891 /*
1892 + * This property is inheritable by nature,
1893 + * but user can do only "set" operation,
1894 + * because "inherit" does not make sence
1895 + */
1896 + if (prop == ZFS_PROP_WBC_MODE)
1897 + return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf));
1898 +
1899 + /*
1837 1900 * Check to see if the value applies to this type
1838 1901 */
1839 1902 if (!zfs_prop_valid_for_type(prop, zhp->zfs_type))
1840 1903 return (zfs_error(hdl, EZFS_PROPTYPE, errbuf));
1841 1904
1842 1905 /*
1843 1906 * Normalize the name, to get rid of shorthand abbreviations.
1844 1907 */
1845 1908 propname = zfs_prop_to_name(prop);
1846 1909 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
1847 1910 (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value));
1848 1911
1849 1912 if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID &&
1850 1913 zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) {
1851 1914 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1852 1915 "dataset is used in a non-global zone"));
1853 1916 return (zfs_error(hdl, EZFS_ZONED, errbuf));
1854 1917 }
1855 1918
1856 1919 /*
1857 1920 * Determine datasets which will be affected by this change, if any.
1858 1921 */
1859 1922 if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL)
1860 1923 return (-1);
1861 1924
1862 1925 if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) {
1863 1926 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1864 1927 "child dataset with inherited mountpoint is used "
1865 1928 "in a non-global zone"));
1866 1929 ret = zfs_error(hdl, EZFS_ZONED, errbuf);
1867 1930 goto error;
1868 1931 }
1869 1932
1870 1933 if ((ret = changelist_prefix(cl)) != 0)
1871 1934 goto error;
1872 1935
1873 1936 if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc)) != 0) {
1874 1937 return (zfs_standard_error(hdl, errno, errbuf));
1875 1938 } else {
1876 1939
1877 1940 if ((ret = changelist_postfix(cl)) != 0)
1878 1941 goto error;
1879 1942
1880 1943 /*
1881 1944 * Refresh the statistics so the new property is reflected.
1882 1945 */
1883 1946 (void) get_stats(zhp);
1884 1947 }
1885 1948
1886 1949 error:
1887 1950 changelist_free(cl);
1888 1951 return (ret);
1889 1952 }
1890 1953
1891 1954 /*
1892 1955 * True DSL properties are stored in an nvlist. The following two functions
1893 1956 * extract them appropriately.
1894 1957 */
1895 1958 static uint64_t
1896 1959 getprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source)
1897 1960 {
1898 1961 nvlist_t *nv;
1899 1962 uint64_t value;
1900 1963
1901 1964 *source = NULL;
1902 1965 if (nvlist_lookup_nvlist(zhp->zfs_props,
1903 1966 zfs_prop_to_name(prop), &nv) == 0) {
1904 1967 verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0);
1905 1968 (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source);
1906 1969 } else {
1907 1970 verify(!zhp->zfs_props_table ||
1908 1971 zhp->zfs_props_table[prop] == B_TRUE);
1909 1972 value = zfs_prop_default_numeric(prop);
1910 1973 *source = "";
1911 1974 }
1912 1975
1913 1976 return (value);
1914 1977 }
1915 1978
1916 1979 static const char *
1917 1980 getprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source)
1918 1981 {
1919 1982 nvlist_t *nv;
1920 1983 const char *value;
1921 1984
1922 1985 *source = NULL;
1923 1986 if (nvlist_lookup_nvlist(zhp->zfs_props,
1924 1987 zfs_prop_to_name(prop), &nv) == 0) {
1925 1988 value = fnvlist_lookup_string(nv, ZPROP_VALUE);
1926 1989 (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source);
1927 1990 } else {
1928 1991 verify(!zhp->zfs_props_table ||
1929 1992 zhp->zfs_props_table[prop] == B_TRUE);
1930 1993 value = zfs_prop_default_string(prop);
1931 1994 *source = "";
1932 1995 }
1933 1996
1934 1997 return (value);
1935 1998 }
1936 1999
1937 2000 static boolean_t
1938 2001 zfs_is_recvd_props_mode(zfs_handle_t *zhp)
1939 2002 {
1940 2003 return (zhp->zfs_props == zhp->zfs_recvd_props);
1941 2004 }
1942 2005
1943 2006 static void
1944 2007 zfs_set_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie)
1945 2008 {
1946 2009 *cookie = (uint64_t)(uintptr_t)zhp->zfs_props;
1947 2010 zhp->zfs_props = zhp->zfs_recvd_props;
1948 2011 }
1949 2012
1950 2013 static void
1951 2014 zfs_unset_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie)
1952 2015 {
1953 2016 zhp->zfs_props = (nvlist_t *)(uintptr_t)*cookie;
1954 2017 *cookie = 0;
1955 2018 }
1956 2019
1957 2020 /*
1958 2021 * Internal function for getting a numeric property. Both zfs_prop_get() and
1959 2022 * zfs_prop_get_int() are built using this interface.
1960 2023 *
1961 2024 * Certain properties can be overridden using 'mount -o'. In this case, scan
1962 2025 * the contents of the /etc/mnttab entry, searching for the appropriate options.
1963 2026 * If they differ from the on-disk values, report the current values and mark
1964 2027 * the source "temporary".
1965 2028 */
1966 2029 static int
1967 2030 get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src,
1968 2031 char **source, uint64_t *val)
1969 2032 {
1970 2033 zfs_cmd_t zc = { 0 };
1971 2034 nvlist_t *zplprops = NULL;
1972 2035 struct mnttab mnt;
1973 2036 char *mntopt_on = NULL;
1974 2037 char *mntopt_off = NULL;
1975 2038 boolean_t received = zfs_is_recvd_props_mode(zhp);
1976 2039
1977 2040 *source = NULL;
1978 2041
1979 2042 switch (prop) {
1980 2043 case ZFS_PROP_ATIME:
1981 2044 mntopt_on = MNTOPT_ATIME;
1982 2045 mntopt_off = MNTOPT_NOATIME;
1983 2046 break;
1984 2047
1985 2048 case ZFS_PROP_DEVICES:
1986 2049 mntopt_on = MNTOPT_DEVICES;
1987 2050 mntopt_off = MNTOPT_NODEVICES;
1988 2051 break;
1989 2052
1990 2053 case ZFS_PROP_EXEC:
1991 2054 mntopt_on = MNTOPT_EXEC;
1992 2055 mntopt_off = MNTOPT_NOEXEC;
1993 2056 break;
1994 2057
1995 2058 case ZFS_PROP_READONLY:
1996 2059 mntopt_on = MNTOPT_RO;
1997 2060 mntopt_off = MNTOPT_RW;
1998 2061 break;
1999 2062
2000 2063 case ZFS_PROP_SETUID:
2001 2064 mntopt_on = MNTOPT_SETUID;
2002 2065 mntopt_off = MNTOPT_NOSETUID;
2003 2066 break;
2004 2067
2005 2068 case ZFS_PROP_XATTR:
2006 2069 mntopt_on = MNTOPT_XATTR;
2007 2070 mntopt_off = MNTOPT_NOXATTR;
2008 2071 break;
2009 2072
2010 2073 case ZFS_PROP_NBMAND:
2011 2074 mntopt_on = MNTOPT_NBMAND;
2012 2075 mntopt_off = MNTOPT_NONBMAND;
2013 2076 break;
2014 2077
2015 2078 default:
2016 2079 break;
2017 2080 }
2018 2081
2019 2082 /*
2020 2083 * Because looking up the mount options is potentially expensive
2021 2084 * (iterating over all of /etc/mnttab), we defer its calculation until
2022 2085 * we're looking up a property which requires its presence.
2023 2086 */
2024 2087 if (!zhp->zfs_mntcheck &&
2025 2088 (mntopt_on != NULL || prop == ZFS_PROP_MOUNTED)) {
2026 2089 libzfs_handle_t *hdl = zhp->zfs_hdl;
2027 2090 struct mnttab entry;
2028 2091
2029 2092 if (libzfs_mnttab_find(hdl, zhp->zfs_name, &entry) == 0) {
2030 2093 zhp->zfs_mntopts = zfs_strdup(hdl,
2031 2094 entry.mnt_mntopts);
2032 2095 if (zhp->zfs_mntopts == NULL)
2033 2096 return (-1);
2034 2097 }
2035 2098
2036 2099 zhp->zfs_mntcheck = B_TRUE;
2037 2100 }
2038 2101
2039 2102 if (zhp->zfs_mntopts == NULL)
2040 2103 mnt.mnt_mntopts = "";
2041 2104 else
2042 2105 mnt.mnt_mntopts = zhp->zfs_mntopts;
2043 2106
2044 2107 switch (prop) {
2045 2108 case ZFS_PROP_ATIME:
2046 2109 case ZFS_PROP_DEVICES:
2047 2110 case ZFS_PROP_EXEC:
2048 2111 case ZFS_PROP_READONLY:
2049 2112 case ZFS_PROP_SETUID:
2050 2113 case ZFS_PROP_XATTR:
2051 2114 case ZFS_PROP_NBMAND:
2052 2115 *val = getprop_uint64(zhp, prop, source);
2053 2116
2054 2117 if (received)
2055 2118 break;
2056 2119
2057 2120 if (hasmntopt(&mnt, mntopt_on) && !*val) {
2058 2121 *val = B_TRUE;
2059 2122 if (src)
2060 2123 *src = ZPROP_SRC_TEMPORARY;
2061 2124 } else if (hasmntopt(&mnt, mntopt_off) && *val) {
2062 2125 *val = B_FALSE;
2063 2126 if (src)
2064 2127 *src = ZPROP_SRC_TEMPORARY;
2065 2128 }
2066 2129 break;
2067 2130
|
↓ open down ↓ |
221 lines elided |
↑ open up ↑ |
2068 2131 case ZFS_PROP_CANMOUNT:
2069 2132 case ZFS_PROP_VOLSIZE:
2070 2133 case ZFS_PROP_QUOTA:
2071 2134 case ZFS_PROP_REFQUOTA:
2072 2135 case ZFS_PROP_RESERVATION:
2073 2136 case ZFS_PROP_REFRESERVATION:
2074 2137 case ZFS_PROP_FILESYSTEM_LIMIT:
2075 2138 case ZFS_PROP_SNAPSHOT_LIMIT:
2076 2139 case ZFS_PROP_FILESYSTEM_COUNT:
2077 2140 case ZFS_PROP_SNAPSHOT_COUNT:
2141 + case ZFS_PROP_RATE_LIMIT:
2078 2142 *val = getprop_uint64(zhp, prop, source);
2079 2143
2080 2144 if (*source == NULL) {
2081 2145 /* not default, must be local */
2082 2146 *source = zhp->zfs_name;
2083 2147 }
2084 2148 break;
2085 2149
2086 2150 case ZFS_PROP_MOUNTED:
2087 2151 *val = (zhp->zfs_mntopts != NULL);
2088 2152 break;
2089 2153
2090 2154 case ZFS_PROP_NUMCLONES:
2091 2155 *val = zhp->zfs_dmustats.dds_num_clones;
2092 2156 break;
2093 2157
2094 2158 case ZFS_PROP_VERSION:
2095 2159 case ZFS_PROP_NORMALIZE:
2096 2160 case ZFS_PROP_UTF8ONLY:
2097 2161 case ZFS_PROP_CASE:
2098 2162 if (!zfs_prop_valid_for_type(prop, zhp->zfs_head_type) ||
2099 2163 zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
2100 2164 return (-1);
2101 2165 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
2102 2166 if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_OBJSET_ZPLPROPS, &zc)) {
2103 2167 zcmd_free_nvlists(&zc);
2104 2168 return (-1);
2105 2169 }
2106 2170 if (zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &zplprops) != 0 ||
2107 2171 nvlist_lookup_uint64(zplprops, zfs_prop_to_name(prop),
2108 2172 val) != 0) {
2109 2173 zcmd_free_nvlists(&zc);
2110 2174 return (-1);
2111 2175 }
2112 2176 nvlist_free(zplprops);
2113 2177 zcmd_free_nvlists(&zc);
2114 2178 break;
2115 2179
2116 2180 case ZFS_PROP_INCONSISTENT:
2117 2181 *val = zhp->zfs_dmustats.dds_inconsistent;
2118 2182 break;
2119 2183
2120 2184 default:
2121 2185 switch (zfs_prop_get_type(prop)) {
2122 2186 case PROP_TYPE_NUMBER:
2123 2187 case PROP_TYPE_INDEX:
2124 2188 *val = getprop_uint64(zhp, prop, source);
2125 2189 /*
2126 2190 * If we tried to use a default value for a
2127 2191 * readonly property, it means that it was not
2128 2192 * present. Note this only applies to "truly"
2129 2193 * readonly properties, not set-once properties
2130 2194 * like volblocksize.
2131 2195 */
2132 2196 if (zfs_prop_readonly(prop) &&
2133 2197 !zfs_prop_setonce(prop) &&
2134 2198 *source != NULL && (*source)[0] == '\0') {
2135 2199 *source = NULL;
2136 2200 return (-1);
2137 2201 }
2138 2202 break;
2139 2203
2140 2204 case PROP_TYPE_STRING:
2141 2205 default:
2142 2206 zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
2143 2207 "cannot get non-numeric property"));
2144 2208 return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP,
2145 2209 dgettext(TEXT_DOMAIN, "internal error")));
2146 2210 }
2147 2211 }
2148 2212
2149 2213 return (0);
2150 2214 }
2151 2215
2152 2216 /*
2153 2217 * Calculate the source type, given the raw source string.
2154 2218 */
2155 2219 static void
2156 2220 get_source(zfs_handle_t *zhp, zprop_source_t *srctype, char *source,
2157 2221 char *statbuf, size_t statlen)
2158 2222 {
2159 2223 if (statbuf == NULL || *srctype == ZPROP_SRC_TEMPORARY)
2160 2224 return;
2161 2225
2162 2226 if (source == NULL) {
2163 2227 *srctype = ZPROP_SRC_NONE;
2164 2228 } else if (source[0] == '\0') {
2165 2229 *srctype = ZPROP_SRC_DEFAULT;
2166 2230 } else if (strstr(source, ZPROP_SOURCE_VAL_RECVD) != NULL) {
2167 2231 *srctype = ZPROP_SRC_RECEIVED;
2168 2232 } else {
2169 2233 if (strcmp(source, zhp->zfs_name) == 0) {
2170 2234 *srctype = ZPROP_SRC_LOCAL;
2171 2235 } else {
2172 2236 (void) strlcpy(statbuf, source, statlen);
2173 2237 *srctype = ZPROP_SRC_INHERITED;
2174 2238 }
2175 2239 }
2176 2240
2177 2241 }
2178 2242
2179 2243 int
2180 2244 zfs_prop_get_recvd(zfs_handle_t *zhp, const char *propname, char *propbuf,
2181 2245 size_t proplen, boolean_t literal)
2182 2246 {
2183 2247 zfs_prop_t prop;
2184 2248 int err = 0;
2185 2249
2186 2250 if (zhp->zfs_recvd_props == NULL)
2187 2251 if (get_recvd_props_ioctl(zhp) != 0)
2188 2252 return (-1);
2189 2253
2190 2254 prop = zfs_name_to_prop(propname);
2191 2255
2192 2256 if (prop != ZPROP_INVAL) {
2193 2257 uint64_t cookie;
2194 2258 if (!nvlist_exists(zhp->zfs_recvd_props, propname))
2195 2259 return (-1);
2196 2260 zfs_set_recvd_props_mode(zhp, &cookie);
2197 2261 err = zfs_prop_get(zhp, prop, propbuf, proplen,
2198 2262 NULL, NULL, 0, literal);
2199 2263 zfs_unset_recvd_props_mode(zhp, &cookie);
2200 2264 } else {
2201 2265 nvlist_t *propval;
2202 2266 char *recvdval;
2203 2267 if (nvlist_lookup_nvlist(zhp->zfs_recvd_props,
2204 2268 propname, &propval) != 0)
2205 2269 return (-1);
2206 2270 verify(nvlist_lookup_string(propval, ZPROP_VALUE,
2207 2271 &recvdval) == 0);
2208 2272 (void) strlcpy(propbuf, recvdval, proplen);
2209 2273 }
2210 2274
2211 2275 return (err == 0 ? 0 : -1);
2212 2276 }
2213 2277
2214 2278 static int
2215 2279 get_clones_string(zfs_handle_t *zhp, char *propbuf, size_t proplen)
2216 2280 {
2217 2281 nvlist_t *value;
2218 2282 nvpair_t *pair;
2219 2283
2220 2284 value = zfs_get_clones_nvl(zhp);
2221 2285 if (value == NULL)
2222 2286 return (-1);
2223 2287
2224 2288 propbuf[0] = '\0';
2225 2289 for (pair = nvlist_next_nvpair(value, NULL); pair != NULL;
2226 2290 pair = nvlist_next_nvpair(value, pair)) {
2227 2291 if (propbuf[0] != '\0')
2228 2292 (void) strlcat(propbuf, ",", proplen);
2229 2293 (void) strlcat(propbuf, nvpair_name(pair), proplen);
2230 2294 }
2231 2295
2232 2296 return (0);
2233 2297 }
2234 2298
2235 2299 struct get_clones_arg {
2236 2300 uint64_t numclones;
2237 2301 nvlist_t *value;
2238 2302 const char *origin;
2239 2303 char buf[ZFS_MAX_DATASET_NAME_LEN];
2240 2304 };
2241 2305
2242 2306 int
2243 2307 get_clones_cb(zfs_handle_t *zhp, void *arg)
2244 2308 {
2245 2309 struct get_clones_arg *gca = arg;
2246 2310
2247 2311 if (gca->numclones == 0) {
2248 2312 zfs_close(zhp);
2249 2313 return (0);
2250 2314 }
2251 2315
2252 2316 if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, gca->buf, sizeof (gca->buf),
2253 2317 NULL, NULL, 0, B_TRUE) != 0)
2254 2318 goto out;
2255 2319 if (strcmp(gca->buf, gca->origin) == 0) {
2256 2320 fnvlist_add_boolean(gca->value, zfs_get_name(zhp));
2257 2321 gca->numclones--;
2258 2322 }
2259 2323
2260 2324 out:
2261 2325 (void) zfs_iter_children(zhp, get_clones_cb, gca);
2262 2326 zfs_close(zhp);
2263 2327 return (0);
2264 2328 }
2265 2329
2266 2330 nvlist_t *
2267 2331 zfs_get_clones_nvl(zfs_handle_t *zhp)
2268 2332 {
2269 2333 nvlist_t *nv, *value;
2270 2334
2271 2335 if (nvlist_lookup_nvlist(zhp->zfs_props,
2272 2336 zfs_prop_to_name(ZFS_PROP_CLONES), &nv) != 0) {
2273 2337 struct get_clones_arg gca;
2274 2338
2275 2339 /*
2276 2340 * if this is a snapshot, then the kernel wasn't able
2277 2341 * to get the clones. Do it by slowly iterating.
2278 2342 */
2279 2343 if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT)
2280 2344 return (NULL);
2281 2345 if (nvlist_alloc(&nv, NV_UNIQUE_NAME, 0) != 0)
2282 2346 return (NULL);
2283 2347 if (nvlist_alloc(&value, NV_UNIQUE_NAME, 0) != 0) {
2284 2348 nvlist_free(nv);
2285 2349 return (NULL);
2286 2350 }
2287 2351
2288 2352 gca.numclones = zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES);
2289 2353 gca.value = value;
2290 2354 gca.origin = zhp->zfs_name;
2291 2355
2292 2356 if (gca.numclones != 0) {
2293 2357 zfs_handle_t *root;
2294 2358 char pool[ZFS_MAX_DATASET_NAME_LEN];
2295 2359 char *cp = pool;
2296 2360
2297 2361 /* get the pool name */
2298 2362 (void) strlcpy(pool, zhp->zfs_name, sizeof (pool));
2299 2363 (void) strsep(&cp, "/@");
2300 2364 root = zfs_open(zhp->zfs_hdl, pool,
2301 2365 ZFS_TYPE_FILESYSTEM);
2302 2366
2303 2367 (void) get_clones_cb(root, &gca);
2304 2368 }
2305 2369
2306 2370 if (gca.numclones != 0 ||
2307 2371 nvlist_add_nvlist(nv, ZPROP_VALUE, value) != 0 ||
2308 2372 nvlist_add_nvlist(zhp->zfs_props,
2309 2373 zfs_prop_to_name(ZFS_PROP_CLONES), nv) != 0) {
2310 2374 nvlist_free(nv);
2311 2375 nvlist_free(value);
2312 2376 return (NULL);
2313 2377 }
2314 2378 nvlist_free(nv);
2315 2379 nvlist_free(value);
2316 2380 verify(0 == nvlist_lookup_nvlist(zhp->zfs_props,
2317 2381 zfs_prop_to_name(ZFS_PROP_CLONES), &nv));
2318 2382 }
2319 2383
2320 2384 verify(nvlist_lookup_nvlist(nv, ZPROP_VALUE, &value) == 0);
2321 2385
2322 2386 return (value);
2323 2387 }
2324 2388
2325 2389 /*
2326 2390 * Accepts a property and value and checks that the value
2327 2391 * matches the one found by the channel program. If they are
2328 2392 * not equal, print both of them.
2329 2393 */
2330 2394 void
2331 2395 zcp_check(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t intval,
2332 2396 const char *strval)
2333 2397 {
2334 2398 if (!zhp->zfs_hdl->libzfs_prop_debug)
2335 2399 return;
2336 2400 int error;
2337 2401 char *poolname = zhp->zpool_hdl->zpool_name;
2338 2402 const char *program =
2339 2403 "args = ...\n"
2340 2404 "ds = args['dataset']\n"
2341 2405 "prop = args['property']\n"
2342 2406 "value, setpoint = zfs.get_prop(ds, prop)\n"
2343 2407 "return {value=value, setpoint=setpoint}\n";
2344 2408 nvlist_t *outnvl;
2345 2409 nvlist_t *retnvl;
2346 2410 nvlist_t *argnvl = fnvlist_alloc();
2347 2411
2348 2412 fnvlist_add_string(argnvl, "dataset", zhp->zfs_name);
2349 2413 fnvlist_add_string(argnvl, "property", zfs_prop_to_name(prop));
2350 2414
2351 2415 error = lzc_channel_program_nosync(poolname, program,
2352 2416 10 * 1000 * 1000, 10 * 1024 * 1024, argnvl, &outnvl);
2353 2417
2354 2418 if (error == 0) {
2355 2419 retnvl = fnvlist_lookup_nvlist(outnvl, "return");
2356 2420 if (zfs_prop_get_type(prop) == PROP_TYPE_NUMBER) {
2357 2421 int64_t ans;
2358 2422 error = nvlist_lookup_int64(retnvl, "value", &ans);
2359 2423 if (error != 0) {
2360 2424 (void) fprintf(stderr, "zcp check error: %u\n",
2361 2425 error);
2362 2426 return;
2363 2427 }
2364 2428 if (ans != intval) {
2365 2429 (void) fprintf(stderr,
2366 2430 "%s: zfs found %lld, but zcp found %lld\n",
2367 2431 zfs_prop_to_name(prop),
2368 2432 (longlong_t)intval, (longlong_t)ans);
2369 2433 }
2370 2434 } else {
2371 2435 char *str_ans;
2372 2436 error = nvlist_lookup_string(retnvl, "value", &str_ans);
2373 2437 if (error != 0) {
2374 2438 (void) fprintf(stderr, "zcp check error: %u\n",
2375 2439 error);
2376 2440 return;
2377 2441 }
2378 2442 if (strcmp(strval, str_ans) != 0) {
2379 2443 (void) fprintf(stderr,
2380 2444 "%s: zfs found %s, but zcp found %s\n",
2381 2445 zfs_prop_to_name(prop),
2382 2446 strval, str_ans);
2383 2447 }
2384 2448 }
2385 2449 } else {
2386 2450 (void) fprintf(stderr,
2387 2451 "zcp check failed, channel program error: %u\n", error);
2388 2452 }
2389 2453 nvlist_free(argnvl);
2390 2454 nvlist_free(outnvl);
2391 2455 }
2392 2456
2393 2457 /*
2394 2458 * Retrieve a property from the given object. If 'literal' is specified, then
2395 2459 * numbers are left as exact values. Otherwise, numbers are converted to a
2396 2460 * human-readable form.
2397 2461 *
2398 2462 * Returns 0 on success, or -1 on error.
2399 2463 */
2400 2464 int
2401 2465 zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
2402 2466 zprop_source_t *src, char *statbuf, size_t statlen, boolean_t literal)
2403 2467 {
2404 2468 char *source = NULL;
2405 2469 uint64_t val;
2406 2470 const char *str;
2407 2471 const char *strval;
2408 2472 boolean_t received = zfs_is_recvd_props_mode(zhp);
2409 2473
2410 2474 /*
2411 2475 * Check to see if this property applies to our object
2412 2476 */
2413 2477 if (!zfs_prop_valid_for_type(prop, zhp->zfs_type))
2414 2478 return (-1);
2415 2479
2416 2480 if (received && zfs_prop_readonly(prop))
2417 2481 return (-1);
2418 2482
2419 2483 if (src)
2420 2484 *src = ZPROP_SRC_NONE;
2421 2485
2422 2486 switch (prop) {
2423 2487 case ZFS_PROP_CREATION:
2424 2488 /*
2425 2489 * 'creation' is a time_t stored in the statistics. We convert
2426 2490 * this into a string unless 'literal' is specified.
2427 2491 */
2428 2492 {
2429 2493 val = getprop_uint64(zhp, prop, &source);
2430 2494 time_t time = (time_t)val;
2431 2495 struct tm t;
2432 2496
2433 2497 if (literal ||
2434 2498 localtime_r(&time, &t) == NULL ||
2435 2499 strftime(propbuf, proplen, "%a %b %e %k:%M %Y",
2436 2500 &t) == 0)
2437 2501 (void) snprintf(propbuf, proplen, "%llu", val);
2438 2502 }
2439 2503 zcp_check(zhp, prop, val, NULL);
2440 2504 break;
2441 2505
2442 2506 case ZFS_PROP_MOUNTPOINT:
2443 2507 /*
2444 2508 * Getting the precise mountpoint can be tricky.
2445 2509 *
2446 2510 * - for 'none' or 'legacy', return those values.
2447 2511 * - for inherited mountpoints, we want to take everything
2448 2512 * after our ancestor and append it to the inherited value.
2449 2513 *
2450 2514 * If the pool has an alternate root, we want to prepend that
2451 2515 * root to any values we return.
2452 2516 */
2453 2517
2454 2518 str = getprop_string(zhp, prop, &source);
2455 2519
2456 2520 if (str[0] == '/') {
2457 2521 char buf[MAXPATHLEN];
2458 2522 char *root = buf;
2459 2523 const char *relpath;
2460 2524
2461 2525 /*
2462 2526 * If we inherit the mountpoint, even from a dataset
2463 2527 * with a received value, the source will be the path of
2464 2528 * the dataset we inherit from. If source is
2465 2529 * ZPROP_SOURCE_VAL_RECVD, the received value is not
2466 2530 * inherited.
2467 2531 */
2468 2532 if (strcmp(source, ZPROP_SOURCE_VAL_RECVD) == 0) {
2469 2533 relpath = "";
2470 2534 } else {
2471 2535 relpath = zhp->zfs_name + strlen(source);
2472 2536 if (relpath[0] == '/')
2473 2537 relpath++;
2474 2538 }
2475 2539
2476 2540 if ((zpool_get_prop(zhp->zpool_hdl,
2477 2541 ZPOOL_PROP_ALTROOT, buf, MAXPATHLEN, NULL,
2478 2542 B_FALSE)) || (strcmp(root, "-") == 0))
2479 2543 root[0] = '\0';
2480 2544 /*
2481 2545 * Special case an alternate root of '/'. This will
2482 2546 * avoid having multiple leading slashes in the
2483 2547 * mountpoint path.
2484 2548 */
2485 2549 if (strcmp(root, "/") == 0)
2486 2550 root++;
2487 2551
2488 2552 /*
2489 2553 * If the mountpoint is '/' then skip over this
2490 2554 * if we are obtaining either an alternate root or
2491 2555 * an inherited mountpoint.
2492 2556 */
2493 2557 if (str[1] == '\0' && (root[0] != '\0' ||
2494 2558 relpath[0] != '\0'))
2495 2559 str++;
2496 2560
2497 2561 if (relpath[0] == '\0')
2498 2562 (void) snprintf(propbuf, proplen, "%s%s",
2499 2563 root, str);
2500 2564 else
2501 2565 (void) snprintf(propbuf, proplen, "%s%s%s%s",
2502 2566 root, str, relpath[0] == '@' ? "" : "/",
2503 2567 relpath);
2504 2568 } else {
2505 2569 /* 'legacy' or 'none' */
2506 2570 (void) strlcpy(propbuf, str, proplen);
2507 2571 }
2508 2572 zcp_check(zhp, prop, NULL, propbuf);
2509 2573 break;
2510 2574
2511 2575 case ZFS_PROP_ORIGIN:
2512 2576 str = getprop_string(zhp, prop, &source);
2513 2577 if (str == NULL)
2514 2578 return (-1);
2515 2579 (void) strlcpy(propbuf, str, proplen);
2516 2580 zcp_check(zhp, prop, NULL, str);
2517 2581 break;
2518 2582
2519 2583 case ZFS_PROP_CLONES:
2520 2584 if (get_clones_string(zhp, propbuf, proplen) != 0)
2521 2585 return (-1);
2522 2586 break;
2523 2587
2524 2588 case ZFS_PROP_QUOTA:
2525 2589 case ZFS_PROP_REFQUOTA:
2526 2590 case ZFS_PROP_RESERVATION:
2527 2591 case ZFS_PROP_REFRESERVATION:
2528 2592
2529 2593 if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
2530 2594 return (-1);
2531 2595 /*
2532 2596 * If quota or reservation is 0, we translate this into 'none'
2533 2597 * (unless literal is set), and indicate that it's the default
2534 2598 * value. Otherwise, we print the number nicely and indicate
2535 2599 * that its set locally.
2536 2600 */
2537 2601 if (val == 0) {
2538 2602 if (literal)
2539 2603 (void) strlcpy(propbuf, "0", proplen);
2540 2604 else
2541 2605 (void) strlcpy(propbuf, "none", proplen);
2542 2606 } else {
2543 2607 if (literal)
2544 2608 (void) snprintf(propbuf, proplen, "%llu",
2545 2609 (u_longlong_t)val);
|
↓ open down ↓ |
458 lines elided |
↑ open up ↑ |
2546 2610 else
2547 2611 zfs_nicenum(val, propbuf, proplen);
2548 2612 }
2549 2613 zcp_check(zhp, prop, val, NULL);
2550 2614 break;
2551 2615
2552 2616 case ZFS_PROP_FILESYSTEM_LIMIT:
2553 2617 case ZFS_PROP_SNAPSHOT_LIMIT:
2554 2618 case ZFS_PROP_FILESYSTEM_COUNT:
2555 2619 case ZFS_PROP_SNAPSHOT_COUNT:
2620 + case ZFS_PROP_RATE_LIMIT:
2556 2621
2557 2622 if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
2558 2623 return (-1);
2559 2624
2560 2625 /*
2561 2626 * If limit is UINT64_MAX, we translate this into 'none' (unless
2562 2627 * literal is set), and indicate that it's the default value.
2563 2628 * Otherwise, we print the number nicely and indicate that it's
2564 2629 * set locally.
2565 2630 */
2566 2631 if (literal) {
2567 2632 (void) snprintf(propbuf, proplen, "%llu",
2568 2633 (u_longlong_t)val);
2569 2634 } else if (val == UINT64_MAX) {
2570 2635 (void) strlcpy(propbuf, "none", proplen);
2571 2636 } else {
2572 2637 zfs_nicenum(val, propbuf, proplen);
2573 2638 }
2574 2639
2575 2640 zcp_check(zhp, prop, val, NULL);
2576 2641 break;
2577 2642
2578 2643 case ZFS_PROP_REFRATIO:
2579 2644 case ZFS_PROP_COMPRESSRATIO:
2580 2645 if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
2581 2646 return (-1);
2582 2647 (void) snprintf(propbuf, proplen, "%llu.%02llux",
2583 2648 (u_longlong_t)(val / 100),
2584 2649 (u_longlong_t)(val % 100));
2585 2650 zcp_check(zhp, prop, val, NULL);
2586 2651 break;
2587 2652
2588 2653 case ZFS_PROP_TYPE:
|
↓ open down ↓ |
23 lines elided |
↑ open up ↑ |
2589 2654 switch (zhp->zfs_type) {
2590 2655 case ZFS_TYPE_FILESYSTEM:
2591 2656 str = "filesystem";
2592 2657 break;
2593 2658 case ZFS_TYPE_VOLUME:
2594 2659 str = "volume";
2595 2660 break;
2596 2661 case ZFS_TYPE_SNAPSHOT:
2597 2662 str = "snapshot";
2598 2663 break;
2664 + case ZFS_TYPE_AUTOSNAP:
2665 + str = "autosnap";
2666 + break;
2599 2667 case ZFS_TYPE_BOOKMARK:
2600 2668 str = "bookmark";
2601 2669 break;
2602 2670 default:
2603 2671 abort();
2604 2672 }
2605 2673 (void) snprintf(propbuf, proplen, "%s", str);
2606 2674 zcp_check(zhp, prop, NULL, propbuf);
2607 2675 break;
2608 2676
2609 2677 case ZFS_PROP_MOUNTED:
2610 2678 /*
2611 2679 * The 'mounted' property is a pseudo-property that described
2612 2680 * whether the filesystem is currently mounted. Even though
2613 2681 * it's a boolean value, the typical values of "on" and "off"
2614 2682 * don't make sense, so we translate to "yes" and "no".
2615 2683 */
2616 2684 if (get_numeric_property(zhp, ZFS_PROP_MOUNTED,
2617 2685 src, &source, &val) != 0)
2618 2686 return (-1);
2619 2687 if (val)
2620 2688 (void) strlcpy(propbuf, "yes", proplen);
2621 2689 else
2622 2690 (void) strlcpy(propbuf, "no", proplen);
2623 2691 break;
2624 2692
2625 2693 case ZFS_PROP_NAME:
2626 2694 /*
2627 2695 * The 'name' property is a pseudo-property derived from the
2628 2696 * dataset name. It is presented as a real property to simplify
2629 2697 * consumers.
2630 2698 */
2631 2699 (void) strlcpy(propbuf, zhp->zfs_name, proplen);
2632 2700 zcp_check(zhp, prop, NULL, propbuf);
2633 2701 break;
2634 2702
2635 2703 case ZFS_PROP_MLSLABEL:
2636 2704 {
2637 2705 m_label_t *new_sl = NULL;
2638 2706 char *ascii = NULL; /* human readable label */
2639 2707
2640 2708 (void) strlcpy(propbuf,
2641 2709 getprop_string(zhp, prop, &source), proplen);
2642 2710
2643 2711 if (literal || (strcasecmp(propbuf,
2644 2712 ZFS_MLSLABEL_DEFAULT) == 0))
2645 2713 break;
2646 2714
2647 2715 /*
2648 2716 * Try to translate the internal hex string to
2649 2717 * human-readable output. If there are any
2650 2718 * problems just use the hex string.
2651 2719 */
2652 2720
2653 2721 if (str_to_label(propbuf, &new_sl, MAC_LABEL,
2654 2722 L_NO_CORRECTION, NULL) == -1) {
2655 2723 m_label_free(new_sl);
2656 2724 break;
2657 2725 }
2658 2726
2659 2727 if (label_to_str(new_sl, &ascii, M_LABEL,
2660 2728 DEF_NAMES) != 0) {
2661 2729 if (ascii)
2662 2730 free(ascii);
2663 2731 m_label_free(new_sl);
2664 2732 break;
2665 2733 }
2666 2734 m_label_free(new_sl);
2667 2735
2668 2736 (void) strlcpy(propbuf, ascii, proplen);
2669 2737 free(ascii);
2670 2738 }
2671 2739 break;
2672 2740
2673 2741 case ZFS_PROP_GUID:
2674 2742 /*
|
↓ open down ↓ |
66 lines elided |
↑ open up ↑ |
2675 2743 * GUIDs are stored as numbers, but they are identifiers.
2676 2744 * We don't want them to be pretty printed, because pretty
2677 2745 * printing mangles the ID into a truncated and useless value.
2678 2746 */
2679 2747 if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
2680 2748 return (-1);
2681 2749 (void) snprintf(propbuf, proplen, "%llu", (u_longlong_t)val);
2682 2750 zcp_check(zhp, prop, val, NULL);
2683 2751 break;
2684 2752
2753 + case ZFS_PROP_MODIFIED:
2754 + /*
2755 + * For a snapshot the "modified" pseudo-property is set to
2756 + * "yes" if parent filesystem/zvol differs from the snapshot.
2757 + * Even though it's a boolean value, the typical
2758 + * values of "on" and "off" don't make sense, so we translate
2759 + * to "yes" and "no".
2760 + */
2761 + if (get_numeric_property(zhp, ZFS_PROP_MODIFIED,
2762 + src, &source, &val) != 0)
2763 + return (-1);
2764 + if (val != 0)
2765 + (void) strlcpy(propbuf, "yes", proplen);
2766 + else
2767 + (void) strlcpy(propbuf, "no", proplen);
2768 + break;
2769 +
2685 2770 default:
2686 2771 switch (zfs_prop_get_type(prop)) {
2687 2772 case PROP_TYPE_NUMBER:
2688 2773 if (get_numeric_property(zhp, prop, src,
2689 2774 &source, &val) != 0) {
2690 2775 return (-1);
2691 2776 }
2692 2777
2693 2778 if (literal) {
2694 2779 (void) snprintf(propbuf, proplen, "%llu",
2695 2780 (u_longlong_t)val);
2696 2781 } else {
2697 2782 zfs_nicenum(val, propbuf, proplen);
2698 2783 }
2699 2784 zcp_check(zhp, prop, val, NULL);
2700 2785 break;
2701 2786
2702 2787 case PROP_TYPE_STRING:
2703 2788 str = getprop_string(zhp, prop, &source);
2704 2789 if (str == NULL)
2705 2790 return (-1);
2706 2791
2707 2792 (void) strlcpy(propbuf, str, proplen);
2708 2793 zcp_check(zhp, prop, NULL, str);
2709 2794 break;
2710 2795
2711 2796 case PROP_TYPE_INDEX:
2712 2797 if (get_numeric_property(zhp, prop, src,
2713 2798 &source, &val) != 0)
2714 2799 return (-1);
2715 2800 if (zfs_prop_index_to_string(prop, val, &strval) != 0)
2716 2801 return (-1);
2717 2802
2718 2803 (void) strlcpy(propbuf, strval, proplen);
2719 2804 zcp_check(zhp, prop, NULL, strval);
2720 2805 break;
2721 2806
2722 2807 default:
2723 2808 abort();
2724 2809 }
2725 2810 }
2726 2811
2727 2812 get_source(zhp, src, source, statbuf, statlen);
2728 2813
2729 2814 return (0);
2730 2815 }
2731 2816
2732 2817 /*
2733 2818 * Utility function to get the given numeric property. Does no validation that
2734 2819 * the given property is the appropriate type; should only be used with
2735 2820 * hard-coded property types.
2736 2821 */
2737 2822 uint64_t
2738 2823 zfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop)
2739 2824 {
2740 2825 char *source;
2741 2826 uint64_t val;
2742 2827
2743 2828 (void) get_numeric_property(zhp, prop, NULL, &source, &val);
2744 2829
2745 2830 return (val);
2746 2831 }
2747 2832
2748 2833 int
2749 2834 zfs_prop_set_int(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t val)
2750 2835 {
2751 2836 char buf[64];
2752 2837
2753 2838 (void) snprintf(buf, sizeof (buf), "%llu", (longlong_t)val);
2754 2839 return (zfs_prop_set(zhp, zfs_prop_to_name(prop), buf));
2755 2840 }
2756 2841
2757 2842 /*
2758 2843 * Similar to zfs_prop_get(), but returns the value as an integer.
2759 2844 */
2760 2845 int
2761 2846 zfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value,
2762 2847 zprop_source_t *src, char *statbuf, size_t statlen)
2763 2848 {
2764 2849 char *source;
2765 2850
2766 2851 /*
2767 2852 * Check to see if this property applies to our object
2768 2853 */
2769 2854 if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) {
2770 2855 return (zfs_error_fmt(zhp->zfs_hdl, EZFS_PROPTYPE,
2771 2856 dgettext(TEXT_DOMAIN, "cannot get property '%s'"),
2772 2857 zfs_prop_to_name(prop)));
2773 2858 }
2774 2859
2775 2860 if (src)
2776 2861 *src = ZPROP_SRC_NONE;
2777 2862
2778 2863 if (get_numeric_property(zhp, prop, src, &source, value) != 0)
2779 2864 return (-1);
2780 2865
2781 2866 get_source(zhp, src, source, statbuf, statlen);
2782 2867
2783 2868 return (0);
2784 2869 }
2785 2870
2786 2871 static int
2787 2872 idmap_id_to_numeric_domain_rid(uid_t id, boolean_t isuser,
2788 2873 char **domainp, idmap_rid_t *ridp)
2789 2874 {
2790 2875 idmap_get_handle_t *get_hdl = NULL;
2791 2876 idmap_stat status;
2792 2877 int err = EINVAL;
2793 2878
2794 2879 if (idmap_get_create(&get_hdl) != IDMAP_SUCCESS)
2795 2880 goto out;
2796 2881
2797 2882 if (isuser) {
2798 2883 err = idmap_get_sidbyuid(get_hdl, id,
2799 2884 IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status);
2800 2885 } else {
2801 2886 err = idmap_get_sidbygid(get_hdl, id,
2802 2887 IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status);
2803 2888 }
2804 2889 if (err == IDMAP_SUCCESS &&
2805 2890 idmap_get_mappings(get_hdl) == IDMAP_SUCCESS &&
2806 2891 status == IDMAP_SUCCESS)
2807 2892 err = 0;
2808 2893 else
2809 2894 err = EINVAL;
2810 2895 out:
2811 2896 if (get_hdl)
2812 2897 idmap_get_destroy(get_hdl);
2813 2898 return (err);
2814 2899 }
2815 2900
2816 2901 /*
2817 2902 * convert the propname into parameters needed by kernel
2818 2903 * Eg: userquota@ahrens -> ZFS_PROP_USERQUOTA, "", 126829
2819 2904 * Eg: userused@matt@domain -> ZFS_PROP_USERUSED, "S-1-123-456", 789
2820 2905 */
2821 2906 static int
2822 2907 userquota_propname_decode(const char *propname, boolean_t zoned,
2823 2908 zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp)
2824 2909 {
2825 2910 zfs_userquota_prop_t type;
2826 2911 char *cp, *end;
2827 2912 char *numericsid = NULL;
2828 2913 boolean_t isuser;
2829 2914
2830 2915 domain[0] = '\0';
2831 2916 *ridp = 0;
2832 2917 /* Figure out the property type ({user|group}{quota|space}) */
2833 2918 for (type = 0; type < ZFS_NUM_USERQUOTA_PROPS; type++) {
2834 2919 if (strncmp(propname, zfs_userquota_prop_prefixes[type],
2835 2920 strlen(zfs_userquota_prop_prefixes[type])) == 0)
2836 2921 break;
2837 2922 }
2838 2923 if (type == ZFS_NUM_USERQUOTA_PROPS)
2839 2924 return (EINVAL);
2840 2925 *typep = type;
2841 2926
2842 2927 isuser = (type == ZFS_PROP_USERQUOTA ||
2843 2928 type == ZFS_PROP_USERUSED);
2844 2929
2845 2930 cp = strchr(propname, '@') + 1;
2846 2931
2847 2932 if (strchr(cp, '@')) {
2848 2933 /*
2849 2934 * It's a SID name (eg "user@domain") that needs to be
2850 2935 * turned into S-1-domainID-RID.
2851 2936 */
2852 2937 int flag = 0;
2853 2938 idmap_stat stat, map_stat;
2854 2939 uid_t pid;
2855 2940 idmap_rid_t rid;
2856 2941 idmap_get_handle_t *gh = NULL;
2857 2942
2858 2943 stat = idmap_get_create(&gh);
2859 2944 if (stat != IDMAP_SUCCESS) {
2860 2945 idmap_get_destroy(gh);
2861 2946 return (ENOMEM);
2862 2947 }
2863 2948 if (zoned && getzoneid() == GLOBAL_ZONEID)
2864 2949 return (ENOENT);
2865 2950 if (isuser) {
2866 2951 stat = idmap_getuidbywinname(cp, NULL, flag, &pid);
2867 2952 if (stat < 0)
2868 2953 return (ENOENT);
2869 2954 stat = idmap_get_sidbyuid(gh, pid, flag, &numericsid,
2870 2955 &rid, &map_stat);
2871 2956 } else {
2872 2957 stat = idmap_getgidbywinname(cp, NULL, flag, &pid);
2873 2958 if (stat < 0)
2874 2959 return (ENOENT);
2875 2960 stat = idmap_get_sidbygid(gh, pid, flag, &numericsid,
2876 2961 &rid, &map_stat);
2877 2962 }
2878 2963 if (stat < 0) {
2879 2964 idmap_get_destroy(gh);
2880 2965 return (ENOENT);
2881 2966 }
2882 2967 stat = idmap_get_mappings(gh);
2883 2968 idmap_get_destroy(gh);
2884 2969
2885 2970 if (stat < 0) {
2886 2971 return (ENOENT);
2887 2972 }
2888 2973 if (numericsid == NULL)
2889 2974 return (ENOENT);
2890 2975 cp = numericsid;
2891 2976 *ridp = rid;
2892 2977 /* will be further decoded below */
2893 2978 }
2894 2979
2895 2980 if (strncmp(cp, "S-1-", 4) == 0) {
2896 2981 /* It's a numeric SID (eg "S-1-234-567-89") */
2897 2982 (void) strlcpy(domain, cp, domainlen);
2898 2983 errno = 0;
2899 2984 if (*ridp == 0) {
2900 2985 cp = strrchr(domain, '-');
2901 2986 *cp = '\0';
2902 2987 cp++;
2903 2988 *ridp = strtoull(cp, &end, 10);
2904 2989 } else {
2905 2990 end = "";
2906 2991 }
2907 2992 if (numericsid) {
2908 2993 free(numericsid);
2909 2994 numericsid = NULL;
2910 2995 }
2911 2996 if (errno != 0 || *end != '\0')
2912 2997 return (EINVAL);
2913 2998 } else if (!isdigit(*cp)) {
2914 2999 /*
2915 3000 * It's a user/group name (eg "user") that needs to be
2916 3001 * turned into a uid/gid
2917 3002 */
2918 3003 if (zoned && getzoneid() == GLOBAL_ZONEID)
2919 3004 return (ENOENT);
2920 3005 if (isuser) {
2921 3006 struct passwd *pw;
2922 3007 pw = getpwnam(cp);
2923 3008 if (pw == NULL)
2924 3009 return (ENOENT);
2925 3010 *ridp = pw->pw_uid;
2926 3011 } else {
2927 3012 struct group *gr;
2928 3013 gr = getgrnam(cp);
2929 3014 if (gr == NULL)
2930 3015 return (ENOENT);
2931 3016 *ridp = gr->gr_gid;
2932 3017 }
2933 3018 } else {
2934 3019 /* It's a user/group ID (eg "12345"). */
2935 3020 uid_t id = strtoul(cp, &end, 10);
2936 3021 idmap_rid_t rid;
2937 3022 char *mapdomain;
2938 3023
2939 3024 if (*end != '\0')
2940 3025 return (EINVAL);
2941 3026 if (id > MAXUID) {
2942 3027 /* It's an ephemeral ID. */
2943 3028 if (idmap_id_to_numeric_domain_rid(id, isuser,
2944 3029 &mapdomain, &rid) != 0)
2945 3030 return (ENOENT);
2946 3031 (void) strlcpy(domain, mapdomain, domainlen);
2947 3032 *ridp = rid;
2948 3033 } else {
2949 3034 *ridp = id;
2950 3035 }
2951 3036 }
2952 3037
2953 3038 ASSERT3P(numericsid, ==, NULL);
2954 3039 return (0);
2955 3040 }
2956 3041
2957 3042 static int
2958 3043 zfs_prop_get_userquota_common(zfs_handle_t *zhp, const char *propname,
2959 3044 uint64_t *propvalue, zfs_userquota_prop_t *typep)
2960 3045 {
2961 3046 int err;
2962 3047 zfs_cmd_t zc = { 0 };
2963 3048
2964 3049 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
2965 3050
2966 3051 err = userquota_propname_decode(propname,
2967 3052 zfs_prop_get_int(zhp, ZFS_PROP_ZONED),
2968 3053 typep, zc.zc_value, sizeof (zc.zc_value), &zc.zc_guid);
2969 3054 zc.zc_objset_type = *typep;
2970 3055 if (err)
2971 3056 return (err);
2972 3057
2973 3058 err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_USERSPACE_ONE, &zc);
2974 3059 if (err)
2975 3060 return (err);
2976 3061
2977 3062 *propvalue = zc.zc_cookie;
2978 3063 return (0);
2979 3064 }
2980 3065
2981 3066 int
2982 3067 zfs_prop_get_userquota_int(zfs_handle_t *zhp, const char *propname,
2983 3068 uint64_t *propvalue)
2984 3069 {
2985 3070 zfs_userquota_prop_t type;
2986 3071
2987 3072 return (zfs_prop_get_userquota_common(zhp, propname, propvalue,
2988 3073 &type));
2989 3074 }
2990 3075
2991 3076 int
2992 3077 zfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname,
2993 3078 char *propbuf, int proplen, boolean_t literal)
2994 3079 {
2995 3080 int err;
2996 3081 uint64_t propvalue;
2997 3082 zfs_userquota_prop_t type;
2998 3083
2999 3084 err = zfs_prop_get_userquota_common(zhp, propname, &propvalue,
3000 3085 &type);
3001 3086
3002 3087 if (err)
3003 3088 return (err);
3004 3089
3005 3090 if (literal) {
3006 3091 (void) snprintf(propbuf, proplen, "%llu", propvalue);
3007 3092 } else if (propvalue == 0 &&
3008 3093 (type == ZFS_PROP_USERQUOTA || type == ZFS_PROP_GROUPQUOTA)) {
3009 3094 (void) strlcpy(propbuf, "none", proplen);
3010 3095 } else {
3011 3096 zfs_nicenum(propvalue, propbuf, proplen);
3012 3097 }
3013 3098 return (0);
3014 3099 }
3015 3100
3016 3101 int
3017 3102 zfs_prop_get_written_int(zfs_handle_t *zhp, const char *propname,
3018 3103 uint64_t *propvalue)
3019 3104 {
3020 3105 int err;
3021 3106 zfs_cmd_t zc = { 0 };
3022 3107 const char *snapname;
3023 3108
3024 3109 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
3025 3110
3026 3111 snapname = strchr(propname, '@') + 1;
3027 3112 if (strchr(snapname, '@')) {
3028 3113 (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value));
3029 3114 } else {
3030 3115 /* snapname is the short name, append it to zhp's fsname */
3031 3116 char *cp;
3032 3117
3033 3118 (void) strlcpy(zc.zc_value, zhp->zfs_name,
3034 3119 sizeof (zc.zc_value));
3035 3120 cp = strchr(zc.zc_value, '@');
3036 3121 if (cp != NULL)
3037 3122 *cp = '\0';
3038 3123 (void) strlcat(zc.zc_value, "@", sizeof (zc.zc_value));
3039 3124 (void) strlcat(zc.zc_value, snapname, sizeof (zc.zc_value));
3040 3125 }
3041 3126
3042 3127 err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SPACE_WRITTEN, &zc);
3043 3128 if (err)
3044 3129 return (err);
3045 3130
3046 3131 *propvalue = zc.zc_cookie;
3047 3132 return (0);
3048 3133 }
3049 3134
3050 3135 int
3051 3136 zfs_prop_get_written(zfs_handle_t *zhp, const char *propname,
3052 3137 char *propbuf, int proplen, boolean_t literal)
3053 3138 {
3054 3139 int err;
3055 3140 uint64_t propvalue;
3056 3141
3057 3142 err = zfs_prop_get_written_int(zhp, propname, &propvalue);
3058 3143
3059 3144 if (err)
3060 3145 return (err);
3061 3146
3062 3147 if (literal) {
3063 3148 (void) snprintf(propbuf, proplen, "%llu", propvalue);
3064 3149 } else {
3065 3150 zfs_nicenum(propvalue, propbuf, proplen);
3066 3151 }
3067 3152 return (0);
3068 3153 }
3069 3154
3070 3155 /*
3071 3156 * Returns the name of the given zfs handle.
3072 3157 */
3073 3158 const char *
3074 3159 zfs_get_name(const zfs_handle_t *zhp)
3075 3160 {
3076 3161 return (zhp->zfs_name);
3077 3162 }
3078 3163
3079 3164 /*
3080 3165 * Returns the name of the parent pool for the given zfs handle.
3081 3166 */
3082 3167 const char *
3083 3168 zfs_get_pool_name(const zfs_handle_t *zhp)
3084 3169 {
3085 3170 return (zhp->zpool_hdl->zpool_name);
3086 3171 }
3087 3172
3088 3173 /*
3089 3174 * Returns the type of the given zfs handle.
3090 3175 */
3091 3176 zfs_type_t
3092 3177 zfs_get_type(const zfs_handle_t *zhp)
3093 3178 {
3094 3179 return (zhp->zfs_type);
3095 3180 }
3096 3181
3097 3182 /*
3098 3183 * Is one dataset name a child dataset of another?
3099 3184 *
3100 3185 * Needs to handle these cases:
3101 3186 * Dataset 1 "a/foo" "a/foo" "a/foo" "a/foo"
3102 3187 * Dataset 2 "a/fo" "a/foobar" "a/bar/baz" "a/foo/bar"
3103 3188 * Descendant? No. No. No. Yes.
3104 3189 */
3105 3190 static boolean_t
3106 3191 is_descendant(const char *ds1, const char *ds2)
3107 3192 {
3108 3193 size_t d1len = strlen(ds1);
3109 3194
3110 3195 /* ds2 can't be a descendant if it's smaller */
3111 3196 if (strlen(ds2) < d1len)
3112 3197 return (B_FALSE);
3113 3198
3114 3199 /* otherwise, compare strings and verify that there's a '/' char */
3115 3200 return (ds2[d1len] == '/' && (strncmp(ds1, ds2, d1len) == 0));
3116 3201 }
3117 3202
3118 3203 /*
3119 3204 * Given a complete name, return just the portion that refers to the parent.
3120 3205 * Will return -1 if there is no parent (path is just the name of the
3121 3206 * pool).
3122 3207 */
3123 3208 static int
3124 3209 parent_name(const char *path, char *buf, size_t buflen)
3125 3210 {
3126 3211 char *slashp;
3127 3212
3128 3213 (void) strlcpy(buf, path, buflen);
3129 3214
3130 3215 if ((slashp = strrchr(buf, '/')) == NULL)
3131 3216 return (-1);
3132 3217 *slashp = '\0';
3133 3218
3134 3219 return (0);
|
↓ open down ↓ |
440 lines elided |
↑ open up ↑ |
3135 3220 }
3136 3221
3137 3222 /*
3138 3223 * If accept_ancestor is false, then check to make sure that the given path has
3139 3224 * a parent, and that it exists. If accept_ancestor is true, then find the
3140 3225 * closest existing ancestor for the given path. In prefixlen return the
3141 3226 * length of already existing prefix of the given path. We also fetch the
3142 3227 * 'zoned' property, which is used to validate property settings when creating
3143 3228 * new datasets.
3144 3229 */
3145 -static int
3230 +int
3146 3231 check_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned,
3147 3232 boolean_t accept_ancestor, int *prefixlen)
3148 3233 {
3149 3234 zfs_cmd_t zc = { 0 };
3150 3235 char parent[ZFS_MAX_DATASET_NAME_LEN];
3151 3236 char *slash;
3152 3237 zfs_handle_t *zhp;
3153 3238 char errbuf[1024];
3154 3239 uint64_t is_zoned;
3155 3240
3156 3241 (void) snprintf(errbuf, sizeof (errbuf),
3157 3242 dgettext(TEXT_DOMAIN, "cannot create '%s'"), path);
3158 3243
3159 3244 /* get parent, and check to see if this is just a pool */
3160 3245 if (parent_name(path, parent, sizeof (parent)) != 0) {
3161 3246 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3162 3247 "missing dataset name"));
3163 3248 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3164 3249 }
3165 3250
3166 3251 /* check to see if the pool exists */
3167 3252 if ((slash = strchr(parent, '/')) == NULL)
3168 3253 slash = parent + strlen(parent);
3169 3254 (void) strncpy(zc.zc_name, parent, slash - parent);
3170 3255 zc.zc_name[slash - parent] = '\0';
3171 3256 if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 &&
3172 3257 errno == ENOENT) {
3173 3258 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3174 3259 "no such pool '%s'"), zc.zc_name);
3175 3260 return (zfs_error(hdl, EZFS_NOENT, errbuf));
3176 3261 }
3177 3262
3178 3263 /* check to see if the parent dataset exists */
3179 3264 while ((zhp = make_dataset_handle(hdl, parent)) == NULL) {
3180 3265 if (errno == ENOENT && accept_ancestor) {
3181 3266 /*
3182 3267 * Go deeper to find an ancestor, give up on top level.
3183 3268 */
3184 3269 if (parent_name(parent, parent, sizeof (parent)) != 0) {
3185 3270 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3186 3271 "no such pool '%s'"), zc.zc_name);
3187 3272 return (zfs_error(hdl, EZFS_NOENT, errbuf));
3188 3273 }
3189 3274 } else if (errno == ENOENT) {
3190 3275 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3191 3276 "parent does not exist"));
3192 3277 return (zfs_error(hdl, EZFS_NOENT, errbuf));
3193 3278 } else
3194 3279 return (zfs_standard_error(hdl, errno, errbuf));
3195 3280 }
3196 3281
3197 3282 is_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
3198 3283 if (zoned != NULL)
3199 3284 *zoned = is_zoned;
3200 3285
3201 3286 /* we are in a non-global zone, but parent is in the global zone */
3202 3287 if (getzoneid() != GLOBAL_ZONEID && !is_zoned) {
3203 3288 (void) zfs_standard_error(hdl, EPERM, errbuf);
3204 3289 zfs_close(zhp);
3205 3290 return (-1);
3206 3291 }
3207 3292
3208 3293 /* make sure parent is a filesystem */
3209 3294 if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
3210 3295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3211 3296 "parent is not a filesystem"));
3212 3297 (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
3213 3298 zfs_close(zhp);
3214 3299 return (-1);
3215 3300 }
3216 3301
3217 3302 zfs_close(zhp);
3218 3303 if (prefixlen != NULL)
3219 3304 *prefixlen = strlen(parent);
3220 3305 return (0);
3221 3306 }
3222 3307
3223 3308 /*
3224 3309 * Finds whether the dataset of the given type(s) exists.
3225 3310 */
3226 3311 boolean_t
3227 3312 zfs_dataset_exists(libzfs_handle_t *hdl, const char *path, zfs_type_t types)
3228 3313 {
3229 3314 zfs_handle_t *zhp;
3230 3315
3231 3316 if (!zfs_validate_name(hdl, path, types, B_FALSE))
3232 3317 return (B_FALSE);
3233 3318
3234 3319 /*
3235 3320 * Try to get stats for the dataset, which will tell us if it exists.
3236 3321 */
3237 3322 if ((zhp = make_dataset_handle(hdl, path)) != NULL) {
3238 3323 int ds_type = zhp->zfs_type;
3239 3324
3240 3325 zfs_close(zhp);
3241 3326 if (types & ds_type)
3242 3327 return (B_TRUE);
3243 3328 }
3244 3329 return (B_FALSE);
3245 3330 }
3246 3331
3247 3332 /*
3248 3333 * Given a path to 'target', create all the ancestors between
3249 3334 * the prefixlen portion of the path, and the target itself.
3250 3335 * Fail if the initial prefixlen-ancestor does not already exist.
3251 3336 */
3252 3337 int
3253 3338 create_parents(libzfs_handle_t *hdl, char *target, int prefixlen)
3254 3339 {
3255 3340 zfs_handle_t *h;
3256 3341 char *cp;
3257 3342 const char *opname;
3258 3343
3259 3344 /* make sure prefix exists */
3260 3345 cp = target + prefixlen;
3261 3346 if (*cp != '/') {
3262 3347 assert(strchr(cp, '/') == NULL);
3263 3348 h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM);
3264 3349 } else {
3265 3350 *cp = '\0';
3266 3351 h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM);
3267 3352 *cp = '/';
3268 3353 }
3269 3354 if (h == NULL)
3270 3355 return (-1);
3271 3356 zfs_close(h);
3272 3357
3273 3358 /*
3274 3359 * Attempt to create, mount, and share any ancestor filesystems,
3275 3360 * up to the prefixlen-long one.
3276 3361 */
3277 3362 for (cp = target + prefixlen + 1;
3278 3363 (cp = strchr(cp, '/')) != NULL; *cp = '/', cp++) {
3279 3364
3280 3365 *cp = '\0';
3281 3366
3282 3367 h = make_dataset_handle(hdl, target);
3283 3368 if (h) {
3284 3369 /* it already exists, nothing to do here */
3285 3370 zfs_close(h);
3286 3371 continue;
3287 3372 }
3288 3373
3289 3374 if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM,
3290 3375 NULL) != 0) {
3291 3376 opname = dgettext(TEXT_DOMAIN, "create");
3292 3377 goto ancestorerr;
3293 3378 }
3294 3379
3295 3380 h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM);
3296 3381 if (h == NULL) {
3297 3382 opname = dgettext(TEXT_DOMAIN, "open");
3298 3383 goto ancestorerr;
3299 3384 }
3300 3385
3301 3386 if (zfs_mount(h, NULL, 0) != 0) {
3302 3387 opname = dgettext(TEXT_DOMAIN, "mount");
3303 3388 goto ancestorerr;
3304 3389 }
3305 3390
3306 3391 if (zfs_share(h) != 0) {
3307 3392 opname = dgettext(TEXT_DOMAIN, "share");
3308 3393 goto ancestorerr;
3309 3394 }
3310 3395
3311 3396 zfs_close(h);
3312 3397 }
3313 3398
3314 3399 return (0);
3315 3400
3316 3401 ancestorerr:
3317 3402 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3318 3403 "failed to %s ancestor '%s'"), opname, target);
3319 3404 return (-1);
3320 3405 }
3321 3406
3322 3407 /*
3323 3408 * Creates non-existing ancestors of the given path.
3324 3409 */
3325 3410 int
3326 3411 zfs_create_ancestors(libzfs_handle_t *hdl, const char *path)
3327 3412 {
3328 3413 int prefix;
3329 3414 char *path_copy;
3330 3415 int rc = 0;
3331 3416
3332 3417 if (check_parents(hdl, path, NULL, B_TRUE, &prefix) != 0)
3333 3418 return (-1);
3334 3419
3335 3420 if ((path_copy = strdup(path)) != NULL) {
3336 3421 rc = create_parents(hdl, path_copy, prefix);
3337 3422 free(path_copy);
3338 3423 }
3339 3424 if (path_copy == NULL || rc != 0)
3340 3425 return (-1);
3341 3426
3342 3427 return (0);
3343 3428 }
3344 3429
3345 3430 /*
3346 3431 * Create a new filesystem or volume.
3347 3432 */
3348 3433 int
3349 3434 zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
3350 3435 nvlist_t *props)
3351 3436 {
3352 3437 int ret;
3353 3438 uint64_t size = 0;
3354 3439 uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE);
3355 3440 char errbuf[1024];
3356 3441 uint64_t zoned;
3357 3442 enum lzc_dataset_type ost;
3358 3443 zpool_handle_t *zpool_handle;
3359 3444
3360 3445 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3361 3446 "cannot create '%s'"), path);
3362 3447
3363 3448 /* validate the path, taking care to note the extended error message */
3364 3449 if (!zfs_validate_name(hdl, path, type, B_TRUE))
3365 3450 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3366 3451
3367 3452 /* validate parents exist */
3368 3453 if (check_parents(hdl, path, &zoned, B_FALSE, NULL) != 0)
3369 3454 return (-1);
3370 3455
3371 3456 /*
3372 3457 * The failure modes when creating a dataset of a different type over
3373 3458 * one that already exists is a little strange. In particular, if you
3374 3459 * try to create a dataset on top of an existing dataset, the ioctl()
3375 3460 * will return ENOENT, not EEXIST. To prevent this from happening, we
3376 3461 * first try to see if the dataset exists.
3377 3462 */
3378 3463 if (zfs_dataset_exists(hdl, path, ZFS_TYPE_DATASET)) {
3379 3464 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3380 3465 "dataset already exists"));
3381 3466 return (zfs_error(hdl, EZFS_EXISTS, errbuf));
3382 3467 }
3383 3468
3384 3469 if (type == ZFS_TYPE_VOLUME)
3385 3470 ost = LZC_DATSET_TYPE_ZVOL;
3386 3471 else
3387 3472 ost = LZC_DATSET_TYPE_ZFS;
3388 3473
3389 3474 /* open zpool handle for prop validation */
3390 3475 char pool_path[ZFS_MAX_DATASET_NAME_LEN];
3391 3476 (void) strlcpy(pool_path, path, sizeof (pool_path));
3392 3477
3393 3478 /* truncate pool_path at first slash */
3394 3479 char *p = strchr(pool_path, '/');
3395 3480 if (p != NULL)
3396 3481 *p = '\0';
3397 3482
3398 3483 if ((zpool_handle = zpool_open(hdl, pool_path)) == NULL)
3399 3484 return (-1);
3400 3485
3401 3486 if (props && (props = zfs_valid_proplist(hdl, type, props,
3402 3487 zoned, NULL, zpool_handle, errbuf)) == 0) {
3403 3488 zpool_close(zpool_handle);
3404 3489 return (-1);
3405 3490 }
3406 3491 zpool_close(zpool_handle);
3407 3492
3408 3493 if (type == ZFS_TYPE_VOLUME) {
3409 3494 /*
3410 3495 * If we are creating a volume, the size and block size must
3411 3496 * satisfy a few restraints. First, the blocksize must be a
3412 3497 * valid block size between SPA_{MIN,MAX}BLOCKSIZE. Second, the
3413 3498 * volsize must be a multiple of the block size, and cannot be
3414 3499 * zero.
3415 3500 */
3416 3501 if (props == NULL || nvlist_lookup_uint64(props,
3417 3502 zfs_prop_to_name(ZFS_PROP_VOLSIZE), &size) != 0) {
3418 3503 nvlist_free(props);
3419 3504 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3420 3505 "missing volume size"));
3421 3506 return (zfs_error(hdl, EZFS_BADPROP, errbuf));
3422 3507 }
3423 3508
3424 3509 if ((ret = nvlist_lookup_uint64(props,
3425 3510 zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
3426 3511 &blocksize)) != 0) {
3427 3512 if (ret == ENOENT) {
3428 3513 blocksize = zfs_prop_default_numeric(
3429 3514 ZFS_PROP_VOLBLOCKSIZE);
3430 3515 } else {
3431 3516 nvlist_free(props);
3432 3517 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3433 3518 "missing volume block size"));
3434 3519 return (zfs_error(hdl, EZFS_BADPROP, errbuf));
3435 3520 }
3436 3521 }
3437 3522
3438 3523 if (size == 0) {
3439 3524 nvlist_free(props);
3440 3525 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3441 3526 "volume size cannot be zero"));
3442 3527 return (zfs_error(hdl, EZFS_BADPROP, errbuf));
3443 3528 }
3444 3529
3445 3530 if (size % blocksize != 0) {
3446 3531 nvlist_free(props);
|
↓ open down ↓ |
291 lines elided |
↑ open up ↑ |
3447 3532 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3448 3533 "volume size must be a multiple of volume block "
3449 3534 "size"));
3450 3535 return (zfs_error(hdl, EZFS_BADPROP, errbuf));
3451 3536 }
3452 3537 }
3453 3538
3454 3539 /* create the dataset */
3455 3540 ret = lzc_create(path, ost, props);
3456 3541 nvlist_free(props);
3542 + if (ret == 0)
3543 + libzfs_log_event(hdl, path);
3457 3544
3458 3545 /* check for failure */
3459 3546 if (ret != 0) {
3460 3547 char parent[ZFS_MAX_DATASET_NAME_LEN];
3461 3548 (void) parent_name(path, parent, sizeof (parent));
3462 3549
3463 3550 switch (errno) {
3464 3551 case ENOENT:
3465 3552 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3466 3553 "no such parent '%s'"), parent);
3467 3554 return (zfs_error(hdl, EZFS_NOENT, errbuf));
3468 3555
3469 3556 case EINVAL:
3470 3557 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3471 3558 "parent '%s' is not a filesystem"), parent);
3472 3559 return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
3473 3560
3474 3561 case ENOTSUP:
3475 3562 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3476 3563 "pool must be upgraded to set this "
3477 3564 "property or value"));
3478 3565 return (zfs_error(hdl, EZFS_BADVERSION, errbuf));
3479 3566 case ERANGE:
3480 3567 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3481 3568 "invalid property value(s) specified"));
3482 3569 return (zfs_error(hdl, EZFS_BADPROP, errbuf));
3483 3570 #ifdef _ILP32
3484 3571 case EOVERFLOW:
3485 3572 /*
3486 3573 * This platform can't address a volume this big.
3487 3574 */
3488 3575 if (type == ZFS_TYPE_VOLUME)
3489 3576 return (zfs_error(hdl, EZFS_VOLTOOBIG,
3490 3577 errbuf));
|
↓ open down ↓ |
24 lines elided |
↑ open up ↑ |
3491 3578 #endif
3492 3579 /* FALLTHROUGH */
3493 3580 default:
3494 3581 return (zfs_standard_error(hdl, errno, errbuf));
3495 3582 }
3496 3583 }
3497 3584
3498 3585 return (0);
3499 3586 }
3500 3587
3588 +int
3589 +zfs_check_krrp(libzfs_handle_t *hdl, const char *name)
3590 +{
3591 + zfs_cmd_t zc = { 0 };
3592 + int err;
3593 +
3594 + (void) strncpy(zc.zc_name, name, ZFS_MAX_DATASET_NAME_LEN);
3595 + zc.zc_name[ZFS_MAX_DATASET_NAME_LEN - 1] = '\0';
3596 +
3597 + (void) zfs_ioctl(hdl, ZFS_IOC_CHECK_KRRP, &zc);
3598 + err = errno;
3599 +
3600 + free((void *)(uintptr_t)zc.zc_nvlist_dst);
3601 +
3602 + return (err);
3603 +}
3604 +
3605 +int
3606 +zfs_destroy_atomically(zfs_handle_t *zhp, boolean_t defer)
3607 +{
3608 + zfs_cmd_t zc = { 0 };
3609 +
3610 + if (zhp->zfs_type == ZFS_TYPE_BOOKMARK) {
3611 + nvlist_t *nv = fnvlist_alloc();
3612 + fnvlist_add_boolean(nv, zhp->zfs_name);
3613 + int error = lzc_destroy_bookmarks(nv, NULL);
3614 + fnvlist_free(nv);
3615 + if (error != 0) {
3616 + return (zfs_standard_error_fmt(zhp->zfs_hdl, errno,
3617 + dgettext(TEXT_DOMAIN, "cannot destroy '%s'"),
3618 + zhp->zfs_name));
3619 + }
3620 + return (0);
3621 + }
3622 +
3623 + (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
3624 +
3625 + if (ZFS_IS_VOLUME(zhp)) {
3626 + zc.zc_objset_type = DMU_OST_ZVOL;
3627 + } else {
3628 + zc.zc_objset_type = DMU_OST_ZFS;
3629 + }
3630 +
3631 + zc.zc_defer_destroy = defer;
3632 + zc.zc_guid = B_TRUE;
3633 + if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY, &zc) != 0 &&
3634 + errno != ENOENT) {
3635 + return (zfs_standard_error_fmt(zhp->zfs_hdl, errno,
3636 + dgettext(TEXT_DOMAIN, "cannot destroy '%s'"),
3637 + zhp->zfs_name));
3638 + }
3639 +
3640 + remove_mountpoint(zhp);
3641 +
3642 + return (0);
3643 +
3644 +}
3645 +
3501 3646 /*
3502 3647 * Destroys the given dataset. The caller must make sure that the filesystem
3503 3648 * isn't mounted, and that there are no active dependents. If the file system
3504 3649 * does not exist this function does nothing.
3505 3650 */
3506 3651 int
3507 3652 zfs_destroy(zfs_handle_t *zhp, boolean_t defer)
3508 3653 {
3509 3654 zfs_cmd_t zc = { 0 };
3510 3655
3511 3656 if (zhp->zfs_type == ZFS_TYPE_BOOKMARK) {
3512 3657 nvlist_t *nv = fnvlist_alloc();
3513 3658 fnvlist_add_boolean(nv, zhp->zfs_name);
3514 3659 int error = lzc_destroy_bookmarks(nv, NULL);
3515 3660 fnvlist_free(nv);
3516 3661 if (error != 0) {
3517 3662 return (zfs_standard_error_fmt(zhp->zfs_hdl, errno,
3518 3663 dgettext(TEXT_DOMAIN, "cannot destroy '%s'"),
3519 3664 zhp->zfs_name));
3520 3665 }
3521 3666 return (0);
3522 3667 }
3523 3668
3524 3669 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
3525 3670
3526 3671 if (ZFS_IS_VOLUME(zhp)) {
3527 3672 zc.zc_objset_type = DMU_OST_ZVOL;
3528 3673 } else {
3529 3674 zc.zc_objset_type = DMU_OST_ZFS;
3530 3675 }
3531 3676
3532 3677 zc.zc_defer_destroy = defer;
3533 3678 if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY, &zc) != 0 &&
3534 3679 errno != ENOENT) {
3535 3680 return (zfs_standard_error_fmt(zhp->zfs_hdl, errno,
3536 3681 dgettext(TEXT_DOMAIN, "cannot destroy '%s'"),
3537 3682 zhp->zfs_name));
3538 3683 }
3539 3684
3540 3685 remove_mountpoint(zhp);
3541 3686
3542 3687 return (0);
3543 3688 }
3544 3689
3545 3690 struct destroydata {
3546 3691 nvlist_t *nvl;
3547 3692 const char *snapname;
3548 3693 };
3549 3694
3550 3695 static int
3551 3696 zfs_check_snap_cb(zfs_handle_t *zhp, void *arg)
3552 3697 {
3553 3698 struct destroydata *dd = arg;
3554 3699 char name[ZFS_MAX_DATASET_NAME_LEN];
3555 3700 int rv = 0;
3556 3701
3557 3702 (void) snprintf(name, sizeof (name),
3558 3703 "%s@%s", zhp->zfs_name, dd->snapname);
3559 3704
3560 3705 if (lzc_exists(name))
3561 3706 verify(nvlist_add_boolean(dd->nvl, name) == 0);
3562 3707
3563 3708 rv = zfs_iter_filesystems(zhp, zfs_check_snap_cb, dd);
3564 3709 zfs_close(zhp);
3565 3710 return (rv);
3566 3711 }
3567 3712
3568 3713 /*
3569 3714 * Destroys all snapshots with the given name in zhp & descendants.
3570 3715 */
3571 3716 int
3572 3717 zfs_destroy_snaps(zfs_handle_t *zhp, char *snapname, boolean_t defer)
3573 3718 {
3574 3719 int ret;
3575 3720 struct destroydata dd = { 0 };
3576 3721
3577 3722 dd.snapname = snapname;
3578 3723 verify(nvlist_alloc(&dd.nvl, NV_UNIQUE_NAME, 0) == 0);
3579 3724 (void) zfs_check_snap_cb(zfs_handle_dup(zhp), &dd);
3580 3725
3581 3726 if (nvlist_empty(dd.nvl)) {
3582 3727 ret = zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT,
3583 3728 dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"),
3584 3729 zhp->zfs_name, snapname);
3585 3730 } else {
3586 3731 ret = zfs_destroy_snaps_nvl(zhp->zfs_hdl, dd.nvl, defer);
3587 3732 }
3588 3733 nvlist_free(dd.nvl);
|
↓ open down ↓ |
78 lines elided |
↑ open up ↑ |
3589 3734 return (ret);
3590 3735 }
3591 3736
3592 3737 /*
3593 3738 * Destroys all the snapshots named in the nvlist.
3594 3739 */
3595 3740 int
3596 3741 zfs_destroy_snaps_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, boolean_t defer)
3597 3742 {
3598 3743 int ret;
3744 + nvpair_t *elem;
3599 3745 nvlist_t *errlist = NULL;
3600 3746
3601 3747 ret = lzc_destroy_snaps(snaps, defer, &errlist);
3748 + if (ret == 0) {
3749 + for (elem = nvlist_next_nvpair(snaps, NULL); elem != NULL;
3750 + elem = nvlist_next_nvpair(snaps, elem))
3751 + libzfs_log_event(hdl, nvpair_name(elem));
3752 + }
3602 3753
3603 3754 if (ret == 0) {
3604 3755 nvlist_free(errlist);
3605 3756 return (0);
3606 3757 }
3607 3758
3608 3759 if (nvlist_empty(errlist)) {
3609 3760 char errbuf[1024];
3610 3761 (void) snprintf(errbuf, sizeof (errbuf),
3611 3762 dgettext(TEXT_DOMAIN, "cannot destroy snapshots"));
3612 3763
3613 3764 ret = zfs_standard_error(hdl, ret, errbuf);
3614 3765 }
3615 3766 for (nvpair_t *pair = nvlist_next_nvpair(errlist, NULL);
3616 3767 pair != NULL; pair = nvlist_next_nvpair(errlist, pair)) {
3617 3768 char errbuf[1024];
3618 3769 (void) snprintf(errbuf, sizeof (errbuf),
3619 3770 dgettext(TEXT_DOMAIN, "cannot destroy snapshot %s"),
3620 3771 nvpair_name(pair));
3621 3772
3622 3773 switch (fnvpair_value_int32(pair)) {
3623 3774 case EEXIST:
3624 3775 zfs_error_aux(hdl,
3625 3776 dgettext(TEXT_DOMAIN, "snapshot is cloned"));
3626 3777 ret = zfs_error(hdl, EZFS_EXISTS, errbuf);
3627 3778 break;
3628 3779 default:
3629 3780 ret = zfs_standard_error(hdl, errno, errbuf);
3630 3781 break;
3631 3782 }
3632 3783 }
3633 3784
3634 3785 nvlist_free(errlist);
3635 3786 return (ret);
3636 3787 }
3637 3788
3638 3789 /*
3639 3790 * Clones the given dataset. The target must be of the same type as the source.
3640 3791 */
3641 3792 int
3642 3793 zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props)
3643 3794 {
3644 3795 char parent[ZFS_MAX_DATASET_NAME_LEN];
3645 3796 int ret;
3646 3797 char errbuf[1024];
3647 3798 libzfs_handle_t *hdl = zhp->zfs_hdl;
3648 3799 uint64_t zoned;
3649 3800
3650 3801 assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
3651 3802
3652 3803 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3653 3804 "cannot create '%s'"), target);
3654 3805
3655 3806 /* validate the target/clone name */
3656 3807 if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM, B_TRUE))
3657 3808 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3658 3809
3659 3810 /* validate parents exist */
3660 3811 if (check_parents(hdl, target, &zoned, B_FALSE, NULL) != 0)
3661 3812 return (-1);
3662 3813
3663 3814 (void) parent_name(target, parent, sizeof (parent));
3664 3815
3665 3816 /* do the clone */
3666 3817
3667 3818 if (props) {
3668 3819 zfs_type_t type;
3669 3820 if (ZFS_IS_VOLUME(zhp)) {
3670 3821 type = ZFS_TYPE_VOLUME;
|
↓ open down ↓ |
59 lines elided |
↑ open up ↑ |
3671 3822 } else {
3672 3823 type = ZFS_TYPE_FILESYSTEM;
3673 3824 }
3674 3825 if ((props = zfs_valid_proplist(hdl, type, props, zoned,
3675 3826 zhp, zhp->zpool_hdl, errbuf)) == NULL)
3676 3827 return (-1);
3677 3828 }
3678 3829
3679 3830 ret = lzc_clone(target, zhp->zfs_name, props);
3680 3831 nvlist_free(props);
3832 + if (ret == 0)
3833 + libzfs_log_event(hdl, target);
3681 3834
3682 3835 if (ret != 0) {
3683 3836 switch (errno) {
3684 3837
3685 3838 case ENOENT:
3686 3839 /*
3687 3840 * The parent doesn't exist. We should have caught this
3688 3841 * above, but there may a race condition that has since
3689 3842 * destroyed the parent.
3690 3843 *
3691 3844 * At this point, we don't know whether it's the source
3692 3845 * that doesn't exist anymore, or whether the target
3693 3846 * dataset doesn't exist.
3694 3847 */
3695 3848 zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
3696 3849 "no such parent '%s'"), parent);
3697 3850 return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf));
3698 3851
3699 3852 case EXDEV:
3700 3853 zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
3701 3854 "source and target pools differ"));
3702 3855 return (zfs_error(zhp->zfs_hdl, EZFS_CROSSTARGET,
3703 3856 errbuf));
3704 3857
3705 3858 default:
3706 3859 return (zfs_standard_error(zhp->zfs_hdl, errno,
3707 3860 errbuf));
3708 3861 }
3709 3862 }
3710 3863
3711 3864 return (ret);
3712 3865 }
3713 3866
3714 3867 /*
3715 3868 * Promotes the given clone fs to be the clone parent.
3716 3869 */
3717 3870 int
3718 3871 zfs_promote(zfs_handle_t *zhp)
3719 3872 {
3720 3873 libzfs_handle_t *hdl = zhp->zfs_hdl;
3721 3874 char snapname[ZFS_MAX_DATASET_NAME_LEN];
3722 3875 int ret;
3723 3876 char errbuf[1024];
3724 3877
3725 3878 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3726 3879 "cannot promote '%s'"), zhp->zfs_name);
3727 3880
3728 3881 if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
3729 3882 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
↓ open down ↓ |
39 lines elided |
↑ open up ↑ |
3730 3883 "snapshots can not be promoted"));
3731 3884 return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
3732 3885 }
3733 3886
3734 3887 if (zhp->zfs_dmustats.dds_origin[0] == '\0') {
3735 3888 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3736 3889 "not a cloned filesystem"));
3737 3890 return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
3738 3891 }
3739 3892
3740 - if (!zfs_validate_name(hdl, zhp->zfs_name, zhp->zfs_type, B_TRUE))
3741 - return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3742 -
3743 3893 ret = lzc_promote(zhp->zfs_name, snapname, sizeof (snapname));
3744 3894
3745 3895 if (ret != 0) {
3746 3896 switch (ret) {
3747 3897 case EEXIST:
3748 3898 /* There is a conflicting snapshot name. */
3749 3899 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3750 3900 "conflicting snapshot '%s' from parent '%s'"),
3751 3901 snapname, zhp->zfs_dmustats.dds_origin);
3752 3902 return (zfs_error(hdl, EZFS_EXISTS, errbuf));
3753 3903
3754 3904 default:
3755 3905 return (zfs_standard_error(hdl, ret, errbuf));
3756 3906 }
3757 3907 }
3758 3908 return (ret);
3759 3909 }
3760 3910
3761 3911 typedef struct snapdata {
3762 3912 nvlist_t *sd_nvl;
3763 3913 const char *sd_snapname;
3764 3914 } snapdata_t;
3765 3915
3766 3916 static int
3767 3917 zfs_snapshot_cb(zfs_handle_t *zhp, void *arg)
3768 3918 {
3769 3919 snapdata_t *sd = arg;
3770 3920 char name[ZFS_MAX_DATASET_NAME_LEN];
3771 3921 int rv = 0;
3772 3922
3773 3923 if (zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) == 0) {
3774 3924 (void) snprintf(name, sizeof (name),
3775 3925 "%s@%s", zfs_get_name(zhp), sd->sd_snapname);
|
↓ open down ↓ |
23 lines elided |
↑ open up ↑ |
3776 3926
3777 3927 fnvlist_add_boolean(sd->sd_nvl, name);
3778 3928
3779 3929 rv = zfs_iter_filesystems(zhp, zfs_snapshot_cb, sd);
3780 3930 }
3781 3931 zfs_close(zhp);
3782 3932
3783 3933 return (rv);
3784 3934 }
3785 3935
3786 -int
3787 -zfs_remap_indirects(libzfs_handle_t *hdl, const char *fs)
3788 -{
3789 - int err;
3790 - char errbuf[1024];
3791 -
3792 - (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3793 - "cannot remap filesystem '%s' "), fs);
3794 -
3795 - err = lzc_remap(fs);
3796 -
3797 - if (err != 0) {
3798 - (void) zfs_standard_error(hdl, err, errbuf);
3799 - }
3800 -
3801 - return (err);
3802 -}
3803 -
3804 3936 /*
3805 3937 * Creates snapshots. The keys in the snaps nvlist are the snapshots to be
3806 3938 * created.
3807 3939 */
3808 3940 int
3809 3941 zfs_snapshot_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, nvlist_t *props)
3810 3942 {
3811 3943 int ret;
3812 3944 char errbuf[1024];
3813 3945 nvpair_t *elem;
3814 3946 nvlist_t *errors;
3815 3947
3816 3948 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3817 3949 "cannot create snapshots "));
3818 3950
3819 3951 elem = NULL;
3820 3952 while ((elem = nvlist_next_nvpair(snaps, elem)) != NULL) {
3821 3953 const char *snapname = nvpair_name(elem);
3822 3954
3823 3955 /* validate the target name */
3824 3956 if (!zfs_validate_name(hdl, snapname, ZFS_TYPE_SNAPSHOT,
3825 3957 B_TRUE)) {
3826 3958 (void) snprintf(errbuf, sizeof (errbuf),
3827 3959 dgettext(TEXT_DOMAIN,
3828 3960 "cannot create snapshot '%s'"), snapname);
3829 3961 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3830 3962 }
3831 3963 }
3832 3964
3833 3965 /*
3834 3966 * get pool handle for prop validation. assumes all snaps are in the
3835 3967 * same pool, as does lzc_snapshot (below).
3836 3968 */
3837 3969 char pool[ZFS_MAX_DATASET_NAME_LEN];
3838 3970 elem = nvlist_next_nvpair(snaps, NULL);
3839 3971 (void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
3840 3972 pool[strcspn(pool, "/@")] = '\0';
3841 3973 zpool_handle_t *zpool_hdl = zpool_open(hdl, pool);
|
↓ open down ↓ |
28 lines elided |
↑ open up ↑ |
3842 3974
3843 3975 if (props != NULL &&
3844 3976 (props = zfs_valid_proplist(hdl, ZFS_TYPE_SNAPSHOT,
3845 3977 props, B_FALSE, NULL, zpool_hdl, errbuf)) == NULL) {
3846 3978 zpool_close(zpool_hdl);
3847 3979 return (-1);
3848 3980 }
3849 3981 zpool_close(zpool_hdl);
3850 3982
3851 3983 ret = lzc_snapshot(snaps, props, &errors);
3984 + if (ret == 0) {
3985 + for (elem = nvlist_next_nvpair(snaps, NULL); elem != NULL;
3986 + elem = nvlist_next_nvpair(snaps, elem))
3987 + libzfs_log_event(hdl, nvpair_name(elem));
3988 + }
3852 3989
3853 3990 if (ret != 0) {
3854 3991 boolean_t printed = B_FALSE;
3855 3992 for (elem = nvlist_next_nvpair(errors, NULL);
3856 3993 elem != NULL;
3857 3994 elem = nvlist_next_nvpair(errors, elem)) {
3858 3995 (void) snprintf(errbuf, sizeof (errbuf),
3859 3996 dgettext(TEXT_DOMAIN,
3860 3997 "cannot create snapshot '%s'"), nvpair_name(elem));
3861 3998 (void) zfs_standard_error(hdl,
3862 3999 fnvpair_value_int32(elem), errbuf);
3863 4000 printed = B_TRUE;
3864 4001 }
3865 4002 if (!printed) {
3866 4003 switch (ret) {
3867 4004 case EXDEV:
3868 4005 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3869 4006 "multiple snapshots of same "
3870 4007 "fs not allowed"));
3871 4008 (void) zfs_error(hdl, EZFS_EXISTS, errbuf);
3872 4009
3873 4010 break;
3874 4011 default:
3875 4012 (void) zfs_standard_error(hdl, ret, errbuf);
3876 4013 }
3877 4014 }
3878 4015 }
3879 4016
3880 4017 nvlist_free(props);
3881 4018 nvlist_free(errors);
3882 4019 return (ret);
3883 4020 }
3884 4021
3885 4022 int
3886 4023 zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive,
3887 4024 nvlist_t *props)
3888 4025 {
3889 4026 int ret;
3890 4027 snapdata_t sd = { 0 };
3891 4028 char fsname[ZFS_MAX_DATASET_NAME_LEN];
3892 4029 char *cp;
3893 4030 zfs_handle_t *zhp;
3894 4031 char errbuf[1024];
3895 4032
3896 4033 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3897 4034 "cannot snapshot %s"), path);
3898 4035
3899 4036 if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT, B_TRUE))
3900 4037 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3901 4038
3902 4039 (void) strlcpy(fsname, path, sizeof (fsname));
3903 4040 cp = strchr(fsname, '@');
3904 4041 *cp = '\0';
3905 4042 sd.sd_snapname = cp + 1;
3906 4043
3907 4044 if ((zhp = zfs_open(hdl, fsname, ZFS_TYPE_FILESYSTEM |
3908 4045 ZFS_TYPE_VOLUME)) == NULL) {
3909 4046 return (-1);
3910 4047 }
3911 4048
3912 4049 verify(nvlist_alloc(&sd.sd_nvl, NV_UNIQUE_NAME, 0) == 0);
3913 4050 if (recursive) {
3914 4051 (void) zfs_snapshot_cb(zfs_handle_dup(zhp), &sd);
3915 4052 } else {
3916 4053 fnvlist_add_boolean(sd.sd_nvl, path);
3917 4054 }
3918 4055
3919 4056 ret = zfs_snapshot_nvl(hdl, sd.sd_nvl, props);
3920 4057 nvlist_free(sd.sd_nvl);
3921 4058 zfs_close(zhp);
3922 4059 return (ret);
3923 4060 }
3924 4061
3925 4062 /*
3926 4063 * Destroy any more recent snapshots. We invoke this callback on any dependents
3927 4064 * of the snapshot first. If the 'cb_dependent' member is non-zero, then this
3928 4065 * is a dependent and we should just destroy it without checking the transaction
3929 4066 * group.
3930 4067 */
3931 4068 typedef struct rollback_data {
3932 4069 const char *cb_target; /* the snapshot */
3933 4070 uint64_t cb_create; /* creation time reference */
3934 4071 boolean_t cb_error;
3935 4072 boolean_t cb_force;
3936 4073 } rollback_data_t;
3937 4074
3938 4075 static int
3939 4076 rollback_destroy_dependent(zfs_handle_t *zhp, void *data)
3940 4077 {
3941 4078 rollback_data_t *cbp = data;
3942 4079 prop_changelist_t *clp;
3943 4080
3944 4081 /* We must destroy this clone; first unmount it */
3945 4082 clp = changelist_gather(zhp, ZFS_PROP_NAME, 0,
3946 4083 cbp->cb_force ? MS_FORCE: 0);
3947 4084 if (clp == NULL || changelist_prefix(clp) != 0) {
3948 4085 cbp->cb_error = B_TRUE;
3949 4086 zfs_close(zhp);
3950 4087 return (0);
3951 4088 }
3952 4089 if (zfs_destroy(zhp, B_FALSE) != 0)
3953 4090 cbp->cb_error = B_TRUE;
3954 4091 else
3955 4092 changelist_remove(clp, zhp->zfs_name);
3956 4093 (void) changelist_postfix(clp);
3957 4094 changelist_free(clp);
3958 4095
3959 4096 zfs_close(zhp);
3960 4097 return (0);
3961 4098 }
3962 4099
3963 4100 static int
3964 4101 rollback_destroy(zfs_handle_t *zhp, void *data)
3965 4102 {
3966 4103 rollback_data_t *cbp = data;
3967 4104
3968 4105 if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > cbp->cb_create) {
3969 4106 cbp->cb_error |= zfs_iter_dependents(zhp, B_FALSE,
3970 4107 rollback_destroy_dependent, cbp);
3971 4108
3972 4109 cbp->cb_error |= zfs_destroy(zhp, B_FALSE);
3973 4110 }
3974 4111
3975 4112 zfs_close(zhp);
3976 4113 return (0);
3977 4114 }
3978 4115
3979 4116 /*
3980 4117 * Given a dataset, rollback to a specific snapshot, discarding any
3981 4118 * data changes since then and making it the active dataset.
3982 4119 *
3983 4120 * Any snapshots and bookmarks more recent than the target are
3984 4121 * destroyed, along with their dependents (i.e. clones).
3985 4122 */
3986 4123 int
3987 4124 zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force)
3988 4125 {
3989 4126 rollback_data_t cb = { 0 };
3990 4127 int err;
3991 4128 boolean_t restore_resv = 0;
3992 4129 uint64_t old_volsize = 0, new_volsize;
3993 4130 zfs_prop_t resv_prop;
3994 4131
3995 4132 assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM ||
3996 4133 zhp->zfs_type == ZFS_TYPE_VOLUME);
3997 4134
3998 4135 /*
3999 4136 * Destroy all recent snapshots and their dependents.
4000 4137 */
4001 4138 cb.cb_force = force;
4002 4139 cb.cb_target = snap->zfs_name;
4003 4140 cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG);
4004 4141 (void) zfs_iter_snapshots(zhp, B_FALSE, rollback_destroy, &cb);
4005 4142 (void) zfs_iter_bookmarks(zhp, rollback_destroy, &cb);
4006 4143
4007 4144 if (cb.cb_error)
4008 4145 return (-1);
4009 4146
4010 4147 /*
4011 4148 * Now that we have verified that the snapshot is the latest,
4012 4149 * rollback to the given snapshot.
4013 4150 */
4014 4151
4015 4152 if (zhp->zfs_type == ZFS_TYPE_VOLUME) {
4016 4153 if (zfs_which_resv_prop(zhp, &resv_prop) < 0)
4017 4154 return (-1);
4018 4155 old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
4019 4156 restore_resv =
4020 4157 (old_volsize == zfs_prop_get_int(zhp, resv_prop));
4021 4158 }
4022 4159
4023 4160 /*
4024 4161 * Pass both the filesystem and the wanted snapshot names,
4025 4162 * we would get an error back if the snapshot is destroyed or
4026 4163 * a new snapshot is created before this request is processed.
4027 4164 */
4028 4165 err = lzc_rollback_to(zhp->zfs_name, snap->zfs_name);
4029 4166 if (err != 0) {
4030 4167 char errbuf[1024];
4031 4168
4032 4169 (void) snprintf(errbuf, sizeof (errbuf),
4033 4170 dgettext(TEXT_DOMAIN, "cannot rollback '%s'"),
4034 4171 zhp->zfs_name);
4035 4172 switch (err) {
4036 4173 case EEXIST:
4037 4174 zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
4038 4175 "there is a snapshot or bookmark more recent "
4039 4176 "than '%s'"), snap->zfs_name);
4040 4177 (void) zfs_error(zhp->zfs_hdl, EZFS_EXISTS, errbuf);
4041 4178 break;
4042 4179 case ESRCH:
4043 4180 zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
4044 4181 "'%s' is not found among snapshots of '%s'"),
4045 4182 snap->zfs_name, zhp->zfs_name);
4046 4183 (void) zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf);
4047 4184 break;
4048 4185 case EINVAL:
4049 4186 (void) zfs_error(zhp->zfs_hdl, EZFS_BADTYPE, errbuf);
4050 4187 break;
4051 4188 default:
4052 4189 (void) zfs_standard_error(zhp->zfs_hdl, err, errbuf);
4053 4190 }
4054 4191 return (err);
4055 4192 }
4056 4193
4057 4194 /*
4058 4195 * For volumes, if the pre-rollback volsize matched the pre-
4059 4196 * rollback reservation and the volsize has changed then set
4060 4197 * the reservation property to the post-rollback volsize.
4061 4198 * Make a new handle since the rollback closed the dataset.
4062 4199 */
4063 4200 if ((zhp->zfs_type == ZFS_TYPE_VOLUME) &&
4064 4201 (zhp = make_dataset_handle(zhp->zfs_hdl, zhp->zfs_name))) {
4065 4202 if (restore_resv) {
4066 4203 new_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
4067 4204 if (old_volsize != new_volsize)
4068 4205 err = zfs_prop_set_int(zhp, resv_prop,
4069 4206 new_volsize);
4070 4207 }
4071 4208 zfs_close(zhp);
4072 4209 }
4073 4210 return (err);
4074 4211 }
4075 4212
4076 4213 /*
4077 4214 * Renames the given dataset.
4078 4215 */
4079 4216 int
4080 4217 zfs_rename(zfs_handle_t *zhp, const char *target, boolean_t recursive,
4081 4218 boolean_t force_unmount)
4082 4219 {
4083 4220 int ret = 0;
4084 4221 zfs_cmd_t zc = { 0 };
4085 4222 char *delim;
4086 4223 prop_changelist_t *cl = NULL;
4087 4224 zfs_handle_t *zhrp = NULL;
4088 4225 char *parentname = NULL;
4089 4226 char parent[ZFS_MAX_DATASET_NAME_LEN];
|
↓ open down ↓ |
228 lines elided |
↑ open up ↑ |
4090 4227 libzfs_handle_t *hdl = zhp->zfs_hdl;
4091 4228 char errbuf[1024];
4092 4229
4093 4230 /* if we have the same exact name, just return success */
4094 4231 if (strcmp(zhp->zfs_name, target) == 0)
4095 4232 return (0);
4096 4233
4097 4234 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
4098 4235 "cannot rename to '%s'"), target);
4099 4236
4100 - /* make sure source name is valid */
4101 - if (!zfs_validate_name(hdl, zhp->zfs_name, zhp->zfs_type, B_TRUE))
4102 - return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
4237 + if (zhp->zfs_type == ZFS_TYPE_AUTOSNAP) {
4238 + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4239 + "autosnapshots cannot be renamed"));
4240 + return (zfs_error(hdl, EZFS_PERM, errbuf));
4241 + }
4103 4242
4104 4243 /*
4105 4244 * Make sure the target name is valid
4106 4245 */
4107 4246 if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
4108 4247 if ((strchr(target, '@') == NULL) ||
4109 4248 *target == '@') {
4110 4249 /*
4111 4250 * Snapshot target name is abbreviated,
4112 4251 * reconstruct full dataset name
4113 4252 */
4114 4253 (void) strlcpy(parent, zhp->zfs_name,
4115 4254 sizeof (parent));
4116 4255 delim = strchr(parent, '@');
4117 4256 if (strchr(target, '@') == NULL)
4118 4257 *(++delim) = '\0';
4119 4258 else
4120 4259 *delim = '\0';
4121 4260 (void) strlcat(parent, target, sizeof (parent));
4122 4261 target = parent;
4123 4262 } else {
4124 4263 /*
4125 4264 * Make sure we're renaming within the same dataset.
4126 4265 */
4127 4266 delim = strchr(target, '@');
4128 4267 if (strncmp(zhp->zfs_name, target, delim - target)
4129 4268 != 0 || zhp->zfs_name[delim - target] != '@') {
4130 4269 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4131 4270 "snapshots must be part of same "
4132 4271 "dataset"));
4133 4272 return (zfs_error(hdl, EZFS_CROSSTARGET,
4134 4273 errbuf));
4135 4274 }
4136 4275 }
4137 4276 if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE))
4138 4277 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
4139 4278 } else {
4140 4279 if (recursive) {
4141 4280 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4142 4281 "recursive rename must be a snapshot"));
4143 4282 return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
4144 4283 }
4145 4284
4146 4285 if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE))
4147 4286 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
4148 4287
4149 4288 /* validate parents */
4150 4289 if (check_parents(hdl, target, NULL, B_FALSE, NULL) != 0)
4151 4290 return (-1);
4152 4291
4153 4292 /* make sure we're in the same pool */
4154 4293 verify((delim = strchr(target, '/')) != NULL);
4155 4294 if (strncmp(zhp->zfs_name, target, delim - target) != 0 ||
4156 4295 zhp->zfs_name[delim - target] != '/') {
4157 4296 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4158 4297 "datasets must be within same pool"));
4159 4298 return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf));
4160 4299 }
4161 4300
4162 4301 /* new name cannot be a child of the current dataset name */
4163 4302 if (is_descendant(zhp->zfs_name, target)) {
4164 4303 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4165 4304 "New dataset name cannot be a descendant of "
4166 4305 "current dataset name"));
4167 4306 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
4168 4307 }
4169 4308 }
4170 4309
4171 4310 (void) snprintf(errbuf, sizeof (errbuf),
4172 4311 dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name);
4173 4312
4174 4313 if (getzoneid() == GLOBAL_ZONEID &&
4175 4314 zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) {
4176 4315 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4177 4316 "dataset is used in a non-global zone"));
4178 4317 return (zfs_error(hdl, EZFS_ZONED, errbuf));
4179 4318 }
4180 4319
4181 4320 if (recursive) {
4182 4321 parentname = zfs_strdup(zhp->zfs_hdl, zhp->zfs_name);
4183 4322 if (parentname == NULL) {
4184 4323 ret = -1;
4185 4324 goto error;
4186 4325 }
4187 4326 delim = strchr(parentname, '@');
4188 4327 *delim = '\0';
4189 4328 zhrp = zfs_open(zhp->zfs_hdl, parentname, ZFS_TYPE_DATASET);
4190 4329 if (zhrp == NULL) {
4191 4330 ret = -1;
4192 4331 goto error;
4193 4332 }
4194 4333 } else if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT) {
4195 4334 if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0,
4196 4335 force_unmount ? MS_FORCE : 0)) == NULL)
4197 4336 return (-1);
4198 4337
4199 4338 if (changelist_haszonedchild(cl)) {
4200 4339 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4201 4340 "child dataset with inherited mountpoint is used "
4202 4341 "in a non-global zone"));
4203 4342 (void) zfs_error(hdl, EZFS_ZONED, errbuf);
4204 4343 ret = -1;
4205 4344 goto error;
4206 4345 }
4207 4346
4208 4347 if ((ret = changelist_prefix(cl)) != 0)
4209 4348 goto error;
4210 4349 }
4211 4350
4212 4351 if (ZFS_IS_VOLUME(zhp))
4213 4352 zc.zc_objset_type = DMU_OST_ZVOL;
4214 4353 else
4215 4354 zc.zc_objset_type = DMU_OST_ZFS;
4216 4355
4217 4356 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
4218 4357 (void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value));
4219 4358
4220 4359 zc.zc_cookie = recursive;
4221 4360
4222 4361 if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_RENAME, &zc)) != 0) {
4223 4362 /*
4224 4363 * if it was recursive, the one that actually failed will
4225 4364 * be in zc.zc_name
4226 4365 */
4227 4366 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
4228 4367 "cannot rename '%s'"), zc.zc_name);
4229 4368
4230 4369 if (recursive && errno == EEXIST) {
4231 4370 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4232 4371 "a child dataset already has a snapshot "
4233 4372 "with the new name"));
4234 4373 (void) zfs_error(hdl, EZFS_EXISTS, errbuf);
4235 4374 } else {
4236 4375 (void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf);
4237 4376 }
4238 4377
4239 4378 /*
4240 4379 * On failure, we still want to remount any filesystems that
4241 4380 * were previously mounted, so we don't alter the system state.
4242 4381 */
4243 4382 if (cl != NULL)
4244 4383 (void) changelist_postfix(cl);
4245 4384 } else {
4246 4385 if (cl != NULL) {
4247 4386 changelist_rename(cl, zfs_get_name(zhp), target);
4248 4387 ret = changelist_postfix(cl);
4249 4388 }
4250 4389 }
4251 4390
4252 4391 error:
4253 4392 if (parentname != NULL) {
4254 4393 free(parentname);
4255 4394 }
4256 4395 if (zhrp != NULL) {
4257 4396 zfs_close(zhrp);
4258 4397 }
4259 4398 if (cl != NULL) {
4260 4399 changelist_free(cl);
4261 4400 }
4262 4401 return (ret);
4263 4402 }
4264 4403
4265 4404 nvlist_t *
4266 4405 zfs_get_user_props(zfs_handle_t *zhp)
4267 4406 {
4268 4407 return (zhp->zfs_user_props);
4269 4408 }
4270 4409
4271 4410 nvlist_t *
4272 4411 zfs_get_recvd_props(zfs_handle_t *zhp)
4273 4412 {
4274 4413 if (zhp->zfs_recvd_props == NULL)
4275 4414 if (get_recvd_props_ioctl(zhp) != 0)
4276 4415 return (NULL);
4277 4416 return (zhp->zfs_recvd_props);
4278 4417 }
4279 4418
4280 4419 /*
4281 4420 * This function is used by 'zfs list' to determine the exact set of columns to
4282 4421 * display, and their maximum widths. This does two main things:
4283 4422 *
4284 4423 * - If this is a list of all properties, then expand the list to include
4285 4424 * all native properties, and set a flag so that for each dataset we look
4286 4425 * for new unique user properties and add them to the list.
4287 4426 *
4288 4427 * - For non fixed-width properties, keep track of the maximum width seen
4289 4428 * so that we can size the column appropriately. If the user has
4290 4429 * requested received property values, we also need to compute the width
4291 4430 * of the RECEIVED column.
4292 4431 */
4293 4432 int
4294 4433 zfs_expand_proplist(zfs_handle_t *zhp, zprop_list_t **plp, boolean_t received,
4295 4434 boolean_t literal)
4296 4435 {
4297 4436 libzfs_handle_t *hdl = zhp->zfs_hdl;
4298 4437 zprop_list_t *entry;
4299 4438 zprop_list_t **last, **start;
4300 4439 nvlist_t *userprops, *propval;
4301 4440 nvpair_t *elem;
4302 4441 char *strval;
4303 4442 char buf[ZFS_MAXPROPLEN];
4304 4443
4305 4444 if (zprop_expand_list(hdl, plp, ZFS_TYPE_DATASET) != 0)
4306 4445 return (-1);
4307 4446
4308 4447 userprops = zfs_get_user_props(zhp);
4309 4448
4310 4449 entry = *plp;
4311 4450 if (entry->pl_all && nvlist_next_nvpair(userprops, NULL) != NULL) {
4312 4451 /*
4313 4452 * Go through and add any user properties as necessary. We
4314 4453 * start by incrementing our list pointer to the first
4315 4454 * non-native property.
4316 4455 */
4317 4456 start = plp;
4318 4457 while (*start != NULL) {
4319 4458 if ((*start)->pl_prop == ZPROP_INVAL)
4320 4459 break;
4321 4460 start = &(*start)->pl_next;
4322 4461 }
4323 4462
4324 4463 elem = NULL;
4325 4464 while ((elem = nvlist_next_nvpair(userprops, elem)) != NULL) {
4326 4465 /*
4327 4466 * See if we've already found this property in our list.
4328 4467 */
4329 4468 for (last = start; *last != NULL;
4330 4469 last = &(*last)->pl_next) {
4331 4470 if (strcmp((*last)->pl_user_prop,
4332 4471 nvpair_name(elem)) == 0)
4333 4472 break;
4334 4473 }
4335 4474
4336 4475 if (*last == NULL) {
4337 4476 if ((entry = zfs_alloc(hdl,
4338 4477 sizeof (zprop_list_t))) == NULL ||
4339 4478 ((entry->pl_user_prop = zfs_strdup(hdl,
4340 4479 nvpair_name(elem)))) == NULL) {
4341 4480 free(entry);
4342 4481 return (-1);
4343 4482 }
4344 4483
4345 4484 entry->pl_prop = ZPROP_INVAL;
4346 4485 entry->pl_width = strlen(nvpair_name(elem));
4347 4486 entry->pl_all = B_TRUE;
4348 4487 *last = entry;
4349 4488 }
4350 4489 }
4351 4490 }
4352 4491
4353 4492 /*
4354 4493 * Now go through and check the width of any non-fixed columns
4355 4494 */
4356 4495 for (entry = *plp; entry != NULL; entry = entry->pl_next) {
4357 4496 if (entry->pl_fixed && !literal)
4358 4497 continue;
4359 4498
4360 4499 if (entry->pl_prop != ZPROP_INVAL) {
4361 4500 if (zfs_prop_get(zhp, entry->pl_prop,
4362 4501 buf, sizeof (buf), NULL, NULL, 0, literal) == 0) {
4363 4502 if (strlen(buf) > entry->pl_width)
4364 4503 entry->pl_width = strlen(buf);
4365 4504 }
4366 4505 if (received && zfs_prop_get_recvd(zhp,
4367 4506 zfs_prop_to_name(entry->pl_prop),
4368 4507 buf, sizeof (buf), literal) == 0)
4369 4508 if (strlen(buf) > entry->pl_recvd_width)
4370 4509 entry->pl_recvd_width = strlen(buf);
4371 4510 } else {
4372 4511 if (nvlist_lookup_nvlist(userprops, entry->pl_user_prop,
4373 4512 &propval) == 0) {
4374 4513 verify(nvlist_lookup_string(propval,
4375 4514 ZPROP_VALUE, &strval) == 0);
4376 4515 if (strlen(strval) > entry->pl_width)
4377 4516 entry->pl_width = strlen(strval);
4378 4517 }
4379 4518 if (received && zfs_prop_get_recvd(zhp,
4380 4519 entry->pl_user_prop,
4381 4520 buf, sizeof (buf), literal) == 0)
4382 4521 if (strlen(buf) > entry->pl_recvd_width)
4383 4522 entry->pl_recvd_width = strlen(buf);
4384 4523 }
4385 4524 }
4386 4525
4387 4526 return (0);
4388 4527 }
4389 4528
4390 4529 int
4391 4530 zfs_deleg_share_nfs(libzfs_handle_t *hdl, char *dataset, char *path,
4392 4531 char *resource, void *export, void *sharetab,
4393 4532 int sharemax, zfs_share_op_t operation)
4394 4533 {
4395 4534 zfs_cmd_t zc = { 0 };
4396 4535 int error;
4397 4536
4398 4537 (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
4399 4538 (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value));
4400 4539 if (resource)
4401 4540 (void) strlcpy(zc.zc_string, resource, sizeof (zc.zc_string));
4402 4541 zc.zc_share.z_sharedata = (uint64_t)(uintptr_t)sharetab;
4403 4542 zc.zc_share.z_exportdata = (uint64_t)(uintptr_t)export;
4404 4543 zc.zc_share.z_sharetype = operation;
4405 4544 zc.zc_share.z_sharemax = sharemax;
4406 4545 error = ioctl(hdl->libzfs_fd, ZFS_IOC_SHARE, &zc);
4407 4546 return (error);
4408 4547 }
4409 4548
4410 4549 void
4411 4550 zfs_prune_proplist(zfs_handle_t *zhp, uint8_t *props)
4412 4551 {
4413 4552 nvpair_t *curr;
4414 4553
4415 4554 /*
4416 4555 * Keep a reference to the props-table against which we prune the
4417 4556 * properties.
4418 4557 */
4419 4558 zhp->zfs_props_table = props;
4420 4559
4421 4560 curr = nvlist_next_nvpair(zhp->zfs_props, NULL);
4422 4561
4423 4562 while (curr) {
4424 4563 zfs_prop_t zfs_prop = zfs_name_to_prop(nvpair_name(curr));
4425 4564 nvpair_t *next = nvlist_next_nvpair(zhp->zfs_props, curr);
4426 4565
4427 4566 /*
4428 4567 * User properties will result in ZPROP_INVAL, and since we
4429 4568 * only know how to prune standard ZFS properties, we always
4430 4569 * leave these in the list. This can also happen if we
4431 4570 * encounter an unknown DSL property (when running older
4432 4571 * software, for example).
4433 4572 */
4434 4573 if (zfs_prop != ZPROP_INVAL && props[zfs_prop] == B_FALSE)
4435 4574 (void) nvlist_remove(zhp->zfs_props,
4436 4575 nvpair_name(curr), nvpair_type(curr));
4437 4576 curr = next;
4438 4577 }
4439 4578 }
4440 4579
4441 4580 static int
4442 4581 zfs_smb_acl_mgmt(libzfs_handle_t *hdl, char *dataset, char *path,
4443 4582 zfs_smb_acl_op_t cmd, char *resource1, char *resource2)
4444 4583 {
4445 4584 zfs_cmd_t zc = { 0 };
4446 4585 nvlist_t *nvlist = NULL;
4447 4586 int error;
4448 4587
4449 4588 (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
4450 4589 (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value));
4451 4590 zc.zc_cookie = (uint64_t)cmd;
4452 4591
4453 4592 if (cmd == ZFS_SMB_ACL_RENAME) {
4454 4593 if (nvlist_alloc(&nvlist, NV_UNIQUE_NAME, 0) != 0) {
4455 4594 (void) no_memory(hdl);
4456 4595 return (0);
4457 4596 }
4458 4597 }
4459 4598
4460 4599 switch (cmd) {
4461 4600 case ZFS_SMB_ACL_ADD:
4462 4601 case ZFS_SMB_ACL_REMOVE:
4463 4602 (void) strlcpy(zc.zc_string, resource1, sizeof (zc.zc_string));
4464 4603 break;
4465 4604 case ZFS_SMB_ACL_RENAME:
4466 4605 if (nvlist_add_string(nvlist, ZFS_SMB_ACL_SRC,
4467 4606 resource1) != 0) {
4468 4607 (void) no_memory(hdl);
4469 4608 return (-1);
4470 4609 }
4471 4610 if (nvlist_add_string(nvlist, ZFS_SMB_ACL_TARGET,
4472 4611 resource2) != 0) {
4473 4612 (void) no_memory(hdl);
4474 4613 return (-1);
4475 4614 }
4476 4615 if (zcmd_write_src_nvlist(hdl, &zc, nvlist) != 0) {
4477 4616 nvlist_free(nvlist);
4478 4617 return (-1);
4479 4618 }
4480 4619 break;
4481 4620 case ZFS_SMB_ACL_PURGE:
4482 4621 break;
4483 4622 default:
4484 4623 return (-1);
4485 4624 }
4486 4625 error = ioctl(hdl->libzfs_fd, ZFS_IOC_SMB_ACL, &zc);
4487 4626 nvlist_free(nvlist);
4488 4627 return (error);
4489 4628 }
4490 4629
4491 4630 int
4492 4631 zfs_smb_acl_add(libzfs_handle_t *hdl, char *dataset,
4493 4632 char *path, char *resource)
4494 4633 {
4495 4634 return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_ADD,
4496 4635 resource, NULL));
4497 4636 }
4498 4637
4499 4638 int
4500 4639 zfs_smb_acl_remove(libzfs_handle_t *hdl, char *dataset,
4501 4640 char *path, char *resource)
4502 4641 {
4503 4642 return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_REMOVE,
4504 4643 resource, NULL));
4505 4644 }
4506 4645
4507 4646 int
4508 4647 zfs_smb_acl_purge(libzfs_handle_t *hdl, char *dataset, char *path)
4509 4648 {
4510 4649 return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_PURGE,
4511 4650 NULL, NULL));
4512 4651 }
4513 4652
4514 4653 int
4515 4654 zfs_smb_acl_rename(libzfs_handle_t *hdl, char *dataset, char *path,
4516 4655 char *oldname, char *newname)
4517 4656 {
4518 4657 return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_RENAME,
4519 4658 oldname, newname));
4520 4659 }
4521 4660
4522 4661 int
4523 4662 zfs_userspace(zfs_handle_t *zhp, zfs_userquota_prop_t type,
4524 4663 zfs_userspace_cb_t func, void *arg)
4525 4664 {
4526 4665 zfs_cmd_t zc = { 0 };
4527 4666 zfs_useracct_t buf[100];
4528 4667 libzfs_handle_t *hdl = zhp->zfs_hdl;
4529 4668 int ret;
4530 4669
4531 4670 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
4532 4671
4533 4672 zc.zc_objset_type = type;
4534 4673 zc.zc_nvlist_dst = (uintptr_t)buf;
4535 4674
4536 4675 for (;;) {
4537 4676 zfs_useracct_t *zua = buf;
4538 4677
4539 4678 zc.zc_nvlist_dst_size = sizeof (buf);
4540 4679 if (zfs_ioctl(hdl, ZFS_IOC_USERSPACE_MANY, &zc) != 0) {
4541 4680 char errbuf[1024];
4542 4681
4543 4682 (void) snprintf(errbuf, sizeof (errbuf),
4544 4683 dgettext(TEXT_DOMAIN,
4545 4684 "cannot get used/quota for %s"), zc.zc_name);
4546 4685 return (zfs_standard_error_fmt(hdl, errno, errbuf));
4547 4686 }
4548 4687 if (zc.zc_nvlist_dst_size == 0)
4549 4688 break;
4550 4689
4551 4690 while (zc.zc_nvlist_dst_size > 0) {
4552 4691 if ((ret = func(arg, zua->zu_domain, zua->zu_rid,
4553 4692 zua->zu_space)) != 0)
4554 4693 return (ret);
4555 4694 zua++;
4556 4695 zc.zc_nvlist_dst_size -= sizeof (zfs_useracct_t);
4557 4696 }
4558 4697 }
4559 4698
4560 4699 return (0);
4561 4700 }
4562 4701
4563 4702 struct holdarg {
4564 4703 nvlist_t *nvl;
4565 4704 const char *snapname;
4566 4705 const char *tag;
4567 4706 boolean_t recursive;
4568 4707 int error;
4569 4708 };
4570 4709
4571 4710 static int
4572 4711 zfs_hold_one(zfs_handle_t *zhp, void *arg)
4573 4712 {
4574 4713 struct holdarg *ha = arg;
4575 4714 char name[ZFS_MAX_DATASET_NAME_LEN];
4576 4715 int rv = 0;
4577 4716
4578 4717 (void) snprintf(name, sizeof (name),
4579 4718 "%s@%s", zhp->zfs_name, ha->snapname);
4580 4719
4581 4720 if (lzc_exists(name))
4582 4721 fnvlist_add_string(ha->nvl, name, ha->tag);
4583 4722
4584 4723 if (ha->recursive)
4585 4724 rv = zfs_iter_filesystems(zhp, zfs_hold_one, ha);
4586 4725 zfs_close(zhp);
4587 4726 return (rv);
4588 4727 }
4589 4728
4590 4729 int
4591 4730 zfs_hold(zfs_handle_t *zhp, const char *snapname, const char *tag,
4592 4731 boolean_t recursive, int cleanup_fd)
4593 4732 {
4594 4733 int ret;
4595 4734 struct holdarg ha;
4596 4735
4597 4736 ha.nvl = fnvlist_alloc();
4598 4737 ha.snapname = snapname;
4599 4738 ha.tag = tag;
4600 4739 ha.recursive = recursive;
4601 4740 (void) zfs_hold_one(zfs_handle_dup(zhp), &ha);
4602 4741
4603 4742 if (nvlist_empty(ha.nvl)) {
4604 4743 char errbuf[1024];
4605 4744
4606 4745 fnvlist_free(ha.nvl);
4607 4746 ret = ENOENT;
4608 4747 (void) snprintf(errbuf, sizeof (errbuf),
4609 4748 dgettext(TEXT_DOMAIN,
4610 4749 "cannot hold snapshot '%s@%s'"),
4611 4750 zhp->zfs_name, snapname);
4612 4751 (void) zfs_standard_error(zhp->zfs_hdl, ret, errbuf);
4613 4752 return (ret);
4614 4753 }
4615 4754
4616 4755 ret = zfs_hold_nvl(zhp, cleanup_fd, ha.nvl);
4617 4756 fnvlist_free(ha.nvl);
4618 4757
4619 4758 return (ret);
4620 4759 }
4621 4760
4622 4761 int
4623 4762 zfs_hold_nvl(zfs_handle_t *zhp, int cleanup_fd, nvlist_t *holds)
4624 4763 {
4625 4764 int ret;
4626 4765 nvlist_t *errors;
4627 4766 libzfs_handle_t *hdl = zhp->zfs_hdl;
4628 4767 char errbuf[1024];
4629 4768 nvpair_t *elem;
4630 4769
4631 4770 errors = NULL;
4632 4771 ret = lzc_hold(holds, cleanup_fd, &errors);
4633 4772
4634 4773 if (ret == 0) {
4635 4774 /* There may be errors even in the success case. */
4636 4775 fnvlist_free(errors);
4637 4776 return (0);
4638 4777 }
4639 4778
4640 4779 if (nvlist_empty(errors)) {
4641 4780 /* no hold-specific errors */
4642 4781 (void) snprintf(errbuf, sizeof (errbuf),
4643 4782 dgettext(TEXT_DOMAIN, "cannot hold"));
4644 4783 switch (ret) {
4645 4784 case ENOTSUP:
4646 4785 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4647 4786 "pool must be upgraded"));
4648 4787 (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
4649 4788 break;
4650 4789 case EINVAL:
4651 4790 (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
4652 4791 break;
4653 4792 default:
4654 4793 (void) zfs_standard_error(hdl, ret, errbuf);
4655 4794 }
4656 4795 }
4657 4796
4658 4797 for (elem = nvlist_next_nvpair(errors, NULL);
4659 4798 elem != NULL;
4660 4799 elem = nvlist_next_nvpair(errors, elem)) {
4661 4800 (void) snprintf(errbuf, sizeof (errbuf),
4662 4801 dgettext(TEXT_DOMAIN,
4663 4802 "cannot hold snapshot '%s'"), nvpair_name(elem));
4664 4803 switch (fnvpair_value_int32(elem)) {
4665 4804 case E2BIG:
4666 4805 /*
4667 4806 * Temporary tags wind up having the ds object id
4668 4807 * prepended. So even if we passed the length check
4669 4808 * above, it's still possible for the tag to wind
4670 4809 * up being slightly too long.
4671 4810 */
4672 4811 (void) zfs_error(hdl, EZFS_TAGTOOLONG, errbuf);
4673 4812 break;
4674 4813 case EINVAL:
4675 4814 (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
4676 4815 break;
4677 4816 case EEXIST:
4678 4817 (void) zfs_error(hdl, EZFS_REFTAG_HOLD, errbuf);
4679 4818 break;
4680 4819 default:
4681 4820 (void) zfs_standard_error(hdl,
4682 4821 fnvpair_value_int32(elem), errbuf);
4683 4822 }
4684 4823 }
4685 4824
4686 4825 fnvlist_free(errors);
4687 4826 return (ret);
4688 4827 }
4689 4828
4690 4829 static int
4691 4830 zfs_release_one(zfs_handle_t *zhp, void *arg)
4692 4831 {
4693 4832 struct holdarg *ha = arg;
4694 4833 char name[ZFS_MAX_DATASET_NAME_LEN];
4695 4834 int rv = 0;
4696 4835 nvlist_t *existing_holds;
4697 4836
4698 4837 (void) snprintf(name, sizeof (name),
4699 4838 "%s@%s", zhp->zfs_name, ha->snapname);
4700 4839
4701 4840 if (lzc_get_holds(name, &existing_holds) != 0) {
|
↓ open down ↓ |
589 lines elided |
↑ open up ↑ |
4702 4841 ha->error = ENOENT;
4703 4842 } else if (!nvlist_exists(existing_holds, ha->tag)) {
4704 4843 ha->error = ESRCH;
4705 4844 } else {
4706 4845 nvlist_t *torelease = fnvlist_alloc();
4707 4846 fnvlist_add_boolean(torelease, ha->tag);
4708 4847 fnvlist_add_nvlist(ha->nvl, name, torelease);
4709 4848 fnvlist_free(torelease);
4710 4849 }
4711 4850
4851 + fnvlist_free(existing_holds);
4852 +
4712 4853 if (ha->recursive)
4713 4854 rv = zfs_iter_filesystems(zhp, zfs_release_one, ha);
4714 4855 zfs_close(zhp);
4715 4856 return (rv);
4716 4857 }
4717 4858
4718 4859 int
4719 4860 zfs_release(zfs_handle_t *zhp, const char *snapname, const char *tag,
4720 4861 boolean_t recursive)
4721 4862 {
4722 4863 int ret;
4723 4864 struct holdarg ha;
4724 4865 nvlist_t *errors = NULL;
4725 4866 nvpair_t *elem;
4726 4867 libzfs_handle_t *hdl = zhp->zfs_hdl;
4727 4868 char errbuf[1024];
4728 4869
4729 4870 ha.nvl = fnvlist_alloc();
4730 4871 ha.snapname = snapname;
4731 4872 ha.tag = tag;
4732 4873 ha.recursive = recursive;
4733 4874 ha.error = 0;
4734 4875 (void) zfs_release_one(zfs_handle_dup(zhp), &ha);
4735 4876
4736 4877 if (nvlist_empty(ha.nvl)) {
4737 4878 fnvlist_free(ha.nvl);
4738 4879 ret = ha.error;
4739 4880 (void) snprintf(errbuf, sizeof (errbuf),
4740 4881 dgettext(TEXT_DOMAIN,
4741 4882 "cannot release hold from snapshot '%s@%s'"),
4742 4883 zhp->zfs_name, snapname);
4743 4884 if (ret == ESRCH) {
4744 4885 (void) zfs_error(hdl, EZFS_REFTAG_RELE, errbuf);
4745 4886 } else {
4746 4887 (void) zfs_standard_error(hdl, ret, errbuf);
4747 4888 }
4748 4889 return (ret);
4749 4890 }
4750 4891
4751 4892 ret = lzc_release(ha.nvl, &errors);
4752 4893 fnvlist_free(ha.nvl);
4753 4894
4754 4895 if (ret == 0) {
4755 4896 /* There may be errors even in the success case. */
4756 4897 fnvlist_free(errors);
4757 4898 return (0);
4758 4899 }
4759 4900
4760 4901 if (nvlist_empty(errors)) {
4761 4902 /* no hold-specific errors */
4762 4903 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
4763 4904 "cannot release"));
4764 4905 switch (errno) {
4765 4906 case ENOTSUP:
4766 4907 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4767 4908 "pool must be upgraded"));
4768 4909 (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
4769 4910 break;
4770 4911 default:
4771 4912 (void) zfs_standard_error_fmt(hdl, errno, errbuf);
4772 4913 }
4773 4914 }
4774 4915
4775 4916 for (elem = nvlist_next_nvpair(errors, NULL);
4776 4917 elem != NULL;
4777 4918 elem = nvlist_next_nvpair(errors, elem)) {
4778 4919 (void) snprintf(errbuf, sizeof (errbuf),
4779 4920 dgettext(TEXT_DOMAIN,
4780 4921 "cannot release hold from snapshot '%s'"),
4781 4922 nvpair_name(elem));
4782 4923 switch (fnvpair_value_int32(elem)) {
4783 4924 case ESRCH:
4784 4925 (void) zfs_error(hdl, EZFS_REFTAG_RELE, errbuf);
4785 4926 break;
4786 4927 case EINVAL:
4787 4928 (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
4788 4929 break;
4789 4930 default:
4790 4931 (void) zfs_standard_error_fmt(hdl,
4791 4932 fnvpair_value_int32(elem), errbuf);
4792 4933 }
4793 4934 }
4794 4935
4795 4936 fnvlist_free(errors);
4796 4937 return (ret);
4797 4938 }
4798 4939
4799 4940 int
4800 4941 zfs_get_fsacl(zfs_handle_t *zhp, nvlist_t **nvl)
4801 4942 {
4802 4943 zfs_cmd_t zc = { 0 };
4803 4944 libzfs_handle_t *hdl = zhp->zfs_hdl;
4804 4945 int nvsz = 2048;
4805 4946 void *nvbuf;
4806 4947 int err = 0;
4807 4948 char errbuf[1024];
4808 4949
4809 4950 assert(zhp->zfs_type == ZFS_TYPE_VOLUME ||
4810 4951 zhp->zfs_type == ZFS_TYPE_FILESYSTEM);
4811 4952
4812 4953 tryagain:
4813 4954
4814 4955 nvbuf = malloc(nvsz);
4815 4956 if (nvbuf == NULL) {
4816 4957 err = (zfs_error(hdl, EZFS_NOMEM, strerror(errno)));
4817 4958 goto out;
4818 4959 }
4819 4960
4820 4961 zc.zc_nvlist_dst_size = nvsz;
4821 4962 zc.zc_nvlist_dst = (uintptr_t)nvbuf;
4822 4963
4823 4964 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
4824 4965
4825 4966 if (ioctl(hdl->libzfs_fd, ZFS_IOC_GET_FSACL, &zc) != 0) {
4826 4967 (void) snprintf(errbuf, sizeof (errbuf),
4827 4968 dgettext(TEXT_DOMAIN, "cannot get permissions on '%s'"),
4828 4969 zc.zc_name);
4829 4970 switch (errno) {
4830 4971 case ENOMEM:
4831 4972 free(nvbuf);
4832 4973 nvsz = zc.zc_nvlist_dst_size;
4833 4974 goto tryagain;
4834 4975
4835 4976 case ENOTSUP:
4836 4977 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4837 4978 "pool must be upgraded"));
4838 4979 err = zfs_error(hdl, EZFS_BADVERSION, errbuf);
4839 4980 break;
4840 4981 case EINVAL:
4841 4982 err = zfs_error(hdl, EZFS_BADTYPE, errbuf);
4842 4983 break;
4843 4984 case ENOENT:
4844 4985 err = zfs_error(hdl, EZFS_NOENT, errbuf);
4845 4986 break;
4846 4987 default:
4847 4988 err = zfs_standard_error_fmt(hdl, errno, errbuf);
4848 4989 break;
4849 4990 }
4850 4991 } else {
4851 4992 /* success */
4852 4993 int rc = nvlist_unpack(nvbuf, zc.zc_nvlist_dst_size, nvl, 0);
4853 4994 if (rc) {
4854 4995 (void) snprintf(errbuf, sizeof (errbuf), dgettext(
4855 4996 TEXT_DOMAIN, "cannot get permissions on '%s'"),
4856 4997 zc.zc_name);
4857 4998 err = zfs_standard_error_fmt(hdl, rc, errbuf);
4858 4999 }
4859 5000 }
4860 5001
4861 5002 free(nvbuf);
4862 5003 out:
4863 5004 return (err);
4864 5005 }
4865 5006
4866 5007 int
4867 5008 zfs_set_fsacl(zfs_handle_t *zhp, boolean_t un, nvlist_t *nvl)
4868 5009 {
4869 5010 zfs_cmd_t zc = { 0 };
4870 5011 libzfs_handle_t *hdl = zhp->zfs_hdl;
4871 5012 char *nvbuf;
4872 5013 char errbuf[1024];
4873 5014 size_t nvsz;
4874 5015 int err;
4875 5016
4876 5017 assert(zhp->zfs_type == ZFS_TYPE_VOLUME ||
4877 5018 zhp->zfs_type == ZFS_TYPE_FILESYSTEM);
4878 5019
4879 5020 err = nvlist_size(nvl, &nvsz, NV_ENCODE_NATIVE);
4880 5021 assert(err == 0);
4881 5022
4882 5023 nvbuf = malloc(nvsz);
4883 5024
4884 5025 err = nvlist_pack(nvl, &nvbuf, &nvsz, NV_ENCODE_NATIVE, 0);
4885 5026 assert(err == 0);
4886 5027
4887 5028 zc.zc_nvlist_src_size = nvsz;
4888 5029 zc.zc_nvlist_src = (uintptr_t)nvbuf;
4889 5030 zc.zc_perm_action = un;
4890 5031
4891 5032 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
4892 5033
4893 5034 if (zfs_ioctl(hdl, ZFS_IOC_SET_FSACL, &zc) != 0) {
4894 5035 (void) snprintf(errbuf, sizeof (errbuf),
4895 5036 dgettext(TEXT_DOMAIN, "cannot set permissions on '%s'"),
4896 5037 zc.zc_name);
4897 5038 switch (errno) {
4898 5039 case ENOTSUP:
4899 5040 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4900 5041 "pool must be upgraded"));
4901 5042 err = zfs_error(hdl, EZFS_BADVERSION, errbuf);
4902 5043 break;
4903 5044 case EINVAL:
4904 5045 err = zfs_error(hdl, EZFS_BADTYPE, errbuf);
4905 5046 break;
4906 5047 case ENOENT:
4907 5048 err = zfs_error(hdl, EZFS_NOENT, errbuf);
4908 5049 break;
4909 5050 default:
4910 5051 err = zfs_standard_error_fmt(hdl, errno, errbuf);
4911 5052 break;
4912 5053 }
4913 5054 }
4914 5055
4915 5056 free(nvbuf);
4916 5057
4917 5058 return (err);
4918 5059 }
4919 5060
4920 5061 int
4921 5062 zfs_get_holds(zfs_handle_t *zhp, nvlist_t **nvl)
4922 5063 {
4923 5064 int err;
4924 5065 char errbuf[1024];
4925 5066
4926 5067 err = lzc_get_holds(zhp->zfs_name, nvl);
4927 5068
4928 5069 if (err != 0) {
4929 5070 libzfs_handle_t *hdl = zhp->zfs_hdl;
4930 5071
4931 5072 (void) snprintf(errbuf, sizeof (errbuf),
4932 5073 dgettext(TEXT_DOMAIN, "cannot get holds for '%s'"),
4933 5074 zhp->zfs_name);
4934 5075 switch (err) {
4935 5076 case ENOTSUP:
4936 5077 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4937 5078 "pool must be upgraded"));
4938 5079 err = zfs_error(hdl, EZFS_BADVERSION, errbuf);
4939 5080 break;
4940 5081 case EINVAL:
4941 5082 err = zfs_error(hdl, EZFS_BADTYPE, errbuf);
4942 5083 break;
4943 5084 case ENOENT:
4944 5085 err = zfs_error(hdl, EZFS_NOENT, errbuf);
4945 5086 break;
4946 5087 default:
4947 5088 err = zfs_standard_error_fmt(hdl, errno, errbuf);
4948 5089 break;
4949 5090 }
4950 5091 }
4951 5092
4952 5093 return (err);
4953 5094 }
4954 5095
4955 5096 /*
4956 5097 * Convert the zvol's volume size to an appropriate reservation.
4957 5098 * Note: If this routine is updated, it is necessary to update the ZFS test
4958 5099 * suite's shell version in reservation.kshlib.
4959 5100 */
4960 5101 uint64_t
4961 5102 zvol_volsize_to_reservation(uint64_t volsize, nvlist_t *props)
4962 5103 {
4963 5104 uint64_t numdb;
4964 5105 uint64_t nblocks, volblocksize;
4965 5106 int ncopies;
4966 5107 char *strval;
4967 5108
4968 5109 if (nvlist_lookup_string(props,
4969 5110 zfs_prop_to_name(ZFS_PROP_COPIES), &strval) == 0)
4970 5111 ncopies = atoi(strval);
4971 5112 else
4972 5113 ncopies = 1;
4973 5114 if (nvlist_lookup_uint64(props,
4974 5115 zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
4975 5116 &volblocksize) != 0)
4976 5117 volblocksize = ZVOL_DEFAULT_BLOCKSIZE;
4977 5118 nblocks = volsize/volblocksize;
4978 5119 /* start with metadnode L0-L6 */
4979 5120 numdb = 7;
4980 5121 /* calculate number of indirects */
4981 5122 while (nblocks > 1) {
4982 5123 nblocks += DNODES_PER_LEVEL - 1;
4983 5124 nblocks /= DNODES_PER_LEVEL;
4984 5125 numdb += nblocks;
4985 5126 }
4986 5127 numdb *= MIN(SPA_DVAS_PER_BP, ncopies + 1);
4987 5128 volsize *= ncopies;
4988 5129 /*
4989 5130 * this is exactly DN_MAX_INDBLKSHIFT when metadata isn't
4990 5131 * compressed, but in practice they compress down to about
4991 5132 * 1100 bytes
4992 5133 */
4993 5134 numdb *= 1ULL << DN_MAX_INDBLKSHIFT;
4994 5135 volsize += numdb;
4995 5136 return (volsize);
4996 5137 }
|
↓ open down ↓ |
275 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX