[PATCH] pipe: export size and blocks via system call fstat(2)

From: Changli Gao
Date: Thu May 27 2010 - 10:11:13 EST


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-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/