Skip to content

Commit

Permalink
Backport moby#4202 to v0.9.1
Browse files Browse the repository at this point in the history
  • Loading branch information
Lans Carstensen authored and Lans Carstensen committed Apr 2, 2014
1 parent 867b2a9 commit 62c236e
Show file tree
Hide file tree
Showing 14 changed files with 649 additions and 5 deletions.
28 changes: 28 additions & 0 deletions api/client.go
Expand Up @@ -89,6 +89,7 @@ func (cli *DockerCli) CmdHelp(args ...string) error {
{"commit", "Create a new image from a container's changes"},
{"cp", "Copy files/folders from the containers filesystem to the host path"},
{"diff", "Inspect changes on a container's filesystem"},
{"driver", "Driver specific operations"},
{"events", "Get real time events from the server"},
{"export", "Stream the contents of a container as a tar archive"},
{"history", "Show the history of an image"},
Expand Down Expand Up @@ -124,6 +125,33 @@ func (cli *DockerCli) CmdHelp(args ...string) error {
return nil
}

// 'docker driver': driver specific ops
func (cli *DockerCli) CmdDriver(args ...string) error {
cmd := cli.Subcmd("driver", "OPERATION [ARGUMENTS]", "Driver specific ops.")
if err := cmd.Parse(args); err != nil {
return nil
}

if cmd.NArg() == 0 {
cmd.Usage()
return nil
}

operation := cmd.Arg(0)

val := url.Values{}
if cmd.NArg() > 1 {
val.Set("args", strings.Join(cmd.Args()[1:], " "))
}

_, _, err := readBody(cli.call("GET", "/driver/"+operation+"?"+val.Encode(), nil, false))
if err != nil {
return err
}

return nil
}

func (cli *DockerCli) CmdInsert(args ...string) error {
cmd := cli.Subcmd("insert", "IMAGE URL PATH", "Insert a file from URL in the IMAGE at PATH")
if err := cmd.Parse(args); err != nil {
Expand Down
22 changes: 22 additions & 0 deletions api/server.go
Expand Up @@ -1002,6 +1002,7 @@ func createRouter(eng *engine.Engine, logging, enableCors bool, dockerVersion st
"/containers/{name:.*}/json": getContainersByName,
"/containers/{name:.*}/top": getContainersTop,
"/containers/{name:.*}/attach/ws": wsContainersAttach,
"/driver/{operation:.*}": getDriverOperation,
},
"POST": {
"/auth": postAuth,
Expand Down Expand Up @@ -1220,3 +1221,24 @@ func AcceptConnections(job *engine.Job) engine.Status {

return engine.StatusOK
}

func getDriverOperation(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
if err := parseForm(r); err != nil {
return err
}
args := []string{vars["operation"]}
argsString := r.Form.Get("args")
if argsString != "" {
args = append(args, strings.Split(argsString, " ")...)
}

job := eng.Job("driver", args...)
if err := job.Run(); err != nil {
return err
}
w.WriteHeader(http.StatusNoContent)
return nil
}
4 changes: 4 additions & 0 deletions graphdriver/aufs/aufs.go
Expand Up @@ -399,3 +399,7 @@ func rollbackMount(target string, err error) {
Unmount(target)
}
}

func (a Driver) Operation(op string, args []string) error {
return fmt.Errorf("Operation %s not supported", op)
}
4 changes: 4 additions & 0 deletions graphdriver/btrfs/btrfs.go
Expand Up @@ -211,3 +211,7 @@ func (d *Driver) Exists(id string) bool {
_, err := os.Stat(dir)
return err == nil
}

func (d *Driver) Operation(op string, args []string) error {
return fmt.Errorf("Operation %s not supported", op)
}
153 changes: 152 additions & 1 deletion graphdriver/devmapper/deviceset.go
Expand Up @@ -14,6 +14,7 @@ import (
"strconv"
"strings"
"sync"
"syscall"
"time"
)

Expand Down Expand Up @@ -395,7 +396,100 @@ func minor(device uint64) uint64 {
return (device & 0xff) | ((device >> 12) & 0xfff00)
}

func (devices *DeviceSet) getBlockDevice(name string) (*osFile, error) {
dirname := devices.loopbackDir()
filename := path.Join(dirname, name)

file, err := osOpenFile(filename, osORdWr, 0)
if file == nil {
return nil, err
}
defer file.Close()

loopback := FindLoopDeviceFor(file)
if loopback == nil {
return nil, fmt.Errorf("Unable to find loopback mount for: %s", filename)
}
return loopback, nil
}

func (devices *DeviceSet) TrimPool() error {
devices.Lock()
defer devices.Unlock()

totalSizeInSectors, _, _, dataTotal, _, _, err := devices.poolStatus()
if err != nil {
return err
}
blockSizeInSectors := totalSizeInSectors / dataTotal
SectorSize := blockSizeInSectors * 512

data, err := devices.getBlockDevice("data")
if err != nil {
return err
}
defer data.Close()

dataSize, err := GetBlockDeviceSize(data)
if err != nil {
return err
}

metadata, err := devices.getBlockDevice("metadata")
if err != nil {
return err
}
defer metadata.Close()

// Suspend the pool so the metadata doesn't change and new blocks
// are not loaded
if err := suspendDevice(devices.getPoolName()); err != nil {
return fmt.Errorf("Unable to suspend pool: %s", err)
}

// Just in case, make sure everything is on disk
syscall.Sync()

ranges, err := readMetadataRanges(metadata.Name())
if err != nil {
resumeDevice(devices.getPoolName())
return err
}

lastEnd := uint64(0)

for e := ranges.Front(); e != nil; e = e.Next() {
r := e.Value.(*Range)
// Convert to bytes
rBegin := r.begin * SectorSize
rEnd := r.end * SectorSize

if rBegin > lastEnd {
if err := BlockDeviceDiscard(data, lastEnd, rBegin-lastEnd); err != nil {
return fmt.Errorf("Failing do discard block, leaving pool suspended: %v", err)
}
}
lastEnd = rEnd
}

if dataSize > lastEnd {
if err := BlockDeviceDiscard(data, lastEnd, dataSize-lastEnd); err != nil {
return fmt.Errorf("Failing do discard block, leaving pool suspended: %v", err)
}
}

// Resume the pool
if err := resumeDevice(devices.getPoolName()); err != nil {
return fmt.Errorf("Unable to resume pool: %s", err)
}

return nil
}

func (devices *DeviceSet) ResizePool(size int64) error {
devices.Lock()
defer devices.Unlock()

dirname := devices.loopbackDir()
datafilename := path.Join(dirname, "data")
metadatafilename := path.Join(dirname, "metadata")
Expand Down Expand Up @@ -604,7 +698,7 @@ func (devices *DeviceSet) deleteDevice(hash string) error {
// on the thin pool when we remove a thinp device, so we do it
// manually
if err := devices.activateDeviceIfNeeded(hash); err == nil {
if err := BlockDeviceDiscard(info.DevName()); err != nil {
if err := BlockDeviceDiscardAll(info.DevName()); err != nil {
utils.Debugf("Error discarding block on device: %s (ignoring)\n", err)
}
}
Expand Down Expand Up @@ -1074,6 +1168,63 @@ func (devices *DeviceSet) Status() *Status {
return status
}

func (devices *DeviceSet) ResizeDevice(hash string, size int64) error {
devices.Lock()
defer devices.Unlock()

info := devices.Devices[hash]
if info == nil {
return fmt.Errorf("Unknown device %s", hash)
}

if size < 0 || info.Size > uint64(size) {
return fmt.Errorf("Can't shrink devices")
}

devinfo, err := getInfo(info.Name())
if info == nil {
return err
}

if devinfo.OpenCount != 0 {
return fmt.Errorf("Device in use")
}

if devinfo.Exists != 0 {
if err := devices.deactivateDevice(hash); err != nil {
return err
}
}

oldSize := info.Size
info.Size = uint64(size)

if err := devices.saveMetadata(); err != nil {
info.Size = oldSize
return err
}

if err := devices.activateDeviceIfNeeded(hash); err != nil {
return err
}

err = execRun("e2fsck", "-f", "-y", info.DevName())
if err != nil {
return fmt.Errorf("e2fsck failed: %v", err)
}

err = execRun("resize2fs", info.DevName())
if err != nil {
return fmt.Errorf("resizee2fs failed: %v", err)
}

if err := devices.deactivateDevice(hash); err != nil {
return err
}

return nil
}

func NewDeviceSet(root string, doInit bool) (*DeviceSet, error) {
SetDevDir("/dev")

Expand Down
16 changes: 12 additions & 4 deletions graphdriver/devmapper/devmapper.go
Expand Up @@ -202,8 +202,8 @@ func FindLoopDeviceFor(file *osFile) *osFile {
if err != nil {
return nil
}
targetInode := stat.Sys().(*sysStatT).Ino
targetDevice := stat.Sys().(*sysStatT).Dev
targetInode := stat.Sys().(*syscall.Stat_t).Ino
targetDevice := stat.Sys().(*syscall.Stat_t).Dev

for i := 0; true; i++ {
path := fmt.Sprintf("/dev/loop%d", i)
Expand Down Expand Up @@ -289,7 +289,7 @@ func GetBlockDeviceSize(file *osFile) (uint64, error) {
return uint64(size), nil
}

func BlockDeviceDiscard(path string) error {
func BlockDeviceDiscardAll(path string) error {
file, err := osOpenFile(path, osORdWr, 0)
if err != nil {
return err
Expand All @@ -301,7 +301,7 @@ func BlockDeviceDiscard(path string) error {
return err
}

if err := ioctlBlkDiscard(file.Fd(), 0, size); err != nil {
if err := BlockDeviceDiscard(file, 0, size); err != nil {
return err
}

Expand All @@ -312,6 +312,14 @@ func BlockDeviceDiscard(path string) error {
return nil
}

func BlockDeviceDiscard(file *osFile, offset, length uint64) error {
if err := ioctlBlkDiscard(file.Fd(), offset, length); err != nil {
return err
}

return nil
}

// This is the programmatic example of "dmsetup create"
func createPool(poolName string, dataFile, metadataFile *osFile) error {
task, err := createTask(DeviceCreate, poolName)
Expand Down

0 comments on commit 62c236e

Please sign in to comment.