zoukankan      html  css  js  c++  java
  • Samba共享传输大文件(ex:1G)失败的问题

    1:问题描述

      1.1 基本信息

      遇见这样一个bug,路由器有USB share的功能,可将U盘内的文件通过samba和LAN端PC机中文件进行共享,测试发现小文件可正常共享,一旦文件大了(比如1G左右),window端便显示一直在计算文件大小,最后客户端(LAN pc)会因为服务器许久不回一个Subcommand:SET_FILE_INFO(0x0008)的报文而出现timeout,导致文件传输失败.

    过了一段时间后客户端发出timeout [RST] 报文(windows会弹出异常对话框取消文件传输)

       重要的是对于NTFS的格式的U盘是正常的,只有FAT32格式的U盘有这个问题.

    2:解决方法

      2.1 刚开始我觉得FAT32与NTFS的分区方式不同,可是了解到FAT32分区方式单个文件最大是4G,所以排除U盘本身问题,问题还是出在Samba服务器或者linux系统中(之所以怀疑linux系统是因为我在任何PC机上拷文件到此U盘都没问题)

      2.2 然后先debug samba源码,重点注意有关文件size和fat格式处理的相关代码,然后再源码中(samba-3.0.24sourcesmbdvfs-wrap.c)看见了这个:

    int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, int fd, SMB_OFF_T len)
    {
        int result = -1;
        SMB_STRUCT_STAT st;
        char c = 0;
        SMB_OFF_T currpos;
    
        START_PROFILE(syscall_ftruncate);
    
        if (lp_strict_allocate(SNUM(fsp->conn))) {
            result = strict_allocate_ftruncate(handle, fsp, fd, len);
            END_PROFILE(syscall_ftruncate);
            return result;
        }
    
        /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
           sys_ftruncate if the system supports it. Then I discovered that
           you can have some filesystems that support ftruncate
           expansion and some that don't! On Linux fat can't do
           ftruncate extend but ext2 can. */
        
        result = sys_ftruncate(fd, len);
        if (result == 0)
            goto done;
        
        /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
           extend a file with ftruncate. Provide alternate implementation
           for this */
        currpos = SMB_VFS_LSEEK(fsp, fd, 0, SEEK_CUR);
        if (currpos == -1) {
            goto done;
        }
    
        /* Do an fstat to see if the file is longer than the requested
           size in which case the ftruncate above should have
           succeeded or shorter, in which case seek to len - 1 and
           write 1 byte of zero */
        if (SMB_VFS_FSTAT(fsp, fd, &st) == -1) {
            goto done;
        }
    
    #ifdef S_ISFIFO
        if (S_ISFIFO(st.st_mode)) {
            result = 0;
            goto done;
        }
    #endif
    
        if (st.st_size == len) {
            result = 0;
            goto done;
        }
    
        if (st.st_size > len) {
            /* the sys_ftruncate should have worked */
            goto done;
        }
    
        if (SMB_VFS_LSEEK(fsp, fd, len-1, SEEK_SET) != len -1)
            goto done;
    
        if (SMB_VFS_WRITE(fsp, fd, &c, 1)!=1)
            goto done;
    
        /* Seek to where we were */
        if (SMB_VFS_LSEEK(fsp, fd, currpos, SEEK_SET) != currpos)
            goto done;
        result = 0;
    
      done:
    
        END_PROFILE(syscall_ftruncate);
        return result;
    }

       红色的两个函数是关键,在调试中发现,sys_ftruncate和SMB_VFS_WRITE在创建大一点的文件时会耗费很多的时间,这也是服务器迟迟不回复客户端SET_FILE_INFO请求的原因。所以将这两个函数屏蔽之后就正常了.

      也可以不屏蔽sys_ftruncate,可以将kernel的ftruncate函数实现修改一下:linux-3.14fsfatfile.c 中函数fat_setattr

    if (attr->ia_valid & ATTR_SIZE) {
            if (attr->ia_size > inode->i_size) {//if current size grenter than old size,extend it
            // if we allow this, fat ftruncate extend large size will cause samba wait a long long time.
            #if 1
                error = -EPERM;
                goto out;
            #else
                error = fat_cont_expand(inode, attr->ia_size);
                if (error || attr->ia_valid == ATTR_SIZE)
                    goto out;
                attr->ia_valid &= ~ATTR_SIZE;
            #endif
            }
        }

      这样也可以解决问题.

     总结:

      不管是FAT32还是NTFS都是先接收数据然后写入到文件系统中,所以samba使用ftruncate函数扩展文件到文件系统中,我猜测可能是FAT32是把文件一次性使用fat_setattr函数写到文件系统中(大文件导致写入的时间过长),而NTFS是收到多少写入多少.这样导致FAT32不行而NTFS可行.

  • 相关阅读:
    java 手写 jvm高性能缓存
    给大家推荐一款非常好用的表单验证插件:lr-verify.js
    如何设计处优秀的Restful API
    volatile、static
    微服务学习(一):微服务介绍
    spark过滤算子+StringIndexer算子出发的一个逻辑bug
    spark和深度学习集成调研
    收藏一个不错的个人博客
    二分法中的逼近法
    netty服务端启动--ServerBootstrap源码解析
  • 原文地址:https://www.cnblogs.com/Flychown/p/6548021.html
Copyright © 2011-2022 走看看