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

📄 file.c

📁 课程设计
💻 C
字号:
#include <linux/fs.h>
#include <linux/buffer_head.h>
#include <linux/bio.h>

#include "xbfs.h"

int xbfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat);
u32 bmp_get_block(struct super_block *sb);
void bmp_free_block(struct super_block *sb, u32 block);

static void xbfs_truncate(struct inode * inode)
{
	int start, end;
	struct xbfs_inode_disk *id;
	struct buffer_head *bh;

	DPRINT("inode truncate to %lld\n", inode->i_size);

	bh = sb_bread(inode->i_sb, inode->i_ino);
	if (!bh) {
		DPRINT("sb_bread inode %ld error\n", inode->i_ino);
		return;
	}

	id = (typeof(id))bh->b_data;
	start = (id->size + BLK_SIZE - 1) >> BLK_SIZE_BITS;
	end = (inode->i_size + BLK_SIZE - 1) >> BLK_SIZE_BITS;
	
	if (start < end) {
		int i;
		
		// grow
		for (i = start; i < end; i++) {
			u32 blk;

			blk = bmp_get_block(inode->i_sb);
			if (!blk)
				goto failed;
			id->blk_list[i] = blk;
		}
		goto done;

failed:
		for (i = start; i < end; i++)
			bmp_free_block(inode->i_sb, id->blk_list[i]);
		inode->i_size = id->size;
		goto out_brelse;

	} else if (start > end) {
		int i;

		// cut
		for (i = end; i < start; i++)
			bmp_free_block(inode->i_sb, id->blk_list[i]);
		goto done;
	}

done:
	id->size = inode->i_size;
	mark_buffer_dirty(bh);
	mark_inode_dirty(inode);
out_brelse:
	brelse(bh);
}


const struct inode_operations xbfs_file_inode_operations = {
	.truncate	= xbfs_truncate,
	.getattr	= xbfs_getattr,
};


const struct file_operations xbfs_file_operations = {
	.llseek		= generic_file_llseek,
	.read		= do_sync_read,
	.write		= do_sync_write,
	.aio_read	= generic_file_aio_read,
	.aio_write	= generic_file_aio_write,
	.open		= generic_file_open,
};

static int end_bio_readpage(struct bio *bio, unsigned int bytes_done, int err)
{
	struct page *page;
	struct inode *inode;

	page = bio->bi_private;

	inode = page->mapping->host;
	DPRINT("inode %ld rel block %ld block %ld\n", 
		inode->i_ino, page->index, bio->bi_sector >> (BLK_SIZE_BITS - 9));

	if (err == -EOPNOTSUPP) {
		set_bit(BIO_EOPNOTSUPP, &bio->bi_flags);
	}

	if (test_bit(BIO_UPTODATE, &bio->bi_flags)) {
		DPRINT("read ok\n");
		SetPageUptodate(page);
	} else {
		DPRINT("read err\n");
		SetPageError(page);
	}
	
	unlock_page(page);
	bio_put(bio);
	return 0;
}

static int end_bio_writepage(struct bio *bio, unsigned int bytes_done, int err)
{
	struct page *page;
	struct inode *inode;

	page = bio->bi_private;

	inode = page->mapping->host;
	DPRINT("inode %ld rel block %ld block %ld\n", 
		inode->i_ino, page->index, bio->bi_sector >> (BLK_SIZE_BITS - 9));

	if (err == -EOPNOTSUPP) {
		set_bit(BIO_EOPNOTSUPP, &bio->bi_flags);
	}

	if (test_bit(BIO_UPTODATE, &bio->bi_flags)) {
		DPRINT("write ok\n");
		end_page_writeback(page);
	} else {
		DPRINT("write err\n");
		SetPageError(page);
	}
	
	bio_put(bio);
	return 0;
}

static int __bio_rw_page(u32 block, struct page *page, 
		int rw, 
		int func(struct bio *, unsigned int , int ))
{
	struct bio *bio;
	int err;
	struct inode *inode;

	inode = page->mapping->host;
	DPRINT("inode %ld rel block %ld block %u\n", 
		inode->i_ino, page->index, block);

	err = 0;

	bio = bio_alloc(GFP_NOIO, 1);
	if (!bio)
		return -ENOMEM;
		
	bio->bi_sector = block << (BLK_SIZE_BITS - 9);
	bio->bi_bdev = page->mapping->host->i_sb->s_bdev;
	bio->bi_io_vec[0].bv_page = page;
	bio->bi_io_vec[0].bv_len = BLK_SIZE;
	bio->bi_io_vec[0].bv_offset = 0;

	bio->bi_vcnt = 1;
	bio->bi_idx = 0;
	bio->bi_size = BLK_SIZE;

	bio->bi_end_io = func;
	bio->bi_private = page;

	bio_get(bio);
	submit_bio(rw, bio);

	if (bio_flagged(bio, BIO_EOPNOTSUPP))
		err = -EOPNOTSUPP;

	bio_put(bio);
	return err;
}

static inline int bio_readpage(u32 block, struct page *page)
{
	return __bio_rw_page(block, page, READ, end_bio_readpage);
}

static inline int bio_writepage(u32 block, struct page *page)
{
	return __bio_rw_page(block, page, WRITE, end_bio_writepage);	
}

static int xbfs_readpage(struct file *file, struct page *page)
{
	struct xbfs_inode_disk *id;
	struct buffer_head *bh;
	struct inode *inode;
	u32 block;
	int err;

	err = 0;

	inode = page->mapping->host;
	DPRINT("inode %ld rel block %lu mapping pages %ld\n", 
			inode->i_ino, page->index,
			page->mapping->nrpages);

	if (page->index > (inode->i_size >> BLK_SIZE_BITS)) {
		DPRINT("page index out of range\n");
		return -EINVAL;
	}

	bh = sb_bread(inode->i_sb, inode->i_ino);
	if (!bh) {
		DPRINT("sb_bread inode %ld error\n", inode->i_ino);
		return -EINVAL;
	}

	id = (typeof(id))bh->b_data;
	block = id->blk_list[page->index];

	err = bio_readpage(block, page);

	brelse(bh);
	return err;
}

static int xbfs_writepage(struct page *page, struct writeback_control *wbc)
{	
	struct xbfs_inode_disk *id;
	struct buffer_head *bh;
	struct inode *inode;
	int err;
	u32 block;

	err = 0;

	inode = page->mapping->host;
	DPRINT("inode %ld rel block %lu\n", inode->i_ino, page->index);

	bh = sb_bread(inode->i_sb, inode->i_ino);
	if (!bh) {
		DPRINT("sb_bread inode %ld error\n", inode->i_ino);
		return -EINVAL;
	}

	id = (typeof(id))bh->b_data;
	block = id->blk_list[page->index];

	set_page_writeback(page);
	err = bio_writepage(block, page);
	unlock_page(page);

	brelse(bh);
	return err;
}

static int xbfs_prepare_write(struct file *file, struct page *page,
		unsigned from, unsigned to)
{
	struct xbfs_inode_disk *id;
	struct buffer_head *bh;
	struct inode *inode;
	int err;
	u32 tot_blk;

	inode = page->mapping->host;
	DPRINT("inode %ld rel block %lu mapping pages %ld\n", 
			inode->i_ino, page->index, 
			page->mapping->nrpages);

	bh = sb_bread(inode->i_sb, inode->i_ino);
	if (!bh) {
		DPRINT("sb_bread inode %ld error\n", inode->i_ino);
		return -EINVAL;
	}

	err = 0;

	id = (typeof(id))bh->b_data;
	tot_blk = (inode->i_size + BLK_SIZE_BITS - 1) >> BLK_SIZE_BITS;
	if (page->index > tot_blk) {
		DPRINT("out of range\n");

		err = -EINVAL;
	} else if (page->index == tot_blk) {
		u32 blk;
		
		DPRINT("append new block\n");
		
		blk = bmp_get_block(inode->i_sb);
		if (!blk) 
			err = -ENOSPC;
		else {
			id->blk_list[page->index] = blk;
			mark_buffer_dirty(bh);
			mark_inode_dirty(inode);
		}
	} else {
		u32 blk;

		DPRINT("write old block\n");
		
		blk = id->blk_list[page->index];		
		err = bio_readpage(blk, page);

		lock_page(page);
		
		DPRINT("read ok\n");
		if (PageError(page))
			err = -EIO;
	}

	brelse(bh);
	return err;
}


static int xbfs_commit_write(struct file *file, struct page *page,
		unsigned from, unsigned to)
{
	struct inode *inode;
	loff_t pos;
	char *addr;

	addr = kmap(page);	
	DPRINT("content %.10s\n", addr);
	kunmap(page);
	
	inode = page->mapping->host;
	pos = ((loff_t)page->index << BLK_SIZE_BITS) + to;
	if (pos > inode->i_size) {
		DPRINT("size change to %ld\n", pos);

		inode->i_size = pos;
		mark_inode_dirty(inode);
	}

	set_page_dirty(page);
	SetPageUptodate(page);
	return 0;
}


const struct address_space_operations xbfs_aops = {
	.readpage = xbfs_readpage,
	.writepage = xbfs_writepage,
	.prepare_write = xbfs_prepare_write,
	.commit_write = xbfs_commit_write
};

⌨️ 快捷键说明

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