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