+/* returns NULL <==> *reason is set to NULL */
+static struct snapshot *find_removable_snapshot(struct snapshot_list *sl,
+ bool try_hard, char **reason)
+{
+ struct snapshot *victim;
+
+ /*
+ * Don't remove anything if there is free space and we have fewer
+ * snapshots than configured, plus one. This way there is always one
+ * snapshot that can be recycled.
+ */
+ if (!try_hard && sl->num_snapshots <=
+ 1 << OPT_UINT32_VAL(DSS, NUM_INTERVALS))
+ goto nope;
+ victim = find_orphaned_snapshot(sl);
+ if (victim) {
+ *reason = make_message("orphaned");
+ return victim;
+ }
+ victim = find_outdated_snapshot(sl);
+ if (victim) {
+ *reason = make_message("outdated");
+ return victim;
+ }
+ if (!OPT_GIVEN(DSS, KEEP_REDUNDANT)) {
+ victim = find_redundant_snapshot(sl);
+ if (victim) {
+ *reason = make_message("redundant");
+ return victim;
+ }
+ }
+ if (!try_hard)
+ goto nope;
+ DSS_WARNING_LOG(("nothing obvious to remove\n"));
+ victim = find_oldest_removable_snapshot(sl);
+ if (victim) {
+ *reason = make_message("oldest");
+ return victim;
+ }
+nope:
+ *reason = NULL;
+ return NULL;
+}
+