diff --git a/fs/pipe.c b/fs/pipe.c index 2e60e1c8815e1204aa2b5a814d293d849e27c1d6..b1626f269a3445e38f34c1bc338734e0893bbd32 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -874,87 +874,118 @@ static struct inode * get_pipe_inode(void) return NULL; } -int do_pipe(int *fd) +struct file *create_write_pipe(void) { - struct qstr this; - char name[32]; + int err; + struct inode *inode; + struct file *f; struct dentry *dentry; - struct inode * inode; - struct file *f1, *f2; - int error; - int i, j; - - error = -ENFILE; - f1 = get_empty_filp(); - if (!f1) - goto no_files; - - f2 = get_empty_filp(); - if (!f2) - goto close_f1; + char name[32]; + struct qstr this; + f = get_empty_filp(); + if (!f) + return ERR_PTR(-ENFILE); + err = -ENFILE; inode = get_pipe_inode(); if (!inode) - goto close_f12; + goto err_file; - error = get_unused_fd(); - if (error < 0) - goto close_f12_inode; - i = error; - - error = get_unused_fd(); - if (error < 0) - goto close_f12_inode_i; - j = error; - - error = -ENOMEM; sprintf(name, "[%lu]", inode->i_ino); this.name = name; this.len = strlen(name); this.hash = inode->i_ino; /* will go */ + err = -ENOMEM; dentry = d_alloc(pipe_mnt->mnt_sb->s_root, &this); if (!dentry) - goto close_f12_inode_i_j; + goto err_inode; dentry->d_op = &pipefs_dentry_operations; d_add(dentry, inode); - f1->f_vfsmnt = f2->f_vfsmnt = mntget(mntget(pipe_mnt)); - f1->f_dentry = f2->f_dentry = dget(dentry); - f1->f_mapping = f2->f_mapping = inode->i_mapping; - - /* read file */ - f1->f_pos = f2->f_pos = 0; - f1->f_flags = O_RDONLY; - f1->f_op = &read_pipe_fops; - f1->f_mode = FMODE_READ; - f1->f_version = 0; - - /* write file */ - f2->f_flags = O_WRONLY; - f2->f_op = &write_pipe_fops; - f2->f_mode = FMODE_WRITE; - f2->f_version = 0; - - fd_install(i, f1); - fd_install(j, f2); - fd[0] = i; - fd[1] = j; + f->f_vfsmnt = mntget(pipe_mnt); + f->f_dentry = dentry; + f->f_mapping = inode->i_mapping; - return 0; + f->f_flags = O_WRONLY; + f->f_op = &write_pipe_fops; + f->f_mode = FMODE_WRITE; + f->f_version = 0; -close_f12_inode_i_j: - put_unused_fd(j); -close_f12_inode_i: - put_unused_fd(i); -close_f12_inode: + return f; + + err_inode: free_pipe_info(inode); iput(inode); -close_f12: - put_filp(f2); -close_f1: - put_filp(f1); -no_files: - return error; + err_file: + put_filp(f); + return ERR_PTR(err); +} + +void free_write_pipe(struct file *f) +{ + mntput(f->f_vfsmnt); + dput(f->f_dentry); + put_filp(f); +} + +struct file *create_read_pipe(struct file *wrf) +{ + struct file *f = get_empty_filp(); + if (!f) + return ERR_PTR(-ENFILE); + + /* Grab pipe from the writer */ + f->f_vfsmnt = mntget(wrf->f_vfsmnt); + f->f_dentry = dget(wrf->f_dentry); + f->f_mapping = wrf->f_dentry->d_inode->i_mapping; + + f->f_pos = 0; + f->f_flags = O_RDONLY; + f->f_op = &read_pipe_fops; + f->f_mode = FMODE_READ; + f->f_version = 0; + + return f; +} + +int do_pipe(int *fd) +{ + struct file *fw, *fr; + int error; + int fdw, fdr; + + fw = create_write_pipe(); + if (IS_ERR(fw)) + return PTR_ERR(fw); + fr = create_read_pipe(fw); + error = PTR_ERR(fr); + if (IS_ERR(fr)) + goto err_write_pipe; + + error = get_unused_fd(); + if (error < 0) + goto err_read_pipe; + fdr = error; + + error = get_unused_fd(); + if (error < 0) + goto err_fdr; + fdw = error; + + fd_install(fdr, fr); + fd_install(fdw, fw); + fd[0] = fdr; + fd[1] = fdw; + + return 0; + + err_fdr: + put_unused_fd(fdr); + err_read_pipe: + put_filp(fr); + err_write_pipe: + free_write_pipe(fw); + return error; } /* diff --git a/include/linux/fs.h b/include/linux/fs.h index 3493d2828f7d78bae7f395b0dde007087171af75..2e29a2edaeecb2173deffdbce1c4fc9f9e1e4d0f 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1641,6 +1641,9 @@ static inline void allow_write_access(struct file *file) atomic_inc(&file->f_dentry->d_inode->i_writecount); } extern int do_pipe(int *); +extern struct file *create_read_pipe(struct file *f); +extern struct file *create_write_pipe(void); +extern void free_write_pipe(struct file *); extern int open_namei(int dfd, const char *, int, int, struct nameidata *); extern int may_open(struct nameidata *, int, int);