devmapper.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  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 AttachLoopDevice(filename string) (*osFile, error) {
  161. var fd int
  162. res := DmAttachLoopDevice(filename, &fd)
  163. if res == "" {
  164. return nil, ErrAttachLoopbackDevice
  165. }
  166. return &osFile{File: osNewFile(uintptr(fd), res)}, nil
  167. }
  168. func getLoopbackBackingFile(file *osFile) (uint64, uint64, error) {
  169. dev, inode, err := DmGetLoopbackBackingFile(file.Fd())
  170. if err != 0 {
  171. return 0, 0, ErrGetLoopbackBackingFile
  172. }
  173. return dev, inode, nil
  174. }
  175. func LoopbackSetCapacity(file *osFile) error {
  176. if err := DmLoopbackSetCapacity(file.Fd()); err != 0 {
  177. return ErrLoopbackSetCapacity
  178. }
  179. return nil
  180. }
  181. func FindLoopDeviceFor(file *osFile) *osFile {
  182. stat, err := file.Stat()
  183. if err != nil {
  184. return nil
  185. }
  186. targetInode := stat.Sys().(*sysStatT).Ino
  187. targetDevice := stat.Sys().(*sysStatT).Dev
  188. for i := 0; true; i++ {
  189. path := fmt.Sprintf("/dev/loop%d", i)
  190. file, err := osOpenFile(path, osORdWr, 0)
  191. if err != nil {
  192. if osIsNotExist(err) {
  193. return nil
  194. }
  195. // Ignore all errors until the first not-exist
  196. // we want to continue looking for the file
  197. continue
  198. }
  199. dev, inode, err := getLoopbackBackingFile(&osFile{File: file})
  200. if err == nil && dev == targetDevice && inode == targetInode {
  201. return &osFile{File: file}
  202. }
  203. file.Close()
  204. }
  205. return nil
  206. }
  207. func UdevWait(cookie uint) error {
  208. if res := DmUdevWait(cookie); res != 1 {
  209. utils.Debugf("Failed to wait on udev cookie %d", cookie)
  210. return ErrUdevWait
  211. }
  212. return nil
  213. }
  214. func LogInitVerbose(level int) {
  215. DmLogInitVerbose(level)
  216. }
  217. var dmLogger DevmapperLogger = nil
  218. func logInit(logger DevmapperLogger) {
  219. dmLogger = logger
  220. LogWithErrnoInit()
  221. }
  222. func SetDevDir(dir string) error {
  223. if res := DmSetDevDir(dir); res != 1 {
  224. utils.Debugf("Error dm_set_dev_dir")
  225. return ErrSetDevDir
  226. }
  227. return nil
  228. }
  229. func GetLibraryVersion() (string, error) {
  230. var version string
  231. if res := DmGetLibraryVersion(&version); res != 1 {
  232. return "", ErrGetLibraryVersion
  233. }
  234. return version, nil
  235. }
  236. // Useful helper for cleanup
  237. func RemoveDevice(name string) error {
  238. task := TaskCreate(DeviceRemove)
  239. if task == nil {
  240. return ErrCreateRemoveTask
  241. }
  242. if err := task.SetName(name); err != nil {
  243. utils.Debugf("Can't set task name %s", name)
  244. return err
  245. }
  246. if err := task.Run(); err != nil {
  247. return ErrRunRemoveDevice
  248. }
  249. return nil
  250. }
  251. func GetBlockDeviceSize(file *osFile) (uint64, error) {
  252. size, errno := DmGetBlockSize(file.Fd())
  253. if size == -1 || errno != 0 {
  254. return 0, ErrGetBlockSize
  255. }
  256. return uint64(size), nil
  257. }
  258. // This is the programmatic example of "dmsetup create"
  259. func createPool(poolName string, dataFile, metadataFile *osFile) error {
  260. task, err := createTask(DeviceCreate, poolName)
  261. if task == nil {
  262. return err
  263. }
  264. size, err := GetBlockDeviceSize(dataFile)
  265. if err != nil {
  266. return fmt.Errorf("Can't get data size")
  267. }
  268. params := metadataFile.Name() + " " + dataFile.Name() + " 128 32768"
  269. if err := task.AddTarget(0, size/512, "thin-pool", params); err != nil {
  270. return fmt.Errorf("Can't add target")
  271. }
  272. var cookie uint = 0
  273. if err := task.SetCookie(&cookie, 0); err != nil {
  274. return fmt.Errorf("Can't set cookie")
  275. }
  276. if err := task.Run(); err != nil {
  277. return fmt.Errorf("Error running DeviceCreate (createPool)")
  278. }
  279. UdevWait(cookie)
  280. return nil
  281. }
  282. func reloadPool(poolName string, dataFile, metadataFile *osFile) error {
  283. task, err := createTask(DeviceReload, poolName)
  284. if task == nil {
  285. return err
  286. }
  287. size, err := GetBlockDeviceSize(dataFile)
  288. if err != nil {
  289. return fmt.Errorf("Can't get data size")
  290. }
  291. params := metadataFile.Name() + " " + dataFile.Name() + " 128 32768"
  292. if err := task.AddTarget(0, size/512, "thin-pool", params); err != nil {
  293. return fmt.Errorf("Can't add target")
  294. }
  295. if err := task.Run(); err != nil {
  296. return fmt.Errorf("Error running DeviceCreate")
  297. }
  298. return nil
  299. }
  300. func createTask(t TaskType, name string) (*Task, error) {
  301. task := TaskCreate(t)
  302. if task == nil {
  303. return nil, fmt.Errorf("Can't create task of type %d", int(t))
  304. }
  305. if err := task.SetName(name); err != nil {
  306. return nil, fmt.Errorf("Can't set task name %s", name)
  307. }
  308. return task, nil
  309. }
  310. func getInfo(name string) (*Info, error) {
  311. task, err := createTask(DeviceInfo, name)
  312. if task == nil {
  313. return nil, err
  314. }
  315. if err := task.Run(); err != nil {
  316. return nil, err
  317. }
  318. return task.GetInfo()
  319. }
  320. func getStatus(name string) (uint64, uint64, string, string, error) {
  321. task, err := createTask(DeviceStatus, name)
  322. if task == nil {
  323. utils.Debugf("getStatus: Error createTask: %s", err)
  324. return 0, 0, "", "", err
  325. }
  326. if err := task.Run(); err != nil {
  327. utils.Debugf("getStatus: Error Run: %s", err)
  328. return 0, 0, "", "", err
  329. }
  330. devinfo, err := task.GetInfo()
  331. if err != nil {
  332. utils.Debugf("getStatus: Error GetInfo: %s", err)
  333. return 0, 0, "", "", err
  334. }
  335. if devinfo.Exists == 0 {
  336. utils.Debugf("getStatus: Non existing device %s", name)
  337. return 0, 0, "", "", fmt.Errorf("Non existing device %s", name)
  338. }
  339. _, start, length, targetType, params := task.GetNextTarget(0)
  340. return start, length, targetType, params, nil
  341. }
  342. func setTransactionId(poolName string, oldId uint64, newId uint64) error {
  343. task, err := createTask(DeviceTargetMsg, poolName)
  344. if task == nil {
  345. return err
  346. }
  347. if err := task.SetSector(0); err != nil {
  348. return fmt.Errorf("Can't set sector")
  349. }
  350. if err := task.SetMessage(fmt.Sprintf("set_transaction_id %d %d", oldId, newId)); err != nil {
  351. return fmt.Errorf("Can't set message")
  352. }
  353. if err := task.Run(); err != nil {
  354. return fmt.Errorf("Error running setTransactionId")
  355. }
  356. return nil
  357. }
  358. func suspendDevice(name string) error {
  359. task, err := createTask(DeviceSuspend, name)
  360. if task == nil {
  361. return err
  362. }
  363. if err := task.Run(); err != nil {
  364. return fmt.Errorf("Error running DeviceSuspend")
  365. }
  366. return nil
  367. }
  368. func resumeDevice(name string) error {
  369. task, err := createTask(DeviceResume, name)
  370. if task == nil {
  371. return err
  372. }
  373. var cookie uint = 0
  374. if err := task.SetCookie(&cookie, 0); err != nil {
  375. return fmt.Errorf("Can't set cookie")
  376. }
  377. if err := task.Run(); err != nil {
  378. return fmt.Errorf("Error running DeviceSuspend")
  379. }
  380. UdevWait(cookie)
  381. return nil
  382. }
  383. func createDevice(poolName string, deviceId int) error {
  384. utils.Debugf("[devmapper] createDevice(poolName=%v, deviceId=%v)", poolName, deviceId)
  385. task, err := createTask(DeviceTargetMsg, poolName)
  386. if task == nil {
  387. return err
  388. }
  389. if err := task.SetSector(0); err != nil {
  390. return fmt.Errorf("Can't set sector")
  391. }
  392. if err := task.SetMessage(fmt.Sprintf("create_thin %d", deviceId)); err != nil {
  393. return fmt.Errorf("Can't set message")
  394. }
  395. if err := task.Run(); err != nil {
  396. return fmt.Errorf("Error running createDevice")
  397. }
  398. return nil
  399. }
  400. func deleteDevice(poolName string, deviceId int) error {
  401. task, err := createTask(DeviceTargetMsg, poolName)
  402. if task == nil {
  403. return err
  404. }
  405. if err := task.SetSector(0); err != nil {
  406. return fmt.Errorf("Can't set sector")
  407. }
  408. if err := task.SetMessage(fmt.Sprintf("delete %d", deviceId)); err != nil {
  409. return fmt.Errorf("Can't set message")
  410. }
  411. if err := task.Run(); err != nil {
  412. return fmt.Errorf("Error running deleteDevice")
  413. }
  414. return nil
  415. }
  416. func removeDevice(name string) error {
  417. utils.Debugf("[devmapper] removeDevice START")
  418. defer utils.Debugf("[devmapper] removeDevice END")
  419. task, err := createTask(DeviceRemove, name)
  420. if task == nil {
  421. return err
  422. }
  423. if err = task.Run(); err != nil {
  424. return fmt.Errorf("Error running removeDevice")
  425. }
  426. return nil
  427. }
  428. func activateDevice(poolName string, name string, deviceId int, size uint64) error {
  429. task, err := createTask(DeviceCreate, name)
  430. if task == nil {
  431. return err
  432. }
  433. params := fmt.Sprintf("%s %d", poolName, deviceId)
  434. if err := task.AddTarget(0, size/512, "thin", params); err != nil {
  435. return fmt.Errorf("Can't add target")
  436. }
  437. if err := task.SetAddNode(AddNodeOnCreate); err != nil {
  438. return fmt.Errorf("Can't add node")
  439. }
  440. var cookie uint = 0
  441. if err := task.SetCookie(&cookie, 0); err != nil {
  442. return fmt.Errorf("Can't set cookie")
  443. }
  444. if err := task.Run(); err != nil {
  445. return fmt.Errorf("Error running DeviceCreate (activateDevice)")
  446. }
  447. UdevWait(cookie)
  448. return nil
  449. }
  450. func (devices *DeviceSet) createSnapDevice(poolName string, deviceId int, baseName string, baseDeviceId int) error {
  451. devinfo, _ := getInfo(baseName)
  452. doSuspend := devinfo != nil && devinfo.Exists != 0
  453. if doSuspend {
  454. if err := suspendDevice(baseName); err != nil {
  455. return err
  456. }
  457. }
  458. task, err := createTask(DeviceTargetMsg, poolName)
  459. if task == nil {
  460. if doSuspend {
  461. resumeDevice(baseName)
  462. }
  463. return err
  464. }
  465. if err := task.SetSector(0); err != nil {
  466. if doSuspend {
  467. resumeDevice(baseName)
  468. }
  469. return fmt.Errorf("Can't set sector")
  470. }
  471. if err := task.SetMessage(fmt.Sprintf("create_snap %d %d", deviceId, baseDeviceId)); err != nil {
  472. if doSuspend {
  473. resumeDevice(baseName)
  474. }
  475. return fmt.Errorf("Can't set message")
  476. }
  477. if err := task.Run(); err != nil {
  478. if doSuspend {
  479. resumeDevice(baseName)
  480. }
  481. return fmt.Errorf("Error running DeviceCreate (createSnapDevice)")
  482. }
  483. if doSuspend {
  484. if err := resumeDevice(baseName); err != nil {
  485. return err
  486. }
  487. }
  488. return nil
  489. }