file_operations_v2.0

本文档展示了如何模仿Linux内核中的file_operations结构来编写自定义的文件操作函数。代码示例中定义了一个名为my_file_operation的结构,包含了open、read_、write_等函数指针,并实现了简单的文件打开、读取和写入操作。同时,还提供了一个名为first_drv_init的初始化函数来演示这些操作。

file_operations 模仿写程序

file_operations

参考内核代码 file_operation

struct file_operations {
	struct module *owner;
	loff_t (*llseek) (struct file *, loff_t, int);
	ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
	ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
	int (*open) (struct inode *, struct file *);
	xxxxxxxxxxxxxxxxxx
};

file_operations 模仿写程序

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* handy sizes */
#define SIZE_1	                        (1 << 0)  //1
#define SIZE_2	                        (1 << 1)  //2
#define SIZE_4	                        (1 << 2)  //4
#define SIZE_8	                        (1 << 3)  //8
#define SIZE_16	                        (1 << 4)  //16
#define SIZE_32	                        (1 << 5)  //32
#define SIZE_64	                        (1 << 6)  //64
#define SIZE_128	                    (1 << 7)  //128
#define SIZE_256	                    (1 << 8)  //256
#define SIZE_512	                    (1 << 9)  //512 /* 512 Not a change, but a change it */
#define SIZE_1024	                    (1 << 10) //1024
#define SZ_1K                           0x00000400
#define SZ_4K                           0x00001000
#define SZ_8K                           0x00002000
#define SZ_16K                          0x00004000
#define SZ_64K                          0x00010000
#define SZ_128K                         0x00020000
#define SZ_256K                         0x00040000
#define SZ_512K                         0x00080000

#define SZ_1M                           0x00100000
#define SZ_2M                           0x00200000
#define SZ_4M                           0x00400000
#define SZ_8M                           0x00800000
#define SZ_16M                          0x01000000
#define SZ_32M                          0x02000000
#define SZ_64M                          0x04000000
#define SZ_128M                         0x08000000
#define SZ_256M                         0x10000000
#define SZ_512M                         0x20000000

#define SZ_1G                           0x40000000
#define SZ_2G                           0x80000000

#define SIZE_1	    (1 << 0)  //1
#define SIZE_2	    (1 << 1)  //2
#define SIZE_4	    (1 << 2)  //4
#define SIZE_8	    (1 << 3)  //8
#define SIZE_16	    (1 << 4)  //16
#define SIZE_32	    (1 << 5)  //32
#define SIZE_64	    (1 << 6)  //64
#define SIZE_128	(1 << 7)  //128
#define SIZE_256	(1 << 8)  //256
#define SIZE_512	(1 << 9)  //512 /* 512 Not a change, but a change it */
#define SIZE_1024	(1 << 10) //1024
#define SIZE_2048	(1 << 11) //2048
#define SIZE_4096	(1 << 12) //4096
#define SIZE_8192	(1 << 13) //8192
#define SIZE_16384	(1 << 14) //16384 /* Truncating from open(O_TRUNC) */
#define SIZE_32768	(1 << 15) //32768
#define SIZE_65536	(1 << 16) //65536

char name[32] = "Version_1.00";
/*
 * NOTE:
 * read, write, poll, fsync, readv, writev, unlocked_ioctl and compat_ioctl
 * can be called without the big kernel lock held in all filesystems.
 */
struct my_file_operation {
    struct module *owner;
    char *pName;
    FILE *(*open) (const char *filename);
    int (*read_) (FILE *r_FILE, char *data);
    ssize_t (*write_) (const char *data);
    void (*print_hex) (char *buf, int len, const char *name);
};

#if 1
static void PrintHexName(char *buf, int len, const char *name)
{
    int i;
    printf("%s (len=%d): ",name, len);
    for(i = 0; i < len; i ++)
        printf("%02x ", buf[i]);
    printf("\n");
}
#endif

static FILE * first_drv_open(const char *filename)
{
    printf("first_drv_open\n");
    FILE *r_FILE = NULL;
    r_FILE = fopen(filename, "r");
    if(r_FILE == NULL)
    {
        printf("fopen failed... \n");
        return NULL;
    }

    return r_FILE;
}

static int first_drv_read(FILE *r_FILE, char *data)
{
    printf("first_drv_open\n");
    int ret = fread(data, 1, 1024, r_FILE);
    fclose(r_FILE);

    //PrintHexName(data, 1024, "data");
    return ret;
}
static ssize_t first_drv_write(const char *data)
{
    printf("first_drv_write\n");
    return 0;
}

static struct my_file_operation test_fops = {
    .pName  =   name,
    .open  =   first_drv_open,
    .read_  =   first_drv_read,
    .write_	=	first_drv_write,
    .print_hex = PrintHexName,
};

static int first_drv_init(void)
{
    char *r_data = NULL;
    FILE *r_file = NULL;
    const char filename[256] = "1.txt";

    printf("test_fops.pName:%s\n",test_fops.pName);

    r_data = (char *)malloc(10*1024*1024);
    r_file = test_fops.open(filename);
    int len = test_fops.read_(r_file, r_data);

    printf("data printf....\n");
    test_fops.print_hex(r_data, len, "FC");

    return 0;
}

static void first_drv_exit(void)
{
    printf("first_drv_exit...\n");
}

int main()
{
    printf("first_drv_init... ATTR_KILL_SUID:%d\n",SIZE_256);

    first_drv_init();
    first_drv_exit();

    return 0;
}
page_size_compat.h : /* SPDX-License-Identifier: GPL-2.0 */ #ifndef __LINUX_PAGE_SIZE_COMPAT_H #define __LINUX_PAGE_SIZE_COMPAT_H /* * include/linux/page_size_compat.h * * Page Size Emulation * * Copyright (c) 2024, Google LLC. * Author: Kalesh Singh <kaleshsingh@goole.com> * Helper macros for page size emulation. * * The macros for use with the emulated page size are all * namespaced by the prefix '__'. * * The valid range of androidboot.page_shift is [13, 16]. * In other words page sizes of 8KB, 16KB, 32KB and 64KB can * be emulated. */ #include <asm/page.h> #define __MAX_PAGE_SHIFT 14 #define __MAX_PAGE_SIZE (_AC(1,UL) << __MAX_PAGE_SHIFT) #define __MAX_PAGE_MASK (~(__MAX_PAGE_SIZE-1)) #ifndef __ASSEMBLY__ #include <linux/align.h> #include <linux/jump_label.h> #include <linux/mman.h> #include <linux/printk.h> #include <linux/sched.h> #define pgcompat_err(fmt, ...) \ pr_err("pgcompat [%i (%s)]: " fmt, task_pid_nr(current), current->comm, ## __VA_ARGS__) DECLARE_STATIC_KEY_FALSE(page_shift_compat_enabled); extern int page_shift_compat; #ifdef CONFIG_SHMEM extern vm_fault_t shmem_fault(struct vm_fault *vmf); #endif /* CONFIG_SHMEM */ #ifdef CONFIG_F2FS_FS extern vm_fault_t f2fs_filemap_fault(struct vm_fault *vmf); #endif /* CONFIG_F2FS_FS */ #ifdef CONFIG_X86_64 static __always_inline unsigned __page_shift(void) { if (static_branch_unlikely(&page_shift_compat_enabled)) return page_shift_compat; else return PAGE_SHIFT; } #else /* !CONFIG_X86_64 */ #define __page_shift() PAGE_SHIFT #endif /* CONFIG_X86_64 */ #define __PAGE_SHIFT __page_shift() #define __PAGE_SIZE (_AC(1,UL) << __PAGE_SHIFT) #define __PAGE_MASK (~(__PAGE_SIZE-1)) #define __PAGE_ALIGN(addr) ALIGN(addr, __PAGE_SIZE) #define __PAGE_ALIGN_DOWN(addr) ALIGN_DOWN(addr, __PAGE_SIZE) #define __offset_in_page(p) ((unsigned long)(p) & ~__PAGE_MASK) #define __offset_in_page_log(addr) \ ({ \ if (static_branch_unlikely(&page_shift_compat_enabled) && \ __offset_in_page(addr)) \ pgcompat_err("%s: addr (0x%08lx) not page aligned", __func__, addr); \ (__offset_in_page(addr)); \ }) #define __PAGE_ALIGNED(addr) (!__offset_in_page_log(addr)) /* * Increases @size by an adequate amount to allow __PAGE_SIZE alignment * by rounding up; given that @size is already a multiple of the * base page size (PAGE_SIZE). * * Example: * If __PAGE_SHIFT == PAGE_SHIFT == 12 * @size is increased by 0 * ((1 << (0)) - 1) << PAGE_SHIFT * (1 ) - 1) << PAGE_SHIFT * (0 ) << PAGE_SHIFT * * If __PAGE_SHIFT == 13 and PAGE_SHIFT == 12 * @size is increased by PAGE_SIZE (4KB): * ((1 << (1)) - 1) << PAGE_SHIFT * (2 ) - 1) << PAGE_SHIFT * (1 ) << PAGE_SHIFT * If __PAGE_SHIFT == 14 and PAGE_SHIFT == 12 * @size is increased by 3xPAGE_SIZE (12KB): * ((1 << (2)) - 1) << PAGE_SHIFT * (4 ) - 1) << PAGE_SHIFT * (3 ) << PAGE_SHIFT * ... */ #define __PAGE_SIZE_ROUND_UP_ADJ(size) \ ((size) + (((1 << (__PAGE_SHIFT - PAGE_SHIFT)) - 1) << PAGE_SHIFT)) /* * VMA is exempt from emulated page align requirements * * NOTE: __MAP_NO_COMPAT is not new UABI it is only ever set by the kernel * in ___filemap_fixup() */ #define __VM_NO_COMPAT _BITULL(58) #define __MAP_NO_COMPAT _BITUL(31) /* * Conditional page-alignment based on mmap flags * * If the VMA is allowed to not respect the emulated page size, align using the * base PAGE_SIZE, else align using the emulated __PAGE_SIZE. */ #define __COMPAT_PAGE_ALIGN(size, flags) \ (flags & __MAP_NO_COMPAT) ? PAGE_ALIGN(size) : __PAGE_ALIGN(size) /* * Combines the mmap "flags" argument into "vm_flags" * * If page size emulation is enabled, adds translation of the no-compat flag. */ static __always_inline unsigned long calc_vm_flag_bits(struct file *file, unsigned long flags) { unsigned long flag_bits = __calc_vm_flag_bits(file, flags); if (static_branch_unlikely(&page_shift_compat_enabled)) flag_bits |= _calc_vm_trans(flags, __MAP_NO_COMPAT, __VM_NO_COMPAT ); return flag_bits; } extern unsigned long ___filemap_len(struct inode *inode, unsigned long pgoff, unsigned long len, unsigned long flags); extern void ___filemap_fixup(unsigned long addr, unsigned long prot, unsigned long file_backed_len, unsigned long len); static __always_inline unsigned long __filemap_len(struct inode *inode, unsigned long pgoff, unsigned long len, unsigned long flags) { if (static_branch_unlikely(&page_shift_compat_enabled)) return ___filemap_len(inode, pgoff, len, flags); else return len; } static __always_inline void __filemap_fixup(unsigned long addr, unsigned long prot, unsigned long file_backed_len, unsigned long len) { if (static_branch_unlikely(&page_shift_compat_enabled)) ___filemap_fixup(addr, prot, file_backed_len, len); } extern void __fold_filemap_fixup_entry(struct vma_iterator *iter, unsigned long *end); extern int __fixup_swap_header(struct file *swap_file, struct address_space *mapping); #ifdef CONFIG_PROC_PAGE_MONITOR extern bool __is_emulated_pagemap_file(struct file *file); #else static inline bool __is_emulated_pagemap_file(struct file *file) { return false; } #endif #endif /* !__ASSEMBLY__ */ #endif /* __LINUX_PAGE_SIZE_COMPAT_H */ mman.h: /* SPDX-License-Identifier: GPL-2.0 */ #ifndef _LINUX_MMAN_H #define _LINUX_MMAN_H #ifndef __GENKSYMS__ #include <linux/fs.h> #endif #include <linux/mm.h> #include <linux/percpu_counter.h> #include <linux/atomic.h> #include <uapi/linux/mman.h> /* * Arrange for legacy / undefined architecture specific flags to be * ignored by mmap handling code. */ #ifndef MAP_32BIT #define MAP_32BIT 0 #endif #ifndef MAP_ABOVE4G #define MAP_ABOVE4G 0 #endif #ifndef MAP_HUGE_2MB #define MAP_HUGE_2MB 0 #endif #ifndef MAP_HUGE_1GB #define MAP_HUGE_1GB 0 #endif #ifndef MAP_UNINITIALIZED #define MAP_UNINITIALIZED 0 #endif #ifndef MAP_SYNC #define MAP_SYNC 0 #endif /* * The historical set of flags that all mmap implementations implicitly * support when a ->mmap_validate() op is not provided in file_operations. * * MAP_EXECUTABLE and MAP_DENYWRITE are completely ignored throughout the * kernel. */ #define LEGACY_MAP_MASK (MAP_SHARED \ | MAP_PRIVATE \ | MAP_FIXED \ | MAP_ANONYMOUS \ | MAP_DENYWRITE \ | MAP_EXECUTABLE \ | MAP_UNINITIALIZED \ | MAP_GROWSDOWN \ | MAP_LOCKED \ | MAP_NORESERVE \ | MAP_POPULATE \ | MAP_NONBLOCK \ | MAP_STACK \ | MAP_HUGETLB \ | MAP_32BIT \ | MAP_ABOVE4G \ | MAP_HUGE_2MB \ | MAP_HUGE_1GB) extern int sysctl_overcommit_memory; extern int sysctl_overcommit_ratio; extern unsigned long sysctl_overcommit_kbytes; extern struct percpu_counter vm_committed_as; #ifdef CONFIG_SMP extern s32 vm_committed_as_batch; extern void mm_compute_batch(int overcommit_policy); #else #define vm_committed_as_batch 0 static inline void mm_compute_batch(int overcommit_policy) { } #endif unsigned long vm_memory_committed(void); static inline void vm_acct_memory(long pages) { percpu_counter_add_batch(&vm_committed_as, pages, vm_committed_as_batch); } static inline void vm_unacct_memory(long pages) { vm_acct_memory(-pages); } /* * Allow architectures to handle additional protection and flag bits. The * overriding macros must be defined in the arch-specific asm/mman.h file. */ #ifndef arch_calc_vm_prot_bits #define arch_calc_vm_prot_bits(prot, pkey) 0 #endif #ifndef arch_calc_vm_flag_bits #define arch_calc_vm_flag_bits(file, flags) 0 #endif #ifndef arch_validate_prot /* * This is called from mprotect(). PROT_GROWSDOWN and PROT_GROWSUP have * already been masked out. * * Returns true if the prot flags are valid */ static inline bool arch_validate_prot(unsigned long prot, unsigned long addr) { return (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC | PROT_SEM)) == 0; } #define arch_validate_prot arch_validate_prot #endif #ifndef arch_validate_flags /* * This is called from mmap() and mprotect() with the updated vma->vm_flags. * * Returns true if the VM_* flags are valid. */ static inline bool arch_validate_flags(unsigned long flags) { return true; } #define arch_validate_flags arch_validate_flags #endif /* * Optimisation macro. It is equivalent to: * (x & bit1) ? bit2 : 0 * but this version is faster. * ("bit1" and "bit2" must be single bits) */ #define _calc_vm_trans(x, bit1, bit2) \ ((!(bit1) || !(bit2)) ? 0 : \ ((bit1) <= (bit2) ? ((x) & (bit1)) * ((bit2) / (bit1)) \ : ((x) & (bit1)) / ((bit1) / (bit2)))) /* * Combine the mmap "prot" argument into "vm_flags" used internally. */ static inline unsigned long calc_vm_prot_bits(unsigned long prot, unsigned long pkey) { return _calc_vm_trans(prot, PROT_READ, VM_READ ) | _calc_vm_trans(prot, PROT_WRITE, VM_WRITE) | _calc_vm_trans(prot, PROT_EXEC, VM_EXEC) | arch_calc_vm_prot_bits(prot, pkey); } /* * Combine the mmap "flags" argument into "vm_flags" used internally. */ static inline unsigned long __calc_vm_flag_bits(struct file *file, unsigned long flags) { return _calc_vm_trans(flags, MAP_GROWSDOWN, VM_GROWSDOWN ) | _calc_vm_trans(flags, MAP_LOCKED, VM_LOCKED ) | _calc_vm_trans(flags, MAP_SYNC, VM_SYNC ) | arch_calc_vm_flag_bits(file, flags); } unsigned long vm_commit_limit(void); #ifndef arch_memory_deny_write_exec_supported static inline bool arch_memory_deny_write_exec_supported(void) { return true; } #define arch_memory_deny_write_exec_supported arch_memory_deny_write_exec_supported #endif /* * Denies creating a writable executable mapping or gaining executable permissions. * * This denies the following: * * a) mmap(PROT_WRITE | PROT_EXEC) * * b) mmap(PROT_WRITE) * mprotect(PROT_EXEC) * * c) mmap(PROT_WRITE) * mprotect(PROT_READ) * mprotect(PROT_EXEC) * * But allows the following: * * d) mmap(PROT_READ | PROT_EXEC) * mmap(PROT_READ | PROT_EXEC | PROT_BTI) * * This is only applicable if the user has set the Memory-Deny-Write-Execute * (MDWE) protection mask for the current process. * * @old specifies the VMA flags the VMA originally possessed, and @new the ones * we propose to set. * * Return: false if proposed change is OK, true if not ok and should be denied. */ static inline bool map_deny_write_exec(unsigned long old, unsigned long new) { /* If MDWE is disabled, we have nothing to deny. */ if (!test_bit(MMF_HAS_MDWE, &current->mm->flags)) return false; /* If the new VMA is not executable, we have nothing to deny. */ if (!(new & VM_EXEC)) return false; /* Under MDWE we do not accept newly writably executable VMAs... */ if (new & VM_WRITE) return true; /* ...nor previously non-executable VMAs becoming executable. */ if (!(old & VM_EXEC)) return true; return false; } #endif /* _LINUX_MMAN_H */ 两个文件上传,报错信息: /home/work/mnt/miui_codes1/build_home_rom-odm-merged/bazel-cache/b1970bca595d87272e733a0c3ce8a31e/sandbox/processwrapper-sandbox/160/execroot/_main/common/include/linux/mman.h:161:9: error: division by zero is undefined [-Werror,-Wdivision-by-zero] /home/work/mnt/miui_codes1/build_home_rom-odm-merged/bazel-cache/b1970bca595d87272e733a0c3ce8a31e/sandbox/processwrapper-sandbox/160/execroot/_main/common/include/linux/page_size_compat.h:136:16: error: division by zero is undefined [-Werror,-Wdivision-by-zero] 帮我修复
最新发布
10-25
ubantu下编译运行以下代码:#include <linux/module.h> #include <linux/kernel.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/slab.h> #include <linux/list.h> #include <linux/netfilter.h> #include <linux/netfilter_ipv4.h> #include <linux/ip.h> #include <linux/icmp.h> #include <linux/net.h> #include <linux/skbuff.h> #include <linux/version.h> #include <linux/udp.h> #include <linux/tcp.h> // 定义数据结构存储Ping统计信息 struct ping_stat { __be32 src_ip; // 源IP地址 unsigned int count; // 请求计数 __be16 icmp_id; // ICMP标识符 struct list_head list; // 链表头 }; // 全局变量 static LIST_HEAD(ping_list); static DEFINE_SPINLOCK(ping_lock); // Netfilter钩子函数(增强版) static unsigned int hook_func(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) { struct iphdr *ip; struct icmphdr *icmp; struct ping_stat *entry, *new_entry = NULL; int found = 0; // 调试信息:记录进入钩子 printk(KERN_DEBUG "Netfilter hook triggered\n"); // 检查skb是否有效 if (!skb) { printk(KERN_WARNING "Invalid skb in hook\n"); return NF_ACCEPT; } // 获取IP头 ip = ip_hdr(skb); if (!ip) { printk(KERN_WARNING "No IP header found\n"); return NF_ACCEPT; } // 调试信息:打印源IP printk(KERN_DEBUG "Processing packet from: %pI4\n", &ip->saddr); // 检查协议类型 if (ip->protocol != IPPROTO_ICMP) { printk(KERN_DEBUG "Non-ICMP protocol: %d\n", ip->protocol); return NF_ACCEPT; } // 获取ICMP头 icmp = icmp_hdr(skb); if (!icmp) { printk(KERN_WARNING "No ICMP header found\n"); return NF_ACCEPT; } // 检查是否为ICMP Echo请求 if (icmp->type != ICMP_ECHO) { printk(KERN_DEBUG "Non-ECHO ICMP type: %d\n", icmp->type); return NF_ACCEPT; } // 调试信息:打印ICMP标识符 printk(KERN_INFO "Captured ICMP Echo from %pI4 (ID: %u)\n", &ip->saddr, ntohs(icmp->un.echo.id)); // 在列表中查找现有条目 spin_lock(&ping_lock); list_for_each_entry(entry, &ping_list, list) { if (entry->src_ip == ip->saddr) { found = 1; break; } } if (found) { // 更新现有条目 entry->count++; entry->icmp_id = icmp->un.echo.id; printk(KERN_DEBUG "Updated entry for %pI4 (count: %u)\n", &entry->src_ip, entry->count); } else { // 创建新条目 spin_unlock(&ping_lock); new_entry = kmalloc(sizeof(*new_entry), GFP_ATOMIC); if (!new_entry) { printk(KERN_WARNING "Failed to allocate memory for new entry\n"); return NF_ACCEPT; } new_entry->src_ip = ip->saddr; new_entry->count = 1; new_entry->icmp_id = icmp->un.echo.id; INIT_LIST_HEAD(&new_entry->list); spin_lock(&ping_lock); list_add(&new_entry->list, &ping_list); printk(KERN_INFO "Created new entry for %pI4\n", &new_entry->src_ip); } spin_unlock(&ping_lock); return NF_ACCEPT; } // Netfilter钩子操作结构 static struct nf_hook_ops nf_ops = { .hook = hook_func, .pf = NFPROTO_IPV4, .hooknum = NF_INET_PRE_ROUTING, .priority = NF_IP_PRI_FIRST, }; // proc文件系统操作(增强版) static void *seq_start(struct seq_file *s, loff_t *pos) { spin_lock(&ping_lock); return seq_list_start(&ping_list, *pos); } static void *seq_next(struct seq_file *s, void *v, loff_t *pos) { return seq_list_next(v, &ping_list, pos); } static void seq_stop(struct seq_file *s, void *v) { spin_unlock(&ping_lock); } static int seq_show(struct seq_file *s, void *v) { struct ping_stat *entry = list_entry(v, struct ping_stat, list); // 调试信息:记录显示操作 printk(KERN_DEBUG "Displaying entry for %pI4\n", &entry->src_ip); // 显示表头(首次调用时) if (s->count == 0) { seq_puts(s, "Source IP Request Count ICMP ID\n"); seq_puts(s, "----------------------------------------\n"); } // 显示条目 seq_printf(s, "%-15pI4 %-20u %u\n", &entry->src_ip, entry->count, ntohs(entry->icmp_id)); return 0; } static const struct seq_operations ping_seq_ops = { .start = seq_start, .next = seq_next, .stop = seq_stop, .show = seq_show, }; static int ping_open(struct inode *inode, struct file *file) { printk(KERN_DEBUG "Proc file opened\n"); return seq_open(file, &ping_seq_ops); } static const struct file_operations ping_fops = { .owner = THIS_MODULE, .open = ping_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, }; // 模块初始化(增强版) static int __init ping_stat_init(void) { // 创建proc文件 struct proc_dir_entry *proc_entry; proc_entry = proc_create("ping_stats", 0444, NULL, &ping_fops); if (!proc_entry) { printk(KERN_ERR "Failed to create proc entry\n"); return -ENOMEM; } // 注册Netfilter钩子 int ret = nf_register_net_hook(&init_net, &nf_ops); if (ret != 0) { remove_proc_entry("ping_stats", NULL); printk(KERN_ERR "Failed to register Netfilter hook: %d\n", ret); return ret; } printk(KERN_INFO "Ping statistics module loaded successfully\n"); return 0; } // 模块退出 static void __exit ping_stat_exit(void) { struct ping_stat *entry, *tmp; // 注销Netfilter钩子 nf_unregister_net_hook(&init_net, &nf_ops); // 删除proc文件 remove_proc_entry("ping_stats", NULL); // 释放所有内存 spin_lock(&ping_lock); list_for_each_entry_safe(entry, tmp, &ping_list, list) { list_del(&entry->list); kfree(entry); } spin_unlock(&ping_lock); printk(KERN_INFO "Ping statistics module unloaded\n"); } module_init(ping_stat_init); module_exit(ping_stat_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Huaxi"); MODULE_DESCRIPTION("Enhanced Ping Request Statistics Module"); MODULE_VERSION("2.0");这是我的makefile# 内核模块编译Makefile obj-m := ping_stat.o # 指定模块名称(与.c文件名一致) KDIR := /lib/modules/$(shell uname -r)/build # 自动获取当前内核路径 PWD := $(shell pwd) # 获取当前目录 # 默认编译目标 all: $(MAKE) -C $(KDIR) M=$(PWD) modules # 清理编译产物 clean: $(MAKE) -C $(KDIR) M=$(PWD) clean 请给我具体的编译运行和测试流程
08-19
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

静思心远

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值