⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dquot.c

📁 elinux jffs初始版本 具体了解JFFS的文件系统!
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Implementation of the diskquota system for the LINUX operating * system. QUOTA is implemented using the BSD systemcall interface as * the means of communication with the user level. Currently only the * ext2-filesystem has support for diskquotas. Other filesystems may * be added in future time. 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 the LINUX inode-subsystem with added complexity of the * diskquota system. This implementation is not based on any BSD * kernel sourcecode. *  * Version: $Id: dquot.c,v 1.2 1999/07/16 23:52:00 bjornw Exp $ *  * Author:  Marco van Wieringen <mvw@mcs.ow.nl> <mvw@tnix.net> *  * Fixes:   Dmitry Gorodchanin <pgmdsg@ibi.com>, 11 Feb 96 *	    removed race conditions in dqput(), dqget() and iput().  *          Nick Kralevich <nickkral@cal.alumni.berkeley.edu>, 21 Jul 97 *          Fixed a condition where user and group quotas could get mixed up. * * (C) Copyright 1994, 1995 Marco van Wieringen  * */#include <linux/errno.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/types.h>#include <linux/string.h>#include <linux/fcntl.h>#include <linux/stat.h>#include <linux/tty.h>#include <linux/malloc.h>#include <linux/mount.h>#include <asm/segment.h>#define __DQUOT_VERSION__	"dquot_5.6.0"static char quotamessage[MAX_QUOTA_MESSAGE];static char *quotatypes[] = INITQFNAMES;static int nr_dquots = 0, nr_free_dquots = 0;static struct dquot *hash_table[NR_DQHASH];static struct dquot *first_dquot;static struct dqstats dqstats;static struct wait_queue *dquot_wait = (struct wait_queue *)NULL;extern void add_dquot_ref(kdev_t dev, short type);extern void reset_dquot_ptrs(kdev_t dev, short type);#ifndef min#define min(a,b) ((a) < (b)) ? (a) : (b)#endif/* * Functions for management of the hashlist. */static inline int const hashfn(kdev_t dev, unsigned int id, short type){	return((HASHDEV(dev) ^ id) * (MAXQUOTAS - type)) % NR_DQHASH;}static inline struct dquot **const hash(kdev_t dev, unsigned int id, short type){	return(hash_table + hashfn(dev, id, type));}static inline int has_quota_enabled(kdev_t dev, short type){	struct vfsmount *vfsmnt;	return((vfsmnt = lookup_vfsmnt(dev)) != (struct vfsmount *)NULL &&	       (vfsmnt->mnt_quotas[type] != (struct file *)NULL));}static void insert_dquot_free(struct dquot *dquot){	dquot->dq_next = first_dquot;	dquot->dq_prev = first_dquot->dq_prev;	dquot->dq_next->dq_prev = dquot;	dquot->dq_prev->dq_next = dquot;	first_dquot = dquot;}static void remove_dquot_free(struct dquot *dquot){	if (first_dquot == dquot)		first_dquot = first_dquot->dq_next;	if (dquot->dq_next)		dquot->dq_next->dq_prev = dquot->dq_prev;	if (dquot->dq_prev)		dquot->dq_prev->dq_next = dquot->dq_next;	dquot->dq_next = dquot->dq_prev = NODQUOT;}static void insert_dquot_hash(struct dquot *dquot){	struct dquot **hash_ent;	hash_ent = hash(dquot->dq_dev, dquot->dq_id, dquot->dq_type);	dquot->dq_hash_next = *hash_ent;	dquot->dq_hash_prev = NODQUOT;	if (dquot->dq_hash_next)		dquot->dq_hash_next->dq_hash_prev = dquot;	*hash_ent = dquot;}static void remove_dquot_hash(struct dquot *dquot){	struct dquot **hash_ent;	hash_ent = hash(dquot->dq_dev, dquot->dq_id, dquot->dq_type);	if (*hash_ent == dquot)		*hash_ent = dquot->dq_hash_next;	if (dquot->dq_hash_next)		dquot->dq_hash_next->dq_hash_prev = dquot->dq_hash_prev;	if (dquot->dq_hash_prev)		dquot->dq_hash_prev->dq_hash_next = dquot->dq_hash_next;	dquot->dq_hash_prev = dquot->dq_hash_next = NODQUOT;}static void put_last_free(struct dquot *dquot){	remove_dquot_free(dquot);	dquot->dq_prev = first_dquot->dq_prev;	dquot->dq_prev->dq_next = dquot;	dquot->dq_next = first_dquot;	dquot->dq_next->dq_prev = dquot;}static void grow_dquots(void){	struct dquot *dquot;	int cnt;	if (!(dquot = (struct dquot*) get_free_page(GFP_KERNEL)))		return;	dqstats.pages_allocated++;	cnt = PAGE_SIZE / sizeof(struct dquot);	nr_dquots += cnt;	nr_free_dquots += cnt;	if (!first_dquot) {		dquot->dq_next = dquot->dq_prev = first_dquot = dquot++;		cnt--;	}	for (; cnt; cnt--)		insert_dquot_free(dquot++);}/* * Functions for locking and waiting on dquots. */static void __wait_on_dquot(struct dquot *dquot){	struct wait_queue wait = {current, NULL};	add_wait_queue(&dquot->dq_wait, &wait);repeat:	current->state = TASK_UNINTERRUPTIBLE;	if (dquot->dq_flags & DQ_LOCKED) {		dquot->dq_flags |= DQ_WANT;		schedule();		goto repeat;	}	remove_wait_queue(&dquot->dq_wait, &wait);	current->state = TASK_RUNNING;}static inline void wait_on_dquot(struct dquot *dquot){	if (dquot->dq_flags & DQ_LOCKED)		__wait_on_dquot(dquot);}static inline void lock_dquot(struct dquot *dquot){	wait_on_dquot(dquot);	dquot->dq_flags |= DQ_LOCKED;}static inline void unlock_dquot(struct dquot *dquot){	dquot->dq_flags &= ~DQ_LOCKED;	if (dquot->dq_flags & DQ_WANT) {		dquot->dq_flags &= ~DQ_WANT;		wake_up(&dquot->dq_wait);	}}/* * Note that we don't want to disturb any wait-queues when we discard * an dquot. * * FIXME: As soon as we have a nice solution for the inode problem we *		  can also fix this one. I.e. the volatile part. */static void clear_dquot(struct dquot * dquot){	struct wait_queue *wait;	wait_on_dquot(dquot);	remove_dquot_hash(dquot);	remove_dquot_free(dquot);	wait = ((volatile struct dquot *) dquot)->dq_wait;	if (dquot->dq_count)		nr_free_dquots++;	memset(dquot, 0, sizeof(*dquot));	((volatile struct dquot *) dquot)->dq_wait = wait;	insert_dquot_free(dquot);}static void write_dquot(struct dquot *dquot){	short type = dquot->dq_type;	struct file *filp = dquot->dq_mnt->mnt_quotas[type];	unsigned short fs;	if (!(dquot->dq_flags & DQ_MOD) || (filp == (struct file *)NULL))		return;	lock_dquot(dquot);	down(&dquot->dq_mnt->mnt_sem);	if (filp->f_op->lseek) {		if (filp->f_op->lseek(filp->f_inode, filp,		    dqoff(dquot->dq_id), 0) != dqoff(dquot->dq_id)) {			up(&dquot->dq_mnt->mnt_sem);			unlock_dquot(dquot);			return;		}	}	else	{		int p = dqoff(dquot->dq_id);		if(p>=0)			filp->f_pos = p;	}	fs = get_fs();	set_fs(KERNEL_DS);	if (filp->f_op->write(filp->f_inode, filp,	   (char *)&dquot->dq_dqb, sizeof(struct dqblk)) == sizeof(struct dqblk))		dquot->dq_flags &= ~DQ_MOD;	up(&dquot->dq_mnt->mnt_sem);	set_fs(fs);	unlock_dquot(dquot);	dqstats.writes++;}static void read_dquot(struct dquot *dquot){	short type = dquot->dq_type;	struct file *filp = dquot->dq_mnt->mnt_quotas[type];	unsigned short fs;	if (filp == (struct file *)NULL)		return;	lock_dquot(dquot);	down(&dquot->dq_mnt->mnt_sem);	if (filp->f_op->lseek) {		if (filp->f_op->lseek(filp->f_inode, filp,		    dqoff(dquot->dq_id), 0) != dqoff(dquot->dq_id)) {			up(&dquot->dq_mnt->mnt_sem);			unlock_dquot(dquot);			return;		}	} else		filp->f_pos = dqoff(dquot->dq_id);	fs = get_fs();	set_fs(KERNEL_DS);	filp->f_op->read(filp->f_inode, filp, (char *)&dquot->dq_dqb, sizeof(struct dqblk));	up(&dquot->dq_mnt->mnt_sem);	set_fs(fs);	if (dquot->dq_bhardlimit == 0 && dquot->dq_bsoftlimit == 0 &&	    dquot->dq_ihardlimit == 0 && dquot->dq_isoftlimit == 0)		dquot->dq_flags |= DQ_FAKE;	unlock_dquot(dquot);	dqstats.reads++;}int sync_dquots(kdev_t dev, short type){	struct dquot *dquot = first_dquot;	int i;	dqstats.syncs++;	for (i = 0; i < nr_dquots * 2; i++, dquot = dquot->dq_next) {		if (dev == NODEV || dquot->dq_count == 0 || dquot->dq_dev != dev)			continue;		if (type != -1 && dquot->dq_type != type)			continue;		wait_on_dquot(dquot);		if (dquot->dq_flags & DQ_MOD)			write_dquot(dquot);	}	return(0);}/* * Trash the cache for a certain type on a device. */void invalidate_dquots(kdev_t dev, short type){	struct dquot *dquot, *next;	int cnt;	next = first_dquot;	for (cnt = nr_dquots ; cnt > 0 ; cnt--) {		dquot = next;		next = dquot->dq_next;		if (dquot->dq_dev != dev || dquot->dq_type != type)			continue;		if (dquot->dq_flags & DQ_LOCKED) {			printk("VFS: dquot busy on removed device %s\n", kdevname(dev));			continue;		}		if (dquot->dq_flags & DQ_MOD)			write_dquot(dquot);		dqstats.drops++;		clear_dquot(dquot);	}}static inline void dquot_incr_inodes(struct dquot *dquot, unsigned long number){	lock_dquot(dquot);	dquot->dq_curinodes += number;	dquot->dq_flags |= DQ_MOD;	unlock_dquot(dquot);}static inline void dquot_incr_blocks(struct dquot *dquot, unsigned long number){	lock_dquot(dquot);	dquot->dq_curblocks += number;	dquot->dq_flags |= DQ_MOD;	unlock_dquot(dquot);}static inline void dquot_decr_inodes(struct dquot *dquot, unsigned long number){	lock_dquot(dquot);	if (dquot->dq_curinodes > number)		dquot->dq_curinodes -= number;	else		dquot->dq_curinodes = 0;	if (dquot->dq_curinodes < dquot->dq_isoftlimit)		dquot->dq_itime = (time_t) 0;	dquot->dq_flags &= ~DQ_INODES;	dquot->dq_flags |= DQ_MOD;	unlock_dquot(dquot);}static inline void dquot_decr_blocks(struct dquot *dquot, unsigned long number){	lock_dquot(dquot);	if (dquot->dq_curblocks > number)		dquot->dq_curblocks -= number;	else		dquot->dq_curblocks = 0;	if (dquot->dq_curblocks < dquot->dq_bsoftlimit)		dquot->dq_btime = (time_t) 0;	dquot->dq_flags &= ~DQ_BLKS;	dquot->dq_flags |= DQ_MOD;	unlock_dquot(dquot);}static inline int need_print_warning(short type, struct dquot *dquot){	switch (type) {		case USRQUOTA:			return(current->fsuid == dquot->dq_id);		case GRPQUOTA:			return(current->fsgid == dquot->dq_id);	}	return(0);}static int check_idq(struct dquot *dquot, short type, u_long short inodes){	if (inodes <= 0 || dquot->dq_flags & DQ_FAKE)		return(QUOTA_OK);	if (dquot->dq_ihardlimit &&	   (dquot->dq_curinodes + inodes) > dquot->dq_ihardlimit && !fsuser()) {		if ((dquot->dq_flags & DQ_INODES) == 0 &&                     need_print_warning(type, dquot)) {			sprintf(quotamessage, "%s: write failed, %s file limit reached\r\n",			        dquot->dq_mnt->mnt_dirname, quotatypes[type]);			tty_write_message(current->tty, quotamessage);			dquot->dq_flags |= DQ_INODES;		}		return(NO_QUOTA);	}	if (dquot->dq_isoftlimit &&	   (dquot->dq_curinodes + inodes) > dquot->dq_isoftlimit &&	    dquot->dq_itime && CURRENT_TIME >= dquot->dq_itime && !fsuser()) {                if (need_print_warning(type, dquot)) {			sprintf(quotamessage, "%s: warning, %s file quota exceeded too long.\r\n",		        	dquot->dq_mnt->mnt_dirname, quotatypes[type]);			tty_write_message(current->tty, quotamessage);		}		return(NO_QUOTA);	}	if (dquot->dq_isoftlimit &&	   (dquot->dq_curinodes + inodes) > dquot->dq_isoftlimit &&	    dquot->dq_itime == 0 && !fsuser()) {                if (need_print_warning(type, dquot)) {			sprintf(quotamessage, "%s: warning, %s file quota exceeded\r\n",		        	dquot->dq_mnt->mnt_dirname, quotatypes[type]);			tty_write_message(current->tty, quotamessage);		}		dquot->dq_itime = CURRENT_TIME + dquot->dq_mnt->mnt_iexp[type];	}	return(QUOTA_OK);}static int check_bdq(struct dquot *dquot, short type, u_long blocks){	if (blocks <= 0 || dquot->dq_flags & DQ_FAKE)		return(QUOTA_OK);	if (dquot->dq_bhardlimit &&	   (dquot->dq_curblocks + blocks) > dquot->dq_bhardlimit && !fsuser()) {		if ((dquot->dq_flags & DQ_BLKS) == 0 &&                     need_print_warning(type, dquot)) {			sprintf(quotamessage, "%s: write failed, %s disk limit reached.\r\n",			        dquot->dq_mnt->mnt_dirname, quotatypes[type]);			tty_write_message(current->tty, quotamessage);			dquot->dq_flags |= DQ_BLKS;		}		return(NO_QUOTA);	}	if (dquot->dq_bsoftlimit &&	   (dquot->dq_curblocks + blocks) > dquot->dq_bsoftlimit &&	    dquot->dq_btime && CURRENT_TIME >= dquot->dq_btime && !fsuser()) {                if (need_print_warning(type, dquot)) {			sprintf(quotamessage, "%s: write failed, %s disk quota exceeded too long.\r\n",		        	dquot->dq_mnt->mnt_dirname, quotatypes[type]);			tty_write_message(current->tty, quotamessage);		}		return(NO_QUOTA);	}	if (dquot->dq_bsoftlimit &&	   (dquot->dq_curblocks + blocks) > dquot->dq_bsoftlimit &&	    dquot->dq_btime == 0 && !fsuser()) {                if (need_print_warning(type, dquot)) {			sprintf(quotamessage, "%s: warning, %s disk quota exceeded\r\n",		        	dquot->dq_mnt->mnt_dirname, quotatypes[type]);			tty_write_message(current->tty, quotamessage);		}		dquot->dq_btime = CURRENT_TIME + dquot->dq_mnt->mnt_bexp[type];	}	return(QUOTA_OK);}static void dqput(struct dquot *dquot){	if (!dquot)		return;	/*	 * If the dq_mnt pointer isn't initialized this entry needs no	 * checking and doesn't need to be written. It just an empty	 * dquot that is put back into the freelist.	 */	if (dquot->dq_mnt != (struct vfsmount *)NULL) {		dqstats.drops++;		wait_on_dquot(dquot);		if (!dquot->dq_count) {			printk("VFS: dqput: trying to free free dquot\n");			printk("VFS: device %s, dquot of %s %d\n", kdevname(dquot->dq_dev),			       quotatypes[dquot->dq_type], dquot->dq_id);			return;		}repeat:		if (dquot->dq_count > 1) {			dquot->dq_count--;			return;		}		wake_up(&dquot_wait);		if (dquot->dq_flags & DQ_MOD) {			write_dquot(dquot);	/* we can sleep - so do again */			wait_on_dquot(dquot);			goto repeat;		}	}	if (dquot->dq_count) {		dquot->dq_count--;		nr_free_dquots++;	}	return;}static struct dquot *get_empty_dquot(void){	struct dquot *dquot, *best;	int cnt;	if (nr_dquots < NR_DQUOTS && nr_free_dquots < (nr_dquots >> 2))		grow_dquots();repeat:	dquot = first_dquot;	best = NODQUOT;	for (cnt = 0; cnt < nr_dquots; dquot = dquot->dq_next, cnt++) {		if (!dquot->dq_count) {			if (!best)				best = dquot;			if (!(dquot->dq_flags & DQ_MOD) && !(dquot->dq_flags & DQ_LOCKED)) {				best = dquot;				break;			}		}	}	if (!best || best->dq_flags & DQ_MOD || best->dq_flags & DQ_LOCKED)		if (nr_dquots < NR_DQUOTS) {			grow_dquots();			goto repeat;		}	dquot = best;	if (!dquot) {		printk("VFS: No free dquots - contact mvw@mcs.ow.org\n");		sleep_on(&dquot_wait);		goto repeat;	}	if (dquot->dq_flags & DQ_LOCKED) {		wait_on_dquot(dquot);		goto repeat;	}	if (dquot->dq_flags & DQ_MOD) {		write_dquot(dquot);		goto repeat;	}	if (dquot->dq_count)		goto repeat;	clear_dquot(dquot);	dquot->dq_count = 1;	nr_free_dquots--;	if (nr_free_dquots < 0) {		printk ("VFS: get_empty_dquot: bad free dquot count.\n");		nr_free_dquots = 0;	}	return(dquot);}static struct dquot *dqget(kdev_t dev, unsigned int id, short type)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -