xref: /freebsd/sys/contrib/openzfs/module/zfs/zfs_znode.c (revision 22649d4dba730d46244fd2dff4fd174903c8379f)
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