zcp_get.c revision 332525
1/* 2 * CDDL HEADER START 3 * 4 * This file and its contents are supplied under the terms of the 5 * Common Development and Distribution License ("CDDL"), version 1.0. 6 * You may only use this file in accordance with the terms of version 7 * 1.0 of the CDDL. 8 * 9 * A full copy of the text of the CDDL should have accompanied this 10 * source. A copy of the CDDL is also available via the Internet at 11 * http://www.illumos.org/license/CDDL. 12 * 13 * CDDL HEADER END 14 */ 15 16/* 17 * Copyright (c) 2016 by Delphix. All rights reserved. 18 */ 19 20#include "lua.h" 21#include "lualib.h" 22#include "lauxlib.h" 23 24#include <zfs_prop.h> 25 26#include <sys/dsl_prop.h> 27#include <sys/dsl_synctask.h> 28#include <sys/dsl_dataset.h> 29#include <sys/dsl_dir.h> 30#include <sys/dmu_objset.h> 31#include <sys/mntent.h> 32#include <sys/sunddi.h> 33#include <sys/zap.h> 34#include <sys/zcp.h> 35#include <sys/zcp_iter.h> 36#include <sys/zcp_global.h> 37#include <sys/zfs_ioctl.h> 38#include <sys/zfs_znode.h> 39#include <sys/zvol.h> 40 41#ifdef _KERNEL 42#include <sys/zfs_vfsops.h> 43#endif 44 45static int 46get_objset_type(dsl_dataset_t *ds, zfs_type_t *type) 47{ 48 int error; 49 objset_t *os; 50 error = dmu_objset_from_ds(ds, &os); 51 if (error != 0) 52 return (error); 53 if (ds->ds_is_snapshot) { 54 *type = ZFS_TYPE_SNAPSHOT; 55 } else { 56 switch (os->os_phys->os_type) { 57 case DMU_OST_ZFS: 58 *type = ZFS_TYPE_FILESYSTEM; 59 break; 60 case DMU_OST_ZVOL: 61 *type = ZFS_TYPE_VOLUME; 62 break; 63 default: 64 return (EINVAL); 65 } 66 } 67 return (0); 68} 69 70/* 71 * Returns the string name of ds's type in str (a buffer which should be 72 * at least 12 bytes long). 73 */ 74static int 75get_objset_type_name(dsl_dataset_t *ds, char *str) 76{ 77 int error; 78 zfs_type_t type; 79 error = get_objset_type(ds, &type); 80 if (error != 0) 81 return (error); 82 switch (type) { 83 case ZFS_TYPE_SNAPSHOT: 84 (void) strcpy(str, "snapshot"); 85 break; 86 case ZFS_TYPE_FILESYSTEM: 87 (void) strcpy(str, "filesystem"); 88 break; 89 case ZFS_TYPE_VOLUME: 90 (void) strcpy(str, "volume"); 91 break; 92 default: 93 return (EINVAL); 94 } 95 return (0); 96} 97 98/* 99 * Determines the source of a property given its setpoint and 100 * property type. It pushes the source to the lua stack. 101 */ 102static void 103get_prop_src(lua_State *state, const char *setpoint, zfs_prop_t prop) 104{ 105 if (zfs_prop_readonly(prop) || (prop == ZFS_PROP_VERSION)) { 106 lua_pushnil(state); 107 } else { 108 const char *src; 109 if (strcmp("", setpoint) == 0) { 110 src = "default"; 111 } else { 112 src = setpoint; 113 } 114 (void) lua_pushstring(state, src); 115 } 116} 117 118/* 119 * Given an error encountered while getting properties, either longjmp's for 120 * a fatal error or pushes nothing to the stack for a non fatal one. 121 */ 122static int 123zcp_handle_error(lua_State *state, const char *dataset_name, 124 const char *property_name, int error) 125{ 126 ASSERT3S(error, !=, 0); 127 if (error == ENOENT) { 128 return (0); 129 } else if (error == EINVAL) { 130 return (luaL_error(state, 131 "property '%s' is not a valid property on dataset '%s'", 132 property_name, dataset_name)); 133 } else if (error == EIO) { 134 return (luaL_error(state, 135 "I/O error while retrieving property '%s' on dataset '%s'", 136 property_name, dataset_name)); 137 } else { 138 return (luaL_error(state, "unexpected error %d while " 139 "retrieving property '%s' on dataset '%s'", 140 error, property_name, dataset_name)); 141 } 142} 143 144/* 145 * Look up a user defined property in the zap object. If it exists, push it 146 * and the setpoint onto the stack, otherwise don't push anything. 147 */ 148static int 149zcp_get_user_prop(lua_State *state, dsl_pool_t *dp, const char *dataset_name, 150 const char *property_name) 151{ 152 int error; 153 char *buf; 154 char setpoint[ZFS_MAX_DATASET_NAME_LEN]; 155 /* 156 * zcp_dataset_hold will either successfully return the requested 157 * dataset or throw a lua error and longjmp out of the zfs.get_prop call 158 * without returning. 159 */ 160 dsl_dataset_t *ds = zcp_dataset_hold(state, dp, dataset_name, FTAG); 161 if (ds == NULL) 162 return (1); /* not reached; zcp_dataset_hold() longjmp'd */ 163 164 buf = kmem_alloc(ZAP_MAXVALUELEN, KM_SLEEP); 165 error = dsl_prop_get_ds(ds, property_name, 1, ZAP_MAXVALUELEN, 166 buf, setpoint); 167 dsl_dataset_rele(ds, FTAG); 168 169 if (error != 0) { 170 kmem_free(buf, ZAP_MAXVALUELEN); 171 return (zcp_handle_error(state, dataset_name, property_name, 172 error)); 173 } 174 (void) lua_pushstring(state, buf); 175 (void) lua_pushstring(state, setpoint); 176 kmem_free(buf, ZAP_MAXVALUELEN); 177 return (2); 178} 179 180/* 181 * Check if the property we're looking for is stored in the ds_dir. If so, 182 * return it in the 'val' argument. Return 0 on success and ENOENT and if 183 * the property is not present. 184 */ 185static int 186get_dsl_dir_prop(dsl_dataset_t *ds, zfs_prop_t zfs_prop, 187 uint64_t *val) 188{ 189 dsl_dir_t *dd = ds->ds_dir; 190 mutex_enter(&dd->dd_lock); 191 switch (zfs_prop) { 192 case ZFS_PROP_USEDSNAP: 193 *val = dsl_dir_get_usedsnap(dd); 194 break; 195 case ZFS_PROP_USEDCHILD: 196 *val = dsl_dir_get_usedchild(dd); 197 break; 198 case ZFS_PROP_USEDDS: 199 *val = dsl_dir_get_usedds(dd); 200 break; 201 case ZFS_PROP_USEDREFRESERV: 202 *val = dsl_dir_get_usedrefreserv(dd); 203 break; 204 case ZFS_PROP_LOGICALUSED: 205 *val = dsl_dir_get_logicalused(dd); 206 break; 207 default: 208 mutex_exit(&dd->dd_lock); 209 return (ENOENT); 210 } 211 mutex_exit(&dd->dd_lock); 212 return (0); 213} 214 215/* 216 * Takes a dataset, a property, a value and that value's setpoint as 217 * found in the ZAP. Checks if the property has been changed in the vfs. 218 * If so, val and setpoint will be overwritten with updated content. 219 * Otherwise, they are left unchanged. 220 */ 221static int 222get_temporary_prop(dsl_dataset_t *ds, zfs_prop_t zfs_prop, uint64_t *val, 223 char *setpoint) 224{ 225#ifndef _KERNEL 226 return (0); 227#else 228 int error; 229#ifdef illumos 230 zfsvfs_t *zfvp; 231#endif 232 vfs_t *vfsp; 233 objset_t *os; 234 uint64_t tmp = *val; 235 236 error = dmu_objset_from_ds(ds, &os); 237 if (error != 0) 238 return (error); 239 240 error = getzfsvfs_impl(os, &vfsp); 241 if (error != 0) 242 return (error); 243#ifdef illumos 244 vfsp = zfvp->z_vfs; 245#endif 246 switch (zfs_prop) { 247 case ZFS_PROP_ATIME: 248 if (vfs_optionisset(vfsp, MNTOPT_NOATIME, NULL)) 249 tmp = 0; 250 if (vfs_optionisset(vfsp, MNTOPT_ATIME, NULL)) 251 tmp = 1; 252 break; 253 case ZFS_PROP_DEVICES: 254 if (vfs_optionisset(vfsp, MNTOPT_NODEVICES, NULL)) 255 tmp = 0; 256 if (vfs_optionisset(vfsp, MNTOPT_DEVICES, NULL)) 257 tmp = 1; 258 break; 259 case ZFS_PROP_EXEC: 260 if (vfs_optionisset(vfsp, MNTOPT_NOEXEC, NULL)) 261 tmp = 0; 262 if (vfs_optionisset(vfsp, MNTOPT_EXEC, NULL)) 263 tmp = 1; 264 break; 265 case ZFS_PROP_SETUID: 266 if (vfs_optionisset(vfsp, MNTOPT_NOSETUID, NULL)) 267 tmp = 0; 268 if (vfs_optionisset(vfsp, MNTOPT_SETUID, NULL)) 269 tmp = 1; 270 break; 271 case ZFS_PROP_READONLY: 272 if (vfs_optionisset(vfsp, MNTOPT_RW, NULL)) 273 tmp = 0; 274 if (vfs_optionisset(vfsp, MNTOPT_RO, NULL)) 275 tmp = 1; 276 break; 277 case ZFS_PROP_XATTR: 278 if (vfs_optionisset(vfsp, MNTOPT_NOXATTR, NULL)) 279 tmp = 0; 280 if (vfs_optionisset(vfsp, MNTOPT_XATTR, NULL)) 281 tmp = 1; 282 break; 283 case ZFS_PROP_NBMAND: 284 if (vfs_optionisset(vfsp, MNTOPT_NONBMAND, NULL)) 285 tmp = 0; 286 if (vfs_optionisset(vfsp, MNTOPT_NBMAND, NULL)) 287 tmp = 1; 288 break; 289 default: 290#ifdef illumos 291 VFS_RELE(vfsp); 292#else 293 vfs_rel(vfsp); 294#endif 295 return (ENOENT); 296 } 297 298#ifdef illumos 299 VFS_RELE(vfsp); 300#else 301 vfs_rel(vfsp); 302#endif 303 if (tmp != *val) { 304 (void) strcpy(setpoint, "temporary"); 305 *val = tmp; 306 } 307 return (0); 308#endif 309} 310 311/* 312 * Check if the property we're looking for is stored at the dsl_dataset or 313 * dsl_dir level. If so, push the property value and source onto the lua stack 314 * and return 0. If it is not present or a failure occurs in lookup, return a 315 * non-zero error value. 316 */ 317static int 318get_special_prop(lua_State *state, dsl_dataset_t *ds, const char *dsname, 319 zfs_prop_t zfs_prop) 320{ 321 int error = 0; 322 objset_t *os; 323 uint64_t numval; 324 char *strval = kmem_alloc(ZAP_MAXVALUELEN, KM_SLEEP); 325 char setpoint[ZFS_MAX_DATASET_NAME_LEN] = 326 "Internal error - setpoint not determined"; 327 zfs_type_t ds_type; 328 zprop_type_t prop_type = zfs_prop_get_type(zfs_prop); 329 (void) get_objset_type(ds, &ds_type); 330 331 switch (zfs_prop) { 332 case ZFS_PROP_REFRATIO: 333 numval = dsl_get_refratio(ds); 334 break; 335 case ZFS_PROP_USED: 336 numval = dsl_get_used(ds); 337 break; 338 case ZFS_PROP_CLONES: { 339 nvlist_t *clones = fnvlist_alloc(); 340 error = get_clones_stat_impl(ds, clones); 341 if (error == 0) { 342 /* push list to lua stack */ 343 VERIFY0(zcp_nvlist_to_lua(state, clones, NULL, 0)); 344 /* source */ 345 (void) lua_pushnil(state); 346 } 347 nvlist_free(clones); 348 kmem_free(strval, ZAP_MAXVALUELEN); 349 return (error); 350 } 351 case ZFS_PROP_COMPRESSRATIO: 352 numval = dsl_get_compressratio(ds); 353 break; 354 case ZFS_PROP_CREATION: 355 numval = dsl_get_creation(ds); 356 break; 357 case ZFS_PROP_REFERENCED: 358 numval = dsl_get_referenced(ds); 359 break; 360 case ZFS_PROP_AVAILABLE: 361 numval = dsl_get_available(ds); 362 break; 363 case ZFS_PROP_LOGICALREFERENCED: 364 numval = dsl_get_logicalreferenced(ds); 365 break; 366 case ZFS_PROP_CREATETXG: 367 numval = dsl_get_creationtxg(ds); 368 break; 369 case ZFS_PROP_GUID: 370 numval = dsl_get_guid(ds); 371 break; 372 case ZFS_PROP_UNIQUE: 373 numval = dsl_get_unique(ds); 374 break; 375 case ZFS_PROP_OBJSETID: 376 numval = dsl_get_objsetid(ds); 377 break; 378 case ZFS_PROP_ORIGIN: 379 dsl_dir_get_origin(ds->ds_dir, strval); 380 break; 381 case ZFS_PROP_USERACCOUNTING: 382 error = dmu_objset_from_ds(ds, &os); 383 if (error == 0) 384 numval = dmu_objset_userspace_present(os); 385 break; 386 case ZFS_PROP_WRITTEN: 387 error = dsl_get_written(ds, &numval); 388 break; 389 case ZFS_PROP_TYPE: 390 error = get_objset_type_name(ds, strval); 391 break; 392 case ZFS_PROP_PREV_SNAP: 393 error = dsl_get_prev_snap(ds, strval); 394 break; 395 case ZFS_PROP_NAME: 396 dsl_dataset_name(ds, strval); 397 break; 398 case ZFS_PROP_MOUNTPOINT: 399 error = dsl_get_mountpoint(ds, dsname, strval, setpoint); 400 break; 401 case ZFS_PROP_VERSION: 402 /* should be a snapshot or filesystem */ 403 ASSERT(ds_type != ZFS_TYPE_VOLUME); 404 error = dmu_objset_from_ds(ds, &os); 405 /* look in the master node for the version */ 406 if (error == 0) { 407 error = zap_lookup(os, MASTER_NODE_OBJ, ZPL_VERSION_STR, 408 sizeof (numval), 1, &numval); 409 } 410 break; 411 case ZFS_PROP_DEFER_DESTROY: 412 numval = dsl_get_defer_destroy(ds); 413 break; 414 case ZFS_PROP_USERREFS: 415 numval = dsl_get_userrefs(ds); 416 break; 417 case ZFS_PROP_FILESYSTEM_COUNT: 418 error = dsl_dir_get_filesystem_count(ds->ds_dir, &numval); 419 (void) strcpy(setpoint, ""); 420 break; 421 case ZFS_PROP_SNAPSHOT_COUNT: 422 error = dsl_dir_get_snapshot_count(ds->ds_dir, &numval); 423 (void) strcpy(setpoint, ""); 424 break; 425 case ZFS_PROP_REMAPTXG: 426 error = dsl_dir_get_remaptxg(ds->ds_dir, &numval); 427 break; 428 case ZFS_PROP_NUMCLONES: 429 numval = dsl_get_numclones(ds); 430 break; 431 case ZFS_PROP_INCONSISTENT: 432 numval = dsl_get_inconsistent(ds); 433 break; 434 case ZFS_PROP_RECEIVE_RESUME_TOKEN: 435 VERIFY3U(strlcpy(strval, get_receive_resume_stats_impl(ds), 436 ZAP_MAXVALUELEN), <, ZAP_MAXVALUELEN); 437 if (strcmp(strval, "") == 0) { 438 VERIFY3U(strlcpy(strval, get_child_receive_stats(ds), 439 ZAP_MAXVALUELEN), <, ZAP_MAXVALUELEN); 440 if (strcmp(strval, "") == 0) 441 error = ENOENT; 442 } 443 break; 444 case ZFS_PROP_VOLSIZE: 445 ASSERT(ds_type == ZFS_TYPE_VOLUME); 446 error = dmu_objset_from_ds(ds, &os); 447 if (error == 0) { 448 error = zap_lookup(os, ZVOL_ZAP_OBJ, "size", 449 sizeof (numval), 1, &numval); 450 } 451 if (error == 0) 452 (void) strcpy(setpoint, dsname); 453 454 break; 455 case ZFS_PROP_VOLBLOCKSIZE: { 456 ASSERT(ds_type == ZFS_TYPE_VOLUME); 457 dmu_object_info_t doi; 458 error = dmu_objset_from_ds(ds, &os); 459 if (error == 0) { 460 error = dmu_object_info(os, ZVOL_OBJ, &doi); 461 if (error == 0) 462 numval = doi.doi_data_block_size; 463 } 464 break; 465 } 466 default: 467 /* Did not match these props, check in the dsl_dir */ 468 error = get_dsl_dir_prop(ds, zfs_prop, &numval); 469 } 470 if (error != 0) { 471 kmem_free(strval, ZAP_MAXVALUELEN); 472 return (error); 473 } 474 475 switch (prop_type) { 476 case PROP_TYPE_NUMBER: { 477 (void) lua_pushnumber(state, numval); 478 break; 479 } 480 case PROP_TYPE_STRING: { 481 (void) lua_pushstring(state, strval); 482 break; 483 } 484 case PROP_TYPE_INDEX: { 485 const char *propval; 486 error = zfs_prop_index_to_string(zfs_prop, numval, &propval); 487 if (error != 0) { 488 kmem_free(strval, ZAP_MAXVALUELEN); 489 return (error); 490 } 491 (void) lua_pushstring(state, propval); 492 break; 493 } 494 } 495 kmem_free(strval, ZAP_MAXVALUELEN); 496 497 /* Push the source to the stack */ 498 get_prop_src(state, setpoint, zfs_prop); 499 return (0); 500} 501 502/* 503 * Look up a property and its source in the zap object. If the value is 504 * present and successfully retrieved, push the value and source on the 505 * lua stack and return 0. On failure, return a non-zero error value. 506 */ 507static int 508get_zap_prop(lua_State *state, dsl_dataset_t *ds, zfs_prop_t zfs_prop) 509{ 510 int error = 0; 511 char setpoint[ZFS_MAX_DATASET_NAME_LEN]; 512 char *strval = kmem_alloc(ZAP_MAXVALUELEN, KM_SLEEP); 513 uint64_t numval; 514 const char *prop_name = zfs_prop_to_name(zfs_prop); 515 zprop_type_t prop_type = zfs_prop_get_type(zfs_prop); 516 517 if (prop_type == PROP_TYPE_STRING) { 518 /* Push value to lua stack */ 519 error = dsl_prop_get_ds(ds, prop_name, 1, 520 ZAP_MAXVALUELEN, strval, setpoint); 521 if (error == 0) 522 (void) lua_pushstring(state, strval); 523 } else { 524 error = dsl_prop_get_ds(ds, prop_name, sizeof (numval), 525 1, &numval, setpoint); 526 527 /* Fill in temorary value for prop, if applicable */ 528 (void) get_temporary_prop(ds, zfs_prop, &numval, setpoint); 529 530 /* Push value to lua stack */ 531 if (prop_type == PROP_TYPE_INDEX) { 532 const char *propval; 533 error = zfs_prop_index_to_string(zfs_prop, numval, 534 &propval); 535 if (error == 0) 536 (void) lua_pushstring(state, propval); 537 } else { 538 if (error == 0) 539 (void) lua_pushnumber(state, numval); 540 } 541 } 542 kmem_free(strval, ZAP_MAXVALUELEN); 543 if (error == 0) 544 get_prop_src(state, setpoint, zfs_prop); 545 return (error); 546} 547 548/* 549 * Determine whether property is valid for a given dataset 550 */ 551boolean_t 552prop_valid_for_ds(dsl_dataset_t *ds, zfs_prop_t zfs_prop) 553{ 554 int error; 555 zfs_type_t zfs_type; 556 557 /* properties not supported */ 558 if ((zfs_prop == ZFS_PROP_ISCSIOPTIONS) || 559 (zfs_prop == ZFS_PROP_MOUNTED)) 560 return (B_FALSE); 561 562 /* if we want the origin prop, ds must be a clone */ 563 if ((zfs_prop == ZFS_PROP_ORIGIN) && (!dsl_dir_is_clone(ds->ds_dir))) 564 return (B_FALSE); 565 566 error = get_objset_type(ds, &zfs_type); 567 if (error != 0) 568 return (B_FALSE); 569 return (zfs_prop_valid_for_type(zfs_prop, zfs_type)); 570} 571 572/* 573 * Look up a given dataset property. On success return 2, the number of 574 * values pushed to the lua stack (property value and source). On a fatal 575 * error, longjmp. On a non fatal error push nothing. 576 */ 577static int 578zcp_get_system_prop(lua_State *state, dsl_pool_t *dp, const char *dataset_name, 579 zfs_prop_t zfs_prop) 580{ 581 int error; 582 /* 583 * zcp_dataset_hold will either successfully return the requested 584 * dataset or throw a lua error and longjmp out of the zfs.get_prop call 585 * without returning. 586 */ 587 dsl_dataset_t *ds = zcp_dataset_hold(state, dp, dataset_name, FTAG); 588 if (ds == NULL) 589 return (1); /* not reached; zcp_dataset_hold() longjmp'd */ 590 591 /* Check that the property is valid for the given dataset */ 592 const char *prop_name = zfs_prop_to_name(zfs_prop); 593 if (!prop_valid_for_ds(ds, zfs_prop)) { 594 dsl_dataset_rele(ds, FTAG); 595 return (0); 596 } 597 598 /* Check if the property can be accessed directly */ 599 error = get_special_prop(state, ds, dataset_name, zfs_prop); 600 if (error == 0) { 601 dsl_dataset_rele(ds, FTAG); 602 /* The value and source have been pushed by get_special_prop */ 603 return (2); 604 } 605 if (error != ENOENT) { 606 dsl_dataset_rele(ds, FTAG); 607 return (zcp_handle_error(state, dataset_name, 608 prop_name, error)); 609 } 610 611 /* If we were unable to find it, look in the zap object */ 612 error = get_zap_prop(state, ds, zfs_prop); 613 dsl_dataset_rele(ds, FTAG); 614 if (error != 0) { 615 return (zcp_handle_error(state, dataset_name, 616 prop_name, error)); 617 } 618 /* The value and source have been pushed by get_zap_prop */ 619 return (2); 620} 621 622static zfs_userquota_prop_t 623get_userquota_prop(const char *prop_name) 624{ 625 zfs_userquota_prop_t type; 626 /* Figure out the property type ({user|group}{quota|used}) */ 627 for (type = 0; type < ZFS_NUM_USERQUOTA_PROPS; type++) { 628 if (strncmp(prop_name, zfs_userquota_prop_prefixes[type], 629 strlen(zfs_userquota_prop_prefixes[type])) == 0) 630 break; 631 } 632 return (type); 633} 634 635#ifdef _KERNEL 636/* 637 * Given the name of a zfs_userquota_prop, this function determines the 638 * prop type as well as the numeric group/user ids based on the string 639 * following the '@' in the property name. On success, returns 0. On failure, 640 * returns a non-zero error. 641 * 'domain' must be free'd by caller using strfree() 642 */ 643static int 644parse_userquota_prop(const char *prop_name, zfs_userquota_prop_t *type, 645 char **domain, uint64_t *rid) 646{ 647 char *cp, *end, *domain_val; 648 649 *type = get_userquota_prop(prop_name); 650 if (*type >= ZFS_NUM_USERQUOTA_PROPS) 651 return (EINVAL); 652 653 *rid = 0; 654 cp = strchr(prop_name, '@') + 1; 655 if (strncmp(cp, "S-1-", 4) == 0) { 656 /* 657 * It's a numeric SID (eg "S-1-234-567-89") and we want to 658 * seperate the domain id and the rid 659 */ 660 int domain_len = strrchr(cp, '-') - cp; 661 domain_val = kmem_alloc(domain_len + 1, KM_SLEEP); 662 (void) strncpy(domain_val, cp, domain_len); 663 domain_val[domain_len] = '\0'; 664 cp += domain_len + 1; 665 666 (void) ddi_strtoll(cp, &end, 10, (longlong_t *)rid); 667 if (*end != '\0') { 668 strfree(domain_val); 669 return (EINVAL); 670 } 671 } else { 672 /* It's only a user/group ID (eg "12345"), just get the rid */ 673 domain_val = NULL; 674 (void) ddi_strtoll(cp, &end, 10, (longlong_t *)rid); 675 if (*end != '\0') 676 return (EINVAL); 677 } 678 *domain = domain_val; 679 return (0); 680} 681 682/* 683 * Look up {user|group}{quota|used} property for given dataset. On success 684 * push the value (quota or used amount) and the setpoint. On failure, push 685 * a lua error. 686 */ 687static int 688zcp_get_userquota_prop(lua_State *state, dsl_pool_t *dp, 689 const char *dataset_name, const char *prop_name) 690{ 691 zfsvfs_t *zfvp; 692 zfsvfs_t *zfsvfs; 693 int error; 694 zfs_userquota_prop_t type; 695 char *domain; 696 uint64_t rid, value; 697 objset_t *os; 698 699 dsl_dataset_t *ds = zcp_dataset_hold(state, dp, dataset_name, FTAG); 700 if (ds == NULL) 701 return (1); /* not reached; zcp_dataset_hold() longjmp'd */ 702 703 error = parse_userquota_prop(prop_name, &type, &domain, &rid); 704 if (error == 0) { 705 error = dmu_objset_from_ds(ds, &os); 706 if (error == 0) { 707 zfsvfs = kmem_zalloc(sizeof (zfsvfs_t), KM_SLEEP); 708 error = zfsvfs_create_impl(&zfvp, zfsvfs, os); 709 if (error == 0) { 710 error = zfs_userspace_one(zfvp, type, domain, 711 rid, &value); 712 zfsvfs_free(zfvp); 713 } 714 } 715 if (domain != NULL) 716 strfree(domain); 717 } 718 dsl_dataset_rele(ds, FTAG); 719 720 if ((value == 0) && ((type == ZFS_PROP_USERQUOTA) || 721 (type == ZFS_PROP_GROUPQUOTA))) 722 error = ENOENT; 723 if (error != 0) { 724 return (zcp_handle_error(state, dataset_name, 725 prop_name, error)); 726 } 727 728 (void) lua_pushnumber(state, value); 729 (void) lua_pushstring(state, dataset_name); 730 return (2); 731} 732#endif 733 734/* 735 * Determines the name of the snapshot referenced in the written property 736 * name. Returns snapshot name in snap_name, a buffer that must be at least 737 * as large as ZFS_MAX_DATASET_NAME_LEN 738 */ 739static void 740parse_written_prop(const char *dataset_name, const char *prop_name, 741 char *snap_name) 742{ 743 ASSERT(zfs_prop_written(prop_name)); 744 const char *name = prop_name + ZFS_WRITTEN_PROP_PREFIX_LEN; 745 if (strchr(name, '@') == NULL) { 746 (void) sprintf(snap_name, "%s@%s", dataset_name, name); 747 } else { 748 (void) strcpy(snap_name, name); 749 } 750} 751 752/* 753 * Look up written@ property for given dataset. On success 754 * push the value and the setpoint. If error is fatal, we will 755 * longjmp, otherwise push nothing. 756 */ 757static int 758zcp_get_written_prop(lua_State *state, dsl_pool_t *dp, 759 const char *dataset_name, const char *prop_name) 760{ 761 char snap_name[ZFS_MAX_DATASET_NAME_LEN]; 762 uint64_t used, comp, uncomp; 763 dsl_dataset_t *old; 764 int error = 0; 765 766 parse_written_prop(dataset_name, prop_name, snap_name); 767 dsl_dataset_t *new = zcp_dataset_hold(state, dp, dataset_name, FTAG); 768 if (new == NULL) 769 return (1); /* not reached; zcp_dataset_hold() longjmp'd */ 770 771 error = dsl_dataset_hold(dp, snap_name, FTAG, &old); 772 if (error != 0) { 773 dsl_dataset_rele(new, FTAG); 774 return (zcp_dataset_hold_error(state, dp, snap_name, 775 error)); 776 } 777 error = dsl_dataset_space_written(old, new, 778 &used, &comp, &uncomp); 779 780 dsl_dataset_rele(old, FTAG); 781 dsl_dataset_rele(new, FTAG); 782 783 if (error != 0) { 784 return (zcp_handle_error(state, dataset_name, 785 snap_name, error)); 786 } 787 (void) lua_pushnumber(state, used); 788 (void) lua_pushstring(state, dataset_name); 789 return (2); 790} 791 792static int zcp_get_prop(lua_State *state); 793static zcp_lib_info_t zcp_get_prop_info = { 794 .name = "get_prop", 795 .func = zcp_get_prop, 796 .pargs = { 797 { .za_name = "dataset", .za_lua_type = LUA_TSTRING}, 798 { .za_name = "property", .za_lua_type = LUA_TSTRING}, 799 {NULL, 0} 800 }, 801 .kwargs = { 802 {NULL, 0} 803 } 804}; 805 806static int 807zcp_get_prop(lua_State *state) 808{ 809 const char *dataset_name; 810 const char *property_name; 811 dsl_pool_t *dp = zcp_run_info(state)->zri_pool; 812 zcp_lib_info_t *libinfo = &zcp_get_prop_info; 813 814 zcp_parse_args(state, libinfo->name, libinfo->pargs, libinfo->kwargs); 815 816 dataset_name = lua_tostring(state, 1); 817 property_name = lua_tostring(state, 2); 818 819 /* User defined property */ 820 if (zfs_prop_user(property_name)) { 821 return (zcp_get_user_prop(state, dp, 822 dataset_name, property_name)); 823 } 824 /* userspace property */ 825 if (zfs_prop_userquota(property_name)) { 826#ifdef _KERNEL 827 return (zcp_get_userquota_prop(state, dp, 828 dataset_name, property_name)); 829#else 830 return (luaL_error(state, 831 "user quota properties only supported in kernel mode", 832 property_name)); 833#endif 834 } 835 /* written@ property */ 836 if (zfs_prop_written(property_name)) { 837 return (zcp_get_written_prop(state, dp, 838 dataset_name, property_name)); 839 } 840 841 zfs_prop_t zfs_prop = zfs_name_to_prop(property_name); 842 /* Valid system property */ 843 if (zfs_prop != ZPROP_INVAL) { 844 return (zcp_get_system_prop(state, dp, dataset_name, 845 zfs_prop)); 846 } 847 848 /* Invalid property name */ 849 return (luaL_error(state, 850 "'%s' is not a valid property", property_name)); 851} 852 853int 854zcp_load_get_lib(lua_State *state) 855{ 856 lua_pushcclosure(state, zcp_get_prop_info.func, 0); 857 lua_setfield(state, -2, zcp_get_prop_info.name); 858 859 return (1); 860} 861