devmapper.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673
  1. package devmapper
  2. import (
  3. "errors"
  4. "fmt"
  5. "github.com/dotcloud/docker/utils"
  6. "runtime"
  7. "unsafe"
  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. dev, inode, err := DmGetLoopbackBackingFile(file.Fd())
  163. if err != 0 {
  164. return 0, 0, ErrGetLoopbackBackingFile
  165. }
  166. return dev, inode, nil
  167. }
  168. func LoopbackSetCapacity(file *osFile) error {
  169. if err := DmLoopbackSetCapacity(file.Fd()); err != 0 {
  170. return ErrLoopbackSetCapacity
  171. }
  172. return nil
  173. }
  174. func FindLoopDeviceFor(file *osFile) *osFile {
  175. stat, err := file.Stat()
  176. if err != nil {
  177. return nil
  178. }
  179. targetInode := stat.Sys().(*sysStatT).Ino
  180. targetDevice := stat.Sys().(*sysStatT).Dev
  181. for i := 0; true; i++ {
  182. path := fmt.Sprintf("/dev/loop%d", i)
  183. file, err := osOpenFile(path, osORdWr, 0)
  184. if err != nil {
  185. if osIsNotExist(err) {
  186. return nil
  187. }
  188. // Ignore all errors until the first not-exist
  189. // we want to continue looking for the file
  190. continue
  191. }
  192. dev, inode, err := getLoopbackBackingFile(file)
  193. if err == nil && dev == targetDevice && inode == targetInode {
  194. return file
  195. }
  196. file.Close()
  197. }
  198. return nil
  199. }
  200. func UdevWait(cookie uint) error {
  201. if res := DmUdevWait(cookie); res != 1 {
  202. utils.Debugf("Failed to wait on udev cookie %d", cookie)
  203. return ErrUdevWait
  204. }
  205. return nil
  206. }
  207. func LogInitVerbose(level int) {
  208. DmLogInitVerbose(level)
  209. }
  210. var dmLogger DevmapperLogger = nil
  211. func logInit(logger DevmapperLogger) {
  212. dmLogger = logger
  213. LogWithErrnoInit()
  214. }
  215. func SetDevDir(dir string) error {
  216. if res := DmSetDevDir(dir); res != 1 {
  217. utils.Debugf("Error dm_set_dev_dir")
  218. return ErrSetDevDir
  219. }
  220. return nil
  221. }
  222. func GetLibraryVersion() (string, error) {
  223. var version string
  224. if res := DmGetLibraryVersion(&version); res != 1 {
  225. return "", ErrGetLibraryVersion
  226. }
  227. return version, nil
  228. }
  229. // Useful helper for cleanup
  230. func RemoveDevice(name string) error {
  231. task := TaskCreate(DeviceRemove)
  232. if task == nil {
  233. return ErrCreateRemoveTask
  234. }
  235. if err := task.SetName(name); err != nil {
  236. utils.Debugf("Can't set task name %s", name)
  237. return err
  238. }
  239. if err := task.Run(); err != nil {
  240. return ErrRunRemoveDevice
  241. }
  242. return nil
  243. }
  244. func GetBlockDeviceSize(file *osFile) (uint64, error) {
  245. size, errno := DmGetBlockSize(file.Fd())
  246. if size == -1 || errno != 0 {
  247. return 0, ErrGetBlockSize
  248. }
  249. return uint64(size), nil
  250. }
  251. // This is the programmatic example of "dmsetup create"
  252. func createPool(poolName string, dataFile, metadataFile *osFile) error {
  253. task, err := createTask(DeviceCreate, poolName)
  254. if task == nil {
  255. return err
  256. }
  257. size, err := GetBlockDeviceSize(dataFile)
  258. if err != nil {
  259. return fmt.Errorf("Can't get data size")
  260. }
  261. params := metadataFile.Name() + " " + dataFile.Name() + " 128 32768"
  262. if err := task.AddTarget(0, size/512, "thin-pool", params); err != nil {
  263. return fmt.Errorf("Can't add target")
  264. }
  265. var cookie uint = 0
  266. if err := task.SetCookie(&cookie, 0); err != nil {
  267. return fmt.Errorf("Can't set cookie")
  268. }
  269. if err := task.Run(); err != nil {
  270. return fmt.Errorf("Error running DeviceCreate (createPool)")
  271. }
  272. UdevWait(cookie)
  273. return nil
  274. }
  275. func reloadPool(poolName string, dataFile, metadataFile *osFile) error {
  276. task, err := createTask(DeviceReload, poolName)
  277. if task == nil {
  278. return err
  279. }
  280. size, err := GetBlockDeviceSize(dataFile)
  281. if err != nil {
  282. return fmt.Errorf("Can't get data size")
  283. }
  284. params := metadataFile.Name() + " " + dataFile.Name() + " 128 32768"
  285. if err := task.AddTarget(0, size/512, "thin-pool", params); err != nil {
  286. return fmt.Errorf("Can't add target")
  287. }
  288. if err := task.Run(); err != nil {
  289. return fmt.Errorf("Error running DeviceCreate")
  290. }
  291. return nil
  292. }
  293. func createTask(t TaskType, name string) (*Task, error) {
  294. task := TaskCreate(t)
  295. if task == nil {
  296. return nil, fmt.Errorf("Can't create task of type %d", int(t))
  297. }
  298. if err := task.SetName(name); err != nil {
  299. return nil, fmt.Errorf("Can't set task name %s", name)
  300. }
  301. return task, nil
  302. }
  303. func getInfo(name string) (*Info, error) {
  304. task, err := createTask(DeviceInfo, name)
  305. if task == nil {
  306. return nil, err
  307. }
  308. if err := task.Run(); err != nil {
  309. return nil, err
  310. }
  311. return task.GetInfo()
  312. }
  313. func getStatus(name string) (uint64, uint64, string, string, error) {
  314. task, err := createTask(DeviceStatus, name)
  315. if task == nil {
  316. utils.Debugf("getStatus: Error createTask: %s", err)
  317. return 0, 0, "", "", err
  318. }
  319. if err := task.Run(); err != nil {
  320. utils.Debugf("getStatus: Error Run: %s", err)
  321. return 0, 0, "", "", err
  322. }
  323. devinfo, err := task.GetInfo()
  324. if err != nil {
  325. utils.Debugf("getStatus: Error GetInfo: %s", err)
  326. return 0, 0, "", "", err
  327. }
  328. if devinfo.Exists == 0 {
  329. utils.Debugf("getStatus: Non existing device %s", name)
  330. return 0, 0, "", "", fmt.Errorf("Non existing device %s", name)
  331. }
  332. _, start, length, targetType, params := task.GetNextTarget(0)
  333. return start, length, targetType, params, nil
  334. }
  335. func setTransactionId(poolName string, oldId uint64, newId uint64) error {
  336. task, err := createTask(DeviceTargetMsg, poolName)
  337. if task == nil {
  338. return err
  339. }
  340. if err := task.SetSector(0); err != nil {
  341. return fmt.Errorf("Can't set sector")
  342. }
  343. if err := task.SetMessage(fmt.Sprintf("set_transaction_id %d %d", oldId, newId)); err != nil {
  344. return fmt.Errorf("Can't set message")
  345. }
  346. if err := task.Run(); err != nil {
  347. return fmt.Errorf("Error running setTransactionId")
  348. }
  349. return nil
  350. }
  351. func suspendDevice(name string) error {
  352. task, err := createTask(DeviceSuspend, name)
  353. if task == nil {
  354. return err
  355. }
  356. if err := task.Run(); err != nil {
  357. return fmt.Errorf("Error running DeviceSuspend: %s", err)
  358. }
  359. return nil
  360. }
  361. func resumeDevice(name string) error {
  362. task, err := createTask(DeviceResume, name)
  363. if task == nil {
  364. return err
  365. }
  366. var cookie uint = 0
  367. if err := task.SetCookie(&cookie, 0); err != nil {
  368. return fmt.Errorf("Can't set cookie")
  369. }
  370. if err := task.Run(); err != nil {
  371. return fmt.Errorf("Error running DeviceResume")
  372. }
  373. UdevWait(cookie)
  374. return nil
  375. }
  376. func createDevice(poolName string, deviceId int) error {
  377. utils.Debugf("[devmapper] createDevice(poolName=%v, deviceId=%v)", poolName, deviceId)
  378. task, err := createTask(DeviceTargetMsg, poolName)
  379. if task == nil {
  380. return err
  381. }
  382. if err := task.SetSector(0); err != nil {
  383. return fmt.Errorf("Can't set sector")
  384. }
  385. if err := task.SetMessage(fmt.Sprintf("create_thin %d", deviceId)); err != nil {
  386. return fmt.Errorf("Can't set message")
  387. }
  388. if err := task.Run(); err != nil {
  389. return fmt.Errorf("Error running createDevice")
  390. }
  391. return nil
  392. }
  393. func deleteDevice(poolName string, deviceId int) error {
  394. task, err := createTask(DeviceTargetMsg, poolName)
  395. if task == nil {
  396. return err
  397. }
  398. if err := task.SetSector(0); err != nil {
  399. return fmt.Errorf("Can't set sector")
  400. }
  401. if err := task.SetMessage(fmt.Sprintf("delete %d", deviceId)); err != nil {
  402. return fmt.Errorf("Can't set message")
  403. }
  404. if err := task.Run(); err != nil {
  405. return fmt.Errorf("Error running deleteDevice")
  406. }
  407. return nil
  408. }
  409. func removeDevice(name string) error {
  410. utils.Debugf("[devmapper] removeDevice START")
  411. defer utils.Debugf("[devmapper] removeDevice END")
  412. task, err := createTask(DeviceRemove, name)
  413. if task == nil {
  414. return err
  415. }
  416. if err = task.Run(); err != nil {
  417. return fmt.Errorf("Error running removeDevice")
  418. }
  419. return nil
  420. }
  421. func activateDevice(poolName string, name string, deviceId int, size uint64) error {
  422. task, err := createTask(DeviceCreate, name)
  423. if task == nil {
  424. return err
  425. }
  426. params := fmt.Sprintf("%s %d", poolName, deviceId)
  427. if err := task.AddTarget(0, size/512, "thin", params); err != nil {
  428. return fmt.Errorf("Can't add target")
  429. }
  430. if err := task.SetAddNode(AddNodeOnCreate); err != nil {
  431. return fmt.Errorf("Can't add node")
  432. }
  433. var cookie uint = 0
  434. if err := task.SetCookie(&cookie, 0); err != nil {
  435. return fmt.Errorf("Can't set cookie")
  436. }
  437. if err := task.Run(); err != nil {
  438. return fmt.Errorf("Error running DeviceCreate (activateDevice)")
  439. }
  440. UdevWait(cookie)
  441. return nil
  442. }
  443. func (devices *DeviceSet) createSnapDevice(poolName string, deviceId int, baseName string, baseDeviceId int) error {
  444. devinfo, _ := getInfo(baseName)
  445. doSuspend := devinfo != nil && devinfo.Exists != 0
  446. if doSuspend {
  447. if err := suspendDevice(baseName); err != nil {
  448. return err
  449. }
  450. }
  451. task, err := createTask(DeviceTargetMsg, poolName)
  452. if task == nil {
  453. if doSuspend {
  454. resumeDevice(baseName)
  455. }
  456. return err
  457. }
  458. if err := task.SetSector(0); err != nil {
  459. if doSuspend {
  460. resumeDevice(baseName)
  461. }
  462. return fmt.Errorf("Can't set sector")
  463. }
  464. if err := task.SetMessage(fmt.Sprintf("create_snap %d %d", deviceId, baseDeviceId)); err != nil {
  465. if doSuspend {
  466. resumeDevice(baseName)
  467. }
  468. return fmt.Errorf("Can't set message")
  469. }
  470. if err := task.Run(); err != nil {
  471. if doSuspend {
  472. resumeDevice(baseName)
  473. }
  474. return fmt.Errorf("Error running DeviceCreate (createSnapDevice)")
  475. }
  476. if doSuspend {
  477. if err := resumeDevice(baseName); err != nil {
  478. return err
  479. }
  480. }
  481. return nil
  482. }
  483. type LoopInfo64 struct {
  484. loDevice uint64 /* ioctl r/o */
  485. loInode uint64 /* ioctl r/o */
  486. loRdevice uint64 /* ioctl r/o */
  487. loOffset uint64
  488. loSizelimit uint64 /* bytes, 0 == max available */
  489. loNumber uint32 /* ioctl r/o */
  490. loEncrypt_type uint32
  491. loEncrypt_key_size uint32 /* ioctl w/o */
  492. loFlags uint32 /* ioctl r/o */
  493. loFileName [LoNameSize]uint8
  494. loCryptName [LoNameSize]uint8
  495. loEncryptKey [LoKeySize]uint8 /* ioctl w/o */
  496. loInit [2]uint64
  497. }
  498. // attachLoopDevice attaches the given sparse file to the next
  499. // available loopback device. It returns an opened *osFile.
  500. func attachLoopDevice(filename string) (loop *osFile, err error) {
  501. startIndex := 0
  502. // Try to retrieve the next available loopback device via syscall.
  503. // If it fails, we discard error and start loopking for a
  504. // loopback from index 0.
  505. if f, err := osOpenFile("/dev/loop-control", osORdOnly, 0644); err == nil {
  506. if index, _, err := sysSyscall(sysSysIoctl, f.Fd(), LoopCtlGetFree, 0); err != 0 {
  507. utils.Debugf("Error retrieving the next available loopback: %s", err)
  508. } else if index > 0 {
  509. startIndex = int(index)
  510. }
  511. f.Close()
  512. }
  513. // Open the given sparse file (use OpenFile because Open sets O_CLOEXEC)
  514. f, err := osOpenFile(filename, osORdWr, 0644)
  515. if err != nil {
  516. return nil, err
  517. }
  518. defer f.Close()
  519. var (
  520. target string
  521. loopFile *osFile
  522. )
  523. // Start looking for a free /dev/loop
  524. for i := startIndex; ; {
  525. target = fmt.Sprintf("/dev/loop%d", i)
  526. fi, err := osStat(target)
  527. if err != nil {
  528. if osIsNotExist(err) {
  529. utils.Errorf("There are no more loopback device available.")
  530. }
  531. }
  532. // FIXME: Check here if target is a block device (in C: S_ISBLK(mode))
  533. if fi.IsDir() {
  534. }
  535. // Open the targeted loopback (use OpenFile because Open sets O_CLOEXEC)
  536. loopFile, err = osOpenFile(target, osORdWr, 0644)
  537. if err != nil {
  538. return nil, err
  539. }
  540. // Try to attach to the loop file
  541. if _, _, err := sysSyscall(sysSysIoctl, loopFile.Fd(), LoopSetFd, f.Fd()); err != 0 {
  542. loopFile.Close()
  543. // If the error is EBUSY, then try the next loopback
  544. if err != sysEBusy {
  545. utils.Errorf("Cannot set up loopback device %s: %s", target, err)
  546. return nil, err
  547. }
  548. } else {
  549. // In case of success, we finished. Break the loop.
  550. break
  551. }
  552. // In case of EBUSY error, the loop keep going.
  553. }
  554. // This can't happen, but let's be sure
  555. if loopFile == nil {
  556. return nil, fmt.Errorf("Unreachable code reached! Error attaching %s to a loopback device.", filename)
  557. }
  558. // Set the status of the loopback device
  559. var loopInfo LoopInfo64
  560. // Due to type incompatibility (string vs [64]uint8), we copy data
  561. copy(loopInfo.loFileName[:], target[:])
  562. loopInfo.loOffset = 0
  563. loopInfo.loFlags = LoFlagsAutoClear
  564. if _, _, err := sysSyscall(sysSysIoctl, loopFile.Fd(), LoopSetStatus64, uintptr(unsafe.Pointer(&loopInfo))); err != 0 {
  565. // If the call failed, then free the loopback device
  566. utils.Errorf("Cannot set up loopback device info: %s", err)
  567. if _, _, err := sysSyscall(sysSysIoctl, loopFile.Fd(), LoopClrFd, 0); err != 0 {
  568. utils.Errorf("Error while cleaning up the loopback device")
  569. }
  570. loopFile.Close()
  571. return nil, err
  572. }
  573. return loopFile, nil
  574. }