]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/contrib/openzfs/module/zfs/zfs_quota.c
OpenSSL: update to 3.0.11
[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 https://opensource.org/licenses/CDDL-1.0.
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
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.
27  */
28
29 /* Portions Copyright 2010 Robert Milkowski */
30
31 #include <sys/avl.h>
32 #include <sys/dmu_objset.h>
33 #include <sys/sa.h>
34 #include <sys/sa_impl.h>
35 #include <sys/zap.h>
36 #include <sys/zfs_project.h>
37 #include <sys/zfs_quota.h>
38 #include <sys/zfs_znode.h>
39
40 int
41 zpl_get_file_info(dmu_object_type_t bonustype, const void *data,
42     zfs_file_info_t *zoi)
43 {
44         /*
45          * Is it a valid type of object to track?
46          */
47         if (bonustype != DMU_OT_ZNODE && bonustype != DMU_OT_SA)
48                 return (SET_ERROR(ENOENT));
49
50         zoi->zfi_project = ZFS_DEFAULT_PROJID;
51
52         /*
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
56          * use the same ids
57          */
58         if (data == NULL)
59                 return (SET_ERROR(EEXIST));
60
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;
66                 return (0);
67         }
68
69         const sa_hdr_phys_t *sap = data;
70         if (sap->sa_magic == 0) {
71                 /*
72                  * This should only happen for newly created files
73                  * that haven't had the znode data filled in yet.
74                  */
75                 zoi->zfi_user = 0;
76                 zoi->zfi_group = 0;
77                 zoi->zfi_generation = 0;
78                 return (0);
79         }
80
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);
86                 swap = B_TRUE;
87         }
88         VERIFY3U(sa.sa_magic, ==, SA_MAGIC);
89
90         int hdrsize = sa_hdrsize(&sa);
91         VERIFY3U(hdrsize, >=, sizeof (sa_hdr_phys_t));
92
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));
98         if (swap)
99                 flags = BSWAP_64(flags);
100
101         if (flags & ZFS_PROJID) {
102                 zoi->zfi_project =
103                     *((uint64_t *)(data_after_hdr + SA_PROJID_OFFSET));
104         }
105
106         if (swap) {
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);
111         }
112         return (0);
113 }
114
115 static void
116 fuidstr_to_sid(zfsvfs_t *zfsvfs, const char *fuidstr,
117     char *domainbuf, int buflen, uid_t *ridp)
118 {
119         uint64_t fuid;
120         const char *domain;
121
122         fuid = zfs_strtonum(fuidstr, NULL);
123
124         domain = zfs_fuid_find_by_idx(zfsvfs, FUID_INDEX(fuid));
125         if (domain)
126                 (void) strlcpy(domainbuf, domain, buflen);
127         else
128                 domainbuf[0] = '\0';
129         *ridp = FUID_RID(fuid);
130 }
131
132 static uint64_t
133 zfs_userquota_prop_to_obj(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type)
134 {
135         switch (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);
157         default:
158                 return (ZFS_NO_OBJECT);
159         }
160 }
161
162 int
163 zfs_userspace_many(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type,
164     uint64_t *cookiep, void *vbuf, uint64_t *bufsizep)
165 {
166         int error;
167         zap_cursor_t zc;
168         zap_attribute_t za;
169         zfs_useracct_t *buf = vbuf;
170         uint64_t obj;
171         int offset = 0;
172
173         if (!dmu_objset_userspace_present(zfsvfs->z_os))
174                 return (SET_ERROR(ENOTSUP));
175
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));
181
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));
188
189         obj = zfs_userquota_prop_to_obj(zfsvfs, type);
190         if (obj == ZFS_NO_OBJECT) {
191                 *bufsizep = 0;
192                 return (0);
193         }
194
195         if (type == ZFS_PROP_USEROBJUSED || type == ZFS_PROP_GROUPOBJUSED ||
196             type == ZFS_PROP_PROJECTOBJUSED)
197                 offset = DMU_OBJACCT_PREFIX_LEN;
198
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) >
203                     *bufsizep)
204                         break;
205
206                 /*
207                  * skip object quota (with zap name prefix DMU_OBJACCT_PREFIX)
208                  * when dealing with block quota and vice versa.
209                  */
210                 if ((offset > 0) != (strncmp(za.za_name, DMU_OBJACCT_PREFIX,
211                     DMU_OBJACCT_PREFIX_LEN) == 0))
212                         continue;
213
214                 fuidstr_to_sid(zfsvfs, za.za_name + offset,
215                     buf->zu_domain, sizeof (buf->zu_domain), &buf->zu_rid);
216
217                 buf->zu_space = za.za_first_integer;
218                 buf++;
219         }
220         if (error == ENOENT)
221                 error = 0;
222
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);
227         return (error);
228 }
229
230 int
231 zfs_userspace_one(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type,
232     const char *domain, uint64_t rid, uint64_t *valp)
233 {
234         char buf[20 + DMU_OBJACCT_PREFIX_LEN];
235         int offset = 0;
236         int err;
237         uint64_t obj;
238
239         *valp = 0;
240
241         if (!dmu_objset_userspace_present(zfsvfs->z_os))
242                 return (SET_ERROR(ENOTSUP));
243
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));
250
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));
258         }
259
260         obj = zfs_userquota_prop_to_obj(zfsvfs, type);
261         if (obj == ZFS_NO_OBJECT)
262                 return (0);
263
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;
268         }
269
270         err = zfs_id_to_fuidstr(zfsvfs, domain, rid, buf + offset,
271             sizeof (buf) - offset, B_FALSE);
272         if (err)
273                 return (err);
274
275         err = zap_lookup(zfsvfs->z_os, obj, buf, 8, 1, valp);
276         if (err == ENOENT)
277                 err = 0;
278         return (err);
279 }
280
281 int
282 zfs_set_userquota(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type,
283     const char *domain, uint64_t rid, uint64_t quota)
284 {
285         char buf[32];
286         int err;
287         dmu_tx_t *tx;
288         uint64_t *objp;
289         boolean_t fuid_dirtied;
290
291         if (zfsvfs->z_version < ZPL_VERSION_USERSPACE)
292                 return (SET_ERROR(ENOTSUP));
293
294         switch (type) {
295         case ZFS_PROP_USERQUOTA:
296                 objp = &zfsvfs->z_userquota_obj;
297                 break;
298         case ZFS_PROP_GROUPQUOTA:
299                 objp = &zfsvfs->z_groupquota_obj;
300                 break;
301         case ZFS_PROP_USEROBJQUOTA:
302                 objp = &zfsvfs->z_userobjquota_obj;
303                 break;
304         case ZFS_PROP_GROUPOBJQUOTA:
305                 objp = &zfsvfs->z_groupobjquota_obj;
306                 break;
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));
312
313                 objp = &zfsvfs->z_projectquota_obj;
314                 break;
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));
320
321                 objp = &zfsvfs->z_projectobjquota_obj;
322                 break;
323         default:
324                 return (SET_ERROR(EINVAL));
325         }
326
327         err = zfs_id_to_fuidstr(zfsvfs, domain, rid, buf, sizeof (buf), B_TRUE);
328         if (err)
329                 return (err);
330         fuid_dirtied = zfsvfs->z_fuid_dirty;
331
332         tx = dmu_tx_create(zfsvfs->z_os);
333         dmu_tx_hold_zap(tx, *objp ? *objp : DMU_NEW_OBJECT, B_TRUE, NULL);
334         if (*objp == 0) {
335                 dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, B_TRUE,
336                     zfs_userquota_prop_prefixes[type]);
337         }
338         if (fuid_dirtied)
339                 zfs_fuid_txhold(zfsvfs, tx);
340         err = dmu_tx_assign(tx, TXG_WAIT);
341         if (err) {
342                 dmu_tx_abort(tx);
343                 return (err);
344         }
345
346         mutex_enter(&zfsvfs->z_lock);
347         if (*objp == 0) {
348                 *objp = zap_create(zfsvfs->z_os, DMU_OT_USERGROUP_QUOTA,
349                     DMU_OT_NONE, 0, tx);
350                 VERIFY(0 == zap_add(zfsvfs->z_os, MASTER_NODE_OBJ,
351                     zfs_userquota_prop_prefixes[type], 8, 1, objp, tx));
352         }
353         mutex_exit(&zfsvfs->z_lock);
354
355         if (quota == 0) {
356                 err = zap_remove(zfsvfs->z_os, *objp, buf, tx);
357                 if (err == ENOENT)
358                         err = 0;
359         } else {
360                 err = zap_update(zfsvfs->z_os, *objp, buf, 8, 1, &quota, tx);
361         }
362         ASSERT(err == 0);
363         if (fuid_dirtied)
364                 zfs_fuid_sync(zfsvfs, tx);
365         dmu_tx_commit(tx);
366         return (err);
367 }
368
369 boolean_t
370 zfs_id_overobjquota(zfsvfs_t *zfsvfs, uint64_t usedobj, uint64_t id)
371 {
372         char buf[20 + DMU_OBJACCT_PREFIX_LEN];
373         uint64_t used, quota, quotaobj;
374         int err;
375
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);
383                 }
384                 return (B_FALSE);
385         }
386
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);
395                         }
396                         return (B_FALSE);
397                 }
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;
403         } else {
404                 return (B_FALSE);
405         }
406         if (quotaobj == 0 || zfsvfs->z_replay)
407                 return (B_FALSE);
408
409         (void) snprintf(buf, sizeof (buf), "%llx", (longlong_t)id);
410         err = zap_lookup(zfsvfs->z_os, quotaobj, buf, 8, 1, &quota);
411         if (err != 0)
412                 return (B_FALSE);
413
414         (void) snprintf(buf, sizeof (buf), DMU_OBJACCT_PREFIX "%llx",
415             (longlong_t)id);
416         err = zap_lookup(zfsvfs->z_os, usedobj, buf, 8, 1, &used);
417         if (err != 0)
418                 return (B_FALSE);
419         return (used >= quota);
420 }
421
422 boolean_t
423 zfs_id_overblockquota(zfsvfs_t *zfsvfs, uint64_t usedobj, uint64_t id)
424 {
425         char buf[20];
426         uint64_t used, quota, quotaobj;
427         int err;
428
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);
437                         }
438                         return (B_FALSE);
439                 }
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;
445         } else {
446                 return (B_FALSE);
447         }
448         if (quotaobj == 0 || zfsvfs->z_replay)
449                 return (B_FALSE);
450
451         (void) snprintf(buf, sizeof (buf), "%llx", (longlong_t)id);
452         err = zap_lookup(zfsvfs->z_os, quotaobj, buf, 8, 1, &quota);
453         if (err != 0)
454                 return (B_FALSE);
455
456         err = zap_lookup(zfsvfs->z_os, usedobj, buf, 8, 1, &used);
457         if (err != 0)
458                 return (B_FALSE);
459         return (used >= quota);
460 }
461
462 boolean_t
463 zfs_id_overquota(zfsvfs_t *zfsvfs, uint64_t usedobj, uint64_t id)
464 {
465         return (zfs_id_overblockquota(zfsvfs, usedobj, id) ||
466             zfs_id_overobjquota(zfsvfs, usedobj, id));
467 }
468
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);