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

📄 file.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
		err = -EIO;	}	return ERR_PTR(err);}static inline struct buffer_head *affs_getemptyblk_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_getemptyblk(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 intaffs_do_readpage_ofs(struct file *file, struct page *page, unsigned from, unsigned to){	struct inode *inode = page->mapping->host;	struct super_block *sb = inode->i_sb;	struct buffer_head *bh;	char *data;	u32 bidx, boff, bsize;	u32 tmp;	pr_debug("AFFS: read_page(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to);	if (from > to || to > PAGE_CACHE_SIZE)		BUG();	kmap(page);	data = page_address(page);	bsize = AFFS_SB(sb)->s_data_blksize;	tmp = (page->index << PAGE_CACHE_SHIFT) + from;	bidx = tmp / bsize;	boff = tmp % bsize;	while (from < to) {		bh = affs_bread_ino(inode, bidx, 0);		if (IS_ERR(bh))			return PTR_ERR(bh);		tmp = min(bsize - boff, to - from);		if (from + tmp > to || tmp > bsize)			BUG();		memcpy(data + from, AFFS_DATA(bh) + boff, tmp);		affs_brelse(bh);		bidx++;		from += tmp;		boff = 0;	}	flush_dcache_page(page);	kunmap(page);	return 0;}static intaffs_extent_file_ofs(struct inode *inode, u32 newsize){	struct super_block *sb = inode->i_sb;	struct buffer_head *bh, *prev_bh;	u32 bidx, boff;	u32 size, bsize;	u32 tmp;	pr_debug("AFFS: extent_file(%u, %d)\n", (u32)inode->i_ino, newsize);	bsize = AFFS_SB(sb)->s_data_blksize;	bh = NULL;	size = AFFS_I(inode)->mmu_private;	bidx = size / bsize;	boff = size % bsize;	if (boff) {		bh = affs_bread_ino(inode, bidx, 0);		if (IS_ERR(bh))			return PTR_ERR(bh);		tmp = min(bsize - boff, newsize - size);		if (boff + tmp > bsize || tmp > bsize)			BUG();		memset(AFFS_DATA(bh) + boff, 0, tmp);		AFFS_DATA_HEAD(bh)->size = cpu_to_be32(be32_to_cpu(AFFS_DATA_HEAD(bh)->size) + tmp);		affs_fix_checksum(sb, bh);		mark_buffer_dirty_inode(bh, inode);		size += tmp;		bidx++;	} else if (bidx) {		bh = affs_bread_ino(inode, bidx - 1, 0);		if (IS_ERR(bh))			return PTR_ERR(bh);	}	while (size < newsize) {		prev_bh = bh;		bh = affs_getzeroblk_ino(inode, bidx);		if (IS_ERR(bh))			goto out;		tmp = min(bsize, newsize - size);		if (tmp > bsize)			BUG();		AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);		AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino);		AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);		AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp);		affs_fix_checksum(sb, bh);		bh->b_state &= ~(1UL << BH_New);		mark_buffer_dirty_inode(bh, inode);		if (prev_bh) {			u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);			if (tmp)				affs_warning(sb, "extent_file_ofs", "next block already set for %d (%d)", bidx, tmp);			AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);			affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp);			mark_buffer_dirty_inode(prev_bh, inode);			affs_brelse(prev_bh);		}		size += bsize;		bidx++;	}	affs_brelse(bh);	inode->i_size = AFFS_I(inode)->mmu_private = newsize;	return 0;out:	inode->i_size = AFFS_I(inode)->mmu_private = newsize;	return PTR_ERR(bh);}static intaffs_readpage_ofs(struct file *file, struct page *page){	struct inode *inode = page->mapping->host;	u32 to;	int err;	pr_debug("AFFS: read_page(%u, %ld)\n", (u32)inode->i_ino, page->index);	to = PAGE_CACHE_SIZE;	if (((page->index + 1) << PAGE_CACHE_SHIFT) > inode->i_size) {		to = inode->i_size & ~PAGE_CACHE_MASK;		memset(page_address(page) + to, 0, PAGE_CACHE_SIZE - to);	}	err = affs_do_readpage_ofs(file, page, 0, to);	if (!err)		SetPageUptodate(page);	unlock_page(page);	return err;}static int affs_write_begin_ofs(struct file *file, struct address_space *mapping,				loff_t pos, unsigned len, unsigned flags,				struct page **pagep, void **fsdata){	struct inode *inode = mapping->host;	struct page *page;	pgoff_t index;	int err = 0;	pr_debug("AFFS: write_begin(%u, %llu, %llu)\n", (u32)inode->i_ino, (unsigned long long)pos, (unsigned long long)pos + len);	if (pos > AFFS_I(inode)->mmu_private) {		/* XXX: this probably leaves a too-big i_size in case of		 * failure. Should really be updating i_size at write_end time		 */		err = affs_extent_file_ofs(inode, pos);		if (err)			return err;	}	index = pos >> PAGE_CACHE_SHIFT;	page = __grab_cache_page(mapping, index);	if (!page)		return -ENOMEM;	*pagep = page;	if (PageUptodate(page))		return 0;	/* XXX: inefficient but safe in the face of short writes */	err = affs_do_readpage_ofs(file, page, 0, PAGE_CACHE_SIZE);	if (err) {		unlock_page(page);		page_cache_release(page);	}	return err;}static int affs_write_end_ofs(struct file *file, struct address_space *mapping,				loff_t pos, unsigned len, unsigned copied,				struct page *page, void *fsdata){	struct inode *inode = mapping->host;	struct super_block *sb = inode->i_sb;	struct buffer_head *bh, *prev_bh;	char *data;	u32 bidx, boff, bsize;	unsigned from, to;	u32 tmp;	int written;	from = pos & (PAGE_CACHE_SIZE - 1);	to = pos + len;	/*	 * XXX: not sure if this can handle short copies (len < copied), but	 * we don't have to, because the page should always be uptodate here,	 * due to write_begin.	 */	pr_debug("AFFS: write_begin(%u, %llu, %llu)\n", (u32)inode->i_ino, (unsigned long long)pos, (unsigned long long)pos + len);	bsize = AFFS_SB(sb)->s_data_blksize;	data = page_address(page);	bh = NULL;	written = 0;	tmp = (page->index << PAGE_CACHE_SHIFT) + from;	bidx = tmp / bsize;	boff = tmp % bsize;	if (boff) {		bh = affs_bread_ino(inode, bidx, 0);		if (IS_ERR(bh))			return PTR_ERR(bh);		tmp = min(bsize - boff, to - from);		if (boff + tmp > bsize || tmp > bsize)			BUG();		memcpy(AFFS_DATA(bh) + boff, data + from, tmp);		AFFS_DATA_HEAD(bh)->size = cpu_to_be32(be32_to_cpu(AFFS_DATA_HEAD(bh)->size) + tmp);		affs_fix_checksum(sb, bh);		mark_buffer_dirty_inode(bh, inode);		written += tmp;		from += tmp;		bidx++;	} else if (bidx) {		bh = affs_bread_ino(inode, bidx - 1, 0);		if (IS_ERR(bh))			return PTR_ERR(bh);	}	while (from + bsize <= to) {		prev_bh = bh;		bh = affs_getemptyblk_ino(inode, bidx);		if (IS_ERR(bh))			goto out;		memcpy(AFFS_DATA(bh), data + from, bsize);		if (buffer_new(bh)) {			AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);			AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino);			AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);			AFFS_DATA_HEAD(bh)->size = cpu_to_be32(bsize);			AFFS_DATA_HEAD(bh)->next = 0;			bh->b_state &= ~(1UL << BH_New);			if (prev_bh) {				u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);				if (tmp)					affs_warning(sb, "commit_write_ofs", "next block already set for %d (%d)", bidx, tmp);				AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);				affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp);				mark_buffer_dirty_inode(prev_bh, inode);			}		}		affs_brelse(prev_bh);		affs_fix_checksum(sb, bh);		mark_buffer_dirty_inode(bh, inode);		written += bsize;		from += bsize;		bidx++;	}	if (from < to) {		prev_bh = bh;		bh = affs_bread_ino(inode, bidx, 1);		if (IS_ERR(bh))			goto out;		tmp = min(bsize, to - from);		if (tmp > bsize)			BUG();		memcpy(AFFS_DATA(bh), data + from, tmp);		if (buffer_new(bh)) {			AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);			AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino);			AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);			AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp);			AFFS_DATA_HEAD(bh)->next = 0;			bh->b_state &= ~(1UL << BH_New);			if (prev_bh) {				u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);				if (tmp)					affs_warning(sb, "commit_write_ofs", "next block already set for %d (%d)", bidx, tmp);				AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);				affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp);				mark_buffer_dirty_inode(prev_bh, inode);			}		} else if (be32_to_cpu(AFFS_DATA_HEAD(bh)->size) < tmp)			AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp);		affs_brelse(prev_bh);		affs_fix_checksum(sb, bh);		mark_buffer_dirty_inode(bh, inode);		written += tmp;		from += tmp;		bidx++;	}	SetPageUptodate(page);done:	affs_brelse(bh);	tmp = (page->index << PAGE_CACHE_SHIFT) + from;	if (tmp > inode->i_size)		inode->i_size = AFFS_I(inode)->mmu_private = tmp;	unlock_page(page);	page_cache_release(page);	return written;out:	bh = prev_bh;	if (!written)		written = PTR_ERR(bh);	goto done;}const struct address_space_operations affs_aops_ofs = {	.readpage = affs_readpage_ofs,	//.writepage = affs_writepage_ofs,	//.sync_page = affs_sync_page_ofs,	.write_begin = affs_write_begin_ofs,	.write_end = affs_write_end_ofs};/* Free any preallocated blocks. */voidaffs_free_prealloc(struct inode *inode){	struct super_block *sb = inode->i_sb;	pr_debug("AFFS: free_prealloc(ino=%lu)\n", inode->i_ino);	while (AFFS_I(inode)->i_pa_cnt) {		AFFS_I(inode)->i_pa_cnt--;		affs_free_block(sb, ++AFFS_I(inode)->i_lastalloc);	}}/* Truncate (or enlarge) a file to the requested size. */voidaffs_truncate(struct inode *inode){	struct super_block *sb = inode->i_sb;	u32 ext, ext_key;	u32 last_blk, blkcnt, blk;	u32 size;	struct buffer_head *ext_bh;	int i;	pr_debug("AFFS: truncate(inode=%d, oldsize=%u, newsize=%u)\n",		 (u32)inode->i_ino, (u32)AFFS_I(inode)->mmu_private, (u32)inode->i_size);	last_blk = 0;	ext = 0;	if (inode->i_size) {		last_blk = ((u32)inode->i_size - 1) / AFFS_SB(sb)->s_data_blksize;		ext = last_blk / AFFS_SB(sb)->s_hashsize;	}	if (inode->i_size > AFFS_I(inode)->mmu_private) {		struct address_space *mapping = inode->i_mapping;		struct page *page;		void *fsdata;		u32 size = inode->i_size;		int res;		res = mapping->a_ops->write_begin(NULL, mapping, size, 0, 0, &page, &fsdata);		if (!res)			res = mapping->a_ops->write_end(NULL, mapping, size, 0, 0, page, fsdata);		mark_inode_dirty(inode);		return;	} else if (inode->i_size == AFFS_I(inode)->mmu_private)		return;	// lock cache	ext_bh = affs_get_extblock(inode, ext);	if (IS_ERR(ext_bh)) {		affs_warning(sb, "truncate", "unexpected read error for ext block %u (%d)",			     ext, PTR_ERR(ext_bh));		return;	}	if (AFFS_I(inode)->i_lc) {		/* clear linear cache */		i = (ext + 1) >> AFFS_I(inode)->i_lc_shift;		if (AFFS_I(inode)->i_lc_size > i) {			AFFS_I(inode)->i_lc_size = i;			for (; i < AFFS_LC_SIZE; i++)				AFFS_I(inode)->i_lc[i] = 0;		}		/* clear associative cache */		for (i = 0; i < AFFS_AC_SIZE; i++)			if (AFFS_I(inode)->i_ac[i].ext >= ext)				AFFS_I(inode)->i_ac[i].ext = 0;	}	ext_key = be32_to_cpu(AFFS_TAIL(sb, ext_bh)->extension);	blkcnt = AFFS_I(inode)->i_blkcnt;	i = 0;	blk = last_blk;	if (inode->i_size) {		i = last_blk % AFFS_SB(sb)->s_hashsize + 1;		blk++;	} else		AFFS_HEAD(ext_bh)->first_data = 0;	size = AFFS_SB(sb)->s_hashsize;	if (size > blkcnt - blk + i)		size = blkcnt - blk + i;	for (; i < size; i++, blk++) {		affs_free_block(sb, be32_to_cpu(AFFS_BLOCK(sb, ext_bh, i)));		AFFS_BLOCK(sb, ext_bh, i) = 0;	}	AFFS_TAIL(sb, ext_bh)->extension = 0;	affs_fix_checksum(sb, ext_bh);	mark_buffer_dirty_inode(ext_bh, inode);	affs_brelse(ext_bh);	if (inode->i_size) {		AFFS_I(inode)->i_blkcnt = last_blk + 1;		AFFS_I(inode)->i_extcnt = ext + 1;		if (AFFS_SB(sb)->s_flags & SF_OFS) {			struct buffer_head *bh = affs_bread_ino(inode, last_blk, 0);			u32 tmp;			if (IS_ERR(ext_bh)) {				affs_warning(sb, "truncate", "unexpected read error for last block %u (%d)",					     ext, PTR_ERR(ext_bh));				return;			}			tmp = be32_to_cpu(AFFS_DATA_HEAD(bh)->next);			AFFS_DATA_HEAD(bh)->next = 0;			affs_adjust_checksum(bh, -tmp);			affs_brelse(bh);		}	} else {		AFFS_I(inode)->i_blkcnt = 0;		AFFS_I(inode)->i_extcnt = 1;	}	AFFS_I(inode)->mmu_private = inode->i_size;	// unlock cache	while (ext_key) {		ext_bh = affs_bread(sb, ext_key);		size = AFFS_SB(sb)->s_hashsize;		if (size > blkcnt - blk)			size = blkcnt - blk;		for (i = 0; i < size; i++, blk++)			affs_free_block(sb, be32_to_cpu(AFFS_BLOCK(sb, ext_bh, i)));		affs_free_block(sb, ext_key);		ext_key = be32_to_cpu(AFFS_TAIL(sb, ext_bh)->extension);		affs_brelse(ext_bh);	}	affs_free_prealloc(inode);}

⌨️ 快捷键说明

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