📄 file.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 + -