Chinaunix首页 | 论坛 | 博客
  • 博客访问: 612574
  • 博文数量: 90
  • 博客积分: 5111
  • 博客等级: 大校
  • 技术积分: 928
  • 用 户 组: 普通用户
  • 注册时间: 2007-11-29 16:56
文章存档

2011年(15)

2010年(34)

2009年(19)

2008年(22)

我的朋友

分类: LINUX

2010-05-11 15:39:28


File size limit exceeded 问题研究

现象:
今天在长时间测试时出现了个“File size limit exceeded(core dumped)”。

简单结论:
32位系统或64位系统中指定gcc -m32时,默认情况下,
系统调用write和标准I/O fwrite对单个文件的写操作只能写2G大小,
原因是32位的off_t为long int有符号长整型,取址长度为0 ~ 2^31-1。
想改变这些有以下方案:
1)编译时指定宏-D_FILE_OFFSET_BITS=64,将off_t改为64位;
2)系统调用read(2)时,编译时指定-D_LARGEFILE_SOURCE  -D_LARGEFILE64_SOURCE,open(2)选项加入O_LARGEFILE,
只对open(2)有效,对标准I/O fopen(3)无效;
3)64位系统不指定gcc -m32,默认使用64位的off_t;

注:无论是read还是fread,本身实现的offset都应该是64位的,
比如FILE结构体的_offset成员,就是有符号64位的。
但write/fwrite使用的lseek/fseek的offset却是off_t,位数跟系统、选项相关。

问题及研究:

ll(1)发现,该输出文件大小为2147483647,比2GB少1byte。

本以为是ulimit或文件系统有单个文件大小上限的问题,

[root@nwg onix_stub]# ulimit -a
file size               (blocks, -f) unlimited

[root@nwg onix_stub]# df -T
Filesystem    Type   1K-blocks      Used Available Use% Mounted on
/dev/mapper/VolGroup00-LogVol00
              ext3    47517488  35855436   9209368  80% /

limit没有文件大小限制;
磁盘未满;
磁盘格式为ext3,网上查的单文件大小至少为16G;

网上有人说是fwrite的问题,
于是写小程序测试了下:

//测试程序1:
//test_stdio.c
#include
#include
#include
int main(int argc , char * argv[] )
{
        FILE *fp ;
        char buff[1024] ;
        int i ;
    
        printf("sizeof(off_t)=[%d]\n" , sizeof( off_t) ) ;
        unlink("./large_stdio") ;
        fp = fopen("./large_stdio" , "w") ;
        memset(buff , 1 , 1024) ;

        i = 1024*1024*2 + 1 ;
        while( i -- ) {
                fwrite(buff, 1024,1 , fp ) ;
        }

        fflush(fp) ;
        fclose( fp ) ;
        return 1 ;
}


#gcc -m32 -g test_stdio.c
#./a.out

果然在larg_stdio文件马上到2G的时候出现File size limit exceeded。

而改变选项用:
#gcc -m32 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -g test_stdio.c

#gcc -m64 -g test_stdio.c
就没有问题。

//测试程序2:
//test_systemcall.c
#include
#include
#include
#include
#include

int main(int argc , char * argv[] )
{
        int fd ;
        char buff[1024] ;
        int i ;

        printf("sizeof(off_t)=[%d]\n" , sizeof(off_t) ) ;
        unlink("./large_systemcall") ;
        umask(022) ;
        fd = open("./large_systemcall" , O_RDWR | O_CREAT ,0644 ) ;
        memset(buff , 1 , 1024) ;
        i = 1024*1024*2 + 1 ;
        while( i -- ) {
                write(fd , buff, 1024 ) ;
        }
        fsync(fd) ;
        close( fd ) ;
        return 1 ;
}

#gcc -m32 test_systemcall.c 写文件只能到2G少1byte,

#gcc -m64 test_systemcall.c

#gcc -m32 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 test_systemcall.c

fd = open("./large_systemcall" , O_RDWR | O_CREAT | O_LARGEFILE ,0644 ) ;
就没有问题。

结论分析:
在系统调用open/write/lseek,
或者是64位的标准I/O fopen/fwrite/fseeko中,
offset依赖于off_t,
off_t定义在sys/types.h:86:
# ifndef __USE_FILE_OFFSET64
typedef __off_t off_t;   (__off_t为long int型)
# else
typedef __off64_t off_t;  (__off64_t始终为64位)
#endif

32位标准I/O的offset为long:
int fseek(FILE *stream, long offset, int whence);

而宏_LARGEFILE_SOURCE  _LARGEFILE64_SOURCE  _FILE_OFFSET_BITS=64可以改变这些行为。

证明:
1:off_t
man 3 fseeko:
      On many architectures both off_t and long are 32-bit types, but compilation with
              #define _FILE_OFFSET_BITS 64
       will turn off_t into a 64-bit type
man 2 open:
      O_LARGEFILE
              (LFS)  Allow  files  whose  sizes  cannot  be represented in an off_t (but can be represented in an
              off64_t) to be opened.

__off_t为long int型:
./bits/types.h:144:__STD_TYPE __OFF_T_TYPE __off_t;
./bits/typesizes.h:37:#define __OFF_T_TYPE __SLONGWORD_TYPE
./bits/types.h:106:#define __SLONGWORD_TYPE     long int

__off64_t始终为64位:
./bits/types.h:145:__STD_TYPE __OFF64_T_TYPE __off64_t;
./bits/typesizes.h:38:#define __OFF64_T_TYPE __SQUAD_TYPE
./bits/types.h:
108 #if __WORDSIZE == 32
109 # define __SQUAD_TYPE           __quad_t
120 #elif __WORDSIZE == 64
121 # define __SQUAD_TYPE           long int
133 #endif
54 /* quad_t is also 64 bits.  */

2:宏们:
在/usr/include/下grep搜吧。

关于ulimit -f:
指定:
#ulimit -f 10
#ulimit -a
file size (blocks, -f) 10
#
#./a.out
File size limit exceeded (core dumped)
#ll
-rw-r--r-- 1 root root 10240 May 11 15:21 large_systemcall

关于block的大小的查看:
linux用
#tune2fs -l /dev/sda7


参考资料:
ext3单文件大小上限:
http://suchalin.blog.163.com/blog/static/553046772009111911439752/
File size limit exceeded问题研究:
http://gcoder.blogbus.com/logs/48935534.html
block size大小:
http://blog.chinaunix.net/u/11765/showart_235505.html


找工作找的郁闷,
租房子退房子都非常郁闷,
最近时运不济,
心情太差。

以上,
BZ。

阅读(2670) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~