SimpleFs檔案系統初步五(檔案的讀寫)
阿新 • • 發佈:2018-11-24
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; }