aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/kfifo.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/kfifo.c')
-rw-r--r--kernel/kfifo.c76
1 files changed, 49 insertions, 27 deletions
diff --git a/kernel/kfifo.c b/kernel/kfifo.c
index ab615e695052..b50bb622e8b0 100644
--- a/kernel/kfifo.c
+++ b/kernel/kfifo.c
@@ -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
162static inline unsigned int __kfifo_from_user_data(struct kfifo *fifo, 162static 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
188static inline unsigned int __kfifo_to_user_data(struct kfifo *fifo, 193static 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
214unsigned int __kfifo_in_n(struct kfifo *fifo, 228unsigned int __kfifo_in_n(struct kfifo *fifo,
@@ -299,10 +313,13 @@ EXPORT_SYMBOL(__kfifo_out_generic);
299unsigned int __kfifo_from_user_n(struct kfifo *fifo, 313unsigned int __kfifo_from_user_n(struct kfifo *fifo,
300 const void __user *from, unsigned int len, unsigned int recsize) 314 const void __user *from, unsigned int len, unsigned int recsize)
301{ 315{
316 unsigned total;
317
302 if (kfifo_avail(fifo) < len + recsize) 318 if (kfifo_avail(fifo) < len + recsize)
303 return len + 1; 319 return len + 1;
304 320
305 return __kfifo_from_user_data(fifo, from, len, recsize); 321 __kfifo_from_user_data(fifo, from, len, recsize, &total);
322 return total;
306} 323}
307EXPORT_SYMBOL(__kfifo_from_user_n); 324EXPORT_SYMBOL(__kfifo_from_user_n);
308 325
@@ -313,18 +330,21 @@ EXPORT_SYMBOL(__kfifo_from_user_n);
313 * @len: the length of the data to be added. 330 * @len: the length of the data to be added.
314 * 331 *
315 * This function copies at most @len bytes from the @from into the 332 * This function copies at most @len bytes from the @from into the
316 * FIFO depending and returns the number of copied bytes. 333 * FIFO depending and returns -EFAULT/0.
317 * 334 *
318 * Note that with only one concurrent reader and one concurrent 335 * Note that with only one concurrent reader and one concurrent
319 * writer, you don't need extra locking to use these functions. 336 * writer, you don't need extra locking to use these functions.
320 */ 337 */
321unsigned int kfifo_from_user(struct kfifo *fifo, 338int kfifo_from_user(struct kfifo *fifo,
322 const void __user *from, unsigned int len) 339 const void __user *from, unsigned int len, unsigned *total)
323{ 340{
341 int ret;
324 len = min(kfifo_avail(fifo), len); 342 len = min(kfifo_avail(fifo), len);
325 len -= __kfifo_from_user_data(fifo, from, len, 0); 343 ret = __kfifo_from_user_data(fifo, from, len, 0, total);
344 if (ret)
345 return ret;
326 __kfifo_add_in(fifo, len); 346 __kfifo_add_in(fifo, len);
327 return len; 347 return 0;
328} 348}
329EXPORT_SYMBOL(kfifo_from_user); 349EXPORT_SYMBOL(kfifo_from_user);
330 350
@@ -339,17 +359,17 @@ unsigned int __kfifo_to_user_n(struct kfifo *fifo,
339 void __user *to, unsigned int len, unsigned int reclen, 359 void __user *to, unsigned int len, unsigned int reclen,
340 unsigned int recsize) 360 unsigned int recsize)
341{ 361{
342 unsigned int ret; 362 unsigned int ret, total;
343 363
344 if (kfifo_len(fifo) < reclen + recsize) 364 if (kfifo_len(fifo) < reclen + recsize)
345 return len; 365 return len;
346 366
347 ret = __kfifo_to_user_data(fifo, to, reclen, recsize); 367 ret = __kfifo_to_user_data(fifo, to, reclen, recsize, &total);
348 368
349 if (likely(ret == 0)) 369 if (likely(ret == 0))
350 __kfifo_add_out(fifo, reclen + recsize); 370 __kfifo_add_out(fifo, reclen + recsize);
351 371
352 return ret; 372 return total;
353} 373}
354EXPORT_SYMBOL(__kfifo_to_user_n); 374EXPORT_SYMBOL(__kfifo_to_user_n);
355 375
@@ -358,20 +378,22 @@ EXPORT_SYMBOL(__kfifo_to_user_n);
358 * @fifo: the fifo to be used. 378 * @fifo: the fifo to be used.
359 * @to: where the data must be copied. 379 * @to: where the data must be copied.
360 * @len: the size of the destination buffer. 380 * @len: the size of the destination buffer.
381 @ @lenout: pointer to output variable with copied data
361 * 382 *
362 * This function copies at most @len bytes from the FIFO into the 383 * This function copies at most @len bytes from the FIFO into the
363 * @to buffer and returns the number of copied bytes. 384 * @to buffer and 0 or -EFAULT.
364 * 385 *
365 * Note that with only one concurrent reader and one concurrent 386 * Note that with only one concurrent reader and one concurrent
366 * writer, you don't need extra locking to use these functions. 387 * writer, you don't need extra locking to use these functions.
367 */ 388 */
368unsigned int kfifo_to_user(struct kfifo *fifo, 389int kfifo_to_user(struct kfifo *fifo,
369 void __user *to, unsigned int len) 390 void __user *to, unsigned int len, unsigned *lenout)
370{ 391{
392 int ret;
371 len = min(kfifo_len(fifo), len); 393 len = min(kfifo_len(fifo), len);
372 len -= __kfifo_to_user_data(fifo, to, len, 0); 394 ret = __kfifo_to_user_data(fifo, to, len, 0, lenout);
373 __kfifo_add_out(fifo, len); 395 __kfifo_add_out(fifo, *lenout);
374 return len; 396 return ret;
375} 397}
376EXPORT_SYMBOL(kfifo_to_user); 398EXPORT_SYMBOL(kfifo_to_user);
377 399