szaydel
12/28/2017 - 11:20 PM

Dummy IO program used to test proper EIO reporting

This snippet is primarily meant as a building block for tools used to validate system IO, in particular for testing how system behaves with regard to IO error handling.

package main

// A dummy program designed for validating correct EIO reporting from the
// kernel on BrickstorOS.
//
// Build and run something like this, where name of program is doio:
// # ./doio /dev/rdsk/c0t5000C5004271FCCFd0s0
//
// The only valid argument is path to a file, which could be a raw disk 
// device or any old file.

import (
	"fmt"
	"os"
	"syscall"
)

const (
	openMode  = 0644
	openFlags = syscall.O_RDONLY | syscall.O_NDELAY
	loopLimit = 1e5
)

func main() {
	var fd, loopcnt, bytecnt int
	var path string

	buf := make([]byte, 4096)

	if len(os.Args) < 2 {
		os.Exit(1)
	} else {
		path = os.Args[1]
	}

	if info, err := os.Stat(path); err != nil {
		if os.IsNotExist(err) {
			fmt.Printf("%v\n", err)
			os.Exit(1)
		}
	} else {
		fd, err = syscall.Open(path, openFlags, openMode)
		if err != nil {
			fmt.Printf("%v, failed to open %s\n", err, path)
			os.Exit(1)
		}
		fmt.Printf("Opened '%s' for reading\n", info.Name())
		for loopcnt < loopLimit {
			n, err := syscall.Read(fd, buf)
			if err != nil {
				// EIO is what we are interested to trap
				if err == syscall.EIO {
					fmt.Printf("Received EIO (0x5)\n")
					os.Exit(5)
					// Some other unexpected condition
				} else {
					fmt.Printf("%v\n", err)
					os.Exit(1)
				}

			} else {
				if loopcnt%1000 == 0 {
					fmt.Printf("loopcnt: %-8d | bytecnt: %d\n",
						loopcnt, bytecnt)
				}
				loopcnt++
				bytecnt += n
			}
		}
	}
	os.Exit(0)

}