Переглянути джерело

devmapper: Add lock to protext Devices map

Currently access to the Devices map is serialized by the main
DeviceSet lock, but we need to access it outside that lock, so we
add a separate lock for this and grab that everywhere we modify
or read the map.

Docker-DCO-1.1-Signed-off-by: Alexander Larsson <alexl@redhat.com> (github: alexlarsson)
Alexander Larsson 11 роки тому
батько
коміт
70826e8b3f
1 змінених файлів з 26 додано та 1 видалено
  1. 26 1
      runtime/graphdriver/devmapper/deviceset.go

+ 26 - 1
runtime/graphdriver/devmapper/deviceset.go

@@ -51,7 +51,8 @@ type DevInfo struct {
 }
 }
 
 
 type MetaData struct {
 type MetaData struct {
-	Devices map[string]*DevInfo `json:devices`
+	Devices     map[string]*DevInfo `json:devices`
+	devicesLock sync.Mutex          `json:"-"` // Protects all read/writes to Devices map
 }
 }
 
 
 type DeviceSet struct {
 type DeviceSet struct {
@@ -179,7 +180,9 @@ func (devices *DeviceSet) allocateTransactionId() uint64 {
 }
 }
 
 
 func (devices *DeviceSet) saveMetadata() error {
 func (devices *DeviceSet) saveMetadata() error {
+	devices.devicesLock.Lock()
 	jsonData, err := json.Marshal(devices.MetaData)
 	jsonData, err := json.Marshal(devices.MetaData)
+	devices.devicesLock.Unlock()
 	if err != nil {
 	if err != nil {
 		return fmt.Errorf("Error encoding metadata to json: %s", err)
 		return fmt.Errorf("Error encoding metadata to json: %s", err)
 	}
 	}
@@ -215,6 +218,8 @@ func (devices *DeviceSet) saveMetadata() error {
 }
 }
 
 
 func (devices *DeviceSet) lookupDevice(hash string) (*DevInfo, error) {
 func (devices *DeviceSet) lookupDevice(hash string) (*DevInfo, error) {
+	devices.devicesLock.Lock()
+	defer devices.devicesLock.Unlock()
 	info := devices.Devices[hash]
 	info := devices.Devices[hash]
 	if info == nil {
 	if info == nil {
 		return nil, fmt.Errorf("Unknown device %s", hash)
 		return nil, fmt.Errorf("Unknown device %s", hash)
@@ -233,10 +238,15 @@ func (devices *DeviceSet) registerDevice(id int, hash string, size uint64) (*Dev
 		devices:       devices,
 		devices:       devices,
 	}
 	}
 
 
+	devices.devicesLock.Lock()
 	devices.Devices[hash] = info
 	devices.Devices[hash] = info
+	devices.devicesLock.Unlock()
+
 	if err := devices.saveMetadata(); err != nil {
 	if err := devices.saveMetadata(); err != nil {
 		// Try to remove unused device
 		// Try to remove unused device
+		devices.devicesLock.Lock()
 		delete(devices.Devices, hash)
 		delete(devices.Devices, hash)
+		devices.devicesLock.Unlock()
 		return nil, err
 		return nil, err
 	}
 	}
 
 
@@ -632,10 +642,14 @@ func (devices *DeviceSet) deleteDevice(info *DevInfo) error {
 	}
 	}
 
 
 	devices.allocateTransactionId()
 	devices.allocateTransactionId()
+	devices.devicesLock.Lock()
 	delete(devices.Devices, info.Hash)
 	delete(devices.Devices, info.Hash)
+	devices.devicesLock.Unlock()
 
 
 	if err := devices.saveMetadata(); err != nil {
 	if err := devices.saveMetadata(); err != nil {
+		devices.devicesLock.Lock()
 		devices.Devices[info.Hash] = info
 		devices.Devices[info.Hash] = info
+		devices.devicesLock.Unlock()
 		utils.Debugf("Error saving meta data: %s\n", err)
 		utils.Debugf("Error saving meta data: %s\n", err)
 		return err
 		return err
 	}
 	}
@@ -795,7 +809,15 @@ func (devices *DeviceSet) Shutdown() error {
 	utils.Debugf("[devmapper] Shutting down DeviceSet: %s", devices.root)
 	utils.Debugf("[devmapper] Shutting down DeviceSet: %s", devices.root)
 	defer utils.Debugf("[deviceset %s] shutdown END", devices.devicePrefix)
 	defer utils.Debugf("[deviceset %s] shutdown END", devices.devicePrefix)
 
 
+	var devs []*DevInfo
+
+	devices.devicesLock.Lock()
 	for _, info := range devices.Devices {
 	for _, info := range devices.Devices {
+		devs = append(devs, info)
+	}
+	devices.devicesLock.Unlock()
+
+	for _, info := range devs {
 		info.lock.Lock()
 		info.lock.Lock()
 		if info.mountCount > 0 {
 		if info.mountCount > 0 {
 			// We use MNT_DETACH here in case it is still busy in some running
 			// We use MNT_DETACH here in case it is still busy in some running
@@ -979,12 +1001,15 @@ func (devices *DeviceSet) List() []string {
 	devices.Lock()
 	devices.Lock()
 	defer devices.Unlock()
 	defer devices.Unlock()
 
 
+	devices.devicesLock.Lock()
 	ids := make([]string, len(devices.Devices))
 	ids := make([]string, len(devices.Devices))
 	i := 0
 	i := 0
 	for k := range devices.Devices {
 	for k := range devices.Devices {
 		ids[i] = k
 		ids[i] = k
 		i++
 		i++
 	}
 	}
+	devices.devicesLock.Unlock()
+
 	return ids
 	return ids
 }
 }