/*
|
/*
|
* linux/fs/pipe.c
|
* linux/fs/pipe.c
|
*
|
*
|
* Copyright (C) 1991, 1992 Linus Torvalds
|
* Copyright (C) 1991, 1992 Linus Torvalds
|
*/
|
*/
|
|
|
#include <asm/segment.h>
|
#include <asm/segment.h>
|
|
|
#include <linux/sched.h>
|
#include <linux/sched.h>
|
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
#include <linux/errno.h>
|
#include <linux/errno.h>
|
#include <linux/signal.h>
|
#include <linux/signal.h>
|
#include <linux/fcntl.h>
|
#include <linux/fcntl.h>
|
#include <linux/termios.h>
|
#include <linux/termios.h>
|
#include <linux/mm.h>
|
#include <linux/mm.h>
|
|
|
/*
|
/*
|
* Define this if you want SunOS compatibility wrt braindead
|
* Define this if you want SunOS compatibility wrt braindead
|
* select behaviour on FIFO's.
|
* select behaviour on FIFO's.
|
*/
|
*/
|
#undef FIFO_SUNOS_BRAINDAMAGE
|
#undef FIFO_SUNOS_BRAINDAMAGE
|
|
|
/* We don't use the head/tail construction any more. Now we use the start/len*/
|
/* We don't use the head/tail construction any more. Now we use the start/len*/
|
/* construction providing full use of PIPE_BUF (multiple of PAGE_SIZE) */
|
/* construction providing full use of PIPE_BUF (multiple of PAGE_SIZE) */
|
/* Florian Coosmann (FGC) ^ current = 1 */
|
/* Florian Coosmann (FGC) ^ current = 1 */
|
/* Additionally, we now use locking technique. This prevents race condition */
|
/* Additionally, we now use locking technique. This prevents race condition */
|
/* in case of paging and multiple read/write on the same pipe. (FGC) */
|
/* in case of paging and multiple read/write on the same pipe. (FGC) */
|
|
|
|
|
static int pipe_read(struct inode * inode, struct file * filp, char * buf, int count)
|
static int pipe_read(struct inode * inode, struct file * filp, char * buf, int count)
|
{
|
{
|
int chars = 0, size = 0, read = 0;
|
int chars = 0, size = 0, read = 0;
|
char *pipebuf;
|
char *pipebuf;
|
|
|
if (filp->f_flags & O_NONBLOCK) {
|
if (filp->f_flags & O_NONBLOCK) {
|
if (PIPE_LOCK(*inode))
|
if (PIPE_LOCK(*inode))
|
return -EAGAIN;
|
return -EAGAIN;
|
if (PIPE_EMPTY(*inode))
|
if (PIPE_EMPTY(*inode))
|
if (PIPE_WRITERS(*inode))
|
if (PIPE_WRITERS(*inode))
|
return -EAGAIN;
|
return -EAGAIN;
|
else
|
else
|
return 0;
|
return 0;
|
} else while (PIPE_EMPTY(*inode) || PIPE_LOCK(*inode)) {
|
} else while (PIPE_EMPTY(*inode) || PIPE_LOCK(*inode)) {
|
if (PIPE_EMPTY(*inode)) {
|
if (PIPE_EMPTY(*inode)) {
|
if (!PIPE_WRITERS(*inode))
|
if (!PIPE_WRITERS(*inode))
|
return 0;
|
return 0;
|
}
|
}
|
if (current->signal & ~current->blocked)
|
if (current->signal & ~current->blocked)
|
return -ERESTARTSYS;
|
return -ERESTARTSYS;
|
interruptible_sleep_on(&PIPE_WAIT(*inode));
|
interruptible_sleep_on(&PIPE_WAIT(*inode));
|
}
|
}
|
PIPE_LOCK(*inode)++;
|
PIPE_LOCK(*inode)++;
|
while (count>0 && (size = PIPE_SIZE(*inode))) {
|
while (count>0 && (size = PIPE_SIZE(*inode))) {
|
chars = PIPE_MAX_RCHUNK(*inode);
|
chars = PIPE_MAX_RCHUNK(*inode);
|
if (chars > count)
|
if (chars > count)
|
chars = count;
|
chars = count;
|
if (chars > size)
|
if (chars > size)
|
chars = size;
|
chars = size;
|
read += chars;
|
read += chars;
|
pipebuf = PIPE_BASE(*inode)+PIPE_START(*inode);
|
pipebuf = PIPE_BASE(*inode)+PIPE_START(*inode);
|
PIPE_START(*inode) += chars;
|
PIPE_START(*inode) += chars;
|
PIPE_START(*inode) &= (PIPE_BUF-1);
|
PIPE_START(*inode) &= (PIPE_BUF-1);
|
PIPE_LEN(*inode) -= chars;
|
PIPE_LEN(*inode) -= chars;
|
count -= chars;
|
count -= chars;
|
memcpy_tofs(buf, pipebuf, chars );
|
memcpy_tofs(buf, pipebuf, chars );
|
buf += chars;
|
buf += chars;
|
}
|
}
|
PIPE_LOCK(*inode)--;
|
PIPE_LOCK(*inode)--;
|
wake_up_interruptible(&PIPE_WAIT(*inode));
|
wake_up_interruptible(&PIPE_WAIT(*inode));
|
if (read) {
|
if (read) {
|
UPDATE_ATIME(inode);
|
UPDATE_ATIME(inode);
|
return read;
|
return read;
|
}
|
}
|
if (PIPE_WRITERS(*inode))
|
if (PIPE_WRITERS(*inode))
|
return -EAGAIN;
|
return -EAGAIN;
|
return 0;
|
return 0;
|
}
|
}
|
|
|
static int pipe_write(struct inode * inode, struct file * filp, const char * buf, int count)
|
static int pipe_write(struct inode * inode, struct file * filp, const char * buf, int count)
|
{
|
{
|
int chars = 0, free = 0, written = 0;
|
int chars = 0, free = 0, written = 0;
|
char *pipebuf;
|
char *pipebuf;
|
|
|
if (!PIPE_READERS(*inode)) { /* no readers */
|
if (!PIPE_READERS(*inode)) { /* no readers */
|
send_sig(SIGPIPE,current,0);
|
send_sig(SIGPIPE,current,0);
|
return -EPIPE;
|
return -EPIPE;
|
}
|
}
|
/* if count <= PIPE_BUF, we have to make it atomic */
|
/* if count <= PIPE_BUF, we have to make it atomic */
|
if (count <= PIPE_BUF)
|
if (count <= PIPE_BUF)
|
free = count;
|
free = count;
|
else
|
else
|
free = 1; /* can't do it atomically, wait for any free space */
|
free = 1; /* can't do it atomically, wait for any free space */
|
while (count>0) {
|
while (count>0) {
|
while ((PIPE_FREE(*inode) < free) || PIPE_LOCK(*inode)) {
|
while ((PIPE_FREE(*inode) < free) || PIPE_LOCK(*inode)) {
|
if (!PIPE_READERS(*inode)) { /* no readers */
|
if (!PIPE_READERS(*inode)) { /* no readers */
|
send_sig(SIGPIPE,current,0);
|
send_sig(SIGPIPE,current,0);
|
return written? :-EPIPE;
|
return written? :-EPIPE;
|
}
|
}
|
if (current->signal & ~current->blocked)
|
if (current->signal & ~current->blocked)
|
return written? :-ERESTARTSYS;
|
return written? :-ERESTARTSYS;
|
if (filp->f_flags & O_NONBLOCK)
|
if (filp->f_flags & O_NONBLOCK)
|
return written? :-EAGAIN;
|
return written? :-EAGAIN;
|
interruptible_sleep_on(&PIPE_WAIT(*inode));
|
interruptible_sleep_on(&PIPE_WAIT(*inode));
|
}
|
}
|
PIPE_LOCK(*inode)++;
|
PIPE_LOCK(*inode)++;
|
while (count>0 && (free = PIPE_FREE(*inode))) {
|
while (count>0 && (free = PIPE_FREE(*inode))) {
|
chars = PIPE_MAX_WCHUNK(*inode);
|
chars = PIPE_MAX_WCHUNK(*inode);
|
if (chars > count)
|
if (chars > count)
|
chars = count;
|
chars = count;
|
if (chars > free)
|
if (chars > free)
|
chars = free;
|
chars = free;
|
pipebuf = PIPE_BASE(*inode)+PIPE_END(*inode);
|
pipebuf = PIPE_BASE(*inode)+PIPE_END(*inode);
|
written += chars;
|
written += chars;
|
PIPE_LEN(*inode) += chars;
|
PIPE_LEN(*inode) += chars;
|
count -= chars;
|
count -= chars;
|
memcpy_fromfs(pipebuf, buf, chars );
|
memcpy_fromfs(pipebuf, buf, chars );
|
buf += chars;
|
buf += chars;
|
}
|
}
|
PIPE_LOCK(*inode)--;
|
PIPE_LOCK(*inode)--;
|
wake_up_interruptible(&PIPE_WAIT(*inode));
|
wake_up_interruptible(&PIPE_WAIT(*inode));
|
free = 1;
|
free = 1;
|
}
|
}
|
inode->i_ctime = inode->i_mtime = CURRENT_TIME;
|
inode->i_ctime = inode->i_mtime = CURRENT_TIME;
|
return written;
|
return written;
|
}
|
}
|
|
|
static int pipe_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
|
static int pipe_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
|
{
|
{
|
return -ESPIPE;
|
return -ESPIPE;
|
}
|
}
|
|
|
static int bad_pipe_r(struct inode * inode, struct file * filp, char * buf, int count)
|
static int bad_pipe_r(struct inode * inode, struct file * filp, char * buf, int count)
|
{
|
{
|
return -EBADF;
|
return -EBADF;
|
}
|
}
|
|
|
static int bad_pipe_w(struct inode * inode, struct file * filp, const char * buf, int count)
|
static int bad_pipe_w(struct inode * inode, struct file * filp, const char * buf, int count)
|
{
|
{
|
return -EBADF;
|
return -EBADF;
|
}
|
}
|
|
|
static int pipe_ioctl(struct inode *pino, struct file * filp,
|
static int pipe_ioctl(struct inode *pino, struct file * filp,
|
unsigned int cmd, unsigned long arg)
|
unsigned int cmd, unsigned long arg)
|
{
|
{
|
int error;
|
int error;
|
|
|
switch (cmd) {
|
switch (cmd) {
|
case FIONREAD:
|
case FIONREAD:
|
error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
|
error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
|
if (!error)
|
if (!error)
|
put_user(PIPE_SIZE(*pino),(int *) arg);
|
put_user(PIPE_SIZE(*pino),(int *) arg);
|
return error;
|
return error;
|
default:
|
default:
|
return -EINVAL;
|
return -EINVAL;
|
}
|
}
|
}
|
}
|
|
|
static int pipe_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait)
|
static int pipe_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait)
|
{
|
{
|
switch (sel_type) {
|
switch (sel_type) {
|
case SEL_IN:
|
case SEL_IN:
|
if (!PIPE_EMPTY(*inode) || !PIPE_WRITERS(*inode))
|
if (!PIPE_EMPTY(*inode) || !PIPE_WRITERS(*inode))
|
return 1;
|
return 1;
|
select_wait(&PIPE_WAIT(*inode), wait);
|
select_wait(&PIPE_WAIT(*inode), wait);
|
return 0;
|
return 0;
|
case SEL_OUT:
|
case SEL_OUT:
|
if (PIPE_EMPTY(*inode) || !PIPE_READERS(*inode))
|
if (PIPE_EMPTY(*inode) || !PIPE_READERS(*inode))
|
return 1;
|
return 1;
|
select_wait(&PIPE_WAIT(*inode), wait);
|
select_wait(&PIPE_WAIT(*inode), wait);
|
return 0;
|
return 0;
|
case SEL_EX:
|
case SEL_EX:
|
if (!PIPE_READERS(*inode) || !PIPE_WRITERS(*inode))
|
if (!PIPE_READERS(*inode) || !PIPE_WRITERS(*inode))
|
return 1;
|
return 1;
|
select_wait(&inode->i_wait,wait);
|
select_wait(&inode->i_wait,wait);
|
return 0;
|
return 0;
|
}
|
}
|
return 0;
|
return 0;
|
}
|
}
|
|
|
#ifdef FIFO_SUNOS_BRAINDAMAGE
|
#ifdef FIFO_SUNOS_BRAINDAMAGE
|
/*
|
/*
|
* Arggh. Why does SunOS have to have different select() behaviour
|
* Arggh. Why does SunOS have to have different select() behaviour
|
* for pipes and fifos? Hate-Hate-Hate. See difference in SEL_IN..
|
* for pipes and fifos? Hate-Hate-Hate. See difference in SEL_IN..
|
*/
|
*/
|
static int fifo_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait)
|
static int fifo_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait)
|
{
|
{
|
switch (sel_type) {
|
switch (sel_type) {
|
case SEL_IN:
|
case SEL_IN:
|
if (!PIPE_EMPTY(*inode))
|
if (!PIPE_EMPTY(*inode))
|
return 1;
|
return 1;
|
select_wait(&PIPE_WAIT(*inode), wait);
|
select_wait(&PIPE_WAIT(*inode), wait);
|
return 0;
|
return 0;
|
case SEL_OUT:
|
case SEL_OUT:
|
if (!PIPE_FULL(*inode) || !PIPE_READERS(*inode))
|
if (!PIPE_FULL(*inode) || !PIPE_READERS(*inode))
|
return 1;
|
return 1;
|
select_wait(&PIPE_WAIT(*inode), wait);
|
select_wait(&PIPE_WAIT(*inode), wait);
|
return 0;
|
return 0;
|
case SEL_EX:
|
case SEL_EX:
|
if (!PIPE_READERS(*inode) || !PIPE_WRITERS(*inode))
|
if (!PIPE_READERS(*inode) || !PIPE_WRITERS(*inode))
|
return 1;
|
return 1;
|
select_wait(&inode->i_wait,wait);
|
select_wait(&inode->i_wait,wait);
|
return 0;
|
return 0;
|
}
|
}
|
return 0;
|
return 0;
|
}
|
}
|
#else
|
#else
|
|
|
#define fifo_select pipe_select
|
#define fifo_select pipe_select
|
|
|
#endif /* FIFO_SUNOS_BRAINDAMAGE */
|
#endif /* FIFO_SUNOS_BRAINDAMAGE */
|
|
|
/*
|
/*
|
* The 'connect_xxx()' functions are needed for named pipes when
|
* The 'connect_xxx()' functions are needed for named pipes when
|
* the open() code hasn't guaranteed a connection (O_NONBLOCK),
|
* the open() code hasn't guaranteed a connection (O_NONBLOCK),
|
* and we need to act differently until we do get a writer..
|
* and we need to act differently until we do get a writer..
|
*/
|
*/
|
static int connect_read(struct inode * inode, struct file * filp, char * buf, int count)
|
static int connect_read(struct inode * inode, struct file * filp, char * buf, int count)
|
{
|
{
|
if (PIPE_EMPTY(*inode) && !PIPE_WRITERS(*inode))
|
if (PIPE_EMPTY(*inode) && !PIPE_WRITERS(*inode))
|
return 0;
|
return 0;
|
filp->f_op = &read_fifo_fops;
|
filp->f_op = &read_fifo_fops;
|
return pipe_read(inode,filp,buf,count);
|
return pipe_read(inode,filp,buf,count);
|
}
|
}
|
|
|
static int connect_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait)
|
static int connect_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait)
|
{
|
{
|
switch (sel_type) {
|
switch (sel_type) {
|
case SEL_IN:
|
case SEL_IN:
|
if (!PIPE_EMPTY(*inode)) {
|
if (!PIPE_EMPTY(*inode)) {
|
filp->f_op = &read_fifo_fops;
|
filp->f_op = &read_fifo_fops;
|
return 1;
|
return 1;
|
}
|
}
|
if (PIPE_WRITERS(*inode)) {
|
if (PIPE_WRITERS(*inode)) {
|
filp->f_op = &read_fifo_fops;
|
filp->f_op = &read_fifo_fops;
|
}
|
}
|
select_wait(&PIPE_WAIT(*inode), wait);
|
select_wait(&PIPE_WAIT(*inode), wait);
|
return 0;
|
return 0;
|
case SEL_OUT:
|
case SEL_OUT:
|
if (!PIPE_FULL(*inode))
|
if (!PIPE_FULL(*inode))
|
return 1;
|
return 1;
|
select_wait(&PIPE_WAIT(*inode), wait);
|
select_wait(&PIPE_WAIT(*inode), wait);
|
return 0;
|
return 0;
|
case SEL_EX:
|
case SEL_EX:
|
if (!PIPE_READERS(*inode) || !PIPE_WRITERS(*inode))
|
if (!PIPE_READERS(*inode) || !PIPE_WRITERS(*inode))
|
return 1;
|
return 1;
|
select_wait(&inode->i_wait,wait);
|
select_wait(&inode->i_wait,wait);
|
return 0;
|
return 0;
|
}
|
}
|
return 0;
|
return 0;
|
}
|
}
|
|
|
static void pipe_read_release(struct inode * inode, struct file * filp)
|
static void pipe_read_release(struct inode * inode, struct file * filp)
|
{
|
{
|
PIPE_READERS(*inode)--;
|
PIPE_READERS(*inode)--;
|
wake_up_interruptible(&PIPE_WAIT(*inode));
|
wake_up_interruptible(&PIPE_WAIT(*inode));
|
}
|
}
|
|
|
static void pipe_write_release(struct inode * inode, struct file * filp)
|
static void pipe_write_release(struct inode * inode, struct file * filp)
|
{
|
{
|
PIPE_WRITERS(*inode)--;
|
PIPE_WRITERS(*inode)--;
|
wake_up_interruptible(&PIPE_WAIT(*inode));
|
wake_up_interruptible(&PIPE_WAIT(*inode));
|
}
|
}
|
|
|
static void pipe_rdwr_release(struct inode * inode, struct file * filp)
|
static void pipe_rdwr_release(struct inode * inode, struct file * filp)
|
{
|
{
|
if (filp->f_mode & FMODE_READ)
|
if (filp->f_mode & FMODE_READ)
|
PIPE_READERS(*inode)--;
|
PIPE_READERS(*inode)--;
|
if (filp->f_mode & FMODE_WRITE)
|
if (filp->f_mode & FMODE_WRITE)
|
PIPE_WRITERS(*inode)--;
|
PIPE_WRITERS(*inode)--;
|
wake_up_interruptible(&PIPE_WAIT(*inode));
|
wake_up_interruptible(&PIPE_WAIT(*inode));
|
}
|
}
|
|
|
static int pipe_read_open(struct inode * inode, struct file * filp)
|
static int pipe_read_open(struct inode * inode, struct file * filp)
|
{
|
{
|
PIPE_READERS(*inode)++;
|
PIPE_READERS(*inode)++;
|
return 0;
|
return 0;
|
}
|
}
|
|
|
static int pipe_write_open(struct inode * inode, struct file * filp)
|
static int pipe_write_open(struct inode * inode, struct file * filp)
|
{
|
{
|
PIPE_WRITERS(*inode)++;
|
PIPE_WRITERS(*inode)++;
|
return 0;
|
return 0;
|
}
|
}
|
|
|
static int pipe_rdwr_open(struct inode * inode, struct file * filp)
|
static int pipe_rdwr_open(struct inode * inode, struct file * filp)
|
{
|
{
|
if (filp->f_mode & FMODE_READ)
|
if (filp->f_mode & FMODE_READ)
|
PIPE_READERS(*inode)++;
|
PIPE_READERS(*inode)++;
|
if (filp->f_mode & FMODE_WRITE)
|
if (filp->f_mode & FMODE_WRITE)
|
PIPE_WRITERS(*inode)++;
|
PIPE_WRITERS(*inode)++;
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/*
|
/*
|
* The file_operations structs are not static because they
|
* The file_operations structs are not static because they
|
* are also used in linux/fs/fifo.c to do operations on fifo's.
|
* are also used in linux/fs/fifo.c to do operations on fifo's.
|
*/
|
*/
|
struct file_operations connecting_fifo_fops = {
|
struct file_operations connecting_fifo_fops = {
|
pipe_lseek,
|
pipe_lseek,
|
connect_read,
|
connect_read,
|
bad_pipe_w,
|
bad_pipe_w,
|
NULL, /* no readdir */
|
NULL, /* no readdir */
|
connect_select,
|
connect_select,
|
pipe_ioctl,
|
pipe_ioctl,
|
NULL, /* no mmap on pipes.. surprise */
|
NULL, /* no mmap on pipes.. surprise */
|
pipe_read_open,
|
pipe_read_open,
|
pipe_read_release,
|
pipe_read_release,
|
NULL
|
NULL
|
};
|
};
|
|
|
struct file_operations read_fifo_fops = {
|
struct file_operations read_fifo_fops = {
|
pipe_lseek,
|
pipe_lseek,
|
pipe_read,
|
pipe_read,
|
bad_pipe_w,
|
bad_pipe_w,
|
NULL, /* no readdir */
|
NULL, /* no readdir */
|
fifo_select,
|
fifo_select,
|
pipe_ioctl,
|
pipe_ioctl,
|
NULL, /* no mmap on pipes.. surprise */
|
NULL, /* no mmap on pipes.. surprise */
|
pipe_read_open,
|
pipe_read_open,
|
pipe_read_release,
|
pipe_read_release,
|
NULL
|
NULL
|
};
|
};
|
|
|
struct file_operations write_fifo_fops = {
|
struct file_operations write_fifo_fops = {
|
pipe_lseek,
|
pipe_lseek,
|
bad_pipe_r,
|
bad_pipe_r,
|
pipe_write,
|
pipe_write,
|
NULL, /* no readdir */
|
NULL, /* no readdir */
|
fifo_select,
|
fifo_select,
|
pipe_ioctl,
|
pipe_ioctl,
|
NULL, /* mmap */
|
NULL, /* mmap */
|
pipe_write_open,
|
pipe_write_open,
|
pipe_write_release,
|
pipe_write_release,
|
NULL
|
NULL
|
};
|
};
|
|
|
struct file_operations rdwr_fifo_fops = {
|
struct file_operations rdwr_fifo_fops = {
|
pipe_lseek,
|
pipe_lseek,
|
pipe_read,
|
pipe_read,
|
pipe_write,
|
pipe_write,
|
NULL, /* no readdir */
|
NULL, /* no readdir */
|
fifo_select,
|
fifo_select,
|
pipe_ioctl,
|
pipe_ioctl,
|
NULL, /* mmap */
|
NULL, /* mmap */
|
pipe_rdwr_open,
|
pipe_rdwr_open,
|
pipe_rdwr_release,
|
pipe_rdwr_release,
|
NULL
|
NULL
|
};
|
};
|
|
|
struct file_operations read_pipe_fops = {
|
struct file_operations read_pipe_fops = {
|
pipe_lseek,
|
pipe_lseek,
|
pipe_read,
|
pipe_read,
|
bad_pipe_w,
|
bad_pipe_w,
|
NULL, /* no readdir */
|
NULL, /* no readdir */
|
pipe_select,
|
pipe_select,
|
pipe_ioctl,
|
pipe_ioctl,
|
NULL, /* no mmap on pipes.. surprise */
|
NULL, /* no mmap on pipes.. surprise */
|
pipe_read_open,
|
pipe_read_open,
|
pipe_read_release,
|
pipe_read_release,
|
NULL
|
NULL
|
};
|
};
|
|
|
struct file_operations write_pipe_fops = {
|
struct file_operations write_pipe_fops = {
|
pipe_lseek,
|
pipe_lseek,
|
bad_pipe_r,
|
bad_pipe_r,
|
pipe_write,
|
pipe_write,
|
NULL, /* no readdir */
|
NULL, /* no readdir */
|
pipe_select,
|
pipe_select,
|
pipe_ioctl,
|
pipe_ioctl,
|
NULL, /* mmap */
|
NULL, /* mmap */
|
pipe_write_open,
|
pipe_write_open,
|
pipe_write_release,
|
pipe_write_release,
|
NULL
|
NULL
|
};
|
};
|
|
|
struct file_operations rdwr_pipe_fops = {
|
struct file_operations rdwr_pipe_fops = {
|
pipe_lseek,
|
pipe_lseek,
|
pipe_read,
|
pipe_read,
|
pipe_write,
|
pipe_write,
|
NULL, /* no readdir */
|
NULL, /* no readdir */
|
pipe_select,
|
pipe_select,
|
pipe_ioctl,
|
pipe_ioctl,
|
NULL, /* mmap */
|
NULL, /* mmap */
|
pipe_rdwr_open,
|
pipe_rdwr_open,
|
pipe_rdwr_release,
|
pipe_rdwr_release,
|
NULL
|
NULL
|
};
|
};
|
|
|
struct inode_operations pipe_inode_operations = {
|
struct inode_operations pipe_inode_operations = {
|
&rdwr_pipe_fops,
|
&rdwr_pipe_fops,
|
NULL, /* create */
|
NULL, /* create */
|
NULL, /* lookup */
|
NULL, /* lookup */
|
NULL, /* link */
|
NULL, /* link */
|
NULL, /* unlink */
|
NULL, /* unlink */
|
NULL, /* symlink */
|
NULL, /* symlink */
|
NULL, /* mkdir */
|
NULL, /* mkdir */
|
NULL, /* rmdir */
|
NULL, /* rmdir */
|
NULL, /* mknod */
|
NULL, /* mknod */
|
NULL, /* rename */
|
NULL, /* rename */
|
NULL, /* readlink */
|
NULL, /* readlink */
|
NULL, /* follow_link */
|
NULL, /* follow_link */
|
NULL, /* readpage */
|
NULL, /* readpage */
|
NULL, /* writepage */
|
NULL, /* writepage */
|
NULL, /* bmap */
|
NULL, /* bmap */
|
NULL, /* truncate */
|
NULL, /* truncate */
|
NULL /* permission */
|
NULL /* permission */
|
};
|
};
|
|
|
int do_pipe(int *fd)
|
int do_pipe(int *fd)
|
{
|
{
|
struct inode * inode;
|
struct inode * inode;
|
struct file *f1, *f2;
|
struct file *f1, *f2;
|
int error;
|
int error;
|
int i,j;
|
int i,j;
|
|
|
error = -ENFILE;
|
error = -ENFILE;
|
f1 = get_empty_filp();
|
f1 = get_empty_filp();
|
if (!f1)
|
if (!f1)
|
goto no_files;
|
goto no_files;
|
|
|
f2 = get_empty_filp();
|
f2 = get_empty_filp();
|
if (!f2)
|
if (!f2)
|
goto close_f1;
|
goto close_f1;
|
|
|
inode = get_pipe_inode();
|
inode = get_pipe_inode();
|
if (!inode)
|
if (!inode)
|
goto close_f12;
|
goto close_f12;
|
|
|
error = get_unused_fd();
|
error = get_unused_fd();
|
if (error < 0)
|
if (error < 0)
|
goto close_f12_inode;
|
goto close_f12_inode;
|
i = error;
|
i = error;
|
|
|
error = get_unused_fd();
|
error = get_unused_fd();
|
if (error < 0)
|
if (error < 0)
|
goto close_f12_inode_i;
|
goto close_f12_inode_i;
|
j = error;
|
j = error;
|
|
|
f1->f_inode = f2->f_inode = inode;
|
f1->f_inode = f2->f_inode = inode;
|
/* read file */
|
/* read file */
|
f1->f_pos = f2->f_pos = 0;
|
f1->f_pos = f2->f_pos = 0;
|
f1->f_flags = O_RDONLY;
|
f1->f_flags = O_RDONLY;
|
f1->f_op = &read_pipe_fops;
|
f1->f_op = &read_pipe_fops;
|
f1->f_mode = 1;
|
f1->f_mode = 1;
|
/* write file */
|
/* write file */
|
f2->f_flags = O_WRONLY;
|
f2->f_flags = O_WRONLY;
|
f2->f_op = &write_pipe_fops;
|
f2->f_op = &write_pipe_fops;
|
f2->f_mode = 2;
|
f2->f_mode = 2;
|
current->files->fd[i] = f1;
|
current->files->fd[i] = f1;
|
current->files->fd[j] = f2;
|
current->files->fd[j] = f2;
|
fd[0] = i;
|
fd[0] = i;
|
fd[1] = j;
|
fd[1] = j;
|
return 0;
|
return 0;
|
|
|
close_f12_inode_i:
|
close_f12_inode_i:
|
put_unused_fd(i);
|
put_unused_fd(i);
|
close_f12_inode:
|
close_f12_inode:
|
inode->i_count--;
|
inode->i_count--;
|
iput(inode);
|
iput(inode);
|
close_f12:
|
close_f12:
|
f2->f_count--;
|
f2->f_count--;
|
close_f1:
|
close_f1:
|
f1->f_count--;
|
f1->f_count--;
|
no_files:
|
no_files:
|
return error;
|
return error;
|
}
|
}
|
|
|