ssize_t simplefs_write(struct file * filp, const char __user * buf, size_t len,
loff_t * ppos)
{
/* After the commit dd37978c5 in the upstream linux kernel,
* we can use just filp->f_inode instead of the
* f->f_path.dentry->d_inode redirection */
struct inode *inode;
struct simplefs_inode *sfs_inode;
struct buffer_head *bh;
struct super_block *sb;
char *buffer;
int retval;
#if 0
retval = generic_write_checks(filp, ppos, &len, 0);
if (retval) {
return retval;
}
#endif
//通過文件得到內核對應的Inode指針
inode = filp->f_path.dentry->d_inode;
//通過內核的Inode指針進而得到特定文件系統的Inode指針
sfs_inode = SIMPLEFS_INODE(inode);
//通過Inode得到SuperBlock
sb = inode->i_sb;
//獲取該Inode指向的數據塊
bh = sb_bread(filp->f_path.dentry->d_inode->i_sb,
sfs_inode->data_block_number);
if (!bh) {
printk(KERN_ERR "Reading the block number [%llu] failed.",
sfs_inode->data_block_number);
return 0;
}
//將數據區強制轉換爲char*型
buffer = (char *)bh->b_data;
/* Move the pointer until the required byte offset */
//移動到vfs指定的偏移位置
buffer += *ppos;
//拷貝用戶空間的數據到對應的數據塊中
if (copy_from_user(buffer, buf, len)) {
brelse(bh);
printk(KERN_ERR
"Error copying file contents from the userspace buffer to the kernel space\n");
return -EFAULT;
}
//通知VFS指針偏移了多少
*ppos += len;
//將數據區設置爲Dirty,並回寫到磁盤
mark_buffer_dirty(bh);
sync_dirty_buffer(bh);
//最後釋放數據塊的指針
brelse(bh);
/* Set new size
* sfs_inode->file_size = max(sfs_inode->file_size, *ppos);
*
* FIXME: What to do if someone writes only some parts in between ?
* The above code will also fail in case a file is overwritten with
* a shorter buffer */
if (mutex_lock_interruptible(&simplefs_inodes_mgmt_lock)) {
sfs_trace("Failed to acquire mutex lock\n");
return -EINTR;
}
//更新Inode的文件大小
sfs_inode->file_size = *ppos;
//既然更新了Inode的信息,那麼Inode的信息區也要同步更新下
retval = simplefs_inode_save(sb, sfs_inode);
if (retval) {
len = retval;
}
mutex_unlock(&simplefs_inodes_mgmt_lock);
return len;
}
2.讀數據的過程:
ssize_t simplefs_read(struct file * filp, char __user * buf, size_t len,
loff_t * ppos)
{
/* After the commit dd37978c5 in the upstream linux kernel,
* we can use just filp->f_inode instead of the
* f->f_path.dentry->d_inode redirection */
struct simplefs_inode *inode =
SIMPLEFS_INODE(filp->f_path.dentry->d_inode);
struct buffer_head *bh;
char *buffer;
int nbytes;
//如果要讀數據的偏移超出了該Inode的大小,那麼直接返回讀取長度爲0
if (*ppos >= inode->file_size) {
/* Read request with offset beyond the filesize */
return 0;
}
//得到該Inode的數據區,將其讀取出來
bh = sb_bread(filp->f_path.dentry->d_inode->i_sb,
inode->data_block_number);
if (!bh) {
printk(KERN_ERR "Reading the block number [%llu] failed.",
inode->data_block_number);
return 0;
}
//將數據區強制轉換爲Char*
buffer = (char *)bh->b_data;
//既然是讀,就要考慮到有可能你讀取的長度會超過該Inode的大小,因此需要取倆者中的最大值
nbytes = min((size_t) inode->file_size, len);
//該Inode讀取到的數據傳遞給用戶層
if (copy_to_user(buf, buffer, nbytes)) {
brelse(bh);
printk(KERN_ERR
"Error copying file contents to the userspace buffer\n");
return -EFAULT;
}
//由於讀取操作不會改變磁盤的內容因此不需要同步操作,直接釋放數據塊的指針
brelse(bh);
//改變遊標的指針
*ppos += nbytes;
//返回讀取的長度
return nbytes;
}