Bob,
Am Samstag 13 September 2008 10:25:48 schrieb Bob Amstadt:
> I ported the ISP1362 driver from the Blackfin processor to the Coldfire
> processor. Specifically I'm using the MCF5282. Everything works perfectly
> on smaller flash drives (128MB and 256MB). In fact, a 2GB flash drive that
> is formatted to only 512MB also works perfectly.
>
> A 2GB flash drive formatted for 2GB will cause uClinux to crash usually on
> a simple operation such as an ls of the root directory. The device does
> mount successfully, but an ls will cause a crash. The crash is
> unfortunately not consistent. A variety of different types of failures
> occur.
This is a known bug.
For directory parsing, there is a huge area allocated on the stack, and at 2
GBytes, the busybox application crashes because of stack overflow.
The quick fix is to allocate more stack for busybox.
The right fix is to patch uClibc.
Patch from <[EMAIL PROTECTED]> (see attachment)
best regards
Wolfgang
--
Wahre Worte sind nicht schön. Schöne Worte sind nicht wahr.
(Laotse)
diff U3b /users/anta/uClinux/uClinux/uClibc/libc/sysdeps/linux/common/getdents.c.org /users/anta/uClinux/uClinux/uClibc/libc/sysdeps/linux/common/getdents.c
--- /users/anta/uClinux/uClinux/uClibc/libc/sysdeps/linux/common/getdents.c.org Thu May 22 10:17:14 2008
+++ /users/anta/uClinux/uClinux/uClibc/libc/sysdeps/linux/common/getdents.c Thu Jun 26 17:35:18 2008
@@ -52,29 +52,39 @@
struct dirent *dp;
off_t last_offset = -1;
ssize_t retval;
- size_t red_nbytes;
+ size_t skip_bytes;
struct kernel_dirent *skdp, *kdp;
const size_t size_diff = (offsetof (struct dirent, d_name)
- offsetof (struct kernel_dirent, d_name));
+ const size_t alignment = __alignof__ (struct dirent);
+
+ skip_bytes = (nbytes / (offsetof (struct dirent, d_name) + 14)) *
+ ((size_diff + alignment -1) & ~ alignment);
+ skip_bytes = MAX(skip_bytes, alignment);
- red_nbytes = MIN (nbytes - ((nbytes /
- (offsetof (struct dirent, d_name) + 14)) * size_diff),
- nbytes - size_diff);
+ if(skip_bytes >= nbytes)
+ {
+ /* The buffer the user passed in is too small to hold even
+ one entry. */
+ __set_errno (EINVAL);
+ return -1;
+ }
dp = (struct dirent *) buf;
- skdp = kdp = alloca (red_nbytes);
+ skdp = kdp = (struct kernel_dirent*)(buf + skip_bytes);
- retval = __syscall_getdents(fd, (unsigned char *)kdp, red_nbytes);
+ retval = __syscall_getdents(fd, (unsigned char *)kdp, nbytes - skip_bytes);
if (retval == -1)
return -1;
while ((char *) kdp < (char *) skdp + retval) {
- const size_t alignment = __alignof__ (struct dirent);
/* Since kdp->d_reclen is already aligned for the kernel structure
this may compute a value that is bigger than necessary. */
- size_t new_reclen = ((kdp->d_reclen + size_diff + alignment - 1)
+ size_t reclen = kdp->d_reclen;
+ ino_t tmp_ino = kdp->d_ino;
+ size_t new_reclen = ((reclen + size_diff + alignment - 1)
& ~(alignment - 1));
- if ((char *) dp + new_reclen > buf + nbytes) {
+ if ((char *)dp + size_diff > (char *)kdp) {
/* Our heuristic failed. We read too many entries. Reset
the stream. */
assert (last_offset != -1);
@@ -90,14 +100,16 @@
}
last_offset = kdp->d_off;
- dp->d_ino = kdp->d_ino;
- dp->d_off = kdp->d_off;
+
+ memcpy (dp->d_name, kdp->d_name,
+ reclen - offsetof (struct kernel_dirent, d_name));
+
+ dp->d_ino = tmp_ino;
+ dp->d_off = last_offset;
dp->d_reclen = new_reclen;
dp->d_type = DT_UNKNOWN;
- memcpy (dp->d_name, kdp->d_name,
- kdp->d_reclen - offsetof (struct kernel_dirent, d_name));
dp = (struct dirent *) ((char *) dp + new_reclen);
- kdp = (struct kernel_dirent *) (((char *) kdp) + kdp->d_reclen);
+ kdp = (struct kernel_dirent *) (((char *) kdp) + reclen);
}
return (char *) dp - buf;
}
_______________________________________________
uClinux-dev mailing list
[email protected]
http://mailman.uclinux.org/mailman/listinfo/uclinux-dev
This message was resent by [email protected]
To unsubscribe see:
http://mailman.uclinux.org/mailman/options/uclinux-dev