Windows XP Windows 7 Windows 2003 Windows Vista Windows 綜合教學 Linux 系統教學
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟體教學

Linux 內核 seq_file 接口實戰:通過 /proc 導出鏈表數據到用戶態

編輯:Linux 系統常見問題解答

seq_file 是內核提供的標準接口,用於在 /proc 或 /sys 下以流式方式輸出大量數據(如鏈表、數組)。本文通過一個受讀寫自旋鎖保護的鏈表示例,完整演示 seq_operations 四大回調的實現與註冊流程。

核心數據結構

struct node {
    struct node *next;
    int num;
};
struct node *list_head;
DEFINE_RWLOCK(list_lock);

seq_operations 回調設計

struct seq_operations {
    void * (*start) (struct seq_file *m, loff_t *pos);
    void   (*stop)  (struct seq_file *m, void *v);
    void * (*next)  (struct seq_file *m, void *v, loff_t *pos);
    int    (*show)  (struct seq_file *m, void *v);
};
  • start:獲取鎖、初始化迭代器。*pos==0 返回 SEQ_START_TOKEN 打印表頭;否則遍歷鏈表定位到第 pos 個節點。
  • next:移動到下一節點,pos++,返回節點指針或 NULL 結束。
  • show:格式化輸出節點數據。v==SEQ_START_TOKEN 打印表頭;否則輸出 num,每 10 個換行。
  • stop:釋放鎖,打印表尾。

完整實現代碼

static void *my_start(struct seq_file *m, loff_t *pos) {
    int i = 1;
    struct node *tmp;
    read_lock_bh(&list_lock);
    if (*pos == 0) return SEQ_START_TOKEN;
    for (tmp = list_head; tmp; tmp = tmp->next) {
        if (i == *pos) return tmp;
        ++i;
    }
    return NULL;
}

static void *my_next(struct seq_file *m, void *v, loff_t *pos) {
    ++*pos;
    return (v == SEQ_START_TOKEN) ? list_head : ((struct node *)v)->next;
}

static int my_show(struct seq_file *m, void *v) {
    static int line = 0;
    if (v == SEQ_START_TOKEN) {
        seq_printf(m, "\n----- data start -----\n");
    } else {
        seq_printf(m, " %d ", ((struct node *)v)->num);
        if (++line == 10) { seq_printf(m, "\n"); line = 0; }
    }
    return 0;
}

static void my_stop(struct seq_file *m, void *v) {
    read_unlock_bh(&list_lock);
    seq_printf(m, "\n----- data end -----\n");
}

註冊到 /proc

static const struct seq_operations my_seq_ops = {
    .start = my_start, .next = my_next,
    .stop = my_stop,   .show = my_show,
};

static int proc_my_open(struct inode *inode, struct file *file) {
    return seq_open(file, &my_seq_ops);
}

static const struct file_operations my_fops = {
    .owner   = THIS_MODULE,
    .open    = proc_my_open,
    .read    = seq_read,
    .llseek  = seq_lseek,
    .release = seq_release,
};

proc_create("my_test", 0, NULL, &my_fops);

關鍵點總結

  • start/next/stop 可能因緩衝區分頁多次調用,依賴 pos 維持迭代狀態。
  • 鎖的獲取/釋放分別在 start/stop,保證遍歷原子性。
  • 簡單輸出可用 single_open + 單一 show 替代,代碼更精簡。

掌握 seq_file,即可高效實現內核數據到用戶態的大規模、分頁友好導出。

Copyright © Windows教程網 All Rights Reserved