static unsigned long ring_buffer_flags __read_mostly = RB_BUFFERS_ON;
 
+#define BUF_PAGE_HDR_SIZE offsetof(struct buffer_data_page, data)
+
 /**
  * tracing_on - enable all tracing buffers
  *
        local_set(&bpage->commit, 0);
 }
 
+/**
+ * ring_buffer_page_len - the size of data on the page.
+ * @page: The page to read
+ *
+ * Returns the amount of data on the page, including buffer page header.
+ */
 size_t ring_buffer_page_len(void *page)
 {
-       return local_read(&((struct buffer_data_page *)page)->commit);
+       return local_read(&((struct buffer_data_page *)page)->commit)
+               + BUF_PAGE_HDR_SIZE;
 }
 
 /*
        return 0;
 }
 
-#define BUF_PAGE_SIZE (PAGE_SIZE - offsetof(struct buffer_data_page, data))
+#define BUF_PAGE_SIZE (PAGE_SIZE - BUF_PAGE_HDR_SIZE)
 
 /*
  * head_page == tail_page && head == tail then buffer is empty.
        unsigned int read;
        int ret = -1;
 
+       /*
+        * If len is not big enough to hold the page header, then
+        * we can not copy anything.
+        */
+       if (len <= BUF_PAGE_HDR_SIZE)
+               return -1;
+
+       len -= BUF_PAGE_HDR_SIZE;
+
        if (!data_page)
                return -1;
 
        commit = rb_page_commit(reader);
 
        /*
-        * If len > what's left on the page, and the writer is also off of
-        * the read page, then simply switch the read page with the given
-        * page. Otherwise we need to copy the data from the reader to the
-        * writer.
+        * If this page has been partially read or
+        * if len is not big enough to read the rest of the page or
+        * a writer is still on the page, then
+        * we must copy the data from the page to the buffer.
+        * Otherwise, we can simply swap the page with the one passed in.
         */
-       if ((len < (commit - read)) ||
+       if (read || (len < (commit - read)) ||
            cpu_buffer->reader_page == cpu_buffer->commit_page) {
                struct buffer_data_page *rpage = cpu_buffer->reader_page->page;
-               unsigned int pos = read;
+               unsigned int rpos = read;
+               unsigned int pos = 0;
                unsigned int size;
 
                if (full)
 
                /* Need to copy one event at a time */
                do {
-                       memcpy(bpage->data + pos, rpage->data + pos, size);
+                       memcpy(bpage->data + pos, rpage->data + rpos, size);
 
                        len -= size;
 
                        rb_advance_reader(cpu_buffer);
-                       pos = reader->read;
+                       rpos = reader->read;
+                       pos += size;
 
                        event = rb_reader_event(cpu_buffer);
                        size = rb_event_length(event);
                local_set(&bpage->commit, pos);
                bpage->time_stamp = rpage->time_stamp;
 
+               /* we copied everything to the beginning */
+               read = 0;
        } else {
                /* swap the pages */
                rb_init_page(bpage);