package graphdriver import ( "errors" "fmt" "os" "path" "strings" log "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/archive" ) type FsMagic uint32 const ( FsMagicBtrfs = FsMagic(0x9123683E) FsMagicAufs = FsMagic(0x61756673) FsMagicExtfs = FsMagic(0x0000EF53) FsMagicCramfs = FsMagic(0x28cd3d45) FsMagicRamFs = FsMagic(0x858458f6) FsMagicTmpFs = FsMagic(0x01021994) FsMagicSquashFs = FsMagic(0x73717368) FsMagicNfsFs = FsMagic(0x00006969) FsMagicReiserFs = FsMagic(0x52654973) FsMagicSmbFs = FsMagic(0x0000517B) FsMagicJffs2Fs = FsMagic(0x000072b6) FsMagicZfs = FsMagic(0x2fc12fc1) FsMagicXfs = FsMagic(0x58465342) FsMagicUnsupported = FsMagic(0x00000000) ) var ( DefaultDriver string // All registred drivers drivers map[string]InitFunc // Slice of drivers that should be used in an order priority = []string{ "aufs", "btrfs", "devicemapper", "vfs", // experimental, has to be enabled manually for now "overlay", } ErrNotSupported = errors.New("driver not supported") ErrPrerequisites = errors.New("prerequisites for driver not satisfied (wrong filesystem?)") ErrIncompatibleFS = fmt.Errorf("backing file system is unsupported for this graph driver") FsNames = map[FsMagic]string{ FsMagicAufs: "aufs", FsMagicBtrfs: "btrfs", FsMagicExtfs: "extfs", FsMagicCramfs: "cramfs", FsMagicRamFs: "ramfs", FsMagicTmpFs: "tmpfs", FsMagicSquashFs: "squashfs", FsMagicNfsFs: "nfs", FsMagicReiserFs: "reiserfs", FsMagicSmbFs: "smb", FsMagicJffs2Fs: "jffs2", FsMagicZfs: "zfs", FsMagicXfs: "xfs", FsMagicUnsupported: "unsupported", } ) type InitFunc func(root string, options []string) (Driver, error) // ProtoDriver defines the basic capabilities of a driver. // This interface exists solely to be a minimum set of methods // for client code which choose not to implement the entire Driver // interface and use the NaiveDiffDriver wrapper constructor. // // Use of ProtoDriver directly by client code is not recommended. type ProtoDriver interface { // String returns a string representation of this driver. String() string // Create creates a new, empty, filesystem layer with the // specified id and parent. Parent may be "". Create(id, parent string) error // Remove attempts to remove the filesystem layer with this id. Remove(id string) error // Get returns the mountpoint for the layered filesystem referred // to by this id. You can optionally specify a mountLabel or "". // Returns the absolute path to the mounted layered filesystem. Get(id, mountLabel string) (dir string, err error) // Put releases the system resources for the specified id, // e.g, unmounting layered filesystem. Put(id string) error // Exists returns whether a filesystem layer with the specified // ID exists on this driver. Exists(id string) bool // Status returns a set of key-value pairs which give low // level diagnostic status about this driver. Status() [][2]string // Cleanup performs necessary tasks to release resources // held by the driver, e.g., unmounting all layered filesystems // known to this driver. Cleanup() error } // Driver is the interface for layered/snapshot file system drivers. type Driver interface { ProtoDriver // Diff produces an archive of the changes between the specified // layer and its parent layer which may be "". Diff(id, parent string) (archive.Archive, error) // Changes produces a list of changes between the specified layer // and its parent layer. If parent is "", then all changes will be ADD changes. Changes(id, parent string) ([]archive.Change, error) // ApplyDiff extracts the changeset from the given diff into the // layer with the specified id and parent, returning the size of the // new layer in bytes. ApplyDiff(id, parent string, diff archive.ArchiveReader) (size int64, err error) // DiffSize calculates the changes between the specified id // and its parent and returns the size in bytes of the changes // relative to its base filesystem directory. DiffSize(id, parent string) (size int64, err error) } func init() { drivers = make(map[string]InitFunc) } func Register(name string, initFunc InitFunc) error { if _, exists := drivers[name]; exists { return fmt.Errorf("Name already registered %s", name) } drivers[name] = initFunc return nil } func GetDriver(name, home string, options []string) (Driver, error) { if initFunc, exists := drivers[name]; exists { return initFunc(path.Join(home, name), options) } return nil, ErrNotSupported } func New(root string, options []string) (driver Driver, err error) { for _, name := range []string{os.Getenv("DOCKER_DRIVER"), DefaultDriver} { if name != "" { return GetDriver(name, root, options) } } // Check for priority drivers first for _, name := range priority { driver, err = GetDriver(name, root, options) if err != nil { if err == ErrNotSupported || err == ErrPrerequisites || err == ErrIncompatibleFS { continue } return nil, err } checkPriorDriver(name, root) return driver, nil } // Check all registered drivers if no priority driver is found for name, initFunc := range drivers { if driver, err = initFunc(root, options); err != nil { if err == ErrNotSupported || err == ErrPrerequisites || err == ErrIncompatibleFS { continue } return nil, err } checkPriorDriver(name, root) return driver, nil } return nil, fmt.Errorf("No supported storage backend found") } func checkPriorDriver(name, root string) { priorDrivers := []string{} for prior := range drivers { if prior != name && prior != "vfs" { if _, err := os.Stat(path.Join(root, prior)); err == nil { priorDrivers = append(priorDrivers, prior) } } } if len(priorDrivers) > 0 { log.Warnf("Graphdriver %s selected. Your graphdriver directory %s already contains data managed by other graphdrivers: %s", name, root, strings.Join(priorDrivers, ",")) } }