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

📄 file.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  linux/fs/affs/file.c * *  (c) 1996  Hans-Joachim Widmaier - Rewritten * *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem. * *  (C) 1992  Eric Youngdale Modified for ISO 9660 filesystem. * *  (C) 1991  Linus Torvalds - minix filesystem * *  affs regular file handling primitives */#include <asm/div64.h>#include <asm/uaccess.h>#include <asm/system.h>#include <linux/sched.h>#include <linux/affs_fs.h>#include <linux/fcntl.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/slab.h>#include <linux/stat.h>#include <linux/locks.h>#include <linux/smp_lock.h>#include <linux/dirent.h>#include <linux/fs.h>#include <linux/amigaffs.h>#include <linux/mm.h>#include <linux/pagemap.h>#if PAGE_SIZE < 4096#error PAGE_SIZE must be at least 4096#endifstatic int affs_grow_extcache(struct inode *inode, u32 lc_idx);static struct buffer_head *affs_alloc_extblock(struct inode *inode, struct buffer_head *bh, u32 ext);static inline struct buffer_head *affs_get_extblock(struct inode *inode, u32 ext);static struct buffer_head *affs_get_extblock_slow(struct inode *inode, u32 ext);static int affs_get_block(struct inode *inode, long block, struct buffer_head *bh_result, int create);static ssize_t affs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos);static int affs_file_open(struct inode *inode, struct file *filp);static int affs_file_release(struct inode *inode, struct file *filp);struct file_operations affs_file_operations = {	llseek:		generic_file_llseek,	read:		generic_file_read,	write:		affs_file_write,	mmap:		generic_file_mmap,	open:		affs_file_open,	release:	affs_file_release,	fsync:		file_fsync,};struct inode_operations affs_file_inode_operations = {	truncate:	affs_truncate,	setattr:	affs_notify_change,};static intaffs_file_open(struct inode *inode, struct file *filp){	if (atomic_read(&filp->f_count) != 1)		return 0;	pr_debug("AFFS: open(%d)\n", AFFS_INODE->i_opencnt);	AFFS_INODE->i_opencnt++;	return 0;}static intaffs_file_release(struct inode *inode, struct file *filp){	if (atomic_read(&filp->f_count) != 0)		return 0;	pr_debug("AFFS: release(%d)\n", AFFS_INODE->i_opencnt);	AFFS_INODE->i_opencnt--;	if (!AFFS_INODE->i_opencnt)		affs_free_prealloc(inode);	return 0;}static intaffs_grow_extcache(struct inode *inode, u32 lc_idx){	struct super_block	*sb = inode->i_sb;	struct buffer_head	*bh;	u32 lc_max;	int i, j, key;	if (!AFFS_INODE->i_lc) {		char *ptr = (char *)get_zeroed_page(GFP_NOFS);		if (!ptr)			return -ENOMEM;		AFFS_INODE->i_lc = (u32 *)ptr;		AFFS_INODE->i_ac = (struct affs_ext_key *)(ptr + AFFS_CACHE_SIZE / 2);	}	lc_max = AFFS_LC_SIZE << AFFS_INODE->i_lc_shift;	if (AFFS_INODE->i_extcnt > lc_max) {		u32 lc_shift, lc_mask, tmp, off;		/* need to recalculate linear cache, start from old size */		lc_shift = AFFS_INODE->i_lc_shift;		tmp = (AFFS_INODE->i_extcnt / AFFS_LC_SIZE) >> lc_shift;		for (; tmp; tmp >>= 1)			lc_shift++;		lc_mask = (1 << lc_shift) - 1;		/* fix idx and old size to new shift */		lc_idx >>= (lc_shift - AFFS_INODE->i_lc_shift);		AFFS_INODE->i_lc_size >>= (lc_shift - AFFS_INODE->i_lc_shift);		/* first shrink old cache to make more space */		off = 1 << (lc_shift - AFFS_INODE->i_lc_shift);		for (i = 1, j = off; j < AFFS_LC_SIZE; i++, j += off)			AFFS_INODE->i_ac[i] = AFFS_INODE->i_ac[j];		AFFS_INODE->i_lc_shift = lc_shift;		AFFS_INODE->i_lc_mask = lc_mask;	}	/* fill cache to the needed index */	i = AFFS_INODE->i_lc_size;	AFFS_INODE->i_lc_size = lc_idx + 1;	for (; i <= lc_idx; i++) {		if (!i) {			AFFS_INODE->i_lc[0] = inode->i_ino;			continue;		}		key = AFFS_INODE->i_lc[i - 1];		j = AFFS_INODE->i_lc_mask + 1;		// unlock cache		for (; j > 0; j--) {			bh = affs_bread(sb, key);			if (!bh)				goto err;			key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension);			affs_brelse(bh);		}		// lock cache		AFFS_INODE->i_lc[i] = key;	}	return 0;err:	// lock cache	return -EIO;}static struct buffer_head *affs_alloc_extblock(struct inode *inode, struct buffer_head *bh, u32 ext){	struct super_block *sb = inode->i_sb;	struct buffer_head *new_bh;	u32 blocknr, tmp;	blocknr = affs_alloc_block(inode, bh->b_blocknr);	if (!blocknr)		return ERR_PTR(-ENOSPC);	new_bh = affs_getzeroblk(sb, blocknr);	if (!new_bh) {		affs_free_block(sb, blocknr);		return ERR_PTR(-EIO);	}	AFFS_HEAD(new_bh)->ptype = cpu_to_be32(T_LIST);	AFFS_HEAD(new_bh)->key = cpu_to_be32(blocknr);	AFFS_TAIL(sb, new_bh)->stype = cpu_to_be32(ST_FILE);	AFFS_TAIL(sb, new_bh)->parent = cpu_to_be32(inode->i_ino);	affs_fix_checksum(sb, new_bh);	mark_buffer_dirty_inode(new_bh, inode);	tmp = be32_to_cpu(AFFS_TAIL(sb, bh)->extension);	if (tmp)		affs_warning(sb, "alloc_ext", "previous extension set (%x)", tmp);	AFFS_TAIL(sb, bh)->extension = cpu_to_be32(blocknr);	affs_adjust_checksum(bh, blocknr - tmp);	mark_buffer_dirty_inode(bh, inode);	AFFS_INODE->i_extcnt++;	mark_inode_dirty(inode);	return new_bh;}static inline struct buffer_head *affs_get_extblock(struct inode *inode, u32 ext){	/* inline the simplest case: same extended block as last time */	struct buffer_head *bh = AFFS_INODE->i_ext_bh;	if (ext == AFFS_INODE->i_ext_last)		atomic_inc(&bh->b_count);	else		/* we have to do more (not inlined) */		bh = affs_get_extblock_slow(inode, ext);	return bh;}static struct buffer_head *affs_get_extblock_slow(struct inode *inode, u32 ext){	struct super_block *sb = inode->i_sb;	struct buffer_head *bh;	u32 ext_key;	u32 lc_idx, lc_off, ac_idx;	u32 tmp, idx;	if (ext == AFFS_INODE->i_ext_last + 1) {		/* read the next extended block from the current one */		bh = AFFS_INODE->i_ext_bh;		ext_key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension);		if (ext < AFFS_INODE->i_extcnt)			goto read_ext;		if (ext > AFFS_INODE->i_extcnt)			BUG();		bh = affs_alloc_extblock(inode, bh, ext);		if (IS_ERR(bh))			return bh;		goto store_ext;	}	if (ext == 0) {		/* we seek back to the file header block */		ext_key = inode->i_ino;		goto read_ext;	}	if (ext >= AFFS_INODE->i_extcnt) {		struct buffer_head *prev_bh;		/* allocate a new extended block */		if (ext > AFFS_INODE->i_extcnt)			BUG();		/* get previous extended block */		prev_bh = affs_get_extblock(inode, ext - 1);		if (IS_ERR(prev_bh))			return prev_bh;		bh = affs_alloc_extblock(inode, prev_bh, ext);		affs_brelse(prev_bh);		if (IS_ERR(bh))			return bh;		goto store_ext;	}again:	/* check if there is an extended cache and whether it's large enough */	lc_idx = ext >> AFFS_INODE->i_lc_shift;	lc_off = ext & AFFS_INODE->i_lc_mask;	if (lc_idx >= AFFS_INODE->i_lc_size) {		int err;		err = affs_grow_extcache(inode, lc_idx);		if (err)			return ERR_PTR(err);		goto again;	}	/* every n'th key we find in the linear cache */	if (!lc_off) {		ext_key = AFFS_INODE->i_lc[lc_idx];		goto read_ext;	}	/* maybe it's still in the associative cache */	ac_idx = (ext - lc_idx - 1) & AFFS_AC_MASK;	if (AFFS_INODE->i_ac[ac_idx].ext == ext) {		ext_key = AFFS_INODE->i_ac[ac_idx].key;		goto read_ext;	}	/* try to find one of the previous extended blocks */	tmp = ext;	idx = ac_idx;	while (--tmp, --lc_off > 0) {		idx = (idx - 1) & AFFS_AC_MASK;		if (AFFS_INODE->i_ac[idx].ext == tmp) {			ext_key = AFFS_INODE->i_ac[idx].key;			goto find_ext;		}	}	/* fall back to the linear cache */	ext_key = AFFS_INODE->i_lc[lc_idx];find_ext:	/* read all extended blocks until we find the one we need */	//unlock cache	do {		bh = affs_bread(sb, ext_key);		if (!bh)			goto err_bread;		ext_key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension);		affs_brelse(bh);		tmp++;	} while (tmp < ext);	//lock cache	/* store it in the associative cache */	// recalculate ac_idx?	AFFS_INODE->i_ac[ac_idx].ext = ext;	AFFS_INODE->i_ac[ac_idx].key = ext_key;read_ext:	/* finally read the right extended block */	//unlock cache	bh = affs_bread(sb, ext_key);	if (!bh)		goto err_bread;	//lock cachestore_ext:	/* release old cached extended block and store the new one */	affs_brelse(AFFS_INODE->i_ext_bh);	AFFS_INODE->i_ext_last = ext;	AFFS_INODE->i_ext_bh = bh;	atomic_inc(&bh->b_count);	return bh;err_bread:	affs_brelse(bh);	return ERR_PTR(-EIO);}static intaffs_get_block(struct inode *inode, long block, struct buffer_head *bh_result, int create){	struct super_block	*sb = inode->i_sb;	struct buffer_head	*ext_bh;	u32			 ext;	pr_debug("AFFS: get_block(%u, %ld)\n", (u32)inode->i_ino, block);	if (block < 0)		goto err_small;	if (block >= AFFS_INODE->i_blkcnt) {		if (block > AFFS_INODE->i_blkcnt || !create)			goto err_big;	} else		create = 0;	//lock cache	affs_lock_ext(inode);	ext = block / AFFS_SB->s_hashsize;	block -= ext * AFFS_SB->s_hashsize;	ext_bh = affs_get_extblock(inode, ext);	if (IS_ERR(ext_bh))		goto err_ext;	bh_result->b_blocknr = be32_to_cpu(AFFS_BLOCK(sb, ext_bh, block));	bh_result->b_dev = inode->i_dev;	bh_result->b_state |= (1UL << BH_Mapped);	if (create) {		u32 blocknr = affs_alloc_block(inode, ext_bh->b_blocknr);		if (!blocknr)			goto err_alloc;		bh_result->b_state |= (1UL << BH_New);		AFFS_INODE->mmu_private += AFFS_SB->s_data_blksize;		AFFS_INODE->i_blkcnt++;		/* store new block */		if (bh_result->b_blocknr)			affs_warning(sb, "get_block", "block already set (%x)", bh_result->b_blocknr);		AFFS_BLOCK(sb, ext_bh, block) = cpu_to_be32(blocknr);		AFFS_HEAD(ext_bh)->block_count = cpu_to_be32(block + 1);		affs_adjust_checksum(ext_bh, blocknr - bh_result->b_blocknr + 1);		bh_result->b_blocknr = blocknr;		if (!block) {			/* insert first block into header block */			u32 tmp = be32_to_cpu(AFFS_HEAD(ext_bh)->first_data);			if (tmp)				affs_warning(sb, "get_block", "first block already set (%d)", tmp);			AFFS_HEAD(ext_bh)->first_data = cpu_to_be32(blocknr);			affs_adjust_checksum(ext_bh, blocknr - tmp);		}	}	affs_brelse(ext_bh);	//unlock cache	affs_unlock_ext(inode);	return 0;err_small:	affs_error(inode->i_sb,"get_block","Block < 0");	return -EIO;err_big:	affs_error(inode->i_sb,"get_block","strange block request %d", block);	return -EIO;err_ext:	// unlock cache	affs_unlock_ext(inode);	return PTR_ERR(ext_bh);err_alloc:	brelse(ext_bh);	bh_result->b_state &= ~(1UL << BH_Mapped);	// unlock cache	affs_unlock_ext(inode);	return -ENOSPC;}static int affs_writepage(struct page *page){	return block_write_full_page(page, affs_get_block);}static int affs_readpage(struct file *file, struct page *page){	return block_read_full_page(page, affs_get_block);}static int affs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to){	return cont_prepare_write(page, from, to, affs_get_block,		&page->mapping->host->u.affs_i.mmu_private);}static int _affs_bmap(struct address_space *mapping, long block){	return generic_block_bmap(mapping,block,affs_get_block);}struct address_space_operations affs_aops = {	readpage: affs_readpage,	writepage: affs_writepage,	sync_page: block_sync_page,	prepare_write: affs_prepare_write,	commit_write: generic_commit_write,	bmap: _affs_bmap};static inline struct buffer_head *affs_bread_ino(struct inode *inode, int block, int create){	struct buffer_head *bh, tmp_bh;	int err;	tmp_bh.b_state = 0;	err = affs_get_block(inode, block, &tmp_bh, create);	if (!err) {		bh = affs_bread(inode->i_sb, tmp_bh.b_blocknr);		if (bh) {			bh->b_state |= tmp_bh.b_state;			return bh;		}		err = -EIO;	}	return ERR_PTR(err);}static inline struct buffer_head *affs_getzeroblk_ino(struct inode *inode, int block){	struct buffer_head *bh, tmp_bh;	int err;	tmp_bh.b_state = 0;	err = affs_get_block(inode, block, &tmp_bh, 1);	if (!err) {		bh = affs_getzeroblk(inode->i_sb, tmp_bh.b_blocknr);

⌨️ 快捷键说明

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