@@ -91,6 +91,8 @@ var ErrNothingToDo = errors.New("nothing to do")
9191
9292var osutilCheckFreeSpace = osutil .CheckFreeSpace
9393
94+ const defaultDiskSpaceReservation = uint64 (5 * 1024 * 1024 )
95+
9496// TestingLeaveOutKernelUpdateGadgetAssets can be used to simulate an upgrade
9597// from a broken snapd that does not generate a "update-gadget-assets" task.
9698// See LP:#1940553
@@ -172,9 +174,23 @@ func ShouldSendNotificationsToTheUser(st *state.State) (bool, error) {
172174 return true , nil
173175}
174176
175- // safetyMarginDiskSpace returns size plus a safety margin (5Mb)
176- func safetyMarginDiskSpace (size uint64 ) uint64 {
177- return size + 5 * 1024 * 1024
177+ func diskSpaceReservation (tr * config.Transaction ) uint64 {
178+ var reservation string
179+ err := tr .Get ("core" , "system.disk-space-reservation" , & reservation )
180+ if config .IsNoOption (err ) {
181+ // TODO: decide how unset system.disk-space-reservation should behave when
182+ // the experimental disk space feature flags are graduated.
183+ return defaultDiskSpaceReservation
184+ }
185+ if err != nil {
186+ return 0
187+ }
188+
189+ parsedReservation , err := strutil .ParseByteSize (reservation )
190+ if err != nil {
191+ return 0
192+ }
193+ return uint64 (parsedReservation )
178194}
179195
180196// ConfigureSnap returns a set of tasks to configure snapName as done during installation/refresh.
@@ -891,7 +907,7 @@ func downloadTasks(
891907 if ! skipSnapDownload {
892908 // TODO:COMPS: support checking for available space for components
893909 toDownloadTo := filepath .Dir (snapsup .BlobPath ())
894- if err := checkDiskSpaceDownload ([]minimalInstallInfo {installSnapInfo {info }}, toDownloadTo ); err != nil {
910+ if err := checkDiskSpaceDownload (st , []minimalInstallInfo {installSnapInfo {info }}, toDownloadTo ); err != nil {
895911 return nil , nil , err
896912 }
897913
@@ -2506,13 +2522,18 @@ func autoRefreshPhase2(st *state.State, candidates []*refreshCandidate, flags *F
25062522 return updateTss , nil
25072523}
25082524
2509- func checkDiskSpaceDownload (infos []minimalInstallInfo , rootDir string ) error {
2525+ func checkDiskSpaceDownload (st * state.State , infos []minimalInstallInfo , rootDir string ) error {
2526+ reservation := diskSpaceReservation (config .NewTransaction (st ))
2527+ if reservation == 0 {
2528+ return nil
2529+ }
2530+
25102531 var totalSize uint64
25112532 for _ , info := range infos {
25122533 totalSize += uint64 (info .DownloadSize ())
25132534 }
25142535
2515- return checkForAvailableSpace (totalSize , infos , "download" , rootDir )
2536+ return checkForAvailableSpace (totalSize , reservation , infos , "download" , rootDir )
25162537}
25172538
25182539// checkDiskSpace checks if there is enough space for the requested snaps and their prerequisites
@@ -2538,16 +2559,21 @@ func checkDiskSpace(st *state.State, changeKind string, infos []minimalInstallIn
25382559 return nil
25392560 }
25402561
2562+ reservation := diskSpaceReservation (tr )
2563+ if reservation == 0 {
2564+ return nil
2565+ }
2566+
25412567 totalSize , err := installSize (st , infos , userID , prqt )
25422568 if err != nil {
25432569 return err
25442570 }
25452571
2546- return checkForAvailableSpace (totalSize , infos , changeKind , dirs .SnapdStateDir (dirs .GlobalRootDir ))
2572+ return checkForAvailableSpace (totalSize , reservation , infos , changeKind , dirs .SnapdStateDir (dirs .GlobalRootDir ))
25472573}
25482574
2549- func checkForAvailableSpace (totalSize uint64 , infos []minimalInstallInfo , changeKind string , rootDir string ) error {
2550- requiredSpace := safetyMarginDiskSpace ( totalSize )
2575+ func checkForAvailableSpace (totalSize , reservation uint64 , infos []minimalInstallInfo , changeKind string , rootDir string ) error {
2576+ requiredSpace := totalSize + reservation
25512577 if err := osutilCheckFreeSpace (rootDir , requiredSpace ); err != nil {
25522578 snaps := make ([]string , len (infos ))
25532579 for i , up := range infos {
@@ -3144,7 +3170,12 @@ func Remove(st *state.State, name string, revision snap.Revision, flags *RemoveF
31443170 // removeTasks() checks check-disk-space-remove feature flag, so snapshotSize
31453171 // will only be greater than 0 if the feature is enabled.
31463172 if snapshotSize > 0 {
3147- requiredSpace := safetyMarginDiskSpace (snapshotSize )
3173+ reservation := diskSpaceReservation (config .NewTransaction (st ))
3174+ if reservation == 0 {
3175+ return ts , err
3176+ }
3177+
3178+ requiredSpace := snapshotSize + reservation
31483179 path := dirs .SnapdStateDir (dirs .GlobalRootDir )
31493180 if err := osutilCheckFreeSpace (path , requiredSpace ); err != nil {
31503181 if _ , ok := err .(* osutil.NotEnoughDiskSpaceError ); ok {
@@ -3296,7 +3327,7 @@ func removeTasks(st *state.State, snapst *SnapState, removals map[string]bool, r
32963327 if err != nil && ! config .IsNoOption (err ) {
32973328 return nil , 0 , err
32983329 }
3299- if checkDiskSpaceRemove {
3330+ if checkDiskSpaceRemove && diskSpaceReservation ( tr ) != 0 {
33003331 snapshotSize , err = EstimateSnapshotSize (st , instanceName , nil )
33013332 if err != nil {
33023333 return nil , 0 , err
@@ -3579,7 +3610,12 @@ func RemoveMany(st *state.State, names []string, flags *RemoveFlags) ([]string,
35793610 // removeTasks() checks check-disk-space-remove feature flag, so totalSnapshotsSize
35803611 // will only be greater than 0 if the feature is enabled.
35813612 if totalSnapshotsSize > 0 {
3582- requiredSpace := safetyMarginDiskSpace (totalSnapshotsSize )
3613+ reservation := diskSpaceReservation (config .NewTransaction (st ))
3614+ if reservation == 0 {
3615+ return removed , tasksets , nil
3616+ }
3617+
3618+ requiredSpace := totalSnapshotsSize + reservation
35833619 if err := osutilCheckFreeSpace (path , requiredSpace ); err != nil {
35843620 if _ , ok := err .(* osutil.NotEnoughDiskSpaceError ); ok {
35853621 return nil , nil , & InsufficientSpaceError {
0 commit comments