diff options
Diffstat (limited to 'mm/filemap.c')
-rw-r--r-- | mm/filemap.c | 42 |
1 files changed, 37 insertions, 5 deletions
diff --git a/mm/filemap.c b/mm/filemap.c index 88d719665a28..45a2d18df849 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -1105,6 +1105,12 @@ page_not_up_to_date_locked: | |||
1105 | } | 1105 | } |
1106 | 1106 | ||
1107 | readpage: | 1107 | readpage: |
1108 | /* | ||
1109 | * A previous I/O error may have been due to temporary | ||
1110 | * failures, eg. multipath errors. | ||
1111 | * PG_error will be set again if readpage fails. | ||
1112 | */ | ||
1113 | ClearPageError(page); | ||
1108 | /* Start the actual read. The read will unlock the page. */ | 1114 | /* Start the actual read. The read will unlock the page. */ |
1109 | error = mapping->a_ops->readpage(filp, page); | 1115 | error = mapping->a_ops->readpage(filp, page); |
1110 | 1116 | ||
@@ -1269,7 +1275,7 @@ generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov, | |||
1269 | { | 1275 | { |
1270 | struct file *filp = iocb->ki_filp; | 1276 | struct file *filp = iocb->ki_filp; |
1271 | ssize_t retval; | 1277 | ssize_t retval; |
1272 | unsigned long seg; | 1278 | unsigned long seg = 0; |
1273 | size_t count; | 1279 | size_t count; |
1274 | loff_t *ppos = &iocb->ki_pos; | 1280 | loff_t *ppos = &iocb->ki_pos; |
1275 | 1281 | ||
@@ -1296,21 +1302,47 @@ generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov, | |||
1296 | retval = mapping->a_ops->direct_IO(READ, iocb, | 1302 | retval = mapping->a_ops->direct_IO(READ, iocb, |
1297 | iov, pos, nr_segs); | 1303 | iov, pos, nr_segs); |
1298 | } | 1304 | } |
1299 | if (retval > 0) | 1305 | if (retval > 0) { |
1300 | *ppos = pos + retval; | 1306 | *ppos = pos + retval; |
1301 | if (retval) { | 1307 | count -= retval; |
1308 | } | ||
1309 | |||
1310 | /* | ||
1311 | * Btrfs can have a short DIO read if we encounter | ||
1312 | * compressed extents, so if there was an error, or if | ||
1313 | * we've already read everything we wanted to, or if | ||
1314 | * there was a short read because we hit EOF, go ahead | ||
1315 | * and return. Otherwise fallthrough to buffered io for | ||
1316 | * the rest of the read. | ||
1317 | */ | ||
1318 | if (retval < 0 || !count || *ppos >= size) { | ||
1302 | file_accessed(filp); | 1319 | file_accessed(filp); |
1303 | goto out; | 1320 | goto out; |
1304 | } | 1321 | } |
1305 | } | 1322 | } |
1306 | } | 1323 | } |
1307 | 1324 | ||
1325 | count = retval; | ||
1308 | for (seg = 0; seg < nr_segs; seg++) { | 1326 | for (seg = 0; seg < nr_segs; seg++) { |
1309 | read_descriptor_t desc; | 1327 | read_descriptor_t desc; |
1328 | loff_t offset = 0; | ||
1329 | |||
1330 | /* | ||
1331 | * If we did a short DIO read we need to skip the section of the | ||
1332 | * iov that we've already read data into. | ||
1333 | */ | ||
1334 | if (count) { | ||
1335 | if (count > iov[seg].iov_len) { | ||
1336 | count -= iov[seg].iov_len; | ||
1337 | continue; | ||
1338 | } | ||
1339 | offset = count; | ||
1340 | count = 0; | ||
1341 | } | ||
1310 | 1342 | ||
1311 | desc.written = 0; | 1343 | desc.written = 0; |
1312 | desc.arg.buf = iov[seg].iov_base; | 1344 | desc.arg.buf = iov[seg].iov_base + offset; |
1313 | desc.count = iov[seg].iov_len; | 1345 | desc.count = iov[seg].iov_len - offset; |
1314 | if (desc.count == 0) | 1346 | if (desc.count == 0) |
1315 | continue; | 1347 | continue; |
1316 | desc.error = 0; | 1348 | desc.error = 0; |