aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorPaul E. McKenney <paulmck@us.ibm.com>2006-09-29 05:00:11 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-09-29 12:18:13 -0400
commita45bce49545739a940f8bd4ca85c3b7435564893 (patch)
tree3f558e487448db9e49c8d4cd36379d9f42f93da2 /kernel
parent99de055ac065e19ed69de961e97c6336a261b34e (diff)
[PATCH] memory ordering in __kfifo primitives
Both __kfifo_put() and __kfifo_get() have header comments stating that if there is but one concurrent reader and one concurrent writer, locking is not necessary. This is almost the case, but a couple of memory barriers are needed. Another option would be to change the header comments to remove the bit about locking not being needed, and to change the those callers who currently don't use locking to add the required locking. The attachment analyzes this approach, but the patch below seems simpler. Signed-off-by: Paul E. McKenney <paulmck@us.ibm.com> Cc: Stelian Pop <stelian@popies.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/kfifo.c28
1 files changed, 28 insertions, 0 deletions
diff --git a/kernel/kfifo.c b/kernel/kfifo.c
index 64ab045c3d9..5d1d907378a 100644
--- a/kernel/kfifo.c
+++ b/kernel/kfifo.c
@@ -122,6 +122,13 @@ unsigned int __kfifo_put(struct kfifo *fifo,
122 122
123 len = min(len, fifo->size - fifo->in + fifo->out); 123 len = min(len, fifo->size - fifo->in + fifo->out);
124 124
125 /*
126 * Ensure that we sample the fifo->out index -before- we
127 * start putting bytes into the kfifo.
128 */
129
130 smp_mb();
131
125 /* first put the data starting from fifo->in to buffer end */ 132 /* first put the data starting from fifo->in to buffer end */
126 l = min(len, fifo->size - (fifo->in & (fifo->size - 1))); 133 l = min(len, fifo->size - (fifo->in & (fifo->size - 1)));
127 memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l); 134 memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l);
@@ -129,6 +136,13 @@ unsigned int __kfifo_put(struct kfifo *fifo,
129 /* then put the rest (if any) at the beginning of the buffer */ 136 /* then put the rest (if any) at the beginning of the buffer */
130 memcpy(fifo->buffer, buffer + l, len - l); 137 memcpy(fifo->buffer, buffer + l, len - l);
131 138
139 /*
140 * Ensure that we add the bytes to the kfifo -before-
141 * we update the fifo->in index.
142 */
143
144 smp_wmb();
145
132 fifo->in += len; 146 fifo->in += len;
133 147
134 return len; 148 return len;
@@ -154,6 +168,13 @@ unsigned int __kfifo_get(struct kfifo *fifo,
154 168
155 len = min(len, fifo->in - fifo->out); 169 len = min(len, fifo->in - fifo->out);
156 170
171 /*
172 * Ensure that we sample the fifo->in index -before- we
173 * start removing bytes from the kfifo.
174 */
175
176 smp_rmb();
177
157 /* first get the data from fifo->out until the end of the buffer */ 178 /* first get the data from fifo->out until the end of the buffer */
158 l = min(len, fifo->size - (fifo->out & (fifo->size - 1))); 179 l = min(len, fifo->size - (fifo->out & (fifo->size - 1)));
159 memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size - 1)), l); 180 memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size - 1)), l);
@@ -161,6 +182,13 @@ unsigned int __kfifo_get(struct kfifo *fifo,
161 /* then get the rest (if any) from the beginning of the buffer */ 182 /* then get the rest (if any) from the beginning of the buffer */
162 memcpy(buffer + l, fifo->buffer, len - l); 183 memcpy(buffer + l, fifo->buffer, len - l);
163 184
185 /*
186 * Ensure that we remove the bytes from the kfifo -before-
187 * we update the fifo->out index.
188 */
189
190 smp_mb();
191
164 fifo->out += len; 192 fifo->out += len;
165 193
166 return len; 194 return len;