Refactor archive buffering

This PR refactors archive to add buffering to help fix #7291. This PR is the first one of the two PRs required to fix #7291.

The first commit (move some io related utils to pkg/ioutils) moves some Readers and Writers to pkg/ioutils. I've moved these first so that I would avoid adding WriteCloseWrapper to utils/utils.go. I've moved only the io utils which had the least dependencies on other things (e.g. no HTTP related utils were moved and so on).

This PR adds archive/pool to help reuse buffers for reading and for writing. This allows us to use larger buffers by reusing them.

The PR also adds buffering to archive writing, thus helping speed up archive writing and a few other operations.

Please focus on stress testing this with pulls, pushes, builds and anything you can think of. Please check if this helps speed up `docker pull` and `docker push` with the Docker Hub and with private registries.

Open questions:
- [x] Should we make the pool global and share it across components of Docker? We could reuse it in other places as well. Conclusion: YES
- [x] Should we increase the 512K buffers to 1024K to help make downloads even smoother? Conclusion: NO
- [ ] Should we decrease the big buffers to 256K?
Why not to do something like:
```
type ReaderPool struct {
	p sync.Pool
}

func NewReaderPool(size int) *ReaderPool {
	return &ReaderPool{
		p: sync.Pool{
			New: func() interface{} { return bufio.NewReaderSize(nil, size) },
		},
	}
}
```
and let client decide what size is needed?