]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/contrib/openzfs/module/zfs/zfs_quota.c
ssh: update with post-release V_8_9 branch commits
[FreeBSD/FreeBSD.git] / sys / contrib / openzfs / module / zfs / zfs_quota.c
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) 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.
28  */
29
30 /* Portions Copyright 2010 Robert Milkowski */
31
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>
40
41 int
42 zpl_get_file_info(dmu_object_type_t bonustype, const void *data,
43     zfs_file_info_t *zoi)
44 {
45         /*
46          * Is it a valid type of object to track?
47          */
48         if (bonustype != DMU_OT_ZNODE && bonustype != DMU_OT_SA)
49                 return (SET_ERROR(ENOENT));
50
51         zoi->zfi_project = ZFS_DEFAULT_PROJID;
52
53         /*
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
58          */
59         if (data == NULL)
60                 return (SET_ERROR(EEXIST));
61
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);
68         }
69
70         const sa_hdr_phys_t *sap = data;
71         if (sap->sa_magic == 0) {
72                 /*
73                  * This should only happen for newly created files
74                  * that haven't had the znode data filled in yet.
75                  */
76                 zoi->zfi_user = 0;
77                 zoi->zfi_group = 0;
78                 zoi->zfi_generation = 0;
79                 return (0);
80         }
81
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;
88         }
89         VERIFY3U(sa.sa_magic, ==, SA_MAGIC);
90
91         int hdrsize = sa_hdrsize(&sa);
92         VERIFY3U(hdrsize, >=, sizeof (sa_hdr_phys_t));
93
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);
101
102         if (flags & ZFS_PROJID) {
103                 zoi->zfi_project =
104                     *((uint64_t *)(data_after_hdr + SA_PROJID_OFFSET));
105         }
106
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);
112         }
113         return (0);
114 }
115
116 static void
117 fuidstr_to_sid(zfsvfs_t *zfsvfs, const char *fuidstr,
118     char *domainbuf, int buflen, uid_t *ridp)
119 {
120         uint64_t fuid;
121         const char *domain;
122
123         fuid = zfs_strtonum(fuidstr, NULL);
124
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);
131 }
132
133 static uint64_t
134 zfs_userquota_prop_to_obj(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type)
135 {
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);
160         }
161 }
162
163 int
164 zfs_userspace_many(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type,
165     uint64_t *cookiep, void *vbuf, uint64_t *bufsizep)
166 {
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;
173
174         if (!dmu_objset_userspace_present(zfsvfs->z_os))
175                 return (SET_ERROR(ENOTSUP));
176
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));
182
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));
189
190         obj = zfs_userquota_prop_to_obj(zfsvfs, type);
191         if (obj == ZFS_NO_OBJECT) {
192                 *bufsizep = 0;
193                 return (0);
194         }
195
196         if (type == ZFS_PROP_USEROBJUSED || type == ZFS_PROP_GROUPOBJUSED ||
197             type == ZFS_PROP_PROJECTOBJUSED)
198                 offset = DMU_OBJACCT_PREFIX_LEN;
199
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;
206
207                 /*
208                  * skip object quota (with zap name prefix DMU_OBJACCT_PREFIX)
209                  * when dealing with block quota and vice versa.
210                  */
211                 if ((offset > 0) != (strncmp(za.za_name, DMU_OBJACCT_PREFIX,
212                     DMU_OBJACCT_PREFIX_LEN) == 0))
213                         continue;
214
215                 fuidstr_to_sid(zfsvfs, za.za_name + offset,
216                     buf->zu_domain, sizeof (buf->zu_domain), &buf->zu_rid);
217
218                 buf->zu_space = za.za_first_integer;
219                 buf++;
220         }
221         if (error == ENOENT)
222                 error = 0;
223
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);
229 }
230
231 int
232 zfs_userspace_one(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type,
233     const char *domain, uint64_t rid, uint64_t *valp)
234 {
235         char buf[20 + DMU_OBJACCT_PREFIX_LEN];
236         int offset = 0;
237         int err;
238         uint64_t obj;
239
240         *valp = 0;
241
242         if (!dmu_objset_userspace_present(zfsvfs->z_os))
243                 return (SET_ERROR(ENOTSUP));
244
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));
251
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));
259         }
260
261         obj = zfs_userquota_prop_to_obj(zfsvfs, type);
262         if (obj == ZFS_NO_OBJECT)
263                 return (0);
264
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;
269         }
270
271         err = zfs_id_to_fuidstr(zfsvfs, domain, rid, buf + offset,
272             sizeof (buf) - offset, B_FALSE);
273         if (err)
274                 return (err);
275
276         err = zap_lookup(zfsvfs->z_os, obj, buf, 8, 1, valp);
277         if (err == ENOENT)
278                 err = 0;
279         return (err);
280 }
281
282 int
283 zfs_set_userquota(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type,
284     const char *domain, uint64_t rid, uint64_t quota)
285 {
286         char buf[32];
287         int err;
288         dmu_tx_t *tx;
289         uint64_t *objp;
290         boolean_t fuid_dirtied;
291
292         if (zfsvfs->z_version < ZPL_VERSION_USERSPACE)
293                 return (SET_ERROR(ENOTSUP));
294
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));
313
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));
321
322                 objp = &zfsvfs->z_projectobjquota_obj;
323                 break;
324         default:
325                 return (SET_ERROR(EINVAL));
326         }
327
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;
332
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]);
338         }
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);
345         }
346
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));
353         }
354         mutex_exit(&zfsvfs->z_lock);
355
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);
362         }
363         ASSERT(err == 0);
364         if (fuid_dirtied)
365                 zfs_fuid_sync(zfsvfs, tx);
366         dmu_tx_commit(tx);
367         return (err);
368 }
369
370 boolean_t
371 zfs_id_overobjquota(zfsvfs_t *zfsvfs, uint64_t usedobj, uint64_t id)
372 {
373         char buf[20 + DMU_OBJACCT_PREFIX_LEN];
374         uint64_t used, quota, quotaobj;
375         int err;
376
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);
384                 }
385                 return (B_FALSE);
386         }
387
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);
396                         }
397                         return (B_FALSE);
398                 }
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);
406         }
407         if (quotaobj == 0 || zfsvfs->z_replay)
408                 return (B_FALSE);
409
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);
414
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);
421 }
422
423 boolean_t
424 zfs_id_overblockquota(zfsvfs_t *zfsvfs, uint64_t usedobj, uint64_t id)
425 {
426         char buf[20];
427         uint64_t used, quota, quotaobj;
428         int err;
429
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);
438                         }
439                         return (B_FALSE);
440                 }
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);
448         }
449         if (quotaobj == 0 || zfsvfs->z_replay)
450                 return (B_FALSE);
451
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);
456
457         err = zap_lookup(zfsvfs->z_os, usedobj, buf, 8, 1, &used);
458         if (err != 0)
459                 return (B_FALSE);
460         return (used >= quota);
461 }
462
463 boolean_t
464 zfs_id_overquota(zfsvfs_t *zfsvfs, uint64_t usedobj, uint64_t id)
465 {
466         return (zfs_id_overblockquota(zfsvfs, usedobj, id) ||
467             zfs_id_overobjquota(zfsvfs, usedobj, id));
468 }
469
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);