簡體   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