Skip to content

Commit

Permalink
dnode_is_dirty: check dnode and its data for dirtiness
Browse files Browse the repository at this point in the history
Over its history this the dirty dnode test has been changed between
checking for a dnodes being on `os_dirty_dnodes` (`dn_dirty_link`) and
`dn_dirty_record`.

It turns out both are actually required.

In the case of appending data to a newly created file, the dnode proper
is dirtied (at least to change the blocksize) and dirty records are
added.  Thus, a single logical operation is represented by separate
dirty indicators, and must not be separated.

The incorrect dirty check becomes a problem when the first block of a
file is being appended to while another process is calling lseek to skip
holes. There is a small window where the dnode part is undirtied while
there are still dirty records. In this case, `lseek(fd, 0, SEEK_DATA)`
would not know that the file is dirty, and would go to
`dnode_next_offset()`. Since the object has no data blocks yet, it
returns `ESRCH`, indicating no data found, which results in `ENXIO`
being returned to `lseek()`'s caller.

This change simply updates the dirty check to check both types of dirty.
If there's anything dirty at all, we immediately go to the "wait for
sync" stage, It doesn't really matter after that; both changes are on
disk, so the dirty fields should be correct.

Sponsored by:	Klara, Inc.
Sponsored by:	Wasabi Technology, Inc.
  • Loading branch information
robn committed Nov 30, 2023
1 parent f2877ac commit b51ff59
Showing 1 changed file with 2 additions and 1 deletion.
3 changes: 2 additions & 1 deletion sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -2557,7 +2557,8 @@ dmu_object_wait_synced(objset_t *os, uint64_t object)
}

for (i = 0; i < TXG_SIZE; i++) {
if (list_link_active(&dn->dn_dirty_link[i])) {
if (list_link_active(&dn->dn_dirty_link[i]) ||
!list_is_empty(&dn->dn_dirty_records[i])) {
break;
}
}
Expand Down

0 comments on commit b51ff59

Please sign in to comment.