devmapper.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  1. package devmapper
  2. import (
  3. "errors"
  4. "fmt"
  5. "github.com/dotcloud/docker/utils"
  6. "runtime"
  7. )
  8. type DevmapperLogger interface {
  9. log(level int, file string, line int, dmError int, message string)
  10. }
  11. const (
  12. DeviceCreate TaskType = iota
  13. DeviceReload
  14. DeviceRemove
  15. DeviceRemoveAll
  16. DeviceSuspend
  17. DeviceResume
  18. DeviceInfo
  19. DeviceDeps
  20. DeviceRename
  21. DeviceVersion
  22. DeviceStatus
  23. DeviceTable
  24. DeviceWaitevent
  25. DeviceList
  26. DeviceClear
  27. DeviceMknodes
  28. DeviceListVersions
  29. DeviceTargetMsg
  30. DeviceSetGeometry
  31. )
  32. const (
  33. AddNodeOnResume AddNodeType = iota
  34. AddNodeOnCreate
  35. )
  36. var (
  37. ErrTaskRun = errors.New("dm_task_run failed")
  38. ErrTaskSetName = errors.New("dm_task_set_name failed")
  39. ErrTaskSetMessage = errors.New("dm_task_set_message failed")
  40. ErrTaskSetAddNode = errors.New("dm_task_set_add_node failed")
  41. ErrTaskSetRo = errors.New("dm_task_set_ro failed")
  42. ErrTaskAddTarget = errors.New("dm_task_add_target failed")
  43. ErrTaskSetSector = errors.New("dm_task_set_sector failed")
  44. ErrTaskGetInfo = errors.New("dm_task_get_info failed")
  45. ErrTaskSetCookie = errors.New("dm_task_set_cookie failed")
  46. ErrNilCookie = errors.New("cookie ptr can't be nil")
  47. ErrAttachLoopbackDevice = errors.New("loopback mounting failed")
  48. ErrGetBlockSize = errors.New("Can't get block size")
  49. ErrUdevWait = errors.New("wait on udev cookie failed")
  50. ErrSetDevDir = errors.New("dm_set_dev_dir failed")
  51. ErrGetLibraryVersion = errors.New("dm_get_library_version failed")
  52. ErrCreateRemoveTask = errors.New("Can't create task of type DeviceRemove")
  53. ErrRunRemoveDevice = errors.New("running removeDevice failed")
  54. ErrInvalidAddNode = errors.New("Invalide AddNoce type")
  55. ErrGetLoopbackBackingFile = errors.New("Unable to get loopback backing file")
  56. ErrLoopbackSetCapacity = errors.New("Unable set loopback capacity")
  57. )
  58. type (
  59. Task struct {
  60. unmanaged *CDmTask
  61. }
  62. Info struct {
  63. Exists int
  64. Suspended int
  65. LiveTable int
  66. InactiveTable int
  67. OpenCount int32
  68. EventNr uint32
  69. Major uint32
  70. Minor uint32
  71. ReadOnly int
  72. TargetCount int32
  73. }
  74. TaskType int
  75. AddNodeType int
  76. )
  77. func (t *Task) destroy() {
  78. if t != nil {
  79. DmTaskDestroy(t.unmanaged)
  80. runtime.SetFinalizer(t, nil)
  81. }
  82. }
  83. func TaskCreate(tasktype TaskType) *Task {
  84. Ctask := DmTaskCreate(int(tasktype))
  85. if Ctask == nil {
  86. return nil
  87. }
  88. task := &Task{unmanaged: Ctask}
  89. runtime.SetFinalizer(task, (*Task).destroy)
  90. return task
  91. }
  92. func (t *Task) Run() error {
  93. if res := DmTaskRun(t.unmanaged); res != 1 {
  94. return ErrTaskRun
  95. }
  96. return nil
  97. }
  98. func (t *Task) SetName(name string) error {
  99. if res := DmTaskSetName(t.unmanaged, name); res != 1 {
  100. return ErrTaskSetName
  101. }
  102. return nil
  103. }
  104. func (t *Task) SetMessage(message string) error {
  105. if res := DmTaskSetMessage(t.unmanaged, message); res != 1 {
  106. return ErrTaskSetMessage
  107. }
  108. return nil
  109. }
  110. func (t *Task) SetSector(sector uint64) error {
  111. if res := DmTaskSetSector(t.unmanaged, sector); res != 1 {
  112. return ErrTaskSetSector
  113. }
  114. return nil
  115. }
  116. func (t *Task) SetCookie(cookie *uint, flags uint16) error {
  117. if cookie == nil {
  118. return ErrNilCookie
  119. }
  120. if res := DmTaskSetCookie(t.unmanaged, cookie, flags); res != 1 {
  121. return ErrTaskSetCookie
  122. }
  123. return nil
  124. }
  125. func (t *Task) SetAddNode(addNode AddNodeType) error {
  126. if addNode != AddNodeOnResume && addNode != AddNodeOnCreate {
  127. return ErrInvalidAddNode
  128. }
  129. if res := DmTaskSetAddNode(t.unmanaged, addNode); res != 1 {
  130. return ErrTaskSetAddNode
  131. }
  132. return nil
  133. }
  134. func (t *Task) SetRo() error {
  135. if res := DmTaskSetRo(t.unmanaged); res != 1 {
  136. return ErrTaskSetRo
  137. }
  138. return nil
  139. }
  140. func (t *Task) AddTarget(start, size uint64, ttype, params string) error {
  141. if res := DmTaskAddTarget(t.unmanaged, start, size,
  142. ttype, params); res != 1 {
  143. return ErrTaskAddTarget
  144. }
  145. return nil
  146. }
  147. func (t *Task) GetInfo() (*Info, error) {
  148. info := &Info{}
  149. if res := DmTaskGetInfo(t.unmanaged, info); res != 1 {
  150. return nil, ErrTaskGetInfo
  151. }
  152. return info, nil
  153. }
  154. func (t *Task) GetNextTarget(next uintptr) (nextPtr uintptr, start uint64,
  155. length uint64, targetType string, params string) {
  156. return DmGetNextTarget(t.unmanaged, next, &start, &length,
  157. &targetType, &params),
  158. start, length, targetType, params
  159. }
  160. func getLoopbackBackingFile(file *osFile) (uint64, uint64, error) {
  161. loopInfo, err := ioctlLoopGetStatus64(file.Fd())
  162. if err != nil {
  163. utils.Errorf("Error get loopback backing file: %s\n", err)
  164. return 0, 0, ErrGetLoopbackBackingFile
  165. }
  166. return loopInfo.loDevice, loopInfo.loInode, nil
  167. }
  168. func LoopbackSetCapacity(file *osFile) error {
  169. if err := ioctlLoopSetCapacity(file.Fd(), 0); err != nil {
  170. utils.Errorf("Error loopbackSetCapacity: %s", err)
  171. return ErrLoopbackSetCapacity
  172. }
  173. return nil
  174. }
  175. func FindLoopDeviceFor(file *osFile) *osFile {
  176. stat, err := file.Stat()
  177. if err != nil {
  178. return nil
  179. }
  180. targetInode := stat.Sys().(*sysStatT).Ino
  181. targetDevice := stat.Sys().(*sysStatT).Dev
  182. for i := 0; true; i++ {
  183. path := fmt.Sprintf("/dev/loop%d", i)
  184. file, err := osOpenFile(path, osORdWr, 0)
  185. if err != nil {
  186. if osIsNotExist(err) {
  187. return nil
  188. }
  189. // Ignore all errors until the first not-exist
  190. // we want to continue looking for the file
  191. continue
  192. }
  193. dev, inode, err := getLoopbackBackingFile(file)
  194. if err == nil && dev == targetDevice && inode == targetInode {
  195. return file
  196. }
  197. file.Close()
  198. }
  199. return nil
  200. }
  201. func UdevWait(cookie uint) error {
  202. if res := DmUdevWait(cookie); res != 1 {
  203. utils.Debugf("Failed to wait on udev cookie %d", cookie)
  204. return ErrUdevWait
  205. }
  206. return nil
  207. }
  208. func LogInitVerbose(level int) {
  209. DmLogInitVerbose(level)
  210. }
  211. var dmLogger DevmapperLogger = nil
  212. func logInit(logger DevmapperLogger) {
  213. dmLogger = logger
  214. LogWithErrnoInit()
  215. }
  216. func SetDevDir(dir string) error {
  217. if res := DmSetDevDir(dir); res != 1 {
  218. utils.Debugf("Error dm_set_dev_dir")
  219. return ErrSetDevDir
  220. }
  221. return nil
  222. }
  223. func GetLibraryVersion() (string, error) {
  224. var version string
  225. if res := DmGetLibraryVersion(&version); res != 1 {
  226. return "", ErrGetLibraryVersion
  227. }
  228. return version, nil
  229. }
  230. // Useful helper for cleanup
  231. func RemoveDevice(name string) error {
  232. task := TaskCreate(DeviceRemove)
  233. if task == nil {
  234. return ErrCreateRemoveTask
  235. }
  236. if err := task.SetName(name); err != nil {
  237. utils.Debugf("Can't set task name %s", name)
  238. return err
  239. }
  240. if err := task.Run(); err != nil {
  241. return ErrRunRemoveDevice
  242. }
  243. return nil
  244. }
  245. func GetBlockDeviceSize(file *osFile) (uint64, error) {
  246. size, err := ioctlBlkGetSize64(file.Fd())
  247. if err != nil {
  248. utils.Errorf("Error getblockdevicesize: %s", err)
  249. return 0, ErrGetBlockSize
  250. }
  251. return uint64(size), nil
  252. }
  253. // This is the programmatic example of "dmsetup create"
  254. func createPool(poolName string, dataFile, metadataFile *osFile) error {
  255. task, err := createTask(DeviceCreate, poolName)
  256. if task == nil {
  257. return err
  258. }
  259. size, err := GetBlockDeviceSize(dataFile)
  260. if err != nil {
  261. return fmt.Errorf("Can't get data size")
  262. }
  263. params := metadataFile.Name() + " " + dataFile.Name() + " 128 32768"
  264. if err := task.AddTarget(0, size/512, "thin-pool", params); err != nil {
  265. return fmt.Errorf("Can't add target")
  266. }
  267. var cookie uint = 0
  268. if err := task.SetCookie(&cookie, 0); err != nil {
  269. return fmt.Errorf("Can't set cookie")
  270. }
  271. if err := task.Run(); err != nil {
  272. return fmt.Errorf("Error running DeviceCreate (createPool)")
  273. }
  274. UdevWait(cookie)
  275. return nil
  276. }
  277. func reloadPool(poolName string, dataFile, metadataFile *osFile) error {
  278. task, err := createTask(DeviceReload, poolName)
  279. if task == nil {
  280. return err
  281. }
  282. size, err := GetBlockDeviceSize(dataFile)
  283. if err != nil {
  284. return fmt.Errorf("Can't get data size")
  285. }
  286. params := metadataFile.Name() + " " + dataFile.Name() + " 128 32768"
  287. if err := task.AddTarget(0, size/512, "thin-pool", params); err != nil {
  288. return fmt.Errorf("Can't add target")
  289. }
  290. if err := task.Run(); err != nil {
  291. return fmt.Errorf("Error running DeviceCreate")
  292. }
  293. return nil
  294. }
  295. func createTask(t TaskType, name string) (*Task, error) {
  296. task := TaskCreate(t)
  297. if task == nil {
  298. return nil, fmt.Errorf("Can't create task of type %d", int(t))
  299. }
  300. if err := task.SetName(name); err != nil {
  301. return nil, fmt.Errorf("Can't set task name %s", name)
  302. }
  303. return task, nil
  304. }
  305. func getInfo(name string) (*Info, error) {
  306. task, err := createTask(DeviceInfo, name)
  307. if task == nil {
  308. return nil, err
  309. }
  310. if err := task.Run(); err != nil {
  311. return nil, err
  312. }
  313. return task.GetInfo()
  314. }
  315. func getStatus(name string) (uint64, uint64, string, string, error) {
  316. task, err := createTask(DeviceStatus, name)
  317. if task == nil {
  318. utils.Debugf("getStatus: Error createTask: %s", err)
  319. return 0, 0, "", "", err
  320. }
  321. if err := task.Run(); err != nil {
  322. utils.Debugf("getStatus: Error Run: %s", err)
  323. return 0, 0, "", "", err
  324. }
  325. devinfo, err := task.GetInfo()
  326. if err != nil {
  327. utils.Debugf("getStatus: Error GetInfo: %s", err)
  328. return 0, 0, "", "", err
  329. }
  330. if devinfo.Exists == 0 {
  331. utils.Debugf("getStatus: Non existing device %s", name)
  332. return 0, 0, "", "", fmt.Errorf("Non existing device %s", name)
  333. }
  334. _, start, length, targetType, params := task.GetNextTarget(0)
  335. return start, length, targetType, params, nil
  336. }
  337. func setTransactionId(poolName string, oldId uint64, newId uint64) error {
  338. task, err := createTask(DeviceTargetMsg, poolName)
  339. if task == nil {
  340. return err
  341. }
  342. if err := task.SetSector(0); err != nil {
  343. return fmt.Errorf("Can't set sector")
  344. }
  345. if err := task.SetMessage(fmt.Sprintf("set_transaction_id %d %d", oldId, newId)); err != nil {
  346. return fmt.Errorf("Can't set message")
  347. }
  348. if err := task.Run(); err != nil {
  349. return fmt.Errorf("Error running setTransactionId")
  350. }
  351. return nil
  352. }
  353. func suspendDevice(name string) error {
  354. task, err := createTask(DeviceSuspend, name)
  355. if task == nil {
  356. return err
  357. }
  358. if err := task.Run(); err != nil {
  359. return fmt.Errorf("Error running DeviceSuspend: %s", err)
  360. }
  361. return nil
  362. }
  363. func resumeDevice(name string) error {
  364. task, err := createTask(DeviceResume, name)
  365. if task == nil {
  366. return err
  367. }
  368. var cookie uint = 0
  369. if err := task.SetCookie(&cookie, 0); err != nil {
  370. return fmt.Errorf("Can't set cookie")
  371. }
  372. if err := task.Run(); err != nil {
  373. return fmt.Errorf("Error running DeviceResume")
  374. }
  375. UdevWait(cookie)
  376. return nil
  377. }
  378. func createDevice(poolName string, deviceId int) error {
  379. utils.Debugf("[devmapper] createDevice(poolName=%v, deviceId=%v)", poolName, deviceId)
  380. task, err := createTask(DeviceTargetMsg, poolName)
  381. if task == nil {
  382. return err
  383. }
  384. if err := task.SetSector(0); err != nil {
  385. return fmt.Errorf("Can't set sector")
  386. }
  387. if err := task.SetMessage(fmt.Sprintf("create_thin %d", deviceId)); err != nil {
  388. return fmt.Errorf("Can't set message")
  389. }
  390. if err := task.Run(); err != nil {
  391. return fmt.Errorf("Error running createDevice")
  392. }
  393. return nil
  394. }
  395. func deleteDevice(poolName string, deviceId int) error {
  396. task, err := createTask(DeviceTargetMsg, poolName)
  397. if task == nil {
  398. return err
  399. }
  400. if err := task.SetSector(0); err != nil {
  401. return fmt.Errorf("Can't set sector")
  402. }
  403. if err := task.SetMessage(fmt.Sprintf("delete %d", deviceId)); err != nil {
  404. return fmt.Errorf("Can't set message")
  405. }
  406. if err := task.Run(); err != nil {
  407. return fmt.Errorf("Error running deleteDevice")
  408. }
  409. return nil
  410. }
  411. func removeDevice(name string) error {
  412. utils.Debugf("[devmapper] removeDevice START")
  413. defer utils.Debugf("[devmapper] removeDevice END")
  414. task, err := createTask(DeviceRemove, name)
  415. if task == nil {
  416. return err
  417. }
  418. if err = task.Run(); err != nil {
  419. return fmt.Errorf("Error running removeDevice")
  420. }
  421. return nil
  422. }
  423. func activateDevice(poolName string, name string, deviceId int, size uint64) error {
  424. task, err := createTask(DeviceCreate, name)
  425. if task == nil {
  426. return err
  427. }
  428. params := fmt.Sprintf("%s %d", poolName, deviceId)
  429. if err := task.AddTarget(0, size/512, "thin", params); err != nil {
  430. return fmt.Errorf("Can't add target")
  431. }
  432. if err := task.SetAddNode(AddNodeOnCreate); err != nil {
  433. return fmt.Errorf("Can't add node")
  434. }
  435. var cookie uint = 0
  436. if err := task.SetCookie(&cookie, 0); err != nil {
  437. return fmt.Errorf("Can't set cookie")
  438. }
  439. if err := task.Run(); err != nil {
  440. return fmt.Errorf("Error running DeviceCreate (activateDevice)")
  441. }
  442. UdevWait(cookie)
  443. return nil
  444. }
  445. func (devices *DeviceSet) createSnapDevice(poolName string, deviceId int, baseName string, baseDeviceId int) error {
  446. devinfo, _ := getInfo(baseName)
  447. doSuspend := devinfo != nil && devinfo.Exists != 0
  448. if doSuspend {
  449. if err := suspendDevice(baseName); err != nil {
  450. return err
  451. }
  452. }
  453. task, err := createTask(DeviceTargetMsg, poolName)
  454. if task == nil {
  455. if doSuspend {
  456. resumeDevice(baseName)
  457. }
  458. return err
  459. }
  460. if err := task.SetSector(0); err != nil {
  461. if doSuspend {
  462. resumeDevice(baseName)
  463. }
  464. return fmt.Errorf("Can't set sector")
  465. }
  466. if err := task.SetMessage(fmt.Sprintf("create_snap %d %d", deviceId, baseDeviceId)); err != nil {
  467. if doSuspend {
  468. resumeDevice(baseName)
  469. }
  470. return fmt.Errorf("Can't set message")
  471. }
  472. if err := task.Run(); err != nil {
  473. if doSuspend {
  474. resumeDevice(baseName)
  475. }
  476. return fmt.Errorf("Error running DeviceCreate (createSnapDevice)")
  477. }
  478. if doSuspend {
  479. if err := resumeDevice(baseName); err != nil {
  480. return err
  481. }
  482. }
  483. return nil
  484. }