Commit 99df9271 authored by Hirofumi Ogawa's avatar Hirofumi Ogawa Committed by Arnaldo Carvalho de Melo

[PATCH] Adds the large partition (> 128GB) support to FAT (1/5)

This adds large partition (> 128GB) support to FAT.
parent 38ab2cd5
...@@ -302,32 +302,36 @@ static int fat_get_cluster(struct inode *inode, int cluster) ...@@ -302,32 +302,36 @@ static int fat_get_cluster(struct inode *inode, int cluster)
return nr; return nr;
} }
int fat_bmap(struct inode *inode, int sector) int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys)
{ {
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
struct msdos_sb_info *sbi = MSDOS_SB(sb); struct msdos_sb_info *sbi = MSDOS_SB(sb);
int cluster, offset, last_block; sector_t last_block;
int cluster, offset;
*phys = 0;
if ((sbi->fat_bits != 32) && if ((sbi->fat_bits != 32) &&
(inode->i_ino == MSDOS_ROOT_INO || (S_ISDIR(inode->i_mode) && (inode->i_ino == MSDOS_ROOT_INO || (S_ISDIR(inode->i_mode) &&
!MSDOS_I(inode)->i_start))) { !MSDOS_I(inode)->i_start))) {
if (sector >= sbi->dir_entries >> sbi->dir_per_block_bits) if (sector < (sbi->dir_entries >> sbi->dir_per_block_bits))
return 0; *phys = sector + sbi->dir_start;
return sector + sbi->dir_start; return 0;
} }
last_block = (MSDOS_I(inode)->mmu_private + (sb->s_blocksize - 1)) last_block = (MSDOS_I(inode)->mmu_private + (sb->s_blocksize - 1))
>> sb->s_blocksize_bits; >> sb->s_blocksize_bits;
if (sector >= last_block) if (sector >= last_block)
return 0; return 0;
cluster = sector / sbi->cluster_size; cluster = sector >> (sbi->cluster_bits - sb->s_blocksize_bits);
offset = sector % sbi->cluster_size; offset = sector & (sbi->cluster_size - 1);
cluster = fat_get_cluster(inode, cluster); cluster = fat_get_cluster(inode, cluster);
if (cluster < 0) if (cluster < 0)
return cluster; return cluster;
else if (!cluster) else if (cluster) {
return 0; *phys = ((sector_t)cluster - 2) * sbi->cluster_size
return (cluster - 2) * sbi->cluster_size + sbi->data_start + offset; + sbi->data_start + offset;
}
return 0;
} }
......
...@@ -191,11 +191,11 @@ int fat_search_long(struct inode *inode, const char *name, int name_len, ...@@ -191,11 +191,11 @@ int fat_search_long(struct inode *inode, const char *name, int name_len,
int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate; int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
int utf8 = MSDOS_SB(sb)->options.utf8; int utf8 = MSDOS_SB(sb)->options.utf8;
unsigned short opt_shortname = MSDOS_SB(sb)->options.shortname; unsigned short opt_shortname = MSDOS_SB(sb)->options.shortname;
int ino, chl, i, j, last_u, res = 0; int chl, i, j, last_u, res = 0;
loff_t cpos = 0; loff_t i_pos, cpos = 0;
while(1) { while(1) {
if (fat_get_entry(inode,&cpos,&bh,&de,&ino) == -1) if (fat_get_entry(inode,&cpos,&bh,&de,&i_pos) == -1)
goto EODir; goto EODir;
parse_record: parse_record:
long_slots = 0; long_slots = 0;
...@@ -246,7 +246,7 @@ int fat_search_long(struct inode *inode, const char *name, int name_len, ...@@ -246,7 +246,7 @@ int fat_search_long(struct inode *inode, const char *name, int name_len,
if (ds->id & 0x40) { if (ds->id & 0x40) {
unicode[offset + 13] = 0; unicode[offset + 13] = 0;
} }
if (fat_get_entry(inode,&cpos,&bh,&de,&ino)<0) if (fat_get_entry(inode,&cpos,&bh,&de,&i_pos)<0)
goto EODir; goto EODir;
if (slot == 0) if (slot == 0)
break; break;
...@@ -358,8 +358,9 @@ static int fat_readdirx(struct inode *inode, struct file *filp, void *dirent, ...@@ -358,8 +358,9 @@ static int fat_readdirx(struct inode *inode, struct file *filp, void *dirent,
int utf8 = MSDOS_SB(sb)->options.utf8; int utf8 = MSDOS_SB(sb)->options.utf8;
int nocase = MSDOS_SB(sb)->options.nocase; int nocase = MSDOS_SB(sb)->options.nocase;
unsigned short opt_shortname = MSDOS_SB(sb)->options.shortname; unsigned short opt_shortname = MSDOS_SB(sb)->options.shortname;
int ino, inum, chi, chl, i, i2, j, last, last_u, dotoffset = 0; unsigned long inum;
loff_t cpos; int chi, chl, i, i2, j, last, last_u, dotoffset = 0;
loff_t i_pos, cpos;
int ret = 0; int ret = 0;
lock_kernel(); lock_kernel();
...@@ -387,7 +388,7 @@ static int fat_readdirx(struct inode *inode, struct file *filp, void *dirent, ...@@ -387,7 +388,7 @@ static int fat_readdirx(struct inode *inode, struct file *filp, void *dirent,
bh = NULL; bh = NULL;
GetNew: GetNew:
long_slots = 0; long_slots = 0;
if (fat_get_entry(inode,&cpos,&bh,&de,&ino) == -1) if (fat_get_entry(inode,&cpos,&bh,&de,&i_pos) == -1)
goto EODir; goto EODir;
/* Check for long filename entry */ /* Check for long filename entry */
if (isvfat) { if (isvfat) {
...@@ -445,7 +446,7 @@ static int fat_readdirx(struct inode *inode, struct file *filp, void *dirent, ...@@ -445,7 +446,7 @@ static int fat_readdirx(struct inode *inode, struct file *filp, void *dirent,
if (ds->id & 0x40) { if (ds->id & 0x40) {
unicode[offset + 13] = 0; unicode[offset + 13] = 0;
} }
if (fat_get_entry(inode,&cpos,&bh,&de,&ino) == -1) if (fat_get_entry(inode,&cpos,&bh,&de,&i_pos) == -1)
goto EODir; goto EODir;
if (slot == 0) if (slot == 0)
break; break;
...@@ -533,7 +534,7 @@ static int fat_readdirx(struct inode *inode, struct file *filp, void *dirent, ...@@ -533,7 +534,7 @@ static int fat_readdirx(struct inode *inode, struct file *filp, void *dirent,
else if (!memcmp(de->name,MSDOS_DOTDOT,11)) { else if (!memcmp(de->name,MSDOS_DOTDOT,11)) {
inum = parent_ino(filp->f_dentry); inum = parent_ino(filp->f_dentry);
} else { } else {
struct inode *tmp = fat_iget(sb, ino); struct inode *tmp = fat_iget(sb, i_pos);
if (tmp) { if (tmp) {
inum = tmp->i_ino; inum = tmp->i_ino;
iput(tmp); iput(tmp);
...@@ -677,14 +678,14 @@ int fat_dir_ioctl(struct inode * inode, struct file * filp, ...@@ -677,14 +678,14 @@ int fat_dir_ioctl(struct inode * inode, struct file * filp,
/***** See if directory is empty */ /***** See if directory is empty */
int fat_dir_empty(struct inode *dir) int fat_dir_empty(struct inode *dir)
{ {
loff_t pos; loff_t pos, i_pos;
struct buffer_head *bh; struct buffer_head *bh;
struct msdos_dir_entry *de; struct msdos_dir_entry *de;
int ino,result = 0; int result = 0;
pos = 0; pos = 0;
bh = NULL; bh = NULL;
while (fat_get_entry(dir,&pos,&bh,&de,&ino) > -1) { while (fat_get_entry(dir,&pos,&bh,&de,&i_pos) > -1) {
/* Ignore vfat longname entries */ /* Ignore vfat longname entries */
if (de->attr == ATTR_EXT) if (de->attr == ATTR_EXT)
continue; continue;
...@@ -703,7 +704,7 @@ int fat_dir_empty(struct inode *dir) ...@@ -703,7 +704,7 @@ int fat_dir_empty(struct inode *dir)
/* This assumes that size of cluster is above the 32*slots */ /* This assumes that size of cluster is above the 32*slots */
int fat_add_entries(struct inode *dir,int slots, struct buffer_head **bh, int fat_add_entries(struct inode *dir,int slots, struct buffer_head **bh,
struct msdos_dir_entry **de, int *ino) struct msdos_dir_entry **de, loff_t *i_pos)
{ {
struct super_block *sb = dir->i_sb; struct super_block *sb = dir->i_sb;
loff_t offset, curr; loff_t offset, curr;
...@@ -713,7 +714,7 @@ int fat_add_entries(struct inode *dir,int slots, struct buffer_head **bh, ...@@ -713,7 +714,7 @@ int fat_add_entries(struct inode *dir,int slots, struct buffer_head **bh,
offset = curr = 0; offset = curr = 0;
*bh = NULL; *bh = NULL;
row = 0; row = 0;
while (fat_get_entry(dir, &curr, bh, de, ino) > -1) { while (fat_get_entry(dir, &curr, bh, de, i_pos) > -1) {
/* check the maximum size of directory */ /* check the maximum size of directory */
if (curr >= FAT_MAX_DIR_SIZE) { if (curr >= FAT_MAX_DIR_SIZE) {
brelse(*bh); brelse(*bh);
...@@ -735,7 +736,7 @@ int fat_add_entries(struct inode *dir,int slots, struct buffer_head **bh, ...@@ -735,7 +736,7 @@ int fat_add_entries(struct inode *dir,int slots, struct buffer_head **bh,
return PTR_ERR(new_bh); return PTR_ERR(new_bh);
brelse(new_bh); brelse(new_bh);
do { do {
fat_get_entry(dir, &curr, bh, de, ino); fat_get_entry(dir, &curr, bh, de, i_pos);
} while (++row < slots); } while (++row < slots);
return offset; return offset;
......
...@@ -32,11 +32,12 @@ int fat_get_block(struct inode *inode, sector_t iblock, ...@@ -32,11 +32,12 @@ int fat_get_block(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int create) struct buffer_head *bh_result, int create)
{ {
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
unsigned long phys; sector_t phys;
int err;
phys = fat_bmap(inode, iblock); err = fat_bmap(inode, iblock, &phys);
if (phys < 0) if (err)
return phys; return err;
if (phys) { if (phys) {
map_bh(bh_result, sb, phys); map_bh(bh_result, sb, phys);
return 0; return 0;
...@@ -55,9 +56,9 @@ int fat_get_block(struct inode *inode, sector_t iblock, ...@@ -55,9 +56,9 @@ int fat_get_block(struct inode *inode, sector_t iblock,
return error; return error;
} }
MSDOS_I(inode)->mmu_private += sb->s_blocksize; MSDOS_I(inode)->mmu_private += sb->s_blocksize;
phys = fat_bmap(inode, iblock); err = fat_bmap(inode, iblock, &phys);
if (phys < 0) if (err)
return phys; return err;
if (!phys) if (!phys)
BUG(); BUG();
set_buffer_new(bh_result); set_buffer_new(bh_result);
......
...@@ -60,17 +60,17 @@ void fat_hash_init(void) ...@@ -60,17 +60,17 @@ void fat_hash_init(void)
} }
} }
static inline unsigned long fat_hash(struct super_block *sb, int i_pos) static inline unsigned long fat_hash(struct super_block *sb, loff_t i_pos)
{ {
unsigned long tmp = (unsigned long)i_pos | (unsigned long) sb; unsigned long tmp = (unsigned long)i_pos | (unsigned long) sb;
tmp = tmp + (tmp >> FAT_HASH_BITS) + (tmp >> FAT_HASH_BITS * 2); tmp = tmp + (tmp >> FAT_HASH_BITS) + (tmp >> FAT_HASH_BITS * 2);
return tmp & FAT_HASH_MASK; return tmp & FAT_HASH_MASK;
} }
void fat_attach(struct inode *inode, int i_pos) void fat_attach(struct inode *inode, loff_t i_pos)
{ {
spin_lock(&fat_inode_lock); spin_lock(&fat_inode_lock);
MSDOS_I(inode)->i_location = i_pos; MSDOS_I(inode)->i_pos = i_pos;
list_add(&MSDOS_I(inode)->i_fat_hash, list_add(&MSDOS_I(inode)->i_fat_hash,
fat_inode_hashtable + fat_hash(inode->i_sb, i_pos)); fat_inode_hashtable + fat_hash(inode->i_sb, i_pos));
spin_unlock(&fat_inode_lock); spin_unlock(&fat_inode_lock);
...@@ -79,12 +79,12 @@ void fat_attach(struct inode *inode, int i_pos) ...@@ -79,12 +79,12 @@ void fat_attach(struct inode *inode, int i_pos)
void fat_detach(struct inode *inode) void fat_detach(struct inode *inode)
{ {
spin_lock(&fat_inode_lock); spin_lock(&fat_inode_lock);
MSDOS_I(inode)->i_location = 0; MSDOS_I(inode)->i_pos = 0;
list_del_init(&MSDOS_I(inode)->i_fat_hash); list_del_init(&MSDOS_I(inode)->i_fat_hash);
spin_unlock(&fat_inode_lock); spin_unlock(&fat_inode_lock);
} }
struct inode *fat_iget(struct super_block *sb, int i_pos) struct inode *fat_iget(struct super_block *sb, loff_t i_pos)
{ {
struct list_head *p = fat_inode_hashtable + fat_hash(sb, i_pos); struct list_head *p = fat_inode_hashtable + fat_hash(sb, i_pos);
struct list_head *walk; struct list_head *walk;
...@@ -96,7 +96,7 @@ struct inode *fat_iget(struct super_block *sb, int i_pos) ...@@ -96,7 +96,7 @@ struct inode *fat_iget(struct super_block *sb, int i_pos)
i = list_entry(walk, struct msdos_inode_info, i_fat_hash); i = list_entry(walk, struct msdos_inode_info, i_fat_hash);
if (i->vfs_inode.i_sb != sb) if (i->vfs_inode.i_sb != sb)
continue; continue;
if (i->i_location != i_pos) if (i->i_pos != i_pos)
continue; continue;
inode = igrab(&i->vfs_inode); inode = igrab(&i->vfs_inode);
if (inode) if (inode)
...@@ -109,11 +109,11 @@ struct inode *fat_iget(struct super_block *sb, int i_pos) ...@@ -109,11 +109,11 @@ struct inode *fat_iget(struct super_block *sb, int i_pos)
static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de); static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de);
struct inode *fat_build_inode(struct super_block *sb, struct inode *fat_build_inode(struct super_block *sb,
struct msdos_dir_entry *de, int ino, int *res) struct msdos_dir_entry *de, loff_t i_pos, int *res)
{ {
struct inode *inode; struct inode *inode;
*res = 0; *res = 0;
inode = fat_iget(sb, ino); inode = fat_iget(sb, i_pos);
if (inode) if (inode)
goto out; goto out;
inode = new_inode(sb); inode = new_inode(sb);
...@@ -128,7 +128,7 @@ struct inode *fat_build_inode(struct super_block *sb, ...@@ -128,7 +128,7 @@ struct inode *fat_build_inode(struct super_block *sb,
inode = NULL; inode = NULL;
goto out; goto out;
} }
fat_attach(inode, ino); fat_attach(inode, i_pos);
insert_inode_hash(inode); insert_inode_hash(inode);
out: out:
return inode; return inode;
...@@ -500,7 +500,7 @@ static int fat_read_root(struct inode *inode) ...@@ -500,7 +500,7 @@ static int fat_read_root(struct inode *inode)
struct msdos_sb_info *sbi = MSDOS_SB(sb); struct msdos_sb_info *sbi = MSDOS_SB(sb);
int error; int error;
MSDOS_I(inode)->i_location = 0; MSDOS_I(inode)->i_pos = 0;
inode->i_uid = sbi->options.fs_uid; inode->i_uid = sbi->options.fs_uid;
inode->i_gid = sbi->options.fs_gid; inode->i_gid = sbi->options.fs_gid;
inode->i_version++; inode->i_version++;
...@@ -537,9 +537,10 @@ static int fat_read_root(struct inode *inode) ...@@ -537,9 +537,10 @@ static int fat_read_root(struct inode *inode)
* 0/ i_ino - for fast, reliable lookup if still in the cache * 0/ i_ino - for fast, reliable lookup if still in the cache
* 1/ i_generation - to see if i_ino is still valid * 1/ i_generation - to see if i_ino is still valid
* bit 0 == 0 iff directory * bit 0 == 0 iff directory
* 2/ i_location - if ino has changed, but still in cache * 2/ i_pos - if ino has changed, but still in cache (hi)
* 3/ i_logstart - to semi-verify inode found at i_location * 3/ i_pos - if ino has changed, but still in cache (low)
* 4/ parent->i_logstart - maybe used to hunt for the file on disc * 4/ i_logstart - to semi-verify inode found at i_location
* 5/ parent->i_logstart - maybe used to hunt for the file on disc
* *
*/ */
...@@ -551,7 +552,7 @@ struct dentry *fat_decode_fh(struct super_block *sb, __u32 *fh, ...@@ -551,7 +552,7 @@ struct dentry *fat_decode_fh(struct super_block *sb, __u32 *fh,
if (fhtype != 3) if (fhtype != 3)
return ERR_PTR(-ESTALE); return ERR_PTR(-ESTALE);
if (len < 5) if (len < 6)
return ERR_PTR(-ESTALE); return ERR_PTR(-ESTALE);
return sb->s_export_op->find_exported_dentry(sb, fh, NULL, acceptable, context); return sb->s_export_op->find_exported_dentry(sb, fh, NULL, acceptable, context);
...@@ -570,13 +571,15 @@ struct dentry *fat_get_dentry(struct super_block *sb, void *inump) ...@@ -570,13 +571,15 @@ struct dentry *fat_get_dentry(struct super_block *sb, void *inump)
inode = NULL; inode = NULL;
} }
if (!inode) { if (!inode) {
/* try 2 - see if i_location is in F-d-c loff_t i_pos = ((loff_t)fh[2] << 32) | fh[3];
/* try 2 - see if i_pos is in F-d-c
* require i_logstart to be the same * require i_logstart to be the same
* Will fail if you truncate and then re-write * Will fail if you truncate and then re-write
*/ */
inode = fat_iget(sb, fh[2]); inode = fat_iget(sb, i_pos);
if (inode && MSDOS_I(inode)->i_logstart != fh[3]) { if (inode && MSDOS_I(inode)->i_logstart != fh[4]) {
iput(inode); iput(inode);
inode = NULL; inode = NULL;
} }
...@@ -616,15 +619,16 @@ int fat_encode_fh(struct dentry *de, __u32 *fh, int *lenp, int connectable) ...@@ -616,15 +619,16 @@ int fat_encode_fh(struct dentry *de, __u32 *fh, int *lenp, int connectable)
int len = *lenp; int len = *lenp;
struct inode *inode = de->d_inode; struct inode *inode = de->d_inode;
if (len < 5) if (len < 6)
return 255; /* no room */ return 255; /* no room */
*lenp = 5; *lenp = 6;
fh[0] = inode->i_ino; fh[0] = inode->i_ino;
fh[1] = inode->i_generation; fh[1] = inode->i_generation;
fh[2] = MSDOS_I(inode)->i_location; fh[2] = (__u32)(MSDOS_I(inode)->i_pos >> 32);
fh[3] = MSDOS_I(inode)->i_logstart; fh[3] = (__u32)MSDOS_I(inode)->i_pos;
fh[4] = MSDOS_I(inode)->i_logstart;
spin_lock(&de->d_lock); spin_lock(&de->d_lock);
fh[4] = MSDOS_I(de->d_parent->d_inode)->i_logstart; fh[5] = MSDOS_I(de->d_parent->d_inode)->i_logstart;
spin_unlock(&de->d_lock); spin_unlock(&de->d_lock);
return 3; return 3;
} }
...@@ -635,15 +639,15 @@ struct dentry *fat_get_parent(struct dentry *child) ...@@ -635,15 +639,15 @@ struct dentry *fat_get_parent(struct dentry *child)
struct msdos_dir_entry *de = NULL; struct msdos_dir_entry *de = NULL;
struct dentry *parent = NULL; struct dentry *parent = NULL;
int res; int res;
int ino = 0; loff_t i_pos = 0;
struct inode *inode; struct inode *inode;
lock_kernel(); lock_kernel();
res = fat_scan(child->d_inode, MSDOS_DOTDOT, &bh, &de, &ino); res = fat_scan(child->d_inode, MSDOS_DOTDOT, &bh, &de, &i_pos);
if (res < 0) if (res < 0)
goto out; goto out;
inode = fat_build_inode(child->d_sb, de, ino, &res); inode = fat_build_inode(child->d_sb, de, i_pos, &res);
if (res) if (res)
goto out; goto out;
if (!inode) if (!inode)
...@@ -1098,7 +1102,7 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de) ...@@ -1098,7 +1102,7 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
struct msdos_sb_info *sbi = MSDOS_SB(sb); struct msdos_sb_info *sbi = MSDOS_SB(sb);
int error; int error;
MSDOS_I(inode)->i_location = 0; MSDOS_I(inode)->i_pos = 0;
inode->i_uid = sbi->options.fs_uid; inode->i_uid = sbi->options.fs_uid;
inode->i_gid = sbi->options.fs_gid; inode->i_gid = sbi->options.fs_gid;
inode->i_version++; inode->i_version++;
...@@ -1112,10 +1116,9 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de) ...@@ -1112,10 +1116,9 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
inode->i_fop = &fat_dir_operations; inode->i_fop = &fat_dir_operations;
MSDOS_I(inode)->i_start = CF_LE_W(de->start); MSDOS_I(inode)->i_start = CF_LE_W(de->start);
if (sbi->fat_bits == 32) { if (sbi->fat_bits == 32)
MSDOS_I(inode)->i_start |= MSDOS_I(inode)->i_start |= (CF_LE_W(de->starthi) << 16);
(CF_LE_W(de->starthi) << 16);
}
MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start; MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start;
error = fat_calc_dir_size(inode); error = fat_calc_dir_size(inode);
if (error < 0) if (error < 0)
...@@ -1131,10 +1134,9 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de) ...@@ -1131,10 +1134,9 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
? S_IRUGO|S_IWUGO : S_IRWXUGO) ? S_IRUGO|S_IWUGO : S_IRWXUGO)
& ~sbi->options.fs_fmask) | S_IFREG; & ~sbi->options.fs_fmask) | S_IFREG;
MSDOS_I(inode)->i_start = CF_LE_W(de->start); MSDOS_I(inode)->i_start = CF_LE_W(de->start);
if (sbi->fat_bits == 32) { if (sbi->fat_bits == 32)
MSDOS_I(inode)->i_start |= MSDOS_I(inode)->i_start |= (CF_LE_W(de->starthi) << 16);
(CF_LE_W(de->starthi) << 16);
}
MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start; MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start;
inode->i_size = CF_LE_L(de->size); inode->i_size = CF_LE_L(de->size);
inode->i_op = &fat_file_inode_operations; inode->i_op = &fat_file_inode_operations;
...@@ -1168,22 +1170,22 @@ void fat_write_inode(struct inode *inode, int wait) ...@@ -1168,22 +1170,22 @@ void fat_write_inode(struct inode *inode, int wait)
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
struct buffer_head *bh; struct buffer_head *bh;
struct msdos_dir_entry *raw_entry; struct msdos_dir_entry *raw_entry;
unsigned int i_pos; loff_t i_pos;
retry: retry:
i_pos = MSDOS_I(inode)->i_location; i_pos = MSDOS_I(inode)->i_pos;
if (inode->i_ino == MSDOS_ROOT_INO || !i_pos) { if (inode->i_ino == MSDOS_ROOT_INO || !i_pos) {
return; return;
} }
lock_kernel(); lock_kernel();
if (!(bh = sb_bread(sb, i_pos >> MSDOS_SB(sb)->dir_per_block_bits))) { if (!(bh = sb_bread(sb, i_pos >> MSDOS_SB(sb)->dir_per_block_bits))) {
fat_fs_panic(sb, "unable to read i-node block (ino %lu)", fat_fs_panic(sb, "unable to read i-node block (i_pos %llu)",
i_pos); i_pos);
unlock_kernel(); unlock_kernel();
return; return;
} }
spin_lock(&fat_inode_lock); spin_lock(&fat_inode_lock);
if (i_pos != MSDOS_I(inode)->i_location) { if (i_pos != MSDOS_I(inode)->i_pos) {
spin_unlock(&fat_inode_lock); spin_unlock(&fat_inode_lock);
brelse(bh); brelse(bh);
unlock_kernel(); unlock_kernel();
......
...@@ -178,9 +178,9 @@ int fat_add_cluster(struct inode *inode) ...@@ -178,9 +178,9 @@ int fat_add_cluster(struct inode *inode)
struct buffer_head *fat_extend_dir(struct inode *inode) struct buffer_head *fat_extend_dir(struct inode *inode)
{ {
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
int nr, sector, last_sector;
struct buffer_head *bh, *res = NULL; struct buffer_head *bh, *res = NULL;
int cluster_size = MSDOS_SB(sb)->cluster_size; int nr, cluster_size = MSDOS_SB(sb)->cluster_size;
sector_t sector, last_sector;
if (MSDOS_SB(sb)->fat_bits != 32) { if (MSDOS_SB(sb)->fat_bits != 32) {
if (inode->i_ino == MSDOS_ROOT_INO) if (inode->i_ino == MSDOS_ROOT_INO)
...@@ -191,7 +191,7 @@ struct buffer_head *fat_extend_dir(struct inode *inode) ...@@ -191,7 +191,7 @@ struct buffer_head *fat_extend_dir(struct inode *inode)
if (nr < 0) if (nr < 0)
return ERR_PTR(nr); return ERR_PTR(nr);
sector = MSDOS_SB(sb)->data_start + (nr - 2) * cluster_size; sector = ((sector_t)nr - 2) * cluster_size + MSDOS_SB(sb)->data_start;
last_sector = sector + cluster_size; last_sector = sector + cluster_size;
for ( ; sector < last_sector; sector++) { for ( ; sector < last_sector; sector++) {
if ((bh = sb_getblk(sb, sector))) { if ((bh = sb_getblk(sb, sector))) {
...@@ -289,11 +289,13 @@ void fat_date_unix2dos(int unix_date,unsigned short *time, ...@@ -289,11 +289,13 @@ void fat_date_unix2dos(int unix_date,unsigned short *time,
*/ */
int fat__get_entry(struct inode *dir, loff_t *pos,struct buffer_head **bh, int fat__get_entry(struct inode *dir, loff_t *pos,struct buffer_head **bh,
struct msdos_dir_entry **de, int *ino) struct msdos_dir_entry **de, loff_t *i_pos)
{ {
struct super_block *sb = dir->i_sb; struct super_block *sb = dir->i_sb;
struct msdos_sb_info *sbi = MSDOS_SB(sb); struct msdos_sb_info *sbi = MSDOS_SB(sb);
int sector, offset, iblock; sector_t phys, iblock;
loff_t offset;
int err;
next: next:
offset = *pos; offset = *pos;
...@@ -302,14 +304,14 @@ int fat__get_entry(struct inode *dir, loff_t *pos,struct buffer_head **bh, ...@@ -302,14 +304,14 @@ int fat__get_entry(struct inode *dir, loff_t *pos,struct buffer_head **bh,
*bh = NULL; *bh = NULL;
iblock = *pos >> sb->s_blocksize_bits; iblock = *pos >> sb->s_blocksize_bits;
sector = fat_bmap(dir, iblock); err = fat_bmap(dir, iblock, &phys);
if (sector <= 0) if (err || !phys)
return -1; /* beyond EOF or error */ return -1; /* beyond EOF or error */
*bh = sb_bread(sb, sector); *bh = sb_bread(sb, phys);
if (*bh == NULL) { if (*bh == NULL) {
printk(KERN_ERR "FAT: Directory bread(block %d) failed\n", printk(KERN_ERR "FAT: Directory bread(block %llu) failed\n",
sector); phys);
/* skip this block */ /* skip this block */
*pos = (iblock + 1) << sb->s_blocksize_bits; *pos = (iblock + 1) << sb->s_blocksize_bits;
goto next; goto next;
...@@ -318,7 +320,7 @@ int fat__get_entry(struct inode *dir, loff_t *pos,struct buffer_head **bh, ...@@ -318,7 +320,7 @@ int fat__get_entry(struct inode *dir, loff_t *pos,struct buffer_head **bh,
offset &= sb->s_blocksize - 1; offset &= sb->s_blocksize - 1;
*pos += sizeof(struct msdos_dir_entry); *pos += sizeof(struct msdos_dir_entry);
*de = (struct msdos_dir_entry *)((*bh)->b_data + offset); *de = (struct msdos_dir_entry *)((*bh)->b_data + offset);
*ino = (sector << sbi->dir_per_block_bits) + (offset >> MSDOS_DIR_BITS); *i_pos = ((loff_t)phys << sbi->dir_per_block_bits) + (offset >> MSDOS_DIR_BITS);
return 0; return 0;
} }
...@@ -357,7 +359,7 @@ int fat__get_entry(struct inode *dir, loff_t *pos,struct buffer_head **bh, ...@@ -357,7 +359,7 @@ int fat__get_entry(struct inode *dir, loff_t *pos,struct buffer_head **bh,
done = !IS_FREE(data[entry].name) \ done = !IS_FREE(data[entry].name) \
&& ( \ && ( \
( \ ( \
(MSDOS_SB(sb)->fat_bits != 32) ? 0 : (CF_LE_W(data[entry].starthi) << 16) \ (sbi->fat_bits != 32) ? 0 : (CF_LE_W(data[entry].starthi) << 16) \
) \ ) \
| CF_LE_W(data[entry].start) \ | CF_LE_W(data[entry].start) \
) == *number; ) == *number;
...@@ -374,35 +376,38 @@ int fat__get_entry(struct inode *dir, loff_t *pos,struct buffer_head **bh, ...@@ -374,35 +376,38 @@ int fat__get_entry(struct inode *dir, loff_t *pos,struct buffer_head **bh,
(*number)++; \ (*number)++; \
} }
static int raw_scan_sector(struct super_block *sb,int sector,const char *name, static int raw_scan_sector(struct super_block *sb, sector_t sector,
int *number,int *ino,struct buffer_head **res_bh, const char *name, int *number, loff_t *i_pos,
struct msdos_dir_entry **res_de) struct buffer_head **res_bh,
struct msdos_dir_entry **res_de)
{ {
struct msdos_sb_info *sbi = MSDOS_SB(sb);
struct buffer_head *bh; struct buffer_head *bh;
struct msdos_dir_entry *data; struct msdos_dir_entry *data;
int entry,start,done; int entry,start,done;
if (!(bh = sb_bread(sb,sector))) if (!(bh = sb_bread(sb, sector)))
return -EIO; return -EIO;
data = (struct msdos_dir_entry *) bh->b_data; data = (struct msdos_dir_entry *) bh->b_data;
for (entry = 0; entry < MSDOS_SB(sb)->dir_per_block; entry++) { for (entry = 0; entry < sbi->dir_per_block; entry++) {
/* RSS_COUNT: if (data[entry].name == name) done=true else done=false. */ /* RSS_COUNT: if (data[entry].name == name) done=true else done=false. */
if (name) { if (name) {
RSS_NAME RSS_NAME
} else { } else {
if (!ino) RSS_COUNT if (!i_pos) RSS_COUNT
else { else {
if (number) RSS_START if (number) RSS_START
else RSS_FREE else RSS_FREE
} }
} }
if (done) { if (done) {
if (ino) if (i_pos) {
*ino = sector * MSDOS_SB(sb)->dir_per_block + entry; *i_pos = ((loff_t)sector << sbi->dir_per_block_bits) + entry;
}
start = CF_LE_W(data[entry].start); start = CF_LE_W(data[entry].start);
if (MSDOS_SB(sb)->fat_bits == 32) { if (sbi->fat_bits == 32)
start |= (CF_LE_W(data[entry].starthi) << 16); start |= (CF_LE_W(data[entry].starthi) << 16);
}
if (!res_bh) if (!res_bh)
brelse(bh); brelse(bh);
else { else {
...@@ -422,16 +427,19 @@ static int raw_scan_sector(struct super_block *sb,int sector,const char *name, ...@@ -422,16 +427,19 @@ static int raw_scan_sector(struct super_block *sb,int sector,const char *name,
* requested entry is found or the end of the directory is reached. * requested entry is found or the end of the directory is reached.
*/ */
static int raw_scan_root(struct super_block *sb,const char *name,int *number,int *ino, static int raw_scan_root(struct super_block *sb, const char *name,
struct buffer_head **res_bh,struct msdos_dir_entry **res_de) int *number, loff_t *i_pos,
struct buffer_head **res_bh,
struct msdos_dir_entry **res_de)
{ {
int count,cluster; int count,cluster;
for (count = 0; for (count = 0;
count < MSDOS_SB(sb)->dir_entries / MSDOS_SB(sb)->dir_per_block; count < MSDOS_SB(sb)->dir_entries / MSDOS_SB(sb)->dir_per_block;
count++) { count++) {
if ((cluster = raw_scan_sector(sb,MSDOS_SB(sb)->dir_start+count, cluster = raw_scan_sector(sb, MSDOS_SB(sb)->dir_start + count,
name,number,ino,res_bh,res_de)) >= 0) name, number, i_pos, res_bh, res_de);
if (cluster >= 0)
return cluster; return cluster;
} }
return -ENOENT; return -ENOENT;
...@@ -443,24 +451,29 @@ static int raw_scan_root(struct super_block *sb,const char *name,int *number,int ...@@ -443,24 +451,29 @@ static int raw_scan_root(struct super_block *sb,const char *name,int *number,int
* requested entry is found or the end of the directory is reached. * requested entry is found or the end of the directory is reached.
*/ */
static int raw_scan_nonroot(struct super_block *sb,int start,const char *name, static int raw_scan_nonroot(struct super_block *sb, int start, const char *name,
int *number,int *ino,struct buffer_head **res_bh,struct msdos_dir_entry int *number, loff_t *i_pos,
**res_de) struct buffer_head **res_bh,
struct msdos_dir_entry **res_de)
{ {
struct msdos_sb_info *sbi = MSDOS_SB(sb);
int count, cluster; int count, cluster;
unsigned long dir_size = 0; unsigned long dir_size = 0;
sector_t sector;
#ifdef DEBUG #ifdef DEBUG
printk("raw_scan_nonroot: start=%d\n",start); printk("raw_scan_nonroot: start=%d\n",start);
#endif #endif
do { do {
for (count = 0; count < MSDOS_SB(sb)->cluster_size; count++) { for (count = 0; count < sbi->cluster_size; count++) {
if ((cluster = raw_scan_sector(sb,(start-2)* sector = ((sector_t)start - 2) * sbi->cluster_size
MSDOS_SB(sb)->cluster_size+MSDOS_SB(sb)->data_start+ + count + sbi->data_start;
count,name,number,ino,res_bh,res_de)) >= 0) cluster = raw_scan_sector(sb, sector, name, number,
i_pos, res_bh, res_de);
if (cluster >= 0)
return cluster; return cluster;
} }
dir_size += 1 << MSDOS_SB(sb)->cluster_bits; dir_size += 1 << sbi->cluster_bits;
if (dir_size > FAT_MAX_DIR_SIZE) { if (dir_size > FAT_MAX_DIR_SIZE) {
fat_fs_panic(sb, "Directory %d: " fat_fs_panic(sb, "Directory %d: "
"exceeded the maximum size of directory", "exceeded the maximum size of directory",
...@@ -492,13 +505,13 @@ static int raw_scan_nonroot(struct super_block *sb,int start,const char *name, ...@@ -492,13 +505,13 @@ static int raw_scan_nonroot(struct super_block *sb,int start,const char *name,
*/ */
static int raw_scan(struct super_block *sb, int start, const char *name, static int raw_scan(struct super_block *sb, int start, const char *name,
int *number, int *ino, struct buffer_head **res_bh, loff_t *i_pos, struct buffer_head **res_bh,
struct msdos_dir_entry **res_de) struct msdos_dir_entry **res_de)
{ {
if (start) if (start)
return raw_scan_nonroot(sb,start,name,number,ino,res_bh,res_de); return raw_scan_nonroot(sb,start,name,NULL,i_pos,res_bh,res_de);
else else
return raw_scan_root(sb,name,number,ino,res_bh,res_de); return raw_scan_root(sb,name,NULL,i_pos,res_bh,res_de);
} }
/* /*
...@@ -507,19 +520,21 @@ static int raw_scan(struct super_block *sb, int start, const char *name, ...@@ -507,19 +520,21 @@ static int raw_scan(struct super_block *sb, int start, const char *name,
*/ */
int fat_subdirs(struct inode *dir) int fat_subdirs(struct inode *dir)
{ {
int count; struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb);
int number;
count = 0; number = 0;
if ((dir->i_ino == MSDOS_ROOT_INO) && if ((dir->i_ino == MSDOS_ROOT_INO) && (sbi->fat_bits != 32))
(MSDOS_SB(dir->i_sb)->fat_bits != 32)) { raw_scan_root(dir->i_sb, NULL, &number, NULL, NULL, NULL);
(void) raw_scan_root(dir->i_sb,NULL,&count,NULL,NULL,NULL); else {
} else { if ((dir->i_ino != MSDOS_ROOT_INO) && !MSDOS_I(dir)->i_start)
if ((dir->i_ino != MSDOS_ROOT_INO) && return 0; /* in mkdir */
!MSDOS_I(dir)->i_start) return 0; /* in mkdir */ else {
else (void) raw_scan_nonroot(dir->i_sb,MSDOS_I(dir)->i_start, raw_scan_nonroot(dir->i_sb, MSDOS_I(dir)->i_start,
NULL,&count,NULL,NULL,NULL); NULL, &number, NULL, NULL, NULL);
}
} }
return count; return number;
} }
...@@ -528,12 +543,12 @@ int fat_subdirs(struct inode *dir) ...@@ -528,12 +543,12 @@ int fat_subdirs(struct inode *dir)
* for an empty directory slot (name is NULL). Returns an error code or zero. * for an empty directory slot (name is NULL). Returns an error code or zero.
*/ */
int fat_scan(struct inode *dir,const char *name,struct buffer_head **res_bh, int fat_scan(struct inode *dir, const char *name, struct buffer_head **res_bh,
struct msdos_dir_entry **res_de,int *ino) struct msdos_dir_entry **res_de, loff_t *i_pos)
{ {
int res; int res;
res = raw_scan(dir->i_sb,MSDOS_I(dir)->i_start, res = raw_scan(dir->i_sb, MSDOS_I(dir)->i_start, name, i_pos,
name, NULL, ino, res_bh, res_de); res_bh, res_de);
return res<0 ? res : 0; return (res < 0) ? res : 0;
} }
...@@ -112,8 +112,9 @@ static int msdos_format_name(const char *name,int len, ...@@ -112,8 +112,9 @@ static int msdos_format_name(const char *name,int len,
} }
/***** Locates a directory entry. Uses unformatted name. */ /***** Locates a directory entry. Uses unformatted name. */
static int msdos_find(struct inode *dir,const char *name,int len, static int msdos_find(struct inode *dir, const char *name, int len,
struct buffer_head **bh,struct msdos_dir_entry **de,int *ino) struct buffer_head **bh, struct msdos_dir_entry **de,
loff_t *i_pos)
{ {
int res; int res;
char dotsOK; char dotsOK;
...@@ -123,7 +124,7 @@ static int msdos_find(struct inode *dir,const char *name,int len, ...@@ -123,7 +124,7 @@ static int msdos_find(struct inode *dir,const char *name,int len,
res = msdos_format_name(name,len, msdos_name,&MSDOS_SB(dir->i_sb)->options); res = msdos_format_name(name,len, msdos_name,&MSDOS_SB(dir->i_sb)->options);
if (res < 0) if (res < 0)
return -ENOENT; return -ENOENT;
res = fat_scan(dir,msdos_name,bh,de,ino); res = fat_scan(dir, msdos_name, bh, de, i_pos);
if (!res && dotsOK) { if (!res && dotsOK) {
if (name[0]=='.') { if (name[0]=='.') {
if (!((*de)->attr & ATTR_HIDDEN)) if (!((*de)->attr & ATTR_HIDDEN))
...@@ -134,7 +135,6 @@ static int msdos_find(struct inode *dir,const char *name,int len, ...@@ -134,7 +135,6 @@ static int msdos_find(struct inode *dir,const char *name,int len,
} }
} }
return res; return res;
} }
/* /*
...@@ -199,19 +199,19 @@ struct dentry *msdos_lookup(struct inode *dir,struct dentry *dentry) ...@@ -199,19 +199,19 @@ struct dentry *msdos_lookup(struct inode *dir,struct dentry *dentry)
struct inode *inode = NULL; struct inode *inode = NULL;
struct msdos_dir_entry *de; struct msdos_dir_entry *de;
struct buffer_head *bh = NULL; struct buffer_head *bh = NULL;
int ino,res; loff_t i_pos;
int res;
dentry->d_op = &msdos_dentry_operations; dentry->d_op = &msdos_dentry_operations;
lock_kernel(); lock_kernel();
res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &bh, res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &bh,
&de, &ino); &de, &i_pos);
if (res == -ENOENT) if (res == -ENOENT)
goto add; goto add;
if (res < 0) if (res < 0)
goto out; goto out;
inode = fat_build_inode(sb, de, ino, &res); inode = fat_build_inode(sb, de, i_pos, &res);
if (res) if (res)
goto out; goto out;
add: add:
...@@ -231,12 +231,11 @@ struct dentry *msdos_lookup(struct inode *dir,struct dentry *dentry) ...@@ -231,12 +231,11 @@ struct dentry *msdos_lookup(struct inode *dir,struct dentry *dentry)
static int msdos_add_entry(struct inode *dir, const char *name, static int msdos_add_entry(struct inode *dir, const char *name,
struct buffer_head **bh, struct buffer_head **bh,
struct msdos_dir_entry **de, struct msdos_dir_entry **de,
int *ino, loff_t *i_pos, int is_dir, int is_hid)
int is_dir, int is_hid)
{ {
int res; int res;
res = fat_add_entries(dir, 1, bh, de, ino); res = fat_add_entries(dir, 1, bh, de, i_pos);
if (res < 0) if (res < 0)
return res; return res;
...@@ -268,7 +267,8 @@ int msdos_create(struct inode *dir,struct dentry *dentry,int mode) ...@@ -268,7 +267,8 @@ int msdos_create(struct inode *dir,struct dentry *dentry,int mode)
struct buffer_head *bh; struct buffer_head *bh;
struct msdos_dir_entry *de; struct msdos_dir_entry *de;
struct inode *inode; struct inode *inode;
int ino,res,is_hid; loff_t i_pos;
int res, is_hid;
char msdos_name[MSDOS_NAME]; char msdos_name[MSDOS_NAME];
lock_kernel(); lock_kernel();
...@@ -280,18 +280,18 @@ int msdos_create(struct inode *dir,struct dentry *dentry,int mode) ...@@ -280,18 +280,18 @@ int msdos_create(struct inode *dir,struct dentry *dentry,int mode)
} }
is_hid = (dentry->d_name.name[0]=='.') && (msdos_name[0]!='.'); is_hid = (dentry->d_name.name[0]=='.') && (msdos_name[0]!='.');
/* Have to do it due to foo vs. .foo conflicts */ /* Have to do it due to foo vs. .foo conflicts */
if (fat_scan(dir,msdos_name,&bh,&de,&ino) >= 0) { if (fat_scan(dir, msdos_name, &bh, &de, &i_pos) >= 0) {
brelse(bh); brelse(bh);
unlock_kernel(); unlock_kernel();
return -EINVAL; return -EINVAL;
} }
inode = NULL; inode = NULL;
res = msdos_add_entry(dir, msdos_name, &bh, &de, &ino, 0, is_hid); res = msdos_add_entry(dir, msdos_name, &bh, &de, &i_pos, 0, is_hid);
if (res) { if (res) {
unlock_kernel(); unlock_kernel();
return res; return res;
} }
inode = fat_build_inode(dir->i_sb, de, ino, &res); inode = fat_build_inode(dir->i_sb, de, i_pos, &res);
brelse(bh); brelse(bh);
if (!inode) { if (!inode) {
unlock_kernel(); unlock_kernel();
...@@ -308,14 +308,15 @@ int msdos_create(struct inode *dir,struct dentry *dentry,int mode) ...@@ -308,14 +308,15 @@ int msdos_create(struct inode *dir,struct dentry *dentry,int mode)
int msdos_rmdir(struct inode *dir, struct dentry *dentry) int msdos_rmdir(struct inode *dir, struct dentry *dentry)
{ {
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
int res,ino; loff_t i_pos;
int res;
struct buffer_head *bh; struct buffer_head *bh;
struct msdos_dir_entry *de; struct msdos_dir_entry *de;
bh = NULL; bh = NULL;
lock_kernel(); lock_kernel();
res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len,
&bh, &de, &ino); &bh, &de, &i_pos);
if (res < 0) if (res < 0)
goto rmdir_done; goto rmdir_done;
/* /*
...@@ -351,7 +352,7 @@ int msdos_mkdir(struct inode *dir,struct dentry *dentry,int mode) ...@@ -351,7 +352,7 @@ int msdos_mkdir(struct inode *dir,struct dentry *dentry,int mode)
struct inode *inode; struct inode *inode;
int res,is_hid; int res,is_hid;
char msdos_name[MSDOS_NAME]; char msdos_name[MSDOS_NAME];
int ino; loff_t i_pos;
lock_kernel(); lock_kernel();
res = msdos_format_name(dentry->d_name.name,dentry->d_name.len, res = msdos_format_name(dentry->d_name.name,dentry->d_name.len,
...@@ -362,13 +363,13 @@ int msdos_mkdir(struct inode *dir,struct dentry *dentry,int mode) ...@@ -362,13 +363,13 @@ int msdos_mkdir(struct inode *dir,struct dentry *dentry,int mode)
} }
is_hid = (dentry->d_name.name[0]=='.') && (msdos_name[0]!='.'); is_hid = (dentry->d_name.name[0]=='.') && (msdos_name[0]!='.');
/* foo vs .foo situation */ /* foo vs .foo situation */
if (fat_scan(dir,msdos_name,&bh,&de,&ino) >= 0) if (fat_scan(dir, msdos_name, &bh, &de, &i_pos) >= 0)
goto out_exist; goto out_exist;
res = msdos_add_entry(dir, msdos_name, &bh, &de, &ino, 1, is_hid); res = msdos_add_entry(dir, msdos_name, &bh, &de, &i_pos, 1, is_hid);
if (res) if (res)
goto out_unlock; goto out_unlock;
inode = fat_build_inode(dir->i_sb, de, ino, &res); inode = fat_build_inode(dir->i_sb, de, i_pos, &res);
if (!inode) { if (!inode) {
brelse(bh); brelse(bh);
goto out_unlock; goto out_unlock;
...@@ -414,14 +415,15 @@ int msdos_mkdir(struct inode *dir,struct dentry *dentry,int mode) ...@@ -414,14 +415,15 @@ int msdos_mkdir(struct inode *dir,struct dentry *dentry,int mode)
int msdos_unlink( struct inode *dir, struct dentry *dentry) int msdos_unlink( struct inode *dir, struct dentry *dentry)
{ {
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
int res,ino; loff_t i_pos;
int res;
struct buffer_head *bh; struct buffer_head *bh;
struct msdos_dir_entry *de; struct msdos_dir_entry *de;
bh = NULL; bh = NULL;
lock_kernel(); lock_kernel();
res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len,
&bh, &de, &ino); &bh, &de, &i_pos);
if (res < 0) if (res < 0)
goto unlink_done; goto unlink_done;
...@@ -443,12 +445,12 @@ static int do_msdos_rename(struct inode *old_dir, char *old_name, ...@@ -443,12 +445,12 @@ static int do_msdos_rename(struct inode *old_dir, char *old_name,
struct dentry *old_dentry, struct dentry *old_dentry,
struct inode *new_dir,char *new_name, struct dentry *new_dentry, struct inode *new_dir,char *new_name, struct dentry *new_dentry,
struct buffer_head *old_bh, struct buffer_head *old_bh,
struct msdos_dir_entry *old_de, int old_ino, int is_hid) struct msdos_dir_entry *old_de, loff_t old_i_pos, int is_hid)
{ {
struct buffer_head *new_bh=NULL,*dotdot_bh=NULL; struct buffer_head *new_bh=NULL,*dotdot_bh=NULL;
struct msdos_dir_entry *new_de,*dotdot_de; struct msdos_dir_entry *new_de,*dotdot_de;
struct inode *old_inode,*new_inode; struct inode *old_inode,*new_inode;
int new_ino,dotdot_ino; loff_t new_i_pos, dotdot_i_pos;
int error; int error;
int is_dir; int is_dir;
...@@ -456,7 +458,8 @@ static int do_msdos_rename(struct inode *old_dir, char *old_name, ...@@ -456,7 +458,8 @@ static int do_msdos_rename(struct inode *old_dir, char *old_name,
new_inode = new_dentry->d_inode; new_inode = new_dentry->d_inode;
is_dir = S_ISDIR(old_inode->i_mode); is_dir = S_ISDIR(old_inode->i_mode);
if (fat_scan(new_dir,new_name,&new_bh,&new_de,&new_ino)>=0 &&!new_inode) if (fat_scan(new_dir, new_name, &new_bh, &new_de, &new_i_pos) >= 0
&& !new_inode)
goto degenerate_case; goto degenerate_case;
if (is_dir) { if (is_dir) {
if (new_inode) { if (new_inode) {
...@@ -465,7 +468,7 @@ static int do_msdos_rename(struct inode *old_dir, char *old_name, ...@@ -465,7 +468,7 @@ static int do_msdos_rename(struct inode *old_dir, char *old_name,
goto out; goto out;
} }
error = fat_scan(old_inode, MSDOS_DOTDOT, &dotdot_bh, error = fat_scan(old_inode, MSDOS_DOTDOT, &dotdot_bh,
&dotdot_de, &dotdot_ino); &dotdot_de, &dotdot_i_pos);
if (error < 0) { if (error < 0) {
printk(KERN_WARNING printk(KERN_WARNING
"MSDOS: %s/%s, get dotdot failed, ret=%d\n", "MSDOS: %s/%s, get dotdot failed, ret=%d\n",
...@@ -476,7 +479,7 @@ static int do_msdos_rename(struct inode *old_dir, char *old_name, ...@@ -476,7 +479,7 @@ static int do_msdos_rename(struct inode *old_dir, char *old_name,
} }
if (!new_bh) { if (!new_bh) {
error = msdos_add_entry(new_dir, new_name, &new_bh, &new_de, error = msdos_add_entry(new_dir, new_name, &new_bh, &new_de,
&new_ino, is_dir, is_hid); &new_i_pos, is_dir, is_hid);
if (error) if (error)
goto out; goto out;
} }
...@@ -489,7 +492,7 @@ static int do_msdos_rename(struct inode *old_dir, char *old_name, ...@@ -489,7 +492,7 @@ static int do_msdos_rename(struct inode *old_dir, char *old_name,
old_de->name[0] = DELETED_FLAG; old_de->name[0] = DELETED_FLAG;
mark_buffer_dirty(old_bh); mark_buffer_dirty(old_bh);
fat_detach(old_inode); fat_detach(old_inode);
fat_attach(old_inode, new_ino); fat_attach(old_inode, new_i_pos);
if (is_hid) if (is_hid)
MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN; MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
else else
...@@ -544,8 +547,8 @@ int msdos_rename(struct inode *old_dir,struct dentry *old_dentry, ...@@ -544,8 +547,8 @@ int msdos_rename(struct inode *old_dir,struct dentry *old_dentry,
{ {
struct buffer_head *old_bh; struct buffer_head *old_bh;
struct msdos_dir_entry *old_de; struct msdos_dir_entry *old_de;
int old_ino, error; loff_t old_i_pos;
int is_hid,old_hid; /* if new file and old file are hidden */ int error, is_hid, old_hid; /* if new file and old file are hidden */
char old_msdos_name[MSDOS_NAME], new_msdos_name[MSDOS_NAME]; char old_msdos_name[MSDOS_NAME], new_msdos_name[MSDOS_NAME];
lock_kernel(); lock_kernel();
...@@ -562,13 +565,13 @@ int msdos_rename(struct inode *old_dir,struct dentry *old_dentry, ...@@ -562,13 +565,13 @@ int msdos_rename(struct inode *old_dir,struct dentry *old_dentry,
is_hid = (new_dentry->d_name.name[0]=='.') && (new_msdos_name[0]!='.'); is_hid = (new_dentry->d_name.name[0]=='.') && (new_msdos_name[0]!='.');
old_hid = (old_dentry->d_name.name[0]=='.') && (old_msdos_name[0]!='.'); old_hid = (old_dentry->d_name.name[0]=='.') && (old_msdos_name[0]!='.');
error = fat_scan(old_dir, old_msdos_name, &old_bh, &old_de, &old_ino); error = fat_scan(old_dir, old_msdos_name, &old_bh, &old_de, &old_i_pos);
if (error < 0) if (error < 0)
goto rename_done; goto rename_done;
error = do_msdos_rename(old_dir, old_msdos_name, old_dentry, error = do_msdos_rename(old_dir, old_msdos_name, old_dentry,
new_dir, new_msdos_name, new_dentry, new_dir, new_msdos_name, new_dentry,
old_bh, old_de, (ino_t)old_ino, is_hid); old_bh, old_de, old_i_pos, is_hid);
brelse(old_bh); brelse(old_bh);
rename_done: rename_done:
......
...@@ -317,9 +317,10 @@ static int vfat_find_form(struct inode *dir,char *name) ...@@ -317,9 +317,10 @@ static int vfat_find_form(struct inode *dir,char *name)
{ {
struct msdos_dir_entry *de; struct msdos_dir_entry *de;
struct buffer_head *bh = NULL; struct buffer_head *bh = NULL;
int ino,res; loff_t i_pos;
int res;
res = fat_scan(dir,name,&bh,&de,&ino); res = fat_scan(dir, name, &bh, &de, &i_pos);
brelse(bh); brelse(bh);
if (res < 0) if (res < 0)
return -ENOENT; return -ENOENT;
...@@ -781,7 +782,7 @@ static int vfat_add_entry(struct inode *dir,struct qstr* qname, ...@@ -781,7 +782,7 @@ static int vfat_add_entry(struct inode *dir,struct qstr* qname,
int res, len; int res, len;
struct msdos_dir_entry *dummy_de; struct msdos_dir_entry *dummy_de;
struct buffer_head *dummy_bh; struct buffer_head *dummy_bh;
int dummy_ino; loff_t dummy_i_pos;
dir_slots = (struct msdos_dir_slot *) dir_slots = (struct msdos_dir_slot *)
kmalloc(sizeof(struct msdos_dir_slot) * MSDOS_SLOTS, GFP_KERNEL); kmalloc(sizeof(struct msdos_dir_slot) * MSDOS_SLOTS, GFP_KERNEL);
...@@ -797,7 +798,7 @@ static int vfat_add_entry(struct inode *dir,struct qstr* qname, ...@@ -797,7 +798,7 @@ static int vfat_add_entry(struct inode *dir,struct qstr* qname,
goto cleanup; goto cleanup;
/* build the empty directory entry of number of slots */ /* build the empty directory entry of number of slots */
offset = fat_add_entries(dir, slots, &dummy_bh, &dummy_de, &dummy_ino); offset = fat_add_entries(dir, slots, &dummy_bh, &dummy_de, &dummy_i_pos);
if (offset < 0) { if (offset < 0) {
res = offset; res = offset;
goto cleanup; goto cleanup;
...@@ -807,7 +808,7 @@ static int vfat_add_entry(struct inode *dir,struct qstr* qname, ...@@ -807,7 +808,7 @@ static int vfat_add_entry(struct inode *dir,struct qstr* qname,
/* Now create the new entry */ /* Now create the new entry */
*bh = NULL; *bh = NULL;
for (slot = 0; slot < slots; slot++) { for (slot = 0; slot < slots; slot++) {
if (fat_get_entry(dir, &offset, bh, de, &sinfo_out->ino) < 0) { if (fat_get_entry(dir, &offset, bh, de, &sinfo_out->i_pos) < 0) {
res = -EIO; res = -EIO;
goto cleanup; goto cleanup;
} }
...@@ -852,7 +853,7 @@ static int vfat_find(struct inode *dir,struct qstr* qname, ...@@ -852,7 +853,7 @@ static int vfat_find(struct inode *dir,struct qstr* qname,
&offset,&sinfo->longname_offset); &offset,&sinfo->longname_offset);
if (res>0) { if (res>0) {
sinfo->long_slots = res-1; sinfo->long_slots = res-1;
if (fat_get_entry(dir,&offset,last_bh,last_de,&sinfo->ino)>=0) if (fat_get_entry(dir,&offset,last_bh,last_de,&sinfo->i_pos)>=0)
return 0; return 0;
res = -EIO; res = -EIO;
} }
...@@ -882,7 +883,7 @@ struct dentry *vfat_lookup(struct inode *dir,struct dentry *dentry) ...@@ -882,7 +883,7 @@ struct dentry *vfat_lookup(struct inode *dir,struct dentry *dentry)
table++; table++;
goto error; goto error;
} }
inode = fat_build_inode(dir->i_sb, de, sinfo.ino, &res); inode = fat_build_inode(dir->i_sb, de, sinfo.i_pos, &res);
brelse(bh); brelse(bh);
if (res) { if (res) {
unlock_kernel(); unlock_kernel();
...@@ -926,7 +927,7 @@ int vfat_create(struct inode *dir,struct dentry* dentry,int mode) ...@@ -926,7 +927,7 @@ int vfat_create(struct inode *dir,struct dentry* dentry,int mode)
unlock_kernel(); unlock_kernel();
return res; return res;
} }
inode = fat_build_inode(sb, de, sinfo.ino, &res); inode = fat_build_inode(sb, de, sinfo.i_pos, &res);
brelse(bh); brelse(bh);
if (!inode) { if (!inode) {
unlock_kernel(); unlock_kernel();
...@@ -945,8 +946,8 @@ int vfat_create(struct inode *dir,struct dentry* dentry,int mode) ...@@ -945,8 +946,8 @@ int vfat_create(struct inode *dir,struct dentry* dentry,int mode)
static void vfat_remove_entry(struct inode *dir,struct vfat_slot_info *sinfo, static void vfat_remove_entry(struct inode *dir,struct vfat_slot_info *sinfo,
struct buffer_head *bh, struct msdos_dir_entry *de) struct buffer_head *bh, struct msdos_dir_entry *de)
{ {
loff_t offset; loff_t offset, i_pos;
int i,ino; int i;
/* remove the shortname */ /* remove the shortname */
dir->i_mtime = CURRENT_TIME; dir->i_mtime = CURRENT_TIME;
...@@ -958,7 +959,7 @@ static void vfat_remove_entry(struct inode *dir,struct vfat_slot_info *sinfo, ...@@ -958,7 +959,7 @@ static void vfat_remove_entry(struct inode *dir,struct vfat_slot_info *sinfo,
/* remove the longname */ /* remove the longname */
offset = sinfo->longname_offset; de = NULL; offset = sinfo->longname_offset; de = NULL;
for (i = sinfo->long_slots; i > 0; --i) { for (i = sinfo->long_slots; i > 0; --i) {
if (fat_get_entry(dir, &offset, &bh, &de, &ino) < 0) if (fat_get_entry(dir, &offset, &bh, &de, &i_pos) < 0)
continue; continue;
de->name[0] = DELETED_FLAG; de->name[0] = DELETED_FLAG;
de->attr = ATTR_NONE; de->attr = ATTR_NONE;
...@@ -1040,7 +1041,7 @@ int vfat_mkdir(struct inode *dir,struct dentry* dentry,int mode) ...@@ -1040,7 +1041,7 @@ int vfat_mkdir(struct inode *dir,struct dentry* dentry,int mode)
unlock_kernel(); unlock_kernel();
return res; return res;
} }
inode = fat_build_inode(sb, de, sinfo.ino, &res); inode = fat_build_inode(sb, de, sinfo.i_pos, &res);
if (!inode) if (!inode)
goto out; goto out;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
...@@ -1078,7 +1079,7 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry, ...@@ -1078,7 +1079,7 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
{ {
struct buffer_head *old_bh,*new_bh,*dotdot_bh; struct buffer_head *old_bh,*new_bh,*dotdot_bh;
struct msdos_dir_entry *old_de,*new_de,*dotdot_de; struct msdos_dir_entry *old_de,*new_de,*dotdot_de;
int dotdot_ino; loff_t dotdot_i_pos;
struct inode *old_inode, *new_inode; struct inode *old_inode, *new_inode;
int res, is_dir; int res, is_dir;
struct vfat_slot_info old_sinfo,sinfo; struct vfat_slot_info old_sinfo,sinfo;
...@@ -1094,13 +1095,13 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry, ...@@ -1094,13 +1095,13 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
is_dir = S_ISDIR(old_inode->i_mode); is_dir = S_ISDIR(old_inode->i_mode);
if (is_dir && (res = fat_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh, if (is_dir && (res = fat_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh,
&dotdot_de,&dotdot_ino)) < 0) &dotdot_de,&dotdot_i_pos)) < 0)
goto rename_done; goto rename_done;
if (new_dentry->d_inode) { if (new_dentry->d_inode) {
res = vfat_find(new_dir,&new_dentry->d_name,&sinfo,&new_bh, res = vfat_find(new_dir,&new_dentry->d_name,&sinfo,&new_bh,
&new_de); &new_de);
if (res < 0 || MSDOS_I(new_inode)->i_location != sinfo.ino) { if (res < 0 || MSDOS_I(new_inode)->i_pos != sinfo.i_pos) {
/* WTF??? Cry and fail. */ /* WTF??? Cry and fail. */
printk(KERN_WARNING "vfat_rename: fs corrupted\n"); printk(KERN_WARNING "vfat_rename: fs corrupted\n");
goto rename_done; goto rename_done;
...@@ -1124,7 +1125,7 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry, ...@@ -1124,7 +1125,7 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
vfat_remove_entry(old_dir,&old_sinfo,old_bh,old_de); vfat_remove_entry(old_dir,&old_sinfo,old_bh,old_de);
old_bh=NULL; old_bh=NULL;
fat_detach(old_inode); fat_detach(old_inode);
fat_attach(old_inode, sinfo.ino); fat_attach(old_inode, sinfo.i_pos);
mark_inode_dirty(old_inode); mark_inode_dirty(old_inode);
old_dir->i_version++; old_dir->i_version++;
......
...@@ -178,7 +178,7 @@ struct msdos_dir_slot { ...@@ -178,7 +178,7 @@ struct msdos_dir_slot {
struct vfat_slot_info { struct vfat_slot_info {
int long_slots; /* number of long slots in filename */ int long_slots; /* number of long slots in filename */
loff_t longname_offset; /* dir offset for longname start */ loff_t longname_offset; /* dir offset for longname start */
int ino; /* ino for the file */ loff_t i_pos; /* on-disk position of directory entry */
}; };
/* Convert attribute bits and a mask to the UNIX mode. */ /* Convert attribute bits and a mask to the UNIX mode. */
...@@ -241,7 +241,7 @@ static inline void fatwchar_to16(__u8 *dst, const wchar_t *src, size_t len) ...@@ -241,7 +241,7 @@ static inline void fatwchar_to16(__u8 *dst, const wchar_t *src, size_t len)
/* fat/cache.c */ /* fat/cache.c */
extern int fat_access(struct super_block *sb, int nr, int new_value); extern int fat_access(struct super_block *sb, int nr, int new_value);
extern int __fat_access(struct super_block *sb, int nr, int new_value); extern int __fat_access(struct super_block *sb, int nr, int new_value);
extern int fat_bmap(struct inode *inode, int sector); extern int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys);
extern void fat_cache_init(void); extern void fat_cache_init(void);
extern void fat_cache_lookup(struct inode *inode, int cluster, int *f_clu, extern void fat_cache_lookup(struct inode *inode, int cluster, int *f_clu,
int *d_clu); int *d_clu);
...@@ -259,7 +259,7 @@ extern int fat_dir_ioctl(struct inode * inode, struct file * filp, ...@@ -259,7 +259,7 @@ extern int fat_dir_ioctl(struct inode * inode, struct file * filp,
unsigned int cmd, unsigned long arg); unsigned int cmd, unsigned long arg);
extern int fat_dir_empty(struct inode *dir); extern int fat_dir_empty(struct inode *dir);
extern int fat_add_entries(struct inode *dir, int slots, struct buffer_head **bh, extern int fat_add_entries(struct inode *dir, int slots, struct buffer_head **bh,
struct msdos_dir_entry **de, int *ino); struct msdos_dir_entry **de, loff_t *i_pos);
extern int fat_new_dir(struct inode *dir, struct inode *parent, int is_vfat); extern int fat_new_dir(struct inode *dir, struct inode *parent, int is_vfat);
/* fat/file.c */ /* fat/file.c */
...@@ -271,11 +271,11 @@ extern void fat_truncate(struct inode *inode); ...@@ -271,11 +271,11 @@ extern void fat_truncate(struct inode *inode);
/* fat/inode.c */ /* fat/inode.c */
extern void fat_hash_init(void); extern void fat_hash_init(void);
extern void fat_attach(struct inode *inode, int i_pos); extern void fat_attach(struct inode *inode, loff_t i_pos);
extern void fat_detach(struct inode *inode); extern void fat_detach(struct inode *inode);
extern struct inode *fat_iget(struct super_block *sb, int i_pos); extern struct inode *fat_iget(struct super_block *sb, loff_t i_pos);
extern struct inode *fat_build_inode(struct super_block *sb, extern struct inode *fat_build_inode(struct super_block *sb,
struct msdos_dir_entry *de, int ino, int *res); struct msdos_dir_entry *de, loff_t i_pos, int *res);
extern void fat_delete_inode(struct inode *inode); extern void fat_delete_inode(struct inode *inode);
extern void fat_clear_inode(struct inode *inode); extern void fat_clear_inode(struct inode *inode);
extern void fat_put_super(struct super_block *sb); extern void fat_put_super(struct super_block *sb);
...@@ -295,26 +295,27 @@ extern struct buffer_head *fat_extend_dir(struct inode *inode); ...@@ -295,26 +295,27 @@ extern struct buffer_head *fat_extend_dir(struct inode *inode);
extern int date_dos2unix(unsigned short time, unsigned short date); extern int date_dos2unix(unsigned short time, unsigned short date);
extern void fat_date_unix2dos(int unix_date, unsigned short *time, extern void fat_date_unix2dos(int unix_date, unsigned short *time,
unsigned short *date); unsigned short *date);
extern int fat__get_entry(struct inode *dir, loff_t *pos, struct buffer_head **bh, extern int fat__get_entry(struct inode *dir, loff_t *pos,
struct msdos_dir_entry **de, int *ino); struct buffer_head **bh,
struct msdos_dir_entry **de, loff_t *i_pos);
static __inline__ int fat_get_entry(struct inode *dir, loff_t *pos, static __inline__ int fat_get_entry(struct inode *dir, loff_t *pos,
struct buffer_head **bh, struct buffer_head **bh,
struct msdos_dir_entry **de, int *ino) struct msdos_dir_entry **de, loff_t *i_pos)
{ {
/* Fast stuff first */ /* Fast stuff first */
if (*bh && *de && if (*bh && *de &&
(*de - (struct msdos_dir_entry *)(*bh)->b_data) < MSDOS_SB(dir->i_sb)->dir_per_block - 1) { (*de - (struct msdos_dir_entry *)(*bh)->b_data) < MSDOS_SB(dir->i_sb)->dir_per_block - 1) {
*pos += sizeof(struct msdos_dir_entry); *pos += sizeof(struct msdos_dir_entry);
(*de)++; (*de)++;
(*ino)++; (*i_pos)++;
return 0; return 0;
} }
return fat__get_entry(dir,pos,bh,de,ino); return fat__get_entry(dir, pos, bh, de, i_pos);
} }
extern int fat_subdirs(struct inode *dir); extern int fat_subdirs(struct inode *dir);
extern int fat_scan(struct inode *dir, const char *name, extern int fat_scan(struct inode *dir, const char *name,
struct buffer_head **res_bh, struct buffer_head **res_bh,
struct msdos_dir_entry **res_de, int *ino); struct msdos_dir_entry **res_de, loff_t *i_pos);
/* msdos/namei.c - these are for Umsdos */ /* msdos/namei.c - these are for Umsdos */
extern struct dentry *msdos_lookup(struct inode *dir, struct dentry *); extern struct dentry *msdos_lookup(struct inode *dir, struct dentry *);
......
...@@ -13,7 +13,7 @@ struct msdos_inode_info { ...@@ -13,7 +13,7 @@ struct msdos_inode_info {
int i_logstart; /* logical first cluster */ int i_logstart; /* logical first cluster */
int i_attrs; /* unused attribute bits */ int i_attrs; /* unused attribute bits */
int i_ctime_ms; /* unused change time in milliseconds */ int i_ctime_ms; /* unused change time in milliseconds */
int i_location; /* on-disk position of directory entry or 0 */ loff_t i_pos; /* on-disk position of directory entry or 0 */
struct list_head i_fat_hash; /* hash by i_location */ struct list_head i_fat_hash; /* hash by i_location */
struct inode vfs_inode; struct inode vfs_inode;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment