github.com/uppal0016/docker_new@v0.0.0-20240123060250-1c98be13ac2c/daemon/graphdriver/btrfs/btrfs.go (about) 1 // +build linux 2 3 package btrfs 4 5 /* 6 #include <stdlib.h> 7 #include <dirent.h> 8 #include <btrfs/ioctl.h> 9 #include <btrfs/ctree.h> 10 11 static void set_name_btrfs_ioctl_vol_args_v2(struct btrfs_ioctl_vol_args_v2* btrfs_struct, const char* value) { 12 snprintf(btrfs_struct->name, BTRFS_SUBVOL_NAME_MAX, "%s", value); 13 } 14 */ 15 import "C" 16 17 import ( 18 "fmt" 19 "os" 20 "path" 21 "path/filepath" 22 "syscall" 23 "unsafe" 24 25 "github.com/docker/docker/daemon/graphdriver" 26 "github.com/docker/docker/pkg/idtools" 27 "github.com/docker/docker/pkg/mount" 28 "github.com/opencontainers/runc/libcontainer/label" 29 ) 30 31 func init() { 32 graphdriver.Register("btrfs", Init) 33 } 34 35 // Init returns a new BTRFS driver. 36 // An error is returned if BTRFS is not supported. 37 func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) { 38 39 fsMagic, err := graphdriver.GetFSMagic(home) 40 if err != nil { 41 return nil, err 42 } 43 44 if fsMagic != graphdriver.FsMagicBtrfs { 45 return nil, graphdriver.ErrPrerequisites 46 } 47 48 rootUID, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps) 49 if err != nil { 50 return nil, err 51 } 52 if err := idtools.MkdirAllAs(home, 0700, rootUID, rootGID); err != nil { 53 return nil, err 54 } 55 56 if err := mount.MakePrivate(home); err != nil { 57 return nil, err 58 } 59 60 driver := &Driver{ 61 home: home, 62 uidMaps: uidMaps, 63 gidMaps: gidMaps, 64 } 65 66 return graphdriver.NewNaiveDiffDriver(driver, uidMaps, gidMaps), nil 67 } 68 69 // Driver contains information about the filesystem mounted. 70 type Driver struct { 71 //root of the file system 72 home string 73 uidMaps []idtools.IDMap 74 gidMaps []idtools.IDMap 75 } 76 77 // String prints the name of the driver (btrfs). 78 func (d *Driver) String() string { 79 return "btrfs" 80 } 81 82 // Status returns current driver information in a two dimensional string array. 83 // Output contains "Build Version" and "Library Version" of the btrfs libraries used. 84 // Version information can be used to check compatibility with your kernel. 85 func (d *Driver) Status() [][2]string { 86 status := [][2]string{} 87 if bv := btrfsBuildVersion(); bv != "-" { 88 status = append(status, [2]string{"Build Version", bv}) 89 } 90 if lv := btrfsLibVersion(); lv != -1 { 91 status = append(status, [2]string{"Library Version", fmt.Sprintf("%d", lv)}) 92 } 93 return status 94 } 95 96 // GetMetadata returns empty metadata for this driver. 97 func (d *Driver) GetMetadata(id string) (map[string]string, error) { 98 return nil, nil 99 } 100 101 // Cleanup unmounts the home directory. 102 func (d *Driver) Cleanup() error { 103 return mount.Unmount(d.home) 104 } 105 106 func free(p *C.char) { 107 C.free(unsafe.Pointer(p)) 108 } 109 110 func openDir(path string) (*C.DIR, error) { 111 Cpath := C.CString(path) 112 defer free(Cpath) 113 114 dir := C.opendir(Cpath) 115 if dir == nil { 116 return nil, fmt.Errorf("Can't open dir") 117 } 118 return dir, nil 119 } 120 121 func closeDir(dir *C.DIR) { 122 if dir != nil { 123 C.closedir(dir) 124 } 125 } 126 127 func getDirFd(dir *C.DIR) uintptr { 128 return uintptr(C.dirfd(dir)) 129 } 130 131 func subvolCreate(path, name string) error { 132 dir, err := openDir(path) 133 if err != nil { 134 return err 135 } 136 defer closeDir(dir) 137 138 var args C.struct_btrfs_ioctl_vol_args 139 for i, c := range []byte(name) { 140 args.name[i] = C.char(c) 141 } 142 143 _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, getDirFd(dir), C.BTRFS_IOC_SUBVOL_CREATE, 144 uintptr(unsafe.Pointer(&args))) 145 if errno != 0 { 146 return fmt.Errorf("Failed to create btrfs subvolume: %v", errno.Error()) 147 } 148 return nil 149 } 150 151 func subvolSnapshot(src, dest, name string) error { 152 srcDir, err := openDir(src) 153 if err != nil { 154 return err 155 } 156 defer closeDir(srcDir) 157 158 destDir, err := openDir(dest) 159 if err != nil { 160 return err 161 } 162 defer closeDir(destDir) 163 164 var args C.struct_btrfs_ioctl_vol_args_v2 165 args.fd = C.__s64(getDirFd(srcDir)) 166 167 var cs = C.CString(name) 168 C.set_name_btrfs_ioctl_vol_args_v2(&args, cs) 169 C.free(unsafe.Pointer(cs)) 170 171 _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, getDirFd(destDir), C.BTRFS_IOC_SNAP_CREATE_V2, 172 uintptr(unsafe.Pointer(&args))) 173 if errno != 0 { 174 return fmt.Errorf("Failed to create btrfs snapshot: %v", errno.Error()) 175 } 176 return nil 177 } 178 179 func isSubvolume(p string) (bool, error) { 180 var bufStat syscall.Stat_t 181 if err := syscall.Lstat(p, &bufStat); err != nil { 182 return false, err 183 } 184 185 // return true if it is a btrfs subvolume 186 return bufStat.Ino == C.BTRFS_FIRST_FREE_OBJECTID, nil 187 } 188 189 func subvolDelete(dirpath, name string) error { 190 dir, err := openDir(dirpath) 191 if err != nil { 192 return err 193 } 194 defer closeDir(dir) 195 fullPath := path.Join(dirpath, name) 196 197 var args C.struct_btrfs_ioctl_vol_args 198 199 // walk the btrfs subvolumes 200 walkSubvolumes := func(p string, f os.FileInfo, err error) error { 201 if err != nil { 202 if os.IsNotExist(err) && p != fullPath { 203 // missing most likely because the path was a subvolume that got removed in the previous iteration 204 // since it's gone anyway, we don't care 205 return nil 206 } 207 return fmt.Errorf("error walking subvolumes: %v", err) 208 } 209 // we want to check children only so skip itself 210 // it will be removed after the filepath walk anyways 211 if f.IsDir() && p != fullPath { 212 sv, err := isSubvolume(p) 213 if err != nil { 214 return fmt.Errorf("Failed to test if %s is a btrfs subvolume: %v", p, err) 215 } 216 if sv { 217 if err := subvolDelete(path.Dir(p), f.Name()); err != nil { 218 return fmt.Errorf("Failed to destroy btrfs child subvolume (%s) of parent (%s): %v", p, dirpath, err) 219 } 220 } 221 } 222 return nil 223 } 224 if err := filepath.Walk(path.Join(dirpath, name), walkSubvolumes); err != nil { 225 return fmt.Errorf("Recursively walking subvolumes for %s failed: %v", dirpath, err) 226 } 227 228 // all subvolumes have been removed 229 // now remove the one originally passed in 230 for i, c := range []byte(name) { 231 args.name[i] = C.char(c) 232 } 233 _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, getDirFd(dir), C.BTRFS_IOC_SNAP_DESTROY, 234 uintptr(unsafe.Pointer(&args))) 235 if errno != 0 { 236 return fmt.Errorf("Failed to destroy btrfs snapshot %s for %s: %v", dirpath, name, errno.Error()) 237 } 238 return nil 239 } 240 241 func (d *Driver) subvolumesDir() string { 242 return path.Join(d.home, "subvolumes") 243 } 244 245 func (d *Driver) subvolumesDirID(id string) string { 246 return path.Join(d.subvolumesDir(), id) 247 } 248 249 // CreateReadWrite creates a layer that is writable for use as a container 250 // file system. 251 func (d *Driver) CreateReadWrite(id, parent, mountLabel string, storageOpt map[string]string) error { 252 return d.Create(id, parent, mountLabel, storageOpt) 253 } 254 255 // Create the filesystem with given id. 256 func (d *Driver) Create(id, parent, mountLabel string, storageOpt map[string]string) error { 257 258 if len(storageOpt) != 0 { 259 return fmt.Errorf("--storage-opt is not supported for btrfs") 260 } 261 262 subvolumes := path.Join(d.home, "subvolumes") 263 rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps) 264 if err != nil { 265 return err 266 } 267 if err := idtools.MkdirAllAs(subvolumes, 0700, rootUID, rootGID); err != nil { 268 return err 269 } 270 if parent == "" { 271 if err := subvolCreate(subvolumes, id); err != nil { 272 return err 273 } 274 } else { 275 parentDir := d.subvolumesDirID(parent) 276 st, err := os.Stat(parentDir) 277 if err != nil { 278 return err 279 } 280 if !st.IsDir() { 281 return fmt.Errorf("%s: not a directory", parentDir) 282 } 283 if err := subvolSnapshot(parentDir, subvolumes, id); err != nil { 284 return err 285 } 286 } 287 288 // if we have a remapped root (user namespaces enabled), change the created snapshot 289 // dir ownership to match 290 if rootUID != 0 || rootGID != 0 { 291 if err := os.Chown(path.Join(subvolumes, id), rootUID, rootGID); err != nil { 292 return err 293 } 294 } 295 296 return label.Relabel(path.Join(subvolumes, id), mountLabel, false) 297 } 298 299 // Remove the filesystem with given id. 300 func (d *Driver) Remove(id string) error { 301 dir := d.subvolumesDirID(id) 302 if _, err := os.Stat(dir); err != nil { 303 return err 304 } 305 if err := subvolDelete(d.subvolumesDir(), id); err != nil { 306 return err 307 } 308 if err := os.RemoveAll(dir); err != nil && !os.IsNotExist(err) { 309 return err 310 } 311 return nil 312 } 313 314 // Get the requested filesystem id. 315 func (d *Driver) Get(id, mountLabel string) (string, error) { 316 dir := d.subvolumesDirID(id) 317 st, err := os.Stat(dir) 318 if err != nil { 319 return "", err 320 } 321 322 if !st.IsDir() { 323 return "", fmt.Errorf("%s: not a directory", dir) 324 } 325 326 return dir, nil 327 } 328 329 // Put is not implemented for BTRFS as there is no cleanup required for the id. 330 func (d *Driver) Put(id string) error { 331 // Get() creates no runtime resources (like e.g. mounts) 332 // so this doesn't need to do anything. 333 return nil 334 } 335 336 // Exists checks if the id exists in the filesystem. 337 func (d *Driver) Exists(id string) bool { 338 dir := d.subvolumesDirID(id) 339 _, err := os.Stat(dir) 340 return err == nil 341 }