relay: simplify relay_file_read()
[cascardo/linux.git] / kernel / relay.c
index 04d7cf3..6fa398e 100644 (file)
@@ -451,6 +451,13 @@ static struct rchan_buf *relay_open_buf(struct rchan *chan, unsigned int cpu)
                if (!dentry)
                        goto free_buf;
                relay_set_buf_dentry(buf, dentry);
+       } else {
+               /* Only retrieve global info, nothing more, nothing less */
+               dentry = chan->cb->create_buf_file(NULL, NULL,
+                                                  S_IRUSR, buf,
+                                                  &chan->is_global);
+               if (WARN_ON(dentry))
+                       goto free_buf;
        }
 
        buf->cpu = cpu;
@@ -562,6 +569,10 @@ static int relay_hotcpu_callback(struct notifier_block *nb,
  *     attributes specified.  The created channel buffer files
  *     will be named base_filename0...base_filenameN-1.  File
  *     permissions will be %S_IRUSR.
+ *
+ *     If opening a buffer (@parent = NULL) that you later wish to register
+ *     in a filesystem, call relay_late_setup_files() once the @parent dentry
+ *     is available.
  */
 struct rchan *relay_open(const char *base_filename,
                         struct dentry *parent,
@@ -640,8 +651,12 @@ static void __relay_set_buf_dentry(void *info)
  *
  *     Returns 0 if successful, non-zero otherwise.
  *
- *     Use to setup files for a previously buffer-only channel.
- *     Useful to do early tracing in kernel, before VFS is up, for example.
+ *     Use to setup files for a previously buffer-only channel created
+ *     by relay_open() with a NULL parent dentry.
+ *
+ *     For example, this is useful for perfomring early tracing in kernel,
+ *     before VFS is up and then exposing the early results once the dentry
+ *     is available.
  */
 int relay_late_setup_files(struct rchan *chan,
                           const char *base_filename,
@@ -666,6 +681,20 @@ int relay_late_setup_files(struct rchan *chan,
        }
        chan->has_base_filename = 1;
        chan->parent = parent;
+
+       if (chan->is_global) {
+               err = -EINVAL;
+               if (!WARN_ON_ONCE(!chan->buf[0])) {
+                       dentry = relay_create_buf_file(chan, chan->buf[0], 0);
+                       if (dentry && !WARN_ON_ONCE(!chan->is_global)) {
+                               relay_set_buf_dentry(chan->buf[0], dentry);
+                               err = 0;
+                       }
+               }
+               mutex_unlock(&relay_channels_mutex);
+               return err;
+       }
+
        curr_cpu = get_cpu();
        /*
         * The CPU hotplug notifier ran before us and created buffers with
@@ -706,6 +735,7 @@ int relay_late_setup_files(struct rchan *chan,
 
        return err;
 }
+EXPORT_SYMBOL_GPL(relay_late_setup_files);
 
 /**
  *     relay_switch_subbuf - switch to a new sub-buffer
@@ -1091,51 +1121,23 @@ static size_t relay_file_read_end_pos(struct rchan_buf *buf,
        return end_pos;
 }
 
-/*
- *     subbuf_read_actor - read up to one subbuf's worth of data
- */
-static int subbuf_read_actor(size_t read_start,
-                            struct rchan_buf *buf,
-                            size_t avail,
-                            read_descriptor_t *desc)
-{
-       void *from;
-       int ret = 0;
-
-       from = buf->start + read_start;
-       ret = avail;
-       if (copy_to_user(desc->arg.buf, from, avail)) {
-               desc->error = -EFAULT;
-               ret = 0;
-       }
-       desc->arg.data += ret;
-       desc->written += ret;
-       desc->count -= ret;
-
-       return ret;
-}
-
-typedef int (*subbuf_actor_t) (size_t read_start,
-                              struct rchan_buf *buf,
-                              size_t avail,
-                              read_descriptor_t *desc);
-
-/*
- *     relay_file_read_subbufs - read count bytes, bridging subbuf boundaries
- */
-static ssize_t relay_file_read_subbufs(struct file *filp, loff_t *ppos,
-                                       subbuf_actor_t subbuf_actor,
-                                       read_descriptor_t *desc)
+static ssize_t relay_file_read(struct file *filp,
+                              char __user *buffer,
+                              size_t count,
+                              loff_t *ppos)
 {
        struct rchan_buf *buf = filp->private_data;
        size_t read_start, avail;
+       size_t written = 0;
        int ret;
 
-       if (!desc->count)
+       if (!count)
                return 0;
 
        inode_lock(file_inode(filp));
        do {
+               void *from;
+
                if (!relay_file_read_avail(buf, *ppos))
                        break;
 
@@ -1144,32 +1146,22 @@ static ssize_t relay_file_read_subbufs(struct file *filp, loff_t *ppos,
                if (!avail)
                        break;
 
-               avail = min(desc->count, avail);
-               ret = subbuf_actor(read_start, buf, avail, desc);
-               if (desc->error < 0)
+               avail = min(count, avail);
+               from = buf->start + read_start;
+               ret = avail;
+               if (copy_to_user(buffer, from, avail))
                        break;
 
-               if (ret) {
-                       relay_file_read_consume(buf, read_start, ret);
-                       *ppos = relay_file_read_end_pos(buf, read_start, ret);
-               }
-       } while (desc->count && ret);
-       inode_unlock(file_inode(filp));
+               buffer += ret;
+               written += ret;
+               count -= ret;
 
-       return desc->written;
-}
+               relay_file_read_consume(buf, read_start, ret);
+               *ppos = relay_file_read_end_pos(buf, read_start, ret);
+       } while (count);
+       inode_unlock(file_inode(filp));
 
-static ssize_t relay_file_read(struct file *filp,
-                              char __user *buffer,
-                              size_t count,
-                              loff_t *ppos)
-{
-       read_descriptor_t desc;
-       desc.written = 0;
-       desc.count = count;
-       desc.arg.buf = buffer;
-       desc.error = 0;
-       return relay_file_read_subbufs(filp, ppos, subbuf_read_actor, &desc);
+       return written;
 }
 
 static void relay_consume_bytes(struct rchan_buf *rbuf, int bytes_consumed)