Skip to content

Commit 6e58e79

Browse files
author
Al Viro
committed
introduce copy_page_to_iter, kill loop over iovec in generic_file_aio_read()
generic_file_aio_read() was looping over the target iovec, with loop over (source) pages nested inside that. Just set an iov_iter up and pass *that* to do_generic_file_aio_read(). With copy_page_to_iter() doing all work of mapping and copying a page to iovec and advancing iov_iter. Switch shmem_file_aio_read() to the same and kill file_read_actor(), while we are at it. Signed-off-by: Al Viro <[email protected]>
1 parent 9223687 commit 6e58e79

File tree

4 files changed

+138
-144
lines changed

4 files changed

+138
-144
lines changed

include/linux/fs.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2390,7 +2390,6 @@ extern int generic_file_mmap(struct file *, struct vm_area_struct *);
23902390
extern int generic_file_readonly_mmap(struct file *, struct vm_area_struct *);
23912391
extern int generic_file_remap_pages(struct vm_area_struct *, unsigned long addr,
23922392
unsigned long size, pgoff_t pgoff);
2393-
extern int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size);
23942393
int generic_write_checks(struct file *file, loff_t *pos, size_t *count, int isblk);
23952394
extern ssize_t generic_file_aio_read(struct kiocb *, const struct iovec *, unsigned long, loff_t);
23962395
extern ssize_t __generic_file_aio_write(struct kiocb *, const struct iovec *, unsigned long,

include/linux/uio.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ size_t iov_iter_copy_from_user(struct page *page,
6767
void iov_iter_advance(struct iov_iter *i, size_t bytes);
6868
int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes);
6969
size_t iov_iter_single_seg_count(const struct iov_iter *i);
70+
size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes,
71+
struct iov_iter *i);
7072

7173
static inline void iov_iter_init(struct iov_iter *i,
7274
const struct iovec *iov, unsigned long nr_segs,

mm/filemap.c

Lines changed: 109 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,20 +1085,99 @@ static void shrink_readahead_size_eio(struct file *filp,
10851085
ra->ra_pages /= 4;
10861086
}
10871087

1088+
size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes,
1089+
struct iov_iter *i)
1090+
{
1091+
size_t skip, copy, left, wanted;
1092+
const struct iovec *iov;
1093+
char __user *buf;
1094+
void *kaddr, *from;
1095+
1096+
if (unlikely(bytes > i->count))
1097+
bytes = i->count;
1098+
1099+
if (unlikely(!bytes))
1100+
return 0;
1101+
1102+
wanted = bytes;
1103+
iov = i->iov;
1104+
skip = i->iov_offset;
1105+
buf = iov->iov_base + skip;
1106+
copy = min(bytes, iov->iov_len - skip);
1107+
1108+
if (!fault_in_pages_writeable(buf, copy)) {
1109+
kaddr = kmap_atomic(page);
1110+
from = kaddr + offset;
1111+
1112+
/* first chunk, usually the only one */
1113+
left = __copy_to_user_inatomic(buf, from, copy);
1114+
copy -= left;
1115+
skip += copy;
1116+
from += copy;
1117+
bytes -= copy;
1118+
1119+
while (unlikely(!left && bytes)) {
1120+
iov++;
1121+
buf = iov->iov_base;
1122+
copy = min(bytes, iov->iov_len);
1123+
left = __copy_to_user_inatomic(buf, from, copy);
1124+
copy -= left;
1125+
skip = copy;
1126+
from += copy;
1127+
bytes -= copy;
1128+
}
1129+
if (likely(!bytes)) {
1130+
kunmap_atomic(kaddr);
1131+
goto done;
1132+
}
1133+
offset = from - kaddr;
1134+
buf += copy;
1135+
kunmap_atomic(kaddr);
1136+
copy = min(bytes, iov->iov_len - skip);
1137+
}
1138+
/* Too bad - revert to non-atomic kmap */
1139+
kaddr = kmap(page);
1140+
from = kaddr + offset;
1141+
left = __copy_to_user(buf, from, copy);
1142+
copy -= left;
1143+
skip += copy;
1144+
from += copy;
1145+
bytes -= copy;
1146+
while (unlikely(!left && bytes)) {
1147+
iov++;
1148+
buf = iov->iov_base;
1149+
copy = min(bytes, iov->iov_len);
1150+
left = __copy_to_user(buf, from, copy);
1151+
copy -= left;
1152+
skip = copy;
1153+
from += copy;
1154+
bytes -= copy;
1155+
}
1156+
kunmap(page);
1157+
done:
1158+
i->count -= wanted - bytes;
1159+
i->nr_segs -= iov - i->iov;
1160+
i->iov = iov;
1161+
i->iov_offset = skip;
1162+
return wanted - bytes;
1163+
}
1164+
EXPORT_SYMBOL(copy_page_to_iter);
1165+
10881166
/**
10891167
* do_generic_file_read - generic file read routine
10901168
* @filp: the file to read
10911169
* @ppos: current file position
1092-
* @desc: read_descriptor
1170+
* @iter: data destination
1171+
* @written: already copied
10931172
*
10941173
* This is a generic file read routine, and uses the
10951174
* mapping->a_ops->readpage() function for the actual low-level stuff.
10961175
*
10971176
* This is really ugly. But the goto's actually try to clarify some
10981177
* of the logic when it comes to error handling etc.
10991178
*/
1100-
static void do_generic_file_read(struct file *filp, loff_t *ppos,
1101-
read_descriptor_t *desc)
1179+
static ssize_t do_generic_file_read(struct file *filp, loff_t *ppos,
1180+
struct iov_iter *iter, ssize_t written)
11021181
{
11031182
struct address_space *mapping = filp->f_mapping;
11041183
struct inode *inode = mapping->host;
@@ -1108,12 +1187,12 @@ static void do_generic_file_read(struct file *filp, loff_t *ppos,
11081187
pgoff_t prev_index;
11091188
unsigned long offset; /* offset into pagecache page */
11101189
unsigned int prev_offset;
1111-
int error;
1190+
int error = 0;
11121191

11131192
index = *ppos >> PAGE_CACHE_SHIFT;
11141193
prev_index = ra->prev_pos >> PAGE_CACHE_SHIFT;
11151194
prev_offset = ra->prev_pos & (PAGE_CACHE_SIZE-1);
1116-
last_index = (*ppos + desc->count + PAGE_CACHE_SIZE-1) >> PAGE_CACHE_SHIFT;
1195+
last_index = (*ppos + iter->count + PAGE_CACHE_SIZE-1) >> PAGE_CACHE_SHIFT;
11171196
offset = *ppos & ~PAGE_CACHE_MASK;
11181197

11191198
for (;;) {
@@ -1148,7 +1227,7 @@ static void do_generic_file_read(struct file *filp, loff_t *ppos,
11481227
if (!page->mapping)
11491228
goto page_not_up_to_date_locked;
11501229
if (!mapping->a_ops->is_partially_uptodate(page,
1151-
offset, desc->count))
1230+
offset, iter->count))
11521231
goto page_not_up_to_date_locked;
11531232
unlock_page(page);
11541233
}
@@ -1198,24 +1277,23 @@ static void do_generic_file_read(struct file *filp, loff_t *ppos,
11981277
/*
11991278
* Ok, we have the page, and it's up-to-date, so
12001279
* now we can copy it to user space...
1201-
*
1202-
* The file_read_actor routine returns how many bytes were
1203-
* actually used..
1204-
* NOTE! This may not be the same as how much of a user buffer
1205-
* we filled up (we may be padding etc), so we can only update
1206-
* "pos" here (the actor routine has to update the user buffer
1207-
* pointers and the remaining count).
12081280
*/
1209-
ret = file_read_actor(desc, page, offset, nr);
1281+
1282+
ret = copy_page_to_iter(page, offset, nr, iter);
12101283
offset += ret;
12111284
index += offset >> PAGE_CACHE_SHIFT;
12121285
offset &= ~PAGE_CACHE_MASK;
12131286
prev_offset = offset;
12141287

12151288
page_cache_release(page);
1216-
if (ret == nr && desc->count)
1217-
continue;
1218-
goto out;
1289+
written += ret;
1290+
if (!iov_iter_count(iter))
1291+
goto out;
1292+
if (ret < nr) {
1293+
error = -EFAULT;
1294+
goto out;
1295+
}
1296+
continue;
12191297

12201298
page_not_up_to_date:
12211299
/* Get exclusive access to the page ... */
@@ -1250,6 +1328,7 @@ static void do_generic_file_read(struct file *filp, loff_t *ppos,
12501328
if (unlikely(error)) {
12511329
if (error == AOP_TRUNCATED_PAGE) {
12521330
page_cache_release(page);
1331+
error = 0;
12531332
goto find_page;
12541333
}
12551334
goto readpage_error;
@@ -1280,7 +1359,6 @@ static void do_generic_file_read(struct file *filp, loff_t *ppos,
12801359

12811360
readpage_error:
12821361
/* UHHUH! A synchronous read error occurred. Report it */
1283-
desc->error = error;
12841362
page_cache_release(page);
12851363
goto out;
12861364

@@ -1291,16 +1369,17 @@ static void do_generic_file_read(struct file *filp, loff_t *ppos,
12911369
*/
12921370
page = page_cache_alloc_cold(mapping);
12931371
if (!page) {
1294-
desc->error = -ENOMEM;
1372+
error = -ENOMEM;
12951373
goto out;
12961374
}
12971375
error = add_to_page_cache_lru(page, mapping,
12981376
index, GFP_KERNEL);
12991377
if (error) {
13001378
page_cache_release(page);
1301-
if (error == -EEXIST)
1379+
if (error == -EEXIST) {
1380+
error = 0;
13021381
goto find_page;
1303-
desc->error = error;
1382+
}
13041383
goto out;
13051384
}
13061385
goto readpage;
@@ -1313,44 +1392,7 @@ static void do_generic_file_read(struct file *filp, loff_t *ppos,
13131392

13141393
*ppos = ((loff_t)index << PAGE_CACHE_SHIFT) + offset;
13151394
file_accessed(filp);
1316-
}
1317-
1318-
int file_read_actor(read_descriptor_t *desc, struct page *page,
1319-
unsigned long offset, unsigned long size)
1320-
{
1321-
char *kaddr;
1322-
unsigned long left, count = desc->count;
1323-
1324-
if (size > count)
1325-
size = count;
1326-
1327-
/*
1328-
* Faults on the destination of a read are common, so do it before
1329-
* taking the kmap.
1330-
*/
1331-
if (!fault_in_pages_writeable(desc->arg.buf, size)) {
1332-
kaddr = kmap_atomic(page);
1333-
left = __copy_to_user_inatomic(desc->arg.buf,
1334-
kaddr + offset, size);
1335-
kunmap_atomic(kaddr);
1336-
if (left == 0)
1337-
goto success;
1338-
}
1339-
1340-
/* Do it the slow way */
1341-
kaddr = kmap(page);
1342-
left = __copy_to_user(desc->arg.buf, kaddr + offset, size);
1343-
kunmap(page);
1344-
1345-
if (left) {
1346-
size -= left;
1347-
desc->error = -EFAULT;
1348-
}
1349-
success:
1350-
desc->count = count - size;
1351-
desc->written += size;
1352-
desc->arg.buf += size;
1353-
return size;
1395+
return written ? written : error;
13541396
}
13551397

13561398
/*
@@ -1408,14 +1450,15 @@ generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
14081450
{
14091451
struct file *filp = iocb->ki_filp;
14101452
ssize_t retval;
1411-
unsigned long seg = 0;
14121453
size_t count;
14131454
loff_t *ppos = &iocb->ki_pos;
1455+
struct iov_iter i;
14141456

14151457
count = 0;
14161458
retval = generic_segment_checks(iov, &nr_segs, &count, VERIFY_WRITE);
14171459
if (retval)
14181460
return retval;
1461+
iov_iter_init(&i, iov, nr_segs, count, 0);
14191462

14201463
/* coalesce the iovecs and go direct-to-BIO for O_DIRECT */
14211464
if (filp->f_flags & O_DIRECT) {
@@ -1437,6 +1480,11 @@ generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
14371480
if (retval > 0) {
14381481
*ppos = pos + retval;
14391482
count -= retval;
1483+
/*
1484+
* If we did a short DIO read we need to skip the
1485+
* section of the iov that we've already read data into.
1486+
*/
1487+
iov_iter_advance(&i, retval);
14401488
}
14411489

14421490
/*
@@ -1453,39 +1501,7 @@ generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
14531501
}
14541502
}
14551503

1456-
count = retval;
1457-
for (seg = 0; seg < nr_segs; seg++) {
1458-
read_descriptor_t desc;
1459-
loff_t offset = 0;
1460-
1461-
/*
1462-
* If we did a short DIO read we need to skip the section of the
1463-
* iov that we've already read data into.
1464-
*/
1465-
if (count) {
1466-
if (count > iov[seg].iov_len) {
1467-
count -= iov[seg].iov_len;
1468-
continue;
1469-
}
1470-
offset = count;
1471-
count = 0;
1472-
}
1473-
1474-
desc.written = 0;
1475-
desc.arg.buf = iov[seg].iov_base + offset;
1476-
desc.count = iov[seg].iov_len - offset;
1477-
if (desc.count == 0)
1478-
continue;
1479-
desc.error = 0;
1480-
do_generic_file_read(filp, ppos, &desc);
1481-
retval += desc.written;
1482-
if (desc.error) {
1483-
retval = retval ?: desc.error;
1484-
break;
1485-
}
1486-
if (desc.count > 0)
1487-
break;
1488-
}
1504+
retval = do_generic_file_read(filp, ppos, &i, retval);
14891505
out:
14901506
return retval;
14911507
}

0 commit comments

Comments
 (0)