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
zfs_sa_setup(objset_t * osp,sa_attr_type_t ** sa_table)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
zfs_grab_sa_handle(objset_t * osp,uint64_t obj,sa_handle_t ** hdlp,dmu_buf_t ** db,const void * tag)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
zfs_release_sa_handle(sa_handle_t * hdl,dmu_buf_t * db,const void * tag)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
zfs_obj_to_pobj(objset_t * osp,sa_handle_t * hdl,sa_attr_type_t * sa_table,uint64_t * pobjp,int * is_xattrdir)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
zfs_obj_to_stats_impl(sa_handle_t * hdl,sa_attr_type_t * sa_table,zfs_stat_t * sb)145 zfs_obj_to_stats_impl(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
zfs_obj_to_path_impl(objset_t * osp,uint64_t obj,sa_handle_t * hdl,sa_attr_type_t * sa_table,char * buf,int len)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
zfs_obj_to_path(objset_t * osp,uint64_t obj,char * buf,int len)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 int
zfs_obj_to_stats(objset_t * osp,uint64_t obj,zfs_stat_t * sb,char * buf,int len)274 zfs_obj_to_stats(objset_t *osp, uint64_t obj, zfs_stat_t *sb,
275 char *buf, int len)
276 {
277 char *path = buf + len - 1;
278 sa_attr_type_t *sa_table;
279 sa_handle_t *hdl;
280 dmu_buf_t *db;
281 int error;
282
283 *path = '\0';
284
285 error = zfs_sa_setup(osp, &sa_table);
286 if (error != 0)
287 return (error);
288
289 error = zfs_grab_sa_handle(osp, obj, &hdl, &db, FTAG);
290 if (error != 0)
291 return (error);
292
293 error = zfs_obj_to_stats_impl(hdl, sa_table, sb);
294 if (error != 0) {
295 zfs_release_sa_handle(hdl, db, FTAG);
296 return (error);
297 }
298
299 error = zfs_obj_to_path_impl(osp, obj, hdl, sa_table, buf, len);
300
301 zfs_release_sa_handle(hdl, db, FTAG);
302 return (error);
303 }
304
305 /*
306 * Read a property stored within the master node.
307 */
308 int
zfs_get_zplprop(objset_t * os,zfs_prop_t prop,uint64_t * value)309 zfs_get_zplprop(objset_t *os, zfs_prop_t prop, uint64_t *value)
310 {
311 uint64_t *cached_copy = NULL;
312
313 /*
314 * Figure out where in the objset_t the cached copy would live, if it
315 * is available for the requested property.
316 */
317 if (os != NULL) {
318 switch (prop) {
319 case ZFS_PROP_VERSION:
320 cached_copy = &os->os_version;
321 break;
322 case ZFS_PROP_NORMALIZE:
323 cached_copy = &os->os_normalization;
324 break;
325 case ZFS_PROP_UTF8ONLY:
326 cached_copy = &os->os_utf8only;
327 break;
328 case ZFS_PROP_CASE:
329 cached_copy = &os->os_casesensitivity;
330 break;
331 default:
332 break;
333 }
334 }
335 if (cached_copy != NULL && *cached_copy != OBJSET_PROP_UNINITIALIZED) {
336 *value = *cached_copy;
337 return (0);
338 }
339
340 /*
341 * If the property wasn't cached, look up the file system's value for
342 * the property. For the version property, we look up a slightly
343 * different string.
344 */
345 const char *pname;
346 int error = ENOENT;
347 if (prop == ZFS_PROP_VERSION)
348 pname = ZPL_VERSION_STR;
349 else
350 pname = zfs_prop_to_name(prop);
351
352 if (os != NULL) {
353 ASSERT3U(os->os_phys->os_type, ==, DMU_OST_ZFS);
354 error = zap_lookup(os, MASTER_NODE_OBJ, pname, 8, 1, value);
355 }
356
357 if (error == ENOENT) {
358 /* No value set, use the default value */
359 switch (prop) {
360 case ZFS_PROP_VERSION:
361 *value = ZPL_VERSION;
362 break;
363 case ZFS_PROP_NORMALIZE:
364 case ZFS_PROP_UTF8ONLY:
365 *value = 0;
366 break;
367 case ZFS_PROP_CASE:
368 *value = ZFS_CASE_SENSITIVE;
369 break;
370 case ZFS_PROP_ACLTYPE:
371 #ifdef __FreeBSD__
372 *value = ZFS_ACLTYPE_NFSV4;
373 #else
374 *value = ZFS_ACLTYPE_OFF;
375 #endif
376 break;
377 case ZFS_PROP_DEFAULTUSERQUOTA:
378 case ZFS_PROP_DEFAULTGROUPQUOTA:
379 case ZFS_PROP_DEFAULTPROJECTQUOTA:
380 case ZFS_PROP_DEFAULTUSEROBJQUOTA:
381 case ZFS_PROP_DEFAULTGROUPOBJQUOTA:
382 case ZFS_PROP_DEFAULTPROJECTOBJQUOTA:
383 *value = 0;
384 return (0);
385 default:
386 return (error);
387 }
388 error = 0;
389 }
390
391 /*
392 * If one of the methods for getting the property value above worked,
393 * copy it into the objset_t's cache.
394 */
395 if (error == 0 && cached_copy != NULL) {
396 *cached_copy = *value;
397 }
398
399 return (error);
400 }
401