IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

write(2)在磁盘满的时候的行为

心路永恒 2012-09-18 23:26:15 累计浏览 2,707 次
本机暂存

今天一个同事问我关于write(2)在写入文件的时候问题,问题是这样的:

当磁盘剩余空间不能将一次write调用希望写入的数据写完的时候,write是直接返回-1,然后设置errno为ENOSPC,还是先写入一部分数据,将剩余空间占满然后再下一次调用的时候返回错误?

当时发现好像没有考虑过这样的问题,Google了一下,好像没有找到关于这个细节的说明。

于是今天决定自己试试看。用dd建立一个64M大小的文件,然后弄上不同的文件系统用loop挂载,去写满试试看。

测试程序如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <stdbool.h>

#define BUF_LEN 2011

static unsigned short src_buff[BUF_LEN];

static void
init_buf(unsigned short *buff)
{
    int i;

    for (i = 0; i < BUF_LEN; i++)
        buff[i] = i;            /* 缓冲区每个数据内容都唯一 */
}

static bool
add_data(int fd, unsigned short **buff, size_t  cnt)
{
    ssize_t err;
    off_t   cur_pos, last_pos;
    bool    ret = true;

    last_pos    = lseek(fd, 0, SEEK_CUR);
    printf("the first data is %hu\n", **buff);
    err = write(fd, *buff, cnt * sizeof(**buff));
    if (err < 0) {
        perror("write error");
        ret = false;
    } else if (err == 0) {
        perror("File tail");
    } else {
        *buff   += err / sizeof(**buff); /* 必须写入完整的buff元素 */
    }
    cur_pos = lseek(fd, -1 * (err % sizeof(**buff)), SEEK_CUR); /* 抛弃不完整的写入 */
    printf("the last data is %hu\n", *(*buff - 1));
    printf("return value = %zd,\n", err);
    printf("the file offset is %lld to %lld\n",
           (long long int)last_pos,
           (long long int)cur_pos);
    printf("\n");

    return ret;
}

int main(int argc, char *argv[])
{
    unsigned short *buf_pos = src_buff;
    int             fd;
    char           *filename    = "test.dat";

    if (argc == 2) {
        filename    = argv[1];
    } /* 默认打开的文件 */

    fd  = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_SYNC, 0644);
    if (fd == -1) {
        perror("open failure");
        goto err;
    }

    init_buf(src_buff);
    do {
        if (buf_pos - src_buff >= BUF_LEN)
            buf_pos = src_buff;
    } while (add_data(fd, &buf_pos, src_buff + BUF_LEN - buf_pos));

    return EXIT_SUCCESS;
 err:
    return EXIT_FAILURE;
}

然后测试,结束前的输出如下。
reiserfs下:

the first data is 0
the last data is 2010
return value = 4022,
the file offset is 33430864 to 33434886

the first data is 0
the last data is 380
return value = 762,
the file offset is 33434886 to 33435648

the first data is 381
write error: No space left on device
the last data is 380
return value = -1,
the file offset is 33435648 to 33435647

ext4下:

the first data is 0
the last data is 2010
return value = 4022,
the file offset is 59461248 to 59465270

the first data is 0
the last data is 228
return value = 458,
the file offset is 59465270 to 59465728

the first data is 229
write error: No space left on device
the last data is 228
return value = -1,
the file offset is 59465728 to 59465727

jfs下:

the first data is 0
the last data is 2010
return value = 4022,
the file offset is 65699370 to 65703392

the first data is 0
the last data is 271
return value = 544,
the file offset is 65703392 to 65703936

the first data is 272
write error: No space left on device
the last data is 271
return value = -1,
the file offset is 65703936 to 65703935

xfs下:

the first data is 0
the last data is 2010
return value = 4022,
the file offset is 58648804 to 58652826

the first data is 0
the last data is 946
return value = 1894,
the file offset is 58652826 to 58654720

the first data is 947
write error: No space left on device
the last data is 946
return value = -1,
the file offset is 58654720 to 58654719

ntfs-3g:

the first data is 0
the last data is 2010
return value = 4022,
the file offset is 64488748 to 64492770

the first data is 0
the last data is 1422
return value = 2846,
the file offset is 64492770 to 64495616

the first data is 1423
write error: No space left on device
the last data is 1422
return value = -1,
the file offset is 64495616 to 64495615

vfat下:

the first data is 0
the last data is 2010
return value = 4022,
the file offset is 66950212 to 66954234

the first data is 0
the last data is 2010
return value = 4022,
the file offset is 66954234 to 66958256

the first data is 0
write error: No space left on device
the last data is 0
return value = -1,
the file offset is 66958256 to 66958255

貌似除了vfat以外,都是尽量将磁盘写满。但是vfat只要空间不够,就立即返回错误了。

不知道这个特性是什么标准规定的?或者是没有规定的?

同分类推荐文章

  1. 等了十年的 Go 链式管道,终于来了:seq 让你像写 Scala 一样写 Go (2026-06-25 18:38:18)
  2. Go 实验特性详解 (2026-06-21 10:05:27)
  3. amd64 微架构级别对 Go 程序性能提升多少? (2026-06-21 09:38:49)

查看更多 后端 文章 →

建议继续学习

  1. Linux如何统计进程的CPU利用率 (累计阅读 16,308)
  2. 我的 RHCA 之路 (累计阅读 14,013)
  3. Linux内存点滴 用户进程内存空间 (累计阅读 13,229)
  4. 给程序员新手的一些建议 (累计阅读 13,089)
  5. Linux 性能监控、测试、优化工具 (累计阅读 13,011)
  6. 关于linux内存free的一些事情 (累计阅读 12,867)
  7. ps - 按进程消耗内存多少排序 (累计阅读 12,688)
  8. Google怎么用linux (累计阅读 12,581)
  9. Linux Used内存到底哪里去了? (累计阅读 11,867)
  10. find命令的一点注意事项 (累计阅读 11,865)