(Illustration by Gaich Muramatsu)
Here's a patch for coda-src/dir/dirbody.c that fixes a problem we were seeing with large directories under NetBSD 1.3.3 and FreeBSD 2.2.6. readdir(3) on these machines treats directory entries that straddle a 4k boundary (readdir(3)'s buffer size) as end-of-directory markers. This patch to DIR_Convert() prevents the straddling from happening when __BSD44__ is defined. Matt -- Matt Fredette http://mit.edu/fredette/www fredette_at_bbnplanet.com, fredette_at_mit.edu, fredette_at_theory.lcs.mit.edu "[Peter] Banks' career waned after joining `Flash' in 1972 and recording three albums all called `Two Sides Of Peter Banks.'" [snip] Index: dirbody.c =================================================================== RCS file: /cvs/coda/coda-src/dir/dirbody.c,v retrieving revision 1.1.1.2 retrieving revision 1.4 diff -c -r1.1.1.2 -r1.4 *** dirbody.c 1999/01/28 23:20:57 1.1.1.2 --- dirbody.c 1999/02/17 22:39:37 1.4 *************** *** 791,796 **** --- 791,799 ---- int num; char *buf; int offset = 0; + #ifdef __BSD44__ + int direntlen; + #endif /* __BSD44__ */ #ifdef DJGPP int rc; #endif *************** *** 802,807 **** --- 805,822 ---- CODA_ASSERT( fd >= 0 ); len = DIR_Length(dir); + #ifdef __BSD44__ + /* because of a poor libc readdir(), directory entries + cannot span a 4k boundary. because we can't know until + we write out the directory how much we will have to pad + things, just assume that we will have to pad one + maximum-sized directory entry for each 4k chunk of + directory we write. this leads to larger directories + on disk than we strictly need, but hey: */ + #define BSD44_READDIR_BOUNDARY_LOG2 12 + #define BSD44_READDIR_BOUNDARY (1 << BSD44_READDIR_BOUNDARY_LOG2) + len += (len >> BSD44_READDIR_BOUNDARY_LOG2) * ((sizeof(struct venus_dirent) + 3) & ~3); + #endif /* __BSD44__ */ #ifndef DJGPP CODA_ASSERT( ftruncate(fd, len) == 0 ); *************** *** 820,825 **** --- 835,863 ---- ep = dir_GetBlob(dir, num); if (!ep) break; + #ifdef __BSD44__ + /* optimistically write the directory entry: */ + direntlen = dir_DirEntry2VDirent(ep, (struct venus_dirent *) (buf + offset), vol); + /* if what we just wrote crosses a 4k boundary: */ + if (((offset + direntlen) ^ offset) & ~(BSD44_READDIR_BOUNDARY - 1)) { + /* note that vd still points to the *previous* directory + entry. calculate how much we have to add to its d_reclen + and offset for the padding: */ + direntlen = ((offset + (BSD44_READDIR_BOUNDARY - 1)) & + ~(BSD44_READDIR_BOUNDARY - 1)) - offset; + vd->d_reclen += direntlen; + offset += direntlen; + /* fall through to let the original code rewrite the entry */ + } + /* otherwise, we were successful the first time: */ + else { + vd = (struct venus_dirent *)(buf + offset); + offset += direntlen; + num = ntohs(ep->next); + continue; + } + #endif /* __BSD44__ */ + vd = (struct venus_dirent *)(buf + offset); offset += dir_DirEntry2VDirent(ep, vd, vol); num = ntohs(ep->next); [snip]Received on 1999-02-18 12:17:24