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.
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.
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]
22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright (c) 2011 Pawel Jakub Dawidek
24 * Copyright (c) 2012, 2015, 2018 by Delphix. All rights reserved.
25 * Copyright (c) 2014 Integros [integros.com]
26 * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
29 /* Portions Copyright 2010 Robert Milkowski */
32 #include <sys/dmu_objset.h>
34 #include <sys/sa_impl.h>
36 #include <sys/zfs_project.h>
37 #include <sys/zfs_quota.h>
38 #include <sys/zfs_znode.h>
41 zpl_get_file_info(dmu_object_type_t bonustype
, const void *data
,
45 * Is it a valid type of object to track?
47 if (bonustype
!= DMU_OT_ZNODE
&& bonustype
!= DMU_OT_SA
)
48 return (SET_ERROR(ENOENT
));
50 zoi
->zfi_project
= ZFS_DEFAULT_PROJID
;
53 * If we have a NULL data pointer
54 * then assume the id's aren't changing and
55 * return EEXIST to the dmu to let it know to
59 return (SET_ERROR(EEXIST
));
61 if (bonustype
== DMU_OT_ZNODE
) {
62 const znode_phys_t
*znp
= data
;
63 zoi
->zfi_user
= znp
->zp_uid
;
64 zoi
->zfi_group
= znp
->zp_gid
;
65 zoi
->zfi_generation
= znp
->zp_gen
;
69 const sa_hdr_phys_t
*sap
= data
;
70 if (sap
->sa_magic
== 0) {
72 * This should only happen for newly created files
73 * that haven't had the znode data filled in yet.
77 zoi
->zfi_generation
= 0;
81 sa_hdr_phys_t sa
= *sap
;
82 boolean_t swap
= B_FALSE
;
83 if (sa
.sa_magic
== BSWAP_32(SA_MAGIC
)) {
84 sa
.sa_magic
= SA_MAGIC
;
85 sa
.sa_layout_info
= BSWAP_16(sa
.sa_layout_info
);
88 VERIFY3U(sa
.sa_magic
, ==, SA_MAGIC
);
90 int hdrsize
= sa_hdrsize(&sa
);
91 VERIFY3U(hdrsize
, >=, sizeof (sa_hdr_phys_t
));
93 uintptr_t data_after_hdr
= (uintptr_t)data
+ hdrsize
;
94 zoi
->zfi_user
= *((uint64_t *)(data_after_hdr
+ SA_UID_OFFSET
));
95 zoi
->zfi_group
= *((uint64_t *)(data_after_hdr
+ SA_GID_OFFSET
));
96 zoi
->zfi_generation
= *((uint64_t *)(data_after_hdr
+ SA_GEN_OFFSET
));
97 uint64_t flags
= *((uint64_t *)(data_after_hdr
+ SA_FLAGS_OFFSET
));
99 flags
= BSWAP_64(flags
);
101 if (flags
& ZFS_PROJID
) {
103 *((uint64_t *)(data_after_hdr
+ SA_PROJID_OFFSET
));
107 zoi
->zfi_user
= BSWAP_64(zoi
->zfi_user
);
108 zoi
->zfi_group
= BSWAP_64(zoi
->zfi_group
);
109 zoi
->zfi_project
= BSWAP_64(zoi
->zfi_project
);
110 zoi
->zfi_generation
= BSWAP_64(zoi
->zfi_generation
);
116 fuidstr_to_sid(zfsvfs_t
*zfsvfs
, const char *fuidstr
,
117 char *domainbuf
, int buflen
, uid_t
*ridp
)
122 fuid
= zfs_strtonum(fuidstr
, NULL
);
124 domain
= zfs_fuid_find_by_idx(zfsvfs
, FUID_INDEX(fuid
));
126 (void) strlcpy(domainbuf
, domain
, buflen
);
129 *ridp
= FUID_RID(fuid
);
133 zfs_userquota_prop_to_obj(zfsvfs_t
*zfsvfs
, zfs_userquota_prop_t type
)
136 case ZFS_PROP_USERUSED
:
137 case ZFS_PROP_USEROBJUSED
:
138 return (DMU_USERUSED_OBJECT
);
139 case ZFS_PROP_GROUPUSED
:
140 case ZFS_PROP_GROUPOBJUSED
:
141 return (DMU_GROUPUSED_OBJECT
);
142 case ZFS_PROP_PROJECTUSED
:
143 case ZFS_PROP_PROJECTOBJUSED
:
144 return (DMU_PROJECTUSED_OBJECT
);
145 case ZFS_PROP_USERQUOTA
:
146 return (zfsvfs
->z_userquota_obj
);
147 case ZFS_PROP_GROUPQUOTA
:
148 return (zfsvfs
->z_groupquota_obj
);
149 case ZFS_PROP_USEROBJQUOTA
:
150 return (zfsvfs
->z_userobjquota_obj
);
151 case ZFS_PROP_GROUPOBJQUOTA
:
152 return (zfsvfs
->z_groupobjquota_obj
);
153 case ZFS_PROP_PROJECTQUOTA
:
154 return (zfsvfs
->z_projectquota_obj
);
155 case ZFS_PROP_PROJECTOBJQUOTA
:
156 return (zfsvfs
->z_projectobjquota_obj
);
158 return (ZFS_NO_OBJECT
);
163 zfs_userspace_many(zfsvfs_t
*zfsvfs
, zfs_userquota_prop_t type
,
164 uint64_t *cookiep
, void *vbuf
, uint64_t *bufsizep
)
169 zfs_useracct_t
*buf
= vbuf
;
173 if (!dmu_objset_userspace_present(zfsvfs
->z_os
))
174 return (SET_ERROR(ENOTSUP
));
176 if ((type
== ZFS_PROP_PROJECTQUOTA
|| type
== ZFS_PROP_PROJECTUSED
||
177 type
== ZFS_PROP_PROJECTOBJQUOTA
||
178 type
== ZFS_PROP_PROJECTOBJUSED
) &&
179 !dmu_objset_projectquota_present(zfsvfs
->z_os
))
180 return (SET_ERROR(ENOTSUP
));
182 if ((type
== ZFS_PROP_USEROBJUSED
|| type
== ZFS_PROP_GROUPOBJUSED
||
183 type
== ZFS_PROP_USEROBJQUOTA
|| type
== ZFS_PROP_GROUPOBJQUOTA
||
184 type
== ZFS_PROP_PROJECTOBJUSED
||
185 type
== ZFS_PROP_PROJECTOBJQUOTA
) &&
186 !dmu_objset_userobjspace_present(zfsvfs
->z_os
))
187 return (SET_ERROR(ENOTSUP
));
189 obj
= zfs_userquota_prop_to_obj(zfsvfs
, type
);
190 if (obj
== ZFS_NO_OBJECT
) {
195 if (type
== ZFS_PROP_USEROBJUSED
|| type
== ZFS_PROP_GROUPOBJUSED
||
196 type
== ZFS_PROP_PROJECTOBJUSED
)
197 offset
= DMU_OBJACCT_PREFIX_LEN
;
199 za
= zap_attribute_alloc();
200 for (zap_cursor_init_serialized(&zc
, zfsvfs
->z_os
, obj
, *cookiep
);
201 (error
= zap_cursor_retrieve(&zc
, za
)) == 0;
202 zap_cursor_advance(&zc
)) {
203 if ((uintptr_t)buf
- (uintptr_t)vbuf
+ sizeof (zfs_useracct_t
) >
208 * skip object quota (with zap name prefix DMU_OBJACCT_PREFIX)
209 * when dealing with block quota and vice versa.
211 if ((offset
> 0) != (strncmp(za
->za_name
, DMU_OBJACCT_PREFIX
,
212 DMU_OBJACCT_PREFIX_LEN
) == 0))
215 fuidstr_to_sid(zfsvfs
, za
->za_name
+ offset
,
216 buf
->zu_domain
, sizeof (buf
->zu_domain
), &buf
->zu_rid
);
218 buf
->zu_space
= za
->za_first_integer
;
224 ASSERT3U((uintptr_t)buf
- (uintptr_t)vbuf
, <=, *bufsizep
);
225 *bufsizep
= (uintptr_t)buf
- (uintptr_t)vbuf
;
226 *cookiep
= zap_cursor_serialize(&zc
);
227 zap_cursor_fini(&zc
);
228 zap_attribute_free(za
);
233 zfs_userspace_one(zfsvfs_t
*zfsvfs
, zfs_userquota_prop_t type
,
234 const char *domain
, uint64_t rid
, uint64_t *valp
)
236 char buf
[20 + DMU_OBJACCT_PREFIX_LEN
];
243 if (!dmu_objset_userspace_present(zfsvfs
->z_os
))
244 return (SET_ERROR(ENOTSUP
));
246 if ((type
== ZFS_PROP_USEROBJUSED
|| type
== ZFS_PROP_GROUPOBJUSED
||
247 type
== ZFS_PROP_USEROBJQUOTA
|| type
== ZFS_PROP_GROUPOBJQUOTA
||
248 type
== ZFS_PROP_PROJECTOBJUSED
||
249 type
== ZFS_PROP_PROJECTOBJQUOTA
) &&
250 !dmu_objset_userobjspace_present(zfsvfs
->z_os
))
251 return (SET_ERROR(ENOTSUP
));
253 if (type
== ZFS_PROP_PROJECTQUOTA
|| type
== ZFS_PROP_PROJECTUSED
||
254 type
== ZFS_PROP_PROJECTOBJQUOTA
||
255 type
== ZFS_PROP_PROJECTOBJUSED
) {
256 if (!dmu_objset_projectquota_present(zfsvfs
->z_os
))
257 return (SET_ERROR(ENOTSUP
));
258 if (!zpl_is_valid_projid(rid
))
259 return (SET_ERROR(EINVAL
));
262 obj
= zfs_userquota_prop_to_obj(zfsvfs
, type
);
263 if (obj
== ZFS_NO_OBJECT
)
266 if (type
== ZFS_PROP_USEROBJUSED
|| type
== ZFS_PROP_GROUPOBJUSED
||
267 type
== ZFS_PROP_PROJECTOBJUSED
) {
268 strlcpy(buf
, DMU_OBJACCT_PREFIX
, DMU_OBJACCT_PREFIX_LEN
+ 1);
269 offset
= DMU_OBJACCT_PREFIX_LEN
;
272 err
= zfs_id_to_fuidstr(zfsvfs
, domain
, rid
, buf
+ offset
,
273 sizeof (buf
) - offset
, B_FALSE
);
277 err
= zap_lookup(zfsvfs
->z_os
, obj
, buf
, 8, 1, valp
);
284 zfs_set_userquota(zfsvfs_t
*zfsvfs
, zfs_userquota_prop_t type
,
285 const char *domain
, uint64_t rid
, uint64_t quota
)
291 boolean_t fuid_dirtied
;
293 if (zfsvfs
->z_version
< ZPL_VERSION_USERSPACE
)
294 return (SET_ERROR(ENOTSUP
));
297 case ZFS_PROP_USERQUOTA
:
298 objp
= &zfsvfs
->z_userquota_obj
;
300 case ZFS_PROP_GROUPQUOTA
:
301 objp
= &zfsvfs
->z_groupquota_obj
;
303 case ZFS_PROP_USEROBJQUOTA
:
304 objp
= &zfsvfs
->z_userobjquota_obj
;
306 case ZFS_PROP_GROUPOBJQUOTA
:
307 objp
= &zfsvfs
->z_groupobjquota_obj
;
309 case ZFS_PROP_PROJECTQUOTA
:
310 if (!dmu_objset_projectquota_enabled(zfsvfs
->z_os
))
311 return (SET_ERROR(ENOTSUP
));
312 if (!zpl_is_valid_projid(rid
))
313 return (SET_ERROR(EINVAL
));
315 objp
= &zfsvfs
->z_projectquota_obj
;
317 case ZFS_PROP_PROJECTOBJQUOTA
:
318 if (!dmu_objset_projectquota_enabled(zfsvfs
->z_os
))
319 return (SET_ERROR(ENOTSUP
));
320 if (!zpl_is_valid_projid(rid
))
321 return (SET_ERROR(EINVAL
));
323 objp
= &zfsvfs
->z_projectobjquota_obj
;
326 return (SET_ERROR(EINVAL
));
329 err
= zfs_id_to_fuidstr(zfsvfs
, domain
, rid
, buf
, sizeof (buf
), B_TRUE
);
332 fuid_dirtied
= zfsvfs
->z_fuid_dirty
;
334 tx
= dmu_tx_create(zfsvfs
->z_os
);
335 dmu_tx_hold_zap(tx
, *objp
? *objp
: DMU_NEW_OBJECT
, B_TRUE
, NULL
);
337 dmu_tx_hold_zap(tx
, MASTER_NODE_OBJ
, B_TRUE
,
338 zfs_userquota_prop_prefixes
[type
]);
341 zfs_fuid_txhold(zfsvfs
, tx
);
342 err
= dmu_tx_assign(tx
, TXG_WAIT
);
348 mutex_enter(&zfsvfs
->z_lock
);
350 *objp
= zap_create(zfsvfs
->z_os
, DMU_OT_USERGROUP_QUOTA
,
352 VERIFY(0 == zap_add(zfsvfs
->z_os
, MASTER_NODE_OBJ
,
353 zfs_userquota_prop_prefixes
[type
], 8, 1, objp
, tx
));
355 mutex_exit(&zfsvfs
->z_lock
);
358 err
= zap_remove(zfsvfs
->z_os
, *objp
, buf
, tx
);
362 err
= zap_update(zfsvfs
->z_os
, *objp
, buf
, 8, 1, "a
, tx
);
366 zfs_fuid_sync(zfsvfs
, tx
);
372 zfs_id_overobjquota(zfsvfs_t
*zfsvfs
, uint64_t usedobj
, uint64_t id
)
374 char buf
[20 + DMU_OBJACCT_PREFIX_LEN
];
375 uint64_t used
, quota
, quotaobj
;
378 if (!dmu_objset_userobjspace_present(zfsvfs
->z_os
)) {
379 if (dmu_objset_userobjspace_upgradable(zfsvfs
->z_os
)) {
380 dsl_pool_config_enter(
381 dmu_objset_pool(zfsvfs
->z_os
), FTAG
);
382 dmu_objset_id_quota_upgrade(zfsvfs
->z_os
);
383 dsl_pool_config_exit(
384 dmu_objset_pool(zfsvfs
->z_os
), FTAG
);
389 if (usedobj
== DMU_PROJECTUSED_OBJECT
) {
390 if (!dmu_objset_projectquota_present(zfsvfs
->z_os
)) {
391 if (dmu_objset_projectquota_upgradable(zfsvfs
->z_os
)) {
392 dsl_pool_config_enter(
393 dmu_objset_pool(zfsvfs
->z_os
), FTAG
);
394 dmu_objset_id_quota_upgrade(zfsvfs
->z_os
);
395 dsl_pool_config_exit(
396 dmu_objset_pool(zfsvfs
->z_os
), FTAG
);
400 quotaobj
= zfsvfs
->z_projectobjquota_obj
;
401 } else if (usedobj
== DMU_USERUSED_OBJECT
) {
402 quotaobj
= zfsvfs
->z_userobjquota_obj
;
403 } else if (usedobj
== DMU_GROUPUSED_OBJECT
) {
404 quotaobj
= zfsvfs
->z_groupobjquota_obj
;
408 if (quotaobj
== 0 || zfsvfs
->z_replay
)
411 (void) snprintf(buf
, sizeof (buf
), "%llx", (longlong_t
)id
);
412 err
= zap_lookup(zfsvfs
->z_os
, quotaobj
, buf
, 8, 1, "a
);
416 (void) snprintf(buf
, sizeof (buf
), DMU_OBJACCT_PREFIX
"%llx",
418 err
= zap_lookup(zfsvfs
->z_os
, usedobj
, buf
, 8, 1, &used
);
421 return (used
>= quota
);
425 zfs_id_overblockquota(zfsvfs_t
*zfsvfs
, uint64_t usedobj
, uint64_t id
)
428 uint64_t used
, quota
, quotaobj
;
431 if (usedobj
== DMU_PROJECTUSED_OBJECT
) {
432 if (!dmu_objset_projectquota_present(zfsvfs
->z_os
)) {
433 if (dmu_objset_projectquota_upgradable(zfsvfs
->z_os
)) {
434 dsl_pool_config_enter(
435 dmu_objset_pool(zfsvfs
->z_os
), FTAG
);
436 dmu_objset_id_quota_upgrade(zfsvfs
->z_os
);
437 dsl_pool_config_exit(
438 dmu_objset_pool(zfsvfs
->z_os
), FTAG
);
442 quotaobj
= zfsvfs
->z_projectquota_obj
;
443 } else if (usedobj
== DMU_USERUSED_OBJECT
) {
444 quotaobj
= zfsvfs
->z_userquota_obj
;
445 } else if (usedobj
== DMU_GROUPUSED_OBJECT
) {
446 quotaobj
= zfsvfs
->z_groupquota_obj
;
450 if (quotaobj
== 0 || zfsvfs
->z_replay
)
453 (void) snprintf(buf
, sizeof (buf
), "%llx", (longlong_t
)id
);
454 err
= zap_lookup(zfsvfs
->z_os
, quotaobj
, buf
, 8, 1, "a
);
458 err
= zap_lookup(zfsvfs
->z_os
, usedobj
, buf
, 8, 1, &used
);
461 return (used
>= quota
);
465 zfs_id_overquota(zfsvfs_t
*zfsvfs
, uint64_t usedobj
, uint64_t id
)
467 return (zfs_id_overblockquota(zfsvfs
, usedobj
, id
) ||
468 zfs_id_overobjquota(zfsvfs
, usedobj
, id
));
471 EXPORT_SYMBOL(zpl_get_file_info
);
472 EXPORT_SYMBOL(zfs_userspace_one
);
473 EXPORT_SYMBOL(zfs_userspace_many
);
474 EXPORT_SYMBOL(zfs_set_userquota
);
475 EXPORT_SYMBOL(zfs_id_overblockquota
);
476 EXPORT_SYMBOL(zfs_id_overobjquota
);
477 EXPORT_SYMBOL(zfs_id_overquota
);