Print this page
OS-4319 zfs mishandles partial writes

@@ -663,10 +663,11 @@
         zilog_t         *zilog;
         offset_t        woff;
         ssize_t         n, nbytes;
         int             max_blksz = zfsvfs->z_max_blksz;
         int             error = 0;
+        int             prev_error;
         arc_buf_t       *abuf;
         iovec_t         *aiov = NULL;
         xuio_t          *xuio = NULL;
         int             i_iov = 0;
         int             iovcnt = uio->uio_iovcnt;

@@ -970,26 +971,30 @@
                  * account for possible concurrent updates.
                  */
                 while ((end_size = zp->z_size) < uio->uio_loffset) {
                         (void) atomic_cas_64(&zp->z_size, end_size,
                             uio->uio_loffset);
-                        ASSERT(error == 0);
                 }
                 /*
                  * If we are replaying and eof is non zero then force
                  * the file size to the specified eof. Note, there's no
                  * concurrency during replay.
                  */
                 if (zfsvfs->z_replay && zfsvfs->z_replay_eof != 0)
                         zp->z_size = zfsvfs->z_replay_eof;
 
+                /*
+                 * Keep track of a possible pre-existing error from a partial
+                 * write via dmu_write_uio_dbuf above.
+                 */
+                prev_error = error;
                 error = sa_bulk_update(zp->z_sa_hdl, bulk, count, tx);
 
                 zfs_log_write(zilog, tx, TX_WRITE, zp, woff, tx_bytes, ioflag);
                 dmu_tx_commit(tx);
 
-                if (error != 0)
+                if (prev_error != 0 || error != 0)
                         break;
                 ASSERT(tx_bytes == nbytes);
                 n -= nbytes;
 
                 if (!xuio && n > 0)