This allows multiple instances of the backend in different containers
to access devices (although generally only one can modify/create them).
Any old metadata is converted on the first run.
Docker-DCO-1.1-Signed-off-by: Alexander Larsson <alexl@redhat.com> (github: alexlarsson)
| ... | ... |
@@ -106,7 +106,19 @@ func (devices *DeviceSet) loopbackDir() string {
|
| 106 | 106 |
return path.Join(devices.root, "devicemapper") |
| 107 | 107 |
} |
| 108 | 108 |
|
| 109 |
-func (devices *DeviceSet) jsonFile() string {
|
|
| 109 |
+func (devices *DeviceSet) metadataDir() string {
|
|
| 110 |
+ return path.Join(devices.root, "metadata") |
|
| 111 |
+} |
|
| 112 |
+ |
|
| 113 |
+func (devices *DeviceSet) metadataFile(info *DevInfo) string {
|
|
| 114 |
+ file := info.Hash |
|
| 115 |
+ if file == "" {
|
|
| 116 |
+ file = "base" |
|
| 117 |
+ } |
|
| 118 |
+ return path.Join(devices.metadataDir(), file) |
|
| 119 |
+} |
|
| 120 |
+ |
|
| 121 |
+func (devices *DeviceSet) oldMetadataFile() string {
|
|
| 110 | 122 |
return path.Join(devices.loopbackDir(), "json") |
| 111 | 123 |
} |
| 112 | 124 |
|
| ... | ... |
@@ -161,14 +173,19 @@ func (devices *DeviceSet) allocateTransactionId() uint64 {
|
| 161 | 161 |
return devices.NewTransactionId |
| 162 | 162 |
} |
| 163 | 163 |
|
| 164 |
-func (devices *DeviceSet) saveMetadata() error {
|
|
| 165 |
- devices.devicesLock.Lock() |
|
| 166 |
- jsonData, err := json.Marshal(devices.MetaData) |
|
| 167 |
- devices.devicesLock.Unlock() |
|
| 164 |
+func (devices *DeviceSet) removeMetadata(info *DevInfo) error {
|
|
| 165 |
+ if err := osRemoveAll(devices.metadataFile(info)); err != nil {
|
|
| 166 |
+ return fmt.Errorf("Error removing metadata file %s: %s", devices.metadataFile(info), err)
|
|
| 167 |
+ } |
|
| 168 |
+ return nil |
|
| 169 |
+} |
|
| 170 |
+ |
|
| 171 |
+func (devices *DeviceSet) saveMetadata(info *DevInfo) error {
|
|
| 172 |
+ jsonData, err := json.Marshal(info) |
|
| 168 | 173 |
if err != nil {
|
| 169 | 174 |
return fmt.Errorf("Error encoding metadata to json: %s", err)
|
| 170 | 175 |
} |
| 171 |
- tmpFile, err := ioutil.TempFile(filepath.Dir(devices.jsonFile()), ".json") |
|
| 176 |
+ tmpFile, err := ioutil.TempFile(devices.metadataDir(), ".tmp") |
|
| 172 | 177 |
if err != nil {
|
| 173 | 178 |
return fmt.Errorf("Error creating metadata file: %s", err)
|
| 174 | 179 |
} |
| ... | ... |
@@ -186,7 +203,7 @@ func (devices *DeviceSet) saveMetadata() error {
|
| 186 | 186 |
if err := tmpFile.Close(); err != nil {
|
| 187 | 187 |
return fmt.Errorf("Error closing metadata file %s: %s", tmpFile.Name(), err)
|
| 188 | 188 |
} |
| 189 |
- if err := osRename(tmpFile.Name(), devices.jsonFile()); err != nil {
|
|
| 189 |
+ if err := osRename(tmpFile.Name(), devices.metadataFile(info)); err != nil {
|
|
| 190 | 190 |
return fmt.Errorf("Error committing metadata file %s: %s", tmpFile.Name(), err)
|
| 191 | 191 |
} |
| 192 | 192 |
|
| ... | ... |
@@ -204,7 +221,12 @@ func (devices *DeviceSet) lookupDevice(hash string) (*DevInfo, error) {
|
| 204 | 204 |
defer devices.devicesLock.Unlock() |
| 205 | 205 |
info := devices.Devices[hash] |
| 206 | 206 |
if info == nil {
|
| 207 |
- return nil, fmt.Errorf("Unknown device %s", hash)
|
|
| 207 |
+ info = devices.loadMetadata(hash) |
|
| 208 |
+ if info == nil {
|
|
| 209 |
+ return nil, fmt.Errorf("Unknown device %s", hash)
|
|
| 210 |
+ } |
|
| 211 |
+ |
|
| 212 |
+ devices.Devices[hash] = info |
|
| 208 | 213 |
} |
| 209 | 214 |
return info, nil |
| 210 | 215 |
} |
| ... | ... |
@@ -224,7 +246,7 @@ func (devices *DeviceSet) registerDevice(id int, hash string, size uint64) (*Dev |
| 224 | 224 |
devices.Devices[hash] = info |
| 225 | 225 |
devices.devicesLock.Unlock() |
| 226 | 226 |
|
| 227 |
- if err := devices.saveMetadata(); err != nil {
|
|
| 227 |
+ if err := devices.saveMetadata(info); err != nil {
|
|
| 228 | 228 |
// Try to remove unused device |
| 229 | 229 |
devices.devicesLock.Lock() |
| 230 | 230 |
delete(devices.Devices, hash) |
| ... | ... |
@@ -259,9 +281,7 @@ func (devices *DeviceSet) createFilesystem(info *DevInfo) error {
|
| 259 | 259 |
return nil |
| 260 | 260 |
} |
| 261 | 261 |
|
| 262 |
-func (devices *DeviceSet) loadMetaData() error {
|
|
| 263 |
- utils.Debugf("loadMetadata()")
|
|
| 264 |
- defer utils.Debugf("loadMetadata END")
|
|
| 262 |
+func (devices *DeviceSet) initMetaData() error {
|
|
| 265 | 263 |
_, _, _, params, err := getStatus(devices.getPoolName()) |
| 266 | 264 |
if err != nil {
|
| 267 | 265 |
utils.Debugf("\n--->Err: %s\n", err)
|
| ... | ... |
@@ -274,35 +294,64 @@ func (devices *DeviceSet) loadMetaData() error {
|
| 274 | 274 |
} |
| 275 | 275 |
devices.NewTransactionId = devices.TransactionId |
| 276 | 276 |
|
| 277 |
- jsonData, err := ioutil.ReadFile(devices.jsonFile()) |
|
| 277 |
+ // Migrate old metadatafile |
|
| 278 |
+ |
|
| 279 |
+ jsonData, err := ioutil.ReadFile(devices.oldMetadataFile()) |
|
| 278 | 280 |
if err != nil && !osIsNotExist(err) {
|
| 279 | 281 |
utils.Debugf("\n--->Err: %s\n", err)
|
| 280 | 282 |
return err |
| 281 | 283 |
} |
| 282 | 284 |
|
| 283 |
- devices.MetaData.Devices = make(map[string]*DevInfo) |
|
| 284 | 285 |
if jsonData != nil {
|
| 285 |
- if err := json.Unmarshal(jsonData, &devices.MetaData); err != nil {
|
|
| 286 |
+ m := MetaData{Devices: make(map[string]*DevInfo)}
|
|
| 287 |
+ |
|
| 288 |
+ if err := json.Unmarshal(jsonData, &m); err != nil {
|
|
| 286 | 289 |
utils.Debugf("\n--->Err: %s\n", err)
|
| 287 | 290 |
return err |
| 288 | 291 |
} |
| 289 |
- } |
|
| 290 | 292 |
|
| 291 |
- for hash, d := range devices.Devices {
|
|
| 292 |
- d.Hash = hash |
|
| 293 |
- d.devices = devices |
|
| 293 |
+ for hash, info := range m.Devices {
|
|
| 294 |
+ info.Hash = hash |
|
| 294 | 295 |
|
| 295 |
- // If the transaction id is larger than the actual one we lost the device due to some crash |
|
| 296 |
- if d.TransactionId > devices.TransactionId {
|
|
| 297 |
- utils.Debugf("Removing lost device %s with id %d", hash, d.TransactionId)
|
|
| 298 |
- delete(devices.Devices, hash) |
|
| 296 |
+ // If the transaction id is larger than the actual one we lost the device due to some crash |
|
| 297 |
+ if info.TransactionId <= devices.TransactionId {
|
|
| 298 |
+ devices.saveMetadata(info) |
|
| 299 |
+ } |
|
| 300 |
+ } |
|
| 301 |
+ if err := osRename(devices.oldMetadataFile(), devices.oldMetadataFile()+".migrated"); err != nil {
|
|
| 302 |
+ return err |
|
| 299 | 303 |
} |
| 304 |
+ |
|
| 300 | 305 |
} |
| 306 |
+ |
|
| 301 | 307 |
return nil |
| 302 | 308 |
} |
| 303 | 309 |
|
| 310 |
+func (devices *DeviceSet) loadMetadata(hash string) *DevInfo {
|
|
| 311 |
+ info := &DevInfo{Hash: hash, devices: devices}
|
|
| 312 |
+ |
|
| 313 |
+ jsonData, err := ioutil.ReadFile(devices.metadataFile(info)) |
|
| 314 |
+ if err != nil {
|
|
| 315 |
+ return nil |
|
| 316 |
+ } |
|
| 317 |
+ |
|
| 318 |
+ if err := json.Unmarshal(jsonData, &info); err != nil {
|
|
| 319 |
+ return nil |
|
| 320 |
+ } |
|
| 321 |
+ |
|
| 322 |
+ fmt.Printf("Loaded metadata %v\n", info)
|
|
| 323 |
+ |
|
| 324 |
+ // If the transaction id is larger than the actual one we lost the device due to some crash |
|
| 325 |
+ if info.TransactionId > devices.TransactionId {
|
|
| 326 |
+ return nil |
|
| 327 |
+ } |
|
| 328 |
+ |
|
| 329 |
+ return info |
|
| 330 |
+} |
|
| 331 |
+ |
|
| 304 | 332 |
func (devices *DeviceSet) setupBaseImage() error {
|
| 305 | 333 |
oldInfo, _ := devices.lookupDevice("")
|
| 334 |
+ utils.Debugf("oldInfo: %p", oldInfo)
|
|
| 306 | 335 |
if oldInfo != nil && oldInfo.Initialized {
|
| 307 | 336 |
return nil |
| 308 | 337 |
} |
| ... | ... |
@@ -349,7 +398,7 @@ func (devices *DeviceSet) setupBaseImage() error {
|
| 349 | 349 |
} |
| 350 | 350 |
|
| 351 | 351 |
info.Initialized = true |
| 352 |
- if err = devices.saveMetadata(); err != nil {
|
|
| 352 |
+ if err = devices.saveMetadata(info); err != nil {
|
|
| 353 | 353 |
info.Initialized = false |
| 354 | 354 |
utils.Debugf("\n--->Err: %s\n", err)
|
| 355 | 355 |
return err |
| ... | ... |
@@ -457,29 +506,7 @@ func (devices *DeviceSet) ResizePool(size int64) error {
|
| 457 | 457 |
func (devices *DeviceSet) initDevmapper(doInit bool) error {
|
| 458 | 458 |
logInit(devices) |
| 459 | 459 |
|
| 460 |
- // Make sure the sparse images exist in <root>/devicemapper/data and |
|
| 461 |
- // <root>/devicemapper/metadata |
|
| 462 |
- |
|
| 463 |
- hasData := devices.hasImage("data")
|
|
| 464 |
- hasMetadata := devices.hasImage("metadata")
|
|
| 465 |
- |
|
| 466 |
- if !doInit && !hasData {
|
|
| 467 |
- return errors.New("Loopback data file not found")
|
|
| 468 |
- } |
|
| 469 |
- |
|
| 470 |
- if !doInit && !hasMetadata {
|
|
| 471 |
- return errors.New("Loopback metadata file not found")
|
|
| 472 |
- } |
|
| 473 |
- |
|
| 474 |
- createdLoopback := !hasData || !hasMetadata |
|
| 475 |
- data, err := devices.ensureImage("data", DefaultDataLoopbackSize)
|
|
| 476 |
- if err != nil {
|
|
| 477 |
- utils.Debugf("Error device ensureImage (data): %s\n", err)
|
|
| 478 |
- return err |
|
| 479 |
- } |
|
| 480 |
- metadata, err := devices.ensureImage("metadata", DefaultMetaDataLoopbackSize)
|
|
| 481 |
- if err != nil {
|
|
| 482 |
- utils.Debugf("Error device ensureImage (metadata): %s\n", err)
|
|
| 460 |
+ if err := osMkdirAll(devices.metadataDir(), 0700); err != nil && !osIsExist(err) {
|
|
| 483 | 461 |
return err |
| 484 | 462 |
} |
| 485 | 463 |
|
| ... | ... |
@@ -512,10 +539,38 @@ func (devices *DeviceSet) initDevmapper(doInit bool) error {
|
| 512 | 512 |
// so we add this badhack to make sure it closes itself |
| 513 | 513 |
setCloseOnExec("/dev/mapper/control")
|
| 514 | 514 |
|
| 515 |
+ // Make sure the sparse images exist in <root>/devicemapper/data and |
|
| 516 |
+ // <root>/devicemapper/metadata |
|
| 517 |
+ |
|
| 518 |
+ createdLoopback := false |
|
| 519 |
+ |
|
| 515 | 520 |
// If the pool doesn't exist, create it |
| 516 | 521 |
if info.Exists == 0 {
|
| 517 | 522 |
utils.Debugf("Pool doesn't exist. Creating it.")
|
| 518 | 523 |
|
| 524 |
+ hasData := devices.hasImage("data")
|
|
| 525 |
+ hasMetadata := devices.hasImage("metadata")
|
|
| 526 |
+ |
|
| 527 |
+ if !doInit && !hasData {
|
|
| 528 |
+ return errors.New("Loopback data file not found")
|
|
| 529 |
+ } |
|
| 530 |
+ |
|
| 531 |
+ if !doInit && !hasMetadata {
|
|
| 532 |
+ return errors.New("Loopback metadata file not found")
|
|
| 533 |
+ } |
|
| 534 |
+ |
|
| 535 |
+ createdLoopback = !hasData || !hasMetadata |
|
| 536 |
+ data, err := devices.ensureImage("data", DefaultDataLoopbackSize)
|
|
| 537 |
+ if err != nil {
|
|
| 538 |
+ utils.Debugf("Error device ensureImage (data): %s\n", err)
|
|
| 539 |
+ return err |
|
| 540 |
+ } |
|
| 541 |
+ metadata, err := devices.ensureImage("metadata", DefaultMetaDataLoopbackSize)
|
|
| 542 |
+ if err != nil {
|
|
| 543 |
+ utils.Debugf("Error device ensureImage (metadata): %s\n", err)
|
|
| 544 |
+ return err |
|
| 545 |
+ } |
|
| 546 |
+ |
|
| 519 | 547 |
dataFile, err := attachLoopDevice(data) |
| 520 | 548 |
if err != nil {
|
| 521 | 549 |
utils.Debugf("\n--->Err: %s\n", err)
|
| ... | ... |
@@ -537,9 +592,9 @@ func (devices *DeviceSet) initDevmapper(doInit bool) error {
|
| 537 | 537 |
} |
| 538 | 538 |
|
| 539 | 539 |
// If we didn't just create the data or metadata image, we need to |
| 540 |
- // load the metadata from the existing file. |
|
| 540 |
+ // load the transaction id and migrate old metadata |
|
| 541 | 541 |
if !createdLoopback {
|
| 542 |
- if err = devices.loadMetaData(); err != nil {
|
|
| 542 |
+ if err = devices.initMetaData(); err != nil {
|
|
| 543 | 543 |
utils.Debugf("\n--->Err: %s\n", err)
|
| 544 | 544 |
return err |
| 545 | 545 |
} |
| ... | ... |
@@ -608,14 +663,6 @@ func (devices *DeviceSet) deleteDevice(info *DevInfo) error {
|
| 608 | 608 |
} |
| 609 | 609 |
} |
| 610 | 610 |
|
| 611 |
- if info.Initialized {
|
|
| 612 |
- info.Initialized = false |
|
| 613 |
- if err := devices.saveMetadata(); err != nil {
|
|
| 614 |
- utils.Debugf("Error saving meta data: %s\n", err)
|
|
| 615 |
- return err |
|
| 616 |
- } |
|
| 617 |
- } |
|
| 618 |
- |
|
| 619 | 611 |
if err := deleteDevice(devices.getPoolDevName(), info.DeviceId); err != nil {
|
| 620 | 612 |
utils.Debugf("Error deleting device: %s\n", err)
|
| 621 | 613 |
return err |
| ... | ... |
@@ -626,11 +673,11 @@ func (devices *DeviceSet) deleteDevice(info *DevInfo) error {
|
| 626 | 626 |
delete(devices.Devices, info.Hash) |
| 627 | 627 |
devices.devicesLock.Unlock() |
| 628 | 628 |
|
| 629 |
- if err := devices.saveMetadata(); err != nil {
|
|
| 629 |
+ if err := devices.removeMetadata(info); err != nil {
|
|
| 630 | 630 |
devices.devicesLock.Lock() |
| 631 | 631 |
devices.Devices[info.Hash] = info |
| 632 | 632 |
devices.devicesLock.Unlock() |
| 633 |
- utils.Debugf("Error saving meta data: %s\n", err)
|
|
| 633 |
+ utils.Debugf("Error removing meta data: %s\n", err)
|
|
| 634 | 634 |
return err |
| 635 | 635 |
} |
| 636 | 636 |
|
| ... | ... |
@@ -873,7 +920,7 @@ func (devices *DeviceSet) MountDevice(hash, path string, mountLabel string) erro |
| 873 | 873 |
info.mountCount = 1 |
| 874 | 874 |
info.mountPath = path |
| 875 | 875 |
|
| 876 |
- return devices.setInitialized(info) |
|
| 876 |
+ return nil |
|
| 877 | 877 |
} |
| 878 | 878 |
|
| 879 | 879 |
func (devices *DeviceSet) UnmountDevice(hash string) error {
|
| ... | ... |
@@ -924,14 +971,6 @@ func (devices *DeviceSet) HasDevice(hash string) bool {
|
| 924 | 924 |
return info != nil |
| 925 | 925 |
} |
| 926 | 926 |
|
| 927 |
-func (devices *DeviceSet) HasInitializedDevice(hash string) bool {
|
|
| 928 |
- devices.Lock() |
|
| 929 |
- defer devices.Unlock() |
|
| 930 |
- |
|
| 931 |
- info, _ := devices.lookupDevice(hash) |
|
| 932 |
- return info != nil && info.Initialized |
|
| 933 |
-} |
|
| 934 |
- |
|
| 935 | 927 |
func (devices *DeviceSet) HasActivatedDevice(hash string) bool {
|
| 936 | 928 |
info, _ := devices.lookupDevice(hash) |
| 937 | 929 |
if info == nil {
|
| ... | ... |
@@ -948,17 +987,6 @@ func (devices *DeviceSet) HasActivatedDevice(hash string) bool {
|
| 948 | 948 |
return devinfo != nil && devinfo.Exists != 0 |
| 949 | 949 |
} |
| 950 | 950 |
|
| 951 |
-func (devices *DeviceSet) setInitialized(info *DevInfo) error {
|
|
| 952 |
- info.Initialized = true |
|
| 953 |
- if err := devices.saveMetadata(); err != nil {
|
|
| 954 |
- info.Initialized = false |
|
| 955 |
- utils.Debugf("\n--->Err: %s\n", err)
|
|
| 956 |
- return err |
|
| 957 |
- } |
|
| 958 |
- |
|
| 959 |
- return nil |
|
| 960 |
-} |
|
| 961 |
- |
|
| 962 | 951 |
func (devices *DeviceSet) List() []string {
|
| 963 | 952 |
devices.Lock() |
| 964 | 953 |
defer devices.Unlock() |
| ... | ... |
@@ -820,10 +820,6 @@ func TestGetReturnsValidDevice(t *testing.T) {
|
| 820 | 820 |
if !d.HasActivatedDevice("1") {
|
| 821 | 821 |
t.Fatalf("Expected id 1 to be activated")
|
| 822 | 822 |
} |
| 823 |
- |
|
| 824 |
- if !d.HasInitializedDevice("1") {
|
|
| 825 |
- t.Fatalf("Expected id 1 to be initialized")
|
|
| 826 |
- } |
|
| 827 | 823 |
} |
| 828 | 824 |
|
| 829 | 825 |
func TestDriverGetSize(t *testing.T) {
|