diff options
Diffstat (limited to 'kernel/kfifo.c')
-rw-r--r-- | kernel/kfifo.c | 111 |
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 | ||
31 | static void _kfifo_init(struct kfifo *fifo, unsigned char *buffer, | 31 | static 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 | */ |
47 | void kfifo_init(struct kfifo *fifo, unsigned char *buffer, unsigned int size) | 47 | void 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); | |||
97 | void kfifo_free(struct kfifo *fifo) | 97 | void kfifo_free(struct kfifo *fifo) |
98 | { | 98 | { |
99 | kfree(fifo->buffer); | 99 | kfree(fifo->buffer); |
100 | _kfifo_init(fifo, NULL, 0); | ||
100 | } | 101 | } |
101 | EXPORT_SYMBOL(kfifo_free); | 102 | EXPORT_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 | ||
162 | static inline unsigned int __kfifo_from_user_data(struct kfifo *fifo, | 163 | static 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 | ||
188 | static inline unsigned int __kfifo_to_user_data(struct kfifo *fifo, | 194 | static 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 | ||
214 | unsigned int __kfifo_in_n(struct kfifo *fifo, | 229 | unsigned 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 | */ |
238 | unsigned int kfifo_in(struct kfifo *fifo, const unsigned char *from, | 253 | unsigned 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 | */ |
280 | unsigned int kfifo_out(struct kfifo *fifo, unsigned char *to, unsigned int len) | 295 | unsigned 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 | } |
289 | EXPORT_SYMBOL(kfifo_out); | 304 | EXPORT_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 | */ | ||
317 | unsigned 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 | } | ||
325 | EXPORT_SYMBOL(kfifo_out_peek); | ||
326 | |||
291 | unsigned int __kfifo_out_generic(struct kfifo *fifo, | 327 | unsigned 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); | |||
299 | unsigned int __kfifo_from_user_n(struct kfifo *fifo, | 335 | unsigned 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 | } |
307 | EXPORT_SYMBOL(__kfifo_from_user_n); | 346 | EXPORT_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 | */ |
321 | unsigned int kfifo_from_user(struct kfifo *fifo, | 361 | int 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 | } |
329 | EXPORT_SYMBOL(kfifo_from_user); | 372 | EXPORT_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 | } |
354 | EXPORT_SYMBOL(__kfifo_to_user_n); | 397 | EXPORT_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 | */ |
368 | unsigned int kfifo_to_user(struct kfifo *fifo, | 412 | int 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 | } |
376 | EXPORT_SYMBOL(kfifo_to_user); | 421 | EXPORT_SYMBOL(kfifo_to_user); |
377 | 422 | ||