Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 179346
b: refs/heads/master
c: 64ce103
h: refs/heads/master
v: v3
  • Loading branch information
Andi Kleen authored and Linus Torvalds committed Jan 16, 2010
1 parent ee1208e commit a0993ea
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 32 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 8ecc2951534af10e04ddb5e5ff5c6d217b79f5c2
refs/heads/master: 64ce1037c5434b1d036cd99ecaee6e00496bc2e9
8 changes: 4 additions & 4 deletions trunk/include/linux/kfifo.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,11 +235,11 @@ static inline __must_check unsigned int kfifo_out_locked(struct kfifo *fifo,

extern void kfifo_skip(struct kfifo *fifo, unsigned int len);

extern __must_check unsigned int kfifo_from_user(struct kfifo *fifo,
const void __user *from, unsigned int n);
extern __must_check int kfifo_from_user(struct kfifo *fifo,
const void __user *from, unsigned int n, unsigned *lenout);

extern __must_check unsigned int kfifo_to_user(struct kfifo *fifo,
void __user *to, unsigned int n);
extern __must_check int kfifo_to_user(struct kfifo *fifo,
void __user *to, unsigned int n, unsigned *lenout);

/*
* __kfifo_add_out internal helper function for updating the out offset
Expand Down
76 changes: 49 additions & 27 deletions trunk/kernel/kfifo.c
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,9 @@ static inline void __kfifo_out_data(struct kfifo *fifo,
memcpy(to + l, fifo->buffer, len - l);
}

static inline unsigned int __kfifo_from_user_data(struct kfifo *fifo,
const void __user *from, unsigned int len, unsigned int off)
static inline int __kfifo_from_user_data(struct kfifo *fifo,
const void __user *from, unsigned int len, unsigned int off,
unsigned *lenout)
{
unsigned int l;
int ret;
Expand All @@ -177,16 +178,20 @@ static inline unsigned int __kfifo_from_user_data(struct kfifo *fifo,
/* first put the data starting from fifo->in to buffer end */
l = min(len, fifo->size - off);
ret = copy_from_user(fifo->buffer + off, from, l);

if (unlikely(ret))
return ret + len - l;
if (unlikely(ret)) {
*lenout = ret;
return -EFAULT;
}
*lenout = l;

/* then put the rest (if any) at the beginning of the buffer */
return copy_from_user(fifo->buffer, from + l, len - l);
ret = copy_from_user(fifo->buffer, from + l, len - l);
*lenout += ret ? ret : len - l;
return ret ? -EFAULT : 0;
}

static inline unsigned int __kfifo_to_user_data(struct kfifo *fifo,
void __user *to, unsigned int len, unsigned int off)
static inline int __kfifo_to_user_data(struct kfifo *fifo,
void __user *to, unsigned int len, unsigned int off, unsigned *lenout)
{
unsigned int l;
int ret;
Expand All @@ -203,12 +208,21 @@ static inline unsigned int __kfifo_to_user_data(struct kfifo *fifo,
/* first get the data from fifo->out until the end of the buffer */
l = min(len, fifo->size - off);
ret = copy_to_user(to, fifo->buffer + off, l);

if (unlikely(ret))
return ret + len - l;
*lenout = l;
if (unlikely(ret)) {
*lenout -= ret;
return -EFAULT;
}

/* then get the rest (if any) from the beginning of the buffer */
return copy_to_user(to + l, fifo->buffer, len - l);
len -= l;
ret = copy_to_user(to + l, fifo->buffer, len);
if (unlikely(ret)) {
*lenout += len - ret;
return -EFAULT;
}
*lenout += len;
return 0;
}

unsigned int __kfifo_in_n(struct kfifo *fifo,
Expand Down Expand Up @@ -299,10 +313,13 @@ EXPORT_SYMBOL(__kfifo_out_generic);
unsigned int __kfifo_from_user_n(struct kfifo *fifo,
const void __user *from, unsigned int len, unsigned int recsize)
{
unsigned total;

if (kfifo_avail(fifo) < len + recsize)
return len + 1;

return __kfifo_from_user_data(fifo, from, len, recsize);
__kfifo_from_user_data(fifo, from, len, recsize, &total);
return total;
}
EXPORT_SYMBOL(__kfifo_from_user_n);

Expand All @@ -313,18 +330,21 @@ EXPORT_SYMBOL(__kfifo_from_user_n);
* @len: the length of the data to be added.
*
* This function copies at most @len bytes from the @from into the
* FIFO depending and returns the number of copied bytes.
* FIFO depending and returns -EFAULT/0.
*
* Note that with only one concurrent reader and one concurrent
* writer, you don't need extra locking to use these functions.
*/
unsigned int kfifo_from_user(struct kfifo *fifo,
const void __user *from, unsigned int len)
int kfifo_from_user(struct kfifo *fifo,
const void __user *from, unsigned int len, unsigned *total)
{
int ret;
len = min(kfifo_avail(fifo), len);
len -= __kfifo_from_user_data(fifo, from, len, 0);
ret = __kfifo_from_user_data(fifo, from, len, 0, total);
if (ret)
return ret;
__kfifo_add_in(fifo, len);
return len;
return 0;
}
EXPORT_SYMBOL(kfifo_from_user);

Expand All @@ -339,17 +359,17 @@ unsigned int __kfifo_to_user_n(struct kfifo *fifo,
void __user *to, unsigned int len, unsigned int reclen,
unsigned int recsize)
{
unsigned int ret;
unsigned int ret, total;

if (kfifo_len(fifo) < reclen + recsize)
return len;

ret = __kfifo_to_user_data(fifo, to, reclen, recsize);
ret = __kfifo_to_user_data(fifo, to, reclen, recsize, &total);

if (likely(ret == 0))
__kfifo_add_out(fifo, reclen + recsize);

return ret;
return total;
}
EXPORT_SYMBOL(__kfifo_to_user_n);

Expand All @@ -358,20 +378,22 @@ EXPORT_SYMBOL(__kfifo_to_user_n);
* @fifo: the fifo to be used.
* @to: where the data must be copied.
* @len: the size of the destination buffer.
@ @lenout: pointer to output variable with copied data
*
* This function copies at most @len bytes from the FIFO into the
* @to buffer and returns the number of copied bytes.
* @to buffer and 0 or -EFAULT.
*
* Note that with only one concurrent reader and one concurrent
* writer, you don't need extra locking to use these functions.
*/
unsigned int kfifo_to_user(struct kfifo *fifo,
void __user *to, unsigned int len)
int kfifo_to_user(struct kfifo *fifo,
void __user *to, unsigned int len, unsigned *lenout)
{
int ret;
len = min(kfifo_len(fifo), len);
len -= __kfifo_to_user_data(fifo, to, len, 0);
__kfifo_add_out(fifo, len);
return len;
ret = __kfifo_to_user_data(fifo, to, len, 0, lenout);
__kfifo_add_out(fifo, *lenout);
return ret;
}
EXPORT_SYMBOL(kfifo_to_user);

Expand Down

0 comments on commit a0993ea

Please sign in to comment.