Commit 8b59d996 authored by Hirofumi Ogawa's avatar Hirofumi Ogawa Committed by Linus Torvalds

[PATCH] FAT: Add fat_remove_entries()

This changes the fat_slot_info->nr_slot, now it's total counts which
include a shortname entry.  And this adds a fat_remove_entries()
which use the ->nr_slots.

In order not to write out the same block repeatedly,
fat_remove_entries() was rewritten from vfat_remove_entries().
Signed-off-by: default avatarOGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent ae4dc6df
...@@ -144,7 +144,7 @@ int fat_search_long(struct inode *inode, const unsigned char *name, ...@@ -144,7 +144,7 @@ int fat_search_long(struct inode *inode, const unsigned char *name,
struct nls_table *nls_io = MSDOS_SB(sb)->nls_io; struct nls_table *nls_io = MSDOS_SB(sb)->nls_io;
struct nls_table *nls_disk = MSDOS_SB(sb)->nls_disk; struct nls_table *nls_disk = MSDOS_SB(sb)->nls_disk;
wchar_t bufuname[14]; wchar_t bufuname[14];
unsigned char xlate_len, long_slots; unsigned char xlate_len, nr_slots;
wchar_t *unicode = NULL; wchar_t *unicode = NULL;
unsigned char work[8], bufname[260]; /* 256 + 4 */ unsigned char work[8], bufname[260]; /* 256 + 4 */
int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate; int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
...@@ -159,7 +159,7 @@ int fat_search_long(struct inode *inode, const unsigned char *name, ...@@ -159,7 +159,7 @@ int fat_search_long(struct inode *inode, const unsigned char *name,
if (fat_get_entry(inode, &cpos, &bh, &de, &i_pos) == -1) if (fat_get_entry(inode, &cpos, &bh, &de, &i_pos) == -1)
goto EODir; goto EODir;
parse_record: parse_record:
long_slots = 0; nr_slots = 0;
if (de->name[0] == DELETED_FLAG) if (de->name[0] == DELETED_FLAG)
continue; continue;
if (de->attr != ATTR_EXT && (de->attr & ATTR_VOLUME)) if (de->attr != ATTR_EXT && (de->attr & ATTR_VOLUME))
...@@ -191,7 +191,7 @@ int fat_search_long(struct inode *inode, const unsigned char *name, ...@@ -191,7 +191,7 @@ int fat_search_long(struct inode *inode, const unsigned char *name,
slots = id & ~0x40; slots = id & ~0x40;
if (slots > 20 || !slots) /* ceil(256 * 2 / 26) */ if (slots > 20 || !slots) /* ceil(256 * 2 / 26) */
continue; continue;
long_slots = slots; nr_slots = slots;
alias_checksum = ds->alias_checksum; alias_checksum = ds->alias_checksum;
slot = slots; slot = slots;
...@@ -228,7 +228,7 @@ int fat_search_long(struct inode *inode, const unsigned char *name, ...@@ -228,7 +228,7 @@ int fat_search_long(struct inode *inode, const unsigned char *name,
for (sum = 0, i = 0; i < 11; i++) for (sum = 0, i = 0; i < 11; i++)
sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->name[i]; sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->name[i];
if (sum != alias_checksum) if (sum != alias_checksum)
long_slots = 0; nr_slots = 0;
} }
memcpy(work, de->name, sizeof(de->name)); memcpy(work, de->name, sizeof(de->name));
...@@ -276,7 +276,7 @@ int fat_search_long(struct inode *inode, const unsigned char *name, ...@@ -276,7 +276,7 @@ int fat_search_long(struct inode *inode, const unsigned char *name,
xlate_len))) xlate_len)))
goto Found; goto Found;
if (long_slots) { if (nr_slots) {
xlate_len = utf8 xlate_len = utf8
?utf8_wcstombs(bufname, unicode, sizeof(bufname)) ?utf8_wcstombs(bufname, unicode, sizeof(bufname))
:uni16_to_x8(bufname, unicode, uni_xlate, nls_io); :uni16_to_x8(bufname, unicode, uni_xlate, nls_io);
...@@ -290,9 +290,10 @@ int fat_search_long(struct inode *inode, const unsigned char *name, ...@@ -290,9 +290,10 @@ int fat_search_long(struct inode *inode, const unsigned char *name,
} }
Found: Found:
nr_slots++; /* include the de */
sinfo->i_pos = i_pos; sinfo->i_pos = i_pos;
sinfo->slot_off = cpos - (long_slots + 1) * sizeof(*de); sinfo->slot_off = cpos - nr_slots * sizeof(*de);
sinfo->nr_slots = long_slots; sinfo->nr_slots = nr_slots;
sinfo->de = de; sinfo->de = de;
sinfo->bh = bh; sinfo->bh = bh;
err = 0; err = 0;
...@@ -759,6 +760,94 @@ int fat_scan(struct inode *dir, const unsigned char *name, ...@@ -759,6 +760,94 @@ int fat_scan(struct inode *dir, const unsigned char *name,
EXPORT_SYMBOL(fat_scan); EXPORT_SYMBOL(fat_scan);
static int __fat_remove_entries(struct inode *dir, loff_t pos, int nr_slots)
{
struct super_block *sb = dir->i_sb;
struct buffer_head *bh;
struct msdos_dir_entry *de, *endp;
loff_t i_pos;
int err = 0, orig_slots;
while (nr_slots) {
bh = NULL;
if (fat_get_entry(dir, &pos, &bh, &de, &i_pos) < 0) {
err = -EIO;
break;
}
orig_slots = nr_slots;
endp = (struct msdos_dir_entry *)(bh->b_data + sb->s_blocksize);
while (nr_slots && de < endp) {
de->name[0] = DELETED_FLAG;
de++;
nr_slots--;
}
mark_buffer_dirty(bh);
if (IS_DIRSYNC(dir))
err = sync_dirty_buffer(bh);
brelse(bh);
if (err)
break;
/* pos is *next* de's position, so this does `- sizeof(de)' */
pos += ((orig_slots - nr_slots) * sizeof(*de)) - sizeof(*de);
}
return err;
}
int fat_remove_entries(struct inode *dir, struct fat_slot_info *sinfo)
{
struct msdos_dir_entry *de;
struct buffer_head *bh;
int err = 0, nr_slots;
/*
* First stage: Remove the shortname. By this, the directory
* entry is removed.
*/
nr_slots = sinfo->nr_slots;
de = sinfo->de;
sinfo->de = NULL;
bh = sinfo->bh;
sinfo->bh = NULL;
while (nr_slots && de >= (struct msdos_dir_entry *)bh->b_data) {
de->name[0] = DELETED_FLAG;
de--;
nr_slots--;
}
mark_buffer_dirty(bh);
if (IS_DIRSYNC(dir))
err = sync_dirty_buffer(bh);
brelse(bh);
if (err)
return err;
dir->i_version++;
if (nr_slots) {
/*
* Second stage: remove the remaining longname slots.
* (This directory entry is already removed, and so return
* the success)
*/
err = __fat_remove_entries(dir, sinfo->slot_off, nr_slots);
if (err) {
printk(KERN_WARNING
"FAT: Couldn't remove the long name slots\n");
}
}
dir->i_mtime = dir->i_atime = CURRENT_TIME_SEC;
if (IS_DIRSYNC(dir))
(void)fat_sync_inode(dir);
else
mark_inode_dirty(dir);
return 0;
}
EXPORT_SYMBOL(fat_remove_entries);
static struct buffer_head *fat_extend_dir(struct inode *inode) static struct buffer_head *fat_extend_dir(struct inode *inode)
{ {
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
......
...@@ -721,7 +721,7 @@ static int vfat_add_entry(struct inode *dir, struct qstr *qname, ...@@ -721,7 +721,7 @@ static int vfat_add_entry(struct inode *dir, struct qstr *qname,
/* slots can't be less than 1 */ /* slots can't be less than 1 */
sinfo->slot_off = offset - sizeof(struct msdos_dir_slot) * slots; sinfo->slot_off = offset - sizeof(struct msdos_dir_slot) * slots;
sinfo->nr_slots = slots - 1; sinfo->nr_slots = slots;
sinfo->de = de; sinfo->de = de;
sinfo->bh = bh; sinfo->bh = bh;
...@@ -817,39 +817,6 @@ static int vfat_create(struct inode *dir, struct dentry *dentry, int mode, ...@@ -817,39 +817,6 @@ static int vfat_create(struct inode *dir, struct dentry *dentry, int mode,
return res; return res;
} }
static void vfat_remove_entry(struct inode *dir, struct fat_slot_info *sinfo)
{
struct super_block *sb = dir->i_sb;
struct msdos_dir_entry *de = sinfo->de;
struct buffer_head *bh = sinfo->bh;
loff_t offset, i_pos;
int i;
dir->i_mtime = dir->i_atime = CURRENT_TIME_SEC;
dir->i_version++;
mark_inode_dirty(dir);
/* remove the shortname */
de->name[0] = DELETED_FLAG;
mark_buffer_dirty(bh);
if (sb->s_flags & MS_SYNCHRONOUS)
sync_dirty_buffer(bh);
/* remove the longname */
offset = sinfo->slot_off;
de = NULL;
for (i = sinfo->nr_slots; i > 0; --i) {
if (fat_get_entry(dir, &offset, &bh, &de, &i_pos) < 0)
continue;
de->name[0] = DELETED_FLAG;
de->attr = ATTR_NONE;
mark_buffer_dirty(bh);
if (sb->s_flags & MS_SYNCHRONOUS)
sync_dirty_buffer(bh);
}
brelse(bh);
}
static int vfat_rmdir(struct inode *dir, struct dentry *dentry) static int vfat_rmdir(struct inode *dir, struct dentry *dentry)
{ {
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
...@@ -865,14 +832,15 @@ static int vfat_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -865,14 +832,15 @@ static int vfat_rmdir(struct inode *dir, struct dentry *dentry)
if (err) if (err)
goto out; goto out;
err = fat_remove_entries(dir, &sinfo); /* and releases bh */
if (err)
goto out;
dir->i_nlink--;
inode->i_nlink = 0; inode->i_nlink = 0;
inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC; inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
fat_detach(inode); fat_detach(inode);
mark_inode_dirty(inode); mark_inode_dirty(inode);
/* releases bh and syncs it if necessary */
vfat_remove_entry(dir, &sinfo);
dir->i_nlink--;
out: out:
unlock_kernel(); unlock_kernel();
...@@ -891,12 +859,13 @@ static int vfat_unlink(struct inode *dir, struct dentry *dentry) ...@@ -891,12 +859,13 @@ static int vfat_unlink(struct inode *dir, struct dentry *dentry)
if (err) if (err)
goto out; goto out;
err = fat_remove_entries(dir, &sinfo); /* and releases bh */
if (err)
goto out;
inode->i_nlink = 0; inode->i_nlink = 0;
inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC; inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
fat_detach(inode); fat_detach(inode);
mark_inode_dirty(inode); mark_inode_dirty(inode);
/* releases bh and syncs it if necessary */
vfat_remove_entry(dir, &sinfo);
out: out:
unlock_kernel(); unlock_kernel();
...@@ -939,8 +908,7 @@ static int vfat_mkdir(struct inode *dir, struct dentry *dentry, int mode) ...@@ -939,8 +908,7 @@ static int vfat_mkdir(struct inode *dir, struct dentry *dentry, int mode)
inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC; inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
fat_detach(inode); fat_detach(inode);
mark_inode_dirty(inode); mark_inode_dirty(inode);
/* releases bh ands syncs if necessary */ fat_remove_entries(dir, &sinfo); /* and releases bh */
vfat_remove_entry(dir, &sinfo);
iput(inode); iput(inode);
dir->i_nlink--; dir->i_nlink--;
goto out; goto out;
...@@ -956,49 +924,56 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -956,49 +924,56 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
int err, is_dir; int err, is_dir;
struct fat_slot_info old_sinfo, sinfo; struct fat_slot_info old_sinfo, sinfo;
old_sinfo.bh = sinfo.bh = dotdot_bh = NULL; old_sinfo.bh = dotdot_bh = NULL;
old_inode = old_dentry->d_inode; old_inode = old_dentry->d_inode;
new_inode = new_dentry->d_inode; new_inode = new_dentry->d_inode;
lock_kernel(); lock_kernel();
err = vfat_find(old_dir, &old_dentry->d_name, &old_sinfo); err = vfat_find(old_dir, &old_dentry->d_name, &old_sinfo);
if (err) if (err)
goto rename_done; goto out;
is_dir = S_ISDIR(old_inode->i_mode); is_dir = S_ISDIR(old_inode->i_mode);
if (is_dir) { if (is_dir) {
if (fat_scan(old_inode, MSDOS_DOTDOT, &dotdot_bh, if (fat_scan(old_inode, MSDOS_DOTDOT, &dotdot_bh,
&dotdot_de, &dotdot_i_pos) < 0) { &dotdot_de, &dotdot_i_pos) < 0) {
err = -EIO; err = -EIO;
goto rename_done; goto out;
} }
} }
if (new_dentry->d_inode) { if (new_dentry->d_inode) {
err = vfat_find(new_dir, &new_dentry->d_name, &sinfo); err = vfat_find(new_dir, &new_dentry->d_name, &sinfo);
if (err || MSDOS_I(new_inode)->i_pos != sinfo.i_pos) { if (err)
goto out;
brelse(sinfo.bh);
if (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 out;
} }
if (is_dir) { if (is_dir) {
err = fat_dir_empty(new_inode); err = fat_dir_empty(new_inode);
if (err) if (err)
goto rename_done; goto out;
} }
fat_detach(new_inode); fat_detach(new_inode);
} else { } else {
err = vfat_add_entry(new_dir, &new_dentry->d_name, is_dir, err = vfat_add_entry(new_dir, &new_dentry->d_name, is_dir,
&sinfo); &sinfo);
if (err) if (err)
goto rename_done; goto out;
brelse(sinfo.bh);
} }
new_dir->i_version++; new_dir->i_version++;
/* releases old_bh */ /* releases old_bh */
vfat_remove_entry(old_dir, &old_sinfo); err = fat_remove_entries(old_dir, &old_sinfo); /* and releases bh */
old_sinfo.bh = NULL; old_sinfo.bh = NULL;
if (err)
goto out;
if (is_dir)
old_dir->i_nlink--;
fat_detach(old_inode); fat_detach(old_inode);
fat_attach(old_inode, sinfo.i_pos); fat_attach(old_inode, sinfo.i_pos);
mark_inode_dirty(old_inode); mark_inode_dirty(old_inode);
...@@ -1019,7 +994,6 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1019,7 +994,6 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
if (new_dir->i_sb->s_flags & MS_SYNCHRONOUS) if (new_dir->i_sb->s_flags & MS_SYNCHRONOUS)
sync_dirty_buffer(dotdot_bh); sync_dirty_buffer(dotdot_bh);
old_dir->i_nlink--;
if (new_inode) { if (new_inode) {
new_inode->i_nlink--; new_inode->i_nlink--;
} else { } else {
...@@ -1027,10 +1001,9 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1027,10 +1001,9 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
mark_inode_dirty(new_dir); mark_inode_dirty(new_dir);
} }
} }
rename_done: out:
brelse(dotdot_bh); brelse(dotdot_bh);
brelse(old_sinfo.bh); brelse(old_sinfo.bh);
brelse(sinfo.bh);
unlock_kernel(); unlock_kernel();
return err; return err;
......
...@@ -333,6 +333,7 @@ extern int fat_subdirs(struct inode *dir); ...@@ -333,6 +333,7 @@ extern int fat_subdirs(struct inode *dir);
extern int fat_scan(struct inode *dir, const unsigned char *name, extern int fat_scan(struct inode *dir, const unsigned char *name,
struct buffer_head **res_bh, struct buffer_head **res_bh,
struct msdos_dir_entry **res_de, loff_t *i_pos); struct msdos_dir_entry **res_de, loff_t *i_pos);
extern int fat_remove_entries(struct inode *dir, struct fat_slot_info *sinfo);
/* fat/fatent.c */ /* fat/fatent.c */
struct fat_entry { struct fat_entry {
......
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