1. 程式人生 > >SimpleFs檔案系統初步五(檔案的讀寫)

SimpleFs檔案系統初步五(檔案的讀寫)

1.寫資料的過程:

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