文件数据的写入【续】

【write--->vfs_write--->do_sync_write--->generic_file_aio_write--->__generic_file_aio_write--->generic_file_buffered_write】

 

ssize_t generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov,

unsigned long nr_segs, loff_t pos, loff_t *ppos,size_t count, ssize_t written)

{

struct file *file = iocb->ki_filp;

ssize_t status;

struct iov_iter i;

 

iov_iter_init(&i, iov, nr_segs, count, written);

status = generic_perform_write(file, &i, pos);

 

if (likely(status >= 0)) {

written += status;

*ppos = pos + status;

   }

return written ? written : status;

}

在函数iov_iter_init中用待写入数据段初始化iov_iter对象并跳过已写入数据段,然后调用函数generic_perform_write将剩余数据段写入设备缓存。

 

【write--->vfs_write--->do_sync_write--->generic_file_aio_write--->__generic_file_aio_write--->generic_file_buffered_write--->generic_perform_write

 

static ssize_t generic_perform_write(struct file *file,struct iov_iter *i, loff_t pos)

{

......

do {

......

status = a_ops->write_begin(file, mapping, pos, bytes, flags,

&page, &fsdata);

if (unlikely(status))

break;

 

if (mapping_writably_mapped(mapping))

flush_dcache_page(page);

 

pagefault_disable();

copied = iov_iter_copy_from_user_atomic(page, i, offset, bytes);

pagefault_enable();

flush_dcache_page(page);

 

mark_page_accessed(page);

status = a_ops->write_end(file, mapping, pos, bytes, copied,

page, fsdata);

......

} while (iov_iter_count(i));

 

return written ? written : status;

}

首先通过调用函数a_ops->write_begin为数据写入分配页缓存并为这个page准备一组buffer_head结构用于描述组成这个page的数据块,在函数 iov_iter_copy_from_user_atomic中将用户空间数据拷入该页缓存,然后调用函数a_ops->write_end将page中的每一个buffer_head标记为dirty。

 

file->f_mapping是从对应的inode->f_mapping而来,inode->f_mapping->a_ops是由对应的文件系统类型在生成这个inode时赋予的。在ext3文件系统中file->f_mapping->a_ops->write_begin和file->f_mapping->a_ops->write_end定义如下:

static const struct address_space_operations ext3_ordered_aops = {

.....

.write_begin = ext3_write_begin,

.write_end = ext3_ordered_write_end,

......

};

 

【write--->vfs_write--->do_sync_write--->generic_file_aio_write--->__generic_file_aio_write--->generic_file_buffered_write--->generic_perform_write--->ext3_write_begin】

 

static int ext3_write_begin(struct file *file, struct address_space *mapping,

loff_t pos, unsigned len, unsigned flags,struct page **pagep, void **fsdata)

{

......

index = pos >> PAGE_CACHE_SHIFT;

from = pos & (PAGE_CACHE_SIZE - 1);

to = from + len;

 

retry:

page = grab_cache_page_write_begin(mapping, index, flags);

if (!page)

return -ENOMEM;

*pagep = page;

 

......

ret = __block_write_begin(page, pos, len, ext3_get_block);

if (ret)

goto write_begin_failed;

 

......

return ret;

}

在函数grab_cache_page_write_begin中首先通过函数find_lock_page在radix树里面查找要被写的page,如果没找到就通过函数__page_cache_alloc分配一个page。函数__block_write_begin为这个page准备一组buffer_head结构,用于描述组成这个page的数据块。

 

【write--->vfs_write--->do_sync_write--->generic_file_aio_write--->__generic_file_aio_write--->generic_file_buffered_write--->generic_perform_write--->ext3_ordered_write_end】

 

static int ext3_ordered_write_end(struct file *file,struct address_space *mapping,

loff_t pos, unsigned len, unsigned copied,struct page *page, void *fsdata)

{

......

copied = block_write_end(file, mapping, pos, len, copied, page, fsdata);

......

if (ret == 0)

update_file_sizes(inode, pos, copied);

......

return ret ? ret : copied;

}

函数ext3_ordered_write_end就是函数block_write_end的封装。函数block_write_end的工作就是调用函数__block_commit_write将page的每一个buffer_head标记为dirty。然后更新文件的大小inode->i_size = i_size;

 

/**************************************************************/

当数据写入缓存之后等到合适的时候缓存中的数据将被写入设备,这写入设备的工作都将交给具体文件系统的writepage函数来完成。在ext3中函数实现如下:

【ext3_ordered_writepage】

static int ext3_ordered_writepage(struct page *page,

struct writeback_control *wbc)

{

......

ret = block_write_full_page(page, ext3_get_block, wbc);

......

return ret;

}

 

【ext3_ordered_writepage--->block_write_full_page_endio】

int block_write_full_page_endio(struct page *page, get_block_t *get_block,

struct writeback_control *wbc, bh_end_io_t *handler)

{

struct inode * const inode = page->mapping->host;

loff_t i_size = i_size_read(inode);

const pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT;

unsigned offset;

if (page->index < end_index)

return __block_write_full_page(inode, page, get_block, wbc,handler);

 

offset = i_size & (PAGE_CACHE_SIZE-1);

if (page->index >= end_index+1 || !offset) {

do_invalidatepage(page, 0);

unlock_page(page);

return 0; 

}

 

zero_user_segment(page, offset, PAGE_CACHE_SIZE);

return __block_write_full_page(inode, page, get_block, wbc, handler);

}

如果要写入的页在文件容量之内则直接将缓存页写入文件,如果缓存页超出了文件边界则将超出部分清零,然后将整页写入文件。文件大小在上面write_end中更新。

 

【ext3_ordered_writepage--->block_write_full_page_endio--->__block_write_full_page】

 

static int __block_write_full_page(struct inode *inode, struct page *page,

get_block_t *get_block, struct writeback_control *wbc,

bh_end_io_t *handler)

{

......

do {

struct buffer_head *next = bh->b_this_page;

if (buffer_async_write(bh)) {

submit_bh(write_op, bh);

nr_underway++;

}

bh = next;

} while (bh != head);

......

}

将缓存页中的每一个缓存块转化为bio,然后将bio添加到请求,等待数据请求得以处理。

你可能感兴趣的:(数据)