At the kernel summit, there was some discussion of relayfs and the
consensus was that it didn't make sense for relayfs to not implement
read().  So here's a read implementation...

Andrew, please apply.

Tom

Signed-off-by: Tom Zanussi <[EMAIL PROTECTED]>

diff -urpN -X dontdiff linux-2.6.13-rc4-mm1/fs/relayfs/inode.c 
linux-2.6.13-rc4-mm1-cur/fs/relayfs/inode.c
--- linux-2.6.13-rc4-mm1/fs/relayfs/inode.c     2005-08-05 10:14:34.000000000 
-0500
+++ linux-2.6.13-rc4-mm1-cur/fs/relayfs/inode.c 2005-08-05 10:17:47.000000000 
-0500
@@ -232,7 +232,7 @@ int relayfs_remove_dir(struct dentry *de
  *
  *     Increments the channel buffer refcount.
  */
-int relayfs_open(struct inode *inode, struct file *filp)
+static int relayfs_open(struct inode *inode, struct file *filp)
 {
        struct rchan_buf *buf = RELAYFS_I(inode)->buf;
        kref_get(&buf->kref);
@@ -247,7 +247,7 @@ int relayfs_open(struct inode *inode, st
  *
  *     Calls upon relay_mmap_buf to map the file into user space.
  */
-int relayfs_mmap(struct file *filp, struct vm_area_struct *vma)
+static int relayfs_mmap(struct file *filp, struct vm_area_struct *vma)
 {
        struct inode *inode = filp->f_dentry->d_inode;
        return relay_mmap_buf(RELAYFS_I(inode)->buf, vma);
@@ -260,7 +260,7 @@ int relayfs_mmap(struct file *filp, stru
  *
  *     Poll implemention.
  */
-unsigned int relayfs_poll(struct file *filp, poll_table *wait)
+static unsigned int relayfs_poll(struct file *filp, poll_table *wait)
 {
        unsigned int mask = 0;
        struct inode *inode = filp->f_dentry->d_inode;
@@ -286,7 +286,7 @@ unsigned int relayfs_poll(struct file *f
  *     Decrements the channel refcount, as the filesystem is
  *     no longer using it.
  */
-int relayfs_release(struct inode *inode, struct file *filp)
+static int relayfs_release(struct inode *inode, struct file *filp)
 {
        struct rchan_buf *buf = RELAYFS_I(inode)->buf;
        kref_put(&buf->kref, relay_remove_buf);
@@ -295,6 +295,157 @@ int relayfs_release(struct inode *inode,
 }
 
 /**
+ *     relayfs_read_start - find the first available byte to read
+ *
+ *     If the read_pos is in the middle of padding, return the
+ *     position of the first actually available byte, otherwise
+ *     return the original value.
+ */
+static inline unsigned int relayfs_read_start(unsigned int read_pos,
+                                             unsigned int avail,
+                                             unsigned int start_subbuf,
+                                             struct rchan_buf *buf)
+{
+       unsigned int read_subbuf, adj_read_subbuf;
+       unsigned int padding, padding_start, padding_end;
+       unsigned int subbuf_size = buf->chan->subbuf_size;
+       unsigned int n_subbufs = buf->chan->n_subbufs;
+       
+       read_subbuf = read_pos / subbuf_size;
+       adj_read_subbuf = (read_subbuf + start_subbuf) % n_subbufs;
+       
+       if ((read_subbuf + 1) * subbuf_size <= avail) {
+               padding = buf->padding[adj_read_subbuf];
+               padding_start = (read_subbuf + 1) * subbuf_size - padding;
+               padding_end = (read_subbuf + 1) * subbuf_size;
+               if (read_pos >= padding_start && read_pos < padding_end) {
+                       read_subbuf = (read_subbuf + 1) % n_subbufs;
+                       read_pos = read_subbuf * subbuf_size;
+               }
+       }
+
+       return read_pos;
+}
+
+/**
+ *     relayfs_read_end - return the end of available bytes to read
+ *
+ *     If the read_pos is in the middle of a full sub-buffer, return
+ *     the padding-adjusted end of that sub-buffer, otherwise return
+ *     the position after the last byte written to the buffer.  At
+ *     most, 1 sub-buffer can be read at a time.
+ *     
+ */
+static inline unsigned int relayfs_read_end(unsigned int read_pos,
+                                           unsigned int avail,
+                                           unsigned int start_subbuf,
+                                           struct rchan_buf *buf)
+{
+       unsigned int padding, read_endpos, buf_offset;
+       unsigned int read_subbuf, adj_read_subbuf;
+       unsigned int subbuf_size = buf->chan->subbuf_size;
+       unsigned int n_subbufs = buf->chan->n_subbufs;
+
+       buf_offset = buf->offset > subbuf_size ? subbuf_size : buf->offset;
+       read_subbuf = read_pos / subbuf_size;
+       adj_read_subbuf = (read_subbuf + start_subbuf) % n_subbufs;
+
+       if ((read_subbuf + 1) * subbuf_size <= avail) {
+               padding = buf->padding[adj_read_subbuf];
+               read_endpos = (read_subbuf + 1) * subbuf_size - padding;
+       } else
+               read_endpos = read_subbuf * subbuf_size + buf_offset;
+
+       return read_endpos;
+}
+
+/**
+ *     relayfs_read_avail - return total available along with buffer start
+ *
+ *     Because buffers are circular, the 'beginning' of the buffer
+ *     depends on where the buffer was last written.  If the writer
+ *     has cycled around the buffer, the beginning is defined to be
+ *     the beginning of the sub-buffer following the last sub-buffer
+ *     written to, otherwise it's the beginning of sub-buffer 0.
+ *     
+ */
+static inline unsigned int relayfs_read_avail(struct rchan_buf *buf,
+                                             unsigned int *start_subbuf)
+{
+       unsigned int avail, complete_subbufs, cur_subbuf, buf_offset;
+       unsigned int subbuf_size = buf->chan->subbuf_size;
+       unsigned int n_subbufs = buf->chan->n_subbufs;
+
+       buf_offset = buf->offset > subbuf_size ? subbuf_size : buf->offset;
+       
+       if (buf->subbufs_produced >= n_subbufs) {
+               complete_subbufs = n_subbufs - 1;
+               cur_subbuf = (buf->data - buf->start) / subbuf_size;
+               *start_subbuf = (cur_subbuf + 1) % n_subbufs;
+       } else {
+               complete_subbufs = buf->subbufs_produced;
+               *start_subbuf = 0;
+       }
+       
+       avail = complete_subbufs * subbuf_size + buf_offset;
+
+       return avail;
+}
+
+/**
+ *     relayfs_read - read file op for relayfs files
+ *     @filp: the file
+ *     @buffer: the userspace buffer
+ *     @count: number of bytes to read
+ *     @ppos: position to read from
+ *
+ *     Reads count bytes or the number of bytes available in the
+ *     current sub-buffer being read, whichever is smaller.
+ *     
+ *     NOTE: The results of reading a relayfs file which is currently
+ *     being written to are undefined.  This is because the buffer is
+ *     circular and an active writer in the kernel could be
+ *     overwriting the data currently being read.  Therefore read()
+ *     is mainly useful for reading the contents of a buffer after
+ *     logging has completed.
+ */
+static ssize_t relayfs_read(struct file *filp,
+                           char __user *buffer,
+                           size_t count,
+                           loff_t *ppos)
+{
+       struct inode *inode = filp->f_dentry->d_inode;
+       struct rchan_buf *buf = RELAYFS_I(inode)->buf;
+       unsigned int read_start, read_end, avail, start_subbuf;
+       unsigned int buf_size = buf->chan->subbuf_size * buf->chan->n_subbufs;
+       void *from;
+
+       avail = relayfs_read_avail(buf, &start_subbuf);
+       if (*ppos >= avail)
+               return 0;
+
+       read_start = relayfs_read_start(*ppos, avail, start_subbuf, buf);
+       if (read_start == 0 && *ppos)
+               return 0;
+       
+       read_end = relayfs_read_end(read_start, avail, start_subbuf, buf);
+       if (read_end == read_start)
+               return 0;
+       
+       from = buf->start + start_subbuf * buf->chan->subbuf_size + read_start;
+       if (from >= buf->start + buf_size)
+               from -= buf_size;
+
+       count = min(count, read_end - read_start);
+       if (copy_to_user(buffer, from, count))
+               return -EFAULT;
+
+       *ppos = read_start + count;
+       
+       return count;
+}
+
+/**
  *     relayfs alloc_inode() implementation
  */
 static struct inode *relayfs_alloc_inode(struct super_block *sb)
@@ -329,6 +480,7 @@ struct file_operations relayfs_file_oper
        .open           = relayfs_open,
        .poll           = relayfs_poll,
        .mmap           = relayfs_mmap,
+       .read           = relayfs_read,
        .release        = relayfs_release,
 };
 
@@ -404,10 +556,6 @@ static void __exit exit_relayfs_fs(void)
 module_init(init_relayfs_fs)
 module_exit(exit_relayfs_fs)
 
-EXPORT_SYMBOL_GPL(relayfs_open);
-EXPORT_SYMBOL_GPL(relayfs_poll);
-EXPORT_SYMBOL_GPL(relayfs_mmap);
-EXPORT_SYMBOL_GPL(relayfs_release);
 EXPORT_SYMBOL_GPL(relayfs_file_operations);
 EXPORT_SYMBOL_GPL(relayfs_create_dir);
 EXPORT_SYMBOL_GPL(relayfs_remove_dir);


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to