goto out;
}
- tv_divide(wanted, &diff, &tmp); /* sleep time betweeen two snapshots */
- diff.tv_sec = s->completion_time; /* completion time of the the latest snaphot */
+ tv_divide(wanted, &diff, &tmp); /* sleep time between two snapshots */
+ diff.tv_sec = s->completion_time; /* completion time of the latest snapshot */
diff.tv_usec = 0;
tv_add(&diff, &tmp, &next_snapshot_time);
ret = (tv_diff(&now, &next_snapshot_time, &diff) < 0)? 0 : 1;
return s->creation_time == current_snapshot_creation_time;
}
+static int remove_orphaned_snapshot(struct snapshot_list *sl)
+{
+ struct snapshot *s;
+ int i, ret;
+
+ DSS_DEBUG_LOG("looking for orphaned snapshots\n");
+ FOR_EACH_SNAPSHOT(s, i, sl) {
+ if (snapshot_is_being_created(s))
+ continue;
+ /*
+ * We know that no rm is currently running, so if s is marked
+ * as being deleted, a previously started rm must have failed.
+ */
+ if (s->flags & SS_BEING_DELETED)
+ goto remove;
+
+ if (s->flags & SS_COMPLETE) /* good snapshot */
+ continue;
+ /*
+ * This snapshot is incomplete and it is not the snapshot
+ * currently being created. However, we must not remove it if
+ * rsync is about to be restarted. As only the newest snapshot
+ * can be restarted, this snapshot is orphaned if it is not the
+ * newest snapshot or if we are not about to restart rsync.
+ */
+ if (get_newest_snapshot(sl) != s)
+ goto remove;
+ if (snapshot_creation_status != HS_NEEDS_RESTART)
+ goto remove;
+ }
+ return 0; /* no orphaned snapshots */
+remove:
+ ret = pre_remove_hook(s, "orphaned");
+ if (ret < 0)
+ return ret;
+ return 1;
+}
+
/*
* return: 0: no redundant snapshots, 1: rm process started, negative: error
*/
static int remove_oldest_snapshot(struct snapshot_list *sl)
{
+ int ret;
struct snapshot *s = get_oldest_snapshot(sl);
if (!s) /* no snapshot found */
DSS_INFO_LOG("oldest snapshot: %s\n", s->name);
if (snapshot_is_being_created(s))
return 0;
- return pre_remove_hook(s, "oldest");
+ ret = pre_remove_hook(s, "oldest");
+ if (ret < 0)
+ return ret;
+ return 1;
}
static int rename_incomplete_snapshot(int64_t start)
ret = 0;
if (!low_disk_space)
goto out;
+ ret = remove_orphaned_snapshot(&sl);
+ if (ret)
+ goto out;
DSS_WARNING_LOG("disk space low and nothing obvious to remove\n");
ret = remove_oldest_snapshot(&sl);
if (ret)
goto out;
}
es = WEXITSTATUS(status);
- if (es == 13) { /* Errors with program diagnostics */
+ /*
+ * Restart rsync on non-fatal errors:
+ * 12: Error in rsync protocol data stream
+ * 13: Errors with program diagnostics
+ */
+ if (es == 12 || es == 13) {
DSS_WARNING_LOG("rsync process %d returned %d -- restarting\n",
(int)create_pid, es);
snapshot_creation_status = HS_NEEDS_RESTART;