[PATCH 10/29] FAT: Add fat_remove_entries()
From: OGAWA Hirofumi
Date: Sat Mar 05 2005 - 14:50:08 EST
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: OGAWA Hirofumi <hirofumi@xxxxxxxxxxxxxxxxxx>
---
fs/fat/dir.c | 103 +++++++++++++++++++++++++++++++++++++++++++----
fs/vfat/namei.c | 81 ++++++++++++------------------------
include/linux/msdos_fs.h | 1
3 files changed, 124 insertions(+), 61 deletions(-)
diff -puN fs/fat/dir.c~sync06-fat_dir-cleanup3 fs/fat/dir.c
--- linux-2.6.11/fs/fat/dir.c~sync06-fat_dir-cleanup3 2005-03-06 02:36:28.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/dir.c 2005-03-06 02:36:29.000000000 +0900
@@ -144,7 +144,7 @@ int fat_search_long(struct inode *inode,
struct nls_table *nls_io = MSDOS_SB(sb)->nls_io;
struct nls_table *nls_disk = MSDOS_SB(sb)->nls_disk;
wchar_t bufuname[14];
- unsigned char xlate_len, long_slots;
+ unsigned char xlate_len, nr_slots;
wchar_t *unicode = NULL;
unsigned char work[8], bufname[260]; /* 256 + 4 */
int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
@@ -159,7 +159,7 @@ int fat_search_long(struct inode *inode,
if (fat_get_entry(inode, &cpos, &bh, &de, &i_pos) == -1)
goto EODir;
parse_record:
- long_slots = 0;
+ nr_slots = 0;
if (de->name[0] == DELETED_FLAG)
continue;
if (de->attr != ATTR_EXT && (de->attr & ATTR_VOLUME))
@@ -191,7 +191,7 @@ parse_long:
slots = id & ~0x40;
if (slots > 20 || !slots) /* ceil(256 * 2 / 26) */
continue;
- long_slots = slots;
+ nr_slots = slots;
alias_checksum = ds->alias_checksum;
slot = slots;
@@ -228,7 +228,7 @@ parse_long:
for (sum = 0, i = 0; i < 11; i++)
sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->name[i];
if (sum != alias_checksum)
- long_slots = 0;
+ nr_slots = 0;
}
memcpy(work, de->name, sizeof(de->name));
@@ -276,7 +276,7 @@ parse_long:
xlate_len)))
goto Found;
- if (long_slots) {
+ if (nr_slots) {
xlate_len = utf8
?utf8_wcstombs(bufname, unicode, sizeof(bufname))
:uni16_to_x8(bufname, unicode, uni_xlate, nls_io);
@@ -290,9 +290,10 @@ parse_long:
}
Found:
+ nr_slots++; /* include the de */
sinfo->i_pos = i_pos;
- sinfo->slot_off = cpos - (long_slots + 1) * sizeof(*de);
- sinfo->nr_slots = long_slots;
+ sinfo->slot_off = cpos - nr_slots * sizeof(*de);
+ sinfo->nr_slots = nr_slots;
sinfo->de = de;
sinfo->bh = bh;
err = 0;
@@ -759,6 +760,94 @@ int fat_scan(struct inode *dir, const un
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)
{
struct super_block *sb = inode->i_sb;
diff -puN fs/vfat/namei.c~sync06-fat_dir-cleanup3 fs/vfat/namei.c
--- linux-2.6.11/fs/vfat/namei.c~sync06-fat_dir-cleanup3 2005-03-06 02:36:28.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/vfat/namei.c 2005-03-06 02:36:29.000000000 +0900
@@ -721,7 +721,7 @@ static int vfat_add_entry(struct inode *
/* slots can't be less than 1 */
sinfo->slot_off = offset - sizeof(struct msdos_dir_slot) * slots;
- sinfo->nr_slots = slots - 1;
+ sinfo->nr_slots = slots;
sinfo->de = de;
sinfo->bh = bh;
@@ -817,39 +817,6 @@ out:
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)
{
struct inode *inode = dentry->d_inode;
@@ -865,14 +832,15 @@ static int vfat_rmdir(struct inode *dir,
if (err)
goto out;
+ err = fat_remove_entries(dir, &sinfo); /* and releases bh */
+ if (err)
+ goto out;
+ dir->i_nlink--;
+
inode->i_nlink = 0;
inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
fat_detach(inode);
mark_inode_dirty(inode);
- /* releases bh and syncs it if necessary */
- vfat_remove_entry(dir, &sinfo);
-
- dir->i_nlink--;
out:
unlock_kernel();
@@ -891,12 +859,13 @@ static int vfat_unlink(struct inode *dir
if (err)
goto out;
+ err = fat_remove_entries(dir, &sinfo); /* and releases bh */
+ if (err)
+ goto out;
inode->i_nlink = 0;
inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
fat_detach(inode);
mark_inode_dirty(inode);
- /* releases bh and syncs it if necessary */
- vfat_remove_entry(dir, &sinfo);
out:
unlock_kernel();
@@ -939,8 +908,7 @@ mkdir_failed:
inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
fat_detach(inode);
mark_inode_dirty(inode);
- /* releases bh ands syncs if necessary */
- vfat_remove_entry(dir, &sinfo);
+ fat_remove_entries(dir, &sinfo); /* and releases bh */
iput(inode);
dir->i_nlink--;
goto out;
@@ -956,49 +924,56 @@ static int vfat_rename(struct inode *old
int err, is_dir;
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;
new_inode = new_dentry->d_inode;
lock_kernel();
err = vfat_find(old_dir, &old_dentry->d_name, &old_sinfo);
if (err)
- goto rename_done;
+ goto out;
is_dir = S_ISDIR(old_inode->i_mode);
if (is_dir) {
if (fat_scan(old_inode, MSDOS_DOTDOT, &dotdot_bh,
&dotdot_de, &dotdot_i_pos) < 0) {
err = -EIO;
- goto rename_done;
+ goto out;
}
}
if (new_dentry->d_inode) {
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. */
printk(KERN_WARNING "vfat_rename: fs corrupted\n");
- goto rename_done;
+ goto out;
}
if (is_dir) {
err = fat_dir_empty(new_inode);
if (err)
- goto rename_done;
+ goto out;
}
fat_detach(new_inode);
} else {
err = vfat_add_entry(new_dir, &new_dentry->d_name, is_dir,
&sinfo);
if (err)
- goto rename_done;
+ goto out;
+ brelse(sinfo.bh);
}
-
new_dir->i_version++;
/* 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;
+ if (err)
+ goto out;
+ if (is_dir)
+ old_dir->i_nlink--;
fat_detach(old_inode);
fat_attach(old_inode, sinfo.i_pos);
mark_inode_dirty(old_inode);
@@ -1019,7 +994,6 @@ static int vfat_rename(struct inode *old
if (new_dir->i_sb->s_flags & MS_SYNCHRONOUS)
sync_dirty_buffer(dotdot_bh);
- old_dir->i_nlink--;
if (new_inode) {
new_inode->i_nlink--;
} else {
@@ -1027,10 +1001,9 @@ static int vfat_rename(struct inode *old
mark_inode_dirty(new_dir);
}
}
-rename_done:
+out:
brelse(dotdot_bh);
brelse(old_sinfo.bh);
- brelse(sinfo.bh);
unlock_kernel();
return err;
diff -puN include/linux/msdos_fs.h~sync06-fat_dir-cleanup3 include/linux/msdos_fs.h
--- linux-2.6.11/include/linux/msdos_fs.h~sync06-fat_dir-cleanup3 2005-03-06 02:36:28.000000000 +0900
+++ linux-2.6.11-hirofumi/include/linux/msdos_fs.h 2005-03-06 02:36:29.000000000 +0900
@@ -333,6 +333,7 @@ extern int fat_subdirs(struct inode *dir
extern int fat_scan(struct inode *dir, const unsigned char *name,
struct buffer_head **res_bh,
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 */
struct fat_entry {
_
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/