Rebase to v4.16-rc1-29-ge40ff2138985
[ext4-patch-queue.git] / fix-32bit-breakage-in-block-device
blob6ca2c69323bb68e299b570d874fe70299d66b39b
1 [regression] fix 32-bit breakage in block device read(2)
3 From: Al Viro <viro@ZenIV.linux.org.uk>
5 blkdev_read_iter() wants to cap the iov_iter by the amount of
6 data remaining to the end of device.  That's what iov_iter_truncate()
7 is for (trim iter->count if it's above the given limit).  So far,
8 so good, but the argument of iov_iter_truncate() is size_t, so on
9 32bit boxen (in case of a large device) we end up with that upper
10 limit truncated down to 32 bits *before* comparing it with iter->count.
12 Easily fixed by making iov_iter_truncate() take 64bit argument -
13 it does the right thing after such change (we only reach the
14 assignment in there when the current value of iter->count is greater
15 than the limit, i.e. for anything that would get truncated we don't
16 reach the assignment at all) and that argument is not the new
17 value of iter->count - it's an upper limit for such.
19 The overhead of passing u64 is not an issue - the thing is inlined,
20 so callers passing size_t won't pay any penalty.
22 Reported-by: Theodore Tso <tytso@mit.edu>
23 Tested-by: Theodore Tso <tytso@mit.edu>
24 Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
25 ---
27 diff --git a/include/linux/uio.h b/include/linux/uio.h
28 index ddfdb53..17ae7e3 100644
29 --- a/include/linux/uio.h
30 +++ b/include/linux/uio.h
31 @@ -94,8 +94,20 @@ static inline size_t iov_iter_count(struct iov_iter *i)
32         return i->count;
33  }
35 -static inline void iov_iter_truncate(struct iov_iter *i, size_t count)
36 +/*
37 + * Cap the iov_iter by given limit; note that the second argument is
38 + * *not* the new size - it's upper limit for such.  Passing it a value
39 + * greater than the amount of data in iov_iter is fine - it'll just do
40 + * nothing in that case.
41 + */
42 +static inline void iov_iter_truncate(struct iov_iter *i, u64 count)
43  {
44 +       /*
45 +        * count doesn't have to fit in size_t - comparison extends both
46 +        * operands to u64 here and any value that would be truncated by
47 +        * conversion in assignement is by definition greater than all
48 +        * values of size_t, including old i->count.
49 +        */
50         if (i->count > count)
51                 i->count = count;
52  }