/*
 * DF-4714 trigger (scenario A - clean silent-data-loss oracle, no panic).
 *
 * ONE 16KB write() at volume sectors [128,160) - a single data block on
 * subdisk s1 (ordinal 1). Preconditions: s0 (the stripe's parity subdisk)
 * administratively DOWN, s1 in state sd_reborn (both states arise
 * naturally from drive flaps; here placed via 'vinum setstate -f').
 *
 * bre5() marks the down parity subdisk at vinumraid5.c:363-364
 * (m.badsdno = psdno). In the write loop, s1 (reborn) makes
 * checksdstate() return REQUEST_OK (reborn is writable), and the
 * second-bad-subdisk guard at :404 only fires when s != 0 -- so
 * m.badsdno is silently OVERWRITTEN with the data subdisk (:420).
 * The XFR_PARITYLESS_WRITE conversion at :443 never happens; instead
 * the degraded path runs: the data block (flagged XFR_BAD_SUBDISK) is
 * never written, parity is recomputed from the other column plus the
 * user's new data and written to the DOWN parity subdisk, and the
 * write() returns SUCCESS.  The user's 16KB is gone.
 *
 * buggy kernel:  write OK, readback returns the OLD bytes (loss).
 * fixed kernel:  write fails EIO (refusal at the :404 guard).
 */
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#define VOL	"/dev/vinum/vol/rv"
#define OFF	(128 * 512)
#define LEN	(32 * 512)

unsigned char wbuf[LEN], rbuf[LEN];

int main(void)
{
	int fd, rc, i;

	memset(wbuf, 0xBB, LEN);
	memset(rbuf, 0, LEN);
	fd = open(VOL, O_RDWR);
	if (fd < 0) { perror("open"); return 2; }
	if (lseek(fd, OFF, SEEK_SET) < 0) { perror("lseek"); return 2; }

	rc = write(fd, wbuf, LEN);
	if (rc != LEN) {
		perror("write");
		printf("DF-4714-A RESULT: write FAILED (correct behavior on a fixed kernel)\n");
		return 0;
	}
	printf("DF-4714-A: write OK (16KB accepted with parity sd DOWN + data sd REBORN)\n");
	sleep(1);
	if (lseek(fd, OFF, SEEK_SET) < 0) { perror("lseek2"); return 2; }
	rc = read(fd, rbuf, LEN);
	if (rc != LEN) { perror("read"); printf("DF-4714-A RESULT: read FAILED\n"); return 0; }
	for (i = 0; i < LEN; i++) if (rbuf[i] != 0xBB) {
		printf("DF-4714-A RESULT: *** SILENT DATA LOSS (readback %02x != %02x) ***\n",
		    rbuf[i], 0xBB);
		return 1;
	}
	printf("DF-4714-A RESULT: readback matches (no loss)\n");
	return 0;
}
