Allow disabling of unmapped I/O on FreeBSD
[zfs.git] / module / zfs / zfs_quota.c
blobe61db5c7ab832aa75119c5928d57d08a09973619
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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 */
32 #include <sys/avl.h>
33 #include <sys/dmu_objset.h>
34 #include <sys/sa.h>
35 #include <sys/sa_impl.h>
36 #include <sys/zap.h>
37 #include <sys/zfs_project.h>
38 #include <sys/zfs_quota.h>
39 #include <sys/zfs_znode.h>
41 int
42 zpl_get_file_info(dmu_object_type_t bonustype, const void *data,
43 zfs_file_info_t *zoi)
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
57 * use the same ids
59 if (data == NULL)
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;
67 return (0);
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.
76 zoi->zfi_user = 0;
77 zoi->zfi_group = 0;
78 zoi->zfi_generation = 0;
79 return (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);
87 swap = B_TRUE;
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));
99 if (swap)
100 flags = BSWAP_64(flags);
102 if (flags & ZFS_PROJID) {
103 zoi->zfi_project =
104 *((uint64_t *)(data_after_hdr + SA_PROJID_OFFSET));
107 if (swap) {
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);
113 return (0);
116 static void
117 fuidstr_to_sid(zfsvfs_t *zfsvfs, const char *fuidstr,
118 char *domainbuf, int buflen, uid_t *ridp)
120 uint64_t fuid;
121 const char *domain;
123 fuid = zfs_strtonum(fuidstr, NULL);
125 domain = zfs_fuid_find_by_idx(zfsvfs, FUID_INDEX(fuid));
126 if (domain)
127 (void) strlcpy(domainbuf, domain, buflen);
128 else
129 domainbuf[0] = '\0';
130 *ridp = FUID_RID(fuid);
133 static uint64_t
134 zfs_userquota_prop_to_obj(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type)
136 switch (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);
158 default:
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)
167 int error;
168 zap_cursor_t zc;
169 zap_attribute_t za;
170 zfs_useracct_t *buf = vbuf;
171 uint64_t obj;
172 int offset = 0;
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) {
192 *bufsizep = 0;
193 return (0);
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) >
204 *bufsizep)
205 break;
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))
213 continue;
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;
219 buf++;
221 if (error == ENOENT)
222 error = 0;
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 return (error);
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];
236 int offset = 0;
237 int err;
238 uint64_t obj;
240 *valp = 0;
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)
263 return (0);
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);
273 if (err)
274 return (err);
276 err = zap_lookup(zfsvfs->z_os, obj, buf, 8, 1, valp);
277 if (err == ENOENT)
278 err = 0;
279 return (err);
283 zfs_set_userquota(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type,
284 const char *domain, uint64_t rid, uint64_t quota)
286 char buf[32];
287 int err;
288 dmu_tx_t *tx;
289 uint64_t *objp;
290 boolean_t fuid_dirtied;
292 if (zfsvfs->z_version < ZPL_VERSION_USERSPACE)
293 return (SET_ERROR(ENOTSUP));
295 switch (type) {
296 case ZFS_PROP_USERQUOTA:
297 objp = &zfsvfs->z_userquota_obj;
298 break;
299 case ZFS_PROP_GROUPQUOTA:
300 objp = &zfsvfs->z_groupquota_obj;
301 break;
302 case ZFS_PROP_USEROBJQUOTA:
303 objp = &zfsvfs->z_userobjquota_obj;
304 break;
305 case ZFS_PROP_GROUPOBJQUOTA:
306 objp = &zfsvfs->z_groupobjquota_obj;
307 break;
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;
315 break;
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;
323 break;
324 default:
325 return (SET_ERROR(EINVAL));
328 err = zfs_id_to_fuidstr(zfsvfs, domain, rid, buf, sizeof (buf), B_TRUE);
329 if (err)
330 return (err);
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);
335 if (*objp == 0) {
336 dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, B_TRUE,
337 zfs_userquota_prop_prefixes[type]);
339 if (fuid_dirtied)
340 zfs_fuid_txhold(zfsvfs, tx);
341 err = dmu_tx_assign(tx, TXG_WAIT);
342 if (err) {
343 dmu_tx_abort(tx);
344 return (err);
347 mutex_enter(&zfsvfs->z_lock);
348 if (*objp == 0) {
349 *objp = zap_create(zfsvfs->z_os, DMU_OT_USERGROUP_QUOTA,
350 DMU_OT_NONE, 0, tx);
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);
356 if (quota == 0) {
357 err = zap_remove(zfsvfs->z_os, *objp, buf, tx);
358 if (err == ENOENT)
359 err = 0;
360 } else {
361 err = zap_update(zfsvfs->z_os, *objp, buf, 8, 1, &quota, tx);
363 ASSERT(err == 0);
364 if (fuid_dirtied)
365 zfs_fuid_sync(zfsvfs, tx);
366 dmu_tx_commit(tx);
367 return (err);
370 boolean_t
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;
375 int err;
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);
385 return (B_FALSE);
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);
397 return (B_FALSE);
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;
404 } else {
405 return (B_FALSE);
407 if (quotaobj == 0 || zfsvfs->z_replay)
408 return (B_FALSE);
410 (void) snprintf(buf, sizeof (buf), "%llx", (longlong_t)id);
411 err = zap_lookup(zfsvfs->z_os, quotaobj, buf, 8, 1, &quota);
412 if (err != 0)
413 return (B_FALSE);
415 (void) snprintf(buf, sizeof (buf), DMU_OBJACCT_PREFIX "%llx",
416 (longlong_t)id);
417 err = zap_lookup(zfsvfs->z_os, usedobj, buf, 8, 1, &used);
418 if (err != 0)
419 return (B_FALSE);
420 return (used >= quota);
423 boolean_t
424 zfs_id_overblockquota(zfsvfs_t *zfsvfs, uint64_t usedobj, uint64_t id)
426 char buf[20];
427 uint64_t used, quota, quotaobj;
428 int err;
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);
439 return (B_FALSE);
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;
446 } else {
447 return (B_FALSE);
449 if (quotaobj == 0 || zfsvfs->z_replay)
450 return (B_FALSE);
452 (void) snprintf(buf, sizeof (buf), "%llx", (longlong_t)id);
453 err = zap_lookup(zfsvfs->z_os, quotaobj, buf, 8, 1, &quota);
454 if (err != 0)
455 return (B_FALSE);
457 err = zap_lookup(zfsvfs->z_os, usedobj, buf, 8, 1, &used);
458 if (err != 0)
459 return (B_FALSE);
460 return (used >= quota);
463 boolean_t
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);