diff options
Diffstat (limited to 'kernel/kfifo.c')
| -rw-r--r-- | kernel/kfifo.c | 408 | 
1 files changed, 327 insertions, 81 deletions
| diff --git a/kernel/kfifo.c b/kernel/kfifo.c index 3765ff3c1bbe..32c5c15d750d 100644 --- a/kernel/kfifo.c +++ b/kernel/kfifo.c | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | /* | 1 | /* | 
| 2 | * A simple kernel FIFO implementation. | 2 | * A generic kernel FIFO implementation. | 
| 3 | * | 3 | * | 
| 4 | * Copyright (C) 2009 Stefani Seibold <stefani@seibold.net> | ||
| 4 | * Copyright (C) 2004 Stelian Pop <stelian@popies.net> | 5 | * Copyright (C) 2004 Stelian Pop <stelian@popies.net> | 
| 5 | * | 6 | * | 
| 6 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify | 
| @@ -25,50 +26,48 @@ | |||
| 25 | #include <linux/err.h> | 26 | #include <linux/err.h> | 
| 26 | #include <linux/kfifo.h> | 27 | #include <linux/kfifo.h> | 
| 27 | #include <linux/log2.h> | 28 | #include <linux/log2.h> | 
| 29 | #include <linux/uaccess.h> | ||
| 30 | |||
| 31 | static void _kfifo_init(struct kfifo *fifo, void *buffer, | ||
| 32 | unsigned int size) | ||
| 33 | { | ||
| 34 | fifo->buffer = buffer; | ||
| 35 | fifo->size = size; | ||
| 36 | |||
| 37 | kfifo_reset(fifo); | ||
| 38 | } | ||
| 28 | 39 | ||
| 29 | /** | 40 | /** | 
| 30 | * kfifo_init - allocates a new FIFO using a preallocated buffer | 41 | * kfifo_init - initialize a FIFO using a preallocated buffer | 
| 42 | * @fifo: the fifo to assign the buffer | ||
| 31 | * @buffer: the preallocated buffer to be used. | 43 | * @buffer: the preallocated buffer to be used. | 
| 32 | * @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. | 
| 33 | * @gfp_mask: get_free_pages mask, passed to kmalloc() | ||
| 34 | * @lock: the lock to be used to protect the fifo buffer | ||
| 35 | * | 45 | * | 
| 36 | * Do NOT pass the kfifo to kfifo_free() after use! Simply free the | ||
| 37 | * &struct kfifo with kfree(). | ||
| 38 | */ | 46 | */ | 
| 39 | struct kfifo *kfifo_init(unsigned char *buffer, unsigned int size, | 47 | void kfifo_init(struct kfifo *fifo, void *buffer, unsigned int size) | 
| 40 | gfp_t gfp_mask, spinlock_t *lock) | ||
| 41 | { | 48 | { | 
| 42 | struct kfifo *fifo; | ||
| 43 | |||
| 44 | /* size must be a power of 2 */ | 49 | /* size must be a power of 2 */ | 
| 45 | BUG_ON(!is_power_of_2(size)); | 50 | BUG_ON(!is_power_of_2(size)); | 
| 46 | 51 | ||
| 47 | fifo = kmalloc(sizeof(struct kfifo), gfp_mask); | 52 | _kfifo_init(fifo, buffer, size); | 
| 48 | if (!fifo) | ||
| 49 | return ERR_PTR(-ENOMEM); | ||
| 50 | |||
| 51 | fifo->buffer = buffer; | ||
| 52 | fifo->size = size; | ||
| 53 | fifo->in = fifo->out = 0; | ||
| 54 | fifo->lock = lock; | ||
| 55 | |||
| 56 | return fifo; | ||
| 57 | } | 53 | } | 
| 58 | EXPORT_SYMBOL(kfifo_init); | 54 | EXPORT_SYMBOL(kfifo_init); | 
| 59 | 55 | ||
| 60 | /** | 56 | /** | 
| 61 | * kfifo_alloc - allocates a new FIFO and its internal buffer | 57 | * kfifo_alloc - allocates a new FIFO internal buffer | 
| 62 | * @size: the size of the internal buffer to be allocated. | 58 | * @fifo: the fifo to assign then new buffer | 
| 59 | * @size: the size of the buffer to be allocated, this have to be a power of 2. | ||
| 63 | * @gfp_mask: get_free_pages mask, passed to kmalloc() | 60 | * @gfp_mask: get_free_pages mask, passed to kmalloc() | 
| 64 | * @lock: the lock to be used to protect the fifo buffer | 61 | * | 
| 62 | * This function dynamically allocates a new fifo internal buffer | ||
| 65 | * | 63 | * | 
| 66 | * The size will be rounded-up to a power of 2. | 64 | * The size will be rounded-up to a power of 2. | 
| 65 | * The buffer will be release with kfifo_free(). | ||
| 66 | * Return 0 if no error, otherwise the an error code | ||
| 67 | */ | 67 | */ | 
| 68 | struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask, spinlock_t *lock) | 68 | int kfifo_alloc(struct kfifo *fifo, unsigned int size, gfp_t gfp_mask) | 
| 69 | { | 69 | { | 
| 70 | unsigned char *buffer; | 70 | unsigned char *buffer; | 
| 71 | struct kfifo *ret; | ||
| 72 | 71 | ||
| 73 | /* | 72 | /* | 
| 74 | * round up to the next power of 2, since our 'let the indices | 73 | * round up to the next power of 2, since our 'let the indices | 
| @@ -80,48 +79,92 @@ struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask, spinlock_t *lock) | |||
| 80 | } | 79 | } | 
| 81 | 80 | ||
| 82 | buffer = kmalloc(size, gfp_mask); | 81 | buffer = kmalloc(size, gfp_mask); | 
| 83 | if (!buffer) | 82 | if (!buffer) { | 
| 84 | return ERR_PTR(-ENOMEM); | 83 | _kfifo_init(fifo, 0, 0); | 
| 85 | 84 | return -ENOMEM; | |
| 86 | ret = kfifo_init(buffer, size, gfp_mask, lock); | 85 | } | 
| 87 | 86 | ||
| 88 | if (IS_ERR(ret)) | 87 | _kfifo_init(fifo, buffer, size); | 
| 89 | kfree(buffer); | ||
| 90 | 88 | ||
| 91 | return ret; | 89 | return 0; | 
| 92 | } | 90 | } | 
| 93 | EXPORT_SYMBOL(kfifo_alloc); | 91 | EXPORT_SYMBOL(kfifo_alloc); | 
| 94 | 92 | ||
| 95 | /** | 93 | /** | 
| 96 | * kfifo_free - frees the FIFO | 94 | * kfifo_free - frees the FIFO internal buffer | 
| 97 | * @fifo: the fifo to be freed. | 95 | * @fifo: the fifo to be freed. | 
| 98 | */ | 96 | */ | 
| 99 | void kfifo_free(struct kfifo *fifo) | 97 | void kfifo_free(struct kfifo *fifo) | 
| 100 | { | 98 | { | 
| 101 | kfree(fifo->buffer); | 99 | kfree(fifo->buffer); | 
| 102 | kfree(fifo); | ||
| 103 | } | 100 | } | 
| 104 | EXPORT_SYMBOL(kfifo_free); | 101 | EXPORT_SYMBOL(kfifo_free); | 
| 105 | 102 | ||
| 106 | /** | 103 | /** | 
| 107 | * __kfifo_put - puts some data into the FIFO, no locking version | 104 | * kfifo_skip - skip output data | 
| 108 | * @fifo: the fifo to be used. | 105 | * @fifo: the fifo to be used. | 
| 109 | * @buffer: the data to be added. | 106 | * @len: number of bytes to skip | 
| 110 | * @len: the length of the data to be added. | ||
| 111 | * | ||
| 112 | * This function copies at most @len bytes from the @buffer into | ||
| 113 | * the FIFO depending on the free space, and returns the number of | ||
| 114 | * bytes copied. | ||
| 115 | * | ||
| 116 | * Note that with only one concurrent reader and one concurrent | ||
| 117 | * writer, you don't need extra locking to use these functions. | ||
| 118 | */ | 107 | */ | 
| 119 | unsigned int __kfifo_put(struct kfifo *fifo, | 108 | void kfifo_skip(struct kfifo *fifo, unsigned int len) | 
| 120 | const unsigned char *buffer, unsigned int len) | 109 | { | 
| 110 | if (len < kfifo_len(fifo)) { | ||
| 111 | __kfifo_add_out(fifo, len); | ||
| 112 | return; | ||
| 113 | } | ||
| 114 | kfifo_reset_out(fifo); | ||
| 115 | } | ||
| 116 | EXPORT_SYMBOL(kfifo_skip); | ||
| 117 | |||
| 118 | static inline void __kfifo_in_data(struct kfifo *fifo, | ||
| 119 | const void *from, unsigned int len, unsigned int off) | ||
| 121 | { | 120 | { | 
| 122 | unsigned int l; | 121 | unsigned int l; | 
| 123 | 122 | ||
| 124 | len = min(len, fifo->size - fifo->in + fifo->out); | 123 | /* | 
| 124 | * Ensure that we sample the fifo->out index -before- we | ||
| 125 | * start putting bytes into the kfifo. | ||
| 126 | */ | ||
| 127 | |||
| 128 | smp_mb(); | ||
| 129 | |||
| 130 | off = __kfifo_off(fifo, fifo->in + off); | ||
| 131 | |||
| 132 | /* first put the data starting from fifo->in to buffer end */ | ||
| 133 | l = min(len, fifo->size - off); | ||
| 134 | memcpy(fifo->buffer + off, from, l); | ||
| 135 | |||
| 136 | /* then put the rest (if any) at the beginning of the buffer */ | ||
| 137 | memcpy(fifo->buffer, from + l, len - l); | ||
| 138 | } | ||
| 139 | |||
| 140 | static inline void __kfifo_out_data(struct kfifo *fifo, | ||
| 141 | void *to, unsigned int len, unsigned int off) | ||
| 142 | { | ||
| 143 | unsigned int l; | ||
| 144 | |||
| 145 | /* | ||
| 146 | * Ensure that we sample the fifo->in index -before- we | ||
| 147 | * start removing bytes from the kfifo. | ||
| 148 | */ | ||
| 149 | |||
| 150 | smp_rmb(); | ||
| 151 | |||
| 152 | off = __kfifo_off(fifo, fifo->out + off); | ||
| 153 | |||
| 154 | /* first get the data from fifo->out until the end of the buffer */ | ||
| 155 | l = min(len, fifo->size - off); | ||
| 156 | memcpy(to, fifo->buffer + off, l); | ||
| 157 | |||
| 158 | /* then get the rest (if any) from the beginning of the buffer */ | ||
| 159 | memcpy(to + l, fifo->buffer, len - l); | ||
| 160 | } | ||
| 161 | |||
| 162 | static inline int __kfifo_from_user_data(struct kfifo *fifo, | ||
| 163 | const void __user *from, unsigned int len, unsigned int off, | ||
| 164 | unsigned *lenout) | ||
| 165 | { | ||
| 166 | unsigned int l; | ||
| 167 | int ret; | ||
| 125 | 168 | ||
| 126 | /* | 169 | /* | 
| 127 | * Ensure that we sample the fifo->out index -before- we | 170 | * Ensure that we sample the fifo->out index -before- we | 
| @@ -130,68 +173,271 @@ unsigned int __kfifo_put(struct kfifo *fifo, | |||
| 130 | 173 | ||
| 131 | smp_mb(); | 174 | smp_mb(); | 
| 132 | 175 | ||
| 176 | off = __kfifo_off(fifo, fifo->in + off); | ||
| 177 | |||
| 133 | /* first put the data starting from fifo->in to buffer end */ | 178 | /* first put the data starting from fifo->in to buffer end */ | 
| 134 | l = min(len, fifo->size - (fifo->in & (fifo->size - 1))); | 179 | l = min(len, fifo->size - off); | 
| 135 | memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l); | 180 | ret = copy_from_user(fifo->buffer + off, from, l); | 
| 181 | if (unlikely(ret)) { | ||
| 182 | *lenout = ret; | ||
| 183 | return -EFAULT; | ||
| 184 | } | ||
| 185 | *lenout = l; | ||
| 136 | 186 | ||
| 137 | /* 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 */ | 
| 138 | memcpy(fifo->buffer, buffer + 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; | ||
| 191 | } | ||
| 192 | |||
| 193 | static inline int __kfifo_to_user_data(struct kfifo *fifo, | ||
| 194 | void __user *to, unsigned int len, unsigned int off, unsigned *lenout) | ||
| 195 | { | ||
| 196 | unsigned int l; | ||
| 197 | int ret; | ||
| 139 | 198 | ||
| 140 | /* | 199 | /* | 
| 141 | * Ensure that we add the bytes to the kfifo -before- | 200 | * Ensure that we sample the fifo->in index -before- we | 
| 142 | * we update the fifo->in index. | 201 | * start removing bytes from the kfifo. | 
| 143 | */ | 202 | */ | 
| 144 | 203 | ||
| 145 | smp_wmb(); | 204 | smp_rmb(); | 
| 205 | |||
| 206 | off = __kfifo_off(fifo, fifo->out + off); | ||
| 207 | |||
| 208 | /* first get the data from fifo->out until the end of the buffer */ | ||
| 209 | l = min(len, fifo->size - off); | ||
| 210 | ret = copy_to_user(to, fifo->buffer + off, l); | ||
| 211 | *lenout = l; | ||
| 212 | if (unlikely(ret)) { | ||
| 213 | *lenout -= ret; | ||
| 214 | return -EFAULT; | ||
| 215 | } | ||
| 216 | |||
| 217 | /* then get the rest (if any) from the beginning of the buffer */ | ||
| 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; | ||
| 226 | } | ||
| 227 | |||
| 228 | unsigned int __kfifo_in_n(struct kfifo *fifo, | ||
| 229 | const void *from, unsigned int len, unsigned int recsize) | ||
| 230 | { | ||
| 231 | if (kfifo_avail(fifo) < len + recsize) | ||
| 232 | return len + 1; | ||
| 233 | |||
| 234 | __kfifo_in_data(fifo, from, len, recsize); | ||
| 235 | return 0; | ||
| 236 | } | ||
| 237 | EXPORT_SYMBOL(__kfifo_in_n); | ||
| 146 | 238 | ||
| 147 | fifo->in += len; | 239 | /** | 
| 240 | * kfifo_in - puts some data into the FIFO | ||
| 241 | * @fifo: the fifo to be used. | ||
| 242 | * @from: the data to be added. | ||
| 243 | * @len: the length of the data to be added. | ||
| 244 | * | ||
| 245 | * This function copies at most @len bytes from the @from buffer into | ||
| 246 | * the FIFO depending on the free space, and returns the number of | ||
| 247 | * bytes copied. | ||
| 248 | * | ||
| 249 | * Note that with only one concurrent reader and one concurrent | ||
| 250 | * writer, you don't need extra locking to use these functions. | ||
| 251 | */ | ||
| 252 | unsigned int kfifo_in(struct kfifo *fifo, const void *from, | ||
| 253 | unsigned int len) | ||
| 254 | { | ||
| 255 | len = min(kfifo_avail(fifo), len); | ||
| 148 | 256 | ||
| 257 | __kfifo_in_data(fifo, from, len, 0); | ||
| 258 | __kfifo_add_in(fifo, len); | ||
| 149 | return len; | 259 | return len; | 
| 150 | } | 260 | } | 
| 151 | EXPORT_SYMBOL(__kfifo_put); | 261 | EXPORT_SYMBOL(kfifo_in); | 
| 262 | |||
| 263 | unsigned int __kfifo_in_generic(struct kfifo *fifo, | ||
| 264 | const void *from, unsigned int len, unsigned int recsize) | ||
| 265 | { | ||
| 266 | return __kfifo_in_rec(fifo, from, len, recsize); | ||
| 267 | } | ||
| 268 | EXPORT_SYMBOL(__kfifo_in_generic); | ||
| 269 | |||
| 270 | unsigned int __kfifo_out_n(struct kfifo *fifo, | ||
| 271 | void *to, unsigned int len, unsigned int recsize) | ||
| 272 | { | ||
| 273 | if (kfifo_len(fifo) < len + recsize) | ||
| 274 | return len; | ||
| 275 | |||
| 276 | __kfifo_out_data(fifo, to, len, recsize); | ||
| 277 | __kfifo_add_out(fifo, len + recsize); | ||
| 278 | return 0; | ||
| 279 | } | ||
| 280 | EXPORT_SYMBOL(__kfifo_out_n); | ||
| 152 | 281 | ||
| 153 | /** | 282 | /** | 
| 154 | * __kfifo_get - gets some data from the FIFO, no locking version | 283 | * kfifo_out - gets some data from the FIFO | 
| 155 | * @fifo: the fifo to be used. | 284 | * @fifo: the fifo to be used. | 
| 156 | * @buffer: where the data must be copied. | 285 | * @to: where the data must be copied. | 
| 157 | * @len: the size of the destination buffer. | 286 | * @len: the size of the destination buffer. | 
| 158 | * | 287 | * | 
| 159 | * This function copies at most @len bytes from the FIFO into the | 288 | * This function copies at most @len bytes from the FIFO into the | 
| 160 | * @buffer and returns the number of copied bytes. | 289 | * @to buffer and returns the number of copied bytes. | 
| 161 | * | 290 | * | 
| 162 | * Note that with only one concurrent reader and one concurrent | 291 | * Note that with only one concurrent reader and one concurrent | 
| 163 | * writer, you don't need extra locking to use these functions. | 292 | * writer, you don't need extra locking to use these functions. | 
| 164 | */ | 293 | */ | 
| 165 | unsigned int __kfifo_get(struct kfifo *fifo, | 294 | unsigned int kfifo_out(struct kfifo *fifo, void *to, unsigned int len) | 
| 166 | unsigned char *buffer, unsigned int len) | ||
| 167 | { | 295 | { | 
| 168 | unsigned int l; | 296 | len = min(kfifo_len(fifo), len); | 
| 169 | 297 | ||
| 170 | len = min(len, fifo->in - fifo->out); | 298 | __kfifo_out_data(fifo, to, len, 0); | 
| 299 | __kfifo_add_out(fifo, len); | ||
| 171 | 300 | ||
| 172 | /* | 301 | return len; | 
| 173 | * Ensure that we sample the fifo->in index -before- we | 302 | } | 
| 174 | * start removing bytes from the kfifo. | 303 | EXPORT_SYMBOL(kfifo_out); | 
| 175 | */ | ||
| 176 | 304 | ||
| 177 | smp_rmb(); | 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); | ||
| 178 | 320 | ||
| 179 | /* first get the data from fifo->out until the end of the buffer */ | 321 | __kfifo_out_data(fifo, to, len, offset); | 
| 180 | l = min(len, fifo->size - (fifo->out & (fifo->size - 1))); | 322 | return len; | 
| 181 | memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size - 1)), l); | 323 | } | 
| 324 | EXPORT_SYMBOL(kfifo_out_peek); | ||
| 182 | 325 | ||
| 183 | /* then get the rest (if any) from the beginning of the buffer */ | 326 | unsigned int __kfifo_out_generic(struct kfifo *fifo, | 
| 184 | memcpy(buffer + l, fifo->buffer, len - l); | 327 | void *to, unsigned int len, unsigned int recsize, | 
| 328 | unsigned int *total) | ||
| 329 | { | ||
| 330 | return __kfifo_out_rec(fifo, to, len, recsize, total); | ||
| 331 | } | ||
| 332 | EXPORT_SYMBOL(__kfifo_out_generic); | ||
| 185 | 333 | ||
| 186 | /* | 334 | unsigned int __kfifo_from_user_n(struct kfifo *fifo, | 
| 187 | * Ensure that we remove the bytes from the kfifo -before- | 335 | const void __user *from, unsigned int len, unsigned int recsize) | 
| 188 | * we update the fifo->out index. | 336 | { | 
| 189 | */ | 337 | unsigned total; | 
| 190 | 338 | ||
| 191 | smp_mb(); | 339 | if (kfifo_avail(fifo) < len + recsize) | 
| 340 | return len + 1; | ||
| 192 | 341 | ||
| 193 | fifo->out += len; | 342 | __kfifo_from_user_data(fifo, from, len, recsize, &total); | 
| 343 | return total; | ||
| 344 | } | ||
| 345 | EXPORT_SYMBOL(__kfifo_from_user_n); | ||
| 194 | 346 | ||
| 195 | return len; | 347 | /** | 
| 348 | * kfifo_from_user - puts some data from user space into the FIFO | ||
| 349 | * @fifo: the fifo to be used. | ||
| 350 | * @from: pointer to the data to be added. | ||
| 351 | * @len: the length of the data to be added. | ||
| 352 | * | ||
| 353 | * This function copies at most @len bytes from the @from into the | ||
| 354 | * FIFO depending and returns -EFAULT/0. | ||
| 355 | * | ||
| 356 | * Note that with only one concurrent reader and one concurrent | ||
| 357 | * writer, you don't need extra locking to use these functions. | ||
| 358 | */ | ||
| 359 | int kfifo_from_user(struct kfifo *fifo, | ||
| 360 | const void __user *from, unsigned int len, unsigned *total) | ||
| 361 | { | ||
| 362 | int ret; | ||
| 363 | len = min(kfifo_avail(fifo), len); | ||
| 364 | ret = __kfifo_from_user_data(fifo, from, len, 0, total); | ||
| 365 | if (ret) | ||
| 366 | return ret; | ||
| 367 | __kfifo_add_in(fifo, len); | ||
| 368 | return 0; | ||
| 196 | } | 369 | } | 
| 197 | EXPORT_SYMBOL(__kfifo_get); | 370 | EXPORT_SYMBOL(kfifo_from_user); | 
| 371 | |||
| 372 | unsigned int __kfifo_from_user_generic(struct kfifo *fifo, | ||
| 373 | const void __user *from, unsigned int len, unsigned int recsize) | ||
| 374 | { | ||
| 375 | return __kfifo_from_user_rec(fifo, from, len, recsize); | ||
| 376 | } | ||
| 377 | EXPORT_SYMBOL(__kfifo_from_user_generic); | ||
| 378 | |||
| 379 | unsigned int __kfifo_to_user_n(struct kfifo *fifo, | ||
| 380 | void __user *to, unsigned int len, unsigned int reclen, | ||
| 381 | unsigned int recsize) | ||
| 382 | { | ||
| 383 | unsigned int ret, total; | ||
| 384 | |||
| 385 | if (kfifo_len(fifo) < reclen + recsize) | ||
| 386 | return len; | ||
| 387 | |||
| 388 | ret = __kfifo_to_user_data(fifo, to, reclen, recsize, &total); | ||
| 389 | |||
| 390 | if (likely(ret == 0)) | ||
| 391 | __kfifo_add_out(fifo, reclen + recsize); | ||
| 392 | |||
| 393 | return total; | ||
| 394 | } | ||
| 395 | EXPORT_SYMBOL(__kfifo_to_user_n); | ||
| 396 | |||
| 397 | /** | ||
| 398 | * kfifo_to_user - gets data from the FIFO and write it to user space | ||
| 399 | * @fifo: the fifo to be used. | ||
| 400 | * @to: where the data must be copied. | ||
| 401 | * @len: the size of the destination buffer. | ||
| 402 | @ @lenout: pointer to output variable with copied data | ||
| 403 | * | ||
| 404 | * This function copies at most @len bytes from the FIFO into the | ||
| 405 | * @to buffer and 0 or -EFAULT. | ||
| 406 | * | ||
| 407 | * Note that with only one concurrent reader and one concurrent | ||
| 408 | * writer, you don't need extra locking to use these functions. | ||
| 409 | */ | ||
| 410 | int kfifo_to_user(struct kfifo *fifo, | ||
| 411 | void __user *to, unsigned int len, unsigned *lenout) | ||
| 412 | { | ||
| 413 | int ret; | ||
| 414 | len = min(kfifo_len(fifo), len); | ||
| 415 | ret = __kfifo_to_user_data(fifo, to, len, 0, lenout); | ||
| 416 | __kfifo_add_out(fifo, *lenout); | ||
| 417 | return ret; | ||
| 418 | } | ||
| 419 | EXPORT_SYMBOL(kfifo_to_user); | ||
| 420 | |||
| 421 | unsigned int __kfifo_to_user_generic(struct kfifo *fifo, | ||
| 422 | void __user *to, unsigned int len, unsigned int recsize, | ||
| 423 | unsigned int *total) | ||
| 424 | { | ||
| 425 | return __kfifo_to_user_rec(fifo, to, len, recsize, total); | ||
| 426 | } | ||
| 427 | EXPORT_SYMBOL(__kfifo_to_user_generic); | ||
| 428 | |||
| 429 | unsigned int __kfifo_peek_generic(struct kfifo *fifo, unsigned int recsize) | ||
| 430 | { | ||
| 431 | if (recsize == 0) | ||
| 432 | return kfifo_avail(fifo); | ||
| 433 | |||
| 434 | return __kfifo_peek_n(fifo, recsize); | ||
| 435 | } | ||
| 436 | EXPORT_SYMBOL(__kfifo_peek_generic); | ||
| 437 | |||
| 438 | void __kfifo_skip_generic(struct kfifo *fifo, unsigned int recsize) | ||
| 439 | { | ||
| 440 | __kfifo_skip_rec(fifo, recsize); | ||
| 441 | } | ||
| 442 | EXPORT_SYMBOL(__kfifo_skip_generic); | ||
| 443 | |||
