Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 168 additions & 4 deletions file.c
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ static int simplefs_write_end(struct file *file,
* over the data block pointers, releasing the associated data blocks, and
* updating the inode metadata (size and block count).
*/
static int simplefs_file_open(struct inode *inode, struct file *filp)
static int simplefs_open(struct inode *inode, struct file *filp)
{
bool wronly = (filp->f_flags & O_WRONLY);
bool rdwr = (filp->f_flags & O_RDWR);
Expand Down Expand Up @@ -293,6 +293,170 @@ static int simplefs_file_open(struct inode *inode, struct file *filp)
return 0;
}

static ssize_t simplefs_read(struct file *file,
char __user *buf,
size_t len,
loff_t *ppos)
{
struct inode *inode = file_inode(file);
struct super_block *sb = inode->i_sb;
ssize_t bytes_read = 0;
loff_t pos = *ppos;

if (pos > inode->i_size)
return 0;

/* find extent block */
struct buffer_head *bh = sb_bread(sb, SIMPLEFS_INODE(inode)->ei_block);
struct simplefs_file_ei_block *ei_block =
(struct simplefs_file_ei_block *) bh->b_data;


if (pos + len > inode->i_size)
len = inode->i_size - pos;

/* count block position */
sector_t block_index = pos / SIMPLEFS_BLOCK_SIZE;
sector_t ei_index = block_index / SIMPLEFS_MAX_BLOCKS_PER_EXTENT;
sector_t block_offset = ei_block->extents[ei_index].ee_start +
block_index % SIMPLEFS_MAX_BLOCKS_PER_EXTENT;

while (len > 0) {
struct buffer_head *bh_data = sb_bread(sb, block_offset);
if (!bh_data) {
pr_err("Failed to read data block %llu\n", block_offset);
bytes_read = -EIO;
break;
}

size_t offset = pos % SIMPLEFS_BLOCK_SIZE;
size_t bytes_to_read =
min_t(size_t, len, SIMPLEFS_BLOCK_SIZE - pos % SIMPLEFS_BLOCK_SIZE);
if (copy_to_user(buf + bytes_read, bh_data->b_data + offset,
bytes_to_read)) {
brelse(bh_data);
bytes_read = -EFAULT;
break;
}
brelse(bh_data);

/* successfully read data */
bytes_read += bytes_to_read;
len -= bytes_to_read;
pos += bytes_to_read;

/* count extent block */
block_index++;
ei_index = block_index / SIMPLEFS_MAX_BLOCKS_PER_EXTENT;
block_offset = ei_block->extents[ei_index].ee_start +
block_index % SIMPLEFS_MAX_BLOCKS_PER_EXTENT;
}

brelse(bh);
*ppos = pos;

return bytes_read;
}

static ssize_t simplefs_write(struct file *file,
const char __user *buf,
size_t len,
loff_t *ppos)
{
struct inode *inode = file_inode(file);
struct super_block *sb = inode->i_sb;
ssize_t bytes_write = 0;
loff_t pos = *ppos;

if (pos > inode->i_size)
return 0;
len = min_t(size_t, len, SIMPLEFS_MAX_FILESIZE - pos);

/* find extent block */
struct buffer_head *bh = sb_bread(sb, SIMPLEFS_INODE(inode)->ei_block);
if (!bh)
return -EIO;
struct simplefs_file_ei_block *ei_block =
(struct simplefs_file_ei_block *) bh->b_data;

/* count block position */
sector_t block_index = pos / SIMPLEFS_BLOCK_SIZE;
sector_t ei_index = block_index / SIMPLEFS_MAX_BLOCKS_PER_EXTENT;

/* write data */
while (len > 0) {
/* check if block is allocated */
if (ei_block->extents[ei_index].ee_start == 0) {
int bno = get_free_blocks(sb, 8);
if (!bno) {
bytes_write = -ENOSPC;
break;
}
ei_block->extents[ei_index].ee_start = bno;
ei_block->extents[ei_index].ee_len = 8;
ei_block->extents[ei_index].ee_block =
ei_index ? ei_block->extents[ei_index - 1].ee_block +
ei_block->extents[ei_index - 1].ee_len
: 0;
}

struct buffer_head *bh_data =
sb_bread(sb, ei_block->extents[ei_index].ee_start +
block_index % SIMPLEFS_MAX_BLOCKS_PER_EXTENT);
if (!bh_data) {
pr_err("Failed to read data block %llu\n",
ei_block->extents[ei_index].ee_start +
block_index % SIMPLEFS_MAX_BLOCKS_PER_EXTENT);
bytes_write = -EIO;
break;
}
/* copy data from buffer */
size_t bytes_to_write =
min_t(size_t, len, SIMPLEFS_BLOCK_SIZE - pos % SIMPLEFS_BLOCK_SIZE);

if (copy_from_user(bh_data->b_data + pos % SIMPLEFS_BLOCK_SIZE, buf,
bytes_to_write)) {
brelse(bh_data);
bytes_write = -EFAULT;
break;
}

mark_buffer_dirty(bh_data);
sync_dirty_buffer(bh_data);
brelse(bh_data);

/* successfully write data */
len = len - bytes_to_write;
bytes_write += bytes_to_write;
pos += bytes_to_write;

/* count extent block */
block_index = pos / SIMPLEFS_BLOCK_SIZE;
ei_index = block_index / SIMPLEFS_MAX_BLOCKS_PER_EXTENT;
}
mark_buffer_dirty(bh);
sync_dirty_buffer(bh);
brelse(bh);

inode->i_size = max(pos, inode->i_size);
inode->i_blocks = DIV_ROUND_UP(inode->i_size, SIMPLEFS_BLOCK_SIZE) + 1;
#if SIMPLEFS_AT_LEAST(6, 7, 0)
struct timespec64 cur_time = current_time(inode);
inode_set_mtime_to_ts(inode, cur_time);
inode_set_ctime_to_ts(inode, cur_time);
#elif SIMPLEFS_AT_LEAST(6, 6, 0)
struct timespec64 cur_time = current_time(inode);
inode->i_mtime = cur_time;
inode_set_ctime_to_ts(inode, cur_time);
#else
inode->i_mtime = inode->i_ctime = current_time(inode);
#endif
mark_inode_dirty(inode);
*ppos = pos;

return bytes_write;
}

const struct address_space_operations simplefs_aops = {
#if SIMPLEFS_AT_LEAST(5, 19, 0)
.readahead = simplefs_readahead,
Expand All @@ -307,8 +471,8 @@ const struct address_space_operations simplefs_aops = {
const struct file_operations simplefs_file_ops = {
.llseek = generic_file_llseek,
.owner = THIS_MODULE,
.read_iter = generic_file_read_iter,
.write_iter = generic_file_write_iter,
.fsync = generic_file_fsync,
.open = simplefs_file_open,
.open = simplefs_open,
.read = simplefs_read,
.write = simplefs_write,
};
2 changes: 2 additions & 0 deletions simplefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#define SIMPLEFS_MAX_EXTENTS \
((SIMPLEFS_BLOCK_SIZE - sizeof(uint32_t)) / sizeof(struct simplefs_extent))
#define SIMPLEFS_MAX_BLOCKS_PER_EXTENT 8 /* It can be ~(uint32) 0 */
#define SIMPLEFS_MAX_SIZES_PER_EXTENT \
(SIMPLEFS_MAX_BLOCKS_PER_EXTENT * SIMPLEFS_BLOCK_SIZE)
#define SIMPLEFS_MAX_FILESIZE \
((uint64_t) SIMPLEFS_MAX_BLOCKS_PER_EXTENT * SIMPLEFS_BLOCK_SIZE * \
SIMPLEFS_MAX_EXTENTS)
Expand Down