瀏覽代碼

devmapper: Update device-mapper-tool

This makes the device mapper tool work again and adds new features
to get pool status, device status and to list all devices.
Alexander Larsson 11 年之前
父節點
當前提交
80aecc7014
共有 3 個文件被更改,包括 176 次插入38 次删除
  1. 103 18
      graphdriver/devmapper/deviceset.go
  2. 72 19
      graphdriver/devmapper/docker-device-tool/device_tool.go
  3. 1 1
      graphdriver/devmapper/driver.go

+ 103 - 18
graphdriver/devmapper/deviceset.go

@@ -57,6 +57,16 @@ type Status struct {
 	MetadataLoopback string
 	Data             DiskUsage
 	Metadata         DiskUsage
+	SectorSize       uint64
+}
+
+type DevStatus struct {
+	DeviceId            int
+	Size                uint64
+	TransactionId       uint64
+	SizeInSectors       uint64
+	MappedSectors       uint64
+	HighestMappedSector uint64
 }
 
 func getDevName(name string) string {
@@ -357,13 +367,24 @@ func minor(device uint64) uint64 {
 	return (device & 0xff) | ((device >> 12) & 0xfff00)
 }
 
-func (devices *DeviceSet) initDevmapper() error {
+func (devices *DeviceSet) initDevmapper(doInit bool) error {
 	logInit(devices)
 
 	// Make sure the sparse images exist in <root>/devicemapper/data and
 	// <root>/devicemapper/metadata
 
-	createdLoopback := !devices.hasImage("data") || !devices.hasImage("metadata")
+	hasData := devices.hasImage("data")
+	hasMetadata := devices.hasImage("metadata")
+
+	if !doInit && !hasData {
+		return fmt.Errorf("Looback data file not found %s")
+	}
+
+	if !doInit && !hasMetadata {
+		return fmt.Errorf("Looback metadata file not found %s")
+	}
+
+	createdLoopback := !hasData || !hasMetadata
 	data, err := devices.ensureImage("data", DefaultDataLoopbackSize)
 	if err != nil {
 		utils.Debugf("Error device ensureImage (data): %s\n", err)
@@ -438,9 +459,11 @@ func (devices *DeviceSet) initDevmapper() error {
 	}
 
 	// Setup the base image
-	if err := devices.setupBaseImage(); err != nil {
-		utils.Debugf("Error device setupBaseImage: %s\n", err)
-		return err
+	if doInit {
+		if err := devices.setupBaseImage(); err != nil {
+			utils.Debugf("Error device setupBaseImage: %s\n", err)
+			return err
+		}
 	}
 
 	return nil
@@ -757,6 +780,69 @@ func (devices *DeviceSet) setInitialized(hash string) error {
 	return nil
 }
 
+func (devices *DeviceSet) List() []string {
+	devices.Lock()
+	defer devices.Unlock()
+
+	ids := make([]string, len(devices.Devices))
+	i := 0
+	for k := range devices.Devices {
+		ids[i] = k
+		i++
+	}
+	return ids
+}
+
+func (devices *DeviceSet) deviceStatus(devName string) (sizeInSectors, mappedSectors, highestMappedSector uint64, err error) {
+	var params string
+	_, sizeInSectors, _, params, err = getStatus(devName)
+	if err != nil {
+		return
+	}
+	if _, err = fmt.Sscanf(params, "%d %d", &mappedSectors, &highestMappedSector); err == nil {
+		return
+	}
+	return
+}
+
+func (devices *DeviceSet) GetDeviceStatus(hash string) (*DevStatus, error) {
+	devices.Lock()
+	defer devices.Unlock()
+
+	info := devices.Devices[hash]
+	if info == nil {
+		return nil, fmt.Errorf("No device %s", hash)
+	}
+
+	status := &DevStatus{
+		DeviceId:      info.DeviceId,
+		Size:          info.Size,
+		TransactionId: info.TransactionId,
+	}
+
+	if err := devices.activateDeviceIfNeeded(hash); err != nil {
+		return nil, fmt.Errorf("Error activating devmapper device for '%s': %s", hash, err)
+	}
+
+	if sizeInSectors, mappedSectors, highestMappedSector, err := devices.deviceStatus(info.DevName()); err != nil {
+		return nil, err
+	} else {
+		status.SizeInSectors = sizeInSectors
+		status.MappedSectors = mappedSectors
+		status.HighestMappedSector = highestMappedSector
+	}
+
+	return status, nil
+}
+
+func (devices *DeviceSet) poolStatus() (totalSizeInSectors, transactionId, dataUsed, dataTotal, metadataUsed, metadataTotal uint64, err error) {
+	var params string
+	if _, totalSizeInSectors, _, params, err = getStatus(devices.getPoolName()); err == nil {
+		_, err = fmt.Sscanf(params, "%d %d/%d %d/%d", &transactionId, &metadataUsed, &metadataTotal, &dataUsed, &dataTotal)
+	}
+	return
+}
+
 func (devices *DeviceSet) Status() *Status {
 	devices.Lock()
 	defer devices.Unlock()
@@ -767,26 +853,25 @@ func (devices *DeviceSet) Status() *Status {
 	status.DataLoopback = path.Join(devices.loopbackDir(), "data")
 	status.MetadataLoopback = path.Join(devices.loopbackDir(), "metadata")
 
-	_, totalSizeInSectors, _, params, err := getStatus(devices.getPoolName())
+	totalSizeInSectors, _, dataUsed, dataTotal, metadataUsed, metadataTotal, err := devices.poolStatus()
 	if err == nil {
-		var transactionId, dataUsed, dataTotal, metadataUsed, metadataTotal uint64
-		if _, err := fmt.Sscanf(params, "%d %d/%d %d/%d", &transactionId, &metadataUsed, &metadataTotal, &dataUsed, &dataTotal); err == nil {
-			// Convert from blocks to bytes
-			blockSizeInSectors := totalSizeInSectors / dataTotal
+		// Convert from blocks to bytes
+		blockSizeInSectors := totalSizeInSectors / dataTotal
 
-			status.Data.Used = dataUsed * blockSizeInSectors * 512
-			status.Data.Total = dataTotal * blockSizeInSectors * 512
+		status.Data.Used = dataUsed * blockSizeInSectors * 512
+		status.Data.Total = dataTotal * blockSizeInSectors * 512
 
-			// metadata blocks are always 4k
-			status.Metadata.Used = metadataUsed * 4096
-			status.Metadata.Total = metadataTotal * 4096
-		}
+		// metadata blocks are always 4k
+		status.Metadata.Used = metadataUsed * 4096
+		status.Metadata.Total = metadataTotal * 4096
+
+		status.SectorSize = blockSizeInSectors * 512
 	}
 
 	return status
 }
 
-func NewDeviceSet(root string) (*DeviceSet, error) {
+func NewDeviceSet(root string, doInit bool) (*DeviceSet, error) {
 	SetDevDir("/dev")
 
 	devices := &DeviceSet{
@@ -795,7 +880,7 @@ func NewDeviceSet(root string) (*DeviceSet, error) {
 		activeMounts: make(map[string]int),
 	}
 
-	if err := devices.initDevmapper(); err != nil {
+	if err := devices.initDevmapper(doInit); err != nil {
 		return nil, err
 	}
 

+ 72 - 19
graphdriver/devmapper/docker-device-tool/device_tool.go

@@ -1,59 +1,112 @@
 package main
 
 import (
+	"flag"
 	"fmt"
-	"github.com/dotcloud/docker/devmapper"
+	"github.com/dotcloud/docker/graphdriver/devmapper"
 	"os"
+	"path"
+	"sort"
 )
 
 func usage() {
-	fmt.Printf("Usage: %s [snap new-id base-id] | [remove id] | [mount id mountpoint]\n", os.Args[0])
+	fmt.Fprintf(os.Stderr, "Usage: %s <flags>  [status] | [list] | [device id] | [snap new-id base-id] | [remove id] | [mount id mountpoint]\n", os.Args[0])
+	flag.PrintDefaults()
 	os.Exit(1)
 }
 
 func main() {
-	devices := devmapper.NewDeviceSet("/var/lib/docker")
+	root := flag.String("r", "/var/lib/docker", "Docker root dir")
+	flDebug := flag.Bool("D", false, "Debug mode")
 
-	if len(os.Args) < 2 {
+	flag.Parse()
+
+	if *flDebug {
+		os.Setenv("DEBUG", "1")
+	}
+
+	if flag.NArg() < 1 {
 		usage()
 	}
 
-	cmd := os.Args[1]
-	if cmd == "snap" {
-		if len(os.Args) < 4 {
+	args := flag.Args()
+
+	home := path.Join(*root, "devicemapper")
+	devices, err := devmapper.NewDeviceSet(home, false)
+	if err != nil {
+		fmt.Println("Can't initialize device mapper: ", err)
+		os.Exit(1)
+	}
+
+	switch args[0] {
+	case "status":
+		status := devices.Status()
+		fmt.Printf("Pool name: %s\n", status.PoolName)
+		fmt.Printf("Data Loopback file: %s\n", status.DataLoopback)
+		fmt.Printf("Metadata Loopback file: %s\n", status.MetadataLoopback)
+		fmt.Printf("Sector size: %d\n", status.SectorSize)
+		fmt.Printf("Data use: %d of %d (%.1f %%)\n", status.Data.Used, status.Data.Total, 100.0*float64(status.Data.Used)/float64(status.Data.Total))
+		fmt.Printf("Metadata use: %d of %d (%.1f %%)\n", status.Metadata.Used, status.Metadata.Total, 100.0*float64(status.Metadata.Used)/float64(status.Metadata.Total))
+		break
+	case "list":
+		ids := devices.List()
+		sort.Strings(ids)
+		for _, id := range ids {
+			fmt.Println(id)
+		}
+		break
+	case "device":
+		if flag.NArg() < 2 {
+			usage()
+		}
+		status, err := devices.GetDeviceStatus(args[1])
+		if err != nil {
+			fmt.Println("Can't get device info: ", err)
+			os.Exit(1)
+		}
+		fmt.Printf("Id: %d\n", status.DeviceId)
+		fmt.Printf("Size: %d\n", status.Size)
+		fmt.Printf("Transaction Id: %d\n", status.TransactionId)
+		fmt.Printf("Size in Sectors: %d\n", status.SizeInSectors)
+		fmt.Printf("Mapped Sectors: %d\n", status.MappedSectors)
+		fmt.Printf("Highest Mapped Sector: %d\n", status.HighestMappedSector)
+		break
+	case "snap":
+		if flag.NArg() < 3 {
 			usage()
 		}
 
-		err := devices.AddDevice(os.Args[2], os.Args[3])
+		err := devices.AddDevice(args[1], args[2])
 		if err != nil {
 			fmt.Println("Can't create snap device: ", err)
 			os.Exit(1)
 		}
-	} else if cmd == "remove" {
-		if len(os.Args) < 3 {
+		break
+	case "remove":
+		if flag.NArg() < 2 {
 			usage()
 		}
 
-		err := devices.RemoveDevice(os.Args[2])
+		err := devices.RemoveDevice(args[1])
 		if err != nil {
 			fmt.Println("Can't remove device: ", err)
 			os.Exit(1)
 		}
-	} else if cmd == "mount" {
-		if len(os.Args) < 4 {
+		break
+	case "mount":
+		if flag.NArg() < 3 {
 			usage()
 		}
 
-		err := devices.MountDevice(os.Args[2], os.Args[3])
+		err := devices.MountDevice(args[1], args[2], false)
 		if err != nil {
 			fmt.Println("Can't create snap device: ", err)
 			os.Exit(1)
 		}
-	} else {
-		fmt.Printf("Unknown command %s\n", cmd)
-		if len(os.Args) < 4 {
-			usage()
-		}
+		break
+	default:
+		fmt.Printf("Unknown command %s\n", args[0])
+		usage()
 
 		os.Exit(1)
 	}

+ 1 - 1
graphdriver/devmapper/driver.go

@@ -22,7 +22,7 @@ type Driver struct {
 }
 
 func Init(home string) (graphdriver.Driver, error) {
-	deviceSet, err := NewDeviceSet(home)
+	deviceSet, err := NewDeviceSet(home, true)
 	if err != nil {
 		return nil, err
 	}