插件窝 干货文章 Linux中文件系统truncate.c源码分析

Linux中文件系统truncate.c源码分析

文件 truncate 系统 截断 686    来源:    2025-04-22

Linux文件系统truncate.c源码分析

truncate.c是Linux内核中处理文件截断操作的核心实现文件,位于fs/目录下。它实现了系统调用truncate()ftruncate(),以及相关的辅助函数。

主要功能概述

truncate.c主要提供以下功能: 1. 实现truncate()ftruncate()系统调用 2. 处理文件大小调整操作 3. 管理文件截断时的磁盘空间分配与释放 4. 维护文件系统一致性

核心函数分析

1. do_truncate() 函数

int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
                struct file *filp)
{
    struct inode *inode = dentry->d_inode;
    struct iattr newattrs;

    /* 准备属性变更结构 */
    newattrs.ia_size = length;
    newattrs.ia_valid = ATTR_SIZE | time_attrs;

    if (filp) {
        newattrs.ia_file = filp;
        newattrs.ia_valid |= ATTR_FILE;
    }

    /* 调用inode变更通知 */
    return notify_change(dentry, &newattrs, NULL);
}

这是截断操作的核心函数,它: - 接收目标dentry、新长度和可选的文件指针 - 准备一个iattr结构描述要变更的属性 - 通过notify_change()通知文件系统执行实际变更

2. sys_truncate() 系统调用

SYSCALL_DEFINE2(truncate, const char __user *, path, long, length)
{
    struct path file;
    int error;

    error = user_path(path, &file);
    if (error)
        goto out;

    error = do_truncate(file.dentry, length, 0, NULL);
    path_put(&file);
out:
    return error;
}

truncate()系统调用实现: 1. 通过用户路径查找文件 2. 调用do_truncate()执行截断 3. 释放路径引用

3. sys_ftruncate() 系统调用

SYSCALL_DEFINE2(ftruncate, unsigned int, fd, unsigned long, length)
{
    struct fd f = fdget(fd);
    int error = -EBADF;

    if (f.file) {
        error = do_truncate(f.file->f_path.dentry, length, 0, f.file);
        fdput(f);
    }
    return error;
}

ftruncate()系统调用实现: 1. 通过文件描述符获取文件结构 2. 调用do_truncate()执行截断 3. 释放文件引用

关键数据结构

1. struct iattr

struct iattr {
    unsigned int    ia_valid;
    umode_t         ia_mode;
    kuid_t          ia_uid;
    kgid_t          ia_gid;
    loff_t          ia_size;
    struct timespec ia_atime;
    struct timespec ia_mtime;
    struct timespec ia_ctime;
    struct file     *ia_file;
};

用于传递文件属性变更请求,ia_valid字段标识哪些属性需要修改。

文件截断流程

  1. 权限检查:验证调用者是否有权限修改文件大小
  2. 大小验证:确保新大小是非负数且不超过文件系统限制
  3. inode锁定:获取inode锁以保证操作原子性
  4. 空间调整
    • 对于缩小:释放超出部分的块
    • 对于扩大:分配新的空间块
  5. 元数据更新:更新inode中的文件大小和时间戳
  6. 日志记录:对于日志文件系统,记录变更操作
  7. 缓存刷新:确保修改同步到磁盘

文件系统特定操作

实际的空间分配和释放操作由具体文件系统通过inode_operations中的truncate方法实现。例如:

const struct inode_operations ext4_file_inode_operations = {
    .truncate    = ext4_truncate,
    /* 其他操作 */
};

错误处理

truncate.c中处理多种错误情况: - EACCES:权限不足 - EINVAL:无效参数 - EISDIR:目标是目录 - ENOENT:文件不存在 - EPERM:只读文件系统 - EFBIG:文件过大

性能考虑

  1. 延迟分配:某些文件系统可能延迟实际空间分配
  2. 稀疏文件处理:高效处理文件中的"空洞"
  3. 批量操作:对连续块的批量释放/分配

安全考虑

  1. 严格的权限检查
  2. 对用户提供参数的充分验证
  3. 防止符号链接攻击

扩展性

  1. 通过VFS层抽象支持多种文件系统
  2. 可扩展的属性变更通知机制
  3. 支持各种大小的文件(通过loff_t类型)

实际应用示例

// 用户空间调用示例
int ret = truncate("/path/to/file", 1024);  // 截断文件到1024字节
if (ret < 0) {
    perror("truncate failed");
}

总结

Linux的truncate.c实现提供了一个高效、安全的文件截断机制,通过VFS层抽象支持多种文件系统,同时处理了各种边界条件和错误情况。其设计体现了Linux文件系统模块的灵活性和可扩展性。