I canvassed Andres off-list since smgrzeroextend() is his invention, and he wondered if it was a good idea to blur the distinction between the different zero-extension strategies like that. Good question. My take is that it's fine:
mdzeroextend() already uses fallocate() only for nblocks > 8, but otherwise writes out zeroes, because that was seen to interact better with file system heuristics on common systems. That preserves current behaviour for callers of plain-old sgmrextend(), which becomes a wrapper for smgrwrite(..., 1, _ZERO | _EXTEND). If some hypothetical future caller wants to be able to call smgrwritev(..., NULL, 9 blocks, _ZERO | _EXTEND) directly without triggering the fallocate() strategy for some well researched reason, we could add a new flag to say so, ie adjust that gating. In other words, we have already blurred the semantics. To me, it seems nicer to have a single high level interface for the same logical operation, and flags to select strategies more explicitly if that is eventually necessary.