darwin-xnu/bsd/hfs/hfs_quota.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
   3 *
   4 * @APPLE_LICENSE_HEADER_START@
   5 * 
   6 * The contents of this file constitute Original Code as defined in and
   7 * are subject to the Apple Public Source License Version 1.1 (the
   8 * "License").  You may not use this file except in compliance with the
   9 * License.  Please obtain a copy of the License at
  10 * http://www.apple.com/publicsource and read it before using this file.
  11 * 
  12 * This Original Code and all software distributed under the License are
  13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
  16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
  17 * License for the specific language governing rights and limitations
  18 * under the License.
  19 * 
  20 * @APPLE_LICENSE_HEADER_END@
  21 */
  22/*
  23 * Copyright (c) 1982, 1986, 1990, 1993, 1995
  24 *      The Regents of the University of California.  All rights reserved.
  25 *
  26 * This code is derived from software contributed to Berkeley by
  27 * Robert Elz at The University of Melbourne.
  28 *
  29 * Redistribution and use in source and binary forms, with or without
  30 * modification, are permitted provided that the following conditions
  31 * are met:
  32 * 1. Redistributions of source code must retain the above copyright
  33 *    notice, this list of conditions and the following disclaimer.
  34 * 2. Redistributions in binary form must reproduce the above copyright
  35 *    notice, this list of conditions and the following disclaimer in the
  36 *    documentation and/or other materials provided with the distribution.
  37 * 3. All advertising materials mentioning features or use of this software
  38 *    must display the following acknowledgement:
  39 *      This product includes software developed by the University of
  40 *      California, Berkeley and its contributors.
  41 * 4. Neither the name of the University nor the names of its contributors
  42 *    may be used to endorse or promote products derived from this software
  43 *    without specific prior written permission.
  44 *
  45 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  48 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  55 * SUCH DAMAGE.
  56 *
  57 *      @(#)hfs_quota.c
  58 *      derived from @(#)ufs_quota.c    8.5 (Berkeley) 5/20/95
  59 */
  60
  61#include <sys/param.h>
  62#include <sys/kernel.h>
  63#include <sys/systm.h>
  64#include <sys/mount.h>
  65#include <sys/malloc.h>
  66#include <sys/file.h>
  67#include <sys/proc.h>
  68#include <sys/kauth.h>
  69#include <sys/vnode.h>
  70#include <sys/quota.h>
  71#include <sys/proc_internal.h>
  72#include <kern/kalloc.h>
  73
  74#include <hfs/hfs.h>
  75#include <hfs/hfs_cnode.h>
  76#include <hfs/hfs_quota.h>
  77#include <hfs/hfs_mount.h>
  78
  79/*
  80 * Quota name to error message mapping.
  81 */
  82#if 0
  83static char *quotatypes[] = INITQFNAMES;
  84#endif
  85
  86/*
  87 * Set up the quotas for a cnode.
  88 *
  89 * This routine completely defines the semantics of quotas.
  90 * If other criterion want to be used to establish quotas, the
  91 * MAXQUOTAS value in quotas.h should be increased, and the
  92 * additional dquots set up here.
  93 */
  94int
  95hfs_getinoquota(cp)
  96        register struct cnode *cp;
  97{
  98        struct hfsmount *hfsmp;
  99        struct vnode *vp;
 100        int error;
 101
 102        vp = cp->c_vp ? cp->c_vp : cp->c_rsrc_vp;
 103        hfsmp = VTOHFS(vp);
 104        /*
 105         * Set up the user quota based on file uid.
 106         * EINVAL means that quotas are not enabled.
 107         */
 108        if (cp->c_dquot[USRQUOTA] == NODQUOT &&
 109            (error =
 110                dqget(cp->c_uid, &hfsmp->hfs_qfiles[USRQUOTA], USRQUOTA, &cp->c_dquot[USRQUOTA])) &&
 111            error != EINVAL)
 112                return (error);
 113        /*
 114         * Set up the group quota based on file gid.
 115         * EINVAL means that quotas are not enabled.
 116         */
 117        if (cp->c_dquot[GRPQUOTA] == NODQUOT &&
 118            (error =
 119                dqget(cp->c_gid, &hfsmp->hfs_qfiles[GRPQUOTA], GRPQUOTA, &cp->c_dquot[GRPQUOTA])) &&
 120            error != EINVAL)
 121                return (error);
 122        return (0);
 123}
 124
 125/*
 126 * Update disk usage, and take corrective action.
 127 */
 128int
 129hfs_chkdq(cp, change, cred, flags)
 130        register struct cnode *cp;
 131        int64_t change;
 132        kauth_cred_t cred;
 133        int flags;
 134{
 135        register struct dquot *dq;
 136        register int i;
 137        int64_t ncurbytes;
 138        int error=0;
 139        struct proc *p;
 140
 141#if DIAGNOSTIC
 142        if ((flags & CHOWN) == 0)
 143                hfs_chkdquot(cp);
 144#endif
 145        if (change == 0)
 146                return (0);
 147        if (change < 0) {
 148                for (i = 0; i < MAXQUOTAS; i++) {
 149                        if ((dq = cp->c_dquot[i]) == NODQUOT)
 150                                continue;
 151                        dqlock(dq);
 152
 153                        ncurbytes = dq->dq_curbytes + change;
 154                        if (ncurbytes >= 0)
 155                                dq->dq_curbytes = ncurbytes;
 156                        else
 157                                dq->dq_curbytes = 0;
 158                        dq->dq_flags &= ~DQ_BLKS;
 159                        dq->dq_flags |= DQ_MOD;
 160
 161                        dqunlock(dq);
 162                }
 163                return (0);
 164        }
 165        p = current_proc();
 166        if (cred == NOCRED)
 167                cred = proc_ucred(kernproc);
 168        if (suser(cred, NULL) || proc_forcequota(p)) {
 169                for (i = 0; i < MAXQUOTAS; i++) {
 170                        if ((dq = cp->c_dquot[i]) == NODQUOT)
 171                                continue;
 172                        error = hfs_chkdqchg(cp, change, cred, i);
 173                        if (error) {
 174                                break;
 175                        }
 176                }
 177        }
 178        if ((flags & FORCE) || error == 0) {
 179                for (i = 0; i < MAXQUOTAS; i++) {
 180                        if ((dq = cp->c_dquot[i]) == NODQUOT)
 181                                continue;
 182                        dqlock(dq);
 183
 184                        dq->dq_curbytes += change;
 185                        dq->dq_flags |= DQ_MOD;
 186
 187                        dqunlock(dq);
 188                }
 189        }
 190        return (error);
 191}
 192
 193/*
 194 * Check for a valid change to a users allocation.
 195 * Issue an error message if appropriate.
 196 */
 197int
 198hfs_chkdqchg(cp, change, cred, type)
 199        struct cnode *cp;
 200        int64_t change;
 201        kauth_cred_t cred;
 202        int type;
 203{
 204        register struct dquot *dq = cp->c_dquot[type];
 205        u_int64_t ncurbytes;
 206        struct vnode *vp = cp->c_vp ? cp->c_vp : cp->c_rsrc_vp;
 207        
 208        dqlock(dq);
 209        
 210        ncurbytes = dq->dq_curbytes + change;
 211        /*
 212         * If user would exceed their hard limit, disallow space allocation.
 213         */
 214        if (ncurbytes >= dq->dq_bhardlimit && dq->dq_bhardlimit) {
 215                if ((dq->dq_flags & DQ_BLKS) == 0 &&
 216                    cp->c_uid == kauth_cred_getuid(cred)) {
 217#if 0   
 218                        printf("\nwrite failed, %s disk limit reached\n",
 219                            quotatypes[type]);
 220#endif
 221                        dq->dq_flags |= DQ_BLKS;
 222                }
 223                dqunlock(dq);
 224
 225                return (EDQUOT);
 226        }
 227        /*
 228         * If user is over their soft limit for too long, disallow space
 229         * allocation. Reset time limit as they cross their soft limit.
 230         */
 231        if (ncurbytes >= dq->dq_bsoftlimit && dq->dq_bsoftlimit) {
 232                struct timeval tv;
 233
 234                microuptime(&tv);
 235                if (dq->dq_curbytes < dq->dq_bsoftlimit) {
 236                        dq->dq_btime = tv.tv_sec +
 237                            VTOHFS(vp)->hfs_qfiles[type].qf_btime;
 238#if 0
 239                        if (cp->c_uid == kauth_cred_getuid(cred))
 240                                printf("\nwarning, %s %s\n",
 241                                    quotatypes[type], "disk quota exceeded");
 242#endif
 243                        dqunlock(dq);
 244
 245                        return (0);
 246                }
 247                if (tv.tv_sec > dq->dq_btime) {
 248                        if ((dq->dq_flags & DQ_BLKS) == 0 &&
 249                            cp->c_uid == kauth_cred_getuid(cred)) {
 250#if 0
 251                                printf("\nwrite failed, %s %s\n",
 252                                    quotatypes[type],
 253                                    "disk quota exceeded for too long");
 254#endif
 255                                dq->dq_flags |= DQ_BLKS;
 256                        }
 257                        dqunlock(dq);
 258
 259                        return (EDQUOT);
 260                }
 261        }
 262        dqunlock(dq);
 263
 264        return (0);
 265}
 266
 267/*
 268 * Check the inode limit, applying corrective action.
 269 */
 270int
 271hfs_chkiq(cp, change, cred, flags)
 272        register struct cnode *cp;
 273        long change;
 274        kauth_cred_t cred;
 275        int flags;
 276{
 277        register struct dquot *dq;
 278        register int i;
 279        int ncurinodes, error=0;
 280        struct proc *p;
 281
 282#if DIAGNOSTIC
 283        if ((flags & CHOWN) == 0)
 284                hfs_chkdquot(cp);
 285#endif
 286        if (change == 0)
 287                return (0);
 288        if (change < 0) {
 289                for (i = 0; i < MAXQUOTAS; i++) {
 290                        if ((dq = cp->c_dquot[i]) == NODQUOT)
 291                                continue;
 292                        dqlock(dq);
 293
 294                        ncurinodes = dq->dq_curinodes + change;
 295                        if (ncurinodes >= 0)
 296                                dq->dq_curinodes = ncurinodes;
 297                        else
 298                                dq->dq_curinodes = 0;
 299                        dq->dq_flags &= ~DQ_INODS;
 300                        dq->dq_flags |= DQ_MOD;
 301
 302                        dqunlock(dq);
 303                }
 304                return (0);
 305        }
 306        p = current_proc();
 307        if (cred == NOCRED)
 308                cred = proc_ucred(kernproc);
 309        if (suser(cred, NULL) || proc_forcequota(p)) {
 310                for (i = 0; i < MAXQUOTAS; i++) {
 311                        if ((dq = cp->c_dquot[i]) == NODQUOT)
 312                                continue;
 313                        error = hfs_chkiqchg(cp, change, cred, i);
 314                        if (error) {
 315                                break;
 316                        }
 317                }
 318        }
 319        if ((flags & FORCE) || error == 0) { 
 320                for (i = 0; i < MAXQUOTAS; i++) {
 321                        if ((dq = cp->c_dquot[i]) == NODQUOT)
 322                                continue;
 323                        dqlock(dq);
 324
 325                        dq->dq_curinodes += change;
 326                        dq->dq_flags |= DQ_MOD;
 327
 328                        dqunlock(dq);
 329                }
 330        }
 331        return (error);
 332}
 333
 334/*
 335 * Check for a valid change to a users allocation.
 336 * Issue an error message if appropriate.
 337 */
 338int
 339hfs_chkiqchg(cp, change, cred, type)
 340        struct cnode *cp;
 341        long change;
 342        kauth_cred_t cred;
 343        int type;
 344{
 345        register struct dquot *dq = cp->c_dquot[type];
 346        long ncurinodes;
 347        struct vnode *vp = cp->c_vp ? cp->c_vp : cp->c_rsrc_vp;
 348
 349        dqlock(dq);
 350
 351        ncurinodes = dq->dq_curinodes + change;
 352        /*
 353         * If user would exceed their hard limit, disallow cnode allocation.
 354         */
 355        if (ncurinodes >= dq->dq_ihardlimit && dq->dq_ihardlimit) {
 356                if ((dq->dq_flags & DQ_INODS) == 0 &&
 357                    cp->c_uid == kauth_cred_getuid(cred)) {
 358#if 0
 359                        printf("\nwrite failed, %s cnode limit reached\n",
 360                            quotatypes[type]);
 361#endif
 362                        dq->dq_flags |= DQ_INODS;
 363                }
 364                dqunlock(dq);
 365
 366                return (EDQUOT);
 367        }
 368        /*
 369         * If user is over their soft limit for too long, disallow cnode
 370         * allocation. Reset time limit as they cross their soft limit.
 371         */
 372        if (ncurinodes >= dq->dq_isoftlimit && dq->dq_isoftlimit) {
 373                struct timeval tv;
 374                
 375                microuptime(&tv);
 376                if (dq->dq_curinodes < dq->dq_isoftlimit) {
 377                        dq->dq_itime = tv.tv_sec +
 378                            VTOHFS(vp)->hfs_qfiles[type].qf_itime;
 379#if 0
 380                        if (cp->c_uid == kauth_cred_getuid(cred))
 381                                printf("\nwarning, %s %s\n",
 382                                    quotatypes[type], "cnode quota exceeded");
 383#endif
 384                        dqunlock(dq);
 385
 386                        return (0);
 387                }
 388                if (tv.tv_sec > dq->dq_itime) {
 389                        if ((dq->dq_flags & DQ_INODS) == 0 &&
 390                            cp->c_uid == kauth_cred_getuid(cred)) {
 391#if 0
 392                                printf("\nwrite failed, %s %s\n",
 393                                    quotatypes[type],
 394                                    "cnode quota exceeded for too long");
 395#endif
 396                                dq->dq_flags |= DQ_INODS;
 397                        }
 398                        dqunlock(dq);
 399
 400                        return (EDQUOT);
 401                }
 402        }
 403        dqunlock(dq);
 404
 405        return (0);
 406}
 407
 408#if DIAGNOSTIC
 409/*
 410 * On filesystems with quotas enabled, it is an error for a file to change
 411 * size and not to have a dquot structure associated with it.
 412 */
 413void
 414hfs_chkdquot(cp)
 415        register struct cnode *cp;
 416{
 417        struct vnode *vp = cp->c_vp ? cp->c_vp : cp->c_rsrc_vp;
 418        struct hfsmount *hfsmp = VTOHFS(vp);
 419        register int i;
 420
 421        for (i = 0; i < MAXQUOTAS; i++) {
 422                if (hfsmp->hfs_qfiles[i].qf_vp == NULLVP)
 423                        continue;
 424                if (cp->c_dquot[i] == NODQUOT) {
 425                        vprint("chkdquot: missing dquot", vp);
 426                        panic("missing dquot");
 427                }
 428        }
 429}
 430#endif
 431
 432/*
 433 * Code to process quotactl commands.
 434 */
 435
 436/*
 437 * Q_QUOTAON - set up a quota file for a particular file system.
 438 */
 439struct hfs_quotaon_cargs {
 440        int     error;
 441};
 442
 443static int
 444hfs_quotaon_callback(struct vnode *vp, void *cargs)
 445{
 446        struct hfs_quotaon_cargs *args;
 447
 448        args = (struct hfs_quotaon_cargs *)cargs;
 449
 450        args->error = hfs_getinoquota(VTOC(vp));
 451        if (args->error)
 452                return (VNODE_RETURNED_DONE);
 453
 454        return (VNODE_RETURNED);
 455}
 456
 457int
 458hfs_quotaon(p, mp, type, fnamep)
 459        struct proc *p;
 460        struct mount *mp;
 461        register int type;
 462        caddr_t fnamep;
 463{
 464        struct hfsmount *hfsmp = VFSTOHFS(mp);
 465        struct quotafile *qfp;
 466        struct vnode *vp;
 467        int error = 0;
 468        struct hfs_quotaon_cargs args;
 469
 470        qfp = &hfsmp->hfs_qfiles[type];
 471
 472        if ( (qf_get(qfp, QTF_OPENING)) )
 473                return (0);
 474
 475        error = vnode_open(fnamep, FREAD|FWRITE, 0, 0, &vp, NULL);
 476        if (error) {
 477                goto out;
 478        }
 479        if (!vnode_isreg(vp)) {
 480                (void) vnode_close(vp, FREAD|FWRITE, NULL);
 481                error = EACCES;
 482                goto out;
 483        }
 484        vfs_setflags(mp, (uint64_t)((unsigned int)MNT_QUOTA));
 485        vnode_setnoflush(vp);
 486        /*
 487         * Save the credential of the process that turned on quotas.
 488         */
 489        qfp->qf_cred = kauth_cred_proc_ref(p);
 490        qfp->qf_vp = vp;
 491        /*
 492         * Finish initializing the quota file
 493         */
 494        error = dqfileopen(qfp, type);
 495        if (error) {
 496                (void) vnode_close(vp, FREAD|FWRITE, NULL);
 497
 498                kauth_cred_rele(qfp->qf_cred);
 499                qfp->qf_cred = NOCRED;
 500                qfp->qf_vp = NULLVP;
 501                goto out;
 502        }
 503        qf_put(qfp, QTF_OPENING);
 504
 505        /*
 506         * Search vnodes associated with this mount point,
 507         * adding references to quota file being opened.
 508         * NB: only need to add dquot's for cnodes being modified.
 509         *
 510         * hfs_quota_callback will be called for each vnode open for
 511         * 'write' (VNODE_WRITEABLE) hung off of this mount point
 512         * the vnode will be in an 'unbusy' state (VNODE_WAIT) and 
 513         * properly referenced and unreferenced around the callback
 514         */
 515        args.error = 0;
 516
 517        vnode_iterate(mp, VNODE_WRITEABLE | VNODE_WAIT, hfs_quotaon_callback, (void *)&args);
 518        
 519        error = args.error;
 520
 521        if (error) {
 522                hfs_quotaoff(p, mp, type);
 523        }
 524        return (error);
 525
 526out:
 527        qf_put(qfp, QTF_OPENING);
 528
 529        return (error);
 530}
 531
 532
 533/*
 534 * Q_QUOTAOFF - turn off disk quotas for a filesystem.
 535 */
 536struct hfs_quotaoff_cargs {
 537        int     type;
 538};
 539
 540static int
 541hfs_quotaoff_callback(struct vnode *vp, void *cargs)
 542{
 543        struct hfs_quotaoff_cargs *args;
 544        struct cnode *cp;
 545        struct dquot *dq;
 546
 547        args = (struct hfs_quotaoff_cargs *)cargs;
 548
 549        cp = VTOC(vp);
 550
 551        dq = cp->c_dquot[args->type];
 552        cp->c_dquot[args->type] = NODQUOT;
 553
 554        dqrele(dq);
 555
 556        return (VNODE_RETURNED);
 557}
 558
 559int
 560hfs_quotaoff(__unused struct proc *p, struct mount *mp, register int type)
 561{
 562        struct vnode *qvp;
 563        struct hfsmount *hfsmp = VFSTOHFS(mp);
 564        struct quotafile *qfp;
 565        int error;
 566        kauth_cred_t cred;
 567        struct hfs_quotaoff_cargs args;
 568
 569        qfp = &hfsmp->hfs_qfiles[type];
 570        
 571        if ( (qf_get(qfp, QTF_CLOSING)) )
 572                return (0);
 573        qvp = qfp->qf_vp;
 574
 575        /*
 576         * Sync out any orpaned dirty dquot entries.
 577         */
 578        dqsync_orphans(qfp);
 579
 580        /*
 581         * Search vnodes associated with this mount point,
 582         * deleting any references to quota file being closed.
 583         *
 584         * hfs_quotaoff_callback will be called for each vnode
 585         * hung off of this mount point
 586         * the vnode will be in an 'unbusy' state (VNODE_WAIT) and 
 587         * properly referenced and unreferenced around the callback
 588         */
 589        args.type = type;
 590
 591        vnode_iterate(mp, VNODE_WAIT, hfs_quotaoff_callback, (void *)&args);
 592
 593        dqflush(qvp);
 594        /* Finish tearing down the quota file */
 595        dqfileclose(qfp, type);
 596
 597        vnode_clearnoflush(qvp);
 598        error = vnode_close(qvp, FREAD|FWRITE, NULL);
 599
 600        qfp->qf_vp = NULLVP;
 601        cred = qfp->qf_cred;
 602        if (cred != NOCRED) {
 603                qfp->qf_cred = NOCRED;
 604                kauth_cred_rele(cred);
 605        }
 606        for (type = 0; type < MAXQUOTAS; type++)
 607                if (hfsmp->hfs_qfiles[type].qf_vp != NULLVP)
 608                        break;
 609        if (type == MAXQUOTAS)
 610                vfs_clearflags(mp, (uint64_t)((unsigned int)MNT_QUOTA));
 611
 612        qf_put(qfp, QTF_CLOSING);
 613
 614        return (error);
 615}
 616
 617/*
 618 * Q_GETQUOTA - return current values in a dqblk structure.
 619 */
 620int
 621hfs_getquota(mp, id, type, datap)
 622        struct mount *mp;
 623        u_long id;
 624        int type;
 625        caddr_t datap;
 626{
 627        struct dquot *dq;
 628        int error;
 629
 630        error = dqget(id, &VFSTOHFS(mp)->hfs_qfiles[type], type, &dq);
 631        if (error)
 632                return (error);
 633        dqlock(dq);
 634
 635        bcopy(&dq->dq_dqb, datap, sizeof(dq->dq_dqb));
 636        
 637        dqunlock(dq);
 638        dqrele(dq);
 639
 640        return (error);
 641}
 642
 643/*
 644 * Q_SETQUOTA - assign an entire dqblk structure.
 645 */
 646int
 647hfs_setquota(mp, id, type, datap)
 648        struct mount *mp;
 649        u_long id;
 650        int type;
 651        caddr_t datap;
 652{
 653        struct dquot *dq;
 654        struct hfsmount *hfsmp = VFSTOHFS(mp);
 655        struct dqblk * newlimp = (struct dqblk *) datap;
 656        struct timeval tv;
 657        int error;
 658
 659        error = dqget(id, &hfsmp->hfs_qfiles[type], type, &dq);
 660        if (error)
 661                return (error);
 662        dqlock(dq);
 663
 664        /*
 665         * Copy all but the current values.
 666         * Reset time limit if previously had no soft limit or were
 667         * under it, but now have a soft limit and are over it.
 668         */
 669        newlimp->dqb_curbytes = dq->dq_curbytes;
 670        newlimp->dqb_curinodes = dq->dq_curinodes;
 671        if (dq->dq_id != 0) {
 672                newlimp->dqb_btime = dq->dq_btime;
 673                newlimp->dqb_itime = dq->dq_itime;
 674        }
 675        if (newlimp->dqb_bsoftlimit &&
 676            dq->dq_curbytes >= newlimp->dqb_bsoftlimit &&
 677            (dq->dq_bsoftlimit == 0 || dq->dq_curbytes < dq->dq_bsoftlimit)) {
 678                microuptime(&tv);
 679                newlimp->dqb_btime = tv.tv_sec + hfsmp->hfs_qfiles[type].qf_btime;
 680        }
 681        if (newlimp->dqb_isoftlimit &&
 682            dq->dq_curinodes >= newlimp->dqb_isoftlimit &&
 683            (dq->dq_isoftlimit == 0 || dq->dq_curinodes < dq->dq_isoftlimit)) {
 684                microuptime(&tv);
 685                newlimp->dqb_itime = tv.tv_sec + hfsmp->hfs_qfiles[type].qf_itime;
 686        }
 687        bcopy(newlimp, &dq->dq_dqb, sizeof(dq->dq_dqb));
 688        if (dq->dq_curbytes < dq->dq_bsoftlimit)
 689                dq->dq_flags &= ~DQ_BLKS;
 690        if (dq->dq_curinodes < dq->dq_isoftlimit)
 691                dq->dq_flags &= ~DQ_INODS;
 692        if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 &&
 693            dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0)
 694                dq->dq_flags |= DQ_FAKE;
 695        else
 696                dq->dq_flags &= ~DQ_FAKE;
 697        dq->dq_flags |= DQ_MOD;
 698
 699        dqunlock(dq);
 700        dqrele(dq);
 701
 702        return (0);
 703}
 704
 705/*
 706 * Q_SETUSE - set current cnode and byte usage.
 707 */
 708int
 709hfs_setuse(mp, id, type, datap)
 710        struct mount *mp;
 711        u_long id;
 712        int type;
 713        caddr_t datap;
 714{
 715        struct hfsmount *hfsmp = VFSTOHFS(mp);
 716        struct dquot *dq;
 717        struct timeval tv;
 718        int error;
 719        struct dqblk *quotablkp = (struct dqblk *) datap;
 720
 721        error = dqget(id, &hfsmp->hfs_qfiles[type], type, &dq);
 722        if (error)
 723                return (error);
 724        dqlock(dq);
 725
 726        /*
 727         * Reset time limit if have a soft limit and were
 728         * previously under it, but are now over it.
 729         */
 730        if (dq->dq_bsoftlimit && dq->dq_curbytes < dq->dq_bsoftlimit &&
 731            quotablkp->dqb_curbytes >= dq->dq_bsoftlimit) {
 732                microuptime(&tv);
 733                dq->dq_btime = tv.tv_sec + hfsmp->hfs_qfiles[type].qf_btime;
 734        }
 735        if (dq->dq_isoftlimit && dq->dq_curinodes < dq->dq_isoftlimit &&
 736            quotablkp->dqb_curinodes >= dq->dq_isoftlimit) {
 737                microuptime(&tv);
 738                dq->dq_itime = tv.tv_sec + hfsmp->hfs_qfiles[type].qf_itime;
 739        }
 740        dq->dq_curbytes = quotablkp->dqb_curbytes;
 741        dq->dq_curinodes = quotablkp->dqb_curinodes;
 742        if (dq->dq_curbytes < dq->dq_bsoftlimit)
 743                dq->dq_flags &= ~DQ_BLKS;
 744        if (dq->dq_curinodes < dq->dq_isoftlimit)
 745                dq->dq_flags &= ~DQ_INODS;
 746        dq->dq_flags |= DQ_MOD;
 747
 748        dqunlock(dq);
 749        dqrele(dq);
 750
 751        return (0);
 752}
 753
 754
 755/*
 756 * Q_SYNC - sync quota files to disk.
 757 */
 758static int
 759hfs_qsync_callback(struct vnode *vp, __unused void *cargs)
 760{
 761        struct cnode *cp;
 762        struct dquot *dq;
 763        int     i;
 764
 765        cp = VTOC(vp);
 766                    
 767        for (i = 0; i < MAXQUOTAS; i++) {
 768                dq = cp->c_dquot[i];
 769                if (dq != NODQUOT && (dq->dq_flags & DQ_MOD))
 770                        dqsync(dq);
 771        }
 772        return (VNODE_RETURNED);
 773}
 774
 775int
 776hfs_qsync(mp)
 777        struct mount *mp;
 778{
 779        struct hfsmount *hfsmp = VFSTOHFS(mp);
 780        int i;
 781
 782        /*
 783         * Check if the mount point has any quotas.
 784         * If not, simply return.
 785         */
 786        for (i = 0; i < MAXQUOTAS; i++)
 787                if (hfsmp->hfs_qfiles[i].qf_vp != NULLVP)
 788                        break;
 789        if (i == MAXQUOTAS)
 790                return (0);
 791
 792        /*
 793         * Sync out any orpaned dirty dquot entries.
 794         */
 795        for (i = 0; i < MAXQUOTAS; i++)
 796                if (hfsmp->hfs_qfiles[i].qf_vp != NULLVP)
 797                        dqsync_orphans(&hfsmp->hfs_qfiles[i]);
 798
 799        /*
 800         * Search vnodes associated with this mount point,
 801         * synchronizing any modified dquot structures.
 802         *
 803         * hfs_qsync_callback will be called for each vnode
 804         * hung off of this mount point
 805         * the vnode will be
 806         * properly referenced and unreferenced around the callback
 807         */
 808        vnode_iterate(mp, 0, hfs_qsync_callback, (void *)NULL);
 809
 810        return (0);
 811}
 812
 813/*
 814 * Q_QUOTASTAT - get quota on/off status 
 815 */
 816int
 817hfs_quotastat(mp, type, datap)
 818        struct mount *mp;
 819        register int type;
 820        caddr_t datap;
 821{
 822        struct hfsmount *hfsmp = VFSTOHFS(mp);
 823        int error = 0;
 824        int qstat;
 825
 826        if ((((unsigned int)vfs_flags(mp)) & MNT_QUOTA) && (hfsmp->hfs_qfiles[type].qf_vp != NULLVP))
 827          qstat = 1;   /* quotas are on for this type */
 828        else
 829          qstat = 0;   /* quotas are off for this type */
 830        
 831        *((int *)datap) = qstat;
 832        return (error);
 833}
 834
 835
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.