Messages in this thread Patch in this message | | | Date | Fri, 29 May 1998 10:27:33 -0400 | From | Bill Hawes <> | Subject | patch for 2.1.103 fs/pipe.c |
| |
Jeanette Pauline Middelink wrote:
> Hmm, the same happens for a pipe_read. In linux-2.0.x that one > also returned immediatly (due to the check on 0 in sys_read). > But an read of a pipe (0 bytes as count) still blocks... > > I'm nt sure what the proper semantics for the read call are. > Shouldn't it at least be the same for all read's? pipe, > tty, fs, network, unix?
Hi Pauline,
I've attached a patch for pipe.c that should fix the blocking on 0 byte reads, as well as cleaning up some redundant code and checking for faults with the copy_xx_user calls. If you could give this a test and let me know if everything is OK now ...
Regards, Bill--- linux-2.1.103/fs/pipe.c.old Sun May 17 12:19:37 1998 +++ linux-2.1.103/fs/pipe.c Fri May 29 10:11:58 1998 @@ -37,109 +37,126 @@ size_t count, loff_t *ppos) { struct inode * inode = filp->f_dentry->d_inode; - ssize_t chars = 0, size = 0, read = 0; - char *pipebuf; + size_t size = 0, read = 0; + ssize_t retval = 0; if (ppos != &filp->f_pos) return -ESPIPE; + if (!count) + return 0; - if (filp->f_flags & O_NONBLOCK) { - if (PIPE_LOCK(*inode)) - return -EAGAIN; - if (PIPE_EMPTY(*inode)) { - if (PIPE_WRITERS(*inode)) - return -EAGAIN; - else - return 0; - } - } else while (PIPE_EMPTY(*inode) || PIPE_LOCK(*inode)) { + /* + * Make sure data is available and we're not locked. + */ + while (1) { if (PIPE_EMPTY(*inode)) { - if (!PIPE_WRITERS(*inode) || !count) + if (!PIPE_WRITERS(*inode)) return 0; - } + } else if (!PIPE_LOCK(*inode)) + break; + + if (filp->f_flags & O_NONBLOCK) + return -EAGAIN; if (signal_pending(current)) return -ERESTARTSYS; interruptible_sleep_on(&PIPE_WAIT(*inode)); } + PIPE_LOCK(*inode)++; - while (count>0 && (size = PIPE_SIZE(*inode))) { - chars = PIPE_MAX_RCHUNK(*inode); + while (count && (size = PIPE_SIZE(*inode))) { + char *pipebuf = PIPE_BASE(*inode)+PIPE_START(*inode); + size_t chars = PIPE_MAX_RCHUNK(*inode); + if (chars > count) chars = count; if (chars > size) chars = size; + if (copy_to_user(buf, pipebuf, chars)) { + retval = -EFAULT; + break; + } + buf += chars; read += chars; - pipebuf = PIPE_BASE(*inode)+PIPE_START(*inode); PIPE_START(*inode) += chars; PIPE_START(*inode) &= (PIPE_BUF-1); PIPE_LEN(*inode) -= chars; count -= chars; - copy_to_user(buf, pipebuf, chars ); - buf += chars; } PIPE_LOCK(*inode)--; wake_up_interruptible(&PIPE_WAIT(*inode)); if (read) { + retval = read; UPDATE_ATIME(inode); - return read; } - if (PIPE_WRITERS(*inode)) - return -EAGAIN; - return 0; + return retval; } static ssize_t pipe_write(struct file * filp, const char * buf, size_t count, loff_t *ppos) { struct inode * inode = filp->f_dentry->d_inode; - ssize_t chars = 0, free = 0, written = 0; - char *pipebuf; + size_t free = 1, written = 0; + ssize_t retval = 0; if (ppos != &filp->f_pos) return -ESPIPE; + if (!count) + return 0; - if (!PIPE_READERS(*inode)) { /* no readers */ - send_sig(SIGPIPE,current,0); - return -EPIPE; - } - /* if count <= PIPE_BUF, we have to make it atomic */ + /* + * if count <= PIPE_BUF, we have to make it atomic; otherwise + * we can't do it atomically, wait for any free space. + */ if (count <= PIPE_BUF) free = count; - else - free = 1; /* can't do it atomically, wait for any free space */ - while (count>0) { - while ((PIPE_FREE(*inode) < free) || PIPE_LOCK(*inode)) { - if (!PIPE_READERS(*inode)) { /* no readers */ - send_sig(SIGPIPE,current,0); - return written? :-EPIPE; + + while (count) { + if (!PIPE_READERS(*inode)) { /* no readers */ + send_sig(SIGPIPE,current,0); + retval = -EPIPE; + goto out; + } + if ((PIPE_FREE(*inode) < free) || PIPE_LOCK(*inode)) { + if (signal_pending(current)) { + retval = -ERESTARTSYS; + goto out; + } + if (filp->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + goto out; } - if (signal_pending(current)) - return written? :-ERESTARTSYS; - if (filp->f_flags & O_NONBLOCK) - return written? :-EAGAIN; interruptible_sleep_on(&PIPE_WAIT(*inode)); + continue; } PIPE_LOCK(*inode)++; - while (count>0 && (free = PIPE_FREE(*inode))) { - chars = PIPE_MAX_WCHUNK(*inode); + while (count && (free = PIPE_FREE(*inode))) { + char *pipebuf = PIPE_BASE(*inode)+PIPE_END(*inode); + size_t chars = PIPE_MAX_WCHUNK(*inode); + if (chars > count) chars = count; if (chars > free) chars = free; - pipebuf = PIPE_BASE(*inode)+PIPE_END(*inode); + if (copy_from_user(pipebuf, buf, chars)) { + retval = -EFAULT; + goto out; + } written += chars; + buf += chars; PIPE_LEN(*inode) += chars; count -= chars; - copy_from_user(pipebuf, buf, chars ); - buf += chars; } PIPE_LOCK(*inode)--; wake_up_interruptible(&PIPE_WAIT(*inode)); free = 1; } - inode->i_ctime = inode->i_mtime = CURRENT_TIME; - mark_inode_dirty(inode); - return written; +out: + if (written) { + retval = written; + inode->i_ctime = inode->i_mtime = CURRENT_TIME; + mark_inode_dirty(inode); + } + return retval; } static long long pipe_lseek(struct file * file, long long offset, int orig) | |