diff options
author | njl <njl@FreeBSD.org> | 2005-03-11 23:27:45 +0000 |
---|---|---|
committer | njl <njl@FreeBSD.org> | 2005-03-11 23:27:45 +0000 |
commit | a08e532eaa2231786c6ff27b7aeb2a2a33d99601 (patch) | |
tree | dff6507dc162437f83d66fdce169980a279968f7 /sys/fs/msdosfs/msdosfs_conv.c | |
parent | aae81bd5b34df7289c1a7a116888fa8c57c5c655 (diff) | |
download | FreeBSD-src-a08e532eaa2231786c6ff27b7aeb2a2a33d99601.zip FreeBSD-src-a08e532eaa2231786c6ff27b7aeb2a2a33d99601.tar.gz |
The mbnambuf routines combine multiple substrings into a single
long filename. Each substring is indexed by the windows ID, a
sequential one-based value. The previous code was extremely slow,
doing a malloc/strcpy/free for each substring.
This code optimizes these routines with this in mind, using the ID
to index into a single array and concatenating each WIN_CHARS chunk
at once. (The last chunk is variable-length.)
This code has been tested as working on an FS with difficult filename
sizes (255, 13, 26, etc.) It gives a 77.1% decrease in profiled
time (total across all functions) and a 73.7% decrease in wall time.
Test was "ls -laR > /dev/null".
Per-function time savings:
mbnambuf_init: -90.7%
mbnambuf_write: -18.7%
mbnambuf_flush: -67.1%
MFC after: 1 month
Diffstat (limited to 'sys/fs/msdosfs/msdosfs_conv.c')
-rw-r--r-- | sys/fs/msdosfs/msdosfs_conv.c | 77 |
1 files changed, 41 insertions, 36 deletions
diff --git a/sys/fs/msdosfs/msdosfs_conv.c b/sys/fs/msdosfs/msdosfs_conv.c index 1f4a32e..efd2191 100644 --- a/sys/fs/msdosfs/msdosfs_conv.c +++ b/sys/fs/msdosfs/msdosfs_conv.c @@ -101,11 +101,9 @@ static u_int16_t unix2doschr(const u_char **, size_t *, struct msdosfsmount *); static u_int16_t win2unixchr(u_int16_t, struct msdosfsmount *); static u_int16_t unix2winchr(const u_char **, size_t *, int, struct msdosfsmount *); -struct mbnambuf { - char * p; - size_t n; -}; -static struct mbnambuf subent[WIN_MAXSUBENTRIES]; +static char *nambuf_ptr; +static size_t nambuf_len; +static int nambuf_max_id; /* * Convert the unix version of time to dos's idea of time to be used in @@ -1195,59 +1193,66 @@ unix2winchr(const u_char **instr, size_t *ilen, int lower, struct msdosfsmount * } /* - * Make subent empty + * Initialize the temporary concatenation buffer (once) and mark it as + * empty on subsequent calls. */ void mbnambuf_init(void) { - int i; - for (i = 0; i < WIN_MAXSUBENTRIES; i++) { - if (subent[i].p) { - free(subent[i].p, M_MSDOSFSMNT); - subent[i].p = NULL; - subent[i].n = 0; - } + if (nambuf_ptr == NULL) { + nambuf_ptr = malloc(MAXNAMLEN + 1, M_MSDOSFSMNT, M_WAITOK); + nambuf_ptr[MAXNAMLEN] = '\0'; } + nambuf_len = 0; + nambuf_max_id = -1; } /* - * Write a subent entry from a slot + * Fill out our concatenation buffer with the given substring, at the + * offset specified by its id. For the last substring (i.e., the one with + * the maximum id), use it to calculate the length of the entire string. + * Since this function is usually called with ids in descending order, this + * reduces the number of times we need to call strlen() since we know that + * all previous substrings are exactly WIN_CHARS in length. */ void mbnambuf_write(char *name, int id) { - if (subent[id].p) { - printf("mbnambuf_write(): %s -> %s\n", subent[id].p, name); - free(subent[id].p, M_MSDOSFSMNT); + size_t count; + + count = WIN_CHARS; + if (id > nambuf_max_id) { + count = strlen(name); + nambuf_len = id * WIN_CHARS + count; + if (nambuf_len > MAXNAMLEN) { + printf("msdosfs: file name %d too long\n", nambuf_len); + return; + } + nambuf_max_id = id; } - subent[id].n = strlen(name); - subent[id].p = malloc(subent[id].n + 1, M_MSDOSFSMNT, M_WAITOK); - strcpy(subent[id].p, name); + memcpy(nambuf_ptr + (id * WIN_CHARS), name, count); } /* - * Combine each subents to the *dp and initialize subent + * Take the completed string and use it to setup the struct dirent. + * Be sure to always nul-terminate the d_name and then copy the string + * from our buffer. Note that this function assumes the full string has + * been reassembled in the buffer. If it's called before all substrings + * have been written via mbnambuf_write(), the result will be incorrect. */ char * mbnambuf_flush(struct dirent *dp) { - int i; - char *name = dp->d_name; - - *name = '\0'; - dp->d_namlen = 0; - for (i = 0; i < WIN_MAXSUBENTRIES; i++) { - if (subent[i].p) { - if (dp->d_namlen + subent[i].n > sizeof(dp->d_name) - 1) { - mbnambuf_init(); - return (NULL); - } - strcpy(name, subent[i].p); - dp->d_namlen += subent[i].n; - name += subent[i].n; - } + + if (nambuf_len > sizeof(dp->d_name) - 1) { + mbnambuf_init(); + return (NULL); } + nambuf_ptr[nambuf_len] = '\0'; + memcpy(dp->d_name, nambuf_ptr, nambuf_len); + dp->d_namlen = nambuf_len; + mbnambuf_init(); return (dp->d_name); } |