What is a Dnode?
Much of ZFS's internal code focuses around manipulation of objects called dnodes and managing their state on-disk and in-memory. Dnodes can represent a number of things, take a look at the enum used for dnode's dn_type field:
For example, user-created files are represented as dnodes with dn_type=DMU_OT_PLAIN_FILE_CONTENTS.
A dnode is stored on disk as a tree of block pointers. At its root is a dnode_phys_t structure containing metadata on the dnode: its type, number of levels in the dnode tree, whether there is a bonus buffer attached for extra meta-information, the checksumming algorithm used in this dnode, etc. The root of a dnode also contains up to 3 block pointers which reference blocks on disk for storing the actual contents of this dnode object (for example, the information in a user file).
Given that the maximum size of a ZFS block is 128KB and the dnode root structure can only hold up to 3 block pointers, only 384KB of space can be directly referenced from a dnode. Obviously, this isn't enough space to store the vast majority of user files, and so indirect blocks were created. Indirect blocks are ZFS blocks which themselves store block pointers, as opposed to data blocks which store the actual data of the dnode. Data blocks can also be referred to as L0 blocks because they are at level=0 in a dnode, with their immediate parent indirect blocks being L1 blocks, and their parents being L2 blocks, etc. A simple diagram of a dnode with indirect blocks can be found in the ZFS On-Disk Format guide (keep in mind that while a block pointer represents a single logical block, it can be backed by multiple physical blocks pointed to by multiple DVAs).
What is a dnode sync?
To make changes to a ZFS object stored in a dnode (for example, a user file), ZFS reads parts of the file into in-memory DMU buffers. Synchronizing these changes back out to disk at a time decided by ZFS is done in a dnode sync, from the function dnode_sync.