lkml.org 
[lkml]   [1998]   [May]   [29]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subjectpatch 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)
\
 
 \ /
  Last update: 2005-03-22 13:42    [W:0.051 / U:0.024 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site