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.


 25-akpm/fs/fat/inode.c           |    1 +
 25-akpm/fs/fat/misc.c            |   17 +++++++++++------
 25-akpm/include/linux/msdos_fs.h |    3 +--
 3 files changed, 13 insertions(+), 8 deletions(-)

diff -puN fs/fat/inode.c~fat-speedup fs/fat/inode.c
--- 25/fs/fat/inode.c~fat-speedup	Wed Apr 23 14:11:03 2003
+++ 25-akpm/fs/fat/inode.c	Wed Apr 23 14:11:03 2003
@@ -897,6 +897,7 @@ int fat_fill_super(struct super_block *s
 			       sbi->fsinfo_sector);
 		} else {
 			sbi->free_clusters = CF_LE_L(fsinfo->free_clusters);
+			sbi->prev_free = CF_LE_L(fsinfo->next_cluster);
 		}
 
 		brelse(fsinfo_bh);
diff -puN fs/fat/misc.c~fat-speedup fs/fat/misc.c
--- 25/fs/fat/misc.c~fat-speedup	Wed Apr 23 14:11:03 2003
+++ 25-akpm/fs/fat/misc.c	Wed Apr 23 14:11:03 2003
@@ -74,6 +74,7 @@ void fat_clusters_flush(struct super_blo
 		       MSDOS_SB(sb)->fsinfo_sector);
 	} else {
 		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);
 	}
 	brelse(bh);
@@ -130,19 +131,23 @@ int fat_add_cluster(struct inode *inode)
 		unlock_fat(sb);
 		return -ENOSPC;
 	}
-	limit = MSDOS_SB(sb)->clusters;
-	for (count = 0; count < limit; count++) {
-		nr = ((count + MSDOS_SB(sb)->prev_free) % limit) + 2;
+
+	limit = MSDOS_SB(sb)->clusters + 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)
 			break;
 	}
-	if (count >= limit) {
+	if (count >= MSDOS_SB(sb)->clusters) {
 		MSDOS_SB(sb)->free_clusters = 0;
 		unlock_fat(sb);
 		return -ENOSPC;
 	}
-	
-	MSDOS_SB(sb)->prev_free = (count + MSDOS_SB(sb)->prev_free + 1) % limit;
+	MSDOS_SB(sb)->prev_free = nr;
+
 	fat_access(sb, nr, FAT_ENT_EOF);
 	if (MSDOS_SB(sb)->free_clusters != -1)
 		MSDOS_SB(sb)->free_clusters--;
diff -puN include/linux/msdos_fs.h~fat-speedup include/linux/msdos_fs.h
--- 25/include/linux/msdos_fs.h~fat-speedup	Wed Apr 23 14:11:03 2003
+++ 25-akpm/include/linux/msdos_fs.h	Wed Apr 23 14:11:03 2003
@@ -146,8 +146,7 @@ struct fat_boot_fsinfo {
 	__u32   reserved1[120];	/* Nothing as far as I can tell */
 	__u32   signature2;	/* 0x61417272L */
 	__u32   free_clusters;	/* Free cluster count.  -1 if unknown */
-	__u32   next_cluster;	/* Most recently allocated cluster.
-				 * Unused under Linux. */
+	__u32   next_cluster;	/* Most recently allocated cluster */
 	__u32   reserved2[4];
 };
 

_