From: Glenn-1990 Date: Sun, 22 Jan 2017 15:59:16 +0000 (+0100) Subject: dvr: properly abort recordings when running out of free disk space X-Git-Tag: v4.2.1~120 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cf818c05b82a15ae9caa4aaabc20c814c5d84548;p=thirdparty%2Ftvheadend.git dvr: properly abort recordings when running out of free disk space --- diff --git a/src/dvr/dvr.h b/src/dvr/dvr.h index c80251261..f2504118b 100644 --- a/src/dvr/dvr.h +++ b/src/dvr/dvr.h @@ -625,6 +625,7 @@ void dvr_spawn_cmd(dvr_entry_t *de, const char *cmd, const char *filename, int p void dvr_vfs_refresh_entry(dvr_entry_t *de); void dvr_vfs_remove_entry(dvr_entry_t *de); int64_t dvr_vfs_update_filename(const char *filename, htsmsg_t *fdata); +int64_t dvr_vfs_rec_start_check(dvr_config_t *cfg); void dvr_disk_space_boot(void); void dvr_disk_space_init(void); diff --git a/src/dvr/dvr_db.c b/src/dvr/dvr_db.c index c31f14bee..6bb59d31d 100644 --- a/src/dvr/dvr_db.c +++ b/src/dvr/dvr_db.c @@ -645,6 +645,8 @@ dvr_entry_status(dvr_entry_t *de) return N_("User access error"); case SM_CODE_USER_LIMIT: return N_("User limit reached"); + case SM_CODE_NO_SPACE: + return streaming_code2txt(de->de_last_error); default: break; } @@ -658,7 +660,7 @@ dvr_entry_status(dvr_entry_t *de) return N_("Completed OK"); case DVR_MISSED_TIME: - if (de->de_last_error == SM_CODE_SVC_NOT_ENABLED) + if (de->de_last_error == SM_CODE_SVC_NOT_ENABLED || de->de_last_error == SM_CODE_NO_SPACE) return streaming_code2txt(de->de_last_error); return N_("Time missed"); diff --git a/src/dvr/dvr_rec.c b/src/dvr/dvr_rec.c index 5417214f1..24d70c34e 100644 --- a/src/dvr/dvr_rec.c +++ b/src/dvr/dvr_rec.c @@ -929,6 +929,11 @@ dvr_rec_start(dvr_entry_t *de, const streaming_start_t *ss) return -1; } + if (!dvr_vfs_rec_start_check(cfg)) { + dvr_rec_fatal_error(de, "Not enough free disk space"); + return SM_CODE_NO_SPACE; + } + if (!(muxer = prch->prch_muxer)) { if (profile_chain_reopen(prch, &cfg->dvr_muxcnf, 0)) { dvr_rec_fatal_error(de, "Unable to reopen muxer"); @@ -1191,11 +1196,12 @@ dvr_thread_rec_start(dvr_entry_t **_de, streaming_start_t *ss, if (!dvr_thread_global_lock(de, run)) return 0; dvr_rec_set_state(de, DVR_RS_WAIT_PROGRAM_START, 0); - if(dvr_rec_start(de, ss) == 0) { + int code = dvr_rec_start(de, ss); + if(code == 0) { ret = 1; *started = 1; } else - dvr_stop_recording(de, SM_CODE_INVALID_TARGET, 1, 0); + dvr_stop_recording(de, code == SM_CODE_NO_SPACE ? SM_CODE_NO_SPACE : SM_CODE_INVALID_TARGET, 1, 0); dvr_thread_global_unlock(de); } return ret; diff --git a/src/dvr/dvr_vfsmgr.c b/src/dvr/dvr_vfsmgr.c index a5ae2d7ee..a64bc7853 100644 --- a/src/dvr/dvr_vfsmgr.c +++ b/src/dvr/dvr_vfsmgr.c @@ -174,7 +174,7 @@ dvr_vfs_update_filename(const char *filename, htsmsg_t *fdata) * Only "Keep until space needed" recordings are deleted, starting with the oldest one */ static int64_t -dvr_disk_space_cleanup(dvr_config_t *cfg) +dvr_disk_space_cleanup(dvr_config_t *cfg, int include_active) { dvr_entry_t *de, *oldest; time_t stoptime; @@ -264,8 +264,15 @@ dvr_disk_space_cleanup(dvr_config_t *cfg) dvr_disk_space_config_lastdelete = mclk(); dvr_entry_cancel_remove(oldest, 0); /* Remove stored files and mark as "removed" */ } else { - tvhwarn(LS_DVR, "%s \"until space needed\" recordings found for config \"%s\", you are running out of disk space very soon!", - loops > 0 ? "Not enough" : "No", configName); + /* Stop active recordings if cleanup is not possible */ + if (loops == 0 && include_active) { + tvhwarn(LS_DVR, "No \"until space needed\" recordings found for config \"%s\", aborting active recordings now!", configName); + LIST_FOREACH(de, &dvrentries, de_global_link) { + if (de->de_sched_state != DVR_RECORDING || !de->de_config || de->de_config != cfg) + continue; + dvr_stop_recording(de, SM_CODE_NO_SPACE, 1, 0); + } + } goto finish; } @@ -336,7 +343,7 @@ dvr_disk_space_check() } /* only cleanup one directory at the time as the system needs time to delete the actual files */ - dvr_disk_space_cleanup(de->de_config); + dvr_disk_space_cleanup(de->de_config, 1); cleanupDone = 1; dvr_disk_space_config_idx = idx; break; @@ -423,6 +430,37 @@ dvr_get_disk_space_cb(void *aux) mtimer_arm_rel(&dvr_disk_space_timer, dvr_get_disk_space_cb, NULL, sec2mono(15)); } +/** + * Returns the available disk space for a new recording. + * If '0' (= below configured minimum), a new recording should not be started. + */ +int64_t +dvr_vfs_rec_start_check(dvr_config_t *cfg) +{ + struct statvfs diskdata; + dvr_vfs_t *dvfs; + int64_t availBytes, requiredBytes, usedBytes, maximalBytes, cleanedBytes; + + lock_assert(&global_lock); + if (!cfg || !cfg->dvr_enabled || statvfs(cfg->dvr_storage, &diskdata) == -1) + return 0; + availBytes = diskdata.f_bsize * (int64_t)diskdata.f_bavail; + requiredBytes = MIB(cfg->dvr_cleanup_threshold_free); + maximalBytes = MIB(cfg->dvr_cleanup_threshold_used); + dvfs = dvr_vfs_find(NULL, tvh_fsid(diskdata.f_fsid)); + usedBytes = dvfs->used_size; + + if (availBytes < requiredBytes || ((maximalBytes < usedBytes) && cfg->dvr_cleanup_threshold_used)) { + /* Not enough space to start recording, check if cleanup helps */ + cleanedBytes = dvr_disk_space_cleanup(cfg, 0); + availBytes += cleanedBytes; + usedBytes -= cleanedBytes; + if (availBytes < requiredBytes || ((maximalBytes < usedBytes) && cfg->dvr_cleanup_threshold_used)) + return 0; + } + return availBytes; +} + /** * */ diff --git a/src/htsp_server.c b/src/htsp_server.c index 3148c5539..138533634 100644 --- a/src/htsp_server.c +++ b/src/htsp_server.c @@ -4138,6 +4138,8 @@ _htsp_get_subscription_status(int smcode) return "userLimit"; case SM_CODE_WEAK_STREAM: return "weakStream"; + case SM_CODE_NO_SPACE: + return "noDiskSpace"; default: return streaming_code2txt(smcode); } diff --git a/src/streaming.c b/src/streaming.c index 827ab366f..873a104a2 100644 --- a/src/streaming.c +++ b/src/streaming.c @@ -481,6 +481,8 @@ streaming_code2txt(int code) return N_("No access"); case SM_CODE_NO_INPUT: return N_("No input detected"); + case SM_CODE_NO_SPACE: + return N_("Not enough disk space"); default: snprintf(ret, sizeof(ret), _("Unknown reason (%i)"), code); diff --git a/src/tvheadend.h b/src/tvheadend.h index c34e1f213..f147a5a19 100644 --- a/src/tvheadend.h +++ b/src/tvheadend.h @@ -537,6 +537,7 @@ typedef enum { #define SM_CODE_NO_DESCRAMBLER 400 #define SM_CODE_NO_ACCESS 401 #define SM_CODE_NO_INPUT 402 +#define SM_CODE_NO_SPACE 403 typedef enum {