From 290a4cf9455f45895718ed698147061fcd0a2dcb Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Thu, 17 Dec 2020 13:20:53 +0100 Subject: depcache: Cache our InRootSetFunc This avoids the cost of setting up the function every time we mark and sweep. --- apt-pkg/depcache.cc | 26 +++++++++++++++++++------- apt-pkg/depcache.h | 6 +++++- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/apt-pkg/depcache.cc b/apt-pkg/depcache.cc index c7ef7a400..3c9695d56 100644 --- a/apt-pkg/depcache.cc +++ b/apt-pkg/depcache.cc @@ -95,10 +95,14 @@ pkgDepCache::ActionGroup::~ActionGroup() // DepCache::pkgDepCache - Constructors /*{{{*/ // --------------------------------------------------------------------- /* */ -pkgDepCache::pkgDepCache(pkgCache * const pCache,Policy * const Plcy) : - group_level(0), Cache(pCache), PkgState(0), DepState(0), - iUsrSize(0), iDownloadSize(0), iInstCount(0), iDelCount(0), iKeepCount(0), - iBrokenCount(0), iPolicyBrokenCount(0), iBadCount(0), d(NULL) + +struct pkgDepCache::Private +{ + std::unique_ptr inRootSetFunc; +}; +pkgDepCache::pkgDepCache(pkgCache *const pCache, Policy *const Plcy) : group_level(0), Cache(pCache), PkgState(0), DepState(0), + iUsrSize(0), iDownloadSize(0), iInstCount(0), iDelCount(0), iKeepCount(0), + iBrokenCount(0), iPolicyBrokenCount(0), iBadCount(0), d(new Private) { DebugMarker = _config->FindB("Debug::pkgDepCache::Marker", false); DebugAutoInstall = _config->FindB("Debug::pkgDepCache::AutoInstall", false); @@ -116,6 +120,7 @@ pkgDepCache::~pkgDepCache() delete [] PkgState; delete [] DepState; delete delLocalPolicy; + delete d; } /*}}}*/ bool pkgDepCache::CheckConsistency(char const *const msgtag) /*{{{*/ @@ -2157,6 +2162,13 @@ pkgDepCache::InRootSetFunc *pkgDepCache::GetRootSetFunc() /*{{{*/ return NULL; } } + +pkgDepCache::InRootSetFunc *pkgDepCache::GetCachedRootSetFunc() +{ + if (d->inRootSetFunc == nullptr) + d->inRootSetFunc.reset(GetRootSetFunc()); + return d->inRootSetFunc.get(); +} /*}}}*/ bool pkgDepCache::MarkFollowsRecommends() { @@ -2369,9 +2381,9 @@ bool pkgDepCache::MarkAndSweep(InRootSetFunc &rootFunc) } bool pkgDepCache::MarkAndSweep() { - std::unique_ptr f(GetRootSetFunc()); - if(f.get() != NULL) - return MarkAndSweep(*f.get()); + InRootSetFunc *f(GetCachedRootSetFunc()); + if (f != NULL) + return MarkAndSweep(*f); else return false; } diff --git a/apt-pkg/depcache.h b/apt-pkg/depcache.h index 78f88ba2f..9a6019092 100644 --- a/apt-pkg/depcache.h +++ b/apt-pkg/depcache.h @@ -380,6 +380,9 @@ class APT_PUBLIC pkgDepCache : protected pkgCache::Namespace */ virtual InRootSetFunc *GetRootSetFunc(); + /** This should return const really - do not delete. */ + InRootSetFunc *GetCachedRootSetFunc() APT_HIDDEN; + /** \return \b true if the garbage collector should follow recommendations. */ virtual bool MarkFollowsRecommends(); @@ -516,7 +519,8 @@ class APT_PUBLIC pkgDepCache : protected pkgCache::Namespace bool const rPurge, unsigned long const Depth, bool const FromUser); private: - void * const d; + struct Private; + Private *const d; APT_HIDDEN bool MarkInstall_StateChange(PkgIterator const &Pkg, bool AutoInst, bool FromUser); APT_HIDDEN bool MarkInstall_DiscardInstall(PkgIterator const &Pkg); -- cgit v1.2.3 From 04085f46dea9a95dd86123ac00187a63cc4ba2c0 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Thu, 17 Dec 2020 13:24:56 +0100 Subject: Determine autoremovable kernels at run-time Our kernel autoremoval helper script protects the currently booted kernel, but it only runs whenever we install or remove a kernel, causing it to protect the kernel that was booted at that point in time, which is not necessarily the same kernel as the one that is running right now. Reimplement the logic in C++ such that we can calculate it at run-time: Provide a function to produce a regular expression that matches all kernels that need protecting, and by changing the default root set function in the DepCache to make use of that expression. Note that the code groups the kernels by versions as before, and then marks all kernel packages with the same version. This optimized version inserts a virtual package $kernel into the cache when building it to avoid having to iterate over all packages in the cache to find the installed ones, significantly improving performance at a minor cost when building the cache. LP: #1615381 --- apt-pkg/algorithms.cc | 183 +++++++++++++++++++++++++ apt-pkg/algorithms.h | 14 ++ apt-pkg/deb/deblistparser.cc | 8 +- apt-pkg/depcache.cc | 30 +++- debian/apt.auto-removal.sh | 69 +--------- doc/examples/configure-index | 3 + test/integration/test-kernel-helper-autoremove | 15 +- 7 files changed, 239 insertions(+), 83 deletions(-) diff --git a/apt-pkg/algorithms.cc b/apt-pkg/algorithms.cc index cd09a6944..702030943 100644 --- a/apt-pkg/algorithms.cc +++ b/apt-pkg/algorithms.cc @@ -16,20 +16,32 @@ #include #include +#include #include #include #include #include #include +#include #include #include +#include +#include +#include + #include #include #include +#include +#include +#include +#include #include #include +#include #include +#include #include /*}}}*/ @@ -1442,3 +1454,174 @@ void pkgPrioSortList(pkgCache &Cache,pkgCache::Version **List) std::sort(List,List+Count,PrioComp(Cache)); } /*}}}*/ + +namespace APT +{ + +namespace KernelAutoRemoveHelper +{ + +// \brief Returns the uname from a kernel package name, or "" for non-kernel packages. +std::string getUname(std::string const &packageName) +{ + + static const constexpr char *const prefixes[] = { + "linux-image-", + "kfreebsd-image-", + "gnumach-image-", + }; + + for (auto prefix : prefixes) + { + if (likely(not APT::String::Startswith(packageName, prefix))) + continue; + if (unlikely(APT::String::Endswith(packageName, "-dbgsym"))) + continue; + if (unlikely(APT::String::Endswith(packageName, "-dbg"))) + continue; + + auto aUname = packageName.substr(strlen(prefix)); + + // aUname must start with [0-9]+\. + if (aUname.length() < 2) + continue; + if (strchr("0123456789", aUname[0]) == nullptr) + continue; + auto dot = aUname.find_first_not_of("0123456789"); + if (dot == aUname.npos || aUname[dot] != '.') + continue; + + return aUname; + } + + return ""; +} +std::string GetProtectedKernelsRegex(pkgCache *cache, bool ReturnRemove) +{ + if (_config->FindB("APT::Protect-Kernels", true) == false) + return ""; + + struct CompareKernel + { + pkgCache *cache; + bool operator()(const std::string &a, const std::string &b) const + { + return cache->VS->CmpVersion(a, b) < 0; + } + }; + bool Debug = _config->FindB("Debug::pkgAutoRemove", false); + // kernel version -> list of unames + std::map, CompareKernel> version2unames(CompareKernel{cache}); + // needs to be initialized to 0s, might not be set up. + utsname uts{}; + std::string bootedVersion; + std::string lastInstalledVersion; + + std::string lastInstalledUname = _config->Find("APT::LastInstalledKernel"); + + // Get currently booted version, but only when not on reproducible build. + if (getenv("SOURCE_DATE_EPOCH") == 0) + { + if (uname(&uts) != 0) + abort(); + } + + auto VirtualKernelPkg = cache->FindPkg("$kernel", "any"); + if (VirtualKernelPkg.end()) + return ""; + + for (pkgCache::PrvIterator Prv = VirtualKernelPkg.ProvidesList(); Prv.end() == false; ++Prv) + { + auto Pkg = Prv.OwnerPkg(); + if (likely(Pkg->CurrentVer == 0)) + continue; + + auto pkgUname = APT::KernelAutoRemoveHelper::getUname(Pkg.Name()); + auto pkgVersion = Pkg.CurrentVer().VerStr(); + + if (pkgUname.empty()) + continue; + + if (Debug) + std::clog << "Found kernel " << pkgUname << "(" << pkgVersion << ")" << std::endl; + + version2unames[pkgVersion].push_back(pkgUname); + + if (pkgUname == uts.release) + bootedVersion = pkgVersion; + if (pkgUname == lastInstalledUname) + lastInstalledVersion = pkgVersion; + } + + if (version2unames.size() == 0) + return ""; + + auto latest = version2unames.rbegin(); + auto previous = latest; + ++previous; + + std::set keep; + + if (not bootedVersion.empty()) + { + if (Debug || false) + std::clog << "Keeping booted kernel " << bootedVersion << std::endl; + keep.insert(bootedVersion); + } + if (not lastInstalledVersion.empty()) + { + if (Debug || false) + std::clog << "Keeping installed kernel " << lastInstalledVersion << std::endl; + keep.insert(lastInstalledVersion); + } + if (latest != version2unames.rend()) + { + if (Debug || false) + std::clog << "Keeping latest kernel " << latest->first << std::endl; + keep.insert(latest->first); + } + if (previous != version2unames.rend()) + { + if (Debug) + std::clog << "Keeping previous kernel " << previous->first << std::endl; + keep.insert(previous->first); + } + + std::regex special("([\\.\\+])"); + std::ostringstream ss; + for (auto &pattern : _config->FindVector("APT::VersionedKernelPackages")) + { + // Legacy compatibility: Always protected the booted uname and last installed uname + if (not lastInstalledUname.empty()) + ss << "|^" << pattern << "-" << std::regex_replace(lastInstalledUname, special, "\\$1") << "$"; + if (*uts.release) + ss << "|^" << pattern << "-" << std::regex_replace(uts.release, special, "\\$1") << "$"; + for (auto const &kernel : version2unames) + { + if (ReturnRemove ? keep.find(kernel.first) == keep.end() : keep.find(kernel.first) != keep.end()) + { + for (auto const &uname : kernel.second) + ss << "|^" << pattern << "-" << std::regex_replace(uname, special, "\\$1") << "$"; + } + } + } + + auto re = ss.str().substr(1); + if (Debug) + std::clog << "Kernel protection regex: " << re << "\n"; + + return re; +} + +std::unique_ptr GetProtectedKernelsFilter(pkgCache *cache, bool returnRemove) +{ + auto regex = GetProtectedKernelsRegex(cache, returnRemove); + + if (regex.empty()) + return std::make_unique(); + + return std::make_unique(regex); +} + +} // namespace KernelAutoRemoveHelper +} // namespace APT diff --git a/apt-pkg/algorithms.h b/apt-pkg/algorithms.h index fc578a4ca..12a77d4b8 100644 --- a/apt-pkg/algorithms.h +++ b/apt-pkg/algorithms.h @@ -29,11 +29,13 @@ #ifndef PKGLIB_ALGORITHMS_H #define PKGLIB_ALGORITHMS_H +#include #include #include #include #include +#include #include #include @@ -146,5 +148,17 @@ APT_PUBLIC bool pkgFixBroken(pkgDepCache &Cache); APT_PUBLIC void pkgPrioSortList(pkgCache &Cache,pkgCache::Version **List); +namespace APT +{ +namespace KernelAutoRemoveHelper +{ +// Public for linking to apt-private, but no A{P,B}I guarantee. +APT_PUBLIC std::unique_ptr GetProtectedKernelsFilter(pkgCache *cache, bool returnRemove = false); +std::string GetProtectedKernelsRegex(pkgCache *cache, bool ReturnRemove = false); +std::string getUname(std::string const &packageName); + +} // namespace KernelAutoRemoveHelper + +} // namespace APT #endif diff --git a/apt-pkg/deb/deblistparser.cc b/apt-pkg/deb/deblistparser.cc index 240946529..95f6f6fc8 100644 --- a/apt-pkg/deb/deblistparser.cc +++ b/apt-pkg/deb/deblistparser.cc @@ -11,6 +11,7 @@ // Include Files /*{{{*/ #include +#include #include #include #include @@ -246,7 +247,12 @@ bool debListParser::NewVersion(pkgCache::VerIterator &Ver) if (ParseProvides(Ver) == false) return false; - + if (not APT::KernelAutoRemoveHelper::getUname(Ver.ParentPkg().Name()).empty()) + { + if (not NewProvides(Ver, "$kernel", "any", Ver.VerStr(), pkgCache::Flag::MultiArchImplicit)) + return false; + } + return true; } /*}}}*/ diff --git a/apt-pkg/depcache.cc b/apt-pkg/depcache.cc index 3c9695d56..f2b3dbcdc 100644 --- a/apt-pkg/depcache.cc +++ b/apt-pkg/depcache.cc @@ -9,6 +9,7 @@ // Include Files /*{{{*/ #include +#include #include #include #include @@ -43,6 +44,23 @@ using std::string; +// helper for kernel autoremoval /*{{{*/ + +/** \brief Returns \b true for packages matching a regular + * expression in APT::NeverAutoRemove. + */ +class APT_PUBLIC DefaultRootSetFunc2 : public pkgDepCache::DefaultRootSetFunc +{ + std::unique_ptr Kernels; + + public: + DefaultRootSetFunc2(pkgCache *cache) : Kernels(APT::KernelAutoRemoveHelper::GetProtectedKernelsFilter(cache)){}; + virtual ~DefaultRootSetFunc2(){}; + + bool InRootSet(const pkgCache::PkgIterator &pkg) APT_OVERRIDE { return pkg.end() == false && ((*Kernels)(pkg) || DefaultRootSetFunc::InRootSet(pkg)); }; +}; + + /*}}}*/ // helper for Install-Recommends-Sections and Never-MarkAuto-Sections /*{{{*/ static bool ConfigValueInSubTree(const char* SubTree, const char *needle) @@ -2153,14 +2171,14 @@ APT_PURE signed short pkgDepCache::Policy::GetPriority(pkgCache::PkgFileIterator /*}}}*/ pkgDepCache::InRootSetFunc *pkgDepCache::GetRootSetFunc() /*{{{*/ { - DefaultRootSetFunc *f = new DefaultRootSetFunc; - if(f->wasConstructedSuccessfully()) - return f; - else - { + DefaultRootSetFunc *f = new DefaultRootSetFunc2(&GetCache()); + if (f->wasConstructedSuccessfully()) + return f; + else + { delete f; return NULL; - } + } } pkgDepCache::InRootSetFunc *pkgDepCache::GetCachedRootSetFunc() diff --git a/debian/apt.auto-removal.sh b/debian/apt.auto-removal.sh index 2c32b0c9d..eef550a53 100644 --- a/debian/apt.auto-removal.sh +++ b/debian/apt.auto-removal.sh @@ -1,82 +1,15 @@ #!/bin/sh set -e -# Mark as not-for-autoremoval those kernel packages that are: -# - the currently booted version -# - the kernel version we've been called for -# - the latest kernel version (as determined by debian version number) -# - the second-latest kernel version -# -# In the common case this results in two kernels saved (booted into the -# second-latest kernel, we install the latest kernel in an upgrade), but -# can save up to four. Kernel refers here to a distinct release, which can -# potentially be installed in multiple flavours counting as one kernel. eval $(apt-config shell APT_CONF_D Dir::Etc::parts/d) test -n "${APT_CONF_D}" || APT_CONF_D="/etc/apt/apt.conf.d" config_file="${APT_CONF_D}/01autoremove-kernels" -eval $(apt-config shell DPKG Dir::bin::dpkg/f) -test -n "$DPKG" || DPKG="/usr/bin/dpkg" - -list="$("${DPKG}" -l | awk '/^[ih][^nc][ ]+(linux|kfreebsd|gnumach)-image-[0-9]+\./ && $2 !~ /-dbg(:.*)?$/ && $2 !~ /-dbgsym(:.*)?$/ { print $2,$3; }' \ - | sed -e 's#^\(linux\|kfreebsd\|gnumach\)-image-##' -e 's#:[^:]\+ # #')" -debverlist="$(echo "$list" | cut -d' ' -f 2 | sort --unique --reverse --version-sort)" - -if [ -n "$1" ]; then - installed_version="$(echo "$list" | awk "\$1 == \"$1\" { print \$2;exit; }")" -fi -unamer="$(uname -r | tr '[A-Z]' '[a-z]')" -if [ -n "$unamer" ]; then - running_version="$(echo "$list" | awk "\$1 == \"$unamer\" { print \$2;exit; }")" -fi -# ignore the currently running version if attempting a reproducible build -if [ -n "${SOURCE_DATE_EPOCH}" ]; then - unamer="" - running_version="" -fi -latest_version="$(echo "$debverlist" | sed -n 1p)" -previous_version="$(echo "$debverlist" | sed -n 2p)" - -debkernels="$(echo "$latest_version -$installed_version -$running_version -$previous_version" | sort -u | sed -e '/^$/ d')" -kernels="$( (echo "$1 -$unamer"; for deb in $debkernels; do echo "$list" | awk "\$2 == \"$deb\" { print \$1; }"; done; ) \ - | sed -e 's#\([\.\+]\)#\\\1#g' -e '/^$/ d' | sort -u)" - generateconfig() { cat < "${config_file}.dpkg-new" mv -f "${config_file}.dpkg-new" "$config_file" diff --git a/doc/examples/configure-index b/doc/examples/configure-index index b73166082..571bf2369 100644 --- a/doc/examples/configure-index +++ b/doc/examples/configure-index @@ -54,6 +54,9 @@ APT Build-Profiles ""; NeverAutoRemove ""; // list of package name regexes + LastInstalledKernel ""; // last installed kernel version + VersionedKernelPackages ""; // regular expressions to be protected from autoremoval (kernel uname will be appended) + Protect-Kernels ""; // whether to protect installed kernels against autoremoval (default: true) // Options for apt-get Get diff --git a/test/integration/test-kernel-helper-autoremove b/test/integration/test-kernel-helper-autoremove index 9cc978645..8dac44b93 100755 --- a/test/integration/test-kernel-helper-autoremove +++ b/test/integration/test-kernel-helper-autoremove @@ -38,9 +38,8 @@ testprotected() { testsuccess --nomsg test -e rootdir/etc/apt/apt.conf.d/01autoremove-kernels testfilestats 'rootdir/etc/apt/apt.conf.d/01autoremove-kernels' '%U:%G:%a' '=' "${TEST_DEFAULT_USER}:${TEST_DEFAULT_GROUP}:444" - msgtest 'Check kernel autoremoval protection list' 'can be dumped' - testsuccess --nomsg aptconfig dump --no-empty --format '%v%n' 'APT::NeverAutoRemove' - cp rootdir/tmp/testsuccess.output protected.list + testsuccess --nomsg apt -o Debug::PkgAutoRemove=1 autoremove -s + grep "Kernel protection regex" rootdir/tmp/testsuccess.output | cut -f2- -d: | tr '|' '\n' | sed 's/\s*//g' | sort -u > protected.list msgtest 'Check kernel autoremoval protection list' 'can be parsed' testfailure --nomsg grep '^[A-Z]: ' protected.list @@ -71,7 +70,7 @@ The following packages were automatically installed and are no longer required: ${CURRENTKERNEL}-686-pae:i386 (5-1) ${CURRENTKERNEL}-dbg (5-1) Use '$AUTOREMOVE' to remove them. -0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded." aptget install -sV +0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded." aptget install -sV -o APT::Protect-Kernels=0 testsuccessequal "Reading package lists... Building dependency tree... Reading state information... @@ -85,13 +84,13 @@ The following packages were automatically installed and are no longer required: ${CURRENTKERNEL}-dbg (5-1) ${CURRENTKERNEL}-rt (5-1) Use '$AUTOREMOVE' to remove them. -0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded." aptget install -sV --ignore-hold +0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded." aptget install -sV --ignore-hold -o APT::Protect-Kernels=0 testequal "Reading package lists... Building dependency tree... Reading state information... 7 packages were automatically installed and are no longer required. Use '$AUTOREMOVE' to remove them. -0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded." aptget install -s -o APT::Get::HideAutoRemove=small +0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded." aptget install -s -o APT::Get::HideAutoRemove=small -o APT::Protect-Kernels=0 testequal "Reading package lists... Building dependency tree... Reading state information... @@ -110,7 +109,7 @@ Remv linux-image-100.0.0-1-generic [100.0.0-1] Remv $CURRENTKERNEL [5-1] Remv ${CURRENTKERNEL}+variant [5-1] Remv ${CURRENTKERNEL}-686-pae:i386 [5-1] -Remv ${CURRENTKERNEL}-dbg [5-1]" aptget autoremove -sV +Remv ${CURRENTKERNEL}-dbg [5-1]" aptget autoremove -sV -o APT::Protect-Kernels=0 msgmsg "run without parameter" testprotected @@ -168,7 +167,7 @@ Remv ${CURRENTKERNEL}-dbg [5-1]" aptget autoremove -s unset COLUMNS # rt kernel was put on hold while the protected list was generated -testsuccess aptmark unhold "${CURRENTKERNEL}-rt" +testsuccess aptmark hold "${CURRENTKERNEL}-rt" export COLUMNS=99999 testsuccessequal "Reading package lists... Building dependency tree... -- cgit v1.2.3 From 944baec85a7496c1595242a31f6b1b37530451a5 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Thu, 17 Dec 2020 15:19:53 +0100 Subject: Automatically remove unused kernels on dist-upgrade Kernels clutter /boot and /boot is small size, so we need to take extra care to remove kernels when possible. --- apt-private/private-install.cc | 12 +++++++++++- debian/NEWS | 7 +++++++ doc/examples/configure-index | 4 +++- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/apt-private/private-install.cc b/apt-private/private-install.cc index af6697d7f..b110cbdc3 100644 --- a/apt-private/private-install.cc +++ b/apt-private/private-install.cc @@ -406,8 +406,15 @@ bool DoAutomaticRemove(CacheFile &Cache) { bool Debug = _config->FindB("Debug::pkgAutoRemove",false); bool doAutoRemove = _config->FindB("APT::Get::AutomaticRemove", false); + bool doAutoRemoveKernels = _config->FindB("APT::Get::AutomaticRemove::Kernels", false); bool hideAutoRemove = _config->FindB("APT::Get::HideAutoRemove"); + std::unique_ptr kernelAutoremovalMatcher; + if (doAutoRemoveKernels && !doAutoRemove) + { + kernelAutoremovalMatcher = APT::KernelAutoRemoveHelper::GetProtectedKernelsFilter(Cache, true); + } + pkgDepCache::ActionGroup group(*Cache); if(Debug) std::cout << "DoAutomaticRemove()" << std::endl; @@ -436,7 +443,7 @@ bool DoAutomaticRemove(CacheFile &Cache) if(Debug) std::cout << "We could delete " << APT::PrettyPkg(Cache, Pkg) << std::endl; - if (doAutoRemove) + if (doAutoRemove || (kernelAutoremovalMatcher != nullptr && (*kernelAutoremovalMatcher)(Pkg))) { if(Pkg.CurrentVer() != 0 && Pkg->CurrentState != pkgCache::State::ConfigFiles) @@ -692,6 +699,9 @@ bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, std::vectorCndSet("APT::Get::AutomaticRemove::Kernels", "true"); + bool resolver_fail = false; if (distUpgradeMode == true || UpgradeMode != APT::Upgrade::ALLOW_EVERYTHING) resolver_fail = APT::Upgrade::Upgrade(Cache, UpgradeMode, &Progress); diff --git a/debian/NEWS b/debian/NEWS index 13fc64182..9d9c963c2 100644 --- a/debian/NEWS +++ b/debian/NEWS @@ -1,3 +1,10 @@ +apt (2.1.16) UNRELEASED; urgency=medium + + Automatically remove unused kernels on dist-upgrade. To revert to previous + behavior, set APT::Get::AutomaticRemove::Kernels to false. + + -- Julian Andres Klode Mon, 04 Jan 2021 10:47:14 +0100 + apt (1.9.11) experimental; urgency=medium apt(8) now waits for the lock indefinitely if connected to a tty, or diff --git a/doc/examples/configure-index b/doc/examples/configure-index index 571bf2369..15b020198 100644 --- a/doc/examples/configure-index +++ b/doc/examples/configure-index @@ -80,7 +80,9 @@ APT Remove ""; AllowUnauthenticated ""; // skip security - AutomaticRemove ""; + AutomaticRemove "" { + "Kernels" ""; // Allow removing kernels even if not removing other packages (true for dist-upgrade) + }; HideAutoRemove ""; // yes, no, small Simulate ""; -- cgit v1.2.3 From 38c49b8adeadf54f147140b3a5db7693e9b9b50f Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Thu, 17 Dec 2020 15:21:17 +0100 Subject: Only keep up to 3 (not 4) kernels This fixes a problem on Ubuntu systems where the /boot partition has been sized to manage 3 kernels, but does not really work with 4 kernels which was causing problems all over the place. --- apt-pkg/algorithms.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apt-pkg/algorithms.cc b/apt-pkg/algorithms.cc index 702030943..a8e198054 100644 --- a/apt-pkg/algorithms.cc +++ b/apt-pkg/algorithms.cc @@ -1580,7 +1580,7 @@ std::string GetProtectedKernelsRegex(pkgCache *cache, bool ReturnRemove) std::clog << "Keeping latest kernel " << latest->first << std::endl; keep.insert(latest->first); } - if (previous != version2unames.rend()) + if (keep.size() < 3 && previous != version2unames.rend()) { if (Debug) std::clog << "Keeping previous kernel " << previous->first << std::endl; -- cgit v1.2.3