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
}

目录
相关文章
|
5月前
|
关系型数据库 MySQL Linux
Qt连接Mysql出现问题(一):“Driver not loaded Driver not loaded“
第一眼看见这张图我也觉得很奇怪,显示有QMYSQL但是又说没有,这不自相矛盾吗!
834 4
arcgis catalog 连接sde时出现 Target state not found in the STATES table 错误
Target state not found in the STATES table [SDE.DEFAULT][STATE_ID = 8802] 除了arcgis论坛说的这种情况 http://support.esri.com/technical-article/000005952 我自己分析是stateid不在status 表中了 我根据正常的sde库分析了一下,ver
2089 0
|
关系型数据库 MySQL
Loading class `com.mysql.jdbc.Driver‘. This is deprecated. The new driver class
Loading class `com.mysql.jdbc.Driver‘. This is deprecated. The new driver class
362 0
|
关系型数据库 MySQL Java
9. 成功解决:Driver class 'org.gjt.mm.mysql.Driver' could not be found
在使用 Kettle(Spoon) 工具创建 MySQL 数据库连接时,提示:Driver class 'org.gjt.mm.mysql.Driver' could not be found, make sure the 'MySQL' driver (jar file) is installed. org.gjt.mm.mysql.Driver
2492 0
|
关系型数据库 MySQL 数据库
快速解决:Loading class `com.mysql.jdbc.Driver‘. This is deprecated. The new driver class is `com.mysql.c
我们当前使用的数据库版本在6.0以上,原来的驱动(com.mysql.jdbc.Driver)已经被废弃了,要进行更换驱动就好了
33446 1
快速解决:Loading class `com.mysql.jdbc.Driver‘. This is deprecated. The new driver class is `com.mysql.c
|
内存技术
嵌入式 VFS: Cannot open root device "mtdblock2" or unknown-block(2,0)
系统启动后,虽然nand驱动表现正常,但是最后挂载rootfs时候出错: Kernel command line: root=/dev/mtdblock2 rw init=/linuxrc console=ttyAMA1,115200 mem=64M rootfstype=yaffs2。
2277 0
|
关系型数据库 MySQL Java
JDBC 连接 MySQL 报错 Unknown system variable ‘query_cache_size‘
JDBC 连接 MySQL 报错 Unknown system variable ‘query_cache_size‘
2413 0
JDBC 连接 MySQL 报错 Unknown system variable ‘query_cache_size‘
|
并行计算 PyTorch Go
成功解决The NVIDIA driver on your system is too old (found version 8000).Please update your GPU driver
成功解决The NVIDIA driver on your system is too old (found version 8000).Please update your GPU driver
|
SQL 分布式计算 关系型数据库
【报错解决】The specified datastore driver (“com.mysql.jdbc.Driver “) was not found in the CLASSPATH. Plea
【报错解决】The specified datastore driver (“com.mysql.jdbc.Driver “) was not found in the CLASSPATH. Plea
623 0
|
关系型数据库 Java 数据库
Cannot load driver class: com.mysql.jdbc.Driver
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px 'Helvetica Neue'; color: #454545} Cannot load driver class: com.mysql.jdbc.Driver 看到类似的错误应该想到缺少Jar包引用。
1982 0