Fixes large dirreads on 9ns
authorBarret Rhoden <brho@cs.berkeley.edu>
Sun, 20 Jul 2014 22:07:44 +0000 (15:07 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Sun, 20 Jul 2014 22:07:44 +0000 (15:07 -0700)
When reading from large dirs, we would fill the c->buf with lots of Ms,
such that we couldn't fit any more in there, and then we'd error out.
We get lots of Ms because we'd read more than one M per read call, but
extract only one M per read (M2kdirent).

The fix is to attempt to extract an M2kdirent before even performing
the underlying read, to keep the c->bufused size down.  Also avoids
unnecessary reads.

Also, successful dirreads return the sizeof(struct kdirent), which is
the actual amount of memory we are writing back to userspace, instead of
the size of an M.

kern/src/ns/sysfile.c

index fccae2d..634b108 100644 (file)
@@ -763,12 +763,21 @@ static long rread(int fd, void *va, long n, int64_t * offp)
         * new stuff later. Allocate DIRREADSIZE bytes for that purpose.
         */
        if (dir) {
+               int amt;
                /* expecting only one dirent at a time, o/w we're busted */
                assert(n >= sizeof(struct kdirent));
                if (!c->buf) {
                        c->buf=kmalloc(DIRREADSIZE, KMALLOC_WAIT);
                        c->bufused = 0;
                }
+               /* Attempt to extract an M, in case there was some already */
+               amt = convM2kdirent(c->buf, c->bufused, real_va, 0);
+               if (amt) {
+                       c->bufused -= amt;
+                       memmove(c->buf, c->buf + amt, c->bufused);
+                       n = sizeof(struct kdirent);
+                       goto out;
+               }
                /* debugging */
                if (waserror()) {
                        printk("Well, sysread of a dir sucks.%s \n", current_errstr());
@@ -815,13 +824,15 @@ static long rread(int fd, void *va, long n, int64_t * offp)
        if (dir) {
                int amt;
                c->bufused = c->bufused + n;
+               /* extract an M from the front, then shift the remainder back */
                amt = convM2kdirent(c->buf, c->bufused, real_va, 0);
                c->bufused -= amt;
                memmove(c->buf, c->buf + amt, c->bufused);
-               n = amt;
+               n = amt ? sizeof(struct kdirent) : 0;
                poperror();     /* matching our debugging waserror */
        }
 
+out:
        poperror();
        cclose(c);