splice 和管道

splice API

splice 是一種在核心內部移動資料塊的方法,而無需在核心和使用者空間之間不斷傳輸它們。

ssize_t splice_to_pipe(struct pipe_inode_info *pipe, struct splice_pipe_desc *spd)

將傳遞的資料填充到管道中

引數

struct pipe_inode_info *pipe

要填充的管道

struct splice_pipe_desc *spd

要填充的資料

描述

spd 包含頁面和 len/offset 元組的對映,以及與這些頁面關聯的 struct pipe_buf_operations。此函式會將該資料鏈接到管道。

ssize_t copy_splice_read(struct file *in, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags)

從檔案複製資料並將副本拼接到管道中

引數

struct file *in

要從中讀取的檔案

loff_t *ppos

指向要從中讀取的檔案位置的指標

struct pipe_inode_info *pipe

要拼接到的管道

size_t len

要拼接的數量

unsigned int flags

SPLICE_F_* 標誌

描述

此函式分配足夠容納所請求資料量(但受剩餘管道容量限制)的頁面,將其傳遞給檔案的 ->read_iter() 以讀取到其中,然後將已使用的頁面拼接到管道中。

返回

成功時,將返回讀取的位元組數,如果適用,將更新 *ppos;如果沒有更多資料要讀取,將返回 0;如果管道沒有空間,將返回 -EAGAIN,如果發生錯誤,將返回其他負錯誤程式碼。如果管道空間不足、到達資料末尾或遇到空洞,則可能發生短讀取。

int splice_from_pipe_feed(struct pipe_inode_info *pipe, struct splice_desc *sd, splice_actor *actor)

將管道中的可用資料饋送到檔案

引數

struct pipe_inode_info *pipe

要從中拼接的管道

struct splice_desc *sd

傳遞給 actor 的資訊

splice_actor *actor

拼接資料的處理程式

描述

此函式迴圈遍歷管道並呼叫 actor 來執行將單個 struct pipe_buffer 移動到目標位置的實際操作。當管道中沒有更多緩衝區時,或者當請求的位元組數(sd->total_len)已被複制時,它會返回。如果管道需要填充更多資料,它會返回一個正數(一);如果所需的位元組數已被複制,則返回零;如果發生錯誤,則返回 -errno。

此函式與 splice_from_pipe_{begin,end,next} 一起,可用於實現 __splice_from_pipe() 的功能,當需要在將管道緩衝區複製到目標位置時進行鎖定。

int splice_from_pipe_next(struct pipe_inode_info *pipe, struct splice_desc *sd)

等待一些資料進行拼接

引數

struct pipe_inode_info *pipe

要從中拼接的管道

struct splice_desc *sd

有關拼接操作的資訊

描述

此函式將等待一些資料,如果管道緩衝區可用,則返回一個正值(一)。如果沒有更多資料需要拼接,它將返回零或 -errno。

void splice_from_pipe_begin(struct splice_desc *sd)

開始從管道拼接

引數

struct splice_desc *sd

有關拼接操作的資訊

描述

應在包含 splice_from_pipe_next()splice_from_pipe_feed() 的迴圈之前呼叫此函式,以初始化 sd 的必要欄位。

void splice_from_pipe_end(struct pipe_inode_info *pipe, struct splice_desc *sd)

完成從管道拼接

引數

struct pipe_inode_info *pipe

要從中拼接的管道

struct splice_desc *sd

有關拼接操作的資訊

描述

如有必要,此函式將喚醒管道寫入器。應在包含 splice_from_pipe_next()splice_from_pipe_feed() 的迴圈之後呼叫此函式。

ssize_t __splice_from_pipe(struct pipe_inode_info *pipe, struct splice_desc *sd, splice_actor *actor)

將管道中的資料拼接到給定的 actor

引數

struct pipe_inode_info *pipe

要從中拼接的管道

struct splice_desc *sd

傳遞給 actor 的資訊

splice_actor *actor

拼接資料的處理程式

描述

此函式的功能僅限於迴圈遍歷管道並呼叫 actor 來執行將單個 struct pipe_buffer 移動到目標位置的實際操作。請參閱 pipe_to_file、pipe_to_sendmsg 或 pipe_to_user。

ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out, loff_t *ppos, size_t len, unsigned int flags, splice_actor *actor)

將管道中的資料拼接到檔案

引數

struct pipe_inode_info *pipe

要從中拼接的管道

struct file *out

要拼接到的檔案

loff_t *ppos

out 中的位置

size_t len

要拼接的位元組數

unsigned int flags

拼接修飾符標誌

splice_actor *actor

拼接資料的處理程式

描述

請參閱 __splice_from_pipe。此函式鎖定管道 inode,否則它與 __splice_from_pipe() 相同。

ssize_t iter_file_splice_write(struct pipe_inode_info *pipe, struct file *out, loff_t *ppos, size_t len, unsigned int flags)

將管道中的資料拼接到檔案

引數

struct pipe_inode_info *pipe

管道資訊

struct file *out

要寫入的檔案

loff_t *ppos

out 中的位置

size_t len

要拼接的位元組數

unsigned int flags

拼接修飾符標誌

描述

將從給定的管道 inode 移動或複製頁面(由 flags 選項確定)到給定的檔案。這一個基於 ->write_iter。

ssize_t splice_to_socket(struct pipe_inode_info *pipe, struct file *out, loff_t *ppos, size_t len, unsigned int flags)

將管道中的資料拼接到套接字

引數

struct pipe_inode_info *pipe

要從中拼接的管道

struct file *out

要寫入的套接字

loff_t *ppos

out 中的位置

size_t len

要拼接的位元組數

unsigned int flags

拼接修飾符標誌

描述

將從管道傳送 len 位元組到網路套接字。不涉及資料複製。

ssize_t vfs_splice_read(struct file *in, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags)

從檔案讀取資料並將其拼接到管道中

引數

struct file *in

要從中拼接的檔案

loff_t *ppos

輸入檔案偏移量

struct pipe_inode_info *pipe

要拼接到的管道

size_t len

要拼接的位元組數

unsigned int flags

拼接修飾符標誌 (SPLICE_F_*)

描述

將請求的資料量從輸入檔案拼接到管道。這是同步的,因為呼叫者必須在整個操作過程中持有管道鎖。

如果成功,它將返回拼接的資料量;如果它遇到 EOF 或空洞,則返回 0;否則返回一個負錯誤程式碼。

ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd, splice_direct_actor *actor)

在兩個非管道之間直接拼接資料

引數

struct file *in

要從中拼接的檔案

struct splice_desc *sd

關於拼接位置的 actor 資訊

splice_direct_actor *actor

處理資料拼接

描述

這是一個特殊情況的輔助函式,用於直接在兩個點之間拼接,而無需顯式管道。在內部,分配的管道快取在程序中,並在該程序的生命週期內重複使用。

ssize_t do_splice_direct(struct file *in, loff_t *ppos, struct file *out, loff_t *opos, size_t len, unsigned int flags)

在兩個檔案之間直接拼接資料

引數

struct file *in

要從中拼接的檔案

loff_t *ppos

輸入檔案偏移量

struct file *out

要拼接到的檔案

loff_t *opos

輸出檔案偏移量

size_t len

要拼接的位元組數

unsigned int flags

拼接修飾符標誌

描述

供 do_sendfile() 使用。splice 可以輕鬆地模擬 sendfile,但在應用程式中執行它會產生額外的系統呼叫(splice in + splice out,與僅 sendfile() 相比)。因此,此輔助函式可以直接透過程序私有管道進行拼接。

呼叫者已經對整個範圍呼叫了 rw_verify_area()。

ssize_t splice_file_range(struct file *in, loff_t *ppos, struct file *out, loff_t *opos, size_t len)

在兩個檔案之間拼接資料以用於 copy_file_range()

引數

struct file *in

要從中拼接的檔案

loff_t *ppos

輸入檔案偏移量

struct file *out

要拼接到的檔案

loff_t *opos

輸出檔案偏移量

size_t len

要拼接的位元組數

描述

供 ->copy_file_range() 方法使用。與 do_splice_direct() 類似,但 vfs_copy_file_range() 已經在 out 檔案上持有 start_file_write()。

呼叫者已經對整個範圍呼叫了 rw_verify_area()。

管道 API

管道介面全部供核心內部(內建映象)使用。它們不匯出供模組使用。

struct pipe_buffer

Linux 核心管道緩衝區

定義:

struct pipe_buffer {
    struct page *page;
    unsigned int offset, len;
    const struct pipe_buf_operations *ops;
    unsigned int flags;
    unsigned long private;
};

成員

page

包含管道緩衝區資料的頁面

offset

page 中資料的偏移量

len

page 中資料的長度

ops

與此緩衝區關聯的操作。請參閱 pipe_buf_operations

flags

管道緩衝區標誌。請參閱上文。

private

ops 擁有的私有資料。

struct pipe_inode_info

Linux 核心管道

定義:

struct pipe_inode_info {
    struct mutex mutex;
    wait_queue_head_t rd_wait, wr_wait;
    union {
        unsigned long head_tail;
        struct {
            pipe_index_t head;
            pipe_index_t tail;
        };
    };
    unsigned int max_usage;
    unsigned int ring_size;
    unsigned int nr_accounted;
    unsigned int readers;
    unsigned int writers;
    unsigned int files;
    unsigned int r_counter;
    unsigned int w_counter;
    bool poll_usage;
#ifdef CONFIG_WATCH_QUEUE;
    bool note_loss;
#endif;
    struct page *tmp_page[2];
    struct fasync_struct *fasync_readers;
    struct fasync_struct *fasync_writers;
    struct pipe_buffer *bufs;
    struct user_struct *user;
#ifdef CONFIG_WATCH_QUEUE;
    struct watch_queue *watch_queue;
#endif;
};

成員

mutex

保護整個物件的互斥鎖

rd_wait

空管道情況下讀取器等待點

wr_wait

滿管道情況下寫入器等待點

{unnamed_union}

anonymous

head_tail

headtail 的 unsigned long 聯合

{unnamed_struct}

anonymous

head

緩衝區生產點

tail

緩衝區消費點

max_usage

環中可能使用的最大槽數

ring_size

緩衝區總數(應為 2 的冪)

nr_accounted

此管道在 user->pipe_bufs 中佔用的數量

readers

此管道的當前讀取器數量

writers

此管道的當前寫入器數量

files

引用此管道的 struct file 數量(受 ->i_lock 保護)

r_counter

讀取器計數器

w_counter

寫入器計數器

poll_usage

此管道是否用於 epoll,它具有瘋狂的喚醒?

note_loss

下一個 read() 應插入資料丟失訊息

tmp_page

快取的已釋放頁面

fasync_readers

讀取器側 fasync

fasync_writers

寫入器側 fasync

bufs

管道緩衝區的迴圈陣列

user

建立此管道的使用者

watch_queue

如果此管道是 watch_queue,則這是相關內容

bool pipe_has_watch_queue(const struct pipe_inode_info *pipe)

檢查管道是否為 watch_queue,即是否使用 O_NOTIFICATION_PIPE 建立

引數

const struct pipe_inode_info *pipe

要檢查的管道

返回

如果管道是 watch 佇列,則為 true;否則為 false。

unsigned int pipe_occupancy(unsigned int head, unsigned int tail)

返回管道中使用的槽數

引數

unsigned int head

管道環頭指標

unsigned int tail

管道環尾指標

bool pipe_empty(unsigned int head, unsigned int tail)

如果管道為空,則返回 true

引數

unsigned int head

管道環頭指標

unsigned int tail

管道環尾指標

bool pipe_full(unsigned int head, unsigned int tail, unsigned int limit)

如果管道已滿,則返回 true

引數

unsigned int head

管道環頭指標

unsigned int tail

管道環尾指標

unsigned int limit

可用槽位的最大數量。

bool pipe_is_full(const struct pipe_inode_info *pipe)

如果管道已滿,則返回 true

引數

const struct pipe_inode_info *pipe

管道

bool pipe_is_empty(const struct pipe_inode_info *pipe)

如果管道為空,則返回 true

引數

const struct pipe_inode_info *pipe

管道

unsigned int pipe_buf_usage(const struct pipe_inode_info *pipe)

返回正在使用的管道緩衝區數量

引數

const struct pipe_inode_info *pipe

管道

struct pipe_buffer *pipe_buf(const struct pipe_inode_info *pipe, unsigned int slot)

返回管道環中指定槽位的管道緩衝區

引數

const struct pipe_inode_info *pipe

要訪問的管道

unsigned int slot

感興趣的槽位

struct pipe_buffer *pipe_head_buf(const struct pipe_inode_info *pipe)

返回管道環頭部的管道緩衝區

引數

const struct pipe_inode_info *pipe

要訪問的管道

bool pipe_buf_get(struct pipe_inode_info *pipe, struct pipe_buffer *buf)

獲取對 pipe_buffer 的引用

引數

struct pipe_inode_info *pipe

緩衝區所屬的管道

struct pipe_buffer *buf

要獲取引用的緩衝區

返回

如果成功獲取引用,則為 true

void pipe_buf_release(struct pipe_inode_info *pipe, struct pipe_buffer *buf)

釋放一個 pipe_buffer 的引用

引數

struct pipe_inode_info *pipe

緩衝區所屬的管道

struct pipe_buffer *buf

要釋放引用的緩衝區

int pipe_buf_confirm(struct pipe_inode_info *pipe, struct pipe_buffer *buf)

驗證管道緩衝區的內容

引數

struct pipe_inode_info *pipe

緩衝區所屬的管道

struct pipe_buffer *buf

要確認的緩衝區

bool pipe_buf_try_steal(struct pipe_inode_info *pipe, struct pipe_buffer *buf)

嘗試獲取 pipe_buffer 的所有權

引數

struct pipe_inode_info *pipe

緩衝區所屬的管道

struct pipe_buffer *buf

嘗試竊取的緩衝區

bool generic_pipe_buf_try_steal(struct pipe_inode_info *pipe, struct pipe_buffer *buf)

嘗試獲取 pipe_buffer 的所有權

引數

struct pipe_inode_info *pipe

緩衝區所屬的管道

struct pipe_buffer *buf

嘗試竊取的緩衝區

描述

此函式嘗試竊取附加到 bufstruct page。如果成功,此函式返回 0 並在頁面鎖定的情況下返回。呼叫者可以將其重新用於任何他希望的目的;典型用途是插入到不同的檔案頁快取中。

bool generic_pipe_buf_get(struct pipe_inode_info *pipe, struct pipe_buffer *buf)

獲取對 struct pipe_buffer 的引用

引數

struct pipe_inode_info *pipe

緩衝區所屬的管道

struct pipe_buffer *buf

要獲取引用的緩衝區

描述

此函式獲取對 buf 的額外引用。它用於 tee() 系統呼叫,當我們複製一個管道中的緩衝區到另一個管道中時。

void generic_pipe_buf_release(struct pipe_inode_info *pipe, struct pipe_buffer *buf)

釋放對 struct pipe_buffer 的引用

引數

struct pipe_inode_info *pipe

緩衝區所屬的管道

struct pipe_buffer *buf

要釋放引用的緩衝區

描述

此函式釋放對 buf 的引用。