quota.c revision f48205be61a214698b763ff550ab9e657525104c
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* University Copyright- Copyright (c) 1982, 1986, 1988
* The Regents of the University of California
* All Rights Reserved
*
* University Acknowledgment- Portions of this document are derived from
* software developed by the University of California, Berkeley, and its
* contributors.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Code pertaining to management of the in-core data structures.
*/
/*
* Dquot in core hash chain headers
*/
static kmutex_t dq_cachelock;
static kmutex_t dq_freelock;
/*
* Dquot free list.
*/
struct dquot dqfreelist;
#define dqinsheadfree(DQP) { \
mutex_enter(&dq_freelock); \
mutex_exit(&dq_freelock); \
}
#define dqinstailfree(DQP) { \
mutex_enter(&dq_freelock); \
mutex_exit(&dq_freelock); \
}
/* (clear pointers to make sure we don't use them; catch problems early) */
}
/*
* Initialize quota sub-system init lock.
*/
void
qtinit()
{
}
/*
* qtinit2 allocated space for the quota structures. Only do this if
* if quotas are going to be used so that we can save the space if quotas
* aren't used.
*/
void
qtinit2(void)
{
if (ndquot == 0)
/*
* Initialize the cache between the in-core structures
* and the per-file system quota files on disk.
*/
}
}
}
/*
* Obtain the user's on-disk quota limit for file system specified.
* dqpp is returned locked.
*/
int
int force, /* don't do enable checks */
{
int error;
int contig;
int err;
loop:
/*
* Check for quotas enabled.
*/
return (ESRCH);
if (!qip)
/*
* Check the cache first.
*/
continue;
/*
* I may have slept in the mutex_enter. Make sure this is
* still the one I want.
*/
goto loop;
}
return (EINVAL);
}
/*
* Cache hit with no references.
* Take the structure off the free list.
*/
}
return (0);
}
/*
* Not in cache.
* Get dquot at head of free list.
*/
return (EUSERS);
}
panic("getdiskquota: dqp->dq_cnt: "
"%ld != 0 || dqp->dq_flags: 0x%x != 0 (%s)",
/*NOTREACHED*/
}
/*
* Take it off the free list, and off the hash chain it was on.
* Then put it on the new hash chain.
*/
/*
* Check the uid in case it's too large to fit into the 2Gbyte
* 'quotas' file (higher than 67 million or so).
*/
/*
* Large Files: i_size need to be accessed atomically now.
*/
/*
* Read quota info off disk.
*/
/*
* We must set the dq_mof even if not we are not logging in case
* we are later remount to logging.
*/
} else {
}
if (error) {
/*
* I/O error in reading quota file.
* Put dquot on a private, unfindable hash list,
* put dquot at the head of the free list and
* reflect the problem to caller.
*/
/*
* I must exit the dq_lock so that I can acquire the
* dq_cachelock. If another thread finds dqp before
* I remove it from the cache it will see the
* DQ_ERROR and just return EIO.
*/
/*
* Don't bother reacquiring dq_lock because the dq is
* not on the freelist or in the cache so only I have
* access to it.
*/
return (EIO);
}
} else {
}
return (0);
}
/*
* Release dquot.
*/
void
{
(void) ufs_fault(
"dqput: dqp->dq_cnt == 0");
return;
}
/*
* DQ_MOD was cleared by dqupdate().
* DQ_ERROR shouldn't be set if this dquot was being used.
*/
/* quotas are disabled, discard this dquot struct */
} else
}
}
/*
* Update on disk quota info.
*/
void
{
int newtrans = 0;
if (!dqp->dq_ufsvfsp) {
return;
}
if (!vfs_root) {
return;
}
/*
* I don't need to hold dq_rwlock when looking at vfs_qinod here
* because vfs_qinod is only cleared by closedq after it has called
* dqput on all dq's. Since I am holding dq_lock on this dq, closedq
* will have to wait until I am done before it can call dqput on
* this dq so vfs_qinod will not change value until after I return.
*/
if (!qip) {
return;
}
if (!ufsvfsp) {
"dqupdate: NULL vfs_qinod->i_ufsvfs");
return;
}
"dqupdate: vfs_qinod->i_ufsvfs != dqp->dq_ufsvfsp");
return;
}
"dqupdate: !(dqp->dq_flags & DQ_MOD)");
return;
}
newtrans++;
}
if (TRANS_ISTRANS(ufsvfsp)) {
DT_QR, 0, 0);
} else {
/*
* Locknest gets very confused when I lock the quota inode.
* It thinks that qip and ip (the inode that caused the
* quota routines to get called) are the same inode.
*/
/*
* refuse to push if offset would be illegal
*/
sizeof (struct dqblk),
}
}
if (newtrans) {
}
}
/*
* Invalidate a dquot. This function is called when quotas are disabled
* for a specific file system via closedq() or when we unmount the file
* system and invalidate the quota cache via invalidatedq().
*
* Take the dquot off its hash list and put it on a private, unfindable
* hash list (refers to itself). Also, put it at the head of the free list.
* Note that even though dq_cnt is zero, this dquot is NOT yet on the
* freelist.
*/
void
{
/*
* To preserve lock order, we have to drop dq_lock in order to
* grab dq_cachelock. To prevent someone from grabbing this
* dquot from the quota cache via getdiskquota() while we are
* "unsafe", we clear dq_ufsvfsp so it won't match anything.
*/
/*
* The following paranoia is to make sure that getdiskquota()
* has not been broken:
*/
/*
* Now we have the locks in the right order so we can do the
* rest of the work.
*/
}
/*
* Invalidate all quota information records for the specified file system.
*/
void
{
/*
* If quotas are not initialized, then there is nothing to do.
*/
if (!quotas_initialized) {
return;
}
/*
* Invalidate all the quota info records for this file system
* that are in the quota cache:
*/
/*
* If someone else has it, then ignore it. For the target
* file system, this is okay for three reasons:
*
* 1) This routine is called after closedq() so the quota
* sub-system is disabled for this file system.
* 2) We have made the quota sub-system quiescent for
* this file system.
* 3) We are in the process of unmounting this file
* system so the quota sub-system can't be enabled
* for it.
*/
continue;
}
/*
* At this point, any quota info records that are
* associated with the target file system, should have a
* reference count of zero and be on the free list.
* Why? Because these quota info records went to a zero
* dq_cnt (via dqput()) before the file system was
* unmounted and are waiting to be found in the quota
* cache and reused (via getdiskquota()). The exception
* is when a quota transaction is sitting in the deltamap,
* indicated by DQ_TRANS being set in dq_flags.
* This causes a reference to be held on the quota
* information record and it will only be cleared once
* the transaction has reached the log. If we find
* any of these - we ignore them and let logging do
* the right thing.
*/
/* Cope with those orphaned dquots. */
continue;
}
/*
* Take the quota info record off the free list
* so dqinval() can do its job (and put it on the
* front of the free list).
*/
}
}
}