kernel: restructure readi/writei to save memory
authorAlan Cox <alan@linux.intel.com>
Fri, 9 Feb 2018 23:49:50 +0000 (23:49 +0000)
committerAlan Cox <alan@linux.intel.com>
Fri, 9 Feb 2018 23:49:50 +0000 (23:49 +0000)
This saves us 256 bytes on Z80 mostly by removing the amount of 32bit maths
SDCC has the opportunity to **** up.

We introduce a helper (umove) which adjusts all the pointers and offsets
for a given file and use that where we can. We also restructure a bit so we
can use the udata.u_done value in readi/writei

This has some minor consequences:
Callers need to check u_done for completion not u_count
Char and Socket handlers don't affect the offset unless they choose to (which
is saner). Devsys has been modified accordingly.

Handle with care.

Kernel/devsys.c
Kernel/filesys.c
Kernel/include/kernel.h
Kernel/inode.c
Kernel/syscall_exec16.c
Kernel/syscall_exec32.c
Kernel/syscall_fs.c

index 7eb2463..e528386 100644 (file)
@@ -35,7 +35,7 @@ int sys_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
                if (uput((unsigned char *) udata.u_offset, udata.u_base,
                               udata.u_count))
                        return -1;
-               return udata.u_count;
+               return umove(udata.u_count);
        case 2:
                if (udata.u_sysio)
                        memset(udata.u_base, 0, udata.u_count);
@@ -49,7 +49,7 @@ int sys_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
                        return 0;
                if (uput(addr + udata.u_offset, udata.u_base, udata.u_count))
                        return -1;
-               return udata.u_count;
+               return umove(udata.u_count);
 #ifdef CONFIG_DEV_MEM
         case 4:
                 return devmem_read();
@@ -81,7 +81,7 @@ int sys_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
                if(uget((unsigned char *) udata.u_offset, udata.u_base,
                               udata.u_count))
                        return -1;
-               return udata.u_count;
+               return umove(udata.u_count);
        case 3:
                udata.u_error = EINVAL;
                return -1;
index 74dcba5..d8b4dfc 100644 (file)
@@ -321,11 +321,11 @@ bool ch_link(inoptr wd, char *oldname, char *newname, inoptr nindex)
         readi(wd, 0);
 
         /* Read until EOF or name is found.  readi() advances udata.u_offset */
-        if(udata.u_count == 0 || namecomp(oldname, curentry.d_name))
+        if(udata.u_done == 0 || namecomp(oldname, curentry.d_name))
             break;
     }
 
-    if(udata.u_count == 0 && *oldname) {
+    if(udata.u_done == 0 && *oldname) {
         udata.u_error = ENOENT;
         return false;                  /* Entry not found */
     }
@@ -344,7 +344,7 @@ bool ch_link(inoptr wd, char *oldname, char *newname, inoptr nindex)
         curentry.d_ino = 0;
 
     /* If an existing slot is being used, we must back up the file offset */
-    if(udata.u_count){
+    if(udata.u_done){
         udata.u_offset -= DIR_LEN;
     }
 
index 54985c9..e21aaeb 100644 (file)
@@ -883,6 +883,7 @@ extern arg_t unlinki(inoptr ino, inoptr pino, char *fname);
 
 /* inode.c */
 extern void readi(inoptr ino, uint8_t flag);
+extern uint16_t umove(uint16_t n);     /* Probably wants to move ? */
 extern void writei(inoptr ino, uint8_t flag);
 extern int16_t doclose (uint8_t uindex);
 extern inoptr rwsetup (bool is_read, uint8_t *flag);
index 920fb81..340c5db 100644 (file)
@@ -32,11 +32,25 @@ static uint16_t uoff(void)
        return BLKOFF((uint16_t)udata.u_offset);
 }
 
+uint16_t umove(uint16_t n)
+{
+       udata.u_offset += n;
+       udata.u_count -= n;
+       udata.u_done += n;
+       udata.u_base += n;
+       return udata.u_done;
+}
+
+static uint16_t mapcalc(inoptr ino, uint16_t *size, uint8_t m)
+{
+       *size = min(udata.u_count, BLKSIZE - uoff());
+       return bmap(ino, udata.u_offset >> BLKSHIFT, m);
+}
+
 /* Writei (and readi) need more i/o error handling */
 void readi(regptr inoptr ino, uint8_t flag)
 {
        usize_t amount;
-       usize_t toread;
        blkno_t pblk;
        bufptr bp;
        uint16_t dev;
@@ -44,6 +58,8 @@ void readi(regptr inoptr ino, uint8_t flag)
 
        dev = ino->c_dev;
        ispipe = false;
+       udata.u_done = 0;
+
        switch (getmode(ino)) {
        case MODE_R(F_DIR):
        case MODE_R(F_REG):
@@ -59,7 +75,7 @@ void readi(regptr inoptr ino, uint8_t flag)
 
         case MODE_R(F_SOCK):
 #ifdef CONFIG_NET
-                udata.u_count = sock_read(ino, flag);
+                udata.u_done = sock_read(ino, flag);
                 break;
 #endif
        case MODE_R(F_PIPE):
@@ -73,10 +89,8 @@ void readi(regptr inoptr ino, uint8_t flag)
                dev = *(ino->c_node.i_addr);
 
              loop:
-               toread = udata.u_count;
-               while (toread) {
-                       amount = min(toread, BLKSIZE - uoff());
-                       pblk = bmap(ino, udata.u_offset >> BLKSHIFT, 1);
+               while (udata.u_count) {
+                       pblk = mapcalc(ino, &amount, 1);
 
 #if defined(read_direct)
                        if (!ispipe && pblk != NULLBLK && amount == BLKSIZE && read_direct(flag) && bfind(dev, pblk) == 0) {
@@ -111,28 +125,22 @@ void readi(regptr inoptr ino, uint8_t flag)
                        /* Bletch */
 #if defined(__M6809__)
                         gcc_miscompile_workaround();
-#endif                        
-                       udata.u_base += amount;
-                       udata.u_offset += amount;
+#endif
+                       umove(amount);
                        if (ispipe && (uint16_t)udata.u_offset >= 18 * BLKSIZE)
                                udata.u_offset = 0;
-                       toread -= amount;
                        if (ispipe) {
                                ino->c_node.i_size -= amount;
                                wakeup(ino);
                        }
                }
                /* Compute return value */
-               udata.u_count -= toread;
-               if (udata.u_count == 0 && udata.u_error)
-                       udata.u_count = (usize_t) -1;
+               if (udata.u_done == 0 && udata.u_error)
+                       udata.u_done = (usize_t) -1;
                break;
 
        case MODE_R(F_CDEV):
-               udata.u_count = cdread(ino->c_node.i_addr[0], flag);
-
-               if (udata.u_count != (usize_t)-1)
-                       udata.u_offset += udata.u_count;
+               udata.u_done = cdread(ino->c_node.i_addr[0], flag);
                break;
 
        default:
@@ -145,22 +153,18 @@ void readi(regptr inoptr ino, uint8_t flag)
 void writei(regptr inoptr ino, uint8_t flag)
 {
        usize_t amount;
-       usize_t towrite;
        bufptr bp;
-       bool ispipe;
+       bool ispipe = false;
        blkno_t pblk;
        uint16_t dev;
 
        dev = ino->c_dev;
+       udata.u_done = 0;
 
        switch (getmode(ino)) {
 
        case MODE_R(F_BDEV):
                dev = *(ino->c_node.i_addr);
-       case MODE_R(F_DIR):
-       case MODE_R(F_REG):
-               ispipe = false;
-               towrite = udata.u_count;
                goto loop;
 
 #ifdef CONFIG_NET
@@ -172,10 +176,10 @@ void writei(regptr inoptr ino, uint8_t flag)
                ispipe = true;
                /* FIXME: this will hang if you ever write > 16 * BLKSIZE
                   in one go - needs merging into the loop */
-               while ((towrite = udata.u_count) > (16 * BLKSIZE) - 
+               while (udata.u_count > (16 * BLKSIZE) -
                                        (uint16_t)ino->c_node.i_size) {
                        if (ino->c_readers == 0) {      /* No readers */
-                               udata.u_count = (usize_t)-1;
+                               udata.u_done = (usize_t)-1;
                                udata.u_error = EPIPE;
                                ssig(udata.u_ptab, SIGPIPE);
                                return;
@@ -186,11 +190,13 @@ void writei(regptr inoptr ino, uint8_t flag)
                }
                /* Sleep if empty pipe */
 
+       case MODE_R(F_DIR):
+       case MODE_R(F_REG):
              loop:
                flag = flag & O_SYNC ? 2 : 1;
 
-               while (towrite) {
-                       amount = min(towrite, BLKSIZE - uoff());
+               while (udata.u_count) {
+                       pblk = mapcalc(ino, &amount, 0);
 
                         if (udata.u_offset >> BLKOVERSIZE) {
                                 udata.u_error = EFBIG;
@@ -198,9 +204,7 @@ void writei(regptr inoptr ino, uint8_t flag)
                                 break;
                         }
 
-                       if ((pblk =
-                            bmap(ino, udata.u_offset >> BLKSHIFT,
-                                 0)) == NULLBLK)
+                       if (pblk == NULLBLK)
                                break;  /* No space to make more blocks */
 
                        /* If we are writing an entire block, we don't care
@@ -216,8 +220,7 @@ void writei(regptr inoptr ino, uint8_t flag)
                        if (bfree(bp, flag))
                                break;
 
-                       udata.u_base += amount;
-                       udata.u_offset += amount;
+                       umove(amount);
                        if (ispipe) {
                                if ((uint16_t)udata.u_offset >= 18 * 512)
                                        udata.u_offset = 0;
@@ -225,7 +228,6 @@ void writei(regptr inoptr ino, uint8_t flag)
                                /* Wake up any readers */
                                wakeup(ino);
                        }
-                       towrite -= amount;
                }
 
                /* Update size if file grew */
@@ -236,16 +238,12 @@ void writei(regptr inoptr ino, uint8_t flag)
                        }
                }
                /* Compute return value */
-               udata.u_count -= towrite;
-               if (udata.u_count == 0 && udata.u_error)
-                       udata.u_count = (usize_t) -1;
+               if (udata.u_done == 0 && udata.u_error)
+                       udata.u_done = (usize_t) -1;
                break;
 
        case MODE_R(F_CDEV):
-               udata.u_count = cdwrite(ino->c_node.i_addr[0], flag);
-
-               if (udata.u_count != -1)
-                       udata.u_offset += udata.u_count;
+               udata.u_done = cdwrite(ino->c_node.i_addr[0], flag);
                break;
        default:
                udata.u_error = ENODEV;
@@ -300,7 +298,6 @@ inoptr rwsetup(bool is_read, uint8_t * flag)
        udata.u_sysio = false;  /* I/O to user data space */
        udata.u_base = (unsigned char *) udata.u_argn1; /* buf */
        udata.u_count = (susize_t) udata.u_argn2;       /* nbytes */
-       udata.u_done = 0;               /* bytes done so far */
 
        if ((ino = getinode(udata.u_argn)) == NULLINODE) {
                /* kprintf("[WRS: rwsetup(): getinode(%x) fails]", udata.u_argn); */
index 78f4945..c9d1913 100644 (file)
@@ -79,7 +79,7 @@ arg_t _execve(void)
        udata.u_sysio = true;
 
        readi(ino, 0);
-       if (udata.u_count != 16) {
+       if (udata.u_done != 16) {
                udata.u_error = ENOEXEC;
                goto nogood;
        }
@@ -174,7 +174,7 @@ arg_t _execve(void)
                udata.u_count = bin_size;
                udata.u_sysio = false;
                readi(ino, 0);
-               if (udata.u_count != bin_size)
+               if (udata.u_done != bin_size)
                        goto nogood4;
                progptr += bin_size;
        }
index 0fd9cec..e1380d5 100644 (file)
@@ -146,7 +146,7 @@ arg_t _execve(void)
        udata.u_sysio = true;
 
        readi(ino, 0);
-       if (udata.u_count != sizeof(struct binfmt_flat)) {
+       if (udata.u_done != sizeof(struct binfmt_flat)) {
                udata.u_error = ENOEXEC;
                goto nogood;
        }
@@ -232,7 +232,7 @@ arg_t _execve(void)
                udata.u_count = bin_size;
                udata.u_sysio = false;
                readi(ino, 0);
-               if (udata.u_count != bin_size)
+               if (udata.u_done != bin_size)
                        goto nogood4;
        }
 
index 8e1de08..2d0e62b 100644 (file)
@@ -409,7 +409,7 @@ uint16_t nbytes;
 #define buf (char *)udata.u_argn1
 #define nbytes (susize_t)udata.u_argn2
 
-arg_t _read(void)
+arg_t readwrite(uint8_t reading)
 {
        inoptr ino;
        uint8_t flag;
@@ -425,13 +425,18 @@ arg_t _read(void)
        if (!valaddr(buf, nbytes))
                return -1;
        /* Set up u_base, u_offset, ino; check permissions, file num. */
-       if ((ino = rwsetup(true, &flag)) == NULLINODE)
+       if ((ino = rwsetup(reading, &flag)) == NULLINODE)
                return -1;      /* bomb out if error */
 
-       readi(ino, flag);
+       (reading ? readi : writei)(ino, flag);
        updoff();
 
-       return (udata.u_count);
+       return udata.u_done;
+}
+
+arg_t _read(void)
+{
+       return readwrite(1);
 }
 
 #undef d
@@ -479,27 +484,7 @@ uint16_t nbytes;
 
 arg_t _write(void)
 {
-       inoptr ino;
-       uint8_t flag;
-
-       if (!nbytes)
-               return 0;
-
-       if ((ssize_t)nbytes < 0) {
-               udata.u_error = EINVAL;
-               return -1;
-       }
-
-       if (!valaddr(buf, nbytes))
-               return -1;
-       /* Set up u_base, u_offset, ino; check permissions, file num. */
-       if ((ino = rwsetup(false, &flag)) == NULLINODE)
-               return (-1);    /* bomb out if error */
-
-       writei(ino, flag);
-       updoff();
-
-       return (udata.u_count);
+       return readwrite(0);
 }
 
 #undef d