文件打开了,我们就来写一写。
write
系统调用write定义在kernel/fs/read_write.c,通过vfs_write
调用file->f_op->write
来写入文件。
SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf,
size_t, count)
{
struct fd f = fdget_pos(fd);
ssize_t ret = -EBADF;
if (f.file) {
loff_t pos = file_pos_read(f.file);
ret = vfs_write(f.file, buf, count, &pos);
if (ret >= 0)
file_pos_write(f.file, pos);
fdput_pos(f);
}
return ret;
}
FAT的文件操作如下,定义在kernel/fs/fat/file.c,可以看到.write=new_sync_write
,即file->f_op->write=new_sync_write
。
new_sync_write
又调用了filp->f_op->write_iter
,即generic_file_write_iter
。
const struct file_operations fat_file_operations = {
.llseek = generic_file_llseek,
.read = new_sync_read,
.write = new_sync_write,
.read_iter = generic_file_read_iter,
.write_iter = generic_file_write_iter,
.mmap = generic_file_mmap,
.release = fat_file_release,
.unlocked_ioctl = fat_generic_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = fat_generic_compat_ioctl,
#endif
.fsync = fat_file_fsync,
.splice_read = generic_file_splice_read,
};
generic_file_write_iter
定义在kernel/mm/filemap.c,进一步是__generic_file_write_iter
==>generic_perform_write
。
ssize_t generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
{
struct file *file = iocb->ki_filp;
struct inode *inode = file->f_mapping->host;
ssize_t ret;
mutex_lock(&inode->i_mutex);
ret = __generic_file_write_iter(iocb, from);
mutex_unlock(&inode->i_mutex);
if (ret > 0) {
ssize_t err;
err = generic_write_sync(file, iocb->ki_pos - ret, ret);
if (err < 0)
ret = err;
}
return ret;
}
简化如下,iov_iter_copy_from_user_atomic
就是一个类似于memcpy的函数,它把用户buffer的内容复制到内存页中。
ssize_t generic_perform_write(struct file *file,
struct iov_iter *i, loff_t pos)
{
//...
copied = iov_iter_copy_from_user_atomic(page, i, offset, bytes);
//...
}
其实到这里,一般的write流程就结束了,所谓内存页也只是某块内存,也就是write结束时,内容并没有写到磁盘中。如果这时候突然断电,磁盘里是没有更新的。
内存里的脏buffer什么时候刷到磁盘上的呢?