graph driver-device mapper-03thin pool基本操作
// 在thin pool中創建一個新thin device
// 調用路徑:driver.Create()
1.1 func (devices *DeviceSet) AddDevice(hash, baseHash string) error {
//查找父device
baseInfo, err := devices.lookupDevice(baseHash)
if err != nil {
return err
}
baseInfo.lock.Lock()
defer baseInfo.lock.Unlock()
devices.Lock()
defer devices.Unlock()
//檢查imageid/containerid對應的image是否存在
if info, _ := devices.lookupDevice(hash); info != nil {
return fmt.Errorf("device %s already exists", hash)
}
deviceId := devices.nextDeviceId
//創建父設備的鏡像
if err := createSnapDevice(devices.getPoolDevName(), &deviceId, baseInfo.Name(), baseInfo.DeviceId); err != nil {
utils.Debugf("Error creating snap device: %s\n", err)
return err
}
//創建thin device的DevInfo,並保存信息到/var/lib/docker/devicemapper/metadata/$id文件中
if _, err := devices.registerDevice(deviceId, hash, baseInfo.Size); err != nil {
deleteDevice(devices.getPoolDevName(), deviceId)
utils.Debugf("Error registering device: %s\n", err)
return err
}
return nil
}
// 創建鏡像文件的快照
// libdevmapper通過發送msg發送命令
// 調用路徑:AddDevice->createSnapDevice
1.2 func createSnapDevice(poolName string, deviceId *int, baseName string, baseDeviceId int) error {
devinfo, _ := getInfo(baseName)
doSuspend := devinfo != nil && devinfo.Exists != 0
//設備存在,則在快照前要先掛起父設備
if doSuspend {
if err := suspendDevice(baseName); err != nil {
return err
}
}
for {
//創建task,libdevmapper通過msg傳遞命令
task, err := createTask(DeviceTargetMsg, poolName)
if task == nil {
//創建task失敗,恢複父device
if doSuspend {
resumeDevice(baseName)
}
return err
}
if err := task.SetSector(0); err != nil {
if doSuspend {
resumeDevice(baseName)
}
return fmt.Errorf("Can't set sector %s", err)
}
//發送創建命令
if err := task.SetMessage(fmt.Sprintf("create_snap %d %d", *deviceId, baseDeviceId)); err != nil {
if doSuspend {
resumeDevice(baseName)
}
return fmt.Errorf("Can't set message %s", err)
}
dmSawExist = false
if err := task.Run(); err != nil {
//deviceid已存在,繼續嚐試下一個id
if dmSawExist {
*deviceId++
continue
}
if doSuspend {
resumeDevice(baseName)
}
return fmt.Errorf("Error running DeviceCreate (createSnapDevice) %s", err)
}
break
}
//創建成功,恢複父設備
if doSuspend {
if err := resumeDevice(baseName); err != nil {
return err
}
}
return nil
}
// 注冊thin device信息
// 添加devinfo到devices.Devices哈希表,並保存devinfo到/var/lib/docker/devicemapper/metadata/$id文件
// 調用路徑:AddDevice->registerDevice
1.3 func (devices *DeviceSet) registerDevice(id int, hash string, size uint64) (*DevInfo, error) {
info := &DevInfo{
Hash: hash,
DeviceId: id,
Size: size,
//分配一個新的transactionid
TransactionId: devices.allocateTransactionId(),
Initialized: false,
devices: devices,
}
devices.devicesLock.Lock()
//添加devinfo到hash表
devices.Devices[hash] = info
devices.devicesLock.Unlock()
//保存devinfo到/var/lib/docker/devicemapper/metadata/$id文件
if err := devices.saveMetadata(info); err != nil {
devices.devicesLock.Lock()
delete(devices.Devices, hash)
devices.devicesLock.Unlock()
return nil, err
}
return info, nil
}
// 刪除設備
// 調用路徑:driver.Remove()
2.1 func (devices *DeviceSet) DeleteDevice(hash string) error {
//檢查設備是否存在
info, err := devices.lookupDevice(hash)
if err != nil {
return err
}
info.lock.Lock()
defer info.lock.Unlock()
devices.Lock()
defer devices.Unlock()
//傳遞devinfo,刪除設備
return devices.deleteDevice(info)
// 刪除設備
// 1.discard thin device的block
// 2.傳遞device name刪除設備名
// 3.傳遞device id刪除設備
// 4.刪除/var/lib/docker/devicemapper/metadata/$id文件
// 調用路徑:DeleteDevice->deleteDevice
2.2 func (devices *DeviceSet) deleteDevice(info *DevInfo) error {
//刪除設備時,discard其占用的block
if devices.doBlkDiscard {
//激活thin device設備
if err := devices.activateDeviceIfNeeded(info); err == nil {
//discard設備占用的block
if err := BlockDeviceDiscard(info.DevName()); err != nil {
utils.Debugf("Error discarding block on device: %s (ignoring)\n", err)
}
}
}
devinfo, _ := getInfo(info.Name())
if devinfo != nil && devinfo.Exists != 0 {
//傳遞thin device名(docker-$major:$minor-$inode-$id)給libdevmapper,刪除設備名
if err := devices.removeDeviceAndWait(info.Name()); err != nil {
utils.Debugf("Error removing device: %s\n", err)
return err
}
}
//通過thin device id刪除設備
if err := deleteDevice(devices.getPoolDevName(), info.DeviceId); err != nil {
utils.Debugf("Error deleting device: %s\n", err)
return err
}
devices.allocateTransactionId()
devices.devicesLock.Lock()
//從內存中刪除devinfo
delete(devices.Devices, info.Hash)
devices.devicesLock.Unlock()
//刪除/var/lib/docker/devicemapper/metadata/$id文件
if err := devices.removeMetadata(info); err != nil {
devices.devicesLock.Lock()
devices.Devices[info.Hash] = info
devices.devicesLock.Unlock()
utils.Debugf("Error removing meta data: %s\n", err)
return err
}
return nil
}
// 掛載設備到指定路徑
// hash指定要掛載的thin device id
// path指定要掛載到的路徑
// 一個thin device可以被多次掛載到同一個路徑
// 調用路徑:driver.Get()
3.1 func (devices *DeviceSet) MountDevice(hash, path, mountLabel string) error {
info, err := devices.lookupDevice(hash)
if err != nil {
return err
}
info.lock.Lock()
defer info.lock.Unlock()
devices.Lock()
defer devices.Unlock()
//thin device不允許被掛載到多個不同路徑
if info.mountCount > 0 {
if path != info.mountPath {
return fmt.Errorf("Trying to mount devmapper device in multple places (%s, %s)", info.mountPath, path)
}
info.mountCount++
return nil
}
//激活設備
if err := devices.activateDeviceIfNeeded(info); err != nil {
return fmt.Errorf("Error activating devmapper device for '%s': %s", hash, err)
}
var flags uintptr = syscall.MS_MGC_VAL
//獲取thin device上文件係統的類型
//info.DevName()傳遞
fstype, err := ProbeFsType(info.DevName())
if err != nil {
return err
}
options := ""
//通過--storage-option 傳遞的mount選項
options = joinMountOptions(options, devices.mountOptions)
options = joinMountOptions(options, label.FormatMountLabel("", mountLabel))
//mount thin device到指定path
err = syscall.Mount(info.DevName(), path, fstype, flags, joinMountOptions("discard", options))
if err != nil && err == syscall.EINVAL {
err = syscall.Mount(info.DevName(), path, fstype, flags, options)
}
if err != nil {
return fmt.Errorf("Error mounting '%s' on '%s': %s", info.DevName(), path, err)
}
info.mountCount = 1
info.mountPath = path
return nil
}
// 解掛thin device
// hash為imageid或containerid
// 直到掛載計數=0時才真正解掛
// 調用路徑:driver.Put()
4.1 func (devices *DeviceSet) UnmountDevice(hash string) error {
//查找devinfo
info, err := devices.lookupDevice(hash)
if err != nil {
return err
}
info.lock.Lock()
defer info.lock.Unlock()
devices.Lock()
defer devices.Unlock()
//掛載了不止一次,成功返回
info.mountCount--
if info.mountCount > 0 {
return nil
}
//從指定路徑解掛
if err := syscall.Unmount(info.mountPath, 0); err != nil {
return err
}
//停止設備
if err := devices.deactivateDevice(info); err != nil {
return err
}
info.mountPath = ""
return nil
}
// 停止thin device
// 等待thin device從/var/lib/docker/devicemapper/mnt/$id解掛,刪除thin device名
// 調用路徑:UnmountDevice->deactivateDevice
4.2 func (devices *DeviceSet) deactivateDevice(info *DevInfo) error {
//等待thin device解掛,通過device id獲取設備信息,打開計數降到0
if err := devices.waitClose(info); err != nil {
utils.Errorf("Warning: error waiting for device %s to close: %s\n", info.Hash, err)
}
devinfo, err := getInfo(info.Name())
if err != nil {
return err
}
if devinfo.Exists != 0 {
//刪除設備名
if err := devices.removeDeviceAndWait(info.Name()); err != nil {
return err
}
}
return nil
}
最後更新:2017-04-03 05:39:30