// background routine for BlockReader to read the blocks in the // background into the channel // // It uses triple buffering with chan of length 1. One block being // filled, one block in the channel, and one block being used by the // client. func (br *BlockReader) background() { defer br.wg.Done() defer close(br.out) br.spare <- directio.AlignedBlock(BlockSize) br.spare <- directio.AlignedBlock(BlockSize) br.spare <- directio.AlignedBlock(BlockSize) for { block := <-br.spare _, err := io.ReadFull(br.in, block) if err != nil { if err == io.EOF { return } log.Fatalf("Error while reading %q: %s\n", br.file, err) } // FIXME bodge - don't account for reading from the random number if br.file != "random" { stats.Read(BlockSize) } select { case br.out <- block: case <-br.quit: return } } }
func TestDirectIo(t *testing.T) { // Make a temporary file name fd, err := ioutil.TempFile("", "direct_io_test") if err != nil { t.Fatal("Failed to make temp file", err) } path := fd.Name() fd.Close() // starting block block1 := directio.AlignedBlock(directio.BlockSize) for i := 0; i < len(block1); i++ { block1[i] = 'A' } // Write the file out, err := directio.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0666) if err != nil { t.Fatal("Failed to directio.OpenFile for read", err) } _, err = out.Write(block1) if err != nil { t.Fatal("Failed to write", err) } err = out.Close() if err != nil { t.Fatal("Failed to close writer", err) } // Read the file block2 := directio.AlignedBlock(directio.BlockSize) in, err := directio.OpenFile(path, os.O_RDONLY, 0666) if err != nil { t.Fatal("Failed to directio.OpenFile for write", err) } _, err = io.ReadFull(in, block2) if err != nil { t.Fatal("Failed to read", err) } err = in.Close() if err != nil { t.Fatal("Failed to close reader", err) } // Tidy err = os.Remove(path) if err != nil { t.Fatal("Failed to remove temp file", path, err) } // Compare if !bytes.Equal(block1, block2) { t.Fatal("Read not the same as written") } }
func (s *streamSender) Run() error { if err := s.prepare(); err != nil { return err } if err := s.putHeader(&s.header); err != nil { return err } if len(s.srcname) > 0 { // always activate original lv so that target lv can be activated later if err := lvmutil.ActivateLv(s.vgname, s.srcname); err != nil { return err } defer lvmutil.DeactivateLv(s.vgname, s.srcname) } if err := lvmutil.ActivateLv(s.vgname, s.lvname); err != nil { return err } defer lvmutil.DeactivateLv(s.vgname, s.lvname) devpath := lvmutil.LvDevicePath(s.vgname, s.lvname) devFile, err := directio.OpenFile(devpath, os.O_RDONLY, 0644) if err != nil { return err } defer devFile.Close() buf := directio.AlignedBlock(int(s.header.BlockSize)) blockSize := int64(s.header.BlockSize) for _, e := range s.blocks { if e.OpType == thindump.DeltaOpDelete { for i := 0; i < len(buf); i++ { buf[i] = 0 } } else { if _, err := devFile.Seek(e.OriginBlock*blockSize, os.SEEK_SET); err != nil { return err } if _, err := io.ReadFull(devFile, buf); err != nil { return err } } if err := s.putBlock(e.OriginBlock, buf); err != nil { return err } } return nil }
func (constor *Constor) Write(input *fuse.WriteIn, data []byte) (written uint32, code fuse.Status) { constor.log("%d %d", input.Fh, len(data)) ptr := uintptr(input.Fh) offset := input.Offset wdata := data F := constor.getfd(ptr) if F == nil { constor.error("F == nil") return 0, fuse.EIO } if F.flags&syscall.O_DIRECT != 0 { wdata = directio.AlignedBlock(len(data)) copy(wdata, data) } inode := constor.inodemap.findInodePtr(input.NodeId) if inode == nil { return 0, fuse.ENOENT } if F.layer != 0 && inode.layer != 0 { err := constor.copyup(inode) if err != nil { constor.error("%s", err) return 0, fuse.ToStatus(err) } path := constor.getPath(0, inode.id) syscall.Close(F.fd) fd, err := syscall.Open(path, F.flags, 0) if err != nil { constor.error("%s", err) return 0, fuse.ToStatus(err) } F.fd = fd F.layer = 0 constor.log("reset fd for %s", path) } else if F.layer != 0 && inode.layer == 0 { syscall.Close(F.fd) path := constor.getPath(0, inode.id) fd, err := syscall.Open(path, F.flags, 0) if err != nil { constor.error("%s", err) return 0, fuse.ToStatus(err) } F.fd = fd F.layer = 0 constor.log("reset fd for %s", path) } fd := F.fd n, err := syscall.Pwrite(fd, wdata, int64(offset)) return uint32(n), fuse.ToStatus(err) }
func copyN(dst io.Writer, src io.Reader, amount int64) (int, error) { block := directio.AlignedBlock(int(amount)) if _, err := src.Read(block); err != nil { return 0, err } s, err := dst.Write(block) if err != nil { return s, err } return s, nil }
func main() { // Get hold of the current working dir cwd, err := os.Getwd() fatalIfErr(err) // Create a temporary file fd, err := ioutil.TempFile(cwd, "sleepless") fatalIfErr(err) // We just need the file name, we're going to reopen it with the right flags path := fd.Name() fd.Close() // Allocate a block which will be filled with garbage on each iteration garbage := directio.AlignedBlock(directio.BlockSize) // Get ready out, err := directio.OpenFile(path, os.O_CREATE|os.O_RDWR|os.O_SYNC, 0600) fatalIfErr(err) // Setup signal handling sigint := make(chan os.Signal, 1) signal.Notify(sigint, os.Interrupt) go func() { <-sigint cleanup(out, path) os.Exit(0) }() // Start the main loop for { // Garbage in... if _, err = rand.Read(garbage); err != nil { cleanup(out, path) log.Fatal(err) } // ... garbage out if _, err = out.Write(garbage); err != nil { cleanup(out, path) log.Fatal(err) } // Rewind the file to the start so that it does not grow // indefintely if _, err = out.Seek(0, os.SEEK_SET); err != nil { cleanup(out, path) log.Fatal(err) } // Take a nap time.Sleep(10 * time.Second) } }
func (sr *streamRecver) recvNextStream() error { if err := sr.prepare(); err != nil { return err } devpath := lvmutil.LvDevicePath(sr.vgname, sr.lvname) devFile, err := directio.OpenFile(devpath, os.O_WRONLY, 0644) if err != nil { return err } defer devFile.Close() n := 8 + sr.header.BlockSize b := make([]byte, n+md5.Size) buf := directio.AlignedBlock(int(sr.header.BlockSize)) for i := uint64(0); i < sr.header.BlockCount; i++ { if _, err := io.ReadFull(sr.r, b); err != nil { return err } sr.h.Reset() sr.h.Write(b[:n]) if !bytes.Equal(sr.h.Sum(nil), b[n:n+md5.Size]) { return fmt.Errorf("check sum mismatch for %dst block", i) } index := int64(binary.BigEndian.Uint64(b)) copy(buf, b[8:n]) if _, err := devFile.Seek(int64(sr.header.BlockSize)*index, os.SEEK_SET); err != nil { return err } if _, err := devFile.Write(buf); err != nil { return err } } sr.prevUUID = string(sr.header.VolumeUUID[:]) return nil }
func TestZeroSizedBlock(t *testing.T) { // This should not panic! directio.AlignedBlock(0) }
func AlignedBlock(size int) []byte { return directio.AlignedBlock(size) }