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

📄 inode.c

📁 Linux内核源代码 为压缩文件 是<<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/config.h>#include <linux/version.h>#define __NO_VERSION__#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/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/malloc.h>#include <linux/smp_lock.h>#include "msbuffer.h"#include <asm/uaccess.h>#include <asm/unaligned.h>extern struct cvf_format default_cvf, bigblock_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);	for(walk=p->next;walk!=p;walk=walk->next) {		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);	}	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){	lock_kernel();	inode->i_size = 0;	fat_truncate(inode);	unlock_kernel();	clear_inode(inode);}void fat_clear_inode(struct inode *inode){	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 *blksize, 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->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")) {			if (!value || !*value) ret = 0;			else {				*blksize = simple_strtoul(value,&value,0);				if (*value || (*blksize != 512 &&					*blksize != 1024 && *blksize != 2048))					ret = 0;			}		}		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 = kmalloc(len+1, GFP_KERNEL);				if (buffer) {					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_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 += SECTOR_SIZE*sbi->cluster_size;				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 = sbi->cluster_size* SECTOR_SIZE;	inode->i_blocks =		((inode->i_size+inode->i_blksize-1)>>sbi->cluster_bits) *		    sbi->cluster_size;	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;}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,};/* * Read the super block of an MS-DOS FS. * * Note that this may be called from vfat_read_super * with some fields already initialized. */struct super_block *fat_read_super(struct super_block *sb, void *data, int silent,		struct inode_operations *fs_dir_inode_ops){	struct inode *root_inode;	struct buffer_head *bh;	struct fat_boot_sector *b;	struct msdos_sb_info *sbi = MSDOS_SB(sb);	char *p;	int data_sectors,logical_sector_size,sector_mult,fat_clusters=0;	int debug,error,fat,cp;	int blksize = 512;	int fat32;	struct fat_mount_options opts;	char buf[50];	int i;	char cvf_format[21];	char cvf_options[101];	cvf_format[0] = '\0';	cvf_options[0] = '\0';	sbi->cvf_format = NULL;	sbi->private_data = NULL;	sbi->dir_ops = fs_dir_inode_ops;	sb->s_op = &fat_sops;	if (hardsect_size[MAJOR(sb->s_dev)] != NULL){		blksize = hardsect_size[MAJOR(sb->s_dev)][MINOR(sb->s_dev)];		if (blksize != 512){			printk ("MSDOS: Hardware sector size is %d\n",blksize);		}	}	opts.isvfat = sbi->options.isvfat;	if (!parse_options((char *) data, &fat, &blksize, &debug, &opts, 			   cvf_format, cvf_options)	    || (blksize != 512 && blksize != 1024 && blksize != 2048))		goto out_fail;	/* N.B. we should parse directly into the sb structure */	memcpy(&(sbi->options), &opts, sizeof(struct fat_mount_options));	fat_cache_init();	if( blksize > 1024 )	  {

⌨️ 快捷键说明

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