Skip to content

Commit d0497dd

Browse files
Mike SnitzerAnna Schumaker
authored andcommitted
nfs/localio: backfill missing partial read support for misaligned DIO
Misaligned DIO read can be split into 3 IOs, must handle potential for short read from each component IO (follows same pattern used for handling partial writes, except upper layer read code handles advancing offset before retry). Fixes: c817248 ("nfs/localio: add proper O_DIRECT support for READ and WRITE") Signed-off-by: Mike Snitzer <[email protected]> Signed-off-by: Anna Schumaker <[email protected]>
1 parent f2060bd commit d0497dd

File tree

1 file changed

+20
-4
lines changed

1 file changed

+20
-4
lines changed

fs/nfs/localio.c

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ nfs_local_iters_setup_dio(struct nfs_local_kiocb *iocb, int rw,
414414
/* Setup misaligned end?
415415
* If so, the end is purposely setup to be issued using buffered IO
416416
* before the middle (which will use DIO, if DIO-aligned, with AIO).
417-
* This creates problems if/when the end results in a partial write.
417+
* This creates problems if/when the end results in short read or write.
418418
* So must save index and length of end to handle this corner case.
419419
*/
420420
if (local_dio->end_len) {
@@ -580,8 +580,9 @@ static void nfs_local_read_done(struct nfs_local_kiocb *iocb)
580580
*/
581581
hdr->res.replen = 0;
582582

583-
if (hdr->res.count != hdr->args.count ||
584-
hdr->args.offset + hdr->res.count >= i_size_read(file_inode(filp)))
583+
/* nfs_readpage_result() handles short read */
584+
585+
if (hdr->args.offset + hdr->res.count >= i_size_read(file_inode(filp)))
585586
hdr->res.eof = true;
586587

587588
dprintk("%s: read %ld bytes eof %d.\n", __func__,
@@ -620,6 +621,7 @@ static void nfs_local_call_read(struct work_struct *work)
620621
container_of(work, struct nfs_local_kiocb, work);
621622
struct file *filp = iocb->kiocb.ki_filp;
622623
const struct cred *save_cred;
624+
bool force_done = false;
623625
ssize_t status;
624626
int n_iters;
625627

@@ -637,7 +639,21 @@ static void nfs_local_call_read(struct work_struct *work)
637639
iocb->kiocb.ki_pos = iocb->offset[i];
638640
status = filp->f_op->read_iter(&iocb->kiocb, &iocb->iters[i]);
639641
if (status != -EIOCBQUEUED) {
640-
if (nfs_local_pgio_done(iocb, status, false)) {
642+
if (unlikely(status >= 0 && status < iocb->iters[i].count)) {
643+
/* partial read */
644+
if (i == iocb->end_iter_index) {
645+
/* Must not account DIO partial end, otherwise (due
646+
* to end being issued before middle): the partial
647+
* read accounting in nfs_local_read_done()
648+
* would incorrectly advance hdr->args.offset
649+
*/
650+
status = 0;
651+
} else {
652+
/* Partial read at start or middle, force done */
653+
force_done = true;
654+
}
655+
}
656+
if (nfs_local_pgio_done(iocb, status, force_done)) {
641657
nfs_local_read_iocb_done(iocb);
642658
break;
643659
}

0 commit comments

Comments
 (0)