1 // SPDX-License-Identifier: CDDL-1.0 2 /* 3 * This file and its contents are supplied under the terms of the 4 * Common Development and Distribution License ("CDDL"), version 1.0. 5 * You may only use this file in accordance with the terms of version 6 * 1.0 of the CDDL. 7 * 8 * A full copy of the text of the CDDL should have accompanied this 9 * source. A copy of the CDDL is also available via the Internet at 10 * https://opensource.org/license/CDDL-1.0. 11 */ 12 /* 13 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 14 * Copyright (c) 2012, 2018 by Delphix. All rights reserved. 15 * Copyright (c) 2014 Integros [integros.com] 16 */ 17 18 /* Portions Copyright 2007 Jeremy Teo */ 19 /* Portions Copyright 2011 Martin Matuska <mm@FreeBSD.org> */ 20 21 #include <sys/dmu.h> 22 #include <sys/dmu_objset.h> 23 #include <sys/dmu_tx.h> 24 #include <sys/zfs_refcount.h> 25 #include <sys/stat.h> 26 #include <sys/zap.h> 27 #include <sys/zfs_znode.h> 28 #include <sys/sa.h> 29 #include <sys/zfs_sa.h> 30 #include <sys/zfs_stat.h> 31 32 #include "zfs_prop.h" 33 #include "zfs_comutil.h" 34 35 static int 36 zfs_sa_setup(objset_t *osp, sa_attr_type_t **sa_table) 37 { 38 uint64_t sa_obj = 0; 39 int error; 40 41 error = zap_lookup(osp, MASTER_NODE_OBJ, ZFS_SA_ATTRS, 8, 1, &sa_obj); 42 if (error != 0 && error != ENOENT) 43 return (error); 44 45 error = sa_setup(osp, sa_obj, zfs_attr_table, ZPL_END, sa_table); 46 return (error); 47 } 48 49 static int 50 zfs_grab_sa_handle(objset_t *osp, uint64_t obj, sa_handle_t **hdlp, 51 dmu_buf_t **db, const void *tag) 52 { 53 dmu_object_info_t doi; 54 int error; 55 56 if ((error = sa_buf_hold(osp, obj, tag, db)) != 0) 57 return (error); 58 59 dmu_object_info_from_db(*db, &doi); 60 if ((doi.doi_bonus_type != DMU_OT_SA && 61 doi.doi_bonus_type != DMU_OT_ZNODE) || 62 (doi.doi_bonus_type == DMU_OT_ZNODE && 63 doi.doi_bonus_size < sizeof (znode_phys_t))) { 64 sa_buf_rele(*db, tag); 65 return (SET_ERROR(ENOTSUP)); 66 } 67 68 error = sa_handle_get(osp, obj, NULL, SA_HDL_PRIVATE, hdlp); 69 if (error != 0) { 70 sa_buf_rele(*db, tag); 71 return (error); 72 } 73 74 return (0); 75 } 76 77 static void 78 zfs_release_sa_handle(sa_handle_t *hdl, dmu_buf_t *db, const void *tag) 79 { 80 sa_handle_destroy(hdl); 81 sa_buf_rele(db, tag); 82 } 83 84 /* 85 * Given an object number, return its parent object number and whether 86 * or not the object is an extended attribute directory. 87 */ 88 int 89 zfs_obj_to_pobj(objset_t *osp, sa_handle_t *hdl, sa_attr_type_t *sa_table, 90 uint64_t *pobjp, int *is_xattrdir) 91 { 92 uint64_t parent; 93 uint64_t pflags; 94 uint64_t mode; 95 uint64_t parent_mode; 96 sa_bulk_attr_t bulk[3]; 97 sa_handle_t *sa_hdl; 98 dmu_buf_t *sa_db; 99 int count = 0; 100 int error; 101 102 SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_PARENT], NULL, 103 &parent, sizeof (parent)); 104 SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_FLAGS], NULL, 105 &pflags, sizeof (pflags)); 106 SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_MODE], NULL, 107 &mode, sizeof (mode)); 108 109 if ((error = sa_bulk_lookup(hdl, bulk, count)) != 0) 110 return (error); 111 112 /* 113 * When a link is removed its parent pointer is not changed and will 114 * be invalid. There are two cases where a link is removed but the 115 * file stays around, when it goes to the delete queue and when there 116 * are additional links. 117 */ 118 error = zfs_grab_sa_handle(osp, parent, &sa_hdl, &sa_db, FTAG); 119 if (error != 0) 120 return (error); 121 122 error = sa_lookup(sa_hdl, ZPL_MODE, &parent_mode, sizeof (parent_mode)); 123 zfs_release_sa_handle(sa_hdl, sa_db, FTAG); 124 if (error != 0) 125 return (error); 126 127 *is_xattrdir = ((pflags & ZFS_XATTR) != 0) && S_ISDIR(mode); 128 129 /* 130 * Extended attributes can be applied to files, directories, etc. 131 * Otherwise the parent must be a directory. 132 */ 133 if (!*is_xattrdir && !S_ISDIR(parent_mode)) 134 return (SET_ERROR(EINVAL)); 135 136 *pobjp = parent; 137 138 return (0); 139 } 140 141 /* 142 * Given an object number, return some zpl level statistics 143 */ 144 static int 145 zfs_obj_to_stats_legacy(sa_handle_t *hdl, sa_attr_type_t *sa_table, 146 zfs_stat_t *sb) 147 { 148 sa_bulk_attr_t bulk[4]; 149 int count = 0; 150 151 SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_MODE], NULL, 152 &sb->zs_mode, sizeof (sb->zs_mode)); 153 SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_GEN], NULL, 154 &sb->zs_gen, sizeof (sb->zs_gen)); 155 SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_LINKS], NULL, 156 &sb->zs_links, sizeof (sb->zs_links)); 157 SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_CTIME], NULL, 158 &sb->zs_ctime, sizeof (sb->zs_ctime)); 159 160 return (sa_bulk_lookup(hdl, bulk, count)); 161 } 162 163 static int 164 zfs_obj_to_path_impl(objset_t *osp, uint64_t obj, sa_handle_t *hdl, 165 sa_attr_type_t *sa_table, char *buf, int len) 166 { 167 sa_handle_t *sa_hdl; 168 sa_handle_t *prevhdl = NULL; 169 dmu_buf_t *prevdb = NULL; 170 dmu_buf_t *sa_db = NULL; 171 char *path = buf + len - 1; 172 char *comp_buf; 173 int error; 174 175 *path = '\0'; 176 sa_hdl = hdl; 177 178 uint64_t deleteq_obj; 179 VERIFY0(zap_lookup(osp, MASTER_NODE_OBJ, 180 ZFS_UNLINKED_SET, sizeof (uint64_t), 1, &deleteq_obj)); 181 error = zap_lookup_int(osp, deleteq_obj, obj); 182 if (error == 0) { 183 return (ESTALE); 184 } else if (error != ENOENT) { 185 return (error); 186 } 187 188 comp_buf = kmem_alloc(ZAP_MAXNAMELEN_NEW + 2, KM_SLEEP); 189 for (;;) { 190 uint64_t pobj = 0; 191 char *component = comp_buf; 192 size_t complen; 193 int is_xattrdir = 0; 194 195 if (prevdb) { 196 ASSERT3P(prevhdl, !=, NULL); 197 zfs_release_sa_handle(prevhdl, prevdb, FTAG); 198 } 199 200 if ((error = zfs_obj_to_pobj(osp, sa_hdl, sa_table, &pobj, 201 &is_xattrdir)) != 0) 202 break; 203 204 if (pobj == obj) { 205 if (path[0] != '/') 206 *--path = '/'; 207 break; 208 } 209 210 component[0] = '/'; 211 if (is_xattrdir) { 212 strcpy(component + 1, "<xattrdir>"); 213 } else { 214 error = zap_value_search(osp, pobj, obj, 215 ZFS_DIRENT_OBJ(-1ULL), component + 1, 216 ZAP_MAXNAMELEN_NEW); 217 if (error != 0) 218 break; 219 } 220 221 complen = strlen(component); 222 path -= complen; 223 ASSERT3P(path, >=, buf); 224 memcpy(path, component, complen); 225 obj = pobj; 226 227 if (sa_hdl != hdl) { 228 prevhdl = sa_hdl; 229 prevdb = sa_db; 230 } 231 error = zfs_grab_sa_handle(osp, obj, &sa_hdl, &sa_db, FTAG); 232 if (error != 0) { 233 sa_hdl = prevhdl; 234 sa_db = prevdb; 235 break; 236 } 237 } 238 239 if (sa_hdl != NULL && sa_hdl != hdl) { 240 ASSERT3P(sa_db, !=, NULL); 241 zfs_release_sa_handle(sa_hdl, sa_db, FTAG); 242 } 243 244 if (error == 0) 245 (void) memmove(buf, path, buf + len - path); 246 247 kmem_free(comp_buf, ZAP_MAXNAMELEN_NEW +2); 248 return (error); 249 } 250 251 int 252 zfs_obj_to_path(objset_t *osp, uint64_t obj, char *buf, int len) 253 { 254 sa_attr_type_t *sa_table; 255 sa_handle_t *hdl; 256 dmu_buf_t *db; 257 int error; 258 259 error = zfs_sa_setup(osp, &sa_table); 260 if (error != 0) 261 return (error); 262 263 error = zfs_grab_sa_handle(osp, obj, &hdl, &db, FTAG); 264 if (error != 0) 265 return (error); 266 267 error = zfs_obj_to_path_impl(osp, obj, hdl, sa_table, buf, len); 268 269 zfs_release_sa_handle(hdl, db, FTAG); 270 return (error); 271 } 272 273 /* Taken from ZDB */ 274 static const char * 275 zfs_obj_type_name(dmu_object_type_t type) 276 { 277 if (type < DMU_OT_NUMTYPES) 278 return (dmu_ot[type].ot_name); 279 else if ((type & DMU_OT_NEWTYPE) && 280 ((type & DMU_OT_BYTESWAP_MASK) < DMU_BSWAP_NUMFUNCS)) 281 return (dmu_ot_byteswap[type & DMU_OT_BYTESWAP_MASK].ob_name); 282 else 283 return ("UNKNOWN"); 284 } 285 286 static void 287 zfs_obj_to_stats_extended(sa_handle_t *hdl, nvlist_t *nv) 288 { 289 dmu_object_info_t doi; 290 sa_object_info(hdl, &doi); 291 292 fnvlist_add_uint32(nv, ZFS_OBJ_STAT_DATA_BLOCK_SIZE, 293 doi.doi_data_block_size); 294 fnvlist_add_uint32(nv, ZFS_OBJ_STAT_METADATA_BLOCK_SIZE, 295 doi.doi_metadata_block_size); 296 fnvlist_add_uint64(nv, ZFS_OBJ_STAT_TYPE, doi.doi_type); 297 fnvlist_add_string(nv, ZFS_OBJ_STAT_TYPE_STR, 298 zfs_obj_type_name(doi.doi_type)); 299 fnvlist_add_uint64(nv, ZFS_OBJ_STAT_BONUS_TYPE, doi.doi_bonus_type); 300 fnvlist_add_string(nv, ZFS_OBJ_STAT_BONUS_TYPE_STR, 301 zfs_obj_type_name(doi.doi_bonus_type)); 302 fnvlist_add_uint64(nv, ZFS_OBJ_STAT_BONUS_SIZE, doi.doi_bonus_size); 303 fnvlist_add_uint8(nv, ZFS_OBJ_STAT_CHECKSUM, doi.doi_checksum); 304 fnvlist_add_uint8(nv, ZFS_OBJ_STAT_COMPRESS, doi.doi_compress); 305 fnvlist_add_uint64(nv, ZFS_OBJ_STAT_DNODE_SIZE, doi.doi_dnodesize); 306 fnvlist_add_uint64(nv, ZFS_OBJ_STAT_PHYSICAL_BLOCKS_512, 307 doi.doi_physical_blocks_512); 308 fnvlist_add_uint64(nv, ZFS_OBJ_STAT_MAX_OFFSET, doi.doi_max_offset); 309 fnvlist_add_uint64(nv, ZFS_OBJ_STAT_FILL_COUNT, doi.doi_fill_count); 310 } 311 312 int 313 zfs_obj_to_stats(objset_t *osp, uint64_t obj, zfs_stat_t *sb, 314 char *buf, int len, nvlist_t *nv) 315 { 316 char *path = buf + len - 1; 317 sa_attr_type_t *sa_table; 318 sa_handle_t *hdl; 319 dmu_buf_t *db; 320 int error; 321 322 *path = '\0'; 323 324 error = zfs_sa_setup(osp, &sa_table); 325 if (error != 0) 326 return (error); 327 328 error = zfs_grab_sa_handle(osp, obj, &hdl, &db, FTAG); 329 if (error != 0) 330 return (error); 331 332 error = zfs_obj_to_stats_legacy(hdl, sa_table, sb); 333 334 if (error != 0) { 335 zfs_release_sa_handle(hdl, db, FTAG); 336 return (error); 337 } 338 339 if (nv != NULL) 340 zfs_obj_to_stats_extended(hdl, nv); 341 342 error = zfs_obj_to_path_impl(osp, obj, hdl, sa_table, buf, len); 343 344 zfs_release_sa_handle(hdl, db, FTAG); 345 return (error); 346 } 347 348 /* 349 * Read a property stored within the master node. 350 */ 351 int 352 zfs_get_zplprop(objset_t *os, zfs_prop_t prop, uint64_t *value) 353 { 354 uint64_t *cached_copy = NULL; 355 356 /* 357 * Figure out where in the objset_t the cached copy would live, if it 358 * is available for the requested property. 359 */ 360 if (os != NULL) { 361 switch (prop) { 362 case ZFS_PROP_VERSION: 363 cached_copy = &os->os_version; 364 break; 365 case ZFS_PROP_NORMALIZE: 366 cached_copy = &os->os_normalization; 367 break; 368 case ZFS_PROP_UTF8ONLY: 369 cached_copy = &os->os_utf8only; 370 break; 371 case ZFS_PROP_CASE: 372 cached_copy = &os->os_casesensitivity; 373 break; 374 default: 375 break; 376 } 377 } 378 if (cached_copy != NULL && *cached_copy != OBJSET_PROP_UNINITIALIZED) { 379 *value = *cached_copy; 380 return (0); 381 } 382 383 /* 384 * If the property wasn't cached, look up the file system's value for 385 * the property. For the version property, we look up a slightly 386 * different string. 387 */ 388 const char *pname; 389 int error = ENOENT; 390 if (prop == ZFS_PROP_VERSION) 391 pname = ZPL_VERSION_STR; 392 else 393 pname = zfs_prop_to_name(prop); 394 395 if (os != NULL) { 396 ASSERT3U(os->os_phys->os_type, ==, DMU_OST_ZFS); 397 error = zap_lookup(os, MASTER_NODE_OBJ, pname, 8, 1, value); 398 } 399 400 if (error == ENOENT) { 401 /* No value set, use the default value */ 402 switch (prop) { 403 case ZFS_PROP_VERSION: 404 *value = ZPL_VERSION; 405 break; 406 case ZFS_PROP_NORMALIZE: 407 case ZFS_PROP_UTF8ONLY: 408 *value = 0; 409 break; 410 case ZFS_PROP_CASE: 411 *value = ZFS_CASE_SENSITIVE; 412 break; 413 case ZFS_PROP_ACLTYPE: 414 #ifdef __FreeBSD__ 415 *value = ZFS_ACLTYPE_NFSV4; 416 #else 417 *value = ZFS_ACLTYPE_OFF; 418 #endif 419 break; 420 case ZFS_PROP_DEFAULTUSERQUOTA: 421 case ZFS_PROP_DEFAULTGROUPQUOTA: 422 case ZFS_PROP_DEFAULTPROJECTQUOTA: 423 case ZFS_PROP_DEFAULTUSEROBJQUOTA: 424 case ZFS_PROP_DEFAULTGROUPOBJQUOTA: 425 case ZFS_PROP_DEFAULTPROJECTOBJQUOTA: 426 *value = 0; 427 return (0); 428 default: 429 return (error); 430 } 431 error = 0; 432 } 433 434 /* 435 * If one of the methods for getting the property value above worked, 436 * copy it into the objset_t's cache. 437 */ 438 if (error == 0 && cached_copy != NULL) { 439 *cached_copy = *value; 440 } 441 442 return (error); 443 } 444