@@ -1417,26 +1417,30 @@ dmu_read_uio_dnode(dnode_t *dn, zfs_uio_t *uio, uint64_t size)
1417
1417
err = dmu_buf_hold_array_by_dnode (dn , zfs_uio_offset (uio ), size ,
1418
1418
TRUE, FTAG , & numbufs , & dbp , 0 );
1419
1419
if (err )
1420
- return (err );
1420
+ return (err );
1421
1421
1422
- for (i = 0 ; i < numbufs ; i ++ ) {
1423
- uint64_t tocpy ;
1424
- int64_t bufoff ;
1425
- dmu_buf_t * db = dbp [i ];
1422
+ for (i = 0 ; i < numbufs && size > 0 ; ) {
1423
+ uint64_t tocpy ;
1424
+ int64_t bufoff ;
1425
+ dmu_buf_t * db = dbp [i ];
1426
1426
1427
- ASSERT (size > 0 );
1427
+ bufoff = zfs_uio_offset (uio ) - db -> db_offset ;
1428
+ tocpy = MIN (db -> db_size - bufoff , size );
1428
1429
1429
- bufoff = zfs_uio_offset (uio ) - db -> db_offset ;
1430
- tocpy = MIN (db -> db_size - bufoff , size );
1430
+ ASSERT (db -> db_data != NULL );
1431
1431
1432
- ASSERT (db -> db_data != NULL );
1433
- err = zfs_uio_fault_move ((char * )db -> db_data + bufoff , tocpy ,
1434
- UIO_READ , uio );
1432
+ uint64_t resid_before = uio -> uio_resid ;
1433
+ err = zfs_uio_fault_move ((char * )db -> db_data + bufoff ,
1434
+ tocpy , UIO_READ , uio );
1435
+ uint64_t moved = resid_before - uio -> uio_resid ;
1435
1436
1436
- if (err )
1437
- break ;
1437
+ size -= moved ;
1438
1438
1439
- size -= tocpy ;
1439
+ if (err || moved == 0 )
1440
+ break ;
1441
+
1442
+ if (bufoff + moved >= db -> db_size )
1443
+ i ++ ;
1440
1444
}
1441
1445
dmu_buf_rele_array (dbp , numbufs , FTAG );
1442
1446
@@ -1536,41 +1540,44 @@ dmu_write_uio_dnode(dnode_t *dn, zfs_uio_t *uio, uint64_t size, dmu_tx_t *tx)
1536
1540
if (err )
1537
1541
return (err );
1538
1542
1539
- for (int i = 0 ; i < numbufs ; i ++ ) {
1540
- uint64_t tocpy ;
1541
- int64_t bufoff ;
1542
- dmu_buf_t * db = dbp [i ];
1543
+ for (int i = 0 ; i < numbufs && write_size > 0 ; ) {
1544
+ uint64_t tocpy ;
1545
+ int64_t bufoff ;
1546
+ dmu_buf_t * db = dbp [i ];
1543
1547
1544
- ASSERT (write_size > 0 );
1548
+ offset_t off = zfs_uio_offset (uio );
1549
+ bufoff = off - db -> db_offset ;
1550
+ tocpy = MIN (db -> db_size - bufoff , write_size );
1545
1551
1546
- offset_t off = zfs_uio_offset (uio );
1547
- bufoff = off - db -> db_offset ;
1548
- tocpy = MIN (db -> db_size - bufoff , write_size );
1552
+ ASSERT (i == 0 || i == numbufs - 1 || tocpy == db -> db_size );
1549
1553
1550
- ASSERT (i == 0 || i == numbufs - 1 || tocpy == db -> db_size );
1554
+ if (tocpy == db -> db_size )
1555
+ dmu_buf_will_fill (db , tx , B_TRUE );
1556
+ else
1557
+ dmu_buf_will_dirty (db , tx );
1551
1558
1552
- if (tocpy == db -> db_size )
1553
- dmu_buf_will_fill (db , tx , B_TRUE );
1554
- else
1555
- dmu_buf_will_dirty (db , tx );
1559
+ ASSERT (db -> db_data != NULL );
1560
+ uint64_t resid_before = uio -> uio_resid ;
1561
+ err = zfs_uio_fault_move ((char * )db -> db_data + bufoff ,
1562
+ tocpy , UIO_WRITE , uio );
1563
+ uint64_t moved = resid_before - uio -> uio_resid ;
1556
1564
1557
- ASSERT (db -> db_data != NULL );
1558
- err = zfs_uio_fault_move ((char * )db -> db_data + bufoff ,
1559
- tocpy , UIO_WRITE , uio );
1565
+ if (tocpy == db -> db_size && dmu_buf_fill_done (db , tx , err )) {
1566
+ /* The fill was reverted. Undo any uio progress. */
1567
+ zfs_uio_advance (uio , off - zfs_uio_offset (uio ));
1568
+ }
1560
1569
1561
- if (tocpy == db -> db_size && dmu_buf_fill_done (db , tx , err )) {
1562
- /* The fill was reverted. Undo any uio progress. */
1563
- zfs_uio_advance (uio , off - zfs_uio_offset (uio ));
1564
- }
1570
+ if (err || moved == 0 )
1571
+ break ;
1565
1572
1566
- if ( err )
1567
- break ;
1573
+ write_size -= moved ;
1574
+ size -= moved ;
1568
1575
1569
- write_size -= tocpy ;
1570
- size -= tocpy ;
1576
+ if ( bufoff + moved >= db -> db_size )
1577
+ i ++ ;
1571
1578
}
1572
1579
1573
- IMPLY (err == 0 , write_size == 0 );
1580
+ IMPLY (err == 0 , write_size == 0 );
1574
1581
1575
1582
dmu_buf_rele_array (dbp , numbufs , FTAG );
1576
1583
0 commit comments