繁体   English   中英

你如何获得linux内核中文件的大小?

[英]How do you get the size of a file in the linux kernel?

我找到了这个链接( http://www.spinics.net/lists/newbies/msg41016.html )并且一直在研究这样做。 所以我在内核模块中编写了代码:

#include <linux/path.h>
#include <linux/namei.h>
#include <linux/fs.h>

struct path p;
struct kstat ks;
kern_path(filepath, 0, &p);
vfs_getattr(&p, &ks);
printk(KERN_INFO "size: %lld\n", ks.size);

哪个不会编译,因为:

/root/kernelmodule/hello.c:15: warning: passing argument 1 of ‘vfs_getattr’ from incompatible pointer type
include/linux/fs.h:2563: note: expected ‘struct vfsmount *’ but argument is of type ‘struct path *’
/root/kernelmodule/hello.c:15: warning: passing argument 2 of ‘vfs_getattr’ from incompatible pointer type
include/linux/fs.h:2563: note: expected ‘struct dentry *’ but argument is of type ‘struct kstat *’
/root/kernelmodule/hello.c:15: error: too few arguments to function ‘vfs_getattr’

所以我真的很困惑,因为我在看这个文档: http : //lxr.free-electrons.com/source/fs/stat.c#L40

现在我在 /linux/fs.h 中看到 vfs_getattr 的原型是:

extern int vfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);

任何人都可以帮助我实施吗? 我正在阅读 vfsmount 和 dentry,但仍然迷路了。

对该函数的调用取决于您使用的内核版本。 这两个参数版本是在 3.8 和 3.9 之间引入的。 因此,如果您使用的是内核 3.8 或更早版本,则需要“三个参数”,而 3.9 以后,则需要两个参数。

如果你真的想在内核模式下这样做,在比 3.9 更旧的内核上,你最好使用vfs_fstatvfs_stat

但是,处理内核中的文件是不受欢迎的,您可能需要考虑是否没有更好的替代方案 - 例如,如果您想将一些文件内容加载到系统上的主板的内存中,您可以在用户模式进程中加载​​文件,然后通过一些私有的 IOCTL 类型函数将加载的部分传递到内核中。 这更加“内核友好”,如果您打算尝试将您的驱动程序/模块包含在整个内核源代码中,您可能需要这样做。

vfs_stat是一个选项。

下面是一个例子:

#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/stat.h>

static char *load_file(char* filename, int *input_size)
{
        struct kstat *stat;
        struct file *fp;
        mm_segment_t fs;
        loff_t pos = 0;
        char *buf;

        fp = filp_open(filename, O_RDWR, 0644);
                if (IS_ERR(fp)) {
                        printk("Open file error!\n");
                        return ERR_PTR(-ENOENT);
        }

        fs = get_fs();
        set_fs(KERNEL_DS);
        
        stat =(struct kstat *) kmalloc(sizeof(struct kstat), GFP_KERNEL);
        if (!stat)
                return ERR_PTR(-ENOMEM);

        vfs_stat(filename, stat);
        *input_size = stat->size;

        buf = kmalloc(*input_size, GFP_KERNEL);
                if (!buf) {
                        kfree(stat);
                        printk("malloc input buf error!\n");
                        return ERR_PTR(-ENOMEM);
                }
        kernel_read(fp, buf, *input_size, &pos);

        filp_close(fp, NULL);
        set_fs(fs);
        kfree(stat);
        return buf;
}

由于大小未知,所以我们需要在函数内部进行kmalloc,因此buf在以后不再使用时需要kfree

vfs_stat 返回一个奇怪的错误:modpost: "vfs_fstatat" [/mydir/module.ko] 未定义! 所以我更喜欢使用 vfs_getattr 或 vfs_llseek

static char *load_file(char* filename)
{
    struct kstat *stat;
    struct file *fp;
    mm_segment_t fs;
    loff_t pos = 0;
    char *buf;
    int input_size;
    int rc;
    //loff_t mPos;

    fp = filp_open(filename, O_RDONLY, 0644);// O_RDWR O_RDONLY O_WRONLY O_APPEND O_CREAT
            if (IS_ERR(fp)) {
                    printk("Open file error!\n");
                    return ERR_PTR(-ENOENT);
    }

    fs = get_fs();
    set_fs(KERNEL_DS);
    
    stat =(struct kstat *) kmalloc(sizeof(struct kstat), GFP_KERNEL);

    rc = vfs_getattr(&fp->f_path, stat, STATX_SIZE, AT_STATX_SYNC_AS_STAT);
    if(rc != 0){
        printk("vfs_getattr Error");
    }
    //OR symply
    //mPos = vfs_llseek(fp, 0, SEEK_END);
    
    input_size = stat->size;
    //input_size = (int)mPos;

    buf = kmalloc(input_size, GFP_KERNEL);
            if (!buf) {
                    kfree(stat);
                    printk("malloc input buf error!\n");
                    return ERR_PTR(-ENOMEM);
            }
    kernel_read(fp, buf, input_size, &pos);

    filp_close(fp, NULL);
    set_fs(fs);
    kfree(stat);
    return buf;
}

如果您已经有一个来自filp_open的打开file* filp ,您可以像这样读取大小:

loff_t size = i_size_read(file_inode(filp));

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM