Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

questionable code: always copy data from the beginning of buf when file is writing #66

Open
zhuqianbin opened this issue Feb 5, 2025 · 0 comments

Comments

@zhuqianbin
Copy link

zhuqianbin commented Feb 5, 2025

In the following function, buf pointer will not moved forward according to bytes_write and it always copies data from the beginning of buf

if (copy_from_user(bh_data->b_data + pos % SIMPLEFS_BLOCK_SIZE, buf,
bytes_to_write)):

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;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant