[文件系统] 一个简单文件系统的实现(9)
然后就是目录操作(在dir.c中定义)
const struct file_operations gt_dir_operations ={
.llseek =generic_file_llseek,
.read =generic_read_dir,
.readdir =gt_readdir,
.fsync =gt_sync_file,
};
gt_readdir(在dir.c中定义)
linux文件系统对文件的读写是以页为单位的。
static int gt_readdir(struct file *filp,void *dirent,filldir_t filldir){
loff_t pos=filp->f_pos;//目前读到的位置,文件内偏移
struct inode *inode=filp->f_path.dentry->d_inode;//目录文件的inode
unsigned int offset=pos & ~PAGE_CACHE_MASK;
unsigned long n=pos >> PAGE_CACHE_SHIFT;//目前读到第几页
unsigned long npages=gt_dir_pages(inode);//该文件在内存中占用的页数
unsigned chunk_size=sizeof(struct gt_dir_entry);
lock_kernel();
pos=(pos+chunk_size-1)&~(chunk_size-1);//将目前读到的位置调整到目录项开始
if(pos>=inode->i_size)
goto done;
for(;n<npages;n++,offset=){//遍历文件所占用的页
char *kaddr,*limit;
char *p;
struct page *page=gt_get_page(inode,n);//获取到第n页
if(IS_ERR(page)){
continue;
printk("page is error\n");
}
kaddr=(char *)page_address(page);//第n页在内存中的地址
p=(kaddr+offset);//指向当前该读入的目录项的地址
limit=kaddr+gt_last_byte(inode,n)-chunk_size;//边界
for(;p<=limit;p=gt_next_entry(p)){
struct gt_dir_entry * de=(struct gt_dir_entry*)p;
if(de->ino){//目录项有对应的索引节点号
offset=p -kaddr;//在页内的偏移
unsigned name_len=strnlen(de->name,GT_NAME_LEN);
unsigned char d_type=DT_UNKNOWN;
int over=filldir(dirent,de->name,name_len,(n<<PAGE_CACHE_SHIFT)|offset,le32_to_cpu(de->ino),d_type);//调用VFS函数填充dirent结构,有兴趣的朋友可以自己去研究
if(over){
gt_put_page(page);//如果错误就释放该页,跳到done标号处
goto done;
}
}
}
gt_put_page(page);
}
done:
filp->f_pos=(n<<PAGE_CACHE_SHIFT)|offset;//调整当前文件内偏移
unlock_kernel();
return ;
}
这段函数调用了几个新函数,主要是使用作为参数传递进来的filldir函数来完成gt_readdir
下面来看看这段函数中调用的新函数
gt_dir_pages(在dir.c中定义)
static inline unsigned long gt_dir_pages(struct inode *inode){
return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT;
}
很简单,就不解释了
gt_get_page(在dir.c中定义)
static struct page *gt_get_page(struct inode *dir,unsigned long n){
struct address_space *mapping=dir->i_mapping;
struct page *page=read_mapping_page(mapping,n,NULL);
if(!IS_ERR(page)){
kmap(page);
if(!PageUptodate(page))
goto fail;
}
return page;
fail:
gt_put_page(page);
return ERR_PTR(-EIO);
}
gt_get_page主要通过调用read_mapping_page实现,另外还加了点错误判断等
gt_last_byte(在dir.c中定义)
static unsigned gt_last_byte(struct inode *inode, unsigned long page_nr){
unsigned last_byte = inode->i_size;
last_byte -= page_nr << PAGE_CACHE_SHIFT;
if (last_byte > PAGE_CACHE_SIZE)
last_byte = PAGE_CACHE_SIZE;
return last_byte;
}
gt_last_byte函数用来返回文件在第n个页中的偏移,在前n-1个页中偏移都是PAGE_CACHE_SIZE
gt_next_entry(在dir.c中定义)
static inline void *gt_next_entry(void *de){
return (void *)((char *)de+sizeof(struct gt_dir_entry));
}
这个函数也很简单,主用用来遍历目录项
gt_sync_file在前边已经分析完
这样目录操作也分析完了,下边是地址空间操作gt_aops
文章来源CU社区:[文件系统] 一个简单文件系统的实现
相关文章