Skip to content

Commit 4fdccaa

Browse files
author
Andreas Gruenbacher
committed
iomap: Add done_before argument to iomap_dio_rw
Add a done_before argument to iomap_dio_rw that indicates how much of the request has already been transferred. When the request succeeds, we report that done_before additional bytes were tranferred. This is useful for finishing a request asynchronously when part of the request has already been completed synchronously. We'll use that to allow iomap_dio_rw to be used with page faults disabled: when a page fault occurs while submitting a request, we synchronously complete the part of the request that has already been submitted. The caller can then take care of the page fault and call iomap_dio_rw again for the rest of the request, passing in the number of bytes already tranferred. Signed-off-by: Andreas Gruenbacher <[email protected]> Reviewed-by: Darrick J. Wong <[email protected]>
1 parent 97308f8 commit 4fdccaa

File tree

8 files changed

+32
-17
lines changed

8 files changed

+32
-17
lines changed

fs/btrfs/file.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1957,7 +1957,7 @@ static ssize_t btrfs_direct_write(struct kiocb *iocb, struct iov_iter *from)
19571957
}
19581958

19591959
dio = __iomap_dio_rw(iocb, from, &btrfs_dio_iomap_ops, &btrfs_dio_ops,
1960-
0);
1960+
0, 0);
19611961

19621962
btrfs_inode_unlock(inode, ilock_flags);
19631963

@@ -3658,7 +3658,8 @@ static ssize_t btrfs_direct_read(struct kiocb *iocb, struct iov_iter *to)
36583658
return 0;
36593659

36603660
btrfs_inode_lock(inode, BTRFS_ILOCK_SHARED);
3661-
ret = iomap_dio_rw(iocb, to, &btrfs_dio_iomap_ops, &btrfs_dio_ops, 0);
3661+
ret = iomap_dio_rw(iocb, to, &btrfs_dio_iomap_ops, &btrfs_dio_ops,
3662+
0, 0);
36623663
btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED);
36633664
return ret;
36643665
}

fs/erofs/data.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ static ssize_t erofs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
287287

288288
if (!err)
289289
return iomap_dio_rw(iocb, to, &erofs_iomap_ops,
290-
NULL, 0);
290+
NULL, 0, 0);
291291
if (err < 0)
292292
return err;
293293
}

fs/ext4/file.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ static ssize_t ext4_dio_read_iter(struct kiocb *iocb, struct iov_iter *to)
7474
return generic_file_read_iter(iocb, to);
7575
}
7676

77-
ret = iomap_dio_rw(iocb, to, &ext4_iomap_ops, NULL, 0);
77+
ret = iomap_dio_rw(iocb, to, &ext4_iomap_ops, NULL, 0, 0);
7878
inode_unlock_shared(inode);
7979

8080
file_accessed(iocb->ki_filp);
@@ -566,7 +566,8 @@ static ssize_t ext4_dio_write_iter(struct kiocb *iocb, struct iov_iter *from)
566566
if (ilock_shared)
567567
iomap_ops = &ext4_iomap_overwrite_ops;
568568
ret = iomap_dio_rw(iocb, from, iomap_ops, &ext4_dio_write_ops,
569-
(unaligned_io || extend) ? IOMAP_DIO_FORCE_WAIT : 0);
569+
(unaligned_io || extend) ? IOMAP_DIO_FORCE_WAIT : 0,
570+
0);
570571
if (ret == -ENOTBLK)
571572
ret = 0;
572573

fs/gfs2/file.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -822,7 +822,7 @@ static ssize_t gfs2_file_direct_read(struct kiocb *iocb, struct iov_iter *to,
822822
if (ret)
823823
goto out_uninit;
824824

825-
ret = iomap_dio_rw(iocb, to, &gfs2_iomap_ops, NULL, 0);
825+
ret = iomap_dio_rw(iocb, to, &gfs2_iomap_ops, NULL, 0, 0);
826826
gfs2_glock_dq(gh);
827827
out_uninit:
828828
gfs2_holder_uninit(gh);
@@ -856,7 +856,7 @@ static ssize_t gfs2_file_direct_write(struct kiocb *iocb, struct iov_iter *from,
856856
if (offset + len > i_size_read(&ip->i_inode))
857857
goto out;
858858

859-
ret = iomap_dio_rw(iocb, from, &gfs2_iomap_ops, NULL, 0);
859+
ret = iomap_dio_rw(iocb, from, &gfs2_iomap_ops, NULL, 0, 0);
860860
if (ret == -ENOTBLK)
861861
ret = 0;
862862
out:

fs/iomap/direct-io.c

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ struct iomap_dio {
3131
atomic_t ref;
3232
unsigned flags;
3333
int error;
34+
size_t done_before;
3435
bool wait_for_completion;
3536

3637
union {
@@ -124,6 +125,9 @@ ssize_t iomap_dio_complete(struct iomap_dio *dio)
124125
if (ret > 0 && (dio->flags & IOMAP_DIO_NEED_SYNC))
125126
ret = generic_write_sync(iocb, ret);
126127

128+
if (ret > 0)
129+
ret += dio->done_before;
130+
127131
kfree(dio);
128132

129133
return ret;
@@ -450,13 +454,21 @@ static loff_t iomap_dio_iter(const struct iomap_iter *iter,
450454
* may be pure data writes. In that case, we still need to do a full data sync
451455
* completion.
452456
*
457+
* When page faults are disabled and @dio_flags includes IOMAP_DIO_PARTIAL,
458+
* __iomap_dio_rw can return a partial result if it encounters a non-resident
459+
* page in @iter after preparing a transfer. In that case, the non-resident
460+
* pages can be faulted in and the request resumed with @done_before set to the
461+
* number of bytes previously transferred. The request will then complete with
462+
* the correct total number of bytes transferred; this is essential for
463+
* completing partial requests asynchronously.
464+
*
453465
* Returns -ENOTBLK In case of a page invalidation invalidation failure for
454466
* writes. The callers needs to fall back to buffered I/O in this case.
455467
*/
456468
struct iomap_dio *
457469
__iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
458470
const struct iomap_ops *ops, const struct iomap_dio_ops *dops,
459-
unsigned int dio_flags)
471+
unsigned int dio_flags, size_t done_before)
460472
{
461473
struct address_space *mapping = iocb->ki_filp->f_mapping;
462474
struct inode *inode = file_inode(iocb->ki_filp);
@@ -486,6 +498,7 @@ __iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
486498
dio->dops = dops;
487499
dio->error = 0;
488500
dio->flags = 0;
501+
dio->done_before = done_before;
489502

490503
dio->submit.iter = iter;
491504
dio->submit.waiter = current;
@@ -652,11 +665,11 @@ EXPORT_SYMBOL_GPL(__iomap_dio_rw);
652665
ssize_t
653666
iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
654667
const struct iomap_ops *ops, const struct iomap_dio_ops *dops,
655-
unsigned int dio_flags)
668+
unsigned int dio_flags, size_t done_before)
656669
{
657670
struct iomap_dio *dio;
658671

659-
dio = __iomap_dio_rw(iocb, iter, ops, dops, dio_flags);
672+
dio = __iomap_dio_rw(iocb, iter, ops, dops, dio_flags, done_before);
660673
if (IS_ERR_OR_NULL(dio))
661674
return PTR_ERR_OR_ZERO(dio);
662675
return iomap_dio_complete(dio);

fs/xfs/xfs_file.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ xfs_file_dio_read(
259259
ret = xfs_ilock_iocb(iocb, XFS_IOLOCK_SHARED);
260260
if (ret)
261261
return ret;
262-
ret = iomap_dio_rw(iocb, to, &xfs_read_iomap_ops, NULL, 0);
262+
ret = iomap_dio_rw(iocb, to, &xfs_read_iomap_ops, NULL, 0, 0);
263263
xfs_iunlock(ip, XFS_IOLOCK_SHARED);
264264

265265
return ret;
@@ -569,7 +569,7 @@ xfs_file_dio_write_aligned(
569569
}
570570
trace_xfs_file_direct_write(iocb, from);
571571
ret = iomap_dio_rw(iocb, from, &xfs_direct_write_iomap_ops,
572-
&xfs_dio_write_ops, 0);
572+
&xfs_dio_write_ops, 0, 0);
573573
out_unlock:
574574
if (iolock)
575575
xfs_iunlock(ip, iolock);
@@ -647,7 +647,7 @@ xfs_file_dio_write_unaligned(
647647

648648
trace_xfs_file_direct_write(iocb, from);
649649
ret = iomap_dio_rw(iocb, from, &xfs_direct_write_iomap_ops,
650-
&xfs_dio_write_ops, flags);
650+
&xfs_dio_write_ops, flags, 0);
651651

652652
/*
653653
* Retry unaligned I/O with exclusive blocking semantics if the DIO

fs/zonefs/super.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -852,7 +852,7 @@ static ssize_t zonefs_file_dio_write(struct kiocb *iocb, struct iov_iter *from)
852852
ret = zonefs_file_dio_append(iocb, from);
853853
else
854854
ret = iomap_dio_rw(iocb, from, &zonefs_iomap_ops,
855-
&zonefs_write_dio_ops, 0);
855+
&zonefs_write_dio_ops, 0, 0);
856856
if (zi->i_ztype == ZONEFS_ZTYPE_SEQ &&
857857
(ret > 0 || ret == -EIOCBQUEUED)) {
858858
if (ret > 0)
@@ -987,7 +987,7 @@ static ssize_t zonefs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
987987
}
988988
file_accessed(iocb->ki_filp);
989989
ret = iomap_dio_rw(iocb, to, &zonefs_iomap_ops,
990-
&zonefs_read_dio_ops, 0);
990+
&zonefs_read_dio_ops, 0, 0);
991991
} else {
992992
ret = generic_file_read_iter(iocb, to);
993993
if (ret == -EIO)

include/linux/iomap.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -339,10 +339,10 @@ struct iomap_dio_ops {
339339

340340
ssize_t iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
341341
const struct iomap_ops *ops, const struct iomap_dio_ops *dops,
342-
unsigned int dio_flags);
342+
unsigned int dio_flags, size_t done_before);
343343
struct iomap_dio *__iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
344344
const struct iomap_ops *ops, const struct iomap_dio_ops *dops,
345-
unsigned int dio_flags);
345+
unsigned int dio_flags, size_t done_before);
346346
ssize_t iomap_dio_complete(struct iomap_dio *dio);
347347
int iomap_dio_iopoll(struct kiocb *kiocb, bool spin);
348348

0 commit comments

Comments
 (0)