xref: /freebsd/sys/contrib/openzfs/module/zfs/zfs_sa.c (revision 1323ec571215a77ddd21294f0871979d5ad6b992)
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 http://www.opensolaris.org/os/licensing.
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) 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 #include <sys/zfs_context.h>
26 #include <sys/vnode.h>
27 #include <sys/sa.h>
28 #include <sys/zfs_acl.h>
29 #include <sys/zfs_sa.h>
30 #include <sys/dmu_objset.h>
31 #include <sys/sa_impl.h>
32 #include <sys/zfeature.h>
33 
34 /*
35  * ZPL attribute registration table.
36  * Order of attributes doesn't matter
37  * a unique value will be assigned for each
38  * attribute that is file system specific
39  *
40  * This is just the set of ZPL attributes that this
41  * version of ZFS deals with natively.  The file system
42  * could have other attributes stored in files, but they will be
43  * ignored.  The SA framework will preserve them, just that
44  * this version of ZFS won't change or delete them.
45  */
46 
47 const sa_attr_reg_t zfs_attr_table[ZPL_END+1] = {
48 	{"ZPL_ATIME", sizeof (uint64_t) * 2, SA_UINT64_ARRAY, 0},
49 	{"ZPL_MTIME", sizeof (uint64_t) * 2, SA_UINT64_ARRAY, 1},
50 	{"ZPL_CTIME", sizeof (uint64_t) * 2, SA_UINT64_ARRAY, 2},
51 	{"ZPL_CRTIME", sizeof (uint64_t) * 2, SA_UINT64_ARRAY, 3},
52 	{"ZPL_GEN", sizeof (uint64_t), SA_UINT64_ARRAY, 4},
53 	{"ZPL_MODE", sizeof (uint64_t), SA_UINT64_ARRAY, 5},
54 	{"ZPL_SIZE", sizeof (uint64_t), SA_UINT64_ARRAY, 6},
55 	{"ZPL_PARENT", sizeof (uint64_t), SA_UINT64_ARRAY, 7},
56 	{"ZPL_LINKS", sizeof (uint64_t), SA_UINT64_ARRAY, 8},
57 	{"ZPL_XATTR", sizeof (uint64_t), SA_UINT64_ARRAY, 9},
58 	{"ZPL_RDEV", sizeof (uint64_t), SA_UINT64_ARRAY, 10},
59 	{"ZPL_FLAGS", sizeof (uint64_t), SA_UINT64_ARRAY, 11},
60 	{"ZPL_UID", sizeof (uint64_t), SA_UINT64_ARRAY, 12},
61 	{"ZPL_GID", sizeof (uint64_t), SA_UINT64_ARRAY, 13},
62 	{"ZPL_PAD", sizeof (uint64_t) * 4, SA_UINT64_ARRAY, 14},
63 	{"ZPL_ZNODE_ACL", 88, SA_UINT8_ARRAY, 15},
64 	{"ZPL_DACL_COUNT", sizeof (uint64_t), SA_UINT64_ARRAY, 0},
65 	{"ZPL_SYMLINK", 0, SA_UINT8_ARRAY, 0},
66 	{"ZPL_SCANSTAMP", 32, SA_UINT8_ARRAY, 0},
67 	{"ZPL_DACL_ACES", 0, SA_ACL, 0},
68 	{"ZPL_DXATTR", 0, SA_UINT8_ARRAY, 0},
69 	{"ZPL_PROJID", sizeof (uint64_t), SA_UINT64_ARRAY, 0},
70 	{NULL, 0, 0, 0}
71 };
72 
73 
74 #ifdef _KERNEL
75 static int zfs_zil_saxattr = 1;
76 
77 int
78 zfs_sa_readlink(znode_t *zp, zfs_uio_t *uio)
79 {
80 	dmu_buf_t *db = sa_get_db(zp->z_sa_hdl);
81 	size_t bufsz;
82 	int error;
83 
84 	bufsz = zp->z_size;
85 	if (bufsz + ZFS_OLD_ZNODE_PHYS_SIZE <= db->db_size) {
86 		error = zfs_uiomove((caddr_t)db->db_data +
87 		    ZFS_OLD_ZNODE_PHYS_SIZE,
88 		    MIN((size_t)bufsz, zfs_uio_resid(uio)), UIO_READ, uio);
89 	} else {
90 		dmu_buf_t *dbp;
91 		if ((error = dmu_buf_hold(ZTOZSB(zp)->z_os, zp->z_id,
92 		    0, FTAG, &dbp, DMU_READ_NO_PREFETCH)) == 0) {
93 			error = zfs_uiomove(dbp->db_data,
94 			    MIN((size_t)bufsz, zfs_uio_resid(uio)), UIO_READ,
95 			    uio);
96 			dmu_buf_rele(dbp, FTAG);
97 		}
98 	}
99 	return (error);
100 }
101 
102 void
103 zfs_sa_symlink(znode_t *zp, char *link, int len, dmu_tx_t *tx)
104 {
105 	dmu_buf_t *db = sa_get_db(zp->z_sa_hdl);
106 
107 	if (ZFS_OLD_ZNODE_PHYS_SIZE + len <= dmu_bonus_max()) {
108 		VERIFY0(dmu_set_bonus(db, len + ZFS_OLD_ZNODE_PHYS_SIZE, tx));
109 		if (len) {
110 			memcpy((caddr_t)db->db_data +
111 			    ZFS_OLD_ZNODE_PHYS_SIZE, link, len);
112 		}
113 	} else {
114 		dmu_buf_t *dbp;
115 
116 		zfs_grow_blocksize(zp, len, tx);
117 		VERIFY0(dmu_buf_hold(ZTOZSB(zp)->z_os, zp->z_id, 0, FTAG, &dbp,
118 		    DMU_READ_NO_PREFETCH));
119 
120 		dmu_buf_will_dirty(dbp, tx);
121 
122 		ASSERT3U(len, <=, dbp->db_size);
123 		memcpy(dbp->db_data, link, len);
124 		dmu_buf_rele(dbp, FTAG);
125 	}
126 }
127 
128 void
129 zfs_sa_get_scanstamp(znode_t *zp, xvattr_t *xvap)
130 {
131 	zfsvfs_t *zfsvfs = ZTOZSB(zp);
132 	xoptattr_t *xoap;
133 
134 	ASSERT(MUTEX_HELD(&zp->z_lock));
135 	VERIFY((xoap = xva_getxoptattr(xvap)) != NULL);
136 	if (zp->z_is_sa) {
137 		if (sa_lookup(zp->z_sa_hdl, SA_ZPL_SCANSTAMP(zfsvfs),
138 		    &xoap->xoa_av_scanstamp,
139 		    sizeof (xoap->xoa_av_scanstamp)) != 0)
140 			return;
141 	} else {
142 		dmu_object_info_t doi;
143 		dmu_buf_t *db = sa_get_db(zp->z_sa_hdl);
144 		int len;
145 
146 		if (!(zp->z_pflags & ZFS_BONUS_SCANSTAMP))
147 			return;
148 
149 		sa_object_info(zp->z_sa_hdl, &doi);
150 		len = sizeof (xoap->xoa_av_scanstamp) +
151 		    ZFS_OLD_ZNODE_PHYS_SIZE;
152 
153 		if (len <= doi.doi_bonus_size) {
154 			(void) memcpy(xoap->xoa_av_scanstamp,
155 			    (caddr_t)db->db_data + ZFS_OLD_ZNODE_PHYS_SIZE,
156 			    sizeof (xoap->xoa_av_scanstamp));
157 		}
158 	}
159 	XVA_SET_RTN(xvap, XAT_AV_SCANSTAMP);
160 }
161 
162 void
163 zfs_sa_set_scanstamp(znode_t *zp, xvattr_t *xvap, dmu_tx_t *tx)
164 {
165 	zfsvfs_t *zfsvfs = ZTOZSB(zp);
166 	xoptattr_t *xoap;
167 
168 	ASSERT(MUTEX_HELD(&zp->z_lock));
169 	VERIFY((xoap = xva_getxoptattr(xvap)) != NULL);
170 	if (zp->z_is_sa)
171 		VERIFY(0 == sa_update(zp->z_sa_hdl, SA_ZPL_SCANSTAMP(zfsvfs),
172 		    &xoap->xoa_av_scanstamp,
173 		    sizeof (xoap->xoa_av_scanstamp), tx));
174 	else {
175 		dmu_object_info_t doi;
176 		dmu_buf_t *db = sa_get_db(zp->z_sa_hdl);
177 		int len;
178 
179 		sa_object_info(zp->z_sa_hdl, &doi);
180 		len = sizeof (xoap->xoa_av_scanstamp) +
181 		    ZFS_OLD_ZNODE_PHYS_SIZE;
182 		if (len > doi.doi_bonus_size)
183 			VERIFY(dmu_set_bonus(db, len, tx) == 0);
184 		(void) memcpy((caddr_t)db->db_data + ZFS_OLD_ZNODE_PHYS_SIZE,
185 		    xoap->xoa_av_scanstamp, sizeof (xoap->xoa_av_scanstamp));
186 
187 		zp->z_pflags |= ZFS_BONUS_SCANSTAMP;
188 		VERIFY(0 == sa_update(zp->z_sa_hdl, SA_ZPL_FLAGS(zfsvfs),
189 		    &zp->z_pflags, sizeof (uint64_t), tx));
190 	}
191 }
192 
193 int
194 zfs_sa_get_xattr(znode_t *zp)
195 {
196 	zfsvfs_t *zfsvfs = ZTOZSB(zp);
197 	char *obj;
198 	int size;
199 	int error;
200 
201 	ASSERT(RW_LOCK_HELD(&zp->z_xattr_lock));
202 	ASSERT(!zp->z_xattr_cached);
203 	ASSERT(zp->z_is_sa);
204 
205 	error = sa_size(zp->z_sa_hdl, SA_ZPL_DXATTR(zfsvfs), &size);
206 	if (error) {
207 		if (error == ENOENT)
208 			return nvlist_alloc(&zp->z_xattr_cached,
209 			    NV_UNIQUE_NAME, KM_SLEEP);
210 		else
211 			return (error);
212 	}
213 
214 	obj = vmem_alloc(size, KM_SLEEP);
215 
216 	error = sa_lookup(zp->z_sa_hdl, SA_ZPL_DXATTR(zfsvfs), obj, size);
217 	if (error == 0)
218 		error = nvlist_unpack(obj, size, &zp->z_xattr_cached, KM_SLEEP);
219 
220 	vmem_free(obj, size);
221 
222 	return (error);
223 }
224 
225 int
226 zfs_sa_set_xattr(znode_t *zp, const char *name, const void *value, size_t vsize)
227 {
228 	zfsvfs_t *zfsvfs = ZTOZSB(zp);
229 	zilog_t *zilog;
230 	dmu_tx_t *tx;
231 	char *obj;
232 	size_t size;
233 	int error, logsaxattr = 0;
234 
235 	ASSERT(RW_WRITE_HELD(&zp->z_xattr_lock));
236 	ASSERT(zp->z_xattr_cached);
237 	ASSERT(zp->z_is_sa);
238 
239 	error = nvlist_size(zp->z_xattr_cached, &size, NV_ENCODE_XDR);
240 	if ((error == 0) && (size > SA_ATTR_MAX_LEN))
241 		error = SET_ERROR(EFBIG);
242 	if (error)
243 		goto out;
244 
245 	obj = vmem_alloc(size, KM_SLEEP);
246 
247 	error = nvlist_pack(zp->z_xattr_cached, &obj, &size,
248 	    NV_ENCODE_XDR, KM_SLEEP);
249 	if (error)
250 		goto out_free;
251 
252 	zilog = zfsvfs->z_log;
253 
254 	/*
255 	 * Users enable ZIL logging of xattr=sa operations by enabling the
256 	 * SPA_FEATURE_ZILSAXATTR feature on the pool. Feature is activated
257 	 * during zil_process_commit_list/zil_create, if enabled.
258 	 */
259 	if (spa_feature_is_enabled(zfsvfs->z_os->os_spa,
260 	    SPA_FEATURE_ZILSAXATTR) && zfs_zil_saxattr)
261 		logsaxattr = 1;
262 
263 	tx = dmu_tx_create(zfsvfs->z_os);
264 	dmu_tx_hold_sa_create(tx, size);
265 	dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_TRUE);
266 
267 	error = dmu_tx_assign(tx, TXG_WAIT);
268 	if (error) {
269 		dmu_tx_abort(tx);
270 	} else {
271 		int count = 0;
272 		sa_bulk_attr_t bulk[2];
273 		uint64_t ctime[2];
274 
275 		if (logsaxattr)
276 			zfs_log_setsaxattr(zilog, tx, TX_SETSAXATTR, zp, name,
277 			    value, vsize);
278 
279 		zfs_tstamp_update_setup(zp, STATE_CHANGED, NULL, ctime);
280 		SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_DXATTR(zfsvfs),
281 		    NULL, obj, size);
282 		SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zfsvfs),
283 		    NULL, &ctime, 16);
284 		VERIFY0(sa_bulk_update(zp->z_sa_hdl, bulk, count, tx));
285 
286 		dmu_tx_commit(tx);
287 		if (logsaxattr && zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS)
288 			zil_commit(zilog, 0);
289 	}
290 out_free:
291 	vmem_free(obj, size);
292 out:
293 	return (error);
294 }
295 
296 /*
297  * I'm not convinced we should do any of this upgrade.
298  * since the SA code can read both old/new znode formats
299  * with probably little to no performance difference.
300  *
301  * All new files will be created with the new format.
302  */
303 
304 void
305 zfs_sa_upgrade(sa_handle_t *hdl, dmu_tx_t *tx)
306 {
307 	dmu_buf_t *db = sa_get_db(hdl);
308 	znode_t *zp = sa_get_userdata(hdl);
309 	zfsvfs_t *zfsvfs = ZTOZSB(zp);
310 	int count = 0;
311 	sa_bulk_attr_t *bulk, *sa_attrs;
312 	zfs_acl_locator_cb_t locate = { 0 };
313 	uint64_t uid, gid, mode, rdev, xattr, parent, tmp_gen;
314 	uint64_t crtime[2], mtime[2], ctime[2], atime[2];
315 	uint64_t links;
316 	zfs_acl_phys_t znode_acl;
317 	char scanstamp[AV_SCANSTAMP_SZ];
318 	boolean_t drop_lock = B_FALSE;
319 
320 	/*
321 	 * No upgrade if ACL isn't cached
322 	 * since we won't know which locks are held
323 	 * and ready the ACL would require special "locked"
324 	 * interfaces that would be messy
325 	 */
326 	if (zp->z_acl_cached == NULL || Z_ISLNK(ZTOTYPE(zp)))
327 		return;
328 
329 	/*
330 	 * If the z_lock is held and we aren't the owner
331 	 * the just return since we don't want to deadlock
332 	 * trying to update the status of z_is_sa.  This
333 	 * file can then be upgraded at a later time.
334 	 *
335 	 * Otherwise, we know we are doing the
336 	 * sa_update() that caused us to enter this function.
337 	 */
338 	if (MUTEX_NOT_HELD(&zp->z_lock)) {
339 		if (mutex_tryenter(&zp->z_lock) == 0)
340 			return;
341 		else
342 			drop_lock = B_TRUE;
343 	}
344 
345 	/* First do a bulk query of the attributes that aren't cached */
346 	bulk = kmem_alloc(sizeof (sa_bulk_attr_t) * ZPL_END, KM_SLEEP);
347 	SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_ATIME(zfsvfs), NULL, &atime, 16);
348 	SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MTIME(zfsvfs), NULL, &mtime, 16);
349 	SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zfsvfs), NULL, &ctime, 16);
350 	SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CRTIME(zfsvfs), NULL, &crtime, 16);
351 	SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MODE(zfsvfs), NULL, &mode, 8);
352 	SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_PARENT(zfsvfs), NULL, &parent, 8);
353 	SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_XATTR(zfsvfs), NULL, &xattr, 8);
354 	SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_RDEV(zfsvfs), NULL, &rdev, 8);
355 	SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_UID(zfsvfs), NULL, &uid, 8);
356 	SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_GID(zfsvfs), NULL, &gid, 8);
357 	SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_GEN(zfsvfs), NULL, &tmp_gen, 8);
358 	SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_ZNODE_ACL(zfsvfs), NULL,
359 	    &znode_acl, 88);
360 
361 	if (sa_bulk_lookup_locked(hdl, bulk, count) != 0)
362 		goto done;
363 
364 	if (dmu_objset_projectquota_enabled(hdl->sa_os) &&
365 	    !(zp->z_pflags & ZFS_PROJID)) {
366 		zp->z_pflags |= ZFS_PROJID;
367 		zp->z_projid = ZFS_DEFAULT_PROJID;
368 	}
369 
370 	/*
371 	 * While the order here doesn't matter its best to try and organize
372 	 * it is such a way to pick up an already existing layout number
373 	 */
374 	count = 0;
375 	sa_attrs = kmem_zalloc(sizeof (sa_bulk_attr_t) * ZPL_END, KM_SLEEP);
376 	SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_MODE(zfsvfs), NULL, &mode, 8);
377 	SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_SIZE(zfsvfs), NULL,
378 	    &zp->z_size, 8);
379 	SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_GEN(zfsvfs),
380 	    NULL, &tmp_gen, 8);
381 	SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_UID(zfsvfs), NULL, &uid, 8);
382 	SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_GID(zfsvfs), NULL, &gid, 8);
383 	SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_PARENT(zfsvfs),
384 	    NULL, &parent, 8);
385 	SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_FLAGS(zfsvfs), NULL,
386 	    &zp->z_pflags, 8);
387 	SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_ATIME(zfsvfs), NULL,
388 	    &atime, 16);
389 	SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_MTIME(zfsvfs), NULL,
390 	    &mtime, 16);
391 	SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_CTIME(zfsvfs), NULL,
392 	    &ctime, 16);
393 	SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_CRTIME(zfsvfs), NULL,
394 	    &crtime, 16);
395 	links = ZTONLNK(zp);
396 	SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_LINKS(zfsvfs), NULL,
397 	    &links, 8);
398 	if (dmu_objset_projectquota_enabled(hdl->sa_os))
399 		SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_PROJID(zfsvfs), NULL,
400 		    &zp->z_projid, 8);
401 	if (Z_ISBLK(ZTOTYPE(zp)) || Z_ISCHR(ZTOTYPE(zp)))
402 		SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_RDEV(zfsvfs), NULL,
403 		    &rdev, 8);
404 	SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_DACL_COUNT(zfsvfs), NULL,
405 	    &zp->z_acl_cached->z_acl_count, 8);
406 
407 	if (zp->z_acl_cached->z_version < ZFS_ACL_VERSION_FUID)
408 		zfs_acl_xform(zp, zp->z_acl_cached, CRED());
409 
410 	locate.cb_aclp = zp->z_acl_cached;
411 	SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_DACL_ACES(zfsvfs),
412 	    zfs_acl_data_locator, &locate, zp->z_acl_cached->z_acl_bytes);
413 
414 	if (xattr)
415 		SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_XATTR(zfsvfs),
416 		    NULL, &xattr, 8);
417 
418 	/* if scanstamp then add scanstamp */
419 
420 	if (zp->z_pflags & ZFS_BONUS_SCANSTAMP) {
421 		memcpy(scanstamp,
422 		    (caddr_t)db->db_data + ZFS_OLD_ZNODE_PHYS_SIZE,
423 		    AV_SCANSTAMP_SZ);
424 		SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_SCANSTAMP(zfsvfs),
425 		    NULL, scanstamp, AV_SCANSTAMP_SZ);
426 		zp->z_pflags &= ~ZFS_BONUS_SCANSTAMP;
427 	}
428 
429 	VERIFY(dmu_set_bonustype(db, DMU_OT_SA, tx) == 0);
430 	VERIFY(sa_replace_all_by_template_locked(hdl, sa_attrs,
431 	    count, tx) == 0);
432 	if (znode_acl.z_acl_extern_obj)
433 		VERIFY(0 == dmu_object_free(zfsvfs->z_os,
434 		    znode_acl.z_acl_extern_obj, tx));
435 
436 	zp->z_is_sa = B_TRUE;
437 	kmem_free(sa_attrs, sizeof (sa_bulk_attr_t) * ZPL_END);
438 done:
439 	kmem_free(bulk, sizeof (sa_bulk_attr_t) * ZPL_END);
440 	if (drop_lock)
441 		mutex_exit(&zp->z_lock);
442 }
443 
444 void
445 zfs_sa_upgrade_txholds(dmu_tx_t *tx, znode_t *zp)
446 {
447 	if (!ZTOZSB(zp)->z_use_sa || zp->z_is_sa)
448 		return;
449 
450 
451 	dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_TRUE);
452 
453 	if (zfs_external_acl(zp)) {
454 		dmu_tx_hold_free(tx, zfs_external_acl(zp), 0,
455 		    DMU_OBJECT_END);
456 	}
457 }
458 
459 ZFS_MODULE_PARAM(zfs, zfs_, zil_saxattr, INT, ZMOD_RW,
460 	"Disable xattr=sa extended attribute logging in ZIL by settng 0.");
461 
462 EXPORT_SYMBOL(zfs_attr_table);
463 EXPORT_SYMBOL(zfs_sa_readlink);
464 EXPORT_SYMBOL(zfs_sa_symlink);
465 EXPORT_SYMBOL(zfs_sa_get_scanstamp);
466 EXPORT_SYMBOL(zfs_sa_set_scanstamp);
467 EXPORT_SYMBOL(zfs_sa_get_xattr);
468 EXPORT_SYMBOL(zfs_sa_set_xattr);
469 EXPORT_SYMBOL(zfs_sa_upgrade);
470 EXPORT_SYMBOL(zfs_sa_upgrade_txholds);
471 
472 #endif
473