Date: Thu, 30 Aug 2007 23:35:59 +0800 From: "Tz-Huan Huang" <tzhuan@csie.org> To: "Bruce Evans" <brde@optusnet.com.au> Cc: Kostik Belousov <kostikbel@gmail.com>, bugs@freebsd.org, fs@freebsd.org Subject: Re: msdosfs not MPSAFE Message-ID: <6a7033710708300835n5ac95063o6331ede5fcc80662@mail.gmail.com> In-Reply-To: <20070814154812.J24186@besplex.bde.org> References: <20070712084115.GA2200@deviant.kiev.zoral.com.ua> <20070716195556.P12807@besplex.bde.org> <20070721063434.GI2200@deviant.kiev.zoral.com.ua> <20070721233613.Q3366@besplex.bde.org> <20070804075730.GP2738@deviant.kiev.zoral.com.ua> <20070808004001.O926@besplex.bde.org> <20070807170259.GJ2738@deviant.kiev.zoral.com.ua> <20070810133946.H769@besplex.bde.org> <20070810124153.GW2738@deviant.kiev.zoral.com.ua> <20070814154812.J24186@besplex.bde.org>
next in thread | previous in thread | raw e-mail | index | archive | help
[-- Attachment #1 --] hi, I have a patch that remove the global variables nambuf_ptr, nambuf_len and nambuf_last_id entirely. It should be applied on recent 7-current. Please give it a try, thanks a lot. http://w.csie.org/~tzhuan/freebsd/msdosfs.diff Tz-Huan 2007/8/14, Bruce Evans <brde@optusnet.com.au>: > On Fri, 10 Aug 2007, Kostik Belousov wrote: > > > On Fri, Aug 10, 2007 at 01:54:48PM +1000, Bruce Evans wrote: > >> I wrote yet another patch, with allocation on the stack so that no locking > >> is required. This is simpler and doesn't require any new functions. > >> Unfortunately, it is larger because it changes the interfaces for most > >> functions. The interface changes are routine, so this is probably better. > >> Note that 'struct dirent's are already allocated on the stack. This > >> patch adds allocation of 'struct mbnambuf's which are slightly smaller > >> (~256 bytes). I think this is just small enough for stack allocation. > > > > I agree that this is the best approach. The size of the on-stack > > structure still make me worry, although ~270 bytes seems to be not too > > large for 3-pages stack. > > Stack growth seems to be nowhere near a problem. With the extra ~270 > bytes. ls -lR on i386 uses less than a 1-page stack (about 3.5K, > including 0x270 bytes for the pcb). I think the maximum stack depth > is attained when a debugger trap traps a fast interrupt interrupting > a page fault in an i/o routine called from msdosfs_readdir(). Unlike > in RELENG_4, nested interrupts can't occur, so a 1-page stack should > be enough for everything on i386 (but of course isn't quite enough). > I didn't try hard to attain the maximum depth, and just looked at where > the stack got to after running a large ls -lR for a while. msdosfs_readdir() > now allocates 0x2b0 bytes on the stack using "subl $0x2b0,%esp" and > that is now the largest single allocation. This is without INVARIANTS > etc. > > Bruce > _______________________________________________ > freebsd-fs@freebsd.org mailing list > http://lists.freebsd.org/mailman/listinfo/freebsd-fs > To unsubscribe, send any mail to "freebsd-fs-unsubscribe@freebsd.org" > [-- Attachment #2 --] diff -ruN msdosfs.orig/direntry.h msdosfs/direntry.h --- msdosfs.orig/direntry.h 2006-10-24 19:14:05.000000000 +0800 +++ msdosfs/direntry.h 2007-08-30 15:14:04.000000000 +0800 @@ -136,18 +136,15 @@ struct dirent; struct msdosfsmount; -char *mbnambuf_flush(struct dirent *dp); -void mbnambuf_init(void); -void mbnambuf_write(char *name, int id); int dos2unixfn(u_char dn[11], u_char *un, int lower, struct msdosfsmount *pmp); int unix2dosfn(const u_char *un, u_char dn[12], size_t unlen, u_int gen, struct msdosfsmount *pmp); int unix2winfn(const u_char *un, size_t unlen, struct winentry *wep, int cnt, int chksum, struct msdosfsmount *pmp); -int winChkName(const u_char *un, size_t unlen, int chksum, +int winChkName(const u_char *un, size_t unlen, struct dirent *dirbufptr, int chksum, struct msdosfsmount *pmp); -int win2unixfn(struct winentry *wep, int chksum, struct msdosfsmount *pmp); +int win2unixfn(struct winentry *wep, struct dirent *dirbufptr, int chksum, struct msdosfsmount *pmp); u_int8_t winChksum(struct direntry *dep); int winSlotCnt(const u_char *un, size_t unlen, struct msdosfsmount *pmp); size_t winLenFixup(const u_char *un, size_t unlen); diff -ruN msdosfs.orig/msdosfs_conv.c msdosfs/msdosfs_conv.c --- msdosfs.orig/msdosfs_conv.c 2007-08-30 11:33:22.000000000 +0800 +++ msdosfs/msdosfs_conv.c 2007-08-30 16:57:15.000000000 +0800 @@ -64,13 +64,9 @@ static int mbsadjpos(const char **, size_t, size_t, int, int, void *handle); static u_int16_t dos2unixchr(const u_char **, size_t *, int, struct msdosfsmount *); static u_int16_t unix2doschr(const u_char **, size_t *, struct msdosfsmount *); -static u_int16_t win2unixchr(u_int16_t, struct msdosfsmount *); +static size_t win2unixchr(u_int16_t wc, struct dirent *dirbufptr, struct msdosfsmount *pmp); static u_int16_t unix2winchr(const u_char **, size_t *, int, struct msdosfsmount *); -static char *nambuf_ptr; -static size_t nambuf_len; -static int nambuf_last_id; - /* * 0 - character disallowed in long file name. * 1 - character should be replaced by '_' in DOS file name, @@ -249,6 +245,11 @@ int thislong = 0; u_int16_t c; +#ifdef MSDOSFS_DEBUG + u_char *un_ptr = un; + printf("dos2unixfn(): dn %s", dn); +#endif + /* * If first char of the filename is SLOT_E5 (0x05), then the real * first char of the filename should be 0xe5. But, they couldn't @@ -293,6 +294,10 @@ } *un++ = 0; +#ifdef MSDOSFS_DEBUG + printf(" -> un %s, size %d\n", un_ptr, thislong); +#endif + return (thislong); } @@ -601,37 +606,38 @@ * Returns the checksum or -1 if no match */ int -winChkName(un, unlen, chksum, pmp) +winChkName(un, unlen, dirbufptr, chksum, pmp) const u_char *un; size_t unlen; + struct dirent *dirbufptr; int chksum; struct msdosfsmount *pmp; { size_t len; u_int16_t c1, c2; u_char *np; - struct dirent dirbuf; - /* - * We alread have winentry in mbnambuf - */ - if (!mbnambuf_flush(&dirbuf) || !dirbuf.d_namlen) + if (!dirbufptr->d_namlen) return -1; #ifdef MSDOSFS_DEBUG - printf("winChkName(): un=%s:%d,d_name=%s:%d\n", un, unlen, - dirbuf.d_name, - dirbuf.d_namlen); + printf("winChkName(): un=0x"); + for (const u_char *c = un; *c; ++c) + printf("%02x", (unsigned char)*c); + printf(":%d, d_name=0x", unlen); + for (char *c = dirbufptr->d_name; *c; ++c) + printf("%02x", (unsigned char)*c); + printf(":%d\n", dirbufptr->d_namlen); #endif /* * Compare the name parts */ - len = dirbuf.d_namlen; + len = dirbufptr->d_namlen; if (unlen != len) return -2; - for (np = dirbuf.d_name; unlen > 0 && len > 0;) { + for (np = dirbufptr->d_name; unlen > 0 && len > 0;) { /* * Comparison must be case insensitive, because FAT disallows * to look up or create files in case sensitive even when @@ -646,19 +652,36 @@ } /* - * Convert Win95 filename to dirbuf. + * Reverse C-String + * for example, 12345 -> 54321 + */ +static void +strreverse(char *str, size_t n) +{ + char c; + size_t i; + for (i = 0; i < n/2; ++i) { + c = str[i]; + str[i] = str[n-i-1]; + str[n-i-1] = c; + } +} + +/* + * Convert Win95 filename to dirbuf (*dirbufptr). * Returns the checksum or -1 if impossible */ int -win2unixfn(wep, chksum, pmp) +win2unixfn(wep, dirbufptr, chksum, pmp) struct winentry *wep; + struct dirent *dirbufptr; int chksum; struct msdosfsmount *pmp; { u_int8_t *cp; - u_int8_t *np, name[WIN_CHARS * 2 + 1]; u_int16_t code; int i; + const size_t d_namlen = dirbufptr->d_namlen; /* save for reverse */ if ((wep->weCnt&WIN_CNT) > howmany(WIN_MAXLEN, WIN_CHARS) || !(wep->weCnt&WIN_CNT)) @@ -677,22 +700,18 @@ /* * Convert the name parts */ - np = name; for (cp = wep->wePart1, i = sizeof(wep->wePart1)/2; --i >= 0;) { code = (cp[1] << 8) | cp[0]; switch (code) { case 0: - *np = '\0'; - mbnambuf_write(name, (wep->weCnt & WIN_CNT) - 1); + dirbufptr->d_name[dirbufptr->d_namlen] = '\0'; return chksum; case '/': - *np = '\0'; + dirbufptr->d_name[dirbufptr->d_namlen] = '\0'; return -1; default: - code = win2unixchr(code, pmp); - if (code & 0xff00) - *np++ = code >> 8; - *np++ = code; + code = win2unixchr(code, dirbufptr, pmp); + if (code) return -1; break; } cp += 2; @@ -701,17 +720,14 @@ code = (cp[1] << 8) | cp[0]; switch (code) { case 0: - *np = '\0'; - mbnambuf_write(name, (wep->weCnt & WIN_CNT) - 1); + dirbufptr->d_name[dirbufptr->d_namlen] = '\0'; return chksum; case '/': - *np = '\0'; + dirbufptr->d_name[dirbufptr->d_namlen] = '\0'; return -1; default: - code = win2unixchr(code, pmp); - if (code & 0xff00) - *np++ = code >> 8; - *np++ = code; + code = win2unixchr(code, dirbufptr, pmp); + if (code) return -1; break; } cp += 2; @@ -720,23 +736,25 @@ code = (cp[1] << 8) | cp[0]; switch (code) { case 0: - *np = '\0'; - mbnambuf_write(name, (wep->weCnt & WIN_CNT) - 1); + dirbufptr->d_name[dirbufptr->d_namlen] = '\0'; return chksum; case '/': - *np = '\0'; + dirbufptr->d_name[dirbufptr->d_namlen] = '\0'; return -1; default: - code = win2unixchr(code, pmp); - if (code & 0xff00) - *np++ = code >> 8; - *np++ = code; + code = win2unixchr(code, dirbufptr, pmp); + if (code) return -1; break; } cp += 2; } - *np = '\0'; - mbnambuf_write(name, (wep->weCnt & WIN_CNT) - 1); + dirbufptr->d_name[dirbufptr->d_namlen] = '\0'; + + /* swap the dirbufptr->d_name */ + strreverse(dirbufptr->d_name, dirbufptr->d_namlen); + strreverse(dirbufptr->d_name, dirbufptr->d_namlen - d_namlen); + strreverse(dirbufptr->d_name + dirbufptr->d_namlen - d_namlen, d_namlen); + return chksum; } @@ -952,10 +970,10 @@ /* * Convert Windows char to Local char */ -static u_int16_t -win2unixchr(u_int16_t wc, struct msdosfsmount *pmp) +static size_t +win2unixchr(u_int16_t wc, struct dirent *dirbufptr, struct msdosfsmount *pmp) { - u_char *inp, *outp, inbuf[3], outbuf[3]; + u_char *inp, *outp, inbuf[3]; size_t ilen, olen, len; if (wc == 0) @@ -966,31 +984,49 @@ inbuf[1] = (u_char)wc; inbuf[2] = '\0'; - ilen = olen = len = 2; + ilen = 2; + olen = len = sizeof(dirbufptr->d_name) - dirbufptr->d_namlen - 1; inp = inbuf; - outp = outbuf; + outp = dirbufptr->d_name + dirbufptr->d_namlen; + msdosfs_iconv->convchr(pmp->pm_w2u, (const char **)&inp, &ilen, (char **)&outp, &olen); - len -= olen; - /* - * return '?' if failed to convert - */ - if (len == 0) { - wc = '?'; - return (wc); - } + dirbufptr->d_namlen += len - olen; - wc = 0; - while(len--) - wc |= (*(outp - len - 1) & 0xff) << (len << 3); - return (wc); + if (ilen != 0) { + /* failed to convert */ + if (olen == 0) { + /* filename longer then MAXNAMLEN */ + goto too_long; + } else { + /* some character cannot be converted */ + goto failed; + } + } + + goto ok; } - if (wc & 0xff00) - wc = '?'; + if (sizeof(dirbufptr->d_name) <= dirbufptr->d_namlen + 2) { + /* filename longer then MAXNAMLEN */ + goto too_long; + } else if (wc & 0xff00) { + goto failed; + } + dirbufptr->d_name[dirbufptr->d_namlen++] = (u_char)(wc>>8); + dirbufptr->d_name[dirbufptr->d_namlen++] = (u_char)wc; + goto ok; - return (wc); +ok: + return 0; + +too_long: + return 1; + +failed: + dirbufptr->d_name[dirbufptr->d_namlen++] = '?'; + return 2; } /* @@ -1035,78 +1071,3 @@ (*instr)++; return (wc); } - -/* - * Initialize the temporary concatenation buffer (once) and mark it as - * empty on subsequent calls. - */ -void -mbnambuf_init(void) -{ - - if (nambuf_ptr == NULL) { - nambuf_ptr = malloc(MAXNAMLEN + 1, M_MSDOSFSMNT, M_WAITOK); - nambuf_ptr[MAXNAMLEN] = '\0'; - } - nambuf_len = 0; - nambuf_last_id = -1; -} - -/* - * Fill out our concatenation buffer with the given substring, at the offset - * specified by its id. Since this function must be called with ids in - * descending order, we take advantage of the fact that ASCII substrings are - * exactly WIN_CHARS in length. For non-ASCII substrings, we shift all - * previous (i.e. higher id) substrings upwards to make room for this one. - * This only penalizes portions of substrings that contain more than - * WIN_CHARS bytes when they are first encountered. - */ -void -mbnambuf_write(char *name, int id) -{ - size_t count; - char *slot; - - KASSERT(nambuf_len == 0 || id == nambuf_last_id - 1, - ("non-decreasing id, id %d last id %d", id, nambuf_last_id)); - - /* Store this substring in a WIN_CHAR-aligned slot. */ - slot = nambuf_ptr + (id * WIN_CHARS); - count = strlen(name); - if (nambuf_len + count > MAXNAMLEN) { - printf("msdosfs: file name %zu too long\n", nambuf_len + count); - return; - } - - /* Shift suffix upwards by the amount length exceeds WIN_CHARS. */ - if (count > WIN_CHARS && nambuf_len != 0) - bcopy(slot + WIN_CHARS, slot + count, nambuf_len); - - /* Copy in the substring to its slot and update length so far. */ - bcopy(name, slot, count); - nambuf_len += count; - nambuf_last_id = id; -} - -/* - * 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) -{ - - if (nambuf_len > sizeof(dp->d_name) - 1) { - mbnambuf_init(); - return (NULL); - } - bcopy(nambuf_ptr, dp->d_name, nambuf_len); - dp->d_name[nambuf_len] = '\0'; - dp->d_namlen = nambuf_len; - - mbnambuf_init(); - return (dp->d_name); -} diff -ruN msdosfs.orig/msdosfs_lookup.c msdosfs/msdosfs_lookup.c --- msdosfs.orig/msdosfs_lookup.c 2007-08-07 10:25:56.000000000 +0800 +++ msdosfs/msdosfs_lookup.c 2007-08-30 16:44:50.000000000 +0800 @@ -54,6 +54,7 @@ #include <sys/mount.h> #include <sys/namei.h> #include <sys/vnode.h> +#include <sys/dirent.h> #include <fs/msdosfs/bpb.h> #include <fs/msdosfs/direntry.h> @@ -115,7 +116,10 @@ int olddos = 1; #ifdef MSDOSFS_DEBUG - printf("msdosfs_lookup(): looking for %s\n", cnp->cn_nameptr); + printf("msdosfs_lookup(): looking for 0x"); + for (char *c = cnp->cn_nameptr; *c; ++c) + printf("%02x", (unsigned char)*c); + printf("\n"); #endif dp = VTODE(vdp); pmp = dp->de_pmp; @@ -177,15 +181,18 @@ slotcount = 0; #ifdef MSDOSFS_DEBUG - printf("msdosfs_lookup(): dos version of filename %s, length %ld\n", - dosfilename, cnp->cn_namelen); + printf("msdosfs_lookup(): dos version of filename 0x"); + for (char *c = dosfilename; *c; ++c) + printf("%02x", (unsigned char)*c); + printf(" , length %ld\n", cnp->cn_namelen); #endif /* * Search the directory pointed at by vdp for the name pointed at * by cnp->cn_nameptr. */ tdp = NULL; - mbnambuf_init(); + struct dirent namebuf; + namebuf.d_namlen = 0; /* * The outer loop ranges over the clusters that make up the * directory. Note that the root directory is different from all @@ -225,7 +232,7 @@ * Drop memory of previous long matches */ chksum = -1; - mbnambuf_init(); + namebuf.d_namlen = 0; if (slotcount < wincnt) { slotcount++; @@ -251,6 +258,7 @@ continue; chksum = win2unixfn((struct winentry *)dep, + &namebuf, chksum, pmp); continue; @@ -258,9 +266,11 @@ chksum = winChkName((const u_char *)cnp->cn_nameptr, unlen, + &namebuf, chksum, pmp); if (chksum == -2) { + namebuf.d_namlen = 0; chksum = -1; continue; } diff -ruN msdosfs.orig/msdosfs_vnops.c msdosfs/msdosfs_vnops.c --- msdosfs.orig/msdosfs_vnops.c 2007-08-07 18:35:27.000000000 +0800 +++ msdosfs/msdosfs_vnops.c 2007-08-30 15:15:45.000000000 +0800 @@ -1629,7 +1629,8 @@ } } - mbnambuf_init(); + dirbuf.d_namlen = 0; + off = offset; while (uio->uio_resid > 0) { lbn = de_cluster(pmp, offset - bias); @@ -1676,7 +1677,7 @@ */ if (dentp->deName[0] == SLOT_DELETED) { chksum = -1; - mbnambuf_init(); + dirbuf.d_namlen = 0; continue; } @@ -1686,7 +1687,7 @@ if (dentp->deAttributes == ATTR_WIN95) { if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) continue; - chksum = win2unixfn((struct winentry *)dentp, + chksum = win2unixfn((struct winentry *)dentp, &dirbuf, chksum, pmp); continue; } @@ -1696,7 +1697,7 @@ */ if (dentp->deAttributes & ATTR_VOLUME) { chksum = -1; - mbnambuf_init(); + dirbuf.d_namlen = 0; continue; } /* @@ -1738,9 +1739,8 @@ ((pmp->pm_flags & MSDOSFSMNT_SHORTNAME) ? (LCASE_BASE | LCASE_EXT) : 0), pmp); - mbnambuf_init(); - } else - mbnambuf_flush(&dirbuf); + } + chksum = -1; dirbuf.d_reclen = GENERIC_DIRSIZ(&dirbuf); if (uio->uio_resid < dirbuf.d_reclen) { @@ -1760,6 +1760,8 @@ } } off = offset + sizeof(struct direntry); + + dirbuf.d_namlen = 0; } brelse(bp); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a7033710708300835n5ac95063o6331ede5fcc80662>
