overlay.go 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. // +build linux
  2. package overlay
  3. import (
  4. "bufio"
  5. "fmt"
  6. "io/ioutil"
  7. "os"
  8. "os/exec"
  9. "path"
  10. "sync"
  11. "syscall"
  12. log "github.com/Sirupsen/logrus"
  13. "github.com/docker/docker/daemon/graphdriver"
  14. "github.com/docker/docker/pkg/archive"
  15. "github.com/docker/docker/pkg/chrootarchive"
  16. "github.com/docker/libcontainer/label"
  17. )
  18. // This is a small wrapper over the NaiveDiffWriter that lets us have a custom
  19. // implementation of ApplyDiff()
  20. var (
  21. ErrApplyDiffFallback = fmt.Errorf("Fall back to normal ApplyDiff")
  22. )
  23. type ApplyDiffProtoDriver interface {
  24. graphdriver.ProtoDriver
  25. ApplyDiff(id, parent string, diff archive.ArchiveReader) (size int64, err error)
  26. }
  27. type naiveDiffDriverWithApply struct {
  28. graphdriver.Driver
  29. applyDiff ApplyDiffProtoDriver
  30. }
  31. func NaiveDiffDriverWithApply(driver ApplyDiffProtoDriver) graphdriver.Driver {
  32. return &naiveDiffDriverWithApply{
  33. Driver: graphdriver.NaiveDiffDriver(driver),
  34. applyDiff: driver,
  35. }
  36. }
  37. func (d *naiveDiffDriverWithApply) ApplyDiff(id, parent string, diff archive.ArchiveReader) (int64, error) {
  38. b, err := d.applyDiff.ApplyDiff(id, parent, diff)
  39. if err == ErrApplyDiffFallback {
  40. return d.Driver.ApplyDiff(id, parent, diff)
  41. }
  42. return b, err
  43. }
  44. // This backend uses the overlay union filesystem for containers
  45. // plus hard link file sharing for images.
  46. // Each container/image can have a "root" subdirectory which is a plain
  47. // filesystem hierarchy, or they can use overlay.
  48. // If they use overlay there is a "upper" directory and a "lower-id"
  49. // file, as well as "merged" and "work" directories. The "upper"
  50. // directory has the upper layer of the overlay, and "lower-id" contains
  51. // the id of the parent whose "root" directory shall be used as the lower
  52. // layer in the overlay. The overlay itself is mounted in the "merged"
  53. // directory, and the "work" dir is needed for overlay to work.
  54. // When a overlay layer is created there are two cases, either the
  55. // parent has a "root" dir, then we start out with a empty "upper"
  56. // directory overlaid on the parents root. This is typically the
  57. // case with the init layer of a container which is based on an image.
  58. // If there is no "root" in the parent, we inherit the lower-id from
  59. // the parent and start by making a copy if the parents "upper" dir.
  60. // This is typically the case for a container layer which copies
  61. // its parent -init upper layer.
  62. // Additionally we also have a custom implementation of ApplyLayer
  63. // which makes a recursive copy of the parent "root" layer using
  64. // hardlinks to share file data, and then applies the layer on top
  65. // of that. This means all child images share file (but not directory)
  66. // data with the parent.
  67. type ActiveMount struct {
  68. count int
  69. path string
  70. mounted bool
  71. }
  72. type Driver struct {
  73. home string
  74. sync.Mutex // Protects concurrent modification to active
  75. active map[string]*ActiveMount
  76. }
  77. func init() {
  78. graphdriver.Register("overlay", Init)
  79. }
  80. func Init(home string, options []string) (graphdriver.Driver, error) {
  81. if err := supportsOverlay(); err != nil {
  82. return nil, graphdriver.ErrNotSupported
  83. }
  84. // check if they are running over btrfs
  85. var buf syscall.Statfs_t
  86. if err := syscall.Statfs(path.Dir(home), &buf); err != nil {
  87. return nil, err
  88. }
  89. switch graphdriver.FsMagic(buf.Type) {
  90. case graphdriver.FsMagicBtrfs:
  91. log.Error("'overlay' is not supported over btrfs.")
  92. return nil, graphdriver.ErrIncompatibleFS
  93. case graphdriver.FsMagicAufs:
  94. log.Error("'overlay' is not supported over aufs.")
  95. return nil, graphdriver.ErrIncompatibleFS
  96. }
  97. // Create the driver home dir
  98. if err := os.MkdirAll(home, 0755); err != nil && !os.IsExist(err) {
  99. return nil, err
  100. }
  101. d := &Driver{
  102. home: home,
  103. active: make(map[string]*ActiveMount),
  104. }
  105. return NaiveDiffDriverWithApply(d), nil
  106. }
  107. func supportsOverlay() error {
  108. // We can try to modprobe overlay first before looking at
  109. // proc/filesystems for when overlay is supported
  110. exec.Command("modprobe", "overlay").Run()
  111. f, err := os.Open("/proc/filesystems")
  112. if err != nil {
  113. return err
  114. }
  115. defer f.Close()
  116. s := bufio.NewScanner(f)
  117. for s.Scan() {
  118. if s.Text() == "nodev\toverlay" {
  119. return nil
  120. }
  121. }
  122. log.Error("'overlay' not found as a supported filesystem on this host. Please ensure kernel is new enough and has overlay support loaded.")
  123. return graphdriver.ErrNotSupported
  124. }
  125. func (d *Driver) String() string {
  126. return "overlay"
  127. }
  128. func (d *Driver) Status() [][2]string {
  129. return nil
  130. }
  131. func (d *Driver) Cleanup() error {
  132. return nil
  133. }
  134. func (d *Driver) Create(id string, parent string) (retErr error) {
  135. dir := d.dir(id)
  136. if err := os.MkdirAll(path.Dir(dir), 0700); err != nil {
  137. return err
  138. }
  139. if err := os.Mkdir(dir, 0700); err != nil {
  140. return err
  141. }
  142. defer func() {
  143. // Clean up on failure
  144. if retErr != nil {
  145. os.RemoveAll(dir)
  146. }
  147. }()
  148. // Toplevel images are just a "root" dir
  149. if parent == "" {
  150. if err := os.Mkdir(path.Join(dir, "root"), 0755); err != nil {
  151. return err
  152. }
  153. return nil
  154. }
  155. parentDir := d.dir(parent)
  156. // Ensure parent exists
  157. if _, err := os.Lstat(parentDir); err != nil {
  158. return err
  159. }
  160. // If parent has a root, just do a overlay to it
  161. parentRoot := path.Join(parentDir, "root")
  162. if s, err := os.Lstat(parentRoot); err == nil {
  163. if err := os.Mkdir(path.Join(dir, "upper"), s.Mode()); err != nil {
  164. return err
  165. }
  166. if err := os.Mkdir(path.Join(dir, "work"), 0700); err != nil {
  167. return err
  168. }
  169. if err := os.Mkdir(path.Join(dir, "merged"), 0700); err != nil {
  170. return err
  171. }
  172. if err := ioutil.WriteFile(path.Join(dir, "lower-id"), []byte(parent), 0666); err != nil {
  173. return err
  174. }
  175. return nil
  176. }
  177. // Otherwise, copy the upper and the lower-id from the parent
  178. lowerId, err := ioutil.ReadFile(path.Join(parentDir, "lower-id"))
  179. if err != nil {
  180. return err
  181. }
  182. if err := ioutil.WriteFile(path.Join(dir, "lower-id"), lowerId, 0666); err != nil {
  183. return err
  184. }
  185. parentUpperDir := path.Join(parentDir, "upper")
  186. s, err := os.Lstat(parentUpperDir)
  187. if err != nil {
  188. return err
  189. }
  190. upperDir := path.Join(dir, "upper")
  191. if err := os.Mkdir(upperDir, s.Mode()); err != nil {
  192. return err
  193. }
  194. if err := os.Mkdir(path.Join(dir, "work"), 0700); err != nil {
  195. return err
  196. }
  197. if err := os.Mkdir(path.Join(dir, "merged"), 0700); err != nil {
  198. return err
  199. }
  200. return copyDir(parentUpperDir, upperDir, 0)
  201. }
  202. func (d *Driver) dir(id string) string {
  203. return path.Join(d.home, id)
  204. }
  205. func (d *Driver) Remove(id string) error {
  206. dir := d.dir(id)
  207. if _, err := os.Stat(dir); err != nil {
  208. return err
  209. }
  210. return os.RemoveAll(dir)
  211. }
  212. func (d *Driver) Get(id string, mountLabel string) (string, error) {
  213. // Protect the d.active from concurrent access
  214. d.Lock()
  215. defer d.Unlock()
  216. mount := d.active[id]
  217. if mount != nil {
  218. mount.count++
  219. return mount.path, nil
  220. } else {
  221. mount = &ActiveMount{count: 1}
  222. }
  223. dir := d.dir(id)
  224. if _, err := os.Stat(dir); err != nil {
  225. return "", err
  226. }
  227. // If id has a root, just return it
  228. rootDir := path.Join(dir, "root")
  229. if _, err := os.Stat(rootDir); err == nil {
  230. mount.path = rootDir
  231. d.active[id] = mount
  232. return mount.path, nil
  233. }
  234. lowerId, err := ioutil.ReadFile(path.Join(dir, "lower-id"))
  235. if err != nil {
  236. return "", err
  237. }
  238. lowerDir := path.Join(d.dir(string(lowerId)), "root")
  239. upperDir := path.Join(dir, "upper")
  240. workDir := path.Join(dir, "work")
  241. mergedDir := path.Join(dir, "merged")
  242. opts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", lowerDir, upperDir, workDir)
  243. if err := syscall.Mount("overlay", mergedDir, "overlay", 0, label.FormatMountLabel(opts, mountLabel)); err != nil {
  244. return "", err
  245. }
  246. mount.path = mergedDir
  247. mount.mounted = true
  248. d.active[id] = mount
  249. return mount.path, nil
  250. }
  251. func (d *Driver) Put(id string) error {
  252. // Protect the d.active from concurrent access
  253. d.Lock()
  254. defer d.Unlock()
  255. mount := d.active[id]
  256. if mount == nil {
  257. log.Debugf("Put on a non-mounted device %s", id)
  258. return nil
  259. }
  260. mount.count--
  261. if mount.count > 0 {
  262. return nil
  263. }
  264. defer delete(d.active, id)
  265. if mount.mounted {
  266. err := syscall.Unmount(mount.path, 0)
  267. if err != nil {
  268. log.Debugf("Failed to unmount %s overlay: %v", id, err)
  269. }
  270. return err
  271. }
  272. return nil
  273. }
  274. func (d *Driver) ApplyDiff(id string, parent string, diff archive.ArchiveReader) (size int64, err error) {
  275. dir := d.dir(id)
  276. if parent == "" {
  277. return 0, ErrApplyDiffFallback
  278. }
  279. parentRootDir := path.Join(d.dir(parent), "root")
  280. if _, err := os.Stat(parentRootDir); err != nil {
  281. return 0, ErrApplyDiffFallback
  282. }
  283. // We now know there is a parent, and it has a "root" directory containing
  284. // the full root filesystem. We can just hardlink it and apply the
  285. // layer. This relies on two things:
  286. // 1) ApplyDiff is only run once on a clean (no writes to upper layer) container
  287. // 2) ApplyDiff doesn't do any in-place writes to files (would break hardlinks)
  288. // These are all currently true and are not expected to break
  289. tmpRootDir, err := ioutil.TempDir(dir, "tmproot")
  290. if err != nil {
  291. return 0, err
  292. }
  293. defer func() {
  294. if err != nil {
  295. os.RemoveAll(tmpRootDir)
  296. } else {
  297. os.RemoveAll(path.Join(dir, "upper"))
  298. os.RemoveAll(path.Join(dir, "work"))
  299. os.RemoveAll(path.Join(dir, "merged"))
  300. os.RemoveAll(path.Join(dir, "lower-id"))
  301. }
  302. }()
  303. if err = copyDir(parentRootDir, tmpRootDir, CopyHardlink); err != nil {
  304. return 0, err
  305. }
  306. if size, err = chrootarchive.ApplyLayer(tmpRootDir, diff); err != nil {
  307. return 0, err
  308. }
  309. rootDir := path.Join(dir, "root")
  310. if err := os.Rename(tmpRootDir, rootDir); err != nil {
  311. return 0, err
  312. }
  313. return
  314. }
  315. func (d *Driver) Exists(id string) bool {
  316. _, err := os.Stat(d.dir(id))
  317. return err == nil
  318. }