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 http://www.opensolaris.org/os/licensing.
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 <pawel@dawidek.net>.
24 * All rights reserved.
25 * Copyright (c) 2012, 2015, 2018 by Delphix. All rights reserved.
26 * Copyright (c) 2014 Integros [integros.com]
27 * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
30 /* Portions Copyright 2010 Robert Milkowski */
33 #include <sys/dmu_objset.h>
35 #include <sys/sa_impl.h>
37 #include <sys/zfs_project.h>
38 #include <sys/zfs_quota.h>
39 #include <sys/zfs_znode.h>
42 zpl_get_file_info(dmu_object_type_t bonustype
, const void *data
,
46 * Is it a valid type of object to track?
48 if (bonustype
!= DMU_OT_ZNODE
&& bonustype
!= DMU_OT_SA
)
49 return (SET_ERROR(ENOENT
));
51 zoi
->zfi_project
= ZFS_DEFAULT_PROJID
;
54 * If we have a NULL data pointer
55 * then assume the id's aren't changing and
56 * return EEXIST to the dmu to let it know to
60 return (SET_ERROR(EEXIST
));
62 if (bonustype
== DMU_OT_ZNODE
) {
63 const znode_phys_t
*znp
= data
;
64 zoi
->zfi_user
= znp
->zp_uid
;
65 zoi
->zfi_group
= znp
->zp_gid
;
66 zoi
->zfi_generation
= znp
->zp_gen
;
70 const sa_hdr_phys_t
*sap
= data
;
71 if (sap
->sa_magic
== 0) {
73 * This should only happen for newly created files
74 * that haven't had the znode data filled in yet.
78 zoi
->zfi_generation
= 0;
82 sa_hdr_phys_t sa
= *sap
;
83 boolean_t swap
= B_FALSE
;
84 if (sa
.sa_magic
== BSWAP_32(SA_MAGIC
)) {
85 sa
.sa_magic
= SA_MAGIC
;
86 sa
.sa_layout_info
= BSWAP_16(sa
.sa_layout_info
);
89 VERIFY3U(sa
.sa_magic
, ==, SA_MAGIC
);
91 int hdrsize
= sa_hdrsize(&sa
);
92 VERIFY3U(hdrsize
, >=, sizeof (sa_hdr_phys_t
));
94 uintptr_t data_after_hdr
= (uintptr_t)data
+ hdrsize
;
95 zoi
->zfi_user
= *((uint64_t *)(data_after_hdr
+ SA_UID_OFFSET
));
96 zoi
->zfi_group
= *((uint64_t *)(data_after_hdr
+ SA_GID_OFFSET
));
97 zoi
->zfi_generation
= *((uint64_t *)(data_after_hdr
+ SA_GEN_OFFSET
));
98 uint64_t flags
= *((uint64_t *)(data_after_hdr
+ SA_FLAGS_OFFSET
));
100 flags
= BSWAP_64(flags
);
102 if (flags
& ZFS_PROJID
) {
104 *((uint64_t *)(data_after_hdr
+ SA_PROJID_OFFSET
));
108 zoi
->zfi_user
= BSWAP_64(zoi
->zfi_user
);
109 zoi
->zfi_group
= BSWAP_64(zoi
->zfi_group
);
110 zoi
->zfi_project
= BSWAP_64(zoi
->zfi_project
);
111 zoi
->zfi_generation
= BSWAP_64(zoi
->zfi_generation
);
117 fuidstr_to_sid(zfsvfs_t
*zfsvfs
, const char *fuidstr
,
118 char *domainbuf
, int buflen
, uid_t
*ridp
)
123 fuid
= zfs_strtonum(fuidstr
, NULL
);
125 domain
= zfs_fuid_find_by_idx(zfsvfs
, FUID_INDEX(fuid
));
127 (void) strlcpy(domainbuf
, domain
, buflen
);
130 *ridp
= FUID_RID(fuid
);
134 zfs_userquota_prop_to_obj(zfsvfs_t
*zfsvfs
, zfs_userquota_prop_t type
)
137 case ZFS_PROP_USERUSED
:
138 case ZFS_PROP_USEROBJUSED
:
139 return (DMU_USERUSED_OBJECT
);
140 case ZFS_PROP_GROUPUSED
:
141 case ZFS_PROP_GROUPOBJUSED
:
142 return (DMU_GROUPUSED_OBJECT
);
143 case ZFS_PROP_PROJECTUSED
:
144 case ZFS_PROP_PROJECTOBJUSED
:
145 return (DMU_PROJECTUSED_OBJECT
);
146 case ZFS_PROP_USERQUOTA
:
147 return (zfsvfs
->z_userquota_obj
);
148 case ZFS_PROP_GROUPQUOTA
:
149 return (zfsvfs
->z_groupquota_obj
);
150 case ZFS_PROP_USEROBJQUOTA
:
151 return (zfsvfs
->z_userobjquota_obj
);
152 case ZFS_PROP_GROUPOBJQUOTA
:
153 return (zfsvfs
->z_groupobjquota_obj
);
154 case ZFS_PROP_PROJECTQUOTA
:
155 return (zfsvfs
->z_projectquota_obj
);
156 case ZFS_PROP_PROJECTOBJQUOTA
:
157 return (zfsvfs
->z_projectobjquota_obj
);
159 return (ZFS_NO_OBJECT
);
164 zfs_userspace_many(zfsvfs_t
*zfsvfs
, zfs_userquota_prop_t type
,
165 uint64_t *cookiep
, void *vbuf
, uint64_t *bufsizep
)
170 zfs_useracct_t
*buf
= vbuf
;
174 if (!dmu_objset_userspace_present(zfsvfs
->z_os
))
175 return (SET_ERROR(ENOTSUP
));
177 if ((type
== ZFS_PROP_PROJECTQUOTA
|| type
== ZFS_PROP_PROJECTUSED
||
178 type
== ZFS_PROP_PROJECTOBJQUOTA
||
179 type
== ZFS_PROP_PROJECTOBJUSED
) &&
180 !dmu_objset_projectquota_present(zfsvfs
->z_os
))
181 return (SET_ERROR(ENOTSUP
));
183 if ((type
== ZFS_PROP_USEROBJUSED
|| type
== ZFS_PROP_GROUPOBJUSED
||
184 type
== ZFS_PROP_USEROBJQUOTA
|| type
== ZFS_PROP_GROUPOBJQUOTA
||
185 type
== ZFS_PROP_PROJECTOBJUSED
||
186 type
== ZFS_PROP_PROJECTOBJQUOTA
) &&
187 !dmu_objset_userobjspace_present(zfsvfs
->z_os
))
188 return (SET_ERROR(ENOTSUP
));
190 obj
= zfs_userquota_prop_to_obj(zfsvfs
, type
);
191 if (obj
== ZFS_NO_OBJECT
) {
196 if (type
== ZFS_PROP_USEROBJUSED
|| type
== ZFS_PROP_GROUPOBJUSED
||
197 type
== ZFS_PROP_PROJECTOBJUSED
)
198 offset
= DMU_OBJACCT_PREFIX_LEN
;
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
);
232 zfs_userspace_one(zfsvfs_t
*zfsvfs
, zfs_userquota_prop_t type
,
233 const char *domain
, uint64_t rid
, uint64_t *valp
)
235 char buf
[20 + DMU_OBJACCT_PREFIX_LEN
];
242 if (!dmu_objset_userspace_present(zfsvfs
->z_os
))
243 return (SET_ERROR(ENOTSUP
));
245 if ((type
== ZFS_PROP_USEROBJUSED
|| type
== ZFS_PROP_GROUPOBJUSED
||
246 type
== ZFS_PROP_USEROBJQUOTA
|| type
== ZFS_PROP_GROUPOBJQUOTA
||
247 type
== ZFS_PROP_PROJECTOBJUSED
||
248 type
== ZFS_PROP_PROJECTOBJQUOTA
) &&
249 !dmu_objset_userobjspace_present(zfsvfs
->z_os
))
250 return (SET_ERROR(ENOTSUP
));
252 if (type
== ZFS_PROP_PROJECTQUOTA
|| type
== ZFS_PROP_PROJECTUSED
||
253 type
== ZFS_PROP_PROJECTOBJQUOTA
||
254 type
== ZFS_PROP_PROJECTOBJUSED
) {
255 if (!dmu_objset_projectquota_present(zfsvfs
->z_os
))
256 return (SET_ERROR(ENOTSUP
));
257 if (!zpl_is_valid_projid(rid
))
258 return (SET_ERROR(EINVAL
));
261 obj
= zfs_userquota_prop_to_obj(zfsvfs
, type
);
262 if (obj
== ZFS_NO_OBJECT
)
265 if (type
== ZFS_PROP_USEROBJUSED
|| type
== ZFS_PROP_GROUPOBJUSED
||
266 type
== ZFS_PROP_PROJECTOBJUSED
) {
267 strlcpy(buf
, DMU_OBJACCT_PREFIX
, DMU_OBJACCT_PREFIX_LEN
+ 1);
268 offset
= DMU_OBJACCT_PREFIX_LEN
;
271 err
= zfs_id_to_fuidstr(zfsvfs
, domain
, rid
, buf
+ offset
,
272 sizeof (buf
) - offset
, B_FALSE
);
276 err
= zap_lookup(zfsvfs
->z_os
, obj
, buf
, 8, 1, valp
);
283 zfs_set_userquota(zfsvfs_t
*zfsvfs
, zfs_userquota_prop_t type
,
284 const char *domain
, uint64_t rid
, uint64_t quota
)
290 boolean_t fuid_dirtied
;
292 if (zfsvfs
->z_version
< ZPL_VERSION_USERSPACE
)
293 return (SET_ERROR(ENOTSUP
));
296 case ZFS_PROP_USERQUOTA
:
297 objp
= &zfsvfs
->z_userquota_obj
;
299 case ZFS_PROP_GROUPQUOTA
:
300 objp
= &zfsvfs
->z_groupquota_obj
;
302 case ZFS_PROP_USEROBJQUOTA
:
303 objp
= &zfsvfs
->z_userobjquota_obj
;
305 case ZFS_PROP_GROUPOBJQUOTA
:
306 objp
= &zfsvfs
->z_groupobjquota_obj
;
308 case ZFS_PROP_PROJECTQUOTA
:
309 if (!dmu_objset_projectquota_enabled(zfsvfs
->z_os
))
310 return (SET_ERROR(ENOTSUP
));
311 if (!zpl_is_valid_projid(rid
))
312 return (SET_ERROR(EINVAL
));
314 objp
= &zfsvfs
->z_projectquota_obj
;
316 case ZFS_PROP_PROJECTOBJQUOTA
:
317 if (!dmu_objset_projectquota_enabled(zfsvfs
->z_os
))
318 return (SET_ERROR(ENOTSUP
));
319 if (!zpl_is_valid_projid(rid
))
320 return (SET_ERROR(EINVAL
));
322 objp
= &zfsvfs
->z_projectobjquota_obj
;
325 return (SET_ERROR(EINVAL
));
328 err
= zfs_id_to_fuidstr(zfsvfs
, domain
, rid
, buf
, sizeof (buf
), B_TRUE
);
331 fuid_dirtied
= zfsvfs
->z_fuid_dirty
;
333 tx
= dmu_tx_create(zfsvfs
->z_os
);
334 dmu_tx_hold_zap(tx
, *objp
? *objp
: DMU_NEW_OBJECT
, B_TRUE
, NULL
);
336 dmu_tx_hold_zap(tx
, MASTER_NODE_OBJ
, B_TRUE
,
337 zfs_userquota_prop_prefixes
[type
]);
340 zfs_fuid_txhold(zfsvfs
, tx
);
341 err
= dmu_tx_assign(tx
, TXG_WAIT
);
347 mutex_enter(&zfsvfs
->z_lock
);
349 *objp
= zap_create(zfsvfs
->z_os
, DMU_OT_USERGROUP_QUOTA
,
351 VERIFY(0 == zap_add(zfsvfs
->z_os
, MASTER_NODE_OBJ
,
352 zfs_userquota_prop_prefixes
[type
], 8, 1, objp
, tx
));
354 mutex_exit(&zfsvfs
->z_lock
);
357 err
= zap_remove(zfsvfs
->z_os
, *objp
, buf
, tx
);
361 err
= zap_update(zfsvfs
->z_os
, *objp
, buf
, 8, 1, "a
, tx
);
365 zfs_fuid_sync(zfsvfs
, tx
);
371 zfs_id_overobjquota(zfsvfs_t
*zfsvfs
, uint64_t usedobj
, uint64_t id
)
373 char buf
[20 + DMU_OBJACCT_PREFIX_LEN
];
374 uint64_t used
, quota
, quotaobj
;
377 if (!dmu_objset_userobjspace_present(zfsvfs
->z_os
)) {
378 if (dmu_objset_userobjspace_upgradable(zfsvfs
->z_os
)) {
379 dsl_pool_config_enter(
380 dmu_objset_pool(zfsvfs
->z_os
), FTAG
);
381 dmu_objset_id_quota_upgrade(zfsvfs
->z_os
);
382 dsl_pool_config_exit(
383 dmu_objset_pool(zfsvfs
->z_os
), FTAG
);
388 if (usedobj
== DMU_PROJECTUSED_OBJECT
) {
389 if (!dmu_objset_projectquota_present(zfsvfs
->z_os
)) {
390 if (dmu_objset_projectquota_upgradable(zfsvfs
->z_os
)) {
391 dsl_pool_config_enter(
392 dmu_objset_pool(zfsvfs
->z_os
), FTAG
);
393 dmu_objset_id_quota_upgrade(zfsvfs
->z_os
);
394 dsl_pool_config_exit(
395 dmu_objset_pool(zfsvfs
->z_os
), FTAG
);
399 quotaobj
= zfsvfs
->z_projectobjquota_obj
;
400 } else if (usedobj
== DMU_USERUSED_OBJECT
) {
401 quotaobj
= zfsvfs
->z_userobjquota_obj
;
402 } else if (usedobj
== DMU_GROUPUSED_OBJECT
) {
403 quotaobj
= zfsvfs
->z_groupobjquota_obj
;
407 if (quotaobj
== 0 || zfsvfs
->z_replay
)
410 (void) snprintf(buf
, sizeof (buf
), "%llx", (longlong_t
)id
);
411 err
= zap_lookup(zfsvfs
->z_os
, quotaobj
, buf
, 8, 1, "a
);
415 (void) snprintf(buf
, sizeof (buf
), DMU_OBJACCT_PREFIX
"%llx",
417 err
= zap_lookup(zfsvfs
->z_os
, usedobj
, buf
, 8, 1, &used
);
420 return (used
>= quota
);
424 zfs_id_overblockquota(zfsvfs_t
*zfsvfs
, uint64_t usedobj
, uint64_t id
)
427 uint64_t used
, quota
, quotaobj
;
430 if (usedobj
== DMU_PROJECTUSED_OBJECT
) {
431 if (!dmu_objset_projectquota_present(zfsvfs
->z_os
)) {
432 if (dmu_objset_projectquota_upgradable(zfsvfs
->z_os
)) {
433 dsl_pool_config_enter(
434 dmu_objset_pool(zfsvfs
->z_os
), FTAG
);
435 dmu_objset_id_quota_upgrade(zfsvfs
->z_os
);
436 dsl_pool_config_exit(
437 dmu_objset_pool(zfsvfs
->z_os
), FTAG
);
441 quotaobj
= zfsvfs
->z_projectquota_obj
;
442 } else if (usedobj
== DMU_USERUSED_OBJECT
) {
443 quotaobj
= zfsvfs
->z_userquota_obj
;
444 } else if (usedobj
== DMU_GROUPUSED_OBJECT
) {
445 quotaobj
= zfsvfs
->z_groupquota_obj
;
449 if (quotaobj
== 0 || zfsvfs
->z_replay
)
452 (void) snprintf(buf
, sizeof (buf
), "%llx", (longlong_t
)id
);
453 err
= zap_lookup(zfsvfs
->z_os
, quotaobj
, buf
, 8, 1, "a
);
457 err
= zap_lookup(zfsvfs
->z_os
, usedobj
, buf
, 8, 1, &used
);
460 return (used
>= quota
);
464 zfs_id_overquota(zfsvfs_t
*zfsvfs
, uint64_t usedobj
, uint64_t id
)
466 return (zfs_id_overblockquota(zfsvfs
, usedobj
, id
) ||
467 zfs_id_overobjquota(zfsvfs
, usedobj
, id
));
470 EXPORT_SYMBOL(zpl_get_file_info
);
471 EXPORT_SYMBOL(zfs_userspace_one
);
472 EXPORT_SYMBOL(zfs_userspace_many
);
473 EXPORT_SYMBOL(zfs_set_userquota
);
474 EXPORT_SYMBOL(zfs_id_overblockquota
);
475 EXPORT_SYMBOL(zfs_id_overobjquota
);
476 EXPORT_SYMBOL(zfs_id_overquota
);