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

📄 inode.c

📁 linux环境下基于FAT的文件系统的通用代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  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/init.h>#include <linux/time.h>#include <linux/slab.h>#include <linux/smp_lock.h>#include <linux/seq_file.h>#include <linux/pagemap.h>#include <linux/mpage.h>#include <linux/buffer_head.h>#include <linux/exportfs.h>#include <linux/mount.h>#include <linux/vfs.h>#include <linux/parser.h>#include <linux/uio.h>#include <linux/writeback.h>#include <linux/log2.h>#include <linux/hash.h>#include <asm/unaligned.h>#include "fat.h"#ifndef CONFIG_FAT_DEFAULT_IOCHARSET/* if user don't select VFAT, this is undefined. */#define CONFIG_FAT_DEFAULT_IOCHARSET	""#endifstatic int fat_default_codepage = CONFIG_FAT_DEFAULT_CODEPAGE;static char fat_default_iocharset[] = CONFIG_FAT_DEFAULT_IOCHARSET;static int fat_add_cluster(struct inode *inode){	int err, cluster;	err = fat_alloc_clusters(inode, &cluster, 1);	if (err)		return err;	/* FIXME: this cluster should be added after data of this	 * cluster is writed */	err = fat_chain_add(inode, cluster, 1);	if (err)		fat_free_clusters(inode, cluster);	return err;}static inline int __fat_get_block(struct inode *inode, sector_t iblock,				  unsigned long *max_blocks,				  struct buffer_head *bh_result, int create){	struct super_block *sb = inode->i_sb;	struct msdos_sb_info *sbi = MSDOS_SB(sb);	unsigned long mapped_blocks;	sector_t phys;	int err, offset;	err = fat_bmap(inode, iblock, &phys, &mapped_blocks, create);	if (err)		return err;	if (phys) {		map_bh(bh_result, sb, phys);		*max_blocks = min(mapped_blocks, *max_blocks);		return 0;	}	if (!create)		return 0;	if (iblock != MSDOS_I(inode)->mmu_private >> sb->s_blocksize_bits) {		fat_fs_panic(sb, "corrupted file size (i_pos %lld, %lld)",			MSDOS_I(inode)->i_pos, MSDOS_I(inode)->mmu_private);		return -EIO;	}	offset = (unsigned long)iblock & (sbi->sec_per_clus - 1);	if (!offset) {		/* TODO: multiple cluster allocation would be desirable. */		err = fat_add_cluster(inode);		if (err)			return err;	}	/* available blocks on this cluster */	mapped_blocks = sbi->sec_per_clus - offset;	*max_blocks = min(mapped_blocks, *max_blocks);	MSDOS_I(inode)->mmu_private += *max_blocks << sb->s_blocksize_bits;	err = fat_bmap(inode, iblock, &phys, &mapped_blocks, create);	if (err)		return err;	BUG_ON(!phys);	BUG_ON(*max_blocks != mapped_blocks);	set_buffer_new(bh_result);	map_bh(bh_result, sb, phys);	return 0;}static int fat_get_block(struct inode *inode, sector_t iblock,			 struct buffer_head *bh_result, int create){	struct super_block *sb = inode->i_sb;	unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits;	int err;	err = __fat_get_block(inode, iblock, &max_blocks, bh_result, create);	if (err)		return err;	bh_result->b_size = max_blocks << sb->s_blocksize_bits;	return 0;}static int fat_writepage(struct page *page, struct writeback_control *wbc){	return block_write_full_page(page, fat_get_block, wbc);}static int fat_writepages(struct address_space *mapping,			  struct writeback_control *wbc){	return mpage_writepages(mapping, wbc, fat_get_block);}static int fat_readpage(struct file *file, struct page *page){	return mpage_readpage(page, fat_get_block);}static int fat_readpages(struct file *file, struct address_space *mapping,			 struct list_head *pages, unsigned nr_pages){	return mpage_readpages(mapping, pages, nr_pages, fat_get_block);}static int fat_write_begin(struct file *file, struct address_space *mapping,			loff_t pos, unsigned len, unsigned flags,			struct page **pagep, void **fsdata){	*pagep = NULL;	return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,				fat_get_block,				&MSDOS_I(mapping->host)->mmu_private);}static int fat_write_end(struct file *file, struct address_space *mapping,			loff_t pos, unsigned len, unsigned copied,			struct page *pagep, void *fsdata){	struct inode *inode = mapping->host;	int err;	err = generic_write_end(file, mapping, pos, len, copied, pagep, fsdata);	if (!(err < 0) && !(MSDOS_I(inode)->i_attrs & ATTR_ARCH)) {		inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;		MSDOS_I(inode)->i_attrs |= ATTR_ARCH;		mark_inode_dirty(inode);	}	return err;}static ssize_t fat_direct_IO(int rw, struct kiocb *iocb,			     const struct iovec *iov,			     loff_t offset, unsigned long nr_segs){	struct file *file = iocb->ki_filp;	struct inode *inode = file->f_mapping->host;	if (rw == WRITE) {		/*		 * FIXME: blockdev_direct_IO() doesn't use ->write_begin(),		 * so we need to update the ->mmu_private to block boundary.		 *		 * But we must fill the remaining area or hole by nul for		 * updating ->mmu_private.		 *		 * Return 0, and fallback to normal buffered write.		 */		loff_t size = offset + iov_length(iov, nr_segs);		if (MSDOS_I(inode)->mmu_private < size)			return 0;	}	/*	 * FAT need to use the DIO_LOCKING for avoiding the race	 * condition of fat_get_block() and ->truncate().	 */	return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,				  offset, nr_segs, fat_get_block, NULL);}static sector_t _fat_bmap(struct address_space *mapping, sector_t block){	sector_t blocknr;	/* fat_get_cluster() assumes the requested blocknr isn't truncated. */	down_read(&mapping->host->i_alloc_sem);	blocknr = generic_block_bmap(mapping, block, fat_get_block);	up_read(&mapping->host->i_alloc_sem);	return blocknr;}static const struct address_space_operations fat_aops = {	.readpage	= fat_readpage,	.readpages	= fat_readpages,	.writepage	= fat_writepage,	.writepages	= fat_writepages,	.sync_page	= block_sync_page,	.write_begin	= fat_write_begin,	.write_end	= fat_write_end,	.direct_IO	= fat_direct_IO,	.bmap		= _fat_bmap};/* * 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. */static void fat_hash_init(struct super_block *sb){	struct msdos_sb_info *sbi = MSDOS_SB(sb);	int i;	spin_lock_init(&sbi->inode_hash_lock);	for (i = 0; i < FAT_HASH_SIZE; i++)		INIT_HLIST_HEAD(&sbi->inode_hashtable[i]);}static inline unsigned long fat_hash(loff_t i_pos){	return hash_32(i_pos, FAT_HASH_BITS);}void fat_attach(struct inode *inode, loff_t i_pos){	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);	struct hlist_head *head = sbi->inode_hashtable + fat_hash(i_pos);	spin_lock(&sbi->inode_hash_lock);	MSDOS_I(inode)->i_pos = i_pos;	hlist_add_head(&MSDOS_I(inode)->i_fat_hash, head);	spin_unlock(&sbi->inode_hash_lock);}EXPORT_SYMBOL_GPL(fat_attach);void fat_detach(struct inode *inode){	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);	spin_lock(&sbi->inode_hash_lock);	MSDOS_I(inode)->i_pos = 0;	hlist_del_init(&MSDOS_I(inode)->i_fat_hash);	spin_unlock(&sbi->inode_hash_lock);}EXPORT_SYMBOL_GPL(fat_detach);struct inode *fat_iget(struct super_block *sb, loff_t i_pos){	struct msdos_sb_info *sbi = MSDOS_SB(sb);	struct hlist_head *head = sbi->inode_hashtable + fat_hash(i_pos);	struct hlist_node *_p;	struct msdos_inode_info *i;	struct inode *inode = NULL;	spin_lock(&sbi->inode_hash_lock);	hlist_for_each_entry(i, _p, head, i_fat_hash) {		BUG_ON(i->vfs_inode.i_sb != sb);		if (i->i_pos != i_pos)			continue;		inode = igrab(&i->vfs_inode);		if (inode)			break;	}	spin_unlock(&sbi->inode_hash_lock);	return inode;}static int is_exec(unsigned char *extension){	unsigned char *exe_extensions = "EXECOMBAT", *walk;	for (walk = exe_extensions; *walk; walk += 3)		if (!strncmp(extension, walk, 3))			return 1;	return 0;}static int fat_calc_dir_size(struct inode *inode){	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);	int ret, fclus, dclus;	inode->i_size = 0;	if (MSDOS_I(inode)->i_start == 0)		return 0;	ret = fat_get_cluster(inode, FAT_ENT_EOF, &fclus, &dclus);	if (ret < 0)		return ret;	inode->i_size = (fclus + 1) << sbi->cluster_bits;	return 0;}/* doesn't deal with root inode */static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de){	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);	int error;	MSDOS_I(inode)->i_pos = 0;	inode->i_uid = sbi->options.fs_uid;	inode->i_gid = sbi->options.fs_gid;	inode->i_version++;	inode->i_generation = get_seconds();	if ((de->attr & ATTR_DIR) && !IS_FREE(de->name)) {		inode->i_generation &= ~1;		inode->i_mode = fat_make_mode(sbi, de->attr, S_IRWXUGO);		inode->i_op = sbi->dir_ops;		inode->i_fop = &fat_dir_operations;		MSDOS_I(inode)->i_start = le16_to_cpu(de->start);		if (sbi->fat_bits == 32)			MSDOS_I(inode)->i_start |= (le16_to_cpu(de->starthi) << 16);		MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start;		error = fat_calc_dir_size(inode);		if (error < 0)			return error;		MSDOS_I(inode)->mmu_private = inode->i_size;		inode->i_nlink = fat_subdirs(inode);	} else { /* not a directory */		inode->i_generation |= 1;		inode->i_mode = fat_make_mode(sbi, de->attr,			((sbi->options.showexec && !is_exec(de->name + 8))			 ? S_IRUGO|S_IWUGO : S_IRWXUGO));		MSDOS_I(inode)->i_start = le16_to_cpu(de->start);		if (sbi->fat_bits == 32)			MSDOS_I(inode)->i_start |= (le16_to_cpu(de->starthi) << 16);		MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start;		inode->i_size = le32_to_cpu(de->size);		inode->i_op = &fat_file_inode_operations;		inode->i_fop = &fat_file_operations;		inode->i_mapping->a_ops = &fat_aops;		MSDOS_I(inode)->mmu_private = inode->i_size;	}	if (de->attr & ATTR_SYS) {		if (sbi->options.sys_immutable)			inode->i_flags |= S_IMMUTABLE;	}	fat_save_attrs(inode, de->attr);	inode->i_blocks = ((inode->i_size + (sbi->cluster_size - 1))			   & ~((loff_t)sbi->cluster_size - 1)) >> 9;	fat_time_fat2unix(sbi, &inode->i_mtime, de->time, de->date, 0);	if (sbi->options.isvfat) {		fat_time_fat2unix(sbi, &inode->i_ctime, de->ctime,				  de->cdate, de->ctime_cs);		fat_time_fat2unix(sbi, &inode->i_atime, 0, de->adate, 0);	} else		inode->i_ctime = inode->i_atime = inode->i_mtime;	return 0;}struct inode *fat_build_inode(struct super_block *sb,			struct msdos_dir_entry *de, loff_t i_pos){	struct inode *inode;	int err;	inode = fat_iget(sb, i_pos);	if (inode)		goto out;	inode = new_inode(sb);	if (!inode) {		inode = ERR_PTR(-ENOMEM);		goto out;	}	inode->i_ino = iunique(sb, MSDOS_ROOT_INO);	inode->i_version = 1;	err = fat_fill_inode(inode, de);	if (err) {		iput(inode);		inode = ERR_PTR(err);		goto out;	}	fat_attach(inode, i_pos);	insert_inode_hash(inode);out:	return inode;}EXPORT_SYMBOL_GPL(fat_build_inode);static void fat_delete_inode(struct inode *inode){	truncate_inode_pages(&inode->i_data, 0);	inode->i_size = 0;	fat_truncate(inode);	clear_inode(inode);}static void fat_clear_inode(struct inode *inode){	fat_cache_inval_inode(inode);	fat_detach(inode);}static void fat_write_super(struct super_block *sb){	sb->s_dirt = 0;	if (!(sb->s_flags & MS_RDONLY))		fat_clusters_flush(sb);}static void fat_put_super(struct super_block *sb){	struct msdos_sb_info *sbi = MSDOS_SB(sb);	if (sbi->nls_disk) {		unload_nls(sbi->nls_disk);		sbi->nls_disk = NULL;		sbi->options.codepage = fat_default_codepage;	}	if (sbi->nls_io) {		unload_nls(sbi->nls_io);		sbi->nls_io = NULL;	}	if (sbi->options.iocharset != fat_default_iocharset) {		kfree(sbi->options.iocharset);		sbi->options.iocharset = fat_default_iocharset;	}	sb->s_fs_info = NULL;	kfree(sbi);}static struct kmem_cache *fat_inode_cachep;static struct inode *fat_alloc_inode(struct super_block *sb){	struct msdos_inode_info *ei;	ei = kmem_cache_alloc(fat_inode_cachep, GFP_NOFS);	if (!ei)		return NULL;	return &ei->vfs_inode;}static void fat_destroy_inode(struct inode *inode){	kmem_cache_free(fat_inode_cachep, MSDOS_I(inode));}static void init_once(void *foo){	struct msdos_inode_info *ei = (struct msdos_inode_info *)foo;	spin_lock_init(&ei->cache_lru_lock);	ei->nr_caches = 0;	ei->cache_valid_id = FAT_CACHE_VALID + 1;	INIT_LIST_HEAD(&ei->cache_lru);	INIT_HLIST_NODE(&ei->i_fat_hash);	inode_init_once(&ei->vfs_inode);}static int __init fat_init_inodecache(void){	fat_inode_cachep = kmem_cache_create("fat_inode_cache",					     sizeof(struct msdos_inode_info),					     0, (SLAB_RECLAIM_ACCOUNT|						SLAB_MEM_SPREAD),					     init_once);	if (fat_inode_cachep == NULL)		return -ENOMEM;	return 0;}

⌨️ 快捷键说明

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