Search code examples
linux-kerneldriversystems-programming

Linux kernel_write function returns EFBIG when appending data to big file


The task is to write simple character device that copies all the data written to the device to tmp a file.

I use kernel_write function to write data to file and its work fine most of the cases. But when the output file size is bigger than 2.1 GB, kernel_write function fails with return value -27.

To write to file I use this function:

void writeToFile(void* buf, size_t size, loff_t *offset) {
    struct file* destFile;
    char* filePath = "/tmp/output";
    destFile = filp_open(filePath,  O_CREAT|O_WRONLY|O_APPEND, 0666);
    if (IS_ERR(destFile) || destFile == NULL) {
      printk("Cannot open destination file");
      return;
    }
    size_t res = kernel_write(destFile, buf, size, offset);
    printk("%ld", res);
    filp_close(destFile, NULL);
}

If the size of "/tmp/output" < 2.1 GB, this function works just fine.

If the size of "/tmp/output"> 2.1 GB, kernel_write starts to return -27.

How can I fix this?

Thanks


Solution

  • You need to enable Large File Support (LFS) with the O_LARGEFILE flag.

    The below code worked for me. Sorry, I made some other changes for debugging, but I commented above the relevant line.

    struct file* writeToFile(void* buf, size_t size, loff_t *offset) 
    {
        struct file* destFile;
        char* filePath = "/tmp/output";
        size_t res;
        
        // Add the O_LARGEFILE flag here
        destFile = filp_open(filePath, O_CREAT | O_WRONLY | O_APPEND | O_LARGEFILE, 0666);
        if (IS_ERR(destFile)) 
        {
            printk("Error in opening: <%ld>", (long)destFile);
            return destFile;
        }
        if (destFile == NULL)
        {
            printk("Error in opening: null");
            return destFile;
        }
        
        res = kernel_write(destFile, buf, size, offset);
        printk("CODE: <%ld>", res);
        filp_close(destFile, NULL);
    
        return destFile;
    }
    

    To test it, I created a file with fallocate -l 3G /tmp/output, then removed the O_CREAT flag because it was giving the kernel permission errors.


    I should add a disclaimer that a lot of folks says that File I/O from the kernel is a bad idea. Even while testing this out on my own, I accidentally crashed my computer twice due to dumb errors.

    Maybe do this instead: Read/Write from /proc File