I'm successfully using an SPI wrapper I wrote several years ago for exactly the same kind of accesses (e.g. for MCP23S17). The routine to perform a read-then-write (or optionally, write-and-write-again) does quite the same as your sample code (see SPIBus::spidev_write_read() at lines 205ff in p44utils/spi.cpp.
I didn't spot a functional difference to your code, so I'd assume your code should work (I know mine does, its in active use in many projects)
Maybe there's a difference in how you open the spiFd? You can see that part in SPIBus::accessBus() at line 384ff.
I'm using this code with both the MT7688 hardware SPI (which has a known hardware bug for full duplex, but that should not apply here, your read data starts after the write is over), and also with spi-gpio-custom software SPI.
Hope this helps!