Commit a3db5a33 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] fat cluster search speedup

From: Bjorn Stenberg <bjorn@haxx.se>
      OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>

This simple patch makes the linux fat filesystem driver use the
next_cluster field in the fat_boot_fsinfo structure.  This field is a hint
where to start looking for free clusters.

Using this field makes a big difference for disks connected over slow links
such as USB 1.1.  Finding the first free cluster on a 40gig fat-formatted
usb disk can today take several minutes.  This patch cuts it down to a
fraction of a second.

Also, commit the next_cluster search hint toand from the superblock in
write_super/fill_super.
parent 7058e439
...@@ -897,6 +897,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, ...@@ -897,6 +897,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent,
sbi->fsinfo_sector); sbi->fsinfo_sector);
} else { } else {
sbi->free_clusters = CF_LE_L(fsinfo->free_clusters); sbi->free_clusters = CF_LE_L(fsinfo->free_clusters);
sbi->prev_free = CF_LE_L(fsinfo->next_cluster);
} }
brelse(fsinfo_bh); brelse(fsinfo_bh);
......
...@@ -74,6 +74,7 @@ void fat_clusters_flush(struct super_block *sb) ...@@ -74,6 +74,7 @@ void fat_clusters_flush(struct super_block *sb)
MSDOS_SB(sb)->fsinfo_sector); MSDOS_SB(sb)->fsinfo_sector);
} else { } else {
fsinfo->free_clusters = CF_LE_L(MSDOS_SB(sb)->free_clusters); fsinfo->free_clusters = CF_LE_L(MSDOS_SB(sb)->free_clusters);
fsinfo->next_cluster = CF_LE_L(MSDOS_SB(sb)->prev_free);
mark_buffer_dirty(bh); mark_buffer_dirty(bh);
} }
brelse(bh); brelse(bh);
...@@ -130,19 +131,23 @@ int fat_add_cluster(struct inode *inode) ...@@ -130,19 +131,23 @@ int fat_add_cluster(struct inode *inode)
unlock_fat(sb); unlock_fat(sb);
return -ENOSPC; return -ENOSPC;
} }
limit = MSDOS_SB(sb)->clusters;
for (count = 0; count < limit; count++) { limit = MSDOS_SB(sb)->clusters + 2;
nr = ((count + MSDOS_SB(sb)->prev_free) % limit) + 2; nr = MSDOS_SB(sb)->prev_free + 1;
for (count = 0; count < MSDOS_SB(sb)->clusters; count++, nr++) {
nr = nr % limit;
if (nr < 2)
nr = 2;
if (fat_access(sb, nr, -1) == FAT_ENT_FREE) if (fat_access(sb, nr, -1) == FAT_ENT_FREE)
break; break;
} }
if (count >= limit) { if (count >= MSDOS_SB(sb)->clusters) {
MSDOS_SB(sb)->free_clusters = 0; MSDOS_SB(sb)->free_clusters = 0;
unlock_fat(sb); unlock_fat(sb);
return -ENOSPC; return -ENOSPC;
} }
MSDOS_SB(sb)->prev_free = nr;
MSDOS_SB(sb)->prev_free = (count + MSDOS_SB(sb)->prev_free + 1) % limit;
fat_access(sb, nr, FAT_ENT_EOF); fat_access(sb, nr, FAT_ENT_EOF);
if (MSDOS_SB(sb)->free_clusters != -1) if (MSDOS_SB(sb)->free_clusters != -1)
MSDOS_SB(sb)->free_clusters--; MSDOS_SB(sb)->free_clusters--;
......
...@@ -146,8 +146,7 @@ struct fat_boot_fsinfo { ...@@ -146,8 +146,7 @@ struct fat_boot_fsinfo {
__u32 reserved1[120]; /* Nothing as far as I can tell */ __u32 reserved1[120]; /* Nothing as far as I can tell */
__u32 signature2; /* 0x61417272L */ __u32 signature2; /* 0x61417272L */
__u32 free_clusters; /* Free cluster count. -1 if unknown */ __u32 free_clusters; /* Free cluster count. -1 if unknown */
__u32 next_cluster; /* Most recently allocated cluster. __u32 next_cluster; /* Most recently allocated cluster */
* Unused under Linux. */
__u32 reserved2[4]; __u32 reserved2[4];
}; };
......
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