#define CEPH_SAN_LOG_MAX_LEN 256
#define CEPH_SAN_LOG_ENTRY_POISON 0xDEADBEEF
#define CEPH_SAN_MAX_SOURCE_IDS 4096
+#define CEPH_SAN_MAX_CLIENT_IDS 1024
+
+/* Client ID cache entry */
+struct ceph_san_client_id {
+ char fsid[16]; /* Client FSID */
+ u64 global_id; /* Client global ID */
+ u32 idx; /* Index in the cache */
+};
/* Source information mapping structure */
struct ceph_san_source_info {
u64 debug_poison; /* Debug poison value */
u64 ts; /* Timestamp (jiffies) */
u32 source_id; /* ID for source file/function/line */
+ u32 client_id; /* ID for client (fsid:global_id) */
unsigned int len; /* Length of the message */
char *buffer; /* Flexible array for inline buffer */
};
struct ceph_san_batch alloc_batch; /* Batch for allocating new entries */
struct ceph_san_batch log_batch; /* Batch for storing log entries */
struct ceph_san_source_info source_map[CEPH_SAN_MAX_SOURCE_IDS]; /* Source info mapping */
+ struct ceph_san_client_id client_map[CEPH_SAN_MAX_CLIENT_IDS]; /* Client ID mapping */
atomic_t next_source_id; /* Next source ID to assign */
+ u32 next_client_id; /* Next client ID to assign */
+ spinlock_t client_lock; /* Protects client ID operations */
};
/* Iterator for log entries in a single pagefrag */
/* Get source information for ID */
const struct ceph_san_source_info *ceph_san_get_source_info(u32 id);
+/* Check if client ID matches given fsid and global_id, returning the actual ID */
+u32 ceph_san_check_client_id(u32 id, const char *fsid, u64 global_id);
+
+/* Get client information for ID */
+const struct ceph_san_client_id *ceph_san_get_client_info(u32 id);
+
/* Log a message */
-void* ceph_san_log(u32 source_id, size_t size);
+void* ceph_san_log(u32 source_id, size_t needed_size);
/* Get current TLS context, creating if necessary */
struct ceph_san_tls_ctx *ceph_san_get_tls_ctx(void);
} \
} while (0)
+/* Helper macro for logging with client ID */
+#define CEPH_SAN_LOG_CLIENT(client, fmt, ...) \
+ do { \
+ static u32 __source_id = 0; \
+ static u32 __client_id = 0; \
+ static size_t __size = 0; \
+ void *___buffer = NULL; \
+ if (unlikely(__source_id == 0)) { \
+ __source_id = ceph_san_get_source_id(kbasename(__FILE__), __func__, __LINE__, fmt); \
+ __size = ceph_san_cnt(__VA_ARGS__); \
+ } \
+ __client_id = ceph_san_check_client_id(__client_id, client->fsid.fsid, client->monc.auth->global_id); \
+ ___buffer = ceph_san_log(__source_id, __size); \
+ if (likely(___buffer)) { \
+ ceph_san_ser(___buffer, ##__VA_ARGS__);\
+ } \
+ } while (0)
+
/* Global logger instance */
extern struct ceph_san_logger g_logger;
}
EXPORT_SYMBOL(ceph_san_get_source_info);
+/**
+ * ceph_san_check_client_id - Check if a client ID matches the given fsid:global_id pair
+ * @id: Client ID to check
+ * @fsid: Client FSID to compare
+ * @global_id: Client global ID to compare
+ *
+ * Returns the actual ID of the pair. If the given ID doesn't match, scans for
+ * existing matches or allocates a new ID if no match is found.
+ */
+u32 ceph_san_check_client_id(u32 id, const char *fsid, u64 global_id)
+{
+ u32 found_id = 0;
+ struct ceph_san_client_id *entry;
+ u32 max_id;
+
+ /* First check if the given ID matches */
+ if (id != 0 && id < CEPH_SAN_MAX_CLIENT_IDS) {
+ entry = &g_logger.client_map[id];
+ if (memcmp(entry->fsid, fsid, sizeof(entry->fsid)) == 0 &&
+ entry->global_id == global_id) {
+ found_id = id;
+ goto out_fast;
+ }
+ }
+
+ spin_lock(&g_logger.client_lock);
+ max_id = g_logger.next_client_id;
+
+ /* Scan for existing match */
+ for (id = 1; id < max_id && id < CEPH_SAN_MAX_CLIENT_IDS; id++) {
+ entry = &g_logger.client_map[id];
+ if (memcmp(entry->fsid, fsid, sizeof(entry->fsid)) == 0 &&
+ entry->global_id == global_id) {
+ found_id = id;
+ goto out;
+ }
+ }
+
+ /* No match found, allocate new ID */
+ found_id = ++g_logger.next_client_id;
+ if (found_id >= CEPH_SAN_MAX_CLIENT_IDS) {
+ /* If we run out of IDs, just use the first one */
+ pr_warn("ceph_san_logger: client ID overflow, reusing ID 1\n");
+ found_id = 1;
+ }
+
+ entry = &g_logger.client_map[found_id];
+ memcpy(entry->fsid, fsid, sizeof(entry->fsid));
+ entry->global_id = global_id;
+ entry->idx = found_id;
+
+out:
+ spin_unlock(&g_logger.client_lock);
+out_fast:
+ return found_id;
+}
+EXPORT_SYMBOL(ceph_san_check_client_id);
+
+/**
+ * ceph_san_get_client_id - Helper function to get or create a client ID
+ * @fsid: Client FSID
+ * @global_id: Client global ID
+ *
+ * Returns a unique ID for this client pair
+ */
+static u32 ceph_san_get_client_id(const char *fsid, u64 global_id)
+{
+ u32 id;
+ struct ceph_san_client_id *entry;
+ bool found = false;
+ u32 max_id;
+
+ spin_lock(&g_logger.client_lock);
+ max_id = g_logger.next_client_id;
+
+ /* First try to find existing entry */
+ for (id = 1; id < max_id && id < CEPH_SAN_MAX_CLIENT_IDS; id++) {
+ entry = &g_logger.client_map[id];
+ if (memcmp(entry->fsid, fsid, sizeof(entry->fsid)) == 0 &&
+ entry->global_id == global_id) {
+ found = true;
+ break;
+ }
+ }
+
+ /* If not found, allocate new ID */
+ if (!found) {
+ id = ++g_logger.next_client_id;
+ if (id >= CEPH_SAN_MAX_CLIENT_IDS) {
+ /* If we run out of IDs, just use the first one */
+ pr_warn("ceph_san_logger: client ID overflow, reusing ID 1\n");
+ id = 1;
+ }
+
+ entry = &g_logger.client_map[id];
+ memcpy(entry->fsid, fsid, sizeof(entry->fsid));
+ entry->global_id = global_id;
+ entry->idx = id;
+ }
+
+ spin_unlock(&g_logger.client_lock);
+ return id;
+}
+
+/**
+ * ceph_san_get_client_info - Get client info for a given ID
+ * @id: Client ID
+ *
+ * Returns the client information for this ID
+ */
+const struct ceph_san_client_id *ceph_san_get_client_info(u32 id)
+{
+ if (id == 0 || id >= CEPH_SAN_MAX_CLIENT_IDS)
+ return NULL;
+ return &g_logger.client_map[id];
+}
+EXPORT_SYMBOL(ceph_san_get_client_info);
+
/**
* ceph_san_log - Log a message
* @source_id: Source ID for this location