diff options
Diffstat (limited to 'kernel/kfifo.c')
| -rw-r--r-- | kernel/kfifo.c | 107 | 
1 files changed, 75 insertions, 32 deletions
| diff --git a/kernel/kfifo.c b/kernel/kfifo.c index e92d519f93b1..32c5c15d750d 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)); | 
| @@ -159,8 +159,9 @@ static inline void __kfifo_out_data(struct kfifo *fifo, | |||
| 159 | memcpy(to + l, fifo->buffer, len - l); | 159 | memcpy(to + l, fifo->buffer, len - l); | 
| 160 | } | 160 | } | 
| 161 | 161 | ||
| 162 | static inline unsigned int __kfifo_from_user_data(struct kfifo *fifo, | 162 | static inline int __kfifo_from_user_data(struct kfifo *fifo, | 
| 163 | const void __user *from, unsigned int len, unsigned int off) | 163 | const void __user *from, unsigned int len, unsigned int off, | 
| 164 | unsigned *lenout) | ||
| 164 | { | 165 | { | 
| 165 | unsigned int l; | 166 | unsigned int l; | 
| 166 | int ret; | 167 | int ret; | 
| @@ -177,16 +178,20 @@ static inline unsigned int __kfifo_from_user_data(struct kfifo *fifo, | |||
| 177 | /* first put the data starting from fifo->in to buffer end */ | 178 | /* first put the data starting from fifo->in to buffer end */ | 
| 178 | l = min(len, fifo->size - off); | 179 | l = min(len, fifo->size - off); | 
| 179 | ret = copy_from_user(fifo->buffer + off, from, l); | 180 | ret = copy_from_user(fifo->buffer + off, from, l); | 
| 180 | 181 | if (unlikely(ret)) { | |
| 181 | if (unlikely(ret)) | 182 | *lenout = ret; | 
| 182 | return ret + len - l; | 183 | return -EFAULT; | 
| 184 | } | ||
| 185 | *lenout = l; | ||
| 183 | 186 | ||
| 184 | /* then put the rest (if any) at the beginning of the buffer */ | 187 | /* then put the rest (if any) at the beginning of the buffer */ | 
| 185 | return copy_from_user(fifo->buffer, from + l, len - l); | 188 | ret = copy_from_user(fifo->buffer, from + l, len - l); | 
| 189 | *lenout += ret ? ret : len - l; | ||
| 190 | return ret ? -EFAULT : 0; | ||
| 186 | } | 191 | } | 
| 187 | 192 | ||
| 188 | static inline unsigned int __kfifo_to_user_data(struct kfifo *fifo, | 193 | static inline int __kfifo_to_user_data(struct kfifo *fifo, | 
| 189 | void __user *to, unsigned int len, unsigned int off) | 194 | void __user *to, unsigned int len, unsigned int off, unsigned *lenout) | 
| 190 | { | 195 | { | 
| 191 | unsigned int l; | 196 | unsigned int l; | 
| 192 | int ret; | 197 | int ret; | 
| @@ -203,12 +208,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 */ | 208 | /* first get the data from fifo->out until the end of the buffer */ | 
| 204 | l = min(len, fifo->size - off); | 209 | l = min(len, fifo->size - off); | 
| 205 | ret = copy_to_user(to, fifo->buffer + off, l); | 210 | ret = copy_to_user(to, fifo->buffer + off, l); | 
| 206 | 211 | *lenout = l; | |
| 207 | if (unlikely(ret)) | 212 | if (unlikely(ret)) { | 
| 208 | return ret + len - l; | 213 | *lenout -= ret; | 
| 214 | return -EFAULT; | ||
| 215 | } | ||
| 209 | 216 | ||
| 210 | /* then get the rest (if any) from the beginning of the buffer */ | 217 | /* then get the rest (if any) from the beginning of the buffer */ | 
| 211 | return copy_to_user(to + l, fifo->buffer, len - l); | 218 | len -= l; | 
| 219 | ret = copy_to_user(to + l, fifo->buffer, len); | ||
| 220 | if (unlikely(ret)) { | ||
| 221 | *lenout += len - ret; | ||
| 222 | return -EFAULT; | ||
| 223 | } | ||
| 224 | *lenout += len; | ||
| 225 | return 0; | ||
| 212 | } | 226 | } | 
| 213 | 227 | ||
| 214 | unsigned int __kfifo_in_n(struct kfifo *fifo, | 228 | unsigned int __kfifo_in_n(struct kfifo *fifo, | 
| @@ -235,7 +249,7 @@ EXPORT_SYMBOL(__kfifo_in_n); | |||
| 235 | * Note that with only one concurrent reader and one concurrent | 249 | * Note that with only one concurrent reader and one concurrent | 
| 236 | * writer, you don't need extra locking to use these functions. | 250 | * writer, you don't need extra locking to use these functions. | 
| 237 | */ | 251 | */ | 
| 238 | unsigned int kfifo_in(struct kfifo *fifo, const unsigned char *from, | 252 | unsigned int kfifo_in(struct kfifo *fifo, const void *from, | 
| 239 | unsigned int len) | 253 | unsigned int len) | 
| 240 | { | 254 | { | 
| 241 | len = min(kfifo_avail(fifo), len); | 255 | len = min(kfifo_avail(fifo), len); | 
| @@ -277,7 +291,7 @@ EXPORT_SYMBOL(__kfifo_out_n); | |||
| 277 | * Note that with only one concurrent reader and one concurrent | 291 | * Note that with only one concurrent reader and one concurrent | 
| 278 | * writer, you don't need extra locking to use these functions. | 292 | * writer, you don't need extra locking to use these functions. | 
| 279 | */ | 293 | */ | 
| 280 | unsigned int kfifo_out(struct kfifo *fifo, unsigned char *to, unsigned int len) | 294 | unsigned int kfifo_out(struct kfifo *fifo, void *to, unsigned int len) | 
| 281 | { | 295 | { | 
| 282 | len = min(kfifo_len(fifo), len); | 296 | len = min(kfifo_len(fifo), len); | 
| 283 | 297 | ||
| @@ -288,6 +302,27 @@ unsigned int kfifo_out(struct kfifo *fifo, unsigned char *to, unsigned int len) | |||
| 288 | } | 302 | } | 
| 289 | EXPORT_SYMBOL(kfifo_out); | 303 | EXPORT_SYMBOL(kfifo_out); | 
| 290 | 304 | ||
| 305 | /** | ||
| 306 | * kfifo_out_peek - copy some data from the FIFO, but do not remove it | ||
| 307 | * @fifo: the fifo to be used. | ||
| 308 | * @to: where the data must be copied. | ||
| 309 | * @len: the size of the destination buffer. | ||
| 310 | * @offset: offset into the fifo | ||
| 311 | * | ||
| 312 | * This function copies at most @len bytes at @offset from the FIFO | ||
| 313 | * into the @to buffer and returns the number of copied bytes. | ||
| 314 | * The data is not removed from the FIFO. | ||
| 315 | */ | ||
| 316 | unsigned int kfifo_out_peek(struct kfifo *fifo, void *to, unsigned int len, | ||
| 317 | unsigned offset) | ||
| 318 | { | ||
| 319 | len = min(kfifo_len(fifo), len + offset); | ||
| 320 | |||
| 321 | __kfifo_out_data(fifo, to, len, offset); | ||
| 322 | return len; | ||
| 323 | } | ||
| 324 | EXPORT_SYMBOL(kfifo_out_peek); | ||
| 325 | |||
| 291 | unsigned int __kfifo_out_generic(struct kfifo *fifo, | 326 | unsigned int __kfifo_out_generic(struct kfifo *fifo, | 
| 292 | void *to, unsigned int len, unsigned int recsize, | 327 | void *to, unsigned int len, unsigned int recsize, | 
| 293 | unsigned int *total) | 328 | unsigned int *total) | 
| @@ -299,10 +334,13 @@ EXPORT_SYMBOL(__kfifo_out_generic); | |||
| 299 | unsigned int __kfifo_from_user_n(struct kfifo *fifo, | 334 | unsigned int __kfifo_from_user_n(struct kfifo *fifo, | 
| 300 | const void __user *from, unsigned int len, unsigned int recsize) | 335 | const void __user *from, unsigned int len, unsigned int recsize) | 
| 301 | { | 336 | { | 
| 337 | unsigned total; | ||
| 338 | |||
| 302 | if (kfifo_avail(fifo) < len + recsize) | 339 | if (kfifo_avail(fifo) < len + recsize) | 
| 303 | return len + 1; | 340 | return len + 1; | 
| 304 | 341 | ||
| 305 | return __kfifo_from_user_data(fifo, from, len, recsize); | 342 | __kfifo_from_user_data(fifo, from, len, recsize, &total); | 
| 343 | return total; | ||
| 306 | } | 344 | } | 
| 307 | EXPORT_SYMBOL(__kfifo_from_user_n); | 345 | EXPORT_SYMBOL(__kfifo_from_user_n); | 
| 308 | 346 | ||
| @@ -313,18 +351,21 @@ EXPORT_SYMBOL(__kfifo_from_user_n); | |||
| 313 | * @len: the length of the data to be added. | 351 | * @len: the length of the data to be added. | 
| 314 | * | 352 | * | 
| 315 | * This function copies at most @len bytes from the @from into the | 353 | * This function copies at most @len bytes from the @from into the | 
| 316 | * FIFO depending and returns the number of copied bytes. | 354 | * FIFO depending and returns -EFAULT/0. | 
| 317 | * | 355 | * | 
| 318 | * Note that with only one concurrent reader and one concurrent | 356 | * Note that with only one concurrent reader and one concurrent | 
| 319 | * writer, you don't need extra locking to use these functions. | 357 | * writer, you don't need extra locking to use these functions. | 
| 320 | */ | 358 | */ | 
| 321 | unsigned int kfifo_from_user(struct kfifo *fifo, | 359 | int kfifo_from_user(struct kfifo *fifo, | 
| 322 | const void __user *from, unsigned int len) | 360 | const void __user *from, unsigned int len, unsigned *total) | 
| 323 | { | 361 | { | 
| 362 | int ret; | ||
| 324 | len = min(kfifo_avail(fifo), len); | 363 | len = min(kfifo_avail(fifo), len); | 
| 325 | len -= __kfifo_from_user_data(fifo, from, len, 0); | 364 | ret = __kfifo_from_user_data(fifo, from, len, 0, total); | 
| 365 | if (ret) | ||
| 366 | return ret; | ||
| 326 | __kfifo_add_in(fifo, len); | 367 | __kfifo_add_in(fifo, len); | 
| 327 | return len; | 368 | return 0; | 
| 328 | } | 369 | } | 
| 329 | EXPORT_SYMBOL(kfifo_from_user); | 370 | EXPORT_SYMBOL(kfifo_from_user); | 
| 330 | 371 | ||
| @@ -339,17 +380,17 @@ unsigned int __kfifo_to_user_n(struct kfifo *fifo, | |||
| 339 | void __user *to, unsigned int len, unsigned int reclen, | 380 | void __user *to, unsigned int len, unsigned int reclen, | 
| 340 | unsigned int recsize) | 381 | unsigned int recsize) | 
| 341 | { | 382 | { | 
| 342 | unsigned int ret; | 383 | unsigned int ret, total; | 
| 343 | 384 | ||
| 344 | if (kfifo_len(fifo) < reclen + recsize) | 385 | if (kfifo_len(fifo) < reclen + recsize) | 
| 345 | return len; | 386 | return len; | 
| 346 | 387 | ||
| 347 | ret = __kfifo_to_user_data(fifo, to, reclen, recsize); | 388 | ret = __kfifo_to_user_data(fifo, to, reclen, recsize, &total); | 
| 348 | 389 | ||
| 349 | if (likely(ret == 0)) | 390 | if (likely(ret == 0)) | 
| 350 | __kfifo_add_out(fifo, reclen + recsize); | 391 | __kfifo_add_out(fifo, reclen + recsize); | 
| 351 | 392 | ||
| 352 | return ret; | 393 | return total; | 
| 353 | } | 394 | } | 
| 354 | EXPORT_SYMBOL(__kfifo_to_user_n); | 395 | EXPORT_SYMBOL(__kfifo_to_user_n); | 
| 355 | 396 | ||
| @@ -358,20 +399,22 @@ EXPORT_SYMBOL(__kfifo_to_user_n); | |||
| 358 | * @fifo: the fifo to be used. | 399 | * @fifo: the fifo to be used. | 
| 359 | * @to: where the data must be copied. | 400 | * @to: where the data must be copied. | 
| 360 | * @len: the size of the destination buffer. | 401 | * @len: the size of the destination buffer. | 
| 402 | @ @lenout: pointer to output variable with copied data | ||
| 361 | * | 403 | * | 
| 362 | * This function copies at most @len bytes from the FIFO into the | 404 | * This function copies at most @len bytes from the FIFO into the | 
| 363 | * @to buffer and returns the number of copied bytes. | 405 | * @to buffer and 0 or -EFAULT. | 
| 364 | * | 406 | * | 
| 365 | * Note that with only one concurrent reader and one concurrent | 407 | * Note that with only one concurrent reader and one concurrent | 
| 366 | * writer, you don't need extra locking to use these functions. | 408 | * writer, you don't need extra locking to use these functions. | 
| 367 | */ | 409 | */ | 
| 368 | unsigned int kfifo_to_user(struct kfifo *fifo, | 410 | int kfifo_to_user(struct kfifo *fifo, | 
| 369 | void __user *to, unsigned int len) | 411 | void __user *to, unsigned int len, unsigned *lenout) | 
| 370 | { | 412 | { | 
| 413 | int ret; | ||
| 371 | len = min(kfifo_len(fifo), len); | 414 | len = min(kfifo_len(fifo), len); | 
| 372 | len -= __kfifo_to_user_data(fifo, to, len, 0); | 415 | ret = __kfifo_to_user_data(fifo, to, len, 0, lenout); | 
| 373 | __kfifo_add_out(fifo, len); | 416 | __kfifo_add_out(fifo, *lenout); | 
| 374 | return len; | 417 | return ret; | 
| 375 | } | 418 | } | 
| 376 | EXPORT_SYMBOL(kfifo_to_user); | 419 | EXPORT_SYMBOL(kfifo_to_user); | 
| 377 | 420 | ||
