zoukankan      html  css  js  c++  java
  • 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
    ", 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
    ", 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)
    ", 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
    ", err)
    			return err
    		}
    	}
    
    	//通过thin device id删除设备
    	if err := deleteDevice(devices.getPoolDevName(), info.DeviceId); err != nil {
    		utils.Debugf("Error deleting device: %s
    ", 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
    ", 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
    ", 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
    }

  • 相关阅读:
    阿里云ECS安全组之新手不得不面对的问题
    【云栖风向标】VOL.3:阿里云:对不起_这个官司我不服!
    Linux全自动安装wdcp面板脚本
    “程序员”和“码农”究竟有什么区别?
    安卓新标准出台_告别乱弹窗_你的手机真会省电么?
    16年程序员平均工资122478元_你拖后腿了没?
    6.5世界环境日!来聊聊那些你想不到的环保黑科技?
    小扎曝Facebook北极数据中心图片_最先进数据中心都建在哪?
    js之单例模式
    js 之 call 、 apply
  • 原文地址:https://www.cnblogs.com/slgkaifa/p/7182260.html
Copyright © 2011-2022 走看看