Browse code

Merge pull request #10474 from petervo/10473-availble-space

Add available space to devicemapper status output

Vincent Batts authored on 2015/02/11 00:32:51
Showing 3 changed files
... ...
@@ -42,8 +42,10 @@ will display something like:
42 42
 	 Metadata file: /dev/loop4
43 43
 	 Data Space Used: 2.536 GB
44 44
 	 Data Space Total: 107.4 GB
45
+	 Data Space Available: 104.8 GB
45 46
 	 Metadata Space Used: 7.93 MB
46 47
 	 Metadata Space Total: 2.147 GB
48
+	 Metadata Space Available: 2.14 GB
47 49
 	 Udev Sync Supported: true
48 50
 	 Data loop file: /home/docker/devicemapper/devicemapper/data
49 51
 	 Metadata loop file: /home/docker/devicemapper/devicemapper/metadata
... ...
@@ -60,8 +62,10 @@ status information about the driver.
60 60
  *  `Metadata file` blockdevice file used for the devicemapper metadata
61 61
  *  `Data Space Used` tells how much of `Data file` is currently used
62 62
  *  `Data Space Total` tells max size the `Data file`
63
+ *  `Data Space Available` tells how much free space there is in the `Data file`. If you are using a loop device this will report the actual space available to the loop device on the underlying filesystem.
63 64
  *  `Metadata Space Used` tells how much of `Metadata file` is currently used
64 65
  *  `Metadata Space Total` tells max size the `Metadata file`
66
+ *  `Metadata Space Available` tells how much free space there is in the `Metadata file`. If you are using a loop device this will report the actual space available to the loop device on the underlying filesystem.
65 67
  *  `Udev Sync Supported` tells whether devicemapper is able to sync with Udev. Should be `true`.
66 68
  *  `Data loop file` file attached to `Data file`, if loopback device is used
67 69
  *  `Metadata loop file` file attached to `Metadata file`, if loopback device is used
... ...
@@ -100,8 +100,9 @@ type DeviceSet struct {
100 100
 }
101 101
 
102 102
 type DiskUsage struct {
103
-	Used  uint64
104
-	Total uint64
103
+	Used      uint64
104
+	Total     uint64
105
+	Available uint64
105 106
 }
106 107
 
107 108
 type Status struct {
... ...
@@ -1579,6 +1580,28 @@ func (devices *DeviceSet) MetadataDevicePath() string {
1579 1579
 	return devices.metadataDevice
1580 1580
 }
1581 1581
 
1582
+func (devices *DeviceSet) getUnderlyingAvailableSpace(loopFile string) (uint64, error) {
1583
+	buf := new(syscall.Statfs_t)
1584
+	err := syscall.Statfs(loopFile, buf)
1585
+	if err != nil {
1586
+		log.Warnf("Warning: Couldn't stat loopfile filesystem %v: %v", loopFile, err)
1587
+		return 0, err
1588
+	}
1589
+	return buf.Bfree * uint64(buf.Bsize), nil
1590
+}
1591
+
1592
+func (devices *DeviceSet) isRealFile(loopFile string) (bool, error) {
1593
+	if loopFile != "" {
1594
+		fi, err := os.Stat(loopFile)
1595
+		if err != nil {
1596
+			log.Warnf("Warning: Couldn't stat loopfile %v: %v", loopFile, err)
1597
+			return false, err
1598
+		}
1599
+		return fi.Mode().IsRegular(), nil
1600
+	}
1601
+	return false, nil
1602
+}
1603
+
1582 1604
 // Status returns the current status of this deviceset
1583 1605
 func (devices *DeviceSet) Status() *Status {
1584 1606
 	devices.Lock()
... ...
@@ -1600,12 +1623,28 @@ func (devices *DeviceSet) Status() *Status {
1600 1600
 
1601 1601
 		status.Data.Used = dataUsed * blockSizeInSectors * 512
1602 1602
 		status.Data.Total = dataTotal * blockSizeInSectors * 512
1603
+		status.Data.Available = status.Data.Total - status.Data.Used
1603 1604
 
1604 1605
 		// metadata blocks are always 4k
1605 1606
 		status.Metadata.Used = metadataUsed * 4096
1606 1607
 		status.Metadata.Total = metadataTotal * 4096
1608
+		status.Metadata.Available = status.Metadata.Total - status.Metadata.Used
1607 1609
 
1608 1610
 		status.SectorSize = blockSizeInSectors * 512
1611
+
1612
+		if check, _ := devices.isRealFile(devices.dataLoopFile); check {
1613
+			actualSpace, err := devices.getUnderlyingAvailableSpace(devices.dataLoopFile)
1614
+			if err == nil && actualSpace < status.Data.Available {
1615
+				status.Data.Available = actualSpace
1616
+			}
1617
+		}
1618
+
1619
+		if check, _ := devices.isRealFile(devices.metadataLoopFile); check {
1620
+			actualSpace, err := devices.getUnderlyingAvailableSpace(devices.metadataLoopFile)
1621
+			if err == nil && actualSpace < status.Metadata.Available {
1622
+				status.Metadata.Available = actualSpace
1623
+			}
1624
+		}
1609 1625
 	}
1610 1626
 
1611 1627
 	return status
... ...
@@ -72,8 +72,10 @@ func (d *Driver) Status() [][2]string {
72 72
 		{"Metadata file", s.MetadataFile},
73 73
 		{"Data Space Used", fmt.Sprintf("%s", units.HumanSize(float64(s.Data.Used)))},
74 74
 		{"Data Space Total", fmt.Sprintf("%s", units.HumanSize(float64(s.Data.Total)))},
75
+		{"Data Space Available", fmt.Sprintf("%s", units.HumanSize(float64(s.Data.Available)))},
75 76
 		{"Metadata Space Used", fmt.Sprintf("%s", units.HumanSize(float64(s.Metadata.Used)))},
76 77
 		{"Metadata Space Total", fmt.Sprintf("%s", units.HumanSize(float64(s.Metadata.Total)))},
78
+		{"Metadata Space Available", fmt.Sprintf("%s", units.HumanSize(float64(s.Metadata.Available)))},
77 79
 		{"Udev Sync Supported", fmt.Sprintf("%v", s.UdevSyncSupported)},
78 80
 	}
79 81
 	if len(s.DataLoopback) > 0 {