上面的函数fat_cache_lookup从名字可以看出,它只是在cache中进行这样的查找过程中,这显然是不够的,因为cache是存在于内存中的,最初是不存在的,只能从FAT表中进行查找。
int
fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus)
//该函数输入为inode以及要查找的文件的cluster,要返回的是该cluster在磁盘上对应的dclus
{
struct super_block *sb = inode->i_sb;
const int limit = sb->s_maxbytes
>> MSDOS_SB(sb)->cluster_bits;
struct fat_entry fatent;
struct fat_cache_id cid;
int nr;
BUG_ON(MSDOS_I(inode)->i_start == 0);
*fclus = 0;
*dclus = MSDOS_I(inode)->i_start;
if (cluster == 0)
return 0;
//首先尽量从cache中进行查找,这样可以节省很多时间的。
if (fat_cache_lookup(inode, cluster,
&cid, fclus, dclus) < 0) {
/*
* dummy, always not contiguous
* This is reinitialized by cache_init(),
later.
*/
cache_init(&cid, -1, -1);
}
//剩下的工作只能从FAT表中一个一个的查找了,确实是一个一个查找,从后面的代码(*fclus)++;也可以看出来。
fatent_init(&fatent);
//这样可能会出现两种情况
//1.
*fclus = cluster即需要查找的cluster已经被包含在cache中,那么皆大欢喜,查找结束
//2.*fclus
< cluster, cache中包含不完全,其中* dclus中返回的是离cluster最近的cluster在磁盘上位置。然后根据该dclus从FAT表中查找
while (*fclus < cluster) {
/* prevent the infinite loop of
cluster chain */
if (*fclus > limit) {
fat_fs_error(sb, "%s:
detected the cluster chain loop"
" (i_pos %lld)", __func__,
MSDOS_I(inode)->i_pos);
nr = -EIO;
goto out;
}
//根据dclus中FAT表查找出,下一个cluster在磁盘上的位置。
nr = fat_ent_read(inode,
&fatent, *dclus);
if (nr < 0)
goto out;
else if (nr == FAT_ENT_FREE) {
fat_fs_error(sb, "%s:
invalid cluster chain"
" (i_pos %lld)", __func__,
MSDOS_I(inode)->i_pos);
nr = -EIO;
goto out;
} else if (nr == FAT_ENT_EOF) {
fat_cache_add(inode,
&cid);
goto out;
}
(*fclus)++;
*dclus = nr;
if (!cache_contiguous(&cid,
*dclus))
cache_init(&cid,
*fclus, *dclus);
}
nr = 0;
//查找结束,需要将相应的结果添加到cache中,便于下一次查找
fat_cache_add(inode, &cid);
out:
fatent_brelse(&fatent);
//最终返回文件cluster对应的磁盘cluster号
return nr;
}
说到fat_ent_read函数就不得不说struct
fatent_operations结构体,因为这个函数用到了很多的函数指针,因为不同的FAT类型(FAT12,FAT16,FAT32)而不同。
struct
fatent_operations {
void (*ent_blocknr)(struct super_block *,
int, int *, sector_t *);
//对应的cluster所在的FAT表中的位置
void (*ent_set_ptr)(struct fat_entry *,
int);
int (*ent_bread)(struct super_block *,
struct fat_entry *,
int, sector_t);
//用于读出一个block的内容,显然不管是数据读取还是
//在获得文件的存储位置(从FAT表中读取)都是需要
//该函数的
int (*ent_get)(struct fat_entry *);
//用于获得FAT表中的下一个cluster所在的位置
void (*ent_put)(struct fat_entry *, int);
int (*ent_next)(struct fat_entry *);
};
int
fat_ent_read(struct inode *inode, struct fat_entry *fatent, int entry)
{
struct super_block *sb = inode->i_sb;
struct msdos_sb_info *sbi =
MSDOS_SB(inode->i_sb);
struct fatent_operations *ops =
sbi->fatent_ops;
int err, offset;
sector_t blocknr;
if (entry < FAT_START_ENT ||
sbi->max_cluster <= entry) {
fatent_brelse(fatent);
fat_fs_error(sb, "invalid
access to FAT (entry 0x%08x)", entry);
return -EIO;
}
fatent_set_entry(fatent, entry);
//要获得一个文件cluster对应的磁盘cluster要分为三步:
1.算出文件cluster在FAT表中对应的位置,ent_blocknr完成
2.读出FAT表中的内容,ent_bread完成
3.获得对应的磁盘cluster,ent_get完成
ops->ent_blocknr(sb, entry,
&offset, &blocknr);
if (!fat_ent_update_ptr(sb, fatent,
offset, blocknr)) {
fatent_brelse(fatent);
err = ops->ent_bread(sb,
fatent, offset, blocknr);
if (err)
return err;
}
return ops->ent_get(fatent);
}