--- linux-2.6.13-rc6-mm2/fs/relayfs/inode.c~ 2005-08-23 14:29:11.000000000 +0200 +++ linux-2.6.13-rc6-mm2/fs/relayfs/inode.c 2005-08-23 14:29:54.000000000 +0200 @@ -302,94 +302,73 @@ * return the original value. */ static inline size_t relayfs_read_start(size_t read_pos, - size_t avail, - size_t start_subbuf, struct rchan_buf *buf) { - size_t read_subbuf, adj_read_subbuf; - size_t padding, padding_start, padding_end; + size_t read_subbuf, padding, padding_start, padding_end; size_t subbuf_size = buf->chan->subbuf_size; size_t 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; - } + padding = buf->padding[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. + * 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 size_t relayfs_read_end(size_t read_pos, - size_t avail, - size_t start_subbuf, - struct rchan_buf *buf) +static inline size_t relayfs_read_avail(size_t read_pos, + struct rchan_buf *buf) { - size_t padding, read_endpos, buf_offset; - size_t read_subbuf, adj_read_subbuf; + size_t padding, avail = 0; + size_t read_subbuf, read_offset, write_subbuf, write_offset; size_t subbuf_size = buf->chan->subbuf_size; - size_t n_subbufs = buf->chan->n_subbufs; - buf_offset = buf->offset > subbuf_size ? subbuf_size : buf->offset; + write_subbuf = (buf->data - buf->start) / subbuf_size; + write_offset = buf->offset > subbuf_size ? subbuf_size : buf->offset; read_subbuf = read_pos / subbuf_size; - adj_read_subbuf = (read_subbuf + start_subbuf) % n_subbufs; + read_offset = read_pos % subbuf_size; + padding = buf->padding[read_subbuf]; - if ((read_subbuf + 1) * subbuf_size <= avail) { - padding = buf->padding[adj_read_subbuf]; - read_endpos = (read_subbuf + 1) * subbuf_size - padding; + if (read_subbuf == write_subbuf) { + if (read_offset + padding < write_offset) + avail = write_offset - (read_offset + padding); } else - read_endpos = read_subbuf * subbuf_size + buf_offset; + avail = (subbuf_size - padding) - read_offset; - return read_endpos; + return avail; } -/** - * 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 size_t relayfs_read_avail(struct rchan_buf *buf, - size_t *start_subbuf) +static void relayfs_read_consume(struct rchan_buf *buf, + size_t read_pos, + size_t bytes_consumed) { - size_t avail, complete_subbufs, cur_subbuf, buf_offset; size_t subbuf_size = buf->chan->subbuf_size; - size_t n_subbufs = buf->chan->n_subbufs; + size_t read_subbuf; + size_t tmp; - buf_offset = buf->offset > subbuf_size ? subbuf_size : buf->offset; + buf->bytes_consumed += bytes_consumed; + read_subbuf = read_pos / buf->chan->subbuf_size; - 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; + if (buf->bytes_consumed + buf->padding[read_subbuf] == subbuf_size) { + tmp = buf->subbufs_consumed; + relay_subbufs_consumed(buf->chan, buf->cpu, 1); + if (buf->subbufs_consumed != tmp) + buf->bytes_consumed = 0; } - - avail = complete_subbufs * subbuf_size + buf_offset; - - return avail; } /** @@ -401,7 +380,7 @@ * * 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 @@ -416,31 +395,40 @@ { struct inode *inode = filp->f_dentry->d_inode; struct rchan_buf *buf = RELAYFS_I(inode)->buf; - size_t read_start, read_end, avail, start_subbuf; - size_t buf_size = buf->chan->subbuf_size * buf->chan->n_subbufs; + size_t read_start, avail; void *from; + long long produced, consumed; + size_t subbuf_size = buf->chan->subbuf_size; + size_t n_subbufs = buf->chan->n_subbufs; + size_t write_offset = buf->offset > subbuf_size ? subbuf_size : buf->offset; - avail = relayfs_read_avail(buf, &start_subbuf); - if (*ppos >= avail) - return 0; + if (buf->offset > subbuf_size) + produced = (buf->subbufs_produced - 1) * subbuf_size + write_offset; + else + produced = buf->subbufs_produced * subbuf_size + write_offset; + consumed = buf->subbufs_consumed * subbuf_size + buf->bytes_consumed; - read_start = relayfs_read_start(*ppos, avail, start_subbuf, buf); - if (read_start == 0 && *ppos) + if (produced == consumed) return 0; - read_end = relayfs_read_end(read_start, avail, start_subbuf, buf); - if (read_end == read_start) - return 0; + relayfs_read_consume(buf, *ppos, 0); - from = buf->start + start_subbuf * buf->chan->subbuf_size + read_start; - if (from >= buf->start + buf_size) - from -= buf_size; + read_start = relayfs_read_start(*ppos, buf); - count = min(count, read_end - read_start); + avail = relayfs_read_avail(read_start, buf); + if (!avail) + return 0; + + from = buf->start + read_start; + count = min(count, avail); if (copy_to_user(buffer, from, count)) return -EFAULT; *ppos = read_start + count; + if (*ppos >= subbuf_size * n_subbufs) + *ppos = 0; + + relayfs_read_consume(buf, read_start, count); return count; } --- linux-2.6.13-rc6-mm2/fs/relayfs/relay.c~ 2005-08-23 14:29:08.000000000 +0200 +++ linux-2.6.13-rc6-mm2/fs/relayfs/relay.c 2005-08-23 14:29:48.000000000 +0200 @@ -58,6 +58,14 @@ void *prev_subbuf, size_t prev_padding) { + if (relay_buf_full(buf)) { +// if (smp_processor_id() == 0) { +// printk("buf full, cpu %u\n", smp_processor_id()); +// klog_printk("buf full, cpu %u\n", smp_processor_id()); +// } + return 0; + } + return 1; } @@ -262,6 +270,7 @@ for_each_online_cpu(i) { sprintf(tmpname, "%s%d", base_filename, i); chan->buf[i] = relay_open_buf(chan, tmpname, parent); + chan->buf[i]->cpu = i; if (!chan->buf[i]) goto free_bufs; } @@ -328,7 +337,7 @@ return length; toobig: - printk(KERN_WARNING "relayfs: event too large (%u)\n", length); + printk(KERN_WARNING "relayfs: event too large (%lu)\n", length); WARN_ON(1); return 0; } --- linux-2.6.13-rc6-mm2/include/linux/relayfs_fs.h~ 2005-08-23 14:29:21.000000000 +0200 +++ linux-2.6.13-rc6-mm2/include/linux/relayfs_fs.h 2005-08-23 14:29:31.000000000 +0200 @@ -22,7 +22,7 @@ /* * Tracks changes to rchan_buf struct */ -#define RELAYFS_CHANNEL_VERSION 4 +#define RELAYFS_CHANNEL_VERSION 5 /* * Per-cpu relay channel buffer @@ -44,6 +44,8 @@ unsigned int finalized; /* buffer has been finalized */ size_t *padding; /* padding counts per sub-buffer */ size_t prev_padding; /* temporary variable */ + size_t bytes_consumed; /* bytes consumed in cur read subbuf */ + unsigned int cpu; /* this buf's cpu */ } ____cacheline_aligned; /*