88 "strings"
99 "syscall"
1010
11+ "github.com/pkg/errors"
1112 "github.com/rs/zerolog/log"
1213
1314 "github.com/threefoldtech/zos/pkg"
@@ -174,6 +175,10 @@ func (p *btrfsPool) mounted(fs *Btrfs) (string, bool) {
174175 return "" , false
175176}
176177
178+ func (p * btrfsPool ) ID () int {
179+ return 0
180+ }
181+
177182func (p * btrfsPool ) Name () string {
178183 return p .name
179184}
@@ -182,6 +187,16 @@ func (p *btrfsPool) Path() string {
182187 return filepath .Join ("/mnt" , p .name )
183188}
184189
190+ // Limit on a pool is not supported yet
191+ func (p * btrfsPool ) Limit (size uint64 ) error {
192+ return fmt .Errorf ("not implemented" )
193+ }
194+
195+ // FsType of the filesystem of this volume
196+ func (p * btrfsPool ) FsType () string {
197+ return "btrfs"
198+ }
199+
185200// Mount mounts the pool in it's default mount location under /mnt/name
186201func (p * btrfsPool ) Mount () (string , error ) {
187202 ctx := context .Background ()
@@ -287,6 +302,7 @@ func (p *btrfsPool) Volumes() ([]Volume, error) {
287302
288303 for _ , sub := range subs {
289304 volumes = append (volumes , newBtrfsVolume (
305+ sub .ID ,
290306 filepath .Join (mnt , sub .Path ),
291307 p .utils ,
292308 ))
@@ -296,11 +312,17 @@ func (p *btrfsPool) Volumes() ([]Volume, error) {
296312}
297313
298314func (p * btrfsPool ) addVolume (root string ) (* btrfsVolume , error ) {
299- if err := p .utils .SubvolumeAdd (context .Background (), root ); err != nil {
315+ ctx := context .Background ()
316+ if err := p .utils .SubvolumeAdd (ctx , root ); err != nil {
317+ return nil , err
318+ }
319+
320+ volume , err := p .utils .SubvolumeInfo (ctx , root )
321+ if err != nil {
300322 return nil , err
301323 }
302324
303- return newBtrfsVolume (root , p .utils ), nil
325+ return newBtrfsVolume (volume . ID , root , p .utils ), nil
304326}
305327
306328func (p * btrfsPool ) AddVolume (name string ) (Volume , error ) {
@@ -314,7 +336,23 @@ func (p *btrfsPool) AddVolume(name string) (Volume, error) {
314336}
315337
316338func (p * btrfsPool ) removeVolume (root string ) error {
317- return p .utils .SubvolumeRemove (context .Background (), root )
339+ ctx := context .Background ()
340+
341+ info , err := p .utils .SubvolumeInfo (ctx , root )
342+ if err != nil {
343+ return err
344+ }
345+
346+ if err := p .utils .SubvolumeRemove (ctx , root ); err != nil {
347+ return err
348+ }
349+
350+ qgroupID := fmt .Sprintf ("0/%d" , info .ID )
351+ if err := p .utils .QGroupDestroy (ctx , qgroupID , p .Path ()); err != nil {
352+ return errors .Wrapf (err , "failed to delete qgroup %s" , qgroupID )
353+ }
354+
355+ return nil
318356}
319357
320358func (p * btrfsPool ) RemoveVolume (name string ) error {
@@ -357,16 +395,6 @@ func (p *btrfsPool) Usage() (usage Usage, err error) {
357395 return Usage {Size : totalSize / raidSizeDivisor [du .Data .Profile ], Used : uint64 (fsi [0 ].Used )}, nil
358396}
359397
360- // Limit on a pool is not supported yet
361- func (p * btrfsPool ) Limit (size uint64 ) error {
362- return fmt .Errorf ("not implemented" )
363- }
364-
365- // FsType of the filesystem of this volume
366- func (p * btrfsPool ) FsType () string {
367- return "btrfs"
368- }
369-
370398// Type of the physical storage used for this pool
371399func (p * btrfsPool ) Type () pkg.DeviceType {
372400 // We only create heterogenous pools for now
@@ -393,49 +421,71 @@ func (p *btrfsPool) Reserved() (uint64, error) {
393421 return total , nil
394422}
395423
424+ func (p * btrfsPool ) Maintenance () error {
425+ // this method cleans up all the unused
426+ // qgroups that could exists on a filesystem
427+
428+ volumes , err := p .Volumes ()
429+ if err != nil {
430+ return err
431+ }
432+ subVolsIDs := map [string ]struct {}{}
433+ for _ , volume := range volumes {
434+ // use the 0/X notation to match the qgroup IDs format
435+ subVolsIDs [fmt .Sprintf ("0/%d" , volume .ID ())] = struct {}{}
436+ }
437+
438+ ctx := context .Background ()
439+ qgroups , err := p .utils .QGroupList (ctx , p .Path ())
440+ if err != nil {
441+ return err
442+ }
443+
444+ for qgroupID := range qgroups {
445+ // for all qgroup that doesn't have an linked
446+ // volume, delete the qgroup
447+ _ , ok := subVolsIDs [qgroupID ]
448+ if ! ok {
449+ log .Debug ().Str ("id" , qgroupID ).Msg ("destroy qgroup" )
450+ if err := p .utils .QGroupDestroy (ctx , qgroupID , p .Path ()); err != nil {
451+ return err
452+ }
453+ }
454+ }
455+
456+ return nil
457+ }
458+
396459type btrfsVolume struct {
460+ id int
397461 path string
398462 utils * BtrfsUtil
399463}
400464
401- func newBtrfsVolume (path string , utils * BtrfsUtil ) * btrfsVolume {
465+ func newBtrfsVolume (ID int , path string , utils * BtrfsUtil ) * btrfsVolume {
402466 return & btrfsVolume {
467+ id : ID ,
403468 path : path ,
404469 utils : utils ,
405470 }
406471}
407472
408- func (v * btrfsVolume ) Path () string {
409- return v .path
473+ func (v * btrfsVolume ) ID () int {
474+ return v .id
410475}
411476
412- func (v * btrfsVolume ) Volumes () ([]Volume , error ) {
413- var volumes []Volume
414-
415- subs , err := v .utils .SubvolumeList (context .Background (), v .Path ())
416- if err != nil {
417- return nil , err
418- }
419-
420- for _ , sub := range subs {
421- volumes = append (volumes , newBtrfsVolume (filepath .Join (v .Path (), sub .Path ), v .utils ))
422- }
423-
424- return volumes , nil
477+ func (v * btrfsVolume ) Path () string {
478+ return v .path
425479}
426480
427- func (v * btrfsVolume ) AddVolume (name string ) (Volume , error ) {
428- mnt := filepath .Join (v .Path (), name )
429- if err := v .utils .SubvolumeAdd (context .Background (), mnt ); err != nil {
430- return nil , err
431- }
432-
433- return newBtrfsVolume (mnt , v .utils ), nil
481+ // Name of the filesystem
482+ func (v * btrfsVolume ) Name () string {
483+ return filepath .Base (v .Path ())
434484}
435485
436- func ( v * btrfsVolume ) RemoveVolume ( name string ) error {
437- mnt := filepath . Join ( v . Path (), name )
438- return v . utils . SubvolumeRemove ( context . Background (), mnt )
486+ // FsType of the filesystem
487+ func ( v * btrfsVolume ) FsType () string {
488+ return "btrfs"
439489}
440490
441491// Usage return the volume usage
@@ -470,13 +520,3 @@ func (v *btrfsVolume) Limit(size uint64) error {
470520
471521 return v .utils .QGroupLimit (ctx , size , v .Path ())
472522}
473-
474- // Name of the filesystem
475- func (v * btrfsVolume ) Name () string {
476- return filepath .Base (v .Path ())
477- }
478-
479- // FsType of the filesystem
480- func (v * btrfsVolume ) FsType () string {
481- return "btrfs"
482- }
0 commit comments