You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用管道将/proc/self/smaps复制到memfd文件时splice报EINVAL错误

问题分析:splice调用返回EINVAL的原因及解决方法

核心问题

第一个splice调用返回EINVAL,根源在于proc文件系统的虚拟文件不支持作为splice的源端:

  • splice要求参与操作的文件系统实现对应的splice_read/splice_write接口,而/proc/self/smaps是内核动态生成的虚拟文件,proc文件系统并未实现splice_read方法。
  • 当尝试从proc文件描述符向管道splice数据时,内核因无法处理该操作,直接返回EINVAL错误。

修正后的代码

将第一个proc→管道的splice替换为传统的read+write操作,绕开proc文件的限制,同时保留后续管道→memfd的splice逻辑:

#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>

void err(int status, char const* ctx)
{
    if (status == -1) {
        fprintf(stderr, "Error %s: %s\n", ctx, strerrorname_np(errno));
        exit(1);
    }
}

#define MB 1024 * 1024
unsigned copy_fds(int fd_target, int fd_source)
{
    int pipefd[2];
    int status;

    status = pipe2(pipefd, 0); err(status, "creating pipe");
    status = fcntl(pipefd[1], F_SETPIPE_SZ, 1 * MB); err(status, "allocating buf for the pipe");
    status = ftruncate(fd_target, 1 * MB); err(status, "allocating space for the memfd-file");

    // 改用read+write读取proc文件并写入管道,规避proc不支持splice的限制
    char buf[4096];
    ssize_t total_transferred = 0;
    ssize_t read_len;
    while ((read_len = read(fd_source, buf, sizeof(buf))) > 0) {
        ssize_t write_len = write(pipefd[1], buf, read_len);
        err(write_len, "write to pipe");
        total_transferred += write_len;
    }
    err(read_len, "read from smaps");
    
    // 关闭管道写端,通知splice数据已写完
    close(pipefd[1]);

    ssize_t written = splice(pipefd[0], NULL, fd_target, NULL, total_transferred, 0); 
    err(written, "splice to memfd");

    close(pipefd[0]);
    return written;
}

int main()
{
    int fd_smaps = open("/proc/self/smaps", O_RDONLY); err(fd_smaps, "opening smaps");
    int fd_tmp = memfd_create("smaps", 0); err(fd_tmp, "creating memfd");

    printf("Copied: %u\n", copy_fds(fd_tmp, fd_smaps));

    close(fd_smaps);
    close(fd_tmp);

    return 0;
}

关键说明

  1. read+write是proc文件的通用读取方式,不受文件系统接口限制。
  2. 关闭管道写端后,splice会在读完管道内所有数据后终止,避免无限等待。
  3. memfd属于tmpfs文件系统,完全支持splice写入操作,因此第二个splice调用可以正常执行。

内容的提问来源于stack exchange,提问作者ABu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 12:10:26