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

📄 inode.c

📁 嵌入式系统设计与实验教材二源码linux内核移植与编译
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  linux/fs/fat/inode.c * *  Written 1992,1993 by Werner Almesberger *  VFAT extensions by Gordon Chaffee, merged with msdos fs by Henrik Storner *  Rewritten for the constant inumbers support by Al Viro * *  Fixes: * *  	Max Cohan: Fixed invalid FSINFO offset when info_sector is 0 */#include <linux/module.h>#include <linux/msdos_fs.h>#include <linux/nls.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/bitops.h>#include <linux/major.h>#include <linux/blkdev.h>#include <linux/fs.h>#include <linux/stat.h>#include <linux/locks.h>#include <linux/fat_cvf.h>#include <linux/slab.h>#include <linux/smp_lock.h>#include <asm/uaccess.h>#include <asm/unaligned.h>extern struct cvf_format default_cvf;/* #define FAT_PARANOIA 1 */#define DEBUG_LEVEL 0#ifdef FAT_DEBUG#  define PRINTK(x) printk x#else#  define PRINTK(x)#endif#if (DEBUG_LEVEL >= 1)#  define PRINTK1(x) printk x#else#  define PRINTK1(x)#endif/* * New FAT inode stuff. We do the following: *	a) i_ino is constant and has nothing with on-disk location. *	b) FAT manages its own cache of directory entries. *	c) *This* cache is indexed by on-disk location. *	d) inode has an associated directory entry, all right, but *		it may be unhashed. *	e) currently entries are stored within struct inode. That should *		change. *	f) we deal with races in the following way: *		1. readdir() and lookup() do FAT-dir-cache lookup. *		2. rename() unhashes the F-d-c entry and rehashes it in *			a new place. *		3. unlink() and rmdir() unhash F-d-c entry. *		4. fat_write_inode() checks whether the thing is unhashed. *			If it is we silently return. If it isn't we do bread(), *			check if the location is still valid and retry if it *			isn't. Otherwise we do changes. *		5. Spinlock is used to protect hash/unhash/location check/lookup *		6. fat_clear_inode() unhashes the F-d-c entry. *		7. lookup() and readdir() do igrab() if they find a F-d-c entry *			and consider negative result as cache miss. */#define FAT_HASH_BITS	8#define FAT_HASH_SIZE	(1UL << FAT_HASH_BITS)#define FAT_HASH_MASK	(FAT_HASH_SIZE-1)static struct list_head fat_inode_hashtable[FAT_HASH_SIZE];spinlock_t fat_inode_lock = SPIN_LOCK_UNLOCKED;void fat_hash_init(void){	int i;	for(i = 0; i < FAT_HASH_SIZE; i++) {		INIT_LIST_HEAD(&fat_inode_hashtable[i]);	}}static inline unsigned long fat_hash(struct super_block *sb, int i_pos){	unsigned long tmp = (unsigned long)i_pos | (unsigned long) sb;	tmp = tmp + (tmp >> FAT_HASH_BITS) + (tmp >> FAT_HASH_BITS * 2);	return tmp & FAT_HASH_MASK;}void fat_attach(struct inode *inode, int i_pos){	spin_lock(&fat_inode_lock);	MSDOS_I(inode)->i_location = i_pos;	list_add(&MSDOS_I(inode)->i_fat_hash,		fat_inode_hashtable + fat_hash(inode->i_sb, i_pos));	spin_unlock(&fat_inode_lock);}void fat_detach(struct inode *inode){	spin_lock(&fat_inode_lock);	MSDOS_I(inode)->i_location = 0;	list_del(&MSDOS_I(inode)->i_fat_hash);	INIT_LIST_HEAD(&MSDOS_I(inode)->i_fat_hash);	spin_unlock(&fat_inode_lock);}struct inode *fat_iget(struct super_block *sb, int i_pos){	struct list_head *p = fat_inode_hashtable + fat_hash(sb, i_pos);	struct list_head *walk;	struct msdos_inode_info *i;	struct inode *inode = NULL;	spin_lock(&fat_inode_lock);	list_for_each(walk, p) {		i = list_entry(walk, struct msdos_inode_info, i_fat_hash);		if (i->i_fat_inode->i_sb != sb)			continue;		if (i->i_location != i_pos)			continue;		inode = igrab(i->i_fat_inode);		if (inode)			break;	}	spin_unlock(&fat_inode_lock);	return inode;}static void fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de);struct inode *fat_build_inode(struct super_block *sb,				struct msdos_dir_entry *de, int ino, int *res){	struct inode *inode;	*res = 0;	inode = fat_iget(sb, ino);	if (inode)		goto out;	inode = new_inode(sb);	*res = -ENOMEM;	if (!inode)		goto out;	*res = 0;	inode->i_ino = iunique(sb, MSDOS_ROOT_INO);	fat_fill_inode(inode, de);	fat_attach(inode, ino);	insert_inode_hash(inode);out:	return inode;}void fat_delete_inode(struct inode *inode){	if (!is_bad_inode(inode)) {		lock_kernel();		inode->i_size = 0;		fat_truncate(inode);		unlock_kernel();	}	clear_inode(inode);}void fat_clear_inode(struct inode *inode){	if (is_bad_inode(inode))		return;	lock_kernel();	spin_lock(&fat_inode_lock);	fat_cache_inval_inode(inode);	list_del(&MSDOS_I(inode)->i_fat_hash);	spin_unlock(&fat_inode_lock);	unlock_kernel();}void fat_put_super(struct super_block *sb){	if (MSDOS_SB(sb)->cvf_format->cvf_version) {		dec_cvf_format_use_count_by_version(MSDOS_SB(sb)->cvf_format->cvf_version);		MSDOS_SB(sb)->cvf_format->unmount_cvf(sb);	}	if (MSDOS_SB(sb)->fat_bits == 32) {		fat_clusters_flush(sb);	}	fat_cache_inval_dev(sb->s_dev);	set_blocksize (sb->s_dev,BLOCK_SIZE);	if (MSDOS_SB(sb)->nls_disk) {		unload_nls(MSDOS_SB(sb)->nls_disk);		MSDOS_SB(sb)->nls_disk = NULL;		MSDOS_SB(sb)->options.codepage = 0;	}	if (MSDOS_SB(sb)->nls_io) {		unload_nls(MSDOS_SB(sb)->nls_io);		MSDOS_SB(sb)->nls_io = NULL;	}	/*	 * Note: the iocharset option might have been specified	 * without enabling nls_io, so check for it here.	 */	if (MSDOS_SB(sb)->options.iocharset) {		kfree(MSDOS_SB(sb)->options.iocharset);		MSDOS_SB(sb)->options.iocharset = NULL;	}}static int parse_options(char *options,int *fat, int *debug,			 struct fat_mount_options *opts,			 char *cvf_format, char *cvf_options){	char *this_char,*value,save,*savep;	char *p;	int ret = 1, len;	opts->name_check = 'n';	opts->conversion = 'b';	opts->fs_uid = current->uid;	opts->fs_gid = current->gid;	opts->fs_umask = current->fs->umask;	opts->quiet = opts->sys_immutable = opts->dotsOK = opts->showexec = 0;	opts->codepage = 0;	opts->nocase = 0;	opts->shortname = 0;	opts->utf8 = 0;	opts->iocharset = NULL;	*debug = *fat = 0;	if (!options)		goto out;	save = 0;	savep = NULL;	for (this_char = strtok(options,","); this_char;	     this_char = strtok(NULL,",")) {		if ((value = strchr(this_char,'=')) != NULL) {			save = *value;			savep = value;			*value++ = 0;		}		if (!strcmp(this_char,"check") && value) {			if (value[0] && !value[1] && strchr("rns",*value))				opts->name_check = *value;			else if (!strcmp(value,"relaxed"))				opts->name_check = 'r';			else if (!strcmp(value,"normal"))				opts->name_check = 'n';			else if (!strcmp(value,"strict"))				opts->name_check = 's';			else ret = 0;		}		else if (!strcmp(this_char,"conv") && value) {			if (value[0] && !value[1] && strchr("bta",*value))				opts->conversion = *value;			else if (!strcmp(value,"binary"))				opts->conversion = 'b';			else if (!strcmp(value,"text"))				opts->conversion = 't';			else if (!strcmp(value,"auto"))				opts->conversion = 'a';			else ret = 0;		}		else if (!strcmp(this_char,"dots")) {			opts->dotsOK = 1;		}		else if (!strcmp(this_char,"nocase")) {			opts->nocase = 1;		}		else if (!strcmp(this_char,"nodots")) {			opts->dotsOK = 0;		}		else if (!strcmp(this_char,"showexec")) {			opts->showexec = 1;		}		else if (!strcmp(this_char,"dotsOK") && value) {			if (!strcmp(value,"yes")) opts->dotsOK = 1;			else if (!strcmp(value,"no")) opts->dotsOK = 0;			else ret = 0;		}		else if (!strcmp(this_char,"uid")) {			if (!value || !*value) ret = 0;			else {				opts->fs_uid = simple_strtoul(value,&value,0);				if (*value) ret = 0;			}		}		else if (!strcmp(this_char,"gid")) {			if (!value || !*value) ret= 0;			else {				opts->fs_gid = simple_strtoul(value,&value,0);				if (*value) ret = 0;			}		}		else if (!strcmp(this_char,"umask")) {			if (!value || !*value) ret = 0;			else {				opts->fs_umask = simple_strtoul(value,&value,8);				if (*value) ret = 0;			}		}		else if (!strcmp(this_char,"debug")) {			if (value) ret = 0;			else *debug = 1;		}		else if (!strcmp(this_char,"fat")) {			if (!value || !*value) ret = 0;			else {				*fat = simple_strtoul(value,&value,0);				if (*value || (*fat != 12 && *fat != 16 &&					       *fat != 32)) 					ret = 0;			}		}		else if (!strcmp(this_char,"quiet")) {			if (value) ret = 0;			else opts->quiet = 1;		}		else if (!strcmp(this_char,"blocksize")) {			printk("FAT: blocksize option is obsolete, "			       "not supported now\n");		}		else if (!strcmp(this_char,"sys_immutable")) {			if (value) ret = 0;			else opts->sys_immutable = 1;		}		else if (!strcmp(this_char,"codepage") && value) {			opts->codepage = simple_strtoul(value,&value,0);			if (*value) ret = 0;			else printk ("MSDOS FS: Using codepage %d\n",					opts->codepage);		}		else if (!strcmp(this_char,"iocharset") && value) {			p = value;			while (*value && *value != ',')				value++;			len = value - p;			if (len) {				char *buffer;				if (opts->iocharset != NULL) {					kfree(opts->iocharset);					opts->iocharset = NULL;				}				buffer = kmalloc(len + 1, GFP_KERNEL);				if (buffer != NULL) {					opts->iocharset = buffer;					memcpy(buffer, p, len);					buffer[len] = 0;					printk("MSDOS FS: IO charset %s\n", buffer);				} else					ret = 0;			}		}		else if (!strcmp(this_char,"cvf_format")) {			if (!value)				return 0;			strncpy(cvf_format,value,20);		}		else if (!strcmp(this_char,"cvf_options")) {			if (!value)				return 0;			strncpy(cvf_options,value,100);		}		if (this_char != options) *(this_char-1) = ',';		if (value) *savep = save;		if (ret == 0)			break;	}out:	return ret;}static void fat_read_root(struct inode *inode){	struct super_block *sb = inode->i_sb;	struct msdos_sb_info *sbi = MSDOS_SB(sb);	int nr;	INIT_LIST_HEAD(&MSDOS_I(inode)->i_fat_hash);	MSDOS_I(inode)->i_location = 0;	MSDOS_I(inode)->i_fat_inode = inode;	inode->i_uid = sbi->options.fs_uid;	inode->i_gid = sbi->options.fs_gid;	inode->i_version = ++event;	inode->i_generation = 0;	inode->i_mode = (S_IRWXUGO & ~sbi->options.fs_umask) | S_IFDIR;	inode->i_op = sbi->dir_ops;	inode->i_fop = &fat_dir_operations;	if (sbi->fat_bits == 32) {		MSDOS_I(inode)->i_start = sbi->root_cluster;		if ((nr = MSDOS_I(inode)->i_start) != 0) {			while (nr != -1) {				inode->i_size += 1 << sbi->cluster_bits;				if (!(nr = fat_access(sb, nr, -1))) {					printk("Directory %ld: bad FAT\n",					       inode->i_ino);					break;				}			}		}	} else {		MSDOS_I(inode)->i_start = 0;		inode->i_size = sbi->dir_entries * sizeof(struct msdos_dir_entry);	}	inode->i_blksize = 1 << sbi->cluster_bits;	inode->i_blocks = ((inode->i_size + inode->i_blksize - 1)			   & ~(inode->i_blksize - 1)) >> 9;	MSDOS_I(inode)->i_logstart = 0;	MSDOS_I(inode)->mmu_private = inode->i_size;	MSDOS_I(inode)->i_attrs = 0;	inode->i_mtime = inode->i_atime = inode->i_ctime = 0;	MSDOS_I(inode)->i_ctime_ms = 0;	inode->i_nlink = fat_subdirs(inode)+2;}/* * a FAT file handle with fhtype 3 is *  0/  i_ino - for fast, reliable lookup if still in the cache *  1/  i_generation - to see if i_ino is still valid *          bit 0 == 0 iff directory *  2/  i_location - if ino has changed, but still in cache *  3/  i_logstart - to semi-verify inode found at i_location *  4/  parent->i_logstart - maybe used to hunt for the file on disc * */struct dentry *fat_fh_to_dentry(struct super_block *sb, __u32 *fh,				int len, int fhtype, int parent){	struct inode *inode = NULL;	struct list_head *lp;	struct dentry *result;	if (fhtype != 3)		return NULL;	if (len < 5)		return NULL;	if (parent)		return NULL; /* We cannot find the parent,				It better just *be* there */	inode = iget(sb, fh[0]);	if (!inode || is_bad_inode(inode) ||	    inode->i_generation != fh[1]) {		if (inode) iput(inode);		inode = NULL;	}	if (!inode) {		/* try 2 - see if i_location is in F-d-c		 * require i_logstart to be the same		 * Will fail if you truncate and then re-write		 */		inode = fat_iget(sb, fh[2]);		if (inode && MSDOS_I(inode)->i_logstart != fh[3]) {			iput(inode);			inode = NULL;		}	}	if (!inode) {		/* For now, do nothing		 * What we could do is:		 * follow the file starting at fh[4], and record		 * the ".." entry, and the name of the fh[2] entry.		 * The follow the ".." file finding the next step up.		 * This way we build a path to the root of		 * the tree. If this works, we lookup the path and so		 * get this inode into the cache.		 * Finally try the fat_iget lookup again		 * If that fails, then weare totally out of luck		 * But all that is for another day		 */	}	if (!inode)		return ERR_PTR(-ESTALE);		/* now to find a dentry.	 * If possible, get a well-connected one	 *	 * Given the way that we found the inode, it *MUST* be	 * well-connected, but it is easiest to just copy the	 * code.	 */	spin_lock(&dcache_lock);	for (lp = inode->i_dentry.next; lp != &inode->i_dentry ; lp=lp->next) {		result = list_entry(lp,struct dentry, d_alias);		if (! (result->d_flags & DCACHE_NFSD_DISCONNECTED)) {			dget_locked(result);			result->d_vfs_flags |= DCACHE_REFERENCED;			spin_unlock(&dcache_lock);			iput(inode);			return result;		}	}	spin_unlock(&dcache_lock);	result = d_alloc_root(inode);	if (result == NULL) {		iput(inode);		return ERR_PTR(-ENOMEM);	}	result->d_flags |= DCACHE_NFSD_DISCONNECTED;	return result;		}int fat_dentry_to_fh(struct dentry *de, __u32 *fh, int *lenp, int needparent){	int len = *lenp;	struct inode *inode =  de->d_inode;		if (len < 5)		return 255; /* no room */	*lenp = 5;	fh[0] = inode->i_ino;	fh[1] = inode->i_generation;	fh[2] = MSDOS_I(inode)->i_location;	fh[3] = MSDOS_I(inode)->i_logstart;	fh[4] = MSDOS_I(de->d_parent->d_inode)->i_logstart;	return 3;}static struct super_operations fat_sops = { 	write_inode:	fat_write_inode,	delete_inode:	fat_delete_inode,	put_super:	fat_put_super,	statfs:		fat_statfs,	clear_inode:	fat_clear_inode,

⌨️ 快捷键说明

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