Patch for 2.1.75 vfat memory leak and speedup patch

Gordon Chaffee (chaffee@quimby.cs.berkeley.edu)
Mon, 22 Dec 1997 02:06:30 -0800 (PST)


First, I'd like to thank Ingo Molnar and Michael Galbraith for the
excellent work on the memleak patch. I've suspected a leak in vfat
in the recent kernels, so I ran a memleak detecting kernel. After
a few untars of the Linux kernel, it showed up very nicely. One
case didn't go through the proper cleanup so some kmalloced memory
did not get freed.

I also noticed some pretty hideous performance in certain cases in vfat.
Basically, if you have lots of filenames with a common base, vfat needs to
create unique short aliases. It was doing a sequential search with
the same beginning point each time, so by the time you got to the 400th
entry with the same base filename, each file creation would take a second
or two as it tried kept checking the same files over and over and over
again.

I'd also like to put a vote of confidence in Michael Chastain's Smart
Config patch. I'm no longer deathly afraid of rerunning a config
after I've built a kernel. I used to avoid rerunning a config like
the plague since I new everything would get rebuilt. Now, it reconfig
and rebuild is a painless process.

- Gordon

--- /home/zeego/users/chaffee/downloads/linux/linux-2.1/linux-2.1.75-clean/fs/vfat/namei.c Sun Dec 21 21:46:51 1997
+++ /home/zeego/users/chaffee/downloads/linux/linux-2.1/linux/fs/vfat/namei.c Mon Dec 22 01:47:40 1997
@@ -649,29 +649,55 @@
qname.len=totlen;
res = vfat_find(dir, &qname, 0, 0, 0, &sinfo);
}
- i = 0;
- while (res > -1) {
- /* Create the next shortname to try */
- i++;
- if (i == 10000000) return -EEXIST;
- sprintf(buf, "%d", i);
- sz = strlen(buf);
- if (sz + 1 > spaces) {
- baselen = baselen - (sz + 1 - spaces);
- spaces = sz + 1;
- }
-
- strncpy(msdos_name, base, baselen);
- msdos_name[baselen] = '~';
- strcpy(&msdos_name[baselen+1], buf);
- msdos_name[baselen+sz+1] = '.';
- strcpy(&msdos_name[baselen+sz+2], ext);

- totlen = baselen + sz + 1 + extlen + (extlen > 0);
+ if (res > -1) {
+ /*
+ * Try to find a unique extension. This used to
+ * iterate through all possibilities sequentially,
+ * but that gave extremely bad performance. Windows
+ * only tries a few cases before using random
+ * values for part of the base.
+ */
+
+ if (2 > spaces) {
+ baselen = baselen - (2 - spaces);
+ spaces = 2;
+ }
+ msdos_name[baselen] = '~';
+ msdos_name[baselen+2] = '.';
+ strcpy(&msdos_name[baselen+3], ext);
+ totlen = baselen + 2 + extlen + (extlen > 0);
qname.name=msdos_name;
qname.len=totlen;
- res = vfat_find(dir, &qname, 0, 0, 0, &sinfo);
+ for (i = 1; res > -1 && i < 10; i++) {
+ strncpy(msdos_name, base, baselen);
+ msdos_name[baselen+1] = i + '0';
+ res = vfat_find(dir, &qname, 0, 0, 0, &sinfo);
+ }
+ }
+ if (res > -1) {
+ i = jiffies & 0xffff;
+ sz = (jiffies >> 16) & 0x7;
+ if (6 > spaces) {
+ baselen = baselen - (6 - spaces);
+ spaces = 6;
+ }
+ msdos_name[baselen+4] = '~';
+ msdos_name[baselen+5] = '1' + sz;
+ msdos_name[baselen+6] = '.';
+ strcpy(&msdos_name[baselen+7], ext);
+ totlen = baselen + 6 + extlen + (extlen > 0);
+ qname.name=msdos_name;
+ qname.len=totlen;
+ while (res > -1) {
+ sprintf(buf, "%04x", i);
+ memcpy(&msdos_name[baselen], buf, 4);
+ msdos_name[12] = 0;
+ res = vfat_find(dir, &qname, 0, 0, 0, &sinfo);
+ i -= 11;
+ }
}
+
res = vfat_format_name(msdos_name, totlen, name_res, 1, utf8);
return res;
}
@@ -1082,7 +1108,6 @@
sinfo_out->shortname_offset = offset - sizeof(struct msdos_dir_slot);
sinfo_out->longname_offset = offset - sizeof(struct msdos_dir_slot) * slots;
res = 0;
- return 0;
} else {
res = -ENOENT;
}