From 3a326a2ce88e71d00ac0d133e314a3342a7709f8 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 10 Apr 2006 15:18:35 +0200 Subject: [PATCH] introduce a "kernel-internal pipe object" abstraction separate out the 'internal pipe object' abstraction, and make it usable to splice. This cleans up and fixes several aspects of the internal splice APIs and the pipe code: - pipes: the allocation and freeing of pipe_inode_info is now more symmetric and more streamlined with existing kernel practices. - splice: small micro-optimization: less pointer dereferencing in splice methods Signed-off-by: Ingo Molnar Update XFS for the ->splice_read/->splice_write changes. Signed-off-by: Jens Axboe --- include/linux/fs.h | 8 ++++---- include/linux/pipe_fs_i.h | 7 ++++--- 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/include/linux/fs.h b/include/linux/fs.h index 1e9ebaba07b..7e6454454fb 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1039,8 +1039,8 @@ struct file_operations { int (*check_flags)(int); int (*dir_notify)(struct file *filp, unsigned long arg); int (*flock) (struct file *, int, struct file_lock *); - ssize_t (*splice_write)(struct inode *, struct file *, size_t, unsigned int); - ssize_t (*splice_read)(struct file *, struct inode *, size_t, unsigned int); + ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, size_t, unsigned int); + ssize_t (*splice_read)(struct file *, struct pipe_inode_info *, size_t, unsigned int); }; struct inode_operations { @@ -1611,8 +1611,8 @@ extern ssize_t generic_file_sendfile(struct file *, loff_t *, size_t, read_actor extern void do_generic_mapping_read(struct address_space *mapping, struct file_ra_state *, struct file *, loff_t *, read_descriptor_t *, read_actor_t); -extern ssize_t generic_file_splice_read(struct file *, struct inode *, size_t, unsigned int); -extern ssize_t generic_file_splice_write(struct inode *, struct file *, size_t, unsigned int); +extern ssize_t generic_file_splice_read(struct file *, struct pipe_inode_info *, size_t, unsigned int); +extern ssize_t generic_file_splice_write(struct pipe_inode_info *, struct file *, size_t, unsigned int); extern void file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping); extern ssize_t generic_file_readv(struct file *filp, const struct iovec *iov, diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h index ec384958d50..9cf99cb34c1 100644 --- a/include/linux/pipe_fs_i.h +++ b/include/linux/pipe_fs_i.h @@ -36,6 +36,7 @@ struct pipe_inode_info { unsigned int w_counter; struct fasync_struct *fasync_readers; struct fasync_struct *fasync_writers; + struct inode *inode; }; /* Differs from PIPE_BUF in that PIPE_SIZE is the length of the actual @@ -53,10 +54,10 @@ struct pipe_inode_info { #define PIPE_FASYNC_WRITERS(inode) (&((inode).i_pipe->fasync_writers)) /* Drop the inode semaphore and wait for a pipe event, atomically */ -void pipe_wait(struct inode * inode); +void pipe_wait(struct pipe_inode_info *pipe); -struct inode* pipe_new(struct inode* inode); -void free_pipe_info(struct inode* inode); +struct pipe_inode_info * alloc_pipe_info(struct inode * inode); +void free_pipe_info(struct inode * inode); /* * splice is tied to pipes as a transport (at least for now), so we'll just -- cgit From 529565dcb1581c9a1e3f6df1c1763ca3e0f0d512 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 10 Apr 2006 15:18:58 +0200 Subject: [PATCH] splice: add optional input and output offsets add optional input and output offsets to sys_splice(), for seekable file descriptors: asmlinkage long sys_splice(int fd_in, loff_t __user *off_in, int fd_out, loff_t __user *off_out, size_t len, unsigned int flags); semantics are straightforward: f_pos will be updated with the offset provided by user-space, before the splice transfer is about to begin. Providing a NULL offset pointer means the existing f_pos will be used (and updated in situ). Providing an offset for a pipe results in -ESPIPE. Providing an invalid offset pointer results in -EFAULT. Signed-off-by: Ingo Molnar Signed-off-by: Jens Axboe --- include/linux/syscalls.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 5717147596b..4c292faa70c 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -569,8 +569,11 @@ asmlinkage long compat_sys_newfstatat(unsigned int dfd, char __user * filename, asmlinkage long compat_sys_openat(unsigned int dfd, const char __user *filename, int flags, int mode); asmlinkage long sys_unshare(unsigned long unshare_flags); -asmlinkage long sys_splice(int fdin, int fdout, size_t len, - unsigned int flags); + +asmlinkage long sys_splice(int fd_in, loff_t __user *off_in, + int fd_out, loff_t __user *off_out, + size_t len, unsigned int flags); + asmlinkage long sys_sync_file_range(int fd, loff_t offset, loff_t nbytes, int flags); -- cgit From b92ce55893745e011edae70830b8bc863be881f9 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 11 Apr 2006 13:52:07 +0200 Subject: [PATCH] splice: add direct fd <-> fd splicing support It's more efficient for sendfile() emulation. Basically we cache an internal private pipe and just use that as the intermediate area for pages. Direct splicing is not available from sys_splice(), it is only meant to be used for sendfile() emulation. Additional patch from Ingo Molnar to avoid the PIPE_BUFFERS loop at exit for the normal fast path. Signed-off-by: Jens Axboe --- include/linux/fs.h | 2 ++ include/linux/pipe_fs_i.h | 1 + include/linux/sched.h | 6 ++++++ 3 files changed, 9 insertions(+) (limited to 'include/linux') diff --git a/include/linux/fs.h b/include/linux/fs.h index 7e6454454fb..9e8e2ee353b 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1613,6 +1613,8 @@ extern void do_generic_mapping_read(struct address_space *mapping, loff_t *, read_descriptor_t *, read_actor_t); extern ssize_t generic_file_splice_read(struct file *, struct pipe_inode_info *, size_t, unsigned int); extern ssize_t generic_file_splice_write(struct pipe_inode_info *, struct file *, size_t, unsigned int); +extern long do_splice_direct(struct file *in, struct file *out, + size_t len, unsigned int flags); extern void file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping); extern ssize_t generic_file_readv(struct file *filp, const struct iovec *iov, diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h index 9cf99cb34c1..660e9d866e5 100644 --- a/include/linux/pipe_fs_i.h +++ b/include/linux/pipe_fs_i.h @@ -58,6 +58,7 @@ void pipe_wait(struct pipe_inode_info *pipe); struct pipe_inode_info * alloc_pipe_info(struct inode * inode); void free_pipe_info(struct inode * inode); +void __free_pipe_info(struct pipe_inode_info *); /* * splice is tied to pipes as a transport (at least for now), so we'll just diff --git a/include/linux/sched.h b/include/linux/sched.h index 541f4828f5e..e194ec75833 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -684,6 +684,7 @@ static inline void prefetch_stack(struct task_struct *t) { } struct audit_context; /* See audit.c */ struct mempolicy; +struct pipe_inode_info; enum sleep_type { SLEEP_NORMAL, @@ -882,6 +883,11 @@ struct task_struct { atomic_t fs_excl; /* holding fs exclusive resources */ struct rcu_head rcu; + + /* + * cache last used pipe for splice + */ + struct pipe_inode_info *splice_pipe; }; static inline pid_t process_group(struct task_struct *tsk) -- cgit From 9aeedfc4712ed58d9f7ae41596185c72b8dc97e8 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Tue, 11 Apr 2006 13:53:10 +0200 Subject: [PATCH] get rid of the PIPE_*() macros get rid of the PIPE_*() macros. Scripted transformation. Signed-off-by: Ingo Molnar Signed-off-by: Jens Axboe --- include/linux/pipe_fs_i.h | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'include/linux') diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h index 660e9d866e5..123a7c24bc7 100644 --- a/include/linux/pipe_fs_i.h +++ b/include/linux/pipe_fs_i.h @@ -43,16 +43,6 @@ struct pipe_inode_info { memory allocation, whereas PIPE_BUF makes atomicity guarantees. */ #define PIPE_SIZE PAGE_SIZE -#define PIPE_MUTEX(inode) (&(inode).i_mutex) -#define PIPE_WAIT(inode) (&(inode).i_pipe->wait) -#define PIPE_READERS(inode) ((inode).i_pipe->readers) -#define PIPE_WRITERS(inode) ((inode).i_pipe->writers) -#define PIPE_WAITING_WRITERS(inode) ((inode).i_pipe->waiting_writers) -#define PIPE_RCOUNTER(inode) ((inode).i_pipe->r_counter) -#define PIPE_WCOUNTER(inode) ((inode).i_pipe->w_counter) -#define PIPE_FASYNC_READERS(inode) (&((inode).i_pipe->fasync_readers)) -#define PIPE_FASYNC_WRITERS(inode) (&((inode).i_pipe->fasync_writers)) - /* Drop the inode semaphore and wait for a pipe event, atomically */ void pipe_wait(struct pipe_inode_info *pipe); -- cgit From 88e6faefaeed40a162041d85689e94595756d4c3 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 11 Apr 2006 13:59:36 +0200 Subject: [PATCH] splice: warning fix From: Andrew Morton net/socket.c:148: warning: initialization from incompatible pointer type extern declarations in .c files! Bad boy. Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Jens Axboe --- include/linux/fs.h | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/fs.h b/include/linux/fs.h index 9e8e2ee353b..2a629fd88ef 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1611,10 +1611,17 @@ extern ssize_t generic_file_sendfile(struct file *, loff_t *, size_t, read_actor extern void do_generic_mapping_read(struct address_space *mapping, struct file_ra_state *, struct file *, loff_t *, read_descriptor_t *, read_actor_t); -extern ssize_t generic_file_splice_read(struct file *, struct pipe_inode_info *, size_t, unsigned int); -extern ssize_t generic_file_splice_write(struct pipe_inode_info *, struct file *, size_t, unsigned int); + +/* fs/splice.c */ +extern ssize_t generic_file_splice_read(struct file *, + struct pipe_inode_info *, size_t, unsigned int); +extern ssize_t generic_file_splice_write(struct pipe_inode_info *, + struct file *, size_t, unsigned int); +extern ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe, + struct file *out, size_t len, unsigned int flags); extern long do_splice_direct(struct file *in, struct file *out, - size_t len, unsigned int flags); + size_t len, unsigned int flags); + extern void file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping); extern ssize_t generic_file_readv(struct file *filp, const struct iovec *iov, -- cgit