Fix 32-bit regression in block device read(2)
blkdev_read_iter() wants to cap the iov_iter by the amount of data remaining to the end of device. That's what iov_iter_truncate() is for (trim iter->count if it's above the given limit). So far, so good, but the argument of iov_iter_truncate() is size_t, so on 32bit boxen (in case of a large device) we end up with that upper limit truncated down to 32 bits *before* comparing it with iter->count. Easily fixed by making iov_iter_truncate() take 64bit argument - it does the right thing after such change (we only reach the assignment in there when the current value of iter->count is greater than the limit, i.e. for anything that would get truncated we don't reach the assignment at all) and that argument is not the new value of iter->count - it's an upper limit for such. The overhead of passing u64 is not an issue - the thing is inlined, so callers passing size_t won't pay any penalty. Reported-and-tested-by: Theodore Tso <tytso@mit.edu> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Tested-by: Alan Cox <gnomes@lxorguk.ukuu.org.uk> Tested-by: Bruno Wolff III <bruno@wolff.to> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Родитель
d7933ab727
Коммит
0b86dbf675
|
@ -94,8 +94,20 @@ static inline size_t iov_iter_count(struct iov_iter *i)
|
|||
return i->count;
|
||||
}
|
||||
|
||||
static inline void iov_iter_truncate(struct iov_iter *i, size_t count)
|
||||
/*
|
||||
* Cap the iov_iter by given limit; note that the second argument is
|
||||
* *not* the new size - it's upper limit for such. Passing it a value
|
||||
* greater than the amount of data in iov_iter is fine - it'll just do
|
||||
* nothing in that case.
|
||||
*/
|
||||
static inline void iov_iter_truncate(struct iov_iter *i, u64 count)
|
||||
{
|
||||
/*
|
||||
* count doesn't have to fit in size_t - comparison extends both
|
||||
* operands to u64 here and any value that would be truncated by
|
||||
* conversion in assignement is by definition greater than all
|
||||
* values of size_t, including old i->count.
|
||||
*/
|
||||
if (i->count > count)
|
||||
i->count = count;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче