static int unix_read(struct socket *sock, char *ubuf, int size, int nonblock) { struct unix_proto_data *upd; int todo, avail; if ((todo = size) <= 0) return 0; upd = UN_DATA(sock); while (!(avail = UN_BUF_AVAIL(upd))) { if (sock->state != SS_CONNECTED) return ((sock->state == SS_DISCONNECTING) ? 0 : -EINVAL); if (nonblock) return -EAGAIN; sock->flags |= SO_WAITDATA; interruptible_sleep_on(sock->wait); sock->flags &= ~SO_WAITDATA; if (current->signal /* & ~current->blocked */ ) return -ERESTARTSYS; } /* * Copy from the read buffer into the user's buffer, * watching for wraparound. Then we wake up the writer. */ down(&upd->sem); do { int part, cando; if (avail <= 0) { printk("UNIX: read: AVAIL IS NEGATIVE (%d)!!!\n", avail); send_sig(SIGKILL, current, 1); return -EPIPE; } if ((cando = todo) > avail) cando = avail; if (cando > (part = UN_BUF_SIZE - upd->bp_tail)) cando = part; memcpy_tofs(ubuf, upd->buf + upd->bp_tail, cando); upd->bp_tail = (upd->bp_tail + cando) & (UN_BUF_SIZE - 1); ubuf += cando; todo -= cando; if (sock->state == SS_CONNECTED) { wake_up_interruptible(sock->conn->wait); #if 0 sock_wake_async(sock->conn, 2); #endif } avail = UN_BUF_AVAIL(upd); } while (todo && avail); up(&upd->sem); return (size - todo); }
static int unix_write(struct socket *sock, char *ubuf, int size, int nonblock) { struct unix_proto_data *pupd; int todo, space; if ((todo = size) <= 0) return 0; if (sock->state != SS_CONNECTED) { if (sock->state == SS_DISCONNECTING) { send_sig(SIGPIPE, current, 1); return -EPIPE; } return -EINVAL; } pupd = UN_DATA(sock)->peerupd; /* safer than sock->conn */ while (!(space = UN_BUF_SPACE(pupd))) { sock->flags |= SO_NOSPACE; if (nonblock) return -EAGAIN; sock->flags &= ~SO_NOSPACE; interruptible_sleep_on(sock->wait); if (current->signal /* & ~current->blocked */ ) return -ERESTARTSYS; if (sock->state == SS_DISCONNECTING) { send_sig(SIGPIPE, current, 1); return -EPIPE; } } /* * Copy from the user's buffer to the write buffer, * watching for wraparound. Then we wake up the reader. */ down(&pupd->sem); do { int part, cando; if (space <= 0) { printk("UNIX: write: SPACE IS NEGATIVE (%d)!!!\n", space); send_sig(SIGKILL, current, 1); return -EPIPE; } /* * We may become disconnected inside this loop, so watch * for it (peerupd is safe until we close). */ if (sock->state == SS_DISCONNECTING) { send_sig(SIGPIPE, current, 1); up(&pupd->sem); return -EPIPE; } if ((cando = todo) > space) cando = space; if (cando > (part = UN_BUF_SIZE - pupd->bp_head)) cando = part; memcpy_fromfs(pupd->buf + pupd->bp_head, ubuf, cando); pupd->bp_head = (pupd->bp_head + cando) & (UN_BUF_SIZE - 1); ubuf += cando; todo -= cando; if (sock->state == SS_CONNECTED) { wake_up_interruptible(sock->conn->wait); #if 0 sock_wake_async(sock->conn, 1); #endif } space = UN_BUF_SPACE(pupd); } while (todo && space); up(&pupd->sem); return (size - todo); }
/* * we write to our peer's buf. when we connected we ref'd this peer so we * are safe that the buffer remains, even after the peer has disconnected, * which we check other ways. */ static int unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock) { struct unix_proto_data *pupd; int todo, space; if ((todo = size) <= 0) return 0; if (sock->state != SS_CONNECTED) { PRINTK("unix_proto_write: socket not connected\n"); if (sock->state == SS_DISCONNECTING) { send_sig(SIGPIPE,current,1); return -EINTR; } return -EINVAL; } pupd = UN_DATA(sock)->peerupd; /* safer than sock->conn */ while (!(space = UN_BUF_SPACE(pupd))) { PRINTK("unix_proto_write: no space left...\n"); if (nonblock) return -EAGAIN; interruptible_sleep_on(sock->wait); if (current->signal & ~current->blocked) { PRINTK("unix_proto_write: interrupted\n"); return -ERESTARTSYS; } if (sock->state == SS_DISCONNECTING) { PRINTK("unix_proto_write: disconnected (SIGPIPE)\n"); send_sig(SIGPIPE,current,1); return -EINTR; } } /* * copy from the user's buffer to the write buffer, watching for * wraparound. then we wake up the reader */ do { int part, cando; if (space <= 0) { PRINTK("unix_proto_write: SPACE IS NEGATIVE!!!\n"); send_sig(SIGKILL,current,1); return -EINTR; } /* * we may become disconnected inside this loop, so watch * for it (peerupd is safe until we close) */ if (sock->state == SS_DISCONNECTING) { send_sig(SIGPIPE,current,1); return -EINTR; } if ((cando = todo) > space) cando = space; if (cando > (part = BUF_SIZE - pupd->bp_head)) cando = part; PRINTK("unix_proto_write: space=%d, todo=%d, cando=%d\n", space, todo, cando); verify_area(ubuf, cando); memcpy_fromfs(pupd->buf + pupd->bp_head, ubuf, cando); pupd->bp_head = (pupd->bp_head + cando) & (BUF_SIZE-1); ubuf += cando; todo -= cando; if (sock->state == SS_CONNECTED) wake_up(sock->conn->wait); space = UN_BUF_SPACE(pupd); } while (todo && space); return size - todo; }