github.com/codemac/docker@v1.2.1-0.20150518222241-6a18412d5b9c/daemon/graphdriver/driver.go (about) 1 package graphdriver 2 3 import ( 4 "errors" 5 "fmt" 6 "os" 7 "path" 8 "strings" 9 10 "github.com/Sirupsen/logrus" 11 "github.com/docker/docker/pkg/archive" 12 ) 13 14 type FsMagic uint32 15 16 const ( 17 FsMagicAufs = FsMagic(0x61756673) 18 FsMagicBtrfs = FsMagic(0x9123683E) 19 FsMagicCramfs = FsMagic(0x28cd3d45) 20 FsMagicExtfs = FsMagic(0x0000EF53) 21 FsMagicF2fs = FsMagic(0xF2F52010) 22 FsMagicJffs2Fs = FsMagic(0x000072b6) 23 FsMagicJfs = FsMagic(0x3153464a) 24 FsMagicNfsFs = FsMagic(0x00006969) 25 FsMagicRamFs = FsMagic(0x858458f6) 26 FsMagicReiserFs = FsMagic(0x52654973) 27 FsMagicSmbFs = FsMagic(0x0000517B) 28 FsMagicSquashFs = FsMagic(0x73717368) 29 FsMagicTmpFs = FsMagic(0x01021994) 30 FsMagicUnsupported = FsMagic(0x00000000) 31 FsMagicXfs = FsMagic(0x58465342) 32 FsMagicZfs = FsMagic(0x2fc12fc1) 33 ) 34 35 var ( 36 DefaultDriver string 37 // All registred drivers 38 drivers map[string]InitFunc 39 // Slice of drivers that should be used in an order 40 priority = []string{ 41 "aufs", 42 "btrfs", 43 "zfs", 44 "devicemapper", 45 "overlay", 46 "vfs", 47 } 48 49 ErrNotSupported = errors.New("driver not supported") 50 ErrPrerequisites = errors.New("prerequisites for driver not satisfied (wrong filesystem?)") 51 ErrIncompatibleFS = fmt.Errorf("backing file system is unsupported for this graph driver") 52 53 FsNames = map[FsMagic]string{ 54 FsMagicAufs: "aufs", 55 FsMagicBtrfs: "btrfs", 56 FsMagicCramfs: "cramfs", 57 FsMagicExtfs: "extfs", 58 FsMagicF2fs: "f2fs", 59 FsMagicJffs2Fs: "jffs2", 60 FsMagicJfs: "jfs", 61 FsMagicNfsFs: "nfs", 62 FsMagicRamFs: "ramfs", 63 FsMagicReiserFs: "reiserfs", 64 FsMagicSmbFs: "smb", 65 FsMagicSquashFs: "squashfs", 66 FsMagicTmpFs: "tmpfs", 67 FsMagicUnsupported: "unsupported", 68 FsMagicXfs: "xfs", 69 FsMagicZfs: "zfs", 70 } 71 ) 72 73 type InitFunc func(root string, options []string) (Driver, error) 74 75 // ProtoDriver defines the basic capabilities of a driver. 76 // This interface exists solely to be a minimum set of methods 77 // for client code which choose not to implement the entire Driver 78 // interface and use the NaiveDiffDriver wrapper constructor. 79 // 80 // Use of ProtoDriver directly by client code is not recommended. 81 type ProtoDriver interface { 82 // String returns a string representation of this driver. 83 String() string 84 // Create creates a new, empty, filesystem layer with the 85 // specified id and parent. Parent may be "". 86 Create(id, parent string) error 87 // Remove attempts to remove the filesystem layer with this id. 88 Remove(id string) error 89 // Get returns the mountpoint for the layered filesystem referred 90 // to by this id. You can optionally specify a mountLabel or "". 91 // Returns the absolute path to the mounted layered filesystem. 92 Get(id, mountLabel string) (dir string, err error) 93 // Put releases the system resources for the specified id, 94 // e.g, unmounting layered filesystem. 95 Put(id string) error 96 // Exists returns whether a filesystem layer with the specified 97 // ID exists on this driver. 98 Exists(id string) bool 99 // Status returns a set of key-value pairs which give low 100 // level diagnostic status about this driver. 101 Status() [][2]string 102 // Cleanup performs necessary tasks to release resources 103 // held by the driver, e.g., unmounting all layered filesystems 104 // known to this driver. 105 Cleanup() error 106 } 107 108 // Driver is the interface for layered/snapshot file system drivers. 109 type Driver interface { 110 ProtoDriver 111 // Diff produces an archive of the changes between the specified 112 // layer and its parent layer which may be "". 113 Diff(id, parent string) (archive.Archive, error) 114 // Changes produces a list of changes between the specified layer 115 // and its parent layer. If parent is "", then all changes will be ADD changes. 116 Changes(id, parent string) ([]archive.Change, error) 117 // ApplyDiff extracts the changeset from the given diff into the 118 // layer with the specified id and parent, returning the size of the 119 // new layer in bytes. 120 ApplyDiff(id, parent string, diff archive.ArchiveReader) (size int64, err error) 121 // DiffSize calculates the changes between the specified id 122 // and its parent and returns the size in bytes of the changes 123 // relative to its base filesystem directory. 124 DiffSize(id, parent string) (size int64, err error) 125 } 126 127 func init() { 128 drivers = make(map[string]InitFunc) 129 } 130 131 func Register(name string, initFunc InitFunc) error { 132 if _, exists := drivers[name]; exists { 133 return fmt.Errorf("Name already registered %s", name) 134 } 135 drivers[name] = initFunc 136 137 return nil 138 } 139 140 func GetDriver(name, home string, options []string) (Driver, error) { 141 if initFunc, exists := drivers[name]; exists { 142 return initFunc(path.Join(home, name), options) 143 } 144 return nil, ErrNotSupported 145 } 146 147 func New(root string, options []string) (driver Driver, err error) { 148 for _, name := range []string{os.Getenv("DOCKER_DRIVER"), DefaultDriver} { 149 if name != "" { 150 logrus.Debugf("[graphdriver] trying provided driver %q", name) // so the logs show specified driver 151 return GetDriver(name, root, options) 152 } 153 } 154 155 // Guess for prior driver 156 priorDrivers := scanPriorDrivers(root) 157 for _, name := range priority { 158 if name == "vfs" { 159 // don't use vfs even if there is state present. 160 continue 161 } 162 for _, prior := range priorDrivers { 163 // of the state found from prior drivers, check in order of our priority 164 // which we would prefer 165 if prior == name { 166 driver, err = GetDriver(name, root, options) 167 if err != nil { 168 // unlike below, we will return error here, because there is prior 169 // state, and now it is no longer supported/prereq/compatible, so 170 // something changed and needs attention. Otherwise the daemon's 171 // images would just "disappear". 172 logrus.Errorf("[graphdriver] prior storage driver %q failed: %s", name, err) 173 return nil, err 174 } 175 if err := checkPriorDriver(name, root); err != nil { 176 return nil, err 177 } 178 logrus.Infof("[graphdriver] using prior storage driver %q", name) 179 return driver, nil 180 } 181 } 182 } 183 184 // Check for priority drivers first 185 for _, name := range priority { 186 driver, err = GetDriver(name, root, options) 187 if err != nil { 188 if err == ErrNotSupported || err == ErrPrerequisites || err == ErrIncompatibleFS { 189 continue 190 } 191 return nil, err 192 } 193 return driver, nil 194 } 195 196 // Check all registered drivers if no priority driver is found 197 for _, initFunc := range drivers { 198 if driver, err = initFunc(root, options); err != nil { 199 if err == ErrNotSupported || err == ErrPrerequisites || err == ErrIncompatibleFS { 200 continue 201 } 202 return nil, err 203 } 204 return driver, nil 205 } 206 return nil, fmt.Errorf("No supported storage backend found") 207 } 208 209 // scanPriorDrivers returns an un-ordered scan of directories of prior storage drivers 210 func scanPriorDrivers(root string) []string { 211 priorDrivers := []string{} 212 for driver := range drivers { 213 p := path.Join(root, driver) 214 if _, err := os.Stat(p); err == nil { 215 priorDrivers = append(priorDrivers, driver) 216 } 217 } 218 return priorDrivers 219 } 220 221 func checkPriorDriver(name, root string) error { 222 priorDrivers := []string{} 223 for _, prior := range scanPriorDrivers(root) { 224 if prior != name && prior != "vfs" { 225 if _, err := os.Stat(path.Join(root, prior)); err == nil { 226 priorDrivers = append(priorDrivers, prior) 227 } 228 } 229 } 230 231 if len(priorDrivers) > 0 { 232 233 return errors.New(fmt.Sprintf("%q contains other graphdrivers: %s; Please cleanup or explicitly choose storage driver (-s <DRIVER>)", root, strings.Join(priorDrivers, ","))) 234 } 235 return nil 236 }