devmapper.go 13 KB

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