diff options
author | Jan Kara <jack@suse.cz> | 2009-01-26 15:28:09 +0100 |
---|---|---|
committer | Jan Kara <jack@suse.cz> | 2009-03-26 02:18:35 +0100 |
commit | 884d179dff3aa98a73c3ba9dee05fd6050d664f0 (patch) | |
tree | 68c18e3ff8decd2af861e807bed96cca2dea30d4 /fs/dquot.c | |
parent | 60e58e0f30e723464c2a7d34b71b8675566c572d (diff) |
quota: Move quota files into separate directory
Quota subsystem has more and more files. It's time to create a dir for it.
Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/dquot.c')
-rw-r--r-- | fs/dquot.c | 2564 |
1 files changed, 0 insertions, 2564 deletions
diff --git a/fs/dquot.c b/fs/dquot.c deleted file mode 100644 index 28aa1466760..00000000000 --- a/fs/dquot.c +++ /dev/null @@ -1,2564 +0,0 @@ -/* - * Implementation of the diskquota system for the LINUX operating system. QUOTA - * is implemented using the BSD system call interface as the means of - * communication with the user level. This file contains the generic routines - * called by the different filesystems on allocation of an inode or block. - * These routines take care of the administration needed to have a consistent - * diskquota tracking system. The ideas of both user and group quotas are based - * on the Melbourne quota system as used on BSD derived systems. The internal - * implementation is based on one of the several variants of the LINUX - * inode-subsystem with added complexity of the diskquota system. - * - * Author: Marco van Wieringen <mvw@planets.elm.net> - * - * Fixes: Dmitry Gorodchanin <pgmdsg@ibi.com>, 11 Feb 96 - * - * Revised list management to avoid races - * -- Bill Hawes, <whawes@star.net>, 9/98 - * - * Fixed races in dquot_transfer(), dqget() and dquot_alloc_...(). - * As the consequence the locking was moved from dquot_decr_...(), - * dquot_incr_...() to calling functions. - * invalidate_dquots() now writes modified dquots. - * Serialized quota_off() and quota_on() for mount point. - * Fixed a few bugs in grow_dquots(). - * Fixed deadlock in write_dquot() - we no longer account quotas on - * quota files - * remove_dquot_ref() moved to inode.c - it now traverses through inodes - * add_dquot_ref() restarts after blocking - * Added check for bogus uid and fixed check for group in quotactl. - * Jan Kara, <jack@suse.cz>, sponsored by SuSE CR, 10-11/99 - * - * Used struct list_head instead of own list struct - * Invalidation of referenced dquots is no longer possible - * Improved free_dquots list management - * Quota and i_blocks are now updated in one place to avoid races - * Warnings are now delayed so we won't block in critical section - * Write updated not to require dquot lock - * Jan Kara, <jack@suse.cz>, 9/2000 - * - * Added dynamic quota structure allocation - * Jan Kara <jack@suse.cz> 12/2000 - * - * Rewritten quota interface. Implemented new quota format and - * formats registering. - * Jan Kara, <jack@suse.cz>, 2001,2002 - * - * New SMP locking. - * Jan Kara, <jack@suse.cz>, 10/2002 - * - * Added journalled quota support, fix lock inversion problems - * Jan Kara, <jack@suse.cz>, 2003,2004 - * - * (C) Copyright 1994 - 1997 Marco van Wieringen - */ - -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/fs.h> -#include <linux/mount.h> -#include <linux/mm.h> -#include <linux/time.h> -#include <linux/types.h> -#include <linux/string.h> -#include <linux/fcntl.h> -#include <linux/stat.h> -#include <linux/tty.h> -#include <linux/file.h> -#include <linux/slab.h> -#include <linux/sysctl.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/proc_fs.h> -#include <linux/security.h> -#include <linux/kmod.h> -#include <linux/namei.h> -#include <linux/buffer_head.h> -#include <linux/capability.h> -#include <linux/quotaops.h> -#include <linux/writeback.h> /* for inode_lock, oddly enough.. */ -#ifdef CONFIG_QUOTA_NETLINK_INTERFACE -#include <net/netlink.h> -#include <net/genetlink.h> -#endif - -#include <asm/uaccess.h> - -#define __DQUOT_PARANOIA - -/* - * There are three quota SMP locks. dq_list_lock protects all lists with quotas - * and quota formats, dqstats structure containing statistics about the lists - * dq_data_lock protects data from dq_dqb and also mem_dqinfo structures and - * also guards consistency of dquot->dq_dqb with inode->i_blocks, i_bytes. - * i_blocks and i_bytes updates itself are guarded by i_lock acquired directly - * in inode_add_bytes() and inode_sub_bytes(). dq_state_lock protects - * modifications of quota state (on quotaon and quotaoff) and readers who care - * about latest values take it as well. - * - * The spinlock ordering is hence: dq_data_lock > dq_list_lock > i_lock, - * dq_list_lock > dq_state_lock - * - * Note that some things (eg. sb pointer, type, id) doesn't change during - * the life of the dquot structure and so needn't to be protected by a lock - * - * Any operation working on dquots via inode pointers must hold dqptr_sem. If - * operation is just reading pointers from inode (or not using them at all) the - * read lock is enough. If pointers are altered function must hold write lock - * (these locking rules also apply for S_NOQUOTA flag in the inode - note that - * for altering the flag i_mutex is also needed). - * - * Each dquot has its dq_lock mutex. Locked dquots might not be referenced - * from inodes (dquot_alloc_space() and such don't check the dq_lock). - * Currently dquot is locked only when it is being read to memory (or space for - * it is being allocated) on the first dqget() and when it is being released on - * the last dqput(). The allocation and release oparations are serialized by - * the dq_lock and by checking the use count in dquot_release(). Write - * operations on dquots don't hold dq_lock as they copy data under dq_data_lock - * spinlock to internal buffers before writing. - * - * Lock ordering (including related VFS locks) is the following: - * i_mutex > dqonoff_sem > journal_lock > dqptr_sem > dquot->dq_lock > - * dqio_mutex - * The lock ordering of dqptr_sem imposed by quota code is only dqonoff_sem > - * dqptr_sem. But filesystem has to count with the fact that functions such as - * dquot_alloc_space() acquire dqptr_sem and they usually have to be called - * from inside a transaction to keep filesystem consistency after a crash. Also - * filesystems usually want to do some IO on dquot from ->mark_dirty which is - * called with dqptr_sem held. - * i_mutex on quota files is special (it's below dqio_mutex) - */ - -static DEFINE_SPINLOCK(dq_list_lock); -static DEFINE_SPINLOCK(dq_state_lock); -DEFINE_SPINLOCK(dq_data_lock); -EXPORT_SYMBOL(dq_data_lock); - -static char *quotatypes[] = INITQFNAMES; -static struct quota_format_type *quota_formats; /* List of registered formats */ -static struct quota_module_name module_names[] = INIT_QUOTA_MODULE_NAMES; - -/* SLAB cache for dquot structures */ -static struct kmem_cache *dquot_cachep; - -int register_quota_format(struct quota_format_type *fmt) -{ - spin_lock(&dq_list_lock); - fmt->qf_next = quota_formats; - quota_formats = fmt; - spin_unlock(&dq_list_lock); - return 0; -} -EXPORT_SYMBOL(register_quota_format); - -void unregister_quota_format(struct quota_format_type *fmt) -{ - struct quota_format_type **actqf; - - spin_lock(&dq_list_lock); - for (actqf = "a_formats; *actqf && *actqf != fmt; actqf = &(*actqf)->qf_next); - if (*actqf) - *actqf = (*actqf)->qf_next; - spin_unlock(&dq_list_lock); -} -EXPORT_SYMBOL(unregister_quota_format); - -static struct quota_format_type *find_quota_format(int id) -{ - struct quota_format_type *actqf; - - spin_lock(&dq_list_lock); - for (actqf = quota_formats; actqf && actqf->qf_fmt_id != id; actqf = actqf->qf_next); - if (!actqf || !try_module_get(actqf->qf_owner)) { - int qm; - - spin_unlock(&dq_list_lock); - - for (qm = 0; module_names[qm].qm_fmt_id && module_names[qm].qm_fmt_id != id; qm++); - if (!module_names[qm].qm_fmt_id || request_module(module_names[qm].qm_mod_name)) - return NULL; - - spin_lock(&dq_list_lock); - for (actqf = quota_formats; actqf && actqf->qf_fmt_id != id; actqf = actqf->qf_next); - if (actqf && !try_module_get(actqf->qf_owner)) - actqf = NULL; - } - spin_unlock(&dq_list_lock); - return actqf; -} - -static void put_quota_format(struct quota_format_type *fmt) -{ - module_put(fmt->qf_owner); -} - -/* - * Dquot List Management: - * The quota code uses three lists for dquot management: the inuse_list, - * free_dquots, and dquot_hash[] array. A single dquot structure may be - * on all three lists, depending on its current state. - * - * All dquots are placed to the end of inuse_list when first created, and this - * list is used for invalidate operation, which must look at every dquot. - * - * Unused dquots (dq_count == 0) are added to the free_dquots list when freed, - * and this list is searched whenever we need an available dquot. Dquots are - * removed from the list as soon as they are used again, and - * dqstats.free_dquots gives the number of dquots on the list. When - * dquot is invalidated it's completely released from memory. - * - * Dquots with a specific identity (device, type and id) are placed on - * one of the dquot_hash[] hash chains. The provides an efficient search - * mechanism to locate a specific dquot. - */ - -static LIST_HEAD(inuse_list); -static LIST_HEAD(free_dquots); -static unsigned int dq_hash_bits, dq_hash_mask; -static struct hlist_head *dquot_hash; - -struct dqstats dqstats; -EXPORT_SYMBOL(dqstats); - -static inline unsigned int -hashfn(const struct super_block *sb, unsigned int id, int type) -{ - unsigned long tmp; - - tmp = (((unsigned long)sb>>L1_CACHE_SHIFT) ^ id) * (MAXQUOTAS - type); - return (tmp + (tmp >> dq_hash_bits)) & dq_hash_mask; -} - -/* - * Following list functions expect dq_list_lock to be held - */ -static inline void insert_dquot_hash(struct dquot *dquot) -{ - struct hlist_head *head = dquot_hash + hashfn(dquot->dq_sb, dquot->dq_id, dquot->dq_type); - hlist_add_head(&dquot->dq_hash, head); -} - -static inline void remove_dquot_hash(struct dquot *dquot) -{ - hlist_del_init(&dquot->dq_hash); -} - -static inline struct dquot *find_dquot(unsigned int hashent, struct super_block *sb, unsigned int id, int type) -{ - struct hlist_node *node; - struct dquot *dquot; - - hlist_for_each (node, dquot_hash+hashent) { - dquot = hlist_entry(node, struct dquot, dq_hash); - if (dquot->dq_sb == sb && dquot->dq_id == id && dquot->dq_type == type) - return dquot; - } - return NODQUOT; -} - -/* Add a dquot to the tail of the free list */ -static inline void put_dquot_last(struct dquot *dquot) -{ - list_add_tail(&dquot->dq_free, &free_dquots); - dqstats.free_dquots++; -} - -static inline void remove_free_dquot(struct dquot *dquot) -{ - if (list_empty(&dquot->dq_free)) - return; - list_del_init(&dquot->dq_free); - dqstats.free_dquots--; -} - -static inline void put_inuse(struct dquot *dquot) -{ - /* We add to the back of inuse list so we don't have to restart - * when traversing this list and we block */ - list_add_tail(&dquot->dq_inuse, &inuse_list); - dqstats.allocated_dquots++; -} - -static inline void remove_inuse(struct dquot *dquot) -{ - dqstats.allocated_dquots--; - list_del(&dquot->dq_inuse); -} -/* - * End of list functions needing dq_list_lock - */ - -static void wait_on_dquot(struct dquot *dquot) -{ - mutex_lock(&dquot->dq_lock); - mutex_unlock(&dquot->dq_lock); -} - -static inline int dquot_dirty(struct dquot *dquot) -{ - return test_bit(DQ_MOD_B, &dquot->dq_flags); -} - -static inline int mark_dquot_dirty(struct dquot *dquot) -{ - return dquot->dq_sb->dq_op->mark_dirty(dquot); -} - -int dquot_mark_dquot_dirty(struct dquot *dquot) -{ - spin_lock(&dq_list_lock); - if (!test_and_set_bit(DQ_MOD_B, &dquot->dq_flags)) - list_add(&dquot->dq_dirty, &sb_dqopt(dquot->dq_sb)-> - info[dquot->dq_type].dqi_dirty_list); - spin_unlock(&dq_list_lock); - return 0; -} -EXPORT_SYMBOL(dquot_mark_dquot_dirty); - -/* This function needs dq_list_lock */ -static inline int clear_dquot_dirty(struct dquot *dquot) -{ - if (!test_and_clear_bit(DQ_MOD_B, &dquot->dq_flags)) - return 0; - list_del_init(&dquot->dq_dirty); - return 1; -} - -void mark_info_dirty(struct super_block *sb, int type) -{ - set_bit(DQF_INFO_DIRTY_B, &sb_dqopt(sb)->info[type].dqi_flags); -} -EXPORT_SYMBOL(mark_info_dirty); - -/* - * Read dquot from disk and alloc space for it - */ - -int dquot_acquire(struct dquot *dquot) -{ - int ret = 0, ret2 = 0; - struct quota_info *dqopt = sb_dqopt(dquot->dq_sb); - - mutex_lock(&dquot->dq_lock); - mutex_lock(&dqopt->dqio_mutex); - if (!test_bit(DQ_READ_B, &dquot->dq_flags)) - ret = dqopt->ops[dquot->dq_type]->read_dqblk(dquot); - if (ret < 0) - goto out_iolock; - set_bit(DQ_READ_B, &dquot->dq_flags); - /* Instantiate dquot if needed */ - if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && !dquot->dq_off) { - ret = dqopt->ops[dquot->dq_type]->commit_dqblk(dquot); - /* Write the info if needed */ - if (info_dirty(&dqopt->info[dquot->dq_type])) - ret2 = dqopt->ops[dquot->dq_type]->write_file_info(dquot->dq_sb, dquot->dq_type); - if (ret < 0) - goto out_iolock; - if (ret2 < 0) { - ret = ret2; - goto out_iolock; - } - } - set_bit(DQ_ACTIVE_B, &dquot->dq_flags); -out_iolock: - mutex_unlock(&dqopt->dqio_mutex); - mutex_unlock(&dquot->dq_lock); - return ret; -} -EXPORT_SYMBOL(dquot_acquire); - -/* - * Write dquot to disk - */ -int dquot_commit(struct dquot *dquot) -{ - int ret = 0, ret2 = 0; - struct quota_info *dqopt = sb_dqopt(dquot->dq_sb); - - mutex_lock(&dqopt->dqio_mutex); - spin_lock(&dq_list_lock); - if (!clear_dquot_dirty(dquot)) { - spin_unlock(&dq_list_lock); - goto out_sem; - } - spin_unlock(&dq_list_lock); - /* Inactive dquot can be only if there was error during read/init - * => we have better not writing it */ - if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) { - ret = dqopt->ops[dquot->dq_type]->commit_dqblk(dquot); - if (info_dirty(&dqopt->info[dquot->dq_type])) - ret2 = dqopt->ops[dquot->dq_type]->write_file_info(dquot->dq_sb, dquot->dq_type); - if (ret >= 0) - ret = ret2; - } -out_sem: - mutex_unlock(&dqopt->dqio_mutex); - return ret; -} -EXPORT_SYMBOL(dquot_commit); - -/* - * Release dquot - */ -int dquot_release(struct dquot *dquot) -{ - int ret = 0, ret2 = 0; - struct quota_info *dqopt = sb_dqopt(dquot->dq_sb); - - mutex_lock(&dquot->dq_lock); - /* Check whether we are not racing with some other dqget() */ - if (atomic_read(&dquot->dq_count) > 1) - goto out_dqlock; - mutex_lock(&dqopt->dqio_mutex); - if (dqopt->ops[dquot->dq_type]->release_dqblk) { - ret = dqopt->ops[dquot->dq_type]->release_dqblk(dquot); - /* Write the info */ - if (info_dirty(&dqopt->info[dquot->dq_type])) - ret2 = dqopt->ops[dquot->dq_type]->write_file_info(dquot->dq_sb, dquot->dq_type); - if (ret >= 0) - ret = ret2; - } - clear_bit(DQ_ACTIVE_B, &dquot->dq_flags); - mutex_unlock(&dqopt->dqio_mutex); -out_dqlock: - mutex_unlock(&dquot->dq_lock); - return ret; -} -EXPORT_SYMBOL(dquot_release); - -void dquot_destroy(struct dquot *dquot) -{ - kmem_cache_free(dquot_cachep, dquot); -} -EXPORT_SYMBOL(dquot_destroy); - -static inline void do_destroy_dquot(struct dquot *dquot) -{ - dquot->dq_sb->dq_op->destroy_dquot(dquot); -} - -/* Invalidate all dquots on the list. Note that this function is called after - * quota is disabled and pointers from inodes removed so there cannot be new - * quota users. There can still be some users of quotas due to inodes being - * just deleted or pruned by prune_icache() (those are not attached to any - * list) or parallel quotactl call. We have to wait for such users. - */ -static void invalidate_dquots(struct super_block *sb, int type) -{ - struct dquot *dquot, *tmp; - -restart: - spin_lock(&dq_list_lock); - list_for_each_entry_safe(dquot, tmp, &inuse_list, dq_inuse) { - if (dquot->dq_sb != sb) - continue; - if (dquot->dq_type != type) - continue; - /* Wait for dquot users */ - if (atomic_read(&dquot->dq_count)) { - DEFINE_WAIT(wait); - - atomic_inc(&dquot->dq_count); - prepare_to_wait(&dquot->dq_wait_unused, &wait, - TASK_UNINTERRUPTIBLE); - spin_unlock(&dq_list_lock); - /* Once dqput() wakes us up, we know it's time to free - * the dquot. - * IMPORTANT: we rely on the fact that there is always - * at most one process waiting for dquot to free. - * Otherwise dq_count would be > 1 and we would never - * wake up. - */ - if (atomic_read(&dquot->dq_count) > 1) - schedule(); - finish_wait(&dquot->dq_wait_unused, &wait); - dqput(dquot); - /* At this moment dquot() need not exist (it could be - * reclaimed by prune_dqcache(). Hence we must - * restart. */ - goto restart; - } - /* - * Quota now has no users and it has been written on last - * dqput() - */ - remove_dquot_hash(dquot); - remove_free_dquot(dquot); - remove_inuse(dquot); - do_destroy_dquot(dquot); - } - spin_unlock(&dq_list_lock); -} - -/* Call callback for every active dquot on given filesystem */ -int dquot_scan_active(struct super_block *sb, - int (*fn)(struct dquot *dquot, unsigned long priv), - unsigned long priv) -{ - struct dquot *dquot, *old_dquot = NULL; - int ret = 0; - - mutex_lock(&sb_dqopt(sb)->dqonoff_mutex); - spin_lock(&dq_list_lock); - list_for_each_entry(dquot, &inuse_list, dq_inuse) { - if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) - continue; - if (dquot->dq_sb != sb) - continue; - /* Now we have active dquot so we can just increase use count */ - atomic_inc(&dquot->dq_count); - dqstats.lookups++; - spin_unlock(&dq_list_lock); - dqput(old_dquot); - old_dquot = dquot; - ret = fn(dquot, priv); - if (ret < 0) - goto out; - spin_lock(&dq_list_lock); - /* We are safe to continue now because our dquot could not - * be moved out of the inuse list while we hold the reference */ - } - spin_unlock(&dq_list_lock); -out: - dqput(old_dquot); - mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex); - return ret; -} -EXPORT_SYMBOL(dquot_scan_active); - -int vfs_quota_sync(struct super_block *sb, int type) -{ - struct list_head *dirty; - struct dquot *dquot; - struct quota_info *dqopt = sb_dqopt(sb); - int cnt; - - mutex_lock(&dqopt->dqonoff_mutex); - for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - if (type != -1 && cnt != type) - continue; - if (!sb_has_quota_active(sb, cnt)) - continue; - spin_lock(&dq_list_lock); - dirty = &dqopt->info[cnt].dqi_dirty_list; - while (!list_empty(dirty)) { - dquot = list_first_entry(dirty, struct dquot, dq_dirty); - /* Dirty and inactive can be only bad dquot... */ - if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) { - clear_dquot_dirty(dquot); - continue; - } - /* Now we have active dquot from which someone is - * holding reference so we can safely just increase - * use count */ - atomic_inc(&dquot->dq_count); - dqstats.lookups++; - spin_unlock(&dq_list_lock); - sb->dq_op->write_dquot(dquot); - dqput(dquot); - spin_lock(&dq_list_lock); - } - spin_unlock(&dq_list_lock); - } - - for (cnt = 0; cnt < MAXQUOTAS; cnt++) - if ((cnt == type || type == -1) && sb_has_quota_active(sb, cnt) - && info_dirty(&dqopt->info[cnt])) - sb->dq_op->write_info(sb, cnt); - spin_lock(&dq_list_lock); - dqstats.syncs++; - spin_unlock(&dq_list_lock); - mutex_unlock(&dqopt->dqonoff_mutex); - - return 0; -} -EXPORT_SYMBOL(vfs_quota_sync); - -/* Free unused dquots from cache */ -static void prune_dqcache(int count) -{ - struct list_head *head; - struct dquot *dquot; - - head = free_dquots.prev; - while (head != &free_dquots && count) { - dquot = list_entry(head, struct dquot, dq_free); - remove_dquot_hash(dquot); - remove_free_dquot(dquot); - remove_inuse(dquot); - do_destroy_dquot(dquot); - count--; - head = free_dquots.prev; - } -} - -/* - * This is called from kswapd when we think we need some - * more memory - */ - -static int shrink_dqcache_memory(int nr, gfp_t gfp_mask) -{ - if (nr) { - spin_lock(&dq_list_lock); - prune_dqcache(nr); - spin_unlock(&dq_list_lock); - } - return (dqstats.free_dquots / 100) * sysctl_vfs_cache_pressure; -} - -static struct shrinker dqcache_shrinker = { - .shrink = shrink_dqcache_memory, - .seeks = DEFAULT_SEEKS, -}; - -/* - * Put reference to dquot - * NOTE: If you change this function please check whether dqput_blocks() works right... - */ -void dqput(struct dquot *dquot) -{ - int ret; - - if (!dquot) - return; -#ifdef __DQUOT_PARANOIA - if (!atomic_read(&dquot->dq_count)) { - printk("VFS: dqput: trying to free free dquot\n"); - printk("VFS: device %s, dquot of %s %d\n", - dquot->dq_sb->s_id, - quotatypes[dquot->dq_type], - dquot->dq_id); - BUG(); - } -#endif - - spin_lock(&dq_list_lock); - dqstats.drops++; - spin_unlock(&dq_list_lock); -we_slept: - spin_lock(&dq_list_lock); - if (atomic_read(&dquot->dq_count) > 1) { - /* We have more than one user... nothing to do */ - atomic_dec(&dquot->dq_count); - /* Releasing dquot during quotaoff phase? */ - if (!sb_has_quota_active(dquot->dq_sb, dquot->dq_type) && - atomic_read(&dquot->dq_count) == 1) - wake_up(&dquot->dq_wait_unused); - spin_unlock(&dq_list_lock); - return; - } - /* Need to release dquot? */ - if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && dquot_dirty(dquot)) { - spin_unlock(&dq_list_lock); - /* Commit dquot before releasing */ - ret = dquot->dq_sb->dq_op->write_dquot(dquot); - if (ret < 0) { - printk(KERN_ERR "VFS: cannot write quota structure on " - "device %s (error %d). Quota may get out of " - "sync!\n", dquot->dq_sb->s_id, ret); - /* - * We clear dirty bit anyway, so that we avoid - * infinite loop here - */ - spin_lock(&dq_list_lock); - clear_dquot_dirty(dquot); - spin_unlock(&dq_list_lock); - } - goto we_slept; - } - /* Clear flag in case dquot was inactive (something bad happened) */ - clear_dquot_dirty(dquot); - if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) { - spin_unlock(&dq_list_lock); - dquot->dq_sb->dq_op->release_dquot(dquot); - goto we_slept; - } - atomic_dec(&dquot->dq_count); -#ifdef __DQUOT_PARANOIA - /* sanity check */ - BUG_ON(!list_empty(&dquot->dq_free)); -#endif - put_dquot_last(dquot); - spin_unlock(&dq_list_lock); -} -EXPORT_SYMBOL(dqput); - -struct dquot *dquot_alloc(struct super_block *sb, int type) -{ - return kmem_cache_zalloc(dquot_cachep, GFP_NOFS); -} -EXPORT_SYMBOL(dquot_alloc); - -static struct dquot *get_empty_dquot(struct super_block *sb, int type) -{ - struct dquot *dquot; - - dquot = sb->dq_op->alloc_dquot(sb, type); - if(!dquot) - return NODQUOT; - - mutex_init(&dquot->dq_lock); - INIT_LIST_HEAD(&dquot->dq_free); - INIT_LIST_HEAD(&dquot->dq_inuse); - INIT_HLIST_NODE(&dquot->dq_hash); - INIT_LIST_HEAD(&dquot->dq_dirty); - init_waitqueue_head(&dquot->dq_wait_unused); - dquot->dq_sb = sb; - dquot->dq_type = type; - atomic_set(&dquot->dq_count, 1); - - return dquot; -} - -/* - * Get reference to dquot - * - * Locking is slightly tricky here. We are guarded from parallel quotaoff() - * destroying our dquot by: - * a) checking for quota flags under dq_list_lock and - * b) getting a reference to dquot before we release dq_list_lock - */ -struct dquot *dqget(struct super_block *sb, unsigned int id, int type) -{ - unsigned int hashent = hashfn(sb, id, type); - struct dquot *dquot = NODQUOT, *empty = NODQUOT; - - if (!sb_has_quota_active(sb, type)) - return NODQUOT; -we_slept: - spin_lock(&dq_list_lock); - spin_lock(&dq_state_lock); - if (!sb_has_quota_active(sb, type)) { - spin_unlock(&dq_state_lock); - spin_unlock(&dq_list_lock); - goto out; - } - spin_unlock(&dq_state_lock); - - if ((dquot = find_dquot(hashent, sb, id, type)) == NODQUOT) { - if (empty == NODQUOT) { - spin_unlock(&dq_list_lock); - if ((empty = get_empty_dquot(sb, type)) == NODQUOT) - schedule(); /* Try to wait for a moment... */ - goto we_slept; - } - dquot = empty; - empty = NODQUOT; - dquot->dq_id = id; - /* all dquots go on the inuse_list */ - put_inuse(dquot); - /* hash it first so it can be found */ - insert_dquot_hash(dquot); - dqstats.lookups++; - spin_unlock(&dq_list_lock); - } else { - if (!atomic_read(&dquot->dq_count)) - remove_free_dquot(dquot); - atomic_inc(&dquot->dq_count); - dqstats.cache_hits++; - dqstats.lookups++; - spin_unlock(&dq_list_lock); - } - /* Wait for dq_lock - after this we know that either dquot_release() is already - * finished or it will be canceled due to dq_count > 1 test */ - wait_on_dquot(dquot); - /* Read the dquot and instantiate it (everything done only if needed) */ - if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && sb->dq_op->acquire_dquot(dquot) < 0) { - dqput(dquot); - dquot = NODQUOT; - goto out; - } -#ifdef __DQUOT_PARANOIA - BUG_ON(!dquot->dq_sb); /* Has somebody invalidated entry under us? */ -#endif -out: - if (empty) - do_destroy_dquot(empty); - - return dquot; -} -EXPORT_SYMBOL(dqget); - -static int dqinit_needed(struct inode *inode, int type) -{ - int cnt; - - if (IS_NOQUOTA(inode)) - return 0; - if (type != -1) - return inode->i_dquot[type] == NODQUOT; - for (cnt = 0; cnt < MAXQUOTAS; cnt++) - if (inode->i_dquot[cnt] == NODQUOT) - return 1; - return 0; -} - -/* This routine is guarded by dqonoff_mutex mutex */ -static void add_dquot_ref(struct super_block *sb, int type) -{ - struct inode *inode, *old_inode = NULL; - - spin_lock(&inode_lock); - list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { - if (!atomic_read(&inode->i_writecount)) - continue; - if (!dqinit_needed(inode, type)) - continue; - if (inode->i_state & (I_FREEING|I_WILL_FREE)) - continue; - - __iget(inode); - spin_unlock(&inode_lock); - - iput(old_inode); - sb->dq_op->initialize(inode, type); - /* We hold a reference to 'inode' so it couldn't have been - * removed from s_inodes list while we dropped the inode_lock. - * We cannot iput the inode now as we can be holding the last - * reference and we cannot iput it under inode_lock. So we - * keep the reference and iput it later. */ - old_inode = inode; - spin_lock(&inode_lock); - } - spin_unlock(&inode_lock); - iput(old_inode); -} - -/* Return 0 if dqput() won't block (note that 1 doesn't necessarily mean blocking) */ -static inline int dqput_blocks(struct dquot *dquot) -{ - if (atomic_read(&dquot->dq_count) <= 1) - return 1; - return 0; -} - -/* Remove references to dquots from inode - add dquot to list for freeing if needed */ -/* We can't race with anybody because we hold dqptr_sem for writing... */ -static int remove_inode_dquot_ref(struct inode *inode, int type, - struct list_head *tofree_head) -{ - struct dquot *dquot = inode->i_dquot[type]; - - inode->i_dquot[type] = NODQUOT; - if (dquot != NODQUOT) { - if (dqput_blocks(dquot)) { -#ifdef __DQUOT_PARANOIA - if (atomic_read(&dquot->dq_count) != 1) - printk(KERN_WARNING "VFS: Adding dquot with dq_count %d to dispose list.\n", atomic_read(&dquot->dq_count)); -#endif - spin_lock(&dq_list_lock); - list_add(&dquot->dq_free, tofree_head); /* As dquot must have currently users it can't be on the free list... */ - spin_unlock(&dq_list_lock); - return 1; - } - else - dqput(dquot); /* We have guaranteed we won't block */ - } - return 0; -} - -/* Free list of dquots - called from inode.c */ -/* dquots are removed from inodes, no new references can be got so we are the only ones holding reference */ -static void put_dquot_list(struct list_head *tofree_head) -{ - struct list_head *act_head; - struct dquot *dquot; - - act_head = tofree_head->next; - /* So now we have dquots on the list... Just free them */ - while (act_head != tofree_head) { - dquot = list_entry(act_head, struct dquot, dq_free); - act_head = act_head->next; - list_del_init(&dquot->dq_free); /* Remove dquot from the list so we won't have problems... */ - dqput(dquot); - } -} - -static void remove_dquot_ref(struct super_block *sb, int type, - struct list_head *tofree_head) -{ - struct inode *inode; - - spin_lock(&inode_lock); - list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { - if (!IS_NOQUOTA(inode)) - remove_inode_dquot_ref(inode, type, tofree_head); - } - spin_unlock(&inode_lock); -} - -/* Gather all references from inodes and drop them */ -static void drop_dquot_ref(struct super_block *sb, int type) -{ - LIST_HEAD(tofree_head); - - if (sb->dq_op) { - down_write(&sb_dqopt(sb)->dqptr_sem); - remove_dquot_ref(sb, type, &tofree_head); - up_write(&sb_dqopt(sb)->dqptr_sem); - put_dquot_list(&tofree_head); - } -} - -static inline void dquot_incr_inodes(struct dquot *dquot, qsize_t number) -{ - dquot->dq_dqb.dqb_curinodes += number; -} - -static inline void dquot_incr_space(struct dquot *dquot, qsize_t number) -{ - dquot->dq_dqb.dqb_curspace += number; -} - -static inline void dquot_resv_space(struct dquot *dquot, qsize_t number) -{ - dquot->dq_dqb.dqb_rsvspace += number; -} - -/* - * Claim reserved quota space - */ -static void dquot_claim_reserved_space(struct dquot *dquot, - qsize_t number) -{ - WARN_ON(dquot->dq_dqb.dqb_rsvspace < number); - dquot->dq_dqb.dqb_curspace += number; - dquot->dq_dqb.dqb_rsvspace -= number; -} - -static inline -void dquot_free_reserved_space(struct dquot *dquot, qsize_t number) -{ - dquot->dq_dqb.dqb_rsvspace -= number; -} - -static inline void dquot_decr_inodes(struct dquot *dquot, qsize_t number) -{ - if (sb_dqopt(dquot->dq_sb)->flags & DQUOT_NEGATIVE_USAGE || - dquot->dq_dqb.dqb_curinodes >= number) - dquot->dq_dqb.dqb_curinodes -= number; - else - dquot->dq_dqb.dqb_curinodes = 0; - if (dquot->dq_dqb.dqb_curinodes <= dquot->dq_dqb.dqb_isoftlimit) - dquot->dq_dqb.dqb_itime = (time_t) 0; - clear_bit(DQ_INODES_B, &dquot->dq_flags); -} - -static inline void dquot_decr_space(struct dquot *dquot, qsize_t number) -{ - if (sb_dqopt(dquot->dq_sb)->flags & DQUOT_NEGATIVE_USAGE || - dquot->dq_dqb.dqb_curspace >= number) - dquot->dq_dqb.dqb_curspace -= number; - else - dquot->dq_dqb.dqb_curspace = 0; - if (dquot->dq_dqb.dqb_curspace <= dquot->dq_dqb.dqb_bsoftlimit) - dquot->dq_dqb.dqb_btime = (time_t) 0; - clear_bit(DQ_BLKS_B, &dquot->dq_flags); -} - -static int warning_issued(struct dquot *dquot, const int warntype) -{ - int flag = (warntype == QUOTA_NL_BHARDWARN || - warntype == QUOTA_NL_BSOFTLONGWARN) ? DQ_BLKS_B : - ((warntype == QUOTA_NL_IHARDWARN || - warntype == QUOTA_NL_ISOFTLONGWARN) ? DQ_INODES_B : 0); - - if (!flag) - return 0; - return test_and_set_bit(flag, &dquot->dq_flags); -} - -#ifdef CONFIG_PRINT_QUOTA_WARNING -static int flag_print_warnings = 1; - -static inline int need_print_warning(struct dquot *dquot) -{ - if (!flag_print_warnings) - return 0; - - switch (dquot->dq_type) { - case USRQUOTA: - return current_fsuid() == dquot->dq_id; - case GRPQUOTA: - return in_group_p(dquot->dq_id); - } - return 0; -} - -/* Print warning to user which exceeded quota */ -static void print_warning(struct dquot *dquot, const int warntype) -{ - char *msg = NULL; - struct tty_struct *tty; - - if (warntype == QUOTA_NL_IHARDBELOW || - warntype == QUOTA_NL_ISOFTBELOW || - warntype == QUOTA_NL_BHARDBELOW || - warntype == QUOTA_NL_BSOFTBELOW || !need_print_warning(dquot)) - return; - - tty = get_current_tty(); - if (!tty) - return; - tty_write_message(tty, dquot->dq_sb->s_id); - if (warntype == QUOTA_NL_ISOFTWARN || warntype == QUOTA_NL_BSOFTWARN) - tty_write_message(tty, ": warning, "); - else - tty_write_message(tty, ": write failed, "); - tty_write_message(tty, quotatypes[dquot->dq_type]); - switch (warntype) { - case QUOTA_NL_IHARDWARN: - msg = " file limit reached.\r\n"; - break; - case QUOTA_NL_ISOFTLONGWARN: - msg = " file quota exceeded too long.\r\n"; - break; - case QUOTA_NL_ISOFTWARN: - msg = " file quota exceeded.\r\n"; - break; - case QUOTA_NL_BHARDWARN: - msg = " block limit reached.\r\n"; - break; - case QUOTA_NL_BSOFTLONGWARN: - msg = " block quota exceeded too long.\r\n"; - break; - case QUOTA_NL_BSOFTWARN: - msg = " block quota exceeded.\r\n"; - break; - } - tty_write_message(tty, msg); - tty_kref_put(tty); -} -#endif - -#ifdef CONFIG_QUOTA_NETLINK_INTERFACE - -/* Netlink family structure for quota */ -static struct genl_family quota_genl_family = { - .id = GENL_ID_GENERATE, - .hdrsize = 0, - .name = "VFS_DQUOT", - .version = 1, - .maxattr = QUOTA_NL_A_MAX, -}; - -/* Send warning to userspace about user which exceeded quota */ -static void send_warning(const struct dquot *dquot, const char warntype) -{ - static atomic_t seq; - struct sk_buff *skb; - void *msg_head; - int ret; - int msg_size = 4 * nla_total_size(sizeof(u32)) + - 2 * nla_total_size(sizeof(u64)); - - /* We have to allocate using GFP_NOFS as we are called from a - * filesystem performing write and thus further recursion into - * the fs to free some data could cause deadlocks. */ - skb = genlmsg_new(msg_size, GFP_NOFS); - if (!skb) { - printk(KERN_ERR - "VFS: Not enough memory to send quota warning.\n"); - return; - } - msg_head = genlmsg_put(skb, 0, atomic_add_return(1, &seq), - "a_genl_family, 0, QUOTA_NL_C_WARNING); - if (!msg_head) { - printk(KERN_ERR - "VFS: Cannot store netlink header in quota warning.\n"); - goto err_out; - } - ret = nla_put_u32(skb, QUOTA_NL_A_QTYPE, dquot->dq_type); - if (ret) - goto attr_err_out; - ret = nla_put_u64(skb, QUOTA_NL_A_EXCESS_ID, dquot->dq_id); - if (ret) - goto attr_err_out; - ret = nla_put_u32(skb, QUOTA_NL_A_WARNING, warntype); - if (ret) - goto attr_err_out; - ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MAJOR, - MAJOR(dquot->dq_sb->s_dev)); - if (ret) - goto attr_err_out; - ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MINOR, - MINOR(dquot->dq_sb->s_dev)); - if (ret) - goto attr_err_out; - ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID, current_uid()); - if (ret) - goto attr_err_out; - genlmsg_end(skb, msg_head); - - ret = genlmsg_multicast(skb, 0, quota_genl_family.i |