x86: sends the EOI later in the IRQ path
[akaros.git] / kern / src / vfs.c
index 6b6e4ff..7b4c298 100644 (file)
@@ -1750,6 +1750,13 @@ ssize_t pipe_file_write(struct file *file, const char *buf, size_t count,
                }
                cv_wait(&pii->p_cv);
                cpu_relax();
+               /* Still need to check in the loop, in case the last reader left while
+                * we slept. */
+               if (!pii->p_nr_readers) {
+                       cv_unlock(&pii->p_cv);
+                       set_errno(EPIPE);
+                       return -1;
+               }
        }
        /* We might need to wrap-around with our copy, so we'll do the copy in two
         * passes.  This will copy up to the end of the buffer, then on the next
@@ -1780,9 +1787,9 @@ int pipe_open(struct inode *inode, struct file *file)
        struct pipe_inode_info *pii = inode->i_pipe;
        cv_lock(&pii->p_cv);
        /* Ugliness due to not using flags for O_RDONLY and friends... */
-       if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
+       if (file->f_mode == S_IRUSR) {
                pii->p_nr_readers++;
-       } else if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
+       } else if (file->f_mode == S_IWUSR) {
                pii->p_nr_writers++;
        } else {
                warn("Bad pipe file flags 0x%x\n", file->f_flags);
@@ -1796,13 +1803,15 @@ int pipe_release(struct inode *inode, struct file *file)
        struct pipe_inode_info *pii = inode->i_pipe;
        cv_lock(&pii->p_cv);
        /* Ugliness due to not using flags for O_RDONLY and friends... */
-       if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
+       if (file->f_mode == S_IRUSR) {
                pii->p_nr_readers--;
-       } else if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
+       } else if (file->f_mode == S_IWUSR) {
                pii->p_nr_writers--;
        } else {
                warn("Bad pipe file flags 0x%x\n", file->f_flags);
        }
+       /* need to wake up any sleeping readers/writers, since we might be done */
+       __cv_broadcast(&pii->p_cv);
        cv_unlock(&pii->p_cv);
        return 0;
 }
@@ -1815,6 +1824,19 @@ struct file_operations pipe_f_op = {
        0
 };
 
+void pipe_debug(struct file *f)
+{
+       struct pipe_inode_info *pii = f->f_dentry->d_inode->i_pipe;
+       assert(pii);
+       printk("PIPE %p\n", pii);
+       printk("\trdoff %p\n", pii->p_rd_off);
+       printk("\twroff %p\n", pii->p_wr_off);
+       printk("\tnr_rds %d\n", pii->p_nr_readers);
+       printk("\tnr_wrs %d\n", pii->p_nr_writers);
+       printk("\tcv waiters %d\n", pii->p_cv.nr_waiters);
+
+}
+
 /* General plan: get a dentry/inode to represent the pipe.  We'll alloc it from
  * the default_ns SB, but won't actually link it anywhere.  It'll only be held
  * alive by the krefs, til all the FDs are closed. */
@@ -1831,10 +1853,8 @@ int do_pipe(struct file **pipe_files, int flags)
                return -1;
        pipe_d->d_op = &dummy_d_op;
        pipe_i = get_inode(pipe_d);
-       if (!pipe_i) {
-               set_errno(ENOMEM);
-               goto error_with_dentry;
-       }
+       if (!pipe_i)
+               goto error_post_dentry;
        /* preemptively mark the dentry for deletion.  we have an unlinked dentry
         * right off the bat, held in only by the kref chain (pipe_d is the ref). */
        pipe_d->d_flags |= DENTRY_DYING;
@@ -1865,32 +1885,41 @@ int do_pipe(struct file **pipe_files, int flags)
        pii = pipe_i->i_pipe;
        if (!pii) {
                set_errno(ENOMEM);
-               goto error_with_dentry;
+               goto error_kmalloc;
        }
        pii->p_buf = kpage_zalloc_addr();
        if (!pii->p_buf) {
                set_errno(ENOMEM);
-               goto error_with_dentry;
+               goto error_kpage;
        }
        pii->p_rd_off = 0;
        pii->p_wr_off = 0;
+       pii->p_nr_readers = 0;
+       pii->p_nr_writers = 0;
        cv_init(&pii->p_cv);    /* must do this before dentry_open / pipe_open */
        /* Now we have an inode for the pipe.  We need two files for the read and
         * write ends of the pipe. */
        flags &= ~(O_ACCMODE);  /* avoid user bugs */
        pipe_f_read = dentry_open(pipe_d, flags | O_RDONLY);
        if (!pipe_f_read)
-               goto error_with_dentry;
+               goto error_f_read;
        pipe_f_write = dentry_open(pipe_d, flags | O_WRONLY);
-       if (!pipe_f_write) {
-               kref_put(&pipe_f_read->f_kref);
-               goto error_with_dentry;
-       }
+       if (!pipe_f_write)
+               goto error_f_write;
        pipe_files[0] = pipe_f_read;
        pipe_files[1] = pipe_f_write;
        return 0;
+
+error_f_write:
+       kref_put(&pipe_f_read->f_kref);
+error_f_read:
+       page_decref(kva2page(pii->p_buf));
+error_kpage:
+       kfree(pipe_i->i_pipe);
+error_kmalloc:
+       /* We don't need to free the pipe_i; putting the dentry will free it */
+error_post_dentry:
        /* Note we only free the dentry on failure. */
-error_with_dentry:
        kref_put(&pipe_d->d_kref);
        return -1;
 }