1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 */ 4 5 #include "spdk/stdinc.h" 6 #include "spdk/string.h" 7 #include "spdk/thread.h" 8 #include "spdk/util.h" 9 #include "spdk/log.h" 10 11 struct spdk_deprecation { 12 const char tag[64]; 13 const char desc[64]; 14 const char remove[16]; 15 TAILQ_ENTRY(spdk_deprecation) link; 16 uint64_t hits; 17 /* How often (nanoseconds) to log. */ 18 uint64_t interval; 19 /* How many messages were not logged due to rate limiting */ 20 uint32_t deferred; 21 /* CLOCK_MONOTONIC microseconds since g_deprecation_epoch when last warning was logged */ 22 uint64_t last_log; 23 }; 24 25 static TAILQ_HEAD(, spdk_deprecation) g_deprecations = TAILQ_HEAD_INITIALIZER(g_deprecations); 26 static struct timespec g_deprecation_epoch; 27 28 static void 29 __attribute__((constructor)) 30 deprecation_init(void) 31 { 32 clock_gettime(CLOCK_MONOTONIC, &g_deprecation_epoch); 33 } 34 35 static inline uint64_t 36 get_ns_since_epoch(void) 37 { 38 struct timespec now; 39 40 clock_gettime(CLOCK_MONOTONIC, &now); 41 return (now.tv_sec - g_deprecation_epoch.tv_sec) * SPDK_SEC_TO_NSEC + 42 now.tv_nsec - g_deprecation_epoch.tv_nsec; 43 } 44 45 int 46 spdk_log_deprecation_register(const char *tag, const char *description, const char *remove_release, 47 uint32_t rate_limit_seconds, struct spdk_deprecation **depp) 48 { 49 struct spdk_deprecation *dep; 50 51 assert(strnlen(tag, sizeof(dep->tag)) < sizeof(dep->tag)); 52 assert(strnlen(description, sizeof(dep->desc)) < sizeof(dep->desc)); 53 assert(strnlen(remove_release, sizeof(dep->remove)) < sizeof(dep->remove)); 54 55 dep = calloc(1, sizeof(*dep)); 56 if (dep == NULL) { 57 return -ENOMEM; 58 } 59 60 snprintf((char *)dep->tag, sizeof(dep->tag), "%s", tag); 61 snprintf((char *)dep->desc, sizeof(dep->desc), "%s", description); 62 snprintf((char *)dep->remove, sizeof(dep->remove), "%s", remove_release); 63 dep->interval = rate_limit_seconds * SPDK_SEC_TO_NSEC; 64 65 TAILQ_INSERT_TAIL(&g_deprecations, dep, link); 66 *depp = dep; 67 return 0; 68 } 69 70 /* 71 * There is potential for races between pthreads leading to over or under reporting of times that 72 * deprecated code was hit. If this function is called in a hot path where that is likely, we care 73 * more about performance than accuracy of the error counts. The important thing is that at least 74 * one of the racing updates the hits counter to non-zero and the warning is logged at least once. 75 */ 76 void 77 spdk_log_deprecated(struct spdk_deprecation *dep, const char *file, uint32_t line, const char *func) 78 { 79 uint64_t now = get_ns_since_epoch(); 80 81 if (dep == NULL) { 82 SPDK_ERRLOG("NULL deprecation passed from %s:%u:%s\n", file, line, func); 83 assert(false); 84 return; 85 } 86 87 dep->hits++; 88 89 if (dep->interval != 0) { 90 if (dep->last_log != 0 && now < dep->last_log + dep->interval) { 91 dep->deferred++; 92 return; 93 } 94 } 95 96 dep->last_log = now; 97 98 spdk_log(SPDK_LOG_WARN, file, line, func, "%s: deprecated feature %s to be removed in %s\n", 99 dep->tag, dep->desc, dep->remove); 100 if (dep->deferred != 0) { 101 SPDK_WARNLOG("%s: %u messages suppressed\n", dep->tag, dep->deferred); 102 dep->deferred = 0; 103 } 104 } 105 106 int 107 spdk_log_for_each_deprecation(void *ctx, spdk_log_for_each_deprecation_fn fn) 108 { 109 struct spdk_deprecation *dep; 110 int rc = 0; 111 112 TAILQ_FOREACH(dep, &g_deprecations, link) { 113 rc = fn(ctx, dep); 114 if (rc != 0) { 115 break; 116 } 117 } 118 119 return rc; 120 } 121 122 const char * 123 spdk_deprecation_get_tag(const struct spdk_deprecation *deprecation) 124 { 125 return deprecation->tag; 126 } 127 128 const char * 129 spdk_deprecation_get_description(const struct spdk_deprecation *deprecation) 130 { 131 return deprecation->desc; 132 } 133 134 const char * 135 spdk_deprecation_get_remove_release(const struct spdk_deprecation *deprecation) 136 { 137 return deprecation->remove; 138 } 139 140 uint64_t 141 spdk_deprecation_get_hits(const struct spdk_deprecation *deprecation) 142 { 143 return deprecation->hits; 144 } 145