Alexander Polakov <polac...@gmail.com> wrote: >This is a diff from NetBSD pr.34583: >http://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=34583 > >Quoting the author: > > "I noticed that when writing large file (hundreds of megabytes) > to an msdos disk, the writing speed to a file decreases with the > file length. > Since I have some experience with messydos filesystems (I wrote > MSH: for the Amiga) I took a look. > The obvious suspicion with operations that slow down with the > length of a file is an excessive traversal of the FAT cluster > chain. However, there is a cache that caches 2 positions: the > last cluster in the file, and the "most recently looked up" one. > Debugging info showed however that frequent full traversals were > still made. So, apparently when extending a file and after > updating the end cluster, the previous end is again needed. > Adding a 3rd entry in the cache, which keeps the end position > from just before extending a file. > This has the desired effect of keeping the write speed constant. > (What it is that needs that position I have not been able to > ascertain from the filesystem code; it doesn't seem to make > sense, actually, to read or write clusters before the original > EOF. I was hoping to find the place where the cache is trashed > and rewrite it to get the desired info from it beforehand, so > that the extra cache entry is again unneeded, but alas.)" > >While there, I changed 0 to NULL for two pointer arguments of >extendfile(). > >Index: sys/msdosfs/denode.h >=================================================================== >RCS file: /cvs/src/sys/msdosfs/denode.h,v >retrieving revision 1.23 >diff -u -p -u -r1.23 denode.h >--- sys/msdosfs/denode.h 17 Jul 2010 19:27:07 -0000 1.23 >+++ sys/msdosfs/denode.h 1 Apr 2012 14:27:48 -0000 >@@ -116,10 +116,11 @@ struct fatcache { > * cache is probably pretty worthless if a file is opened by multiple > * processes. > */ >-#define FC_SIZE 2 /* number of entries in the cache */ >+#define FC_SIZE 3 /* number of entries in the cache */ > #define FC_LASTMAP 0 /* entry the last call to pcbmap() > resolved > * to */ > #define FC_LASTFC 1 /* entry for the last cluster in the > file */ >+#define FC_NEXTTOLASTFC 2 /* entry for a close to the last >cluster in >the file */ > >#define FCE_EMPTY 0xffffffff /* doesn't represent an actual >cluster # >*/ > >@@ -130,6 +131,12 @@ struct fatcache { > (dep)->de_fc[slot].fc_frcn = frcn; \ > (dep)->de_fc[slot].fc_fsrcn = fsrcn; > >+#define fc_last_to_nexttolast(dep) \ >+ do { \ >+ (dep)->de_fc[FC_NEXTTOLASTFC].fc_frcn = >(dep)->de_fc[FC_LASTFC].fc_frcn; \ >+ (dep)->de_fc[FC_NEXTTOLASTFC].fc_fsrcn = >(dep)->de_fc[FC_LASTFC].fc_fsrcn; \ >+ } while (0) >+ > /* >* This is the in memory variant of a dos directory entry. It is >usually > * contained within a vnode. >Index: sys/msdosfs/msdosfs_fat.c >=================================================================== >RCS file: /cvs/src/sys/msdosfs/msdosfs_fat.c,v >retrieving revision 1.22 >diff -u -p -u -r1.22 msdosfs_fat.c >--- sys/msdosfs/msdosfs_fat.c 4 Jul 2011 04:30:41 -0000 1.22 >+++ sys/msdosfs/msdosfs_fat.c 1 Apr 2012 14:27:49 -0000 >@@ -952,6 +952,8 @@ extendfile(struct denode *dep, uint32_t > return (error); > } > >+ fc_last_to_nexttolast(dep); >+ > while (count > 0) { > /* > * Allocate a new cluster chain and cat onto the end of the >Index: sys/msdosfs/msdosfs_lookup.c >=================================================================== >RCS file: /cvs/src/sys/msdosfs/msdosfs_lookup.c,v >retrieving revision 1.24 >diff -u -p -u -r1.24 msdosfs_lookup.c >--- sys/msdosfs/msdosfs_lookup.c 4 Jul 2011 04:30:41 -0000 1.24 >+++ sys/msdosfs/msdosfs_lookup.c 1 Apr 2012 14:27:49 -0000 >@@ -620,8 +620,9 @@ createde(struct denode *dep, struct deno > diroffset = ddep->de_fndoffset + sizeof(struct direntry) > - ddep->de_FileSize; > dirclust = de_clcount(pmp, diroffset); >- if ((error = extendfile(ddep, dirclust, 0, 0, DE_CLEAR)) != 0) { >- (void)detrunc(ddep, ddep->de_FileSize, 0, NOCRED, NULL); >+ error = extendfile(ddep, dirclust, NULL, NULL, DE_CLEAR); >+ if (error) { >+ (void) detrunc(ddep, ddep->de_FileSize, 0, NOCRED, >NULL); > return error; > } > >tests: > >w/o the patch: > time cp huge.file /mnt/storage/ > 4m5.87s real 0m0.04s user 0m17.56s system > >w/the patch: > time cp huge.file /mnt/storage/ > 2m22.48s real 0m0.02s user 0m45.30s system > >-- >Alexander Polakov | plhk.ru
Just curious; how huge is that file? /Alexander