Properly extract errno from p9 rpc; fix incorrect mkdir error
authorRonald G. Minnich <rminnich@google.com>
Thu, 30 Jan 2014 18:08:04 +0000 (10:08 -0800)
committerRonald G. Minnich <rminnich@google.com>
Thu, 30 Jan 2014 18:08:04 +0000 (10:08 -0800)
mkdir /mnt/tmp/xxx would fail with the wrong errno (EEXIST)
because we could not properly get errno from the Plan 9 RPC.

I've fixed my version of go9p (github.com/rminnich/go9p) to
return Rerror strings in the form 'XXXX error message'
(space after XXXX is important) where XXXX is the hex-encoded
errno (this is how I did it for the original Linux 9p in 1998).
This format has the advantage of being all text; later implementations
(e.g. 9p2000.[ul]) break the rule and embed binary data in the string
and were a backward step IMHO.

I've fixed Akaros 9p parsing to look for a string at least 5 bytes long,
with the first 4 bytes being hex digits, and if that is the case to
set_errno using those digits.

I added get_errno to allow code to save the current errno value.

Finally, in the namec create case, I save errno as well as errstr
and restore them on the errpath.

mkdir /mnt/tmp/xxx now returns the correct errno/error message.

Signed-off-by: Ronald G. Minnich <rminnich@google.com>
kern/drivers/dev/mnt.c
kern/include/syscall.h
kern/src/ns/chan.c
kern/src/syscall.c

index 55d4943..09a324e 100644 (file)
 
 #define MAXRPC (IOHDRSZ+8192)
 
+static __inline int isxdigit(int c)
+{
+       if ((c >= '0') && (c <= '9'))
+               return 1;
+       if ((c >= 'a') && (c <= 'f'))
+               return 1;
+       if ((c >= 'A') && (c <= 'F'))
+               return 1;
+       return 0;
+}
+
 struct mntrpc {
        struct chan *c;                         /* Channel for whom we are working */
        struct mntrpc *list;            /* Free/pending list */
@@ -746,6 +757,7 @@ void mountrpc(struct mnt *m, struct mntrpc *r)
 {
        char *sn, *cn;
        int t;
+       char *e;
 
        r->reply.tag = 0;
        r->reply.type = Tmax;   /* can't ever be a valid message type */
@@ -755,7 +767,20 @@ void mountrpc(struct mnt *m, struct mntrpc *r)
        t = r->reply.type;
        switch (t) {
                case Rerror:
-                       error(r->reply.ename);
+                       /* in Akaros mode, first four characters
+                        * are errno.
+                        */
+                       e = r->reply.ename;
+                       /* If it is in the format "XXXX <at least one char>" */
+                       if ((strlen(e) > 5) && isxdigit(e[0]) &&
+                               isxdigit(e[1]) &&
+                               isxdigit(e[2]) &&
+                               isxdigit(e[3])) {
+                               int errno = strtoul(e, NULL, 16);
+                               set_errno(errno);
+                               error(&r->reply.ename[5]);
+                       } else
+                               error(r->reply.ename);
                case Rflush:
                        error(Eintr);
                default:
index 07c4999..2b6f533 100644 (file)
@@ -45,6 +45,7 @@ void run_local_syscall(struct syscall *sysc);
 intreg_t syscall(struct proc *p, uintreg_t sc_num, uintreg_t a0, uintreg_t a1,
                  uintreg_t a2, uintreg_t a3, uintreg_t a4, uintreg_t a5);
 void set_errno(int errno);
+int get_errno(void);
 void unset_errno(void);
 void set_errstr(char *errstr, ...);
 char *current_errstr(void);
index e01aa5c..8b9caea 100644 (file)
@@ -947,6 +947,7 @@ struct chan *namec(char *aname, int amode, int omode, uint32_t perm)
        Elemlist e;
        struct mhead *m;
        char tmperrbuf[ERRMAX];
+       int saved_errno;
        char *name;
        // Rune r;
 
@@ -1277,8 +1278,10 @@ Open:
 
                        /* save error, so walk doesn't clobber our existing errstr */
                        strncpy(tmperrbuf, current_errstr(), MAX_ERRSTR_LEN);
+                       saved_errno = get_errno();
                        /* note: we depend that walk does not error */
                        if (walk(&c, e.elems + e.ARRAY_SIZEs - 1, 1, nomount, NULL) < 0) {
+                               set_errno(saved_errno);
                                error(tmperrbuf);       /* report the error we had originally */
                        }
                        strncpy(current_errstr(), tmperrbuf, MAX_ERRSTR_LEN);
index 2730872..821a1ea 100644 (file)
@@ -95,6 +95,18 @@ void set_errno(int errno)
                pcpui->cur_kthread->sysc->err = errno;
 }
 
+/* Callable by any function while executing a syscall (or otherwise, actually).
+ */
+int get_errno(void)
+{
+       /* if there's no errno to get, that's not an error I guess. */
+       int errno = 0;
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
+       if (pcpui->cur_kthread && pcpui->cur_kthread->sysc)
+               errno = pcpui->cur_kthread->sysc->err;
+       return errno;
+}
+
 void unset_errno(void)
 {
        struct per_cpu_info *pcpui = &per_cpu_info[core_id()];