The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/contrib/openzfs/module/zfs/zfs_quota.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 <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);

Cache object: 767ffd8c1d817234e99208221a2fc7f4


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.