aufs.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. /*
  2. aufs driver directory structure
  3. .
  4. ├── layers // Metadata of layers
  5. │   ├── 1
  6. │   ├── 2
  7. │   └── 3
  8. ├── diff // Content of the layer
  9. │   ├── 1 // Contains layers that need to be mounted for the id
  10. │   ├── 2
  11. │   └── 3
  12. └── mnt // Mount points for the rw layers to be mounted
  13. ├── 1
  14. ├── 2
  15. └── 3
  16. */
  17. package aufs
  18. import (
  19. "bufio"
  20. "fmt"
  21. "os"
  22. "os/exec"
  23. "path"
  24. "strings"
  25. "sync"
  26. "syscall"
  27. log "github.com/Sirupsen/logrus"
  28. "github.com/docker/docker/daemon/graphdriver"
  29. "github.com/docker/docker/pkg/archive"
  30. "github.com/docker/docker/pkg/chrootarchive"
  31. mountpk "github.com/docker/docker/pkg/mount"
  32. "github.com/docker/docker/utils"
  33. "github.com/docker/libcontainer/label"
  34. )
  35. var (
  36. ErrAufsNotSupported = fmt.Errorf("AUFS was not found in /proc/filesystems")
  37. incompatibleFsMagic = []graphdriver.FsMagic{
  38. graphdriver.FsMagicBtrfs,
  39. graphdriver.FsMagicAufs,
  40. }
  41. )
  42. func init() {
  43. graphdriver.Register("aufs", Init)
  44. }
  45. type Driver struct {
  46. root string
  47. sync.Mutex // Protects concurrent modification to active
  48. active map[string]int
  49. }
  50. // New returns a new AUFS driver.
  51. // An error is returned if AUFS is not supported.
  52. func Init(root string, options []string) (graphdriver.Driver, error) {
  53. // Try to load the aufs kernel module
  54. if err := supportsAufs(); err != nil {
  55. return nil, graphdriver.ErrNotSupported
  56. }
  57. rootdir := path.Dir(root)
  58. var buf syscall.Statfs_t
  59. if err := syscall.Statfs(rootdir, &buf); err != nil {
  60. return nil, fmt.Errorf("Couldn't stat the root directory: %s", err)
  61. }
  62. for _, magic := range incompatibleFsMagic {
  63. if graphdriver.FsMagic(buf.Type) == magic {
  64. return nil, graphdriver.ErrIncompatibleFS
  65. }
  66. }
  67. paths := []string{
  68. "mnt",
  69. "diff",
  70. "layers",
  71. }
  72. a := &Driver{
  73. root: root,
  74. active: make(map[string]int),
  75. }
  76. // Create the root aufs driver dir and return
  77. // if it already exists
  78. // If not populate the dir structure
  79. if err := os.MkdirAll(root, 0755); err != nil {
  80. if os.IsExist(err) {
  81. return a, nil
  82. }
  83. return nil, err
  84. }
  85. if err := mountpk.MakePrivate(root); err != nil {
  86. return nil, err
  87. }
  88. for _, p := range paths {
  89. if err := os.MkdirAll(path.Join(root, p), 0755); err != nil {
  90. return nil, err
  91. }
  92. }
  93. return a, nil
  94. }
  95. // Return a nil error if the kernel supports aufs
  96. // We cannot modprobe because inside dind modprobe fails
  97. // to run
  98. func supportsAufs() error {
  99. // We can try to modprobe aufs first before looking at
  100. // proc/filesystems for when aufs is supported
  101. exec.Command("modprobe", "aufs").Run()
  102. f, err := os.Open("/proc/filesystems")
  103. if err != nil {
  104. return err
  105. }
  106. defer f.Close()
  107. s := bufio.NewScanner(f)
  108. for s.Scan() {
  109. if strings.Contains(s.Text(), "aufs") {
  110. return nil
  111. }
  112. }
  113. return ErrAufsNotSupported
  114. }
  115. func (a *Driver) rootPath() string {
  116. return a.root
  117. }
  118. func (*Driver) String() string {
  119. return "aufs"
  120. }
  121. func (a *Driver) Status() [][2]string {
  122. ids, _ := loadIds(path.Join(a.rootPath(), "layers"))
  123. return [][2]string{
  124. {"Root Dir", a.rootPath()},
  125. {"Dirs", fmt.Sprintf("%d", len(ids))},
  126. }
  127. }
  128. // Exists returns true if the given id is registered with
  129. // this driver
  130. func (a *Driver) Exists(id string) bool {
  131. if _, err := os.Lstat(path.Join(a.rootPath(), "layers", id)); err != nil {
  132. return false
  133. }
  134. return true
  135. }
  136. // Three folders are created for each id
  137. // mnt, layers, and diff
  138. func (a *Driver) Create(id, parent string) error {
  139. if err := a.createDirsFor(id); err != nil {
  140. return err
  141. }
  142. // Write the layers metadata
  143. f, err := os.Create(path.Join(a.rootPath(), "layers", id))
  144. if err != nil {
  145. return err
  146. }
  147. defer f.Close()
  148. if parent != "" {
  149. ids, err := getParentIds(a.rootPath(), parent)
  150. if err != nil {
  151. return err
  152. }
  153. if _, err := fmt.Fprintln(f, parent); err != nil {
  154. return err
  155. }
  156. for _, i := range ids {
  157. if _, err := fmt.Fprintln(f, i); err != nil {
  158. return err
  159. }
  160. }
  161. }
  162. return nil
  163. }
  164. func (a *Driver) createDirsFor(id string) error {
  165. paths := []string{
  166. "mnt",
  167. "diff",
  168. }
  169. for _, p := range paths {
  170. if err := os.MkdirAll(path.Join(a.rootPath(), p, id), 0755); err != nil {
  171. return err
  172. }
  173. }
  174. return nil
  175. }
  176. // Unmount and remove the dir information
  177. func (a *Driver) Remove(id string) error {
  178. // Protect the a.active from concurrent access
  179. a.Lock()
  180. defer a.Unlock()
  181. if a.active[id] != 0 {
  182. log.Errorf("Warning: removing active id %s", id)
  183. }
  184. // Make sure the dir is umounted first
  185. if err := a.unmount(id); err != nil {
  186. return err
  187. }
  188. tmpDirs := []string{
  189. "mnt",
  190. "diff",
  191. }
  192. // Atomically remove each directory in turn by first moving it out of the
  193. // way (so that docker doesn't find it anymore) before doing removal of
  194. // the whole tree.
  195. for _, p := range tmpDirs {
  196. realPath := path.Join(a.rootPath(), p, id)
  197. tmpPath := path.Join(a.rootPath(), p, fmt.Sprintf("%s-removing", id))
  198. if err := os.Rename(realPath, tmpPath); err != nil && !os.IsNotExist(err) {
  199. return err
  200. }
  201. defer os.RemoveAll(tmpPath)
  202. }
  203. // Remove the layers file for the id
  204. if err := os.Remove(path.Join(a.rootPath(), "layers", id)); err != nil && !os.IsNotExist(err) {
  205. return err
  206. }
  207. return nil
  208. }
  209. // Return the rootfs path for the id
  210. // This will mount the dir at it's given path
  211. func (a *Driver) Get(id, mountLabel string) (string, error) {
  212. ids, err := getParentIds(a.rootPath(), id)
  213. if err != nil {
  214. if !os.IsNotExist(err) {
  215. return "", err
  216. }
  217. ids = []string{}
  218. }
  219. // Protect the a.active from concurrent access
  220. a.Lock()
  221. defer a.Unlock()
  222. count := a.active[id]
  223. // If a dir does not have a parent ( no layers )do not try to mount
  224. // just return the diff path to the data
  225. out := path.Join(a.rootPath(), "diff", id)
  226. if len(ids) > 0 {
  227. out = path.Join(a.rootPath(), "mnt", id)
  228. if count == 0 {
  229. if err := a.mount(id, mountLabel); err != nil {
  230. return "", err
  231. }
  232. }
  233. }
  234. a.active[id] = count + 1
  235. return out, nil
  236. }
  237. func (a *Driver) Put(id string) error {
  238. // Protect the a.active from concurrent access
  239. a.Lock()
  240. defer a.Unlock()
  241. if count := a.active[id]; count > 1 {
  242. a.active[id] = count - 1
  243. } else {
  244. ids, _ := getParentIds(a.rootPath(), id)
  245. // We only mounted if there are any parents
  246. if ids != nil && len(ids) > 0 {
  247. a.unmount(id)
  248. }
  249. delete(a.active, id)
  250. }
  251. return nil
  252. }
  253. // Diff produces an archive of the changes between the specified
  254. // layer and its parent layer which may be "".
  255. func (a *Driver) Diff(id, parent string) (archive.Archive, error) {
  256. // AUFS doesn't need the parent layer to produce a diff.
  257. return archive.TarWithOptions(path.Join(a.rootPath(), "diff", id), &archive.TarOptions{
  258. Compression: archive.Uncompressed,
  259. ExcludePatterns: []string{".wh..wh.*"},
  260. })
  261. }
  262. func (a *Driver) applyDiff(id string, diff archive.ArchiveReader) error {
  263. return chrootarchive.Untar(diff, path.Join(a.rootPath(), "diff", id), nil)
  264. }
  265. // DiffSize calculates the changes between the specified id
  266. // and its parent and returns the size in bytes of the changes
  267. // relative to its base filesystem directory.
  268. func (a *Driver) DiffSize(id, parent string) (size int64, err error) {
  269. // AUFS doesn't need the parent layer to calculate the diff size.
  270. return utils.TreeSize(path.Join(a.rootPath(), "diff", id))
  271. }
  272. // ApplyDiff extracts the changeset from the given diff into the
  273. // layer with the specified id and parent, returning the size of the
  274. // new layer in bytes.
  275. func (a *Driver) ApplyDiff(id, parent string, diff archive.ArchiveReader) (size int64, err error) {
  276. // AUFS doesn't need the parent id to apply the diff.
  277. if err = a.applyDiff(id, diff); err != nil {
  278. return
  279. }
  280. return a.DiffSize(id, parent)
  281. }
  282. // Changes produces a list of changes between the specified layer
  283. // and its parent layer. If parent is "", then all changes will be ADD changes.
  284. func (a *Driver) Changes(id, parent string) ([]archive.Change, error) {
  285. // AUFS doesn't have snapshots, so we need to get changes from all parent
  286. // layers.
  287. layers, err := a.getParentLayerPaths(id)
  288. if err != nil {
  289. return nil, err
  290. }
  291. return archive.Changes(layers, path.Join(a.rootPath(), "diff", id))
  292. }
  293. func (a *Driver) getParentLayerPaths(id string) ([]string, error) {
  294. parentIds, err := getParentIds(a.rootPath(), id)
  295. if err != nil {
  296. return nil, err
  297. }
  298. layers := make([]string, len(parentIds))
  299. // Get the diff paths for all the parent ids
  300. for i, p := range parentIds {
  301. layers[i] = path.Join(a.rootPath(), "diff", p)
  302. }
  303. return layers, nil
  304. }
  305. func (a *Driver) mount(id, mountLabel string) error {
  306. // If the id is mounted or we get an error return
  307. if mounted, err := a.mounted(id); err != nil || mounted {
  308. return err
  309. }
  310. var (
  311. target = path.Join(a.rootPath(), "mnt", id)
  312. rw = path.Join(a.rootPath(), "diff", id)
  313. )
  314. layers, err := a.getParentLayerPaths(id)
  315. if err != nil {
  316. return err
  317. }
  318. if err := a.aufsMount(layers, rw, target, mountLabel); err != nil {
  319. return err
  320. }
  321. return nil
  322. }
  323. func (a *Driver) unmount(id string) error {
  324. if mounted, err := a.mounted(id); err != nil || !mounted {
  325. return err
  326. }
  327. target := path.Join(a.rootPath(), "mnt", id)
  328. return Unmount(target)
  329. }
  330. func (a *Driver) mounted(id string) (bool, error) {
  331. target := path.Join(a.rootPath(), "mnt", id)
  332. return mountpk.Mounted(target)
  333. }
  334. // During cleanup aufs needs to unmount all mountpoints
  335. func (a *Driver) Cleanup() error {
  336. ids, err := loadIds(path.Join(a.rootPath(), "layers"))
  337. if err != nil {
  338. return err
  339. }
  340. for _, id := range ids {
  341. if err := a.unmount(id); err != nil {
  342. log.Errorf("Unmounting %s: %s", utils.TruncateID(id), err)
  343. }
  344. }
  345. return mountpk.Unmount(a.root)
  346. }
  347. func (a *Driver) aufsMount(ro []string, rw, target, mountLabel string) (err error) {
  348. defer func() {
  349. if err != nil {
  350. Unmount(target)
  351. }
  352. }()
  353. // Mount options are clipped to page size(4096 bytes). If there are more
  354. // layers then these are remounted individually using append.
  355. b := make([]byte, syscall.Getpagesize()-len(mountLabel)-50) // room for xino & mountLabel
  356. bp := copy(b, fmt.Sprintf("br:%s=rw", rw))
  357. firstMount := true
  358. i := 0
  359. for {
  360. for ; i < len(ro); i++ {
  361. layer := fmt.Sprintf(":%s=ro+wh", ro[i])
  362. if firstMount {
  363. if bp+len(layer) > len(b) {
  364. break
  365. }
  366. bp += copy(b[bp:], layer)
  367. } else {
  368. data := label.FormatMountLabel(fmt.Sprintf("append%s", layer), mountLabel)
  369. if err = mount("none", target, "aufs", MsRemount, data); err != nil {
  370. return
  371. }
  372. }
  373. }
  374. if firstMount {
  375. data := label.FormatMountLabel(fmt.Sprintf("%s,xino=/dev/shm/aufs.xino", string(b[:bp])), mountLabel)
  376. if err = mount("none", target, "aufs", 0, data); err != nil {
  377. return
  378. }
  379. firstMount = false
  380. }
  381. if i == len(ro) {
  382. break
  383. }
  384. }
  385. return
  386. }