kernel log buf dump function kmsg_dump_get_buffer()

kernel log buf dump function kmsg_dump_get_buffer()

4.19/kernel/printk/printk.c

void kmsg_dump(enum kmsg_dump_reason reason)
{
    struct kmsg_dumper *dumper;
    unsigned long flags;

    if ((reason > KMSG_DUMP_OOPS) && !always_kmsg_dump)
        return;

    rcu_read_lock();
    list_for_each_entry_rcu(dumper, &dump_list, list) {
        if (dumper->max_reason && reason > dumper->max_reason)
            continue;

        /* initialize iterator with data about the stored records */
        dumper->active = true;

        logbuf_lock_irqsave(flags);
        dumper->cur_seq = clear_seq;
        dumper->cur_idx = clear_idx;
        dumper->next_seq = log_next_seq;
        dumper->next_idx = log_next_idx;
        logbuf_unlock_irqrestore(flags);

        /* invoke dumper which will iterate over records */
        dumper->dump(dumper, reason);

        /* reset iterator */
        dumper->active = false;
    }
    rcu_read_unlock();
}

 

bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
              char *buf, size_t size, size_t *len)
{
    unsigned long flags;
    u64 seq;
    u32 idx;
    u64 next_seq;
    u32 next_idx;
    size_t l = 0;
    bool ret = false;

    if (!dumper->active)
        goto out;

    logbuf_lock_irqsave(flags);
    if (dumper->cur_seq < log_first_seq) {
        /* messages are gone, move to first available one */
        dumper->cur_seq = log_first_seq;
        dumper->cur_idx = log_first_idx;
    }

    /* last entry */
    if (dumper->cur_seq >= dumper->next_seq) {
        logbuf_unlock_irqrestore(flags);
        goto out;
    }

    /* calculate length of entire buffer */
    seq = dumper->cur_seq;
    idx = dumper->cur_idx;
    while (seq < dumper->next_seq) {
        struct printk_log *msg = log_from_idx(idx);

        l += msg_print_text(msg, true, NULL, 0);
        idx = log_next(idx);
        seq++;
    }

    /* move first record forward until length fits into the buffer */
    seq = dumper->cur_seq;
    idx = dumper->cur_idx;
    while (l >= size && seq < dumper->next_seq) {
        struct printk_log *msg = log_from_idx(idx);

        l -= msg_print_text(msg, true, NULL, 0);
        idx = log_next(idx);
        seq++;
    }

    /* last message in next interation */
    next_seq = seq;
    next_idx = idx;

    l = 0;
    while (seq < dumper->next_seq) {
        struct printk_log *msg = log_from_idx(idx);

        l += msg_print_text(msg, syslog, buf + l, size - l);
        idx = log_next(idx);
        seq++;
    }

    dumper->next_seq = next_seq;
    dumper->next_idx = next_idx;
    ret = true;
    logbuf_unlock_irqrestore(flags);
out:
    if (len)
        *len = l;
    return ret;
}
EXPORT_SYMBOL_GPL(kmsg_dump_get_buffer);

 

下面两个变量表示kernel log buf最后一个clear log buffer后的位置(index)
dumper->cur_seq
dumper->cur_idx
下面两个变量表示kernel log buf里指向buf开头的seq、idx:
log_first_seq
log_first_idx
下面变量表示kernel log buf下一个写log的位置:
dumper->next_seq

kmsg_dump_get_buffer()函数会先计算kernel log buf目前总的size,如果这个len和此函数参数len要大,会将seq、idx前移,直到log buf size小于等于参数len,即会将会将log buf开头部分去掉,之后再将后面的log buf整体复制到函数参数buf所表示的buffer里,所以这会将kernel log buf里最新的log复制给调用者。

 
 



 

 

posted @ 2021-10-27 17:35  aspirs  阅读(295)  评论(0编辑  收藏  举报