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 for (zap_cursor_init_serialized(&zc
, zfsvfs
->z_os
, obj
, *cookiep
);
200 (error
= zap_cursor_retrieve(&zc
, &za
)) == 0;
201 zap_cursor_advance(&zc
)) {
202 if ((uintptr_t)buf
- (uintptr_t)vbuf
+ sizeof (zfs_useracct_t
) >
207 * skip object quota (with zap name prefix DMU_OBJACCT_PREFIX)
208 * when dealing with block quota and vice versa.
210 if ((offset
> 0) != (strncmp(za
.za_name
, DMU_OBJACCT_PREFIX
,
211 DMU_OBJACCT_PREFIX_LEN
) == 0))
214 fuidstr_to_sid(zfsvfs
, za
.za_name
+ offset
,
215 buf
->zu_domain
, sizeof (buf
->zu_domain
), &buf
->zu_rid
);
217 buf
->zu_space
= za
.za_first_integer
;
223 ASSERT3U((uintptr_t)buf
- (uintptr_t)vbuf
, <=, *bufsizep
);
224 *bufsizep
= (uintptr_t)buf
- (uintptr_t)vbuf
;
225 *cookiep
= zap_cursor_serialize(&zc
);
226 zap_cursor_fini(&zc
);
231 zfs_userspace_one(zfsvfs_t
*zfsvfs
, zfs_userquota_prop_t type
,
232 const char *domain
, uint64_t rid
, uint64_t *valp
)
234 char buf
[20 + DMU_OBJACCT_PREFIX_LEN
];
241 if (!dmu_objset_userspace_present(zfsvfs
->z_os
))
242 return (SET_ERROR(ENOTSUP
));
244 if ((type
== ZFS_PROP_USEROBJUSED
|| type
== ZFS_PROP_GROUPOBJUSED
||
245 type
== ZFS_PROP_USEROBJQUOTA
|| type
== ZFS_PROP_GROUPOBJQUOTA
||
246 type
== ZFS_PROP_PROJECTOBJUSED
||
247 type
== ZFS_PROP_PROJECTOBJQUOTA
) &&
248 !dmu_objset_userobjspace_present(zfsvfs
->z_os
))
249 return (SET_ERROR(ENOTSUP
));
251 if (type
== ZFS_PROP_PROJECTQUOTA
|| type
== ZFS_PROP_PROJECTUSED
||
252 type
== ZFS_PROP_PROJECTOBJQUOTA
||
253 type
== ZFS_PROP_PROJECTOBJUSED
) {
254 if (!dmu_objset_projectquota_present(zfsvfs
->z_os
))
255 return (SET_ERROR(ENOTSUP
));
256 if (!zpl_is_valid_projid(rid
))
257 return (SET_ERROR(EINVAL
));
260 obj
= zfs_userquota_prop_to_obj(zfsvfs
, type
);
261 if (obj
== ZFS_NO_OBJECT
)
264 if (type
== ZFS_PROP_USEROBJUSED
|| type
== ZFS_PROP_GROUPOBJUSED
||
265 type
== ZFS_PROP_PROJECTOBJUSED
) {
266 strlcpy(buf
, DMU_OBJACCT_PREFIX
, DMU_OBJACCT_PREFIX_LEN
+ 1);
267 offset
= DMU_OBJACCT_PREFIX_LEN
;
270 err
= zfs_id_to_fuidstr(zfsvfs
, domain
, rid
, buf
+ offset
,
271 sizeof (buf
) - offset
, B_FALSE
);
275 err
= zap_lookup(zfsvfs
->z_os
, obj
, buf
, 8, 1, valp
);
282 zfs_set_userquota(zfsvfs_t
*zfsvfs
, zfs_userquota_prop_t type
,
283 const char *domain
, uint64_t rid
, uint64_t quota
)
289 boolean_t fuid_dirtied
;
291 if (zfsvfs
->z_version
< ZPL_VERSION_USERSPACE
)
292 return (SET_ERROR(ENOTSUP
));
295 case ZFS_PROP_USERQUOTA
:
296 objp
= &zfsvfs
->z_userquota_obj
;
298 case ZFS_PROP_GROUPQUOTA
:
299 objp
= &zfsvfs
->z_groupquota_obj
;
301 case ZFS_PROP_USEROBJQUOTA
:
302 objp
= &zfsvfs
->z_userobjquota_obj
;
304 case ZFS_PROP_GROUPOBJQUOTA
:
305 objp
= &zfsvfs
->z_groupobjquota_obj
;
307 case ZFS_PROP_PROJECTQUOTA
:
308 if (!dmu_objset_projectquota_enabled(zfsvfs
->z_os
))
309 return (SET_ERROR(ENOTSUP
));
310 if (!zpl_is_valid_projid(rid
))
311 return (SET_ERROR(EINVAL
));
313 objp
= &zfsvfs
->z_projectquota_obj
;
315 case ZFS_PROP_PROJECTOBJQUOTA
:
316 if (!dmu_objset_projectquota_enabled(zfsvfs
->z_os
))
317 return (SET_ERROR(ENOTSUP
));
318 if (!zpl_is_valid_projid(rid
))
319 return (SET_ERROR(EINVAL
));
321 objp
= &zfsvfs
->z_projectobjquota_obj
;
324 return (SET_ERROR(EINVAL
));
327 err
= zfs_id_to_fuidstr(zfsvfs
, domain
, rid
, buf
, sizeof (buf
), B_TRUE
);
330 fuid_dirtied
= zfsvfs
->z_fuid_dirty
;
332 tx
= dmu_tx_create(zfsvfs
->z_os
);
333 dmu_tx_hold_zap(tx
, *objp
? *objp
: DMU_NEW_OBJECT
, B_TRUE
, NULL
);
335 dmu_tx_hold_zap(tx
, MASTER_NODE_OBJ
, B_TRUE
,
336 zfs_userquota_prop_prefixes
[type
]);
339 zfs_fuid_txhold(zfsvfs
, tx
);
340 err
= dmu_tx_assign(tx
, TXG_WAIT
);
346 mutex_enter(&zfsvfs
->z_lock
);
348 *objp
= zap_create(zfsvfs
->z_os
, DMU_OT_USERGROUP_QUOTA
,
350 VERIFY(0 == zap_add(zfsvfs
->z_os
, MASTER_NODE_OBJ
,
351 zfs_userquota_prop_prefixes
[type
], 8, 1, objp
, tx
));
353 mutex_exit(&zfsvfs
->z_lock
);
356 err
= zap_remove(zfsvfs
->z_os
, *objp
, buf
, tx
);
360 err
= zap_update(zfsvfs
->z_os
, *objp
, buf
, 8, 1, "a
, tx
);
364 zfs_fuid_sync(zfsvfs
, tx
);
370 zfs_id_overobjquota(zfsvfs_t
*zfsvfs
, uint64_t usedobj
, uint64_t id
)
372 char buf
[20 + DMU_OBJACCT_PREFIX_LEN
];
373 uint64_t used
, quota
, quotaobj
;
376 if (!dmu_objset_userobjspace_present(zfsvfs
->z_os
)) {
377 if (dmu_objset_userobjspace_upgradable(zfsvfs
->z_os
)) {
378 dsl_pool_config_enter(
379 dmu_objset_pool(zfsvfs
->z_os
), FTAG
);
380 dmu_objset_id_quota_upgrade(zfsvfs
->z_os
);
381 dsl_pool_config_exit(
382 dmu_objset_pool(zfsvfs
->z_os
), FTAG
);
387 if (usedobj
== DMU_PROJECTUSED_OBJECT
) {
388 if (!dmu_objset_projectquota_present(zfsvfs
->z_os
)) {
389 if (dmu_objset_projectquota_upgradable(zfsvfs
->z_os
)) {
390 dsl_pool_config_enter(
391 dmu_objset_pool(zfsvfs
->z_os
), FTAG
);
392 dmu_objset_id_quota_upgrade(zfsvfs
->z_os
);
393 dsl_pool_config_exit(
394 dmu_objset_pool(zfsvfs
->z_os
), FTAG
);
398 quotaobj
= zfsvfs
->z_projectobjquota_obj
;
399 } else if (usedobj
== DMU_USERUSED_OBJECT
) {
400 quotaobj
= zfsvfs
->z_userobjquota_obj
;
401 } else if (usedobj
== DMU_GROUPUSED_OBJECT
) {
402 quotaobj
= zfsvfs
->z_groupobjquota_obj
;
406 if (quotaobj
== 0 || zfsvfs
->z_replay
)
409 (void) snprintf(buf
, sizeof (buf
), "%llx", (longlong_t
)id
);
410 err
= zap_lookup(zfsvfs
->z_os
, quotaobj
, buf
, 8, 1, "a
);
414 (void) snprintf(buf
, sizeof (buf
), DMU_OBJACCT_PREFIX
"%llx",
416 err
= zap_lookup(zfsvfs
->z_os
, usedobj
, buf
, 8, 1, &used
);
419 return (used
>= quota
);
423 zfs_id_overblockquota(zfsvfs_t
*zfsvfs
, uint64_t usedobj
, uint64_t id
)
426 uint64_t used
, quota
, quotaobj
;
429 if (usedobj
== DMU_PROJECTUSED_OBJECT
) {
430 if (!dmu_objset_projectquota_present(zfsvfs
->z_os
)) {
431 if (dmu_objset_projectquota_upgradable(zfsvfs
->z_os
)) {
432 dsl_pool_config_enter(
433 dmu_objset_pool(zfsvfs
->z_os
), FTAG
);
434 dmu_objset_id_quota_upgrade(zfsvfs
->z_os
);
435 dsl_pool_config_exit(
436 dmu_objset_pool(zfsvfs
->z_os
), FTAG
);
440 quotaobj
= zfsvfs
->z_projectquota_obj
;
441 } else if (usedobj
== DMU_USERUSED_OBJECT
) {
442 quotaobj
= zfsvfs
->z_userquota_obj
;
443 } else if (usedobj
== DMU_GROUPUSED_OBJECT
) {
444 quotaobj
= zfsvfs
->z_groupquota_obj
;
448 if (quotaobj
== 0 || zfsvfs
->z_replay
)
451 (void) snprintf(buf
, sizeof (buf
), "%llx", (longlong_t
)id
);
452 err
= zap_lookup(zfsvfs
->z_os
, quotaobj
, buf
, 8, 1, "a
);
456 err
= zap_lookup(zfsvfs
->z_os
, usedobj
, buf
, 8, 1, &used
);
459 return (used
>= quota
);
463 zfs_id_overquota(zfsvfs_t
*zfsvfs
, uint64_t usedobj
, uint64_t id
)
465 return (zfs_id_overblockquota(zfsvfs
, usedobj
, id
) ||
466 zfs_id_overobjquota(zfsvfs
, usedobj
, id
));
469 EXPORT_SYMBOL(zpl_get_file_info
);
470 EXPORT_SYMBOL(zfs_userspace_one
);
471 EXPORT_SYMBOL(zfs_userspace_many
);
472 EXPORT_SYMBOL(zfs_set_userquota
);
473 EXPORT_SYMBOL(zfs_id_overblockquota
);
474 EXPORT_SYMBOL(zfs_id_overobjquota
);
475 EXPORT_SYMBOL(zfs_id_overquota
);