aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/kfifo.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/kfifo.c')
-rw-r--r--kernel/kfifo.c111
1 files changed, 78 insertions, 33 deletions
diff --git a/kernel/kfifo.c b/kernel/kfifo.c
index e92d519f93b1..35edbe22e9a9 100644
--- a/kernel/kfifo.c
+++ b/kernel/kfifo.c
@@ -28,7 +28,7 @@
28#include <linux/log2.h> 28#include <linux/log2.h>
29#include <linux/uaccess.h> 29#include <linux/uaccess.h>
30 30
31static void _kfifo_init(struct kfifo *fifo, unsigned char *buffer, 31static void _kfifo_init(struct kfifo *fifo, void *buffer,
32 unsigned int size) 32 unsigned int size)
33{ 33{
34 fifo->buffer = buffer; 34 fifo->buffer = buffer;
@@ -41,10 +41,10 @@ static void _kfifo_init(struct kfifo *fifo, unsigned char *buffer,
41 * kfifo_init - initialize a FIFO using a preallocated buffer 41 * kfifo_init - initialize a FIFO using a preallocated buffer
42 * @fifo: the fifo to assign the buffer 42 * @fifo: the fifo to assign the buffer
43 * @buffer: the preallocated buffer to be used. 43 * @buffer: the preallocated buffer to be used.
44 * @size: the size of the internal buffer, this have to be a power of 2. 44 * @size: the size of the internal buffer, this has to be a power of 2.
45 * 45 *
46 */ 46 */
47void kfifo_init(struct kfifo *fifo, unsigned char *buffer, unsigned int size) 47void kfifo_init(struct kfifo *fifo, void *buffer, unsigned int size)
48{ 48{
49 /* size must be a power of 2 */ 49 /* size must be a power of 2 */
50 BUG_ON(!is_power_of_2(size)); 50 BUG_ON(!is_power_of_2(size));
@@ -80,7 +80,7 @@ int kfifo_alloc(struct kfifo *fifo, unsigned int size, gfp_t gfp_mask)
80 80
81 buffer = kmalloc(size, gfp_mask); 81 buffer = kmalloc(size, gfp_mask);
82 if (!buffer) { 82 if (!buffer) {
83 _kfifo_init(fifo, 0, 0); 83 _kfifo_init(fifo, NULL, 0);
84 return -ENOMEM; 84 return -ENOMEM;
85 } 85 }
86 86
@@ -97,6 +97,7 @@ EXPORT_SYMBOL(kfifo_alloc);
97void kfifo_free(struct kfifo *fifo) 97void kfifo_free(struct kfifo *fifo)
98{ 98{
99 kfree(fifo->buffer); 99 kfree(fifo->buffer);
100 _kfifo_init(fifo, NULL, 0);
100} 101}
101EXPORT_SYMBOL(kfifo_free); 102EXPORT_SYMBOL(kfifo_free);
102 103
@@ -159,8 +160,9 @@ static inline void __kfifo_out_data(struct kfifo *fifo,
159 memcpy(to + l, fifo->buffer, len - l); 160 memcpy(to + l, fifo->buffer, len - l);
160} 161}
161 162
162static inline unsigned int __kfifo_from_user_data(struct kfifo *fifo, 163static inline int __kfifo_from_user_data(struct kfifo *fifo,
163 const void __user *from, unsigned int len, unsigned int off) 164 const void __user *from, unsigned int len, unsigned int off,
165 unsigned *lenout)
164{ 166{
165 unsigned int l; 167 unsigned int l;
166 int ret; 168 int ret;
@@ -177,16 +179,20 @@ static inline unsigned int __kfifo_from_user_data(struct kfifo *fifo,
177 /* first put the data starting from fifo->in to buffer end */ 179 /* first put the data starting from fifo->in to buffer end */
178 l = min(len, fifo->size - off); 180 l = min(len, fifo->size - off);
179 ret = copy_from_user(fifo->buffer + off, from, l); 181 ret = copy_from_user(fifo->buffer + off, from, l);
180 182 if (unlikely(ret)) {
181 if (unlikely(ret)) 183 *lenout = ret;
182 return ret + len - l; 184 return -EFAULT;
185 }
186 *lenout = l;
183 187
184 /* then put the rest (if any) at the beginning of the buffer */ 188 /* then put the rest (if any) at the beginning of the buffer */
185 return copy_from_user(fifo->buffer, from + l, len - l); 189 ret = copy_from_user(fifo->buffer, from + l, len - l);
190 *lenout += ret ? ret : len - l;
191 return ret ? -EFAULT : 0;
186} 192}
187 193
188static inline unsigned int __kfifo_to_user_data(struct kfifo *fifo, 194static inline int __kfifo_to_user_data(struct kfifo *fifo,
189 void __user *to, unsigned int len, unsigned int off) 195 void __user *to, unsigned int len, unsigned int off, unsigned *lenout)
190{ 196{
191 unsigned int l; 197 unsigned int l;
192 int ret; 198 int ret;
@@ -203,12 +209,21 @@ static inline unsigned int __kfifo_to_user_data(struct kfifo *fifo,
203 /* first get the data from fifo->out until the end of the buffer */ 209 /* first get the data from fifo->out until the end of the buffer */
204 l = min(len, fifo->size - off); 210 l = min(len, fifo->size - off);
205 ret = copy_to_user(to, fifo->buffer + off, l); 211 ret = copy_to_user(to, fifo->buffer + off, l);
206 212 *lenout = l;
207 if (unlikely(ret)) 213 if (unlikely(ret)) {
208 return ret + len - l; 214 *lenout -= ret;
215 return -EFAULT;
216 }
209 217
210 /* then get the rest (if any) from the beginning of the buffer */ 218 /* then get the rest (if any) from the beginning of the buffer */
211 return copy_to_user(to + l, fifo->buffer, len - l); 219 len -= l;
220 ret = copy_to_user(to + l, fifo->buffer, len);
221 if (unlikely(ret)) {
222 *lenout += len - ret;
223 return -EFAULT;
224 }
225 *lenout += len;
226 return 0;
212} 227}
213 228
214unsigned int __kfifo_in_n(struct kfifo *fifo, 229unsigned int __kfifo_in_n(struct kfifo *fifo,
@@ -235,7 +250,7 @@ EXPORT_SYMBOL(__kfifo_in_n);
235 * Note that with only one concurrent reader and one concurrent 250 * Note that with only one concurrent reader and one concurrent
236 * writer, you don't need extra locking to use these functions. 251 * writer, you don't need extra locking to use these functions.
237 */ 252 */
238unsigned int kfifo_in(struct kfifo *fifo, const unsigned char *from, 253unsigned int kfifo_in(struct kfifo *fifo, const void *from,
239 unsigned int len) 254 unsigned int len)
240{ 255{
241 len = min(kfifo_avail(fifo), len); 256 len = min(kfifo_avail(fifo), len);
@@ -277,7 +292,7 @@ EXPORT_SYMBOL(__kfifo_out_n);
277 * Note that with only one concurrent reader and one concurrent 292 * Note that with only one concurrent reader and one concurrent
278 * writer, you don't need extra locking to use these functions. 293 * writer, you don't need extra locking to use these functions.
279 */ 294 */
280unsigned int kfifo_out(struct kfifo *fifo, unsigned char *to, unsigned int len) 295unsigned int kfifo_out(struct kfifo *fifo, void *to, unsigned int len)
281{ 296{
282 len = min(kfifo_len(fifo), len); 297 len = min(kfifo_len(fifo), len);
283 298
@@ -288,6 +303,27 @@ unsigned int kfifo_out(struct kfifo *fifo, unsigned char *to, unsigned int len)
288} 303}
289EXPORT_SYMBOL(kfifo_out); 304EXPORT_SYMBOL(kfifo_out);
290 305
306/**
307 * kfifo_out_peek - copy some data from the FIFO, but do not remove it
308 * @fifo: the fifo to be used.
309 * @to: where the data must be copied.
310 * @len: the size of the destination buffer.
311 * @offset: offset into the fifo
312 *
313 * This function copies at most @len bytes at @offset from the FIFO
314 * into the @to buffer and returns the number of copied bytes.
315 * The data is not removed from the FIFO.
316 */
317unsigned int kfifo_out_peek(struct kfifo *fifo, void *to, unsigned int len,
318 unsigned offset)
319{
320 len = min(kfifo_len(fifo), len + offset);
321
322 __kfifo_out_data(fifo, to, len, offset);
323 return len;
324}
325EXPORT_SYMBOL(kfifo_out_peek);
326
291unsigned int __kfifo_out_generic(struct kfifo *fifo, 327unsigned int __kfifo_out_generic(struct kfifo *fifo,
292 void *to, unsigned int len, unsigned int recsize, 328 void *to, unsigned int len, unsigned int recsize,
293 unsigned int *total) 329 unsigned int *total)
@@ -299,10 +335,13 @@ EXPORT_SYMBOL(__kfifo_out_generic);
299unsigned int __kfifo_from_user_n(struct kfifo *fifo, 335unsigned int __kfifo_from_user_n(struct kfifo *fifo,
300 const void __user *from, unsigned int len, unsigned int recsize) 336 const void __user *from, unsigned int len, unsigned int recsize)
301{ 337{
338 unsigned total;
339
302 if (kfifo_avail(fifo) < len + recsize) 340 if (kfifo_avail(fifo) < len + recsize)
303 return len + 1; 341 return len + 1;
304 342
305 return __kfifo_from_user_data(fifo, from, len, recsize); 343 __kfifo_from_user_data(fifo, from, len, recsize, &total);
344 return total;
306} 345}
307EXPORT_SYMBOL(__kfifo_from_user_n); 346EXPORT_SYMBOL(__kfifo_from_user_n);
308 347
@@ -311,20 +350,24 @@ EXPORT_SYMBOL(__kfifo_from_user_n);
311 * @fifo: the fifo to be used. 350 * @fifo: the fifo to be used.
312 * @from: pointer to the data to be added. 351 * @from: pointer to the data to be added.
313 * @len: the length of the data to be added. 352 * @len: the length of the data to be added.
353 * @total: the actual returned data length.
314 * 354 *
315 * This function copies at most @len bytes from the @from into the 355 * This function copies at most @len bytes from the @from into the
316 * FIFO depending and returns the number of copied bytes. 356 * FIFO depending and returns -EFAULT/0.
317 * 357 *
318 * Note that with only one concurrent reader and one concurrent 358 * Note that with only one concurrent reader and one concurrent
319 * writer, you don't need extra locking to use these functions. 359 * writer, you don't need extra locking to use these functions.
320 */ 360 */
321unsigned int kfifo_from_user(struct kfifo *fifo, 361int kfifo_from_user(struct kfifo *fifo,
322 const void __user *from, unsigned int len) 362 const void __user *from, unsigned int len, unsigned *total)
323{ 363{
364 int ret;
324 len = min(kfifo_avail(fifo), len); 365 len = min(kfifo_avail(fifo), len);
325 len -= __kfifo_from_user_data(fifo, from, len, 0); 366 ret = __kfifo_from_user_data(fifo, from, len, 0, total);
367 if (ret)
368 return ret;
326 __kfifo_add_in(fifo, len); 369 __kfifo_add_in(fifo, len);
327 return len; 370 return 0;
328} 371}
329EXPORT_SYMBOL(kfifo_from_user); 372EXPORT_SYMBOL(kfifo_from_user);
330 373
@@ -339,17 +382,17 @@ unsigned int __kfifo_to_user_n(struct kfifo *fifo,
339 void __user *to, unsigned int len, unsigned int reclen, 382 void __user *to, unsigned int len, unsigned int reclen,
340 unsigned int recsize) 383 unsigned int recsize)
341{ 384{
342 unsigned int ret; 385 unsigned int ret, total;
343 386
344 if (kfifo_len(fifo) < reclen + recsize) 387 if (kfifo_len(fifo) < reclen + recsize)
345 return len; 388 return len;
346 389
347 ret = __kfifo_to_user_data(fifo, to, reclen, recsize); 390 ret = __kfifo_to_user_data(fifo, to, reclen, recsize, &total);
348 391
349 if (likely(ret == 0)) 392 if (likely(ret == 0))
350 __kfifo_add_out(fifo, reclen + recsize); 393 __kfifo_add_out(fifo, reclen + recsize);
351 394
352 return ret; 395 return total;
353} 396}
354EXPORT_SYMBOL(__kfifo_to_user_n); 397EXPORT_SYMBOL(__kfifo_to_user_n);
355 398
@@ -358,20 +401,22 @@ EXPORT_SYMBOL(__kfifo_to_user_n);
358 * @fifo: the fifo to be used. 401 * @fifo: the fifo to be used.
359 * @to: where the data must be copied. 402 * @to: where the data must be copied.
360 * @len: the size of the destination buffer. 403 * @len: the size of the destination buffer.
404 * @lenout: pointer to output variable with copied data
361 * 405 *
362 * This function copies at most @len bytes from the FIFO into the 406 * This function copies at most @len bytes from the FIFO into the
363 * @to buffer and returns the number of copied bytes. 407 * @to buffer and 0 or -EFAULT.
364 * 408 *
365 * Note that with only one concurrent reader and one concurrent 409 * Note that with only one concurrent reader and one concurrent
366 * writer, you don't need extra locking to use these functions. 410 * writer, you don't need extra locking to use these functions.
367 */ 411 */
368unsigned int kfifo_to_user(struct kfifo *fifo, 412int kfifo_to_user(struct kfifo *fifo,
369 void __user *to, unsigned int len) 413 void __user *to, unsigned int len, unsigned *lenout)
370{ 414{
415 int ret;
371 len = min(kfifo_len(fifo), len); 416 len = min(kfifo_len(fifo), len);
372 len -= __kfifo_to_user_data(fifo, to, len, 0); 417 ret = __kfifo_to_user_data(fifo, to, len, 0, lenout);
373 __kfifo_add_out(fifo, len); 418 __kfifo_add_out(fifo, *lenout);
374 return len; 419 return ret;
375} 420}
376EXPORT_SYMBOL(kfifo_to_user); 421EXPORT_SYMBOL(kfifo_to_user);
377 422