export size and blocks via system call fstat(2) pipe or fifo doesn't support fstat(2). This patch makes it possible to check the amount of data buffered in a pipe or fifo, and the pages used to store this data via fstat(2). Signed-off-by: Changli Gao <xiaosuo@xxxxxxxxx> ---- fs/inode.c | 5 +++-- fs/pipe.c | 51 ++++++++++++++++++++++++++++++++++++++++----------- include/linux/fs.h | 1 + 3 files changed, 44 insertions(+), 13 deletions(-) diff --git a/fs/inode.c b/fs/inode.c index 258ec22..850ff89 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -1598,9 +1598,10 @@ void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev) } else if (S_ISBLK(mode)) { inode->i_fop = &def_blk_fops; inode->i_rdev = rdev; - } else if (S_ISFIFO(mode)) + } else if (S_ISFIFO(mode)) { + inode->i_op = &pipe_iops; inode->i_fop = &def_fifo_fops; - else if (S_ISSOCK(mode)) + } else if (S_ISSOCK(mode)) inode->i_fop = &bad_sock_fops; else printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o) for" diff --git a/fs/pipe.c b/fs/pipe.c index 37ba29f..3961fcf 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -625,25 +625,33 @@ bad_pipe_w(struct file *filp, const char __user *buf, size_t count, return -EBADF; } -static long pipe_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +static int __pipe_get_size(struct inode *inode) { - struct inode *inode = filp->f_path.dentry->d_inode; struct pipe_inode_info *pipe; int count, buf, nrbufs; + pipe = inode->i_pipe; + count = 0; + buf = pipe->curbuf; + nrbufs = pipe->nrbufs; + while (--nrbufs >= 0) { + count += pipe->bufs[buf].len; + buf = (buf+1) & (PIPE_BUFFERS-1); + } + + return count; +} + +static long pipe_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct inode *inode = filp->f_path.dentry->d_inode; + int count; + switch (cmd) { case FIONREAD: mutex_lock(&inode->i_mutex); - pipe = inode->i_pipe; - count = 0; - buf = pipe->curbuf; - nrbufs = pipe->nrbufs; - while (--nrbufs >= 0) { - count += pipe->bufs[buf].len; - buf = (buf+1) & (PIPE_BUFFERS-1); - } + count = __pipe_get_size(inode); mutex_unlock(&inode->i_mutex); - return put_user(count, (int __user *)arg); default: return -EINVAL; @@ -934,6 +942,7 @@ static struct inode * get_pipe_inode(void) inode->i_pipe = pipe; pipe->readers = pipe->writers = 1; + inode->i_op = &pipe_iops; inode->i_fop = &rdwr_pipefifo_fops; /* @@ -1112,6 +1121,26 @@ static struct file_system_type pipe_fs_type = { .kill_sb = kill_anon_super, }; +static int pipe_getattr(struct vfsmount *mnt, struct dentry *dentry, + struct kstat *stat) +{ + struct inode *inode = dentry->d_inode; + + generic_fillattr(inode, stat); + mutex_lock(&inode->i_mutex); + if (inode->i_pipe) { + stat->blocks = inode->i_pipe->nrbufs * (PAGE_SIZE / 512); + stat->size = __pipe_get_size(inode); + } + mutex_unlock(&inode->i_mutex); + + return 0; +} + +const struct inode_operations pipe_iops = { + .getattr = pipe_getattr, +}; + static int __init init_pipe_fs(void) { int err = register_filesystem(&pipe_fs_type); diff --git a/include/linux/fs.h b/include/linux/fs.h index eb86433..89103b9 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1973,6 +1973,7 @@ extern const struct file_operations def_blk_fops; extern const struct file_operations def_chr_fops; extern const struct file_operations bad_sock_fops; extern const struct file_operations def_fifo_fops; +extern const struct inode_operations pipe_iops; #ifdef CONFIG_BLOCK extern int ioctl_by_bdev(struct block_device *, unsigned, unsigned long); extern int blkdev_ioctl(struct block_device *, fmode_t, unsigned, unsigned long); -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html