aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/kfifo.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/kfifo.c')
-rw-r--r--kernel/kfifo.c286
1 files changed, 193 insertions, 93 deletions
diff --git a/kernel/kfifo.c b/kernel/kfifo.c
index 2a78425ef67f..e92d519f93b1 100644
--- a/kernel/kfifo.c
+++ b/kernel/kfifo.c
@@ -115,27 +115,11 @@ void kfifo_skip(struct kfifo *fifo, unsigned int len)
115} 115}
116EXPORT_SYMBOL(kfifo_skip); 116EXPORT_SYMBOL(kfifo_skip);
117 117
118/** 118static inline void __kfifo_in_data(struct kfifo *fifo,
119 * kfifo_in - puts some data into the FIFO 119 const void *from, unsigned int len, unsigned int off)
120 * @fifo: the fifo to be used.
121 * @from: the data to be added.
122 * @len: the length of the data to be added.
123 *
124 * This function copies at most @len bytes from the @from buffer into
125 * the FIFO depending on the free space, and returns the number of
126 * bytes copied.
127 *
128 * Note that with only one concurrent reader and one concurrent
129 * writer, you don't need extra locking to use these functions.
130 */
131unsigned int kfifo_in(struct kfifo *fifo,
132 const unsigned char *from, unsigned int len)
133{ 120{
134 unsigned int off;
135 unsigned int l; 121 unsigned int l;
136 122
137 len = min(len, fifo->size - fifo->in + fifo->out);
138
139 /* 123 /*
140 * Ensure that we sample the fifo->out index -before- we 124 * Ensure that we sample the fifo->out index -before- we
141 * start putting bytes into the kfifo. 125 * start putting bytes into the kfifo.
@@ -143,7 +127,7 @@ unsigned int kfifo_in(struct kfifo *fifo,
143 127
144 smp_mb(); 128 smp_mb();
145 129
146 off = __kfifo_off(fifo, fifo->in); 130 off = __kfifo_off(fifo, fifo->in + off);
147 131
148 /* first put the data starting from fifo->in to buffer end */ 132 /* first put the data starting from fifo->in to buffer end */
149 l = min(len, fifo->size - off); 133 l = min(len, fifo->size - off);
@@ -151,33 +135,13 @@ unsigned int kfifo_in(struct kfifo *fifo,
151 135
152 /* then put the rest (if any) at the beginning of the buffer */ 136 /* then put the rest (if any) at the beginning of the buffer */
153 memcpy(fifo->buffer, from + l, len - l); 137 memcpy(fifo->buffer, from + l, len - l);
154
155 __kfifo_add_in(fifo, len);
156
157 return len;
158} 138}
159EXPORT_SYMBOL(kfifo_in);
160 139
161/** 140static inline void __kfifo_out_data(struct kfifo *fifo,
162 * kfifo_out - gets some data from the FIFO 141 void *to, unsigned int len, unsigned int off)
163 * @fifo: the fifo to be used.
164 * @to: where the data must be copied.
165 * @len: the size of the destination buffer.
166 *
167 * This function copies at most @len bytes from the FIFO into the
168 * @to buffer and returns the number of copied bytes.
169 *
170 * Note that with only one concurrent reader and one concurrent
171 * writer, you don't need extra locking to use these functions.
172 */
173unsigned int kfifo_out(struct kfifo *fifo,
174 unsigned char *to, unsigned int len)
175{ 142{
176 unsigned int off;
177 unsigned int l; 143 unsigned int l;
178 144
179 len = min(len, fifo->in - fifo->out);
180
181 /* 145 /*
182 * Ensure that we sample the fifo->in index -before- we 146 * Ensure that we sample the fifo->in index -before- we
183 * start removing bytes from the kfifo. 147 * start removing bytes from the kfifo.
@@ -185,7 +149,7 @@ unsigned int kfifo_out(struct kfifo *fifo,
185 149
186 smp_rmb(); 150 smp_rmb();
187 151
188 off = __kfifo_off(fifo, fifo->out); 152 off = __kfifo_off(fifo, fifo->out + off);
189 153
190 /* first get the data from fifo->out until the end of the buffer */ 154 /* first get the data from fifo->out until the end of the buffer */
191 l = min(len, fifo->size - off); 155 l = min(len, fifo->size - off);
@@ -193,34 +157,14 @@ unsigned int kfifo_out(struct kfifo *fifo,
193 157
194 /* then get the rest (if any) from the beginning of the buffer */ 158 /* then get the rest (if any) from the beginning of the buffer */
195 memcpy(to + l, fifo->buffer, len - l); 159 memcpy(to + l, fifo->buffer, len - l);
196
197 __kfifo_add_out(fifo, len);
198
199 return len;
200} 160}
201EXPORT_SYMBOL(kfifo_out);
202 161
203/** 162static inline unsigned int __kfifo_from_user_data(struct kfifo *fifo,
204 * kfifo_from_user - puts some data from user space into the FIFO 163 const void __user *from, unsigned int len, unsigned int off)
205 * @fifo: the fifo to be used.
206 * @from: pointer to the data to be added.
207 * @len: the length of the data to be added.
208 *
209 * This function copies at most @len bytes from the @from into the
210 * FIFO depending and returns the number of copied bytes.
211 *
212 * Note that with only one concurrent reader and one concurrent
213 * writer, you don't need extra locking to use these functions.
214 */
215unsigned int kfifo_from_user(struct kfifo *fifo,
216 const void __user *from, unsigned int len)
217{ 164{
218 unsigned int off;
219 unsigned int l; 165 unsigned int l;
220 int ret; 166 int ret;
221 167
222 len = min(len, fifo->size - fifo->in + fifo->out);
223
224 /* 168 /*
225 * Ensure that we sample the fifo->out index -before- we 169 * Ensure that we sample the fifo->out index -before- we
226 * start putting bytes into the kfifo. 170 * start putting bytes into the kfifo.
@@ -228,29 +172,101 @@ unsigned int kfifo_from_user(struct kfifo *fifo,
228 172
229 smp_mb(); 173 smp_mb();
230 174
231 off = __kfifo_off(fifo, fifo->in); 175 off = __kfifo_off(fifo, fifo->in + off);
232 176
233 /* first put the data starting from fifo->in to buffer end */ 177 /* first put the data starting from fifo->in to buffer end */
234 l = min(len, fifo->size - off); 178 l = min(len, fifo->size - off);
235 ret = copy_from_user(fifo->buffer + off, from, l); 179 ret = copy_from_user(fifo->buffer + off, from, l);
236 180
237 if (unlikely(ret)) 181 if (unlikely(ret))
238 return l - ret; 182 return ret + len - l;
239 183
240 /* then put the rest (if any) at the beginning of the buffer */ 184 /* then put the rest (if any) at the beginning of the buffer */
241 ret = copy_from_user(fifo->buffer, from + l, len - l); 185 return copy_from_user(fifo->buffer, from + l, len - l);
186}
187
188static inline unsigned int __kfifo_to_user_data(struct kfifo *fifo,
189 void __user *to, unsigned int len, unsigned int off)
190{
191 unsigned int l;
192 int ret;
193
194 /*
195 * Ensure that we sample the fifo->in index -before- we
196 * start removing bytes from the kfifo.
197 */
198
199 smp_rmb();
200
201 off = __kfifo_off(fifo, fifo->out + off);
202
203 /* first get the data from fifo->out until the end of the buffer */
204 l = min(len, fifo->size - off);
205 ret = copy_to_user(to, fifo->buffer + off, l);
242 206
243 if (unlikely(ret)) 207 if (unlikely(ret))
244 return len - ret; 208 return ret + len - l;
245 209
246 __kfifo_add_in(fifo, len); 210 /* then get the rest (if any) from the beginning of the buffer */
211 return copy_to_user(to + l, fifo->buffer, len - l);
212}
247 213
214unsigned int __kfifo_in_n(struct kfifo *fifo,
215 const void *from, unsigned int len, unsigned int recsize)
216{
217 if (kfifo_avail(fifo) < len + recsize)
218 return len + 1;
219
220 __kfifo_in_data(fifo, from, len, recsize);
221 return 0;
222}
223EXPORT_SYMBOL(__kfifo_in_n);
224
225/**
226 * kfifo_in - puts some data into the FIFO
227 * @fifo: the fifo to be used.
228 * @from: the data to be added.
229 * @len: the length of the data to be added.
230 *
231 * This function copies at most @len bytes from the @from buffer into
232 * the FIFO depending on the free space, and returns the number of
233 * bytes copied.
234 *
235 * Note that with only one concurrent reader and one concurrent
236 * writer, you don't need extra locking to use these functions.
237 */
238unsigned int kfifo_in(struct kfifo *fifo, const unsigned char *from,
239 unsigned int len)
240{
241 len = min(kfifo_avail(fifo), len);
242
243 __kfifo_in_data(fifo, from, len, 0);
244 __kfifo_add_in(fifo, len);
248 return len; 245 return len;
249} 246}
250EXPORT_SYMBOL(kfifo_from_user); 247EXPORT_SYMBOL(kfifo_in);
248
249unsigned int __kfifo_in_generic(struct kfifo *fifo,
250 const void *from, unsigned int len, unsigned int recsize)
251{
252 return __kfifo_in_rec(fifo, from, len, recsize);
253}
254EXPORT_SYMBOL(__kfifo_in_generic);
255
256unsigned int __kfifo_out_n(struct kfifo *fifo,
257 void *to, unsigned int len, unsigned int recsize)
258{
259 if (kfifo_len(fifo) < len + recsize)
260 return len;
261
262 __kfifo_out_data(fifo, to, len, recsize);
263 __kfifo_add_out(fifo, len + recsize);
264 return 0;
265}
266EXPORT_SYMBOL(__kfifo_out_n);
251 267
252/** 268/**
253 * kfifo_to_user - gets data from the FIFO and write it to user space 269 * kfifo_out - gets some data from the FIFO
254 * @fifo: the fifo to be used. 270 * @fifo: the fifo to be used.
255 * @to: where the data must be copied. 271 * @to: where the data must be copied.
256 * @len: the size of the destination buffer. 272 * @len: the size of the destination buffer.
@@ -261,40 +277,124 @@ EXPORT_SYMBOL(kfifo_from_user);
261 * Note that with only one concurrent reader and one concurrent 277 * Note that with only one concurrent reader and one concurrent
262 * writer, you don't need extra locking to use these functions. 278 * writer, you don't need extra locking to use these functions.
263 */ 279 */
264unsigned int kfifo_to_user(struct kfifo *fifo, 280unsigned int kfifo_out(struct kfifo *fifo, unsigned char *to, unsigned int len)
265 void __user *to, unsigned int len)
266{ 281{
267 unsigned int off; 282 len = min(kfifo_len(fifo), len);
268 unsigned int l;
269 int ret;
270 283
271 len = min(len, fifo->in - fifo->out); 284 __kfifo_out_data(fifo, to, len, 0);
285 __kfifo_add_out(fifo, len);
272 286
273 /* 287 return len;
274 * Ensure that we sample the fifo->in index -before- we 288}
275 * start removing bytes from the kfifo. 289EXPORT_SYMBOL(kfifo_out);
276 */
277 290
278 smp_rmb(); 291unsigned int __kfifo_out_generic(struct kfifo *fifo,
292 void *to, unsigned int len, unsigned int recsize,
293 unsigned int *total)
294{
295 return __kfifo_out_rec(fifo, to, len, recsize, total);
296}
297EXPORT_SYMBOL(__kfifo_out_generic);
279 298
280 off = __kfifo_off(fifo, fifo->out); 299unsigned int __kfifo_from_user_n(struct kfifo *fifo,
300 const void __user *from, unsigned int len, unsigned int recsize)
301{
302 if (kfifo_avail(fifo) < len + recsize)
303 return len + 1;
281 304
282 /* first get the data from fifo->out until the end of the buffer */ 305 return __kfifo_from_user_data(fifo, from, len, recsize);
283 l = min(len, fifo->size - off); 306}
284 ret = copy_to_user(to, fifo->buffer + off, l); 307EXPORT_SYMBOL(__kfifo_from_user_n);
285 308
286 if (unlikely(ret)) 309/**
287 return l - ret; 310 * kfifo_from_user - puts some data from user space into the FIFO
311 * @fifo: the fifo to be used.
312 * @from: pointer to the data to be added.
313 * @len: the length of the data to be added.
314 *
315 * This function copies at most @len bytes from the @from into the
316 * FIFO depending and returns the number of copied bytes.
317 *
318 * Note that with only one concurrent reader and one concurrent
319 * writer, you don't need extra locking to use these functions.
320 */
321unsigned int kfifo_from_user(struct kfifo *fifo,
322 const void __user *from, unsigned int len)
323{
324 len = min(kfifo_avail(fifo), len);
325 len -= __kfifo_from_user_data(fifo, from, len, 0);
326 __kfifo_add_in(fifo, len);
327 return len;
328}
329EXPORT_SYMBOL(kfifo_from_user);
288 330
289 /* then get the rest (if any) from the beginning of the buffer */ 331unsigned int __kfifo_from_user_generic(struct kfifo *fifo,
290 ret = copy_to_user(to + l, fifo->buffer, len - l); 332 const void __user *from, unsigned int len, unsigned int recsize)
333{
334 return __kfifo_from_user_rec(fifo, from, len, recsize);
335}
336EXPORT_SYMBOL(__kfifo_from_user_generic);
291 337
292 if (unlikely(ret)) 338unsigned int __kfifo_to_user_n(struct kfifo *fifo,
293 return len - ret; 339 void __user *to, unsigned int len, unsigned int reclen,
340 unsigned int recsize)
341{
342 unsigned int ret;
294 343
295 __kfifo_add_out(fifo, len); 344 if (kfifo_len(fifo) < reclen + recsize)
345 return len;
296 346
347 ret = __kfifo_to_user_data(fifo, to, reclen, recsize);
348
349 if (likely(ret == 0))
350 __kfifo_add_out(fifo, reclen + recsize);
351
352 return ret;
353}
354EXPORT_SYMBOL(__kfifo_to_user_n);
355
356/**
357 * kfifo_to_user - gets data from the FIFO and write it to user space
358 * @fifo: the fifo to be used.
359 * @to: where the data must be copied.
360 * @len: the size of the destination buffer.
361 *
362 * This function copies at most @len bytes from the FIFO into the
363 * @to buffer and returns the number of copied bytes.
364 *
365 * Note that with only one concurrent reader and one concurrent
366 * writer, you don't need extra locking to use these functions.
367 */
368unsigned int kfifo_to_user(struct kfifo *fifo,
369 void __user *to, unsigned int len)
370{
371 len = min(kfifo_len(fifo), len);
372 len -= __kfifo_to_user_data(fifo, to, len, 0);
373 __kfifo_add_out(fifo, len);
297 return len; 374 return len;
298} 375}
299EXPORT_SYMBOL(kfifo_to_user); 376EXPORT_SYMBOL(kfifo_to_user);
300 377
378unsigned int __kfifo_to_user_generic(struct kfifo *fifo,
379 void __user *to, unsigned int len, unsigned int recsize,
380 unsigned int *total)
381{
382 return __kfifo_to_user_rec(fifo, to, len, recsize, total);
383}
384EXPORT_SYMBOL(__kfifo_to_user_generic);
385
386unsigned int __kfifo_peek_generic(struct kfifo *fifo, unsigned int recsize)
387{
388 if (recsize == 0)
389 return kfifo_avail(fifo);
390
391 return __kfifo_peek_n(fifo, recsize);
392}
393EXPORT_SYMBOL(__kfifo_peek_generic);
394
395void __kfifo_skip_generic(struct kfifo *fifo, unsigned int recsize)
396{
397 __kfifo_skip_rec(fifo, recsize);
398}
399EXPORT_SYMBOL(__kfifo_skip_generic);
400