Print this page
NEX-16623 Ability to set properties for multiple datasets/snapshots during single sync-round
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-7822 40Gb Intel XL710 NIC performance data
Reviewed by: Steve Peng <steve.peng@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-8827 AUTOSNAP: can't register recursive zone when there is a child under autosnappool/volumegrou
Reviewed by: Alex Deiter <alex.deiter@nexenta.com>
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-5987 need to change ssm wearout threshold to 90%
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Gordon Ross <gwr@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-5925 KRRP: Incorrect collecting of snap-props causes errors during recv
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Alexey Komarov <alexey.komarov@nexenta.com>
Reviewed by: Alex Aizman <alex.aizman@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-5341 Race condition causes wrc_004_pos to panic the system
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
NEX-5319 Panic trying to rename zvol used as COMSTAR lu
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Alex Aizman <alex.aizman@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-4934 Add capability to remove special vdev
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
Reviewed by: Alek Pinchuk <alek.pinchuk@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>
NEX-4608 WRC: Possible deadlock during the disabling of WRC for a dataset
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
6160 /usr/lib/fs/zfs/bootinstall should use bootadm
Reviewed by: Igor Kozhukhov <ikozhukhov@gmail.com>
Reviewed by: Adam Števko <adam.stevko@gmail.com>
Reviewed by: Josef Sipek <jeffpc@josefsipek.net>
Approved by: Richard Lowe <richlowe@richlowe.net>
4185 add new cryptographic checksums to ZFS: SHA-512, Skein, Edon-R (NULL is not an int)
6171 dsl_prop_unregister() slows down dataset eviction.
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: Prakash Surya <prakash.surya@delphix.com>
Approved by: Dan McDonald <danmcd@omniti.com>
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>
Remaining fixes for the illumos merge
re #12619 rb4429 More dp->dp_config_rwlock holds
re #13253 rb4328 ssh: openssl version checking needs updating
re #11441 rb4292 panic in apic_record_rdt_entry on VMware hardware version 9
re #12619, rb4287 Deadlocked zfs txg processing in dsl_sync_task_group_sync()
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/fs/zfs/dsl_prop.c
+++ new/usr/src/uts/common/fs/zfs/dsl_prop.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
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
|
↓ open down ↓ |
15 lines elided |
↑ open up ↑ |
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 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23 23 * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
24 24 * Copyright (c) 2013 Martin Matuska. All rights reserved.
25 25 * Copyright 2015, Joyent, Inc.
26 + * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
26 27 */
27 28
28 29 #include <sys/zfs_context.h>
29 30 #include <sys/dmu.h>
30 31 #include <sys/dmu_objset.h>
31 32 #include <sys/dmu_tx.h>
32 33 #include <sys/dsl_dataset.h>
33 34 #include <sys/dsl_dir.h>
34 35 #include <sys/dsl_prop.h>
35 36 #include <sys/dsl_synctask.h>
37 +#include <sys/zfeature.h>
36 38 #include <sys/spa.h>
37 39 #include <sys/zap.h>
38 40 #include <sys/fs/zfs.h>
41 +#include <sys/wbc.h>
39 42
40 43 #include "zfs_prop.h"
44 +#include "zfs_errno.h"
41 45
42 -#define ZPROP_INHERIT_SUFFIX "$inherit"
43 -#define ZPROP_RECVD_SUFFIX "$recvd"
44 -
45 46 static int
46 47 dodefault(zfs_prop_t prop, int intsz, int numints, void *buf)
47 48 {
48 49 /*
49 50 * The setonce properties are read-only, BUT they still
50 51 * have a default value that can be used as the initial
51 52 * value.
52 53 */
53 54 if (prop == ZPROP_INVAL ||
54 55 (zfs_prop_readonly(prop) && !zfs_prop_setonce(prop)))
55 56 return (SET_ERROR(ENOENT));
56 57
57 58 if (zfs_prop_get_type(prop) == PROP_TYPE_STRING) {
58 59 if (intsz != 1)
59 60 return (SET_ERROR(EOVERFLOW));
60 61 (void) strncpy(buf, zfs_prop_default_string(prop),
61 62 numints);
62 63 } else {
63 64 if (intsz != 8 || numints < 1)
64 65 return (SET_ERROR(EOVERFLOW));
65 66
66 67 *(uint64_t *)buf = zfs_prop_default_numeric(prop);
67 68 }
68 69
69 70 return (0);
70 71 }
71 72
72 73 int
73 74 dsl_prop_get_dd(dsl_dir_t *dd, const char *propname,
74 75 int intsz, int numints, void *buf, char *setpoint, boolean_t snapshot)
75 76 {
76 77 int err = ENOENT;
77 78 dsl_dir_t *target = dd;
78 79 objset_t *mos = dd->dd_pool->dp_meta_objset;
79 80 zfs_prop_t prop;
80 81 boolean_t inheritable;
81 82 boolean_t inheriting = B_FALSE;
82 83 char *inheritstr;
83 84 char *recvdstr;
84 85
85 86 ASSERT(dsl_pool_config_held(dd->dd_pool));
86 87
87 88 if (setpoint)
88 89 setpoint[0] = '\0';
89 90
90 91 prop = zfs_name_to_prop(propname);
91 92 inheritable = (prop == ZPROP_INVAL || zfs_prop_inheritable(prop));
92 93 inheritstr = kmem_asprintf("%s%s", propname, ZPROP_INHERIT_SUFFIX);
93 94 recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX);
94 95
95 96 /*
96 97 * Note: dd may become NULL, therefore we shouldn't dereference it
97 98 * after this loop.
98 99 */
99 100 for (; dd != NULL; dd = dd->dd_parent) {
100 101 if (dd != target || snapshot) {
101 102 if (!inheritable)
102 103 break;
103 104 inheriting = B_TRUE;
104 105 }
105 106
106 107 /* Check for a local value. */
107 108 err = zap_lookup(mos, dsl_dir_phys(dd)->dd_props_zapobj,
108 109 propname, intsz, numints, buf);
109 110 if (err != ENOENT) {
110 111 if (setpoint != NULL && err == 0)
111 112 dsl_dir_name(dd, setpoint);
112 113 break;
113 114 }
114 115
115 116 /*
116 117 * Skip the check for a received value if there is an explicit
117 118 * inheritance entry.
118 119 */
119 120 err = zap_contains(mos, dsl_dir_phys(dd)->dd_props_zapobj,
120 121 inheritstr);
121 122 if (err != 0 && err != ENOENT)
122 123 break;
123 124
124 125 if (err == ENOENT) {
125 126 /* Check for a received value. */
126 127 err = zap_lookup(mos, dsl_dir_phys(dd)->dd_props_zapobj,
127 128 recvdstr, intsz, numints, buf);
128 129 if (err != ENOENT) {
129 130 if (setpoint != NULL && err == 0) {
130 131 if (inheriting) {
131 132 dsl_dir_name(dd, setpoint);
132 133 } else {
133 134 (void) strcpy(setpoint,
134 135 ZPROP_SOURCE_VAL_RECVD);
135 136 }
136 137 }
137 138 break;
138 139 }
139 140 }
140 141
141 142 /*
142 143 * If we found an explicit inheritance entry, err is zero even
143 144 * though we haven't yet found the value, so reinitializing err
144 145 * at the end of the loop (instead of at the beginning) ensures
145 146 * that err has a valid post-loop value.
146 147 */
147 148 err = SET_ERROR(ENOENT);
148 149 }
149 150
150 151 if (err == ENOENT)
151 152 err = dodefault(prop, intsz, numints, buf);
152 153
153 154 strfree(inheritstr);
154 155 strfree(recvdstr);
155 156
156 157 return (err);
157 158 }
158 159
159 160 int
160 161 dsl_prop_get_ds(dsl_dataset_t *ds, const char *propname,
161 162 int intsz, int numints, void *buf, char *setpoint)
162 163 {
163 164 zfs_prop_t prop = zfs_name_to_prop(propname);
164 165 boolean_t inheritable;
165 166 uint64_t zapobj;
166 167
167 168 ASSERT(dsl_pool_config_held(ds->ds_dir->dd_pool));
168 169 inheritable = (prop == ZPROP_INVAL || zfs_prop_inheritable(prop));
169 170 zapobj = dsl_dataset_phys(ds)->ds_props_obj;
170 171
171 172 if (zapobj != 0) {
172 173 objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
173 174 int err;
174 175
175 176 ASSERT(ds->ds_is_snapshot);
176 177
177 178 /* Check for a local value. */
178 179 err = zap_lookup(mos, zapobj, propname, intsz, numints, buf);
179 180 if (err != ENOENT) {
180 181 if (setpoint != NULL && err == 0)
181 182 dsl_dataset_name(ds, setpoint);
182 183 return (err);
183 184 }
184 185
185 186 /*
186 187 * Skip the check for a received value if there is an explicit
187 188 * inheritance entry.
188 189 */
189 190 if (inheritable) {
190 191 char *inheritstr = kmem_asprintf("%s%s", propname,
191 192 ZPROP_INHERIT_SUFFIX);
192 193 err = zap_contains(mos, zapobj, inheritstr);
193 194 strfree(inheritstr);
194 195 if (err != 0 && err != ENOENT)
195 196 return (err);
196 197 }
197 198
198 199 if (err == ENOENT) {
199 200 /* Check for a received value. */
200 201 char *recvdstr = kmem_asprintf("%s%s", propname,
201 202 ZPROP_RECVD_SUFFIX);
202 203 err = zap_lookup(mos, zapobj, recvdstr,
203 204 intsz, numints, buf);
204 205 strfree(recvdstr);
205 206 if (err != ENOENT) {
206 207 if (setpoint != NULL && err == 0)
207 208 (void) strcpy(setpoint,
208 209 ZPROP_SOURCE_VAL_RECVD);
209 210 return (err);
210 211 }
211 212 }
212 213 }
213 214
214 215 return (dsl_prop_get_dd(ds->ds_dir, propname,
215 216 intsz, numints, buf, setpoint, ds->ds_is_snapshot));
216 217 }
217 218
218 219 static dsl_prop_record_t *
219 220 dsl_prop_record_find(dsl_dir_t *dd, const char *propname)
220 221 {
221 222 dsl_prop_record_t *pr = NULL;
222 223
223 224 ASSERT(MUTEX_HELD(&dd->dd_lock));
224 225
225 226 for (pr = list_head(&dd->dd_props);
226 227 pr != NULL; pr = list_next(&dd->dd_props, pr)) {
227 228 if (strcmp(pr->pr_propname, propname) == 0)
228 229 break;
229 230 }
230 231
231 232 return (pr);
232 233 }
233 234
234 235 static dsl_prop_record_t *
235 236 dsl_prop_record_create(dsl_dir_t *dd, const char *propname)
236 237 {
237 238 dsl_prop_record_t *pr;
238 239
239 240 ASSERT(MUTEX_HELD(&dd->dd_lock));
240 241
241 242 pr = kmem_alloc(sizeof (dsl_prop_record_t), KM_SLEEP);
242 243 pr->pr_propname = spa_strdup(propname);
243 244 list_create(&pr->pr_cbs, sizeof (dsl_prop_cb_record_t),
244 245 offsetof(dsl_prop_cb_record_t, cbr_pr_node));
245 246 list_insert_head(&dd->dd_props, pr);
246 247
247 248 return (pr);
248 249 }
249 250
250 251 void
251 252 dsl_prop_init(dsl_dir_t *dd)
252 253 {
253 254 list_create(&dd->dd_props, sizeof (dsl_prop_record_t),
254 255 offsetof(dsl_prop_record_t, pr_node));
255 256 }
256 257
257 258 void
258 259 dsl_prop_fini(dsl_dir_t *dd)
259 260 {
260 261 dsl_prop_record_t *pr;
261 262
262 263 while ((pr = list_remove_head(&dd->dd_props)) != NULL) {
263 264 list_destroy(&pr->pr_cbs);
264 265 strfree((char *)pr->pr_propname);
265 266 kmem_free(pr, sizeof (dsl_prop_record_t));
266 267 }
267 268 list_destroy(&dd->dd_props);
268 269 }
269 270
270 271 /*
271 272 * Register interest in the named property. We'll call the callback
272 273 * once to notify it of the current property value, and again each time
273 274 * the property changes, until this callback is unregistered.
274 275 *
275 276 * Return 0 on success, errno if the prop is not an integer value.
276 277 */
277 278 int
278 279 dsl_prop_register(dsl_dataset_t *ds, const char *propname,
279 280 dsl_prop_changed_cb_t *callback, void *cbarg)
|
↓ open down ↓ |
225 lines elided |
↑ open up ↑ |
280 281 {
281 282 dsl_dir_t *dd = ds->ds_dir;
282 283 dsl_pool_t *dp = dd->dd_pool;
283 284 uint64_t value;
284 285 dsl_prop_record_t *pr;
285 286 dsl_prop_cb_record_t *cbr;
286 287 int err;
287 288
288 289 ASSERT(dsl_pool_config_held(dp));
289 290
290 - err = dsl_prop_get_int_ds(ds, propname, &value);
291 + if (zfs_name_to_prop(propname) == ZFS_PROP_WBC_MODE) {
292 + wbc_mode_prop_val_t val;
293 +
294 + err = dsl_prop_get_ds(ds, propname, 8,
295 + WBC_MODE_PROP_VAL_SZ, &val, NULL);
296 + if (err == 0)
297 + value = (uintptr_t)((void *)&val);
298 + } else
299 + err = dsl_prop_get_int_ds(ds, propname, &value);
300 +
291 301 if (err != 0)
292 302 return (err);
293 303
294 304 cbr = kmem_alloc(sizeof (dsl_prop_cb_record_t), KM_SLEEP);
295 305 cbr->cbr_ds = ds;
296 306 cbr->cbr_func = callback;
297 307 cbr->cbr_arg = cbarg;
298 308
299 309 mutex_enter(&dd->dd_lock);
300 310 pr = dsl_prop_record_find(dd, propname);
301 311 if (pr == NULL)
302 312 pr = dsl_prop_record_create(dd, propname);
303 313 cbr->cbr_pr = pr;
304 314 list_insert_head(&pr->pr_cbs, cbr);
305 315 list_insert_head(&ds->ds_prop_cbs, cbr);
306 316 mutex_exit(&dd->dd_lock);
307 317
308 318 cbr->cbr_func(cbr->cbr_arg, value);
309 319 return (0);
310 320 }
311 321
312 322 int
313 323 dsl_prop_get(const char *dsname, const char *propname,
314 324 int intsz, int numints, void *buf, char *setpoint)
315 325 {
316 326 objset_t *os;
317 327 int error;
318 328
319 329 error = dmu_objset_hold(dsname, FTAG, &os);
320 330 if (error != 0)
321 331 return (error);
322 332
323 333 error = dsl_prop_get_ds(dmu_objset_ds(os), propname,
324 334 intsz, numints, buf, setpoint);
325 335
326 336 dmu_objset_rele(os, FTAG);
327 337 return (error);
328 338 }
329 339
330 340 /*
331 341 * Get the current property value. It may have changed by the time this
332 342 * function returns, so it is NOT safe to follow up with
333 343 * dsl_prop_register() and assume that the value has not changed in
334 344 * between.
335 345 *
336 346 * Return 0 on success, ENOENT if ddname is invalid.
337 347 */
338 348 int
339 349 dsl_prop_get_integer(const char *ddname, const char *propname,
340 350 uint64_t *valuep, char *setpoint)
341 351 {
342 352 return (dsl_prop_get(ddname, propname, 8, 1, valuep, setpoint));
343 353 }
344 354
345 355 int
346 356 dsl_prop_get_int_ds(dsl_dataset_t *ds, const char *propname,
347 357 uint64_t *valuep)
348 358 {
349 359 return (dsl_prop_get_ds(ds, propname, 8, 1, valuep, NULL));
350 360 }
351 361
352 362 /*
353 363 * Predict the effective value of the given special property if it were set with
354 364 * the given value and source. This is not a general purpose function. It exists
355 365 * only to handle the special requirements of the quota and reservation
356 366 * properties. The fact that these properties are non-inheritable greatly
357 367 * simplifies the prediction logic.
358 368 *
359 369 * Returns 0 on success, a positive error code on failure, or -1 if called with
360 370 * a property not handled by this function.
361 371 */
362 372 int
363 373 dsl_prop_predict(dsl_dir_t *dd, const char *propname,
364 374 zprop_source_t source, uint64_t value, uint64_t *newvalp)
365 375 {
366 376 zfs_prop_t prop = zfs_name_to_prop(propname);
367 377 objset_t *mos;
368 378 uint64_t zapobj;
369 379 uint64_t version;
370 380 char *recvdstr;
371 381 int err = 0;
372 382
373 383 switch (prop) {
374 384 case ZFS_PROP_QUOTA:
375 385 case ZFS_PROP_RESERVATION:
376 386 case ZFS_PROP_REFQUOTA:
377 387 case ZFS_PROP_REFRESERVATION:
378 388 break;
379 389 default:
380 390 return (-1);
381 391 }
382 392
383 393 mos = dd->dd_pool->dp_meta_objset;
384 394 zapobj = dsl_dir_phys(dd)->dd_props_zapobj;
385 395 recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX);
386 396
387 397 version = spa_version(dd->dd_pool->dp_spa);
388 398 if (version < SPA_VERSION_RECVD_PROPS) {
389 399 if (source & ZPROP_SRC_NONE)
390 400 source = ZPROP_SRC_NONE;
391 401 else if (source & ZPROP_SRC_RECEIVED)
392 402 source = ZPROP_SRC_LOCAL;
393 403 }
394 404
395 405 switch (source) {
396 406 case ZPROP_SRC_NONE:
397 407 /* Revert to the received value, if any. */
398 408 err = zap_lookup(mos, zapobj, recvdstr, 8, 1, newvalp);
399 409 if (err == ENOENT)
400 410 *newvalp = 0;
401 411 break;
402 412 case ZPROP_SRC_LOCAL:
403 413 *newvalp = value;
404 414 break;
405 415 case ZPROP_SRC_RECEIVED:
406 416 /*
407 417 * If there's no local setting, then the new received value will
408 418 * be the effective value.
409 419 */
410 420 err = zap_lookup(mos, zapobj, propname, 8, 1, newvalp);
411 421 if (err == ENOENT)
412 422 *newvalp = value;
413 423 break;
414 424 case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED):
415 425 /*
416 426 * We're clearing the received value, so the local setting (if
417 427 * it exists) remains the effective value.
418 428 */
419 429 err = zap_lookup(mos, zapobj, propname, 8, 1, newvalp);
420 430 if (err == ENOENT)
421 431 *newvalp = 0;
422 432 break;
423 433 default:
424 434 panic("unexpected property source: %d", source);
425 435 }
426 436
427 437 strfree(recvdstr);
428 438
429 439 if (err == ENOENT)
430 440 return (0);
431 441
432 442 return (err);
433 443 }
434 444
435 445 /*
436 446 * Unregister all callbacks that are registered with the
437 447 * given callback argument.
438 448 */
439 449 void
440 450 dsl_prop_unregister_all(dsl_dataset_t *ds, void *cbarg)
441 451 {
442 452 dsl_prop_cb_record_t *cbr, *next_cbr;
443 453
444 454 dsl_dir_t *dd = ds->ds_dir;
445 455
446 456 mutex_enter(&dd->dd_lock);
447 457 next_cbr = list_head(&ds->ds_prop_cbs);
448 458 while (next_cbr != NULL) {
449 459 cbr = next_cbr;
450 460 next_cbr = list_next(&ds->ds_prop_cbs, cbr);
451 461 if (cbr->cbr_arg == cbarg) {
452 462 list_remove(&ds->ds_prop_cbs, cbr);
453 463 list_remove(&cbr->cbr_pr->pr_cbs, cbr);
454 464 kmem_free(cbr, sizeof (dsl_prop_cb_record_t));
455 465 }
456 466 }
457 467 mutex_exit(&dd->dd_lock);
458 468 }
459 469
460 470 boolean_t
461 471 dsl_prop_hascb(dsl_dataset_t *ds)
462 472 {
463 473 return (!list_is_empty(&ds->ds_prop_cbs));
464 474 }
465 475
466 476 /* ARGSUSED */
467 477 static int
468 478 dsl_prop_notify_all_cb(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg)
469 479 {
|
↓ open down ↓ |
169 lines elided |
↑ open up ↑ |
470 480 dsl_dir_t *dd = ds->ds_dir;
471 481 dsl_prop_record_t *pr;
472 482 dsl_prop_cb_record_t *cbr;
473 483
474 484 mutex_enter(&dd->dd_lock);
475 485 for (pr = list_head(&dd->dd_props);
476 486 pr; pr = list_next(&dd->dd_props, pr)) {
477 487 for (cbr = list_head(&pr->pr_cbs); cbr;
478 488 cbr = list_next(&pr->pr_cbs, cbr)) {
479 489 uint64_t value;
490 + const char *propname;
480 491
481 492 /*
482 493 * Callback entries do not have holds on their
483 494 * datasets so that datasets with registered
484 495 * callbacks are still eligible for eviction.
485 496 * Unlike operations to update properties on a
486 497 * single dataset, we are performing a recursive
487 498 * descent of related head datasets. The caller
488 499 * of this function only has a dataset hold on
489 500 * the passed in head dataset, not the snapshots
490 501 * associated with this dataset. Without a hold,
491 502 * the dataset pointer within callback records
492 503 * for snapshots can be invalidated by eviction
493 504 * at any time.
494 505 *
495 506 * Use dsl_dataset_try_add_ref() to verify
496 507 * that the dataset for a snapshot has not
|
↓ open down ↓ |
7 lines elided |
↑ open up ↑ |
497 508 * begun eviction processing and to prevent
498 509 * eviction from occurring for the duration of
499 510 * the callback. If the hold attempt fails,
500 511 * this object is already being evicted and the
501 512 * callback can be safely ignored.
502 513 */
503 514 if (ds != cbr->cbr_ds &&
504 515 !dsl_dataset_try_add_ref(dp, cbr->cbr_ds, FTAG))
505 516 continue;
506 517
507 - if (dsl_prop_get_ds(cbr->cbr_ds,
508 - cbr->cbr_pr->pr_propname, sizeof (value), 1,
509 - &value, NULL) == 0)
518 + propname = cbr->cbr_pr->pr_propname;
519 + if (zfs_name_to_prop(propname) == ZFS_PROP_WBC_MODE) {
520 + wbc_mode_prop_val_t val;
521 +
522 + if (dsl_prop_get_ds(cbr->cbr_ds, propname, 8,
523 + WBC_MODE_PROP_VAL_SZ, &val, NULL) == 0) {
524 + value = (uintptr_t)((void *)&val);
525 + cbr->cbr_func(cbr->cbr_arg, value);
526 + }
527 + } else if (dsl_prop_get_ds(cbr->cbr_ds, propname,
528 + sizeof (value), 1, &value, NULL) == 0) {
510 529 cbr->cbr_func(cbr->cbr_arg, value);
530 + }
511 531
512 532 if (ds != cbr->cbr_ds)
513 533 dsl_dataset_rele(cbr->cbr_ds, FTAG);
514 534 }
515 535 }
516 536 mutex_exit(&dd->dd_lock);
517 537
518 538 return (0);
519 539 }
520 540
521 541 /*
522 542 * Update all property values for ddobj & its descendants. This is used
523 543 * when renaming the dir.
524 544 */
525 545 void
526 546 dsl_prop_notify_all(dsl_dir_t *dd)
527 547 {
528 548 dsl_pool_t *dp = dd->dd_pool;
529 549 ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock));
530 550 (void) dmu_objset_find_dp(dp, dd->dd_object, dsl_prop_notify_all_cb,
531 551 NULL, DS_FIND_CHILDREN);
532 552 }
533 553
534 554 static void
535 555 dsl_prop_changed_notify(dsl_pool_t *dp, uint64_t ddobj,
536 556 const char *propname, uint64_t value, int first)
537 557 {
538 558 dsl_dir_t *dd;
539 559 dsl_prop_record_t *pr;
540 560 dsl_prop_cb_record_t *cbr;
541 561 objset_t *mos = dp->dp_meta_objset;
542 562 zap_cursor_t zc;
543 563 zap_attribute_t *za;
544 564 int err;
545 565
546 566 ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock));
547 567 err = dsl_dir_hold_obj(dp, ddobj, NULL, FTAG, &dd);
548 568 if (err)
549 569 return;
550 570
551 571 if (!first) {
552 572 /*
553 573 * If the prop is set here, then this change is not
554 574 * being inherited here or below; stop the recursion.
555 575 */
556 576 err = zap_contains(mos, dsl_dir_phys(dd)->dd_props_zapobj,
557 577 propname);
558 578 if (err == 0) {
559 579 dsl_dir_rele(dd, FTAG);
560 580 return;
561 581 }
562 582 ASSERT3U(err, ==, ENOENT);
563 583 }
564 584
565 585 mutex_enter(&dd->dd_lock);
566 586 pr = dsl_prop_record_find(dd, propname);
567 587 if (pr != NULL) {
568 588 for (cbr = list_head(&pr->pr_cbs); cbr;
569 589 cbr = list_next(&pr->pr_cbs, cbr)) {
570 590 uint64_t propobj;
571 591
572 592 /*
573 593 * cbr->cbr_ds may be invalidated due to eviction,
574 594 * requiring the use of dsl_dataset_try_add_ref().
575 595 * See comment block in dsl_prop_notify_all_cb()
576 596 * for details.
577 597 */
578 598 if (!dsl_dataset_try_add_ref(dp, cbr->cbr_ds, FTAG))
579 599 continue;
580 600
581 601 propobj = dsl_dataset_phys(cbr->cbr_ds)->ds_props_obj;
582 602
583 603 /*
584 604 * If the property is not set on this ds, then it is
585 605 * inherited here; call the callback.
586 606 */
587 607 if (propobj == 0 ||
588 608 zap_contains(mos, propobj, propname) != 0)
589 609 cbr->cbr_func(cbr->cbr_arg, value);
590 610
591 611 dsl_dataset_rele(cbr->cbr_ds, FTAG);
592 612 }
593 613 }
594 614 mutex_exit(&dd->dd_lock);
595 615
596 616 za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP);
597 617 for (zap_cursor_init(&zc, mos,
598 618 dsl_dir_phys(dd)->dd_child_dir_zapobj);
599 619 zap_cursor_retrieve(&zc, za) == 0;
600 620 zap_cursor_advance(&zc)) {
601 621 dsl_prop_changed_notify(dp, za->za_first_integer,
602 622 propname, value, FALSE);
603 623 }
604 624 kmem_free(za, sizeof (zap_attribute_t));
605 625 zap_cursor_fini(&zc);
606 626 dsl_dir_rele(dd, FTAG);
607 627 }
608 628
609 629 void
610 630 dsl_prop_set_sync_impl(dsl_dataset_t *ds, const char *propname,
611 631 zprop_source_t source, int intsz, int numints, const void *value,
612 632 dmu_tx_t *tx)
|
↓ open down ↓ |
92 lines elided |
↑ open up ↑ |
613 633 {
614 634 objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
615 635 uint64_t zapobj, intval, dummy;
616 636 int isint;
617 637 char valbuf[32];
618 638 const char *valstr = NULL;
619 639 char *inheritstr;
620 640 char *recvdstr;
621 641 char *tbuf = NULL;
622 642 int err;
623 - uint64_t version = spa_version(ds->ds_dir->dd_pool->dp_spa);
643 + spa_t *spa = ds->ds_dir->dd_pool->dp_spa;
644 + uint64_t version = spa_version(spa);
624 645
625 646 isint = (dodefault(zfs_name_to_prop(propname), 8, 1, &intval) == 0);
626 647
627 648 if (ds->ds_is_snapshot) {
628 649 ASSERT(version >= SPA_VERSION_SNAP_PROPS);
629 650 if (dsl_dataset_phys(ds)->ds_props_obj == 0) {
630 651 dmu_buf_will_dirty(ds->ds_dbuf, tx);
631 652 dsl_dataset_phys(ds)->ds_props_obj =
632 653 zap_create(mos,
633 654 DMU_OT_DSL_PROPS, DMU_OT_NONE, 0, tx);
634 655 }
635 656 zapobj = dsl_dataset_phys(ds)->ds_props_obj;
636 657 } else {
637 658 zapobj = dsl_dir_phys(ds->ds_dir)->dd_props_zapobj;
638 659 }
639 660
640 661 if (version < SPA_VERSION_RECVD_PROPS) {
641 662 if (source & ZPROP_SRC_NONE)
642 663 source = ZPROP_SRC_NONE;
643 664 else if (source & ZPROP_SRC_RECEIVED)
644 665 source = ZPROP_SRC_LOCAL;
645 666 }
646 667
647 668 inheritstr = kmem_asprintf("%s%s", propname, ZPROP_INHERIT_SUFFIX);
648 669 recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX);
649 670
650 671 switch (source) {
651 672 case ZPROP_SRC_NONE:
652 673 /*
653 674 * revert to received value, if any (inherit -S)
654 675 * - remove propname
655 676 * - remove propname$inherit
656 677 */
657 678 err = zap_remove(mos, zapobj, propname, tx);
658 679 ASSERT(err == 0 || err == ENOENT);
659 680 err = zap_remove(mos, zapobj, inheritstr, tx);
660 681 ASSERT(err == 0 || err == ENOENT);
661 682 break;
662 683 case ZPROP_SRC_LOCAL:
663 684 /*
664 685 * remove propname$inherit
665 686 * set propname -> value
666 687 */
667 688 err = zap_remove(mos, zapobj, inheritstr, tx);
668 689 ASSERT(err == 0 || err == ENOENT);
669 690 VERIFY0(zap_update(mos, zapobj, propname,
670 691 intsz, numints, value, tx));
671 692 break;
672 693 case ZPROP_SRC_INHERITED:
673 694 /*
674 695 * explicitly inherit
675 696 * - remove propname
676 697 * - set propname$inherit
677 698 */
678 699 err = zap_remove(mos, zapobj, propname, tx);
679 700 ASSERT(err == 0 || err == ENOENT);
680 701 if (version >= SPA_VERSION_RECVD_PROPS &&
681 702 dsl_prop_get_int_ds(ds, ZPROP_HAS_RECVD, &dummy) == 0) {
682 703 dummy = 0;
683 704 VERIFY0(zap_update(mos, zapobj, inheritstr,
684 705 8, 1, &dummy, tx));
685 706 }
686 707 break;
687 708 case ZPROP_SRC_RECEIVED:
688 709 /*
689 710 * set propname$recvd -> value
690 711 */
691 712 err = zap_update(mos, zapobj, recvdstr,
692 713 intsz, numints, value, tx);
693 714 ASSERT(err == 0);
694 715 break;
695 716 case (ZPROP_SRC_NONE | ZPROP_SRC_LOCAL | ZPROP_SRC_RECEIVED):
696 717 /*
697 718 * clear local and received settings
698 719 * - remove propname
699 720 * - remove propname$inherit
700 721 * - remove propname$recvd
701 722 */
702 723 err = zap_remove(mos, zapobj, propname, tx);
703 724 ASSERT(err == 0 || err == ENOENT);
704 725 err = zap_remove(mos, zapobj, inheritstr, tx);
705 726 ASSERT(err == 0 || err == ENOENT);
706 727 /* FALLTHRU */
707 728 case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED):
708 729 /*
709 730 * remove propname$recvd
710 731 */
|
↓ open down ↓ |
77 lines elided |
↑ open up ↑ |
711 732 err = zap_remove(mos, zapobj, recvdstr, tx);
712 733 ASSERT(err == 0 || err == ENOENT);
713 734 break;
714 735 default:
715 736 cmn_err(CE_PANIC, "unexpected property source: %d", source);
716 737 }
717 738
718 739 strfree(inheritstr);
719 740 strfree(recvdstr);
720 741
721 - if (isint) {
742 + if (zfs_name_to_prop(propname) == ZFS_PROP_WBC_MODE) {
743 + wbc_mode_prop_val_t val;
744 +
745 + VERIFY0(dsl_prop_get_ds(ds, propname, 8,
746 + WBC_MODE_PROP_VAL_SZ, &val, NULL));
747 +
748 + dsl_prop_changed_notify(ds->ds_dir->dd_pool,
749 + ds->ds_dir->dd_object, propname,
750 + (uintptr_t)((void *)&val), TRUE);
751 +
752 + /*
753 + * Flow diagram of ZFS_PROP_WBC_MODE states
754 + *
755 + * off (root_ds_object == 0, txg_off == 0)
756 + * (user sees wbc_mode=off, source=default)
757 + *
758 + * user operation "set on" ==>>
759 + *
760 + * on (root_ds_object != 0, txg_off == 0)
761 + * (user sees wbc_mode=on, source=local)
762 + *
763 + * user operation "set off" ==>>
764 + *
765 + * off_delayed (root_ds_object != 0, txg_off != 0)
766 + * (user sees wbc_mode=off, source=local)
767 + *
768 + * internal operation "inherit" ==>>
769 + *
770 + * off (root_ds_object == 0, txg_off == 0)
771 + * (user sees wbc_mode=off, source=default)
772 + */
773 + if (val.root_ds_object == 0)
774 + spa_feature_decr(spa, SPA_FEATURE_WBC, tx);
775 + else if (val.txg_off == 0)
776 + spa_feature_incr(spa, SPA_FEATURE_WBC, tx);
777 +
778 + (void) snprintf(valbuf, sizeof (valbuf),
779 + "%s", (val.root_ds_object != 0 &&
780 + val.txg_off == 0) ? "on" : "off");
781 + valstr = valbuf;
782 + } else if (isint) {
722 783 VERIFY0(dsl_prop_get_int_ds(ds, propname, &intval));
723 784
724 785 if (ds->ds_is_snapshot) {
725 786 dsl_prop_cb_record_t *cbr;
726 787 /*
727 788 * It's a snapshot; nothing can inherit this
728 789 * property, so just look for callbacks on this
729 790 * ds here.
730 791 */
731 792 mutex_enter(&ds->ds_dir->dd_lock);
732 793 for (cbr = list_head(&ds->ds_prop_cbs); cbr;
733 794 cbr = list_next(&ds->ds_prop_cbs, cbr)) {
734 795 if (strcmp(cbr->cbr_pr->pr_propname,
735 796 propname) == 0)
736 797 cbr->cbr_func(cbr->cbr_arg, intval);
737 798 }
738 799 mutex_exit(&ds->ds_dir->dd_lock);
739 800 } else {
740 801 dsl_prop_changed_notify(ds->ds_dir->dd_pool,
741 802 ds->ds_dir->dd_object, propname, intval, TRUE);
742 803 }
743 804
744 805 (void) snprintf(valbuf, sizeof (valbuf),
745 806 "%lld", (longlong_t)intval);
746 807 valstr = valbuf;
747 808 } else {
748 809 if (source == ZPROP_SRC_LOCAL) {
749 810 valstr = value;
750 811 } else {
751 812 tbuf = kmem_alloc(ZAP_MAXVALUELEN, KM_SLEEP);
752 813 if (dsl_prop_get_ds(ds, propname, 1,
753 814 ZAP_MAXVALUELEN, tbuf, NULL) == 0)
754 815 valstr = tbuf;
755 816 }
756 817 }
757 818
758 819 spa_history_log_internal_ds(ds, (source == ZPROP_SRC_NONE ||
759 820 source == ZPROP_SRC_INHERITED) ? "inherit" : "set", tx,
760 821 "%s=%s", propname, (valstr == NULL ? "" : valstr));
761 822
762 823 if (tbuf != NULL)
763 824 kmem_free(tbuf, ZAP_MAXVALUELEN);
764 825 }
765 826
766 827 int
767 828 dsl_prop_set_int(const char *dsname, const char *propname,
768 829 zprop_source_t source, uint64_t value)
769 830 {
770 831 nvlist_t *nvl = fnvlist_alloc();
771 832 int error;
772 833
773 834 fnvlist_add_uint64(nvl, propname, value);
774 835 error = dsl_props_set(dsname, source, nvl);
775 836 fnvlist_free(nvl);
776 837 return (error);
777 838 }
778 839
779 840 int
780 841 dsl_prop_set_string(const char *dsname, const char *propname,
781 842 zprop_source_t source, const char *value)
782 843 {
783 844 nvlist_t *nvl = fnvlist_alloc();
784 845 int error;
785 846
786 847 fnvlist_add_string(nvl, propname, value);
787 848 error = dsl_props_set(dsname, source, nvl);
788 849 fnvlist_free(nvl);
789 850 return (error);
790 851 }
791 852
792 853 int
793 854 dsl_prop_inherit(const char *dsname, const char *propname,
794 855 zprop_source_t source)
|
↓ open down ↓ |
63 lines elided |
↑ open up ↑ |
795 856 {
796 857 nvlist_t *nvl = fnvlist_alloc();
797 858 int error;
798 859
799 860 fnvlist_add_boolean(nvl, propname);
800 861 error = dsl_props_set(dsname, source, nvl);
801 862 fnvlist_free(nvl);
802 863 return (error);
803 864 }
804 865
866 +/* ARGSUSED */
867 +static int
868 +dsl_prop_wbc_mode_check_child_cb(dsl_pool_t *dp,
869 + dsl_dataset_t *ds, void *arg)
870 +{
871 + int err;
872 + zfs_prop_t *prop = arg;
873 + objset_t *os = NULL;
874 +
875 + err = dmu_objset_from_ds(ds, &os);
876 + if (err != 0)
877 + return (err);
878 +
879 + if (*prop == ZFS_PROP_DEDUP) {
880 + /*
881 + * User tries to set ZFS_PROP_DEDUP.
882 + * In this case we just check that
883 + * the target DS and its children
884 + * do not use writecache
885 + */
886 + if (os->os_wbc_mode != ZFS_WBC_MODE_OFF)
887 + return (SET_ERROR(EKZFS_WBCCONFLICT));
888 + } else {
889 + ASSERT3U(*prop, ==, ZFS_PROP_WBC_MODE);
890 +
891 + /*
892 + * User tries to set ZFS_PROP_WBC_MODE.
893 + * In this case we need check that
894 + * the target DS and its children
895 + * do not use writecache and dedup
896 + */
897 + if (os->os_wbc_mode != ZFS_WBC_MODE_OFF)
898 + return (SET_ERROR(EKZFS_WBCCHILD));
899 +
900 + if (os->os_dedup_checksum != ZIO_CHECKSUM_OFF)
901 + return (SET_ERROR(EKZFS_WBCCONFLICT));
902 + }
903 +
904 + return (0);
905 +}
906 +
907 +static int
908 +dsl_prop_wbc_mode_check(dsl_dataset_t *ds, objset_t *os)
909 +{
910 + int err = 0;
911 + zfs_prop_t prop = ZFS_PROP_WBC_MODE;
912 +
913 + if (os->os_wbc_mode != ZFS_WBC_MODE_OFF) {
914 + /*
915 + * ZFS_PROP_WBC_MODE cannot be set for
916 + * a child DS if the prop was set for
917 + * the parent
918 + */
919 + if (os->os_wbc_root_ds_obj != ds->ds_object)
920 + return (SET_ERROR(EKZFS_WBCPARENT));
921 + } else {
922 + /*
923 + * Is not allowed to change wbc_mode for parent
924 + * if its children already have the changed prop
925 + */
926 + err = dmu_objset_find_dp(ds->ds_dir->dd_pool,
927 + ds->ds_dir->dd_object,
928 + dsl_prop_wbc_mode_check_child_cb, &prop,
929 + DS_FIND_CHILDREN);
930 + }
931 +
932 + return (err);
933 +}
934 +
805 935 typedef struct dsl_props_set_arg {
806 936 const char *dpsa_dsname;
807 937 zprop_source_t dpsa_source;
808 938 nvlist_t *dpsa_props;
809 939 } dsl_props_set_arg_t;
810 940
811 941 static int
812 942 dsl_props_set_check(void *arg, dmu_tx_t *tx)
813 943 {
814 944 dsl_props_set_arg_t *dpsa = arg;
815 945 dsl_pool_t *dp = dmu_tx_pool(tx);
816 946 dsl_dataset_t *ds;
947 + objset_t *os = NULL;
817 948 uint64_t version;
818 949 nvpair_t *elem = NULL;
819 950 int err;
820 951
821 952 err = dsl_dataset_hold(dp, dpsa->dpsa_dsname, FTAG, &ds);
822 953 if (err != 0)
823 954 return (err);
824 955
956 + err = dmu_objset_from_ds(ds, &os);
957 + if (err != 0) {
958 + dsl_dataset_rele(ds, FTAG);
959 + return (err);
960 + }
961 +
825 962 version = spa_version(ds->ds_dir->dd_pool->dp_spa);
826 963 while ((elem = nvlist_next_nvpair(dpsa->dpsa_props, elem)) != NULL) {
827 - if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) {
964 + const char *prop_name = nvpair_name(elem);
965 + zfs_prop_t prop = zfs_name_to_prop(prop_name);
966 +
967 + if (strlen(prop_name) >= ZAP_MAXNAMELEN) {
828 968 dsl_dataset_rele(ds, FTAG);
829 969 return (SET_ERROR(ENAMETOOLONG));
830 970 }
971 +
972 + /*
973 + * Deduplication and WBC cannot be used together
974 + * This code returns error also for case when
975 + * WBC is ON, DEDUP is off and a user tries
976 + * to do DEDUP=off, because in this case the code
977 + * will be more complex, but benefit is too small
978 + */
979 + if (prop == ZFS_PROP_DEDUP) {
980 + if (os->os_wbc_root_ds_obj != 0) {
981 + dsl_dataset_rele(ds, FTAG);
982 + return (SET_ERROR(EKZFS_WBCCONFLICT));
983 + }
984 +
985 + /*
986 + * Need to be sure that children DS
987 + * do not use writecache
988 + */
989 + err = dmu_objset_find_dp(ds->ds_dir->dd_pool,
990 + ds->ds_dir->dd_object,
991 + dsl_prop_wbc_mode_check_child_cb, &prop,
992 + DS_FIND_CHILDREN);
993 + if (err != 0) {
994 + dsl_dataset_rele(ds, FTAG);
995 + return (err);
996 + }
997 + }
998 +
999 + if (prop == ZFS_PROP_WBC_MODE) {
1000 + uint64_t wbc_mode_new = 0;
1001 + data_type_t elem_type = nvpair_type(elem);
1002 +
1003 + if (elem_type == DATA_TYPE_UINT64)
1004 + wbc_mode_new = fnvpair_value_uint64(elem);
1005 +
1006 + if (os->os_wbc_root_ds_obj == ds->ds_object &&
1007 + elem_type == DATA_TYPE_UINT64) {
1008 +
1009 + /*
1010 + * ZFS_WBC_MODE_OFF_DELAYED means that
1011 + * the coresponding wbc_instance is in
1012 + * transition state: from ON to OFF
1013 + * so ON/OFF is not permitted
1014 + */
1015 + if (os->os_wbc_mode ==
1016 + ZFS_WBC_MODE_OFF_DELAYED) {
1017 + dsl_dataset_rele(ds, FTAG);
1018 + return (SET_ERROR(EINPROGRESS));
1019 + }
1020 +
1021 + ASSERT3U(os->os_wbc_mode, ==, ZFS_WBC_MODE_ON);
1022 +
1023 + /* Check for double ON */
1024 + if (wbc_mode_new == ZFS_WBC_MODE_ON) {
1025 + dsl_dataset_rele(ds, FTAG);
1026 + return (SET_ERROR(EALREADY));
1027 + }
1028 + }
1029 +
1030 + err = dsl_prop_wbc_mode_check(ds, os);
1031 + if (err != 0) {
1032 + dsl_dataset_rele(ds, FTAG);
1033 + return (err);
1034 + }
1035 +
1036 + /* Check for double OFF */
1037 + if (os->os_wbc_root_ds_obj == 0 &&
1038 + elem_type == DATA_TYPE_UINT64 &&
1039 + wbc_mode_new == ZFS_WBC_MODE_OFF) {
1040 + dsl_dataset_rele(ds, FTAG);
1041 + return (SET_ERROR(EALREADY));
1042 + }
1043 +
1044 + continue;
1045 + }
1046 +
831 1047 if (nvpair_type(elem) == DATA_TYPE_STRING) {
832 1048 char *valstr = fnvpair_value_string(elem);
833 1049 if (strlen(valstr) >= (version <
834 1050 SPA_VERSION_STMF_PROP ?
835 1051 ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) {
836 1052 dsl_dataset_rele(ds, FTAG);
837 - return (E2BIG);
1053 + return (SET_ERROR(E2BIG));
838 1054 }
839 1055 }
1056 +
840 1057 }
841 1058
842 1059 if (ds->ds_is_snapshot && version < SPA_VERSION_SNAP_PROPS) {
843 1060 dsl_dataset_rele(ds, FTAG);
844 1061 return (SET_ERROR(ENOTSUP));
845 1062 }
846 1063 dsl_dataset_rele(ds, FTAG);
847 1064 return (0);
848 1065 }
849 1066
850 1067 void
851 1068 dsl_props_set_sync_impl(dsl_dataset_t *ds, zprop_source_t source,
852 1069 nvlist_t *props, dmu_tx_t *tx)
853 1070 {
854 1071 nvpair_t *elem = NULL;
855 1072
856 1073 while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
857 1074 nvpair_t *pair = elem;
858 - const char *name = nvpair_name(pair);
859 1075
860 1076 if (nvpair_type(pair) == DATA_TYPE_NVLIST) {
861 1077 /*
862 - * This usually happens when we reuse the nvlist_t data
863 - * returned by the counterpart dsl_prop_get_all_impl().
864 - * For instance we do this to restore the original
865 - * received properties when an error occurs in the
866 - * zfs_ioc_recv() codepath.
1078 + * dsl_prop_get_all_impl() returns properties in this
1079 + * format.
867 1080 */
868 1081 nvlist_t *attrs = fnvpair_value_nvlist(pair);
869 1082 pair = fnvlist_lookup_nvpair(attrs, ZPROP_VALUE);
870 1083 }
871 1084
872 1085 if (nvpair_type(pair) == DATA_TYPE_STRING) {
873 1086 const char *value = fnvpair_value_string(pair);
874 - dsl_prop_set_sync_impl(ds, name,
1087 + dsl_prop_set_sync_impl(ds, nvpair_name(pair),
875 1088 source, 1, strlen(value) + 1, value, tx);
876 1089 } else if (nvpair_type(pair) == DATA_TYPE_UINT64) {
1090 + const char *propname = nvpair_name(pair);
1091 + zfs_prop_t prop = zfs_name_to_prop(propname);
877 1092 uint64_t intval = fnvpair_value_uint64(pair);
878 - dsl_prop_set_sync_impl(ds, name,
879 - source, sizeof (intval), 1, &intval, tx);
1093 +
1094 + if (prop == ZFS_PROP_WBC_MODE) {
1095 + wbc_mode_prop_val_t val;
1096 +
1097 + /*
1098 + * Disabling WBC involves the following:
1099 + * 1) all the subsequent data writes will
1100 + * stop using special vdev
1101 + * 2) already WriteBackCached data blocks
1102 + * (with TXG <= txg_off below) will gradually
1103 + * migrated from special vdev
1104 + *
1105 + * To handle this need to remember TXG.
1106 + * WBC will be completely disabled for this DS,
1107 + * after WBC-window cross this TXG
1108 + */
1109 + val.txg_off = (intval == 0) ? tx->tx_txg : 0;
1110 + val.root_ds_object = ds->ds_object;
1111 + val.flags = 0;
1112 +
1113 + dsl_prop_set_sync_impl(ds, nvpair_name(pair),
1114 + source, 8, WBC_MODE_PROP_VAL_SZ, &val, tx);
1115 + } else {
1116 + dsl_prop_set_sync_impl(ds, nvpair_name(pair),
1117 + source, sizeof (intval), 1, &intval, tx);
1118 + }
880 1119 } else if (nvpair_type(pair) == DATA_TYPE_BOOLEAN) {
881 - dsl_prop_set_sync_impl(ds, name,
1120 + dsl_prop_set_sync_impl(ds, nvpair_name(pair),
882 1121 source, 0, 0, NULL, tx);
883 1122 } else {
884 1123 panic("invalid nvpair type");
885 1124 }
886 1125 }
887 1126 }
888 1127
889 1128 static void
890 1129 dsl_props_set_sync(void *arg, dmu_tx_t *tx)
891 1130 {
892 1131 dsl_props_set_arg_t *dpsa = arg;
893 1132 dsl_pool_t *dp = dmu_tx_pool(tx);
894 1133 dsl_dataset_t *ds;
1134 + objset_t *os = NULL;
895 1135
896 1136 VERIFY0(dsl_dataset_hold(dp, dpsa->dpsa_dsname, FTAG, &ds));
1137 + /*
1138 + * Need to initialize os, to be sure that non-mounted datasets and
1139 + * non-exposed zvols will receive notification about modified
1140 + * properties.
1141 + * During the initialization a property can register its callback
1142 + * that will be called if the property is changed.
1143 + * dsl_props_set_sync_impl() calls dsl_prop_changed_notify()
1144 + * that calls the required callback if it exists.
1145 + */
1146 + VERIFY0(dmu_objset_from_ds(ds, &os));
897 1147 dsl_props_set_sync_impl(ds, dpsa->dpsa_source, dpsa->dpsa_props, tx);
898 1148 dsl_dataset_rele(ds, FTAG);
899 1149 }
900 1150
901 1151 /*
902 1152 * All-or-nothing; if any prop can't be set, nothing will be modified.
903 1153 */
904 1154 int
905 1155 dsl_props_set(const char *dsname, zprop_source_t source, nvlist_t *props)
906 1156 {
907 1157 dsl_props_set_arg_t dpsa;
908 1158 int nblks = 0;
909 1159
910 1160 dpsa.dpsa_dsname = dsname;
911 1161 dpsa.dpsa_source = source;
912 1162 dpsa.dpsa_props = props;
913 1163
914 1164 /*
|
↓ open down ↓ |
8 lines elided |
↑ open up ↑ |
915 1165 * If the source includes NONE, then we will only be removing entries
916 1166 * from the ZAP object. In that case don't check for ENOSPC.
917 1167 */
918 1168 if ((source & ZPROP_SRC_NONE) == 0)
919 1169 nblks = 2 * fnvlist_num_pairs(props);
920 1170
921 1171 return (dsl_sync_task(dsname, dsl_props_set_check, dsl_props_set_sync,
922 1172 &dpsa, nblks, ZFS_SPACE_CHECK_RESERVED));
923 1173 }
924 1174
1175 +static void
1176 +dsl_props_mds_set_sync(void *arg, dmu_tx_t *tx)
1177 +{
1178 + dsl_props_set_arg_t *top_dpsa = arg;
1179 + dsl_pool_t *dp = dmu_tx_pool(tx);
1180 + nvlist_t *dss_props = top_dpsa->dpsa_props;
1181 + nvpair_t *pair = NULL;
1182 +
1183 + while ((pair = nvlist_next_nvpair(dss_props, pair)) != NULL) {
1184 + dsl_props_set_arg_t dpsa;
1185 + dsl_dataset_t *ds = NULL;
1186 + const char *ds_name;
1187 +
1188 + ds_name = nvpair_name(pair);
1189 + VERIFY0(dsl_dataset_hold(dp, ds_name, FTAG, &ds));
1190 +
1191 + dpsa.dpsa_dsname = ds_name;
1192 + dpsa.dpsa_source = ZPROP_SRC_LOCAL;
1193 + dpsa.dpsa_props = fnvpair_value_nvlist(pair);
1194 +
1195 + dsl_props_set_sync(&dpsa, tx);
1196 + dsl_dataset_rele(ds, FTAG);
1197 + }
1198 +}
1199 +
1200 +static int
1201 +dsl_props_mds_set_check(void *arg, dmu_tx_t *tx)
1202 +{
1203 + dsl_props_set_arg_t *top_dpsa = arg;
1204 + dsl_pool_t *dp = dmu_tx_pool(tx);
1205 + nvlist_t *dss_props = top_dpsa->dpsa_props;
1206 + nvpair_t *pair = NULL;
1207 +
1208 + while ((pair = nvlist_next_nvpair(dss_props, pair)) != NULL) {
1209 + dsl_props_set_arg_t dpsa;
1210 + dsl_dataset_t *ds = NULL;
1211 + const char *ds_name;
1212 + int err;
1213 +
1214 + ds_name = nvpair_name(pair);
1215 + err = dsl_dataset_hold(dp, ds_name, FTAG, &ds);
1216 + if (err != 0)
1217 + return (err);
1218 +
1219 + if (nvpair_type(pair) != DATA_TYPE_NVLIST) {
1220 + dsl_dataset_rele(ds, FTAG);
1221 + return (SET_ERROR(EINVAL));
1222 + }
1223 +
1224 + dpsa.dpsa_dsname = ds_name;
1225 + dpsa.dpsa_source = ZPROP_SRC_LOCAL;
1226 + dpsa.dpsa_props = fnvpair_value_nvlist(pair);
1227 +
1228 + err = dsl_props_set_check(&dpsa, tx);
1229 + dsl_dataset_rele(ds, FTAG);
1230 + if (err != 0)
1231 + return (err);
1232 + }
1233 +
1234 + return (0);
1235 +}
1236 +
1237 +
1238 +/*
1239 + * The given 'dss_props' nvlist represents the following struct:
1240 + * ds1 -> prop1:value
1241 + * -> prop3:value
1242 + * ds2 -> prop1:value
1243 + * -> prop2:value
1244 + *
1245 + * All-or-nothing: if any prop can't be set, nothing will be modified.
1246 + */
1247 +int
1248 +dsl_props_set_mds(const char *pool_name, nvlist_t *dss_props,
1249 + size_t num_props)
1250 +{
1251 + dsl_props_set_arg_t dpsa;
1252 +
1253 + dpsa.dpsa_dsname = pool_name;
1254 + dpsa.dpsa_source = ZPROP_SRC_LOCAL;
1255 + dpsa.dpsa_props = dss_props;
1256 +
1257 + return (dsl_sync_task(pool_name, dsl_props_mds_set_check,
1258 + dsl_props_mds_set_sync, &dpsa, 2 * num_props,
1259 + ZFS_SPACE_CHECK_RESERVED));
1260 +}
1261 +
925 1262 typedef enum dsl_prop_getflags {
926 1263 DSL_PROP_GET_INHERITING = 0x1, /* searching parent of target ds */
927 1264 DSL_PROP_GET_SNAPSHOT = 0x2, /* snapshot dataset */
928 1265 DSL_PROP_GET_LOCAL = 0x4, /* local properties */
929 1266 DSL_PROP_GET_RECEIVED = 0x8 /* received properties */
930 1267 } dsl_prop_getflags_t;
931 1268
932 1269 static int
933 1270 dsl_prop_get_all_impl(objset_t *mos, uint64_t propobj,
934 1271 const char *setpoint, dsl_prop_getflags_t flags, nvlist_t *nv)
935 1272 {
936 1273 zap_cursor_t zc;
937 1274 zap_attribute_t za;
938 1275 int err = 0;
939 1276
940 1277 for (zap_cursor_init(&zc, mos, propobj);
941 1278 (err = zap_cursor_retrieve(&zc, &za)) == 0;
942 1279 zap_cursor_advance(&zc)) {
943 1280 nvlist_t *propval;
944 1281 zfs_prop_t prop;
945 1282 char buf[ZAP_MAXNAMELEN];
946 1283 char *valstr;
947 1284 const char *suffix;
948 1285 const char *propname;
949 1286 const char *source;
950 1287
951 1288 suffix = strchr(za.za_name, '$');
952 1289
953 1290 if (suffix == NULL) {
954 1291 /*
955 1292 * Skip local properties if we only want received
956 1293 * properties.
957 1294 */
958 1295 if (flags & DSL_PROP_GET_RECEIVED)
959 1296 continue;
960 1297
961 1298 propname = za.za_name;
962 1299 source = setpoint;
963 1300 } else if (strcmp(suffix, ZPROP_INHERIT_SUFFIX) == 0) {
964 1301 /* Skip explicitly inherited entries. */
965 1302 continue;
966 1303 } else if (strcmp(suffix, ZPROP_RECVD_SUFFIX) == 0) {
967 1304 if (flags & DSL_PROP_GET_LOCAL)
968 1305 continue;
969 1306
970 1307 (void) strncpy(buf, za.za_name, (suffix - za.za_name));
971 1308 buf[suffix - za.za_name] = '\0';
972 1309 propname = buf;
973 1310
974 1311 if (!(flags & DSL_PROP_GET_RECEIVED)) {
975 1312 /* Skip if locally overridden. */
976 1313 err = zap_contains(mos, propobj, propname);
977 1314 if (err == 0)
978 1315 continue;
979 1316 if (err != ENOENT)
980 1317 break;
981 1318
982 1319 /* Skip if explicitly inherited. */
983 1320 valstr = kmem_asprintf("%s%s", propname,
984 1321 ZPROP_INHERIT_SUFFIX);
985 1322 err = zap_contains(mos, propobj, valstr);
986 1323 strfree(valstr);
987 1324 if (err == 0)
988 1325 continue;
989 1326 if (err != ENOENT)
990 1327 break;
991 1328 }
992 1329
993 1330 source = ((flags & DSL_PROP_GET_INHERITING) ?
994 1331 setpoint : ZPROP_SOURCE_VAL_RECVD);
995 1332 } else {
996 1333 /*
997 1334 * For backward compatibility, skip suffixes we don't
998 1335 * recognize.
999 1336 */
1000 1337 continue;
1001 1338 }
1002 1339
1003 1340 prop = zfs_name_to_prop(propname);
1004 1341
1005 1342 /* Skip non-inheritable properties. */
1006 1343 if ((flags & DSL_PROP_GET_INHERITING) && prop != ZPROP_INVAL &&
1007 1344 !zfs_prop_inheritable(prop))
1008 1345 continue;
1009 1346
1010 1347 /* Skip properties not valid for this type. */
1011 1348 if ((flags & DSL_PROP_GET_SNAPSHOT) && prop != ZPROP_INVAL &&
1012 1349 !zfs_prop_valid_for_type(prop, ZFS_TYPE_SNAPSHOT))
1013 1350 continue;
1014 1351
1015 1352 /* Skip properties already defined. */
1016 1353 if (nvlist_exists(nv, propname))
1017 1354 continue;
1018 1355
1019 1356 VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
1020 1357 if (za.za_integer_length == 1) {
1021 1358 /*
|
↓ open down ↓ |
87 lines elided |
↑ open up ↑ |
1022 1359 * String property
1023 1360 */
1024 1361 char *tmp = kmem_alloc(za.za_num_integers,
1025 1362 KM_SLEEP);
1026 1363 err = zap_lookup(mos, propobj,
1027 1364 za.za_name, 1, za.za_num_integers, tmp);
1028 1365 if (err != 0) {
1029 1366 kmem_free(tmp, za.za_num_integers);
1030 1367 break;
1031 1368 }
1369 +
1032 1370 VERIFY(nvlist_add_string(propval, ZPROP_VALUE,
1033 1371 tmp) == 0);
1034 1372 kmem_free(tmp, za.za_num_integers);
1035 1373 } else {
1036 1374 /*
1037 1375 * Integer property
1038 1376 */
1039 1377 ASSERT(za.za_integer_length == 8);
1378 +
1379 + if (prop == ZFS_PROP_WBC_MODE) {
1380 + wbc_mode_prop_val_t val;
1381 +
1382 + ASSERT(za.za_num_integers ==
1383 + WBC_MODE_PROP_VAL_SZ);
1384 +
1385 + err = zap_lookup(mos, propobj,
1386 + za.za_name, 8, za.za_num_integers, &val);
1387 + if (err != 0)
1388 + break;
1389 +
1390 + if (val.root_ds_object != 0 &&
1391 + val.txg_off == 0)
1392 + za.za_first_integer = ZFS_WBC_MODE_ON;
1393 + else
1394 + za.za_first_integer = ZFS_WBC_MODE_OFF;
1395 + }
1396 +
1040 1397 (void) nvlist_add_uint64(propval, ZPROP_VALUE,
1041 1398 za.za_first_integer);
1042 1399 }
1043 1400
1044 1401 VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, source) == 0);
1045 1402 VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0);
1046 1403 nvlist_free(propval);
1047 1404 }
1048 1405 zap_cursor_fini(&zc);
1049 1406 if (err == ENOENT)
1050 1407 err = 0;
1051 1408 return (err);
1052 1409 }
1053 1410
1054 1411 /*
1055 1412 * Iterate over all properties for this dataset and return them in an nvlist.
1056 1413 */
1057 1414 static int
1058 1415 dsl_prop_get_all_ds(dsl_dataset_t *ds, nvlist_t **nvp,
1059 1416 dsl_prop_getflags_t flags)
1060 1417 {
1061 1418 dsl_dir_t *dd = ds->ds_dir;
1062 1419 dsl_pool_t *dp = dd->dd_pool;
1063 1420 objset_t *mos = dp->dp_meta_objset;
1064 1421 int err = 0;
1065 1422 char setpoint[ZFS_MAX_DATASET_NAME_LEN];
1066 1423
1067 1424 VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);
1068 1425
1069 1426 if (ds->ds_is_snapshot)
1070 1427 flags |= DSL_PROP_GET_SNAPSHOT;
1071 1428
1072 1429 ASSERT(dsl_pool_config_held(dp));
1073 1430
1074 1431 if (dsl_dataset_phys(ds)->ds_props_obj != 0) {
1075 1432 ASSERT(flags & DSL_PROP_GET_SNAPSHOT);
1076 1433 dsl_dataset_name(ds, setpoint);
1077 1434 err = dsl_prop_get_all_impl(mos,
1078 1435 dsl_dataset_phys(ds)->ds_props_obj, setpoint, flags, *nvp);
1079 1436 if (err)
1080 1437 goto out;
1081 1438 }
1082 1439
1083 1440 for (; dd != NULL; dd = dd->dd_parent) {
1084 1441 if (dd != ds->ds_dir || (flags & DSL_PROP_GET_SNAPSHOT)) {
1085 1442 if (flags & (DSL_PROP_GET_LOCAL |
1086 1443 DSL_PROP_GET_RECEIVED))
1087 1444 break;
1088 1445 flags |= DSL_PROP_GET_INHERITING;
1089 1446 }
1090 1447 dsl_dir_name(dd, setpoint);
1091 1448 err = dsl_prop_get_all_impl(mos,
1092 1449 dsl_dir_phys(dd)->dd_props_zapobj, setpoint, flags, *nvp);
1093 1450 if (err)
1094 1451 break;
1095 1452 }
1096 1453 out:
1097 1454 return (err);
1098 1455 }
1099 1456
1100 1457 boolean_t
1101 1458 dsl_prop_get_hasrecvd(const char *dsname)
1102 1459 {
1103 1460 uint64_t dummy;
1104 1461
1105 1462 return (0 ==
1106 1463 dsl_prop_get_integer(dsname, ZPROP_HAS_RECVD, &dummy, NULL));
1107 1464 }
1108 1465
1109 1466 static int
1110 1467 dsl_prop_set_hasrecvd_impl(const char *dsname, zprop_source_t source)
1111 1468 {
1112 1469 uint64_t version;
1113 1470 spa_t *spa;
1114 1471 int error = 0;
1115 1472
1116 1473 VERIFY0(spa_open(dsname, &spa, FTAG));
1117 1474 version = spa_version(spa);
1118 1475 spa_close(spa, FTAG);
1119 1476
1120 1477 if (version >= SPA_VERSION_RECVD_PROPS)
1121 1478 error = dsl_prop_set_int(dsname, ZPROP_HAS_RECVD, source, 0);
1122 1479 return (error);
1123 1480 }
1124 1481
1125 1482 /*
1126 1483 * Call after successfully receiving properties to ensure that only the first
1127 1484 * receive on or after SPA_VERSION_RECVD_PROPS blows away local properties.
1128 1485 */
1129 1486 int
1130 1487 dsl_prop_set_hasrecvd(const char *dsname)
1131 1488 {
1132 1489 int error = 0;
1133 1490 if (!dsl_prop_get_hasrecvd(dsname))
1134 1491 error = dsl_prop_set_hasrecvd_impl(dsname, ZPROP_SRC_LOCAL);
1135 1492 return (error);
1136 1493 }
1137 1494
1138 1495 void
1139 1496 dsl_prop_unset_hasrecvd(const char *dsname)
1140 1497 {
1141 1498 VERIFY0(dsl_prop_set_hasrecvd_impl(dsname, ZPROP_SRC_NONE));
1142 1499 }
1143 1500
1144 1501 int
1145 1502 dsl_prop_get_all(objset_t *os, nvlist_t **nvp)
1146 1503 {
1147 1504 return (dsl_prop_get_all_ds(os->os_dsl_dataset, nvp, 0));
1148 1505 }
1149 1506
1150 1507 int
1151 1508 dsl_prop_get_received(const char *dsname, nvlist_t **nvp)
1152 1509 {
1153 1510 objset_t *os;
1154 1511 int error;
1155 1512
1156 1513 /*
1157 1514 * Received properties are not distinguishable from local properties
1158 1515 * until the dataset has received properties on or after
1159 1516 * SPA_VERSION_RECVD_PROPS.
1160 1517 */
1161 1518 dsl_prop_getflags_t flags = (dsl_prop_get_hasrecvd(dsname) ?
1162 1519 DSL_PROP_GET_RECEIVED : DSL_PROP_GET_LOCAL);
1163 1520
1164 1521 error = dmu_objset_hold(dsname, FTAG, &os);
1165 1522 if (error != 0)
1166 1523 return (error);
1167 1524 error = dsl_prop_get_all_ds(os->os_dsl_dataset, nvp, flags);
1168 1525 dmu_objset_rele(os, FTAG);
1169 1526 return (error);
1170 1527 }
1171 1528
1172 1529 void
1173 1530 dsl_prop_nvlist_add_uint64(nvlist_t *nv, zfs_prop_t prop, uint64_t value)
1174 1531 {
1175 1532 nvlist_t *propval;
1176 1533 const char *propname = zfs_prop_to_name(prop);
1177 1534 uint64_t default_value;
1178 1535
1179 1536 if (nvlist_lookup_nvlist(nv, propname, &propval) == 0) {
1180 1537 VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0);
1181 1538 return;
1182 1539 }
1183 1540
1184 1541 VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
1185 1542 VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0);
1186 1543 /* Indicate the default source if we can. */
1187 1544 if (dodefault(prop, 8, 1, &default_value) == 0 &&
1188 1545 value == default_value) {
1189 1546 VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, "") == 0);
1190 1547 }
1191 1548 VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0);
1192 1549 nvlist_free(propval);
1193 1550 }
1194 1551
1195 1552 void
1196 1553 dsl_prop_nvlist_add_string(nvlist_t *nv, zfs_prop_t prop, const char *value)
1197 1554 {
1198 1555 nvlist_t *propval;
1199 1556 const char *propname = zfs_prop_to_name(prop);
1200 1557
1201 1558 if (nvlist_lookup_nvlist(nv, propname, &propval) == 0) {
1202 1559 VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0);
1203 1560 return;
1204 1561 }
1205 1562
1206 1563 VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
1207 1564 VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0);
1208 1565 VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0);
1209 1566 nvlist_free(propval);
1210 1567 }
|
↓ open down ↓ |
161 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX