9ns: make kstrdup() actually atomic
[akaros.git] / kern / src / ns / chan.c
index 02f11fd..af83d1b 100644 (file)
@@ -118,8 +118,8 @@ void kstrdup(char **p, char *s)
                        panic("kstrdup: no memory");
        }
        memmove(t, s, n);
-       prev = *p;
-       *p = t;
+
+       prev = atomic_swap_ptr((void**)p, t);
        kfree(prev);
 }
 
@@ -331,7 +331,7 @@ void cclose(struct chan *c)
                return;
 
        if (c->flag & CFREE)
-               panic("cclose %p", getcallerpc(&c));
+               panic("double cclose %p.  maybe kfunc channame and hexdump", c);
 
        kref_put(&c->ref);
 }
@@ -426,6 +426,14 @@ int cmount(struct chan *new, struct chan *old, int flag, char *spec)
        struct mhead *m, **l, *mh;
        struct mount *nm, *f, *um, **h;
 
+       /* Can't bind pointing to a symlink, since it vastly complicates namec
+        * and walk.  In particular, walk() only follows mounts on the
+        * intermediate path elements.  Grep 'ntry - 1'.  Because of that,
+        * walk() can end on a symlink.  Having domount() follow symlinks is a
+        * pain: undomount. */
+       if (new->qid.type & QTSYMLINK)
+               error(EINVAL, "cannot bind a symlink");
+
        /* Can bind anything onto a symlink's name.  Otherwise, both the old and
         * the new must agree on whether or not it is a directory. */
        if (!(old->qid.type & QTSYMLINK) &&
@@ -886,27 +894,7 @@ int walk(struct chan **cp, char **names, int nnames, struct walk_helper *wh,
                                        return -1;
                                }
                                n = wq->nqid;
-                               if (wq->clone->qid.type & QTSYMLINK) {
-                                       nc = walk_symlink(wq->clone, wh, nnames
-                                                         - nhave - n);
-                                       if (!nc) {
-                                               /* walk_symlink() set error.
-                                                * This seems to be the standard
-                                                * walk() error-cleanup. */
-                                               if (nerror)
-                                                       *nerror = nhave +
-                                                               wq->nqid;
-                                               cclose(c);
-                                               cclose(wq->clone);
-                                               cnameclose(cname);
-                                               kfree(wq);
-                                               if (mh != NULL)
-                                                       putmhead(mh);
-                                               return -1;
-                                       }
-                               } else {
-                                       nc = wq->clone;
-                               }
+                               nc = wq->clone;
                        } else {        /* stopped early, at a mount point */
                                if (wq->clone != NULL) {
                                        cclose(wq->clone);
@@ -915,6 +903,26 @@ int walk(struct chan **cp, char **names, int nnames, struct walk_helper *wh,
                                lastmountpoint = nc;
                                n = i + 1;
                        }
+                       if (nc->qid.type & QTSYMLINK) {
+                               struct chan *old_nc = nc;
+
+                               nc = walk_symlink(old_nc, wh,
+                                                 nnames - nhave - n);
+                               if (!nc) {
+                                       /* walk_symlink() set error.
+                                        * This seems to be the standard
+                                        * walk() error-cleanup. */
+                                       if (nerror)
+                                               *nerror = nhave + n;
+                                       cclose(c);
+                                       cclose(old_nc);
+                                       cnameclose(cname);
+                                       kfree(wq);
+                                       if (mh != NULL)
+                                               putmhead(mh);
+                                       return -1;
+                               }
+                       }
                        for (i = 0; i < n; i++)
                                cname = addelem(cname, names[nhave + i]);
                }
@@ -1293,6 +1301,8 @@ Open:
                 * the way out, we putmhead if we have an m, and clean up our
                 * chans.  On success, c becomes cnew (thus close the old c).
                 * On failure, we just close cnew. */
+               if (!(c->qid.type & QTDIR))
+                       error(ENOTDIR, "rename target parent is not a dir");
                e.ARRAY_SIZEs++;
                m = NULL;
                cnew = NULL;