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