我正在尝试编写一个proc驱动程序,它将打印驱动程序历史记录,直到最后10次更新。在这个驱动程序中,我没有添加我想要打印的内核数据结构。但是,我依靠'i'值将值打印到10。这是我的代码。
#include <linux/init.h>
#include <linux/module.h> /** needed by all modules **/
#include <linux/kernel.h> /** This is for KERN_ALERT **/
#include <linux/proc_fs.h> /** This is for procfs **/
#include <linux/seq_file.h>
#include <linux/cdev.h> /** character device **/
#include <linux/device.h> /** for sys device registration in /dev/ and /sys/class **/
/** For class registration to work, you need GPL license **/
MODULE_LICENSE("GPL");
#define PROCFS_NAME "basicProcfs1"
static struct cdev basicCdev;
static struct class *basicDriverClass;
struct proc_dir_entry *procFileEntry = NULL;
static int basicMajorNumber = 0;
#define NUMBER_OF_MINOR_DEVICE (0)
#define NUM_MSG_HIST_ENTRIES (10)
static int gui32CmdMsgHistoryStartIndex=0;
/** This File operation table for proc file system **/
static int av_cmd_hist_show( struct seq_file *filp, void *v )
{
int i = *((int *)v);
printk("the av_cmd_hist_show called\r\n");
if ( i == 0)
{
seq_printf(filp, "Sequential print for debugging-- called for i-times i.e. 10 times \r\n");
}
seq_printf(filp, "Hello SJ proc! %d\r\n", i);
return 0;
}
static void av_cmd_hist_stop( struct seq_file *filp, void *v )
{
printk("av_cmd_hist_stop called..\r\n");
} /* av_cmd_hist_stop */
static void *av_cmd_hist_next( struct seq_file *filp, void *v, loff_t *pos )
{
(*pos)++;
printk("av_cmd_hist_next called..\r\n");
return( ( *pos < NUM_MSG_HIST_ENTRIES ) ? pos : NULL );
} /* av_cmd_hist_next */
static void *av_cmd_hist_start( struct seq_file *filp, loff_t *pos )
{
if( *pos == 0 )
{
printk("av_cmd_hist_start.. Initial..\r\n");
gui32CmdMsgHistoryStartIndex = 5;
}
printk("av_cmd_hist_start.. the *pos=0..\r\n");
return( ( *pos < NUM_MSG_HIST_ENTRIES ) ? pos : NULL );
} /* av_cmd_hist_start */
static struct seq_operations av_seq_cmd_hist_fops =
{
.start = av_cmd_hist_start,
.next = av_cmd_hist_next,
.stop = av_cmd_hist_stop,
.show = av_cmd_hist_show
};
static int basicProcShow(struct seq_file *m, void *v) {
seq_printf(m, "Hello SJ proc!\n");
return 0;
}
static int basicProcOpen(struct inode *inode, struct file *file)
{
int i;
i = seq_open( file, &av_seq_cmd_hist_fops );
return i;
//return single_open(file, basicProcShow, NULL);
}
/** Put data into the proc fs file **/
static const struct file_operations basic_proc_fops =
{
.owner = THIS_MODULE,
.open = basicProcOpen,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static struct file_operations fops = {
.read = NULL,
.write = NULL,
.open = NULL,
.release = NULL
};
static void setup_cdev(struct cdev *dev, int minor, struct file_operations *fops)
{
int err = -1;
/** MKDEV call creates a device number i.e. combination of major and minor number **/
int devno = MKDEV(basicMajorNumber, minor);
/** Initiliaze character dev with fops **/
cdev_init(dev, fops);
/**owner and operations initialized **/
dev->owner = THIS_MODULE;
dev->ops = fops;
/** add the character device to the system**/
/** Here 1 means only 1 minor number, you can give 2 for 2 minor device, the last param is the count of minor number enrolled **/
err = cdev_add (dev, devno, 1);
if (err)
{
printk (KERN_NOTICE "Couldn't add cdev");
}
}
static int chrDriverInit(void)
{
int result;
dev_t dev;
printk("Welcome!! Device Init now..");
/** int alloc_chrdev_region(dev_t *dev, unsigned int firstminor,unsigned int count, char *name); **/
/** dev -> The dev_t variable type,which will get the major number that the kernel allocates. **/
/**The same name will appear in /proc/devices. **/
/** it is registering the character device **/
/** a major number will be dynamically allocated here **/
/** alloc_chrdev_region(&dev_num, FIRST_MINOR, COUNT, DEVICE_NAME); **/
result = alloc_chrdev_region(&dev, 0, NUMBER_OF_MINOR_DEVICE, "pSeudoDrv1");
if( result < 0 )
{
printk("Error in allocating device");
return -1;
}
/** From these two if's we are avoiding the manual mknod command to create the /dev/<driver> **/
/** creating class, and then device created removes the dependency of calling mknod **/
/** A good method - the mknod way is depreciated **/
/** mknod way is - mknod /dev/<driver_name> c <majorNumber> <minorNumber>
/** add the driver to /sys/class/chardrv **/
if ((basicDriverClass = class_create(THIS_MODULE, "chardrv")) == NULL) //$ls /sys/class
{
unregister_chrdev_region(dev, 1);
return -1;
}
/** add the driver to /dev/pSeudoDrv -- here **/
if (device_create(basicDriverClass, NULL, dev, NULL, "pSeudoDrv") == NULL) //$ls /dev/
{
class_destroy(basicDriverClass);
unregister_chrdev_region(dev, 1);
return -1;
}
/** let's see what major number was assigned by the Kernel **/
basicMajorNumber = MAJOR(dev);
printk("Kernel assigned major number is %d ..\r\n",basicMajorNumber );
/** Now setup the cdev **/
setup_cdev(&basicCdev,NUMBER_OF_MINOR_DEVICE, &fops);
/** Setup Proc Entry here **/
/** 0644 means -
* 0 - owning (user) : read and write - 110
* Group - only read - 100
* Other - only read - 100 **/
procFileEntry = proc_create(PROCFS_NAME, 0, NULL, &basic_proc_fops);
if ( procFileEntry == NULL)
{
remove_proc_entry(PROCFS_NAME, NULL);
}
return 0;
}
static void chrDriverExit(void)
{
/** A reverse - destroy mechansim -- the way it was created **/
printk("Releasing Simple Devs -- %s\r\n", __FUNCTION__);
/** delete the character driver added **/
cdev_del(&basicCdev);
/** destroy the device created **/
device_destroy(basicDriverClass, MKDEV(basicMajorNumber, 0));
/** destroy the class created **/
class_destroy(basicDriverClass);
/** unregister the chr dev **/
unregister_chrdev(basicMajorNumber, NUMBER_OF_MINOR_DEVICE);
remove_proc_entry(PROCFS_NAME, NULL);
}
module_init(chrDriverInit);
module_exit(chrDriverExit);
dmesg日志如下。
# dmesg
[14102.921743] Releasing Simple Devs -- chrDriverExit
[14163.285107] Welcome!! Device Init now..Kernel assigned major number is 244 ..
[14174.979098] av_cmd_hist_start.. Initial..
[14174.979103] av_cmd_hist_start.. the *pos=0..
[14174.979104] the av_cmd_hist_show called
[14174.979107] av_cmd_hist_next called..
[14174.979108] the av_cmd_hist_show called
[14174.979109] av_cmd_hist_next called..
[14174.979110] the av_cmd_hist_show called
[14174.979112] av_cmd_hist_next called..
[14174.979113] the av_cmd_hist_show called
[14174.979114] av_cmd_hist_next called..
[14174.979115] the av_cmd_hist_show called
[14174.979117] av_cmd_hist_next called..
[14174.979118] the av_cmd_hist_show called
[14174.979119] av_cmd_hist_next called..
[14174.979120] the av_cmd_hist_show called
[14174.979121] av_cmd_hist_next called..
[14174.979122] the av_cmd_hist_show called
[14174.979124] av_cmd_hist_next called..
[14174.979125] the av_cmd_hist_show called
[14174.979126] av_cmd_hist_next called..
[14174.979127] the av_cmd_hist_show called
[14174.979128] av_cmd_hist_next called..
[14174.979130] av_cmd_hist_stop called..
[14174.979231] av_cmd_hist_start.. the *pos=0..
[14174.979233] av_cmd_hist_stop called..
[14174.979250] ------------[ cut here ]------------
[14174.979252] kernel BUG at mm/slub.c:3483!
[14174.979254] invalid opcode: 0000 [#2] SMP
[14174.979258] Modules linked in: procfs_driver1(O) procfs_driver(O-) tcp_lp nfsv3 nfsv4 nfs fscache dns_resolver fuse vboxpci(O) vboxnetadp(O) vboxnetflt(O) 8021q garp stp llc binfmt_misc vboxdrv(O) tpm_bios snd_hda_codec_hdmi snd_hda_codec_realtek fglrx(PO) snd_hda_intel snd_hda_codec snd_hwdep snd_seq snd_seq_device snd_pcm iTCO_wdt iTCO_vendor_support r8169 snd_timer mii e1000e snd i2c_i801 lpc_ich i2c_core soundcore snd_page_alloc coretemp kvm_intel kvm serio_raw video dcdbas microcode uinput nfsd lockd nfs_acl auth_rpcgss sunrpc crc32c_intel [last unloaded: procfs_driver1]
[14174.979297] Pid: 19055, comm: cat Tainted: P B D C O 3.6.11-4.fc16.i686 #1 Dell Inc. OptiPlex 9010/00F82W
[14174.979300] EIP: 0060:[<c0530891>] EFLAGS: 00210246 CPU: 5
proc输出如下 -
# cat /proc/basicProcfs1
Sequential print for debugging-- called for i-times i.e. 10 times
Hello SJ proc! 0
Hello SJ proc! 1
Hello SJ proc! 2
Hello SJ proc! 3
Hello SJ proc! 4
Hello SJ proc! 5
Hello SJ proc! 6
Hello SJ proc! 7
Hello SJ proc! 8
Hello SJ proc! 9
Segmentation fault
答案 0 :(得分:2)
抱歉,我得到了修复。
错误的代码
static const struct file_operations basic_proc_fops =
{
.owner = THIS_MODULE,
.open = basicProcOpen,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
正确的代码 -
static const struct file_operations basic_proc_fops =
{
.owner = THIS_MODULE,
.open = basicProcOpen,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
如果有人能解释为什么会有所不同,我将不胜感激。
答案 1 :(得分:0)
由于此返回而崩溃((* pos&lt; NUM_MSG_HIST ENTRIES)?pos:NULL);
答案 2 :(得分:0)
(我没有足够的声誉来评论,所以将其添加为答案)关于为什么seq_release而不是single_release的问题,'release'函数应该赞美'open'函数。你在这里打开函数'basicProcOpen'调用'seq_open'所以你应该调用seq_release。
如果你看一下single_release,除了seq_release之外,还有一个kfree(op)导致你的崩溃。
623 int single_release(struct inode *inode, struct file *file)
624 {
625 const struct seq_operations *op = ((struct seq_file *)file->private_data)->op;
626 int res = seq_release(inode, file);
627 kfree(op);
628 return res;
629 }
630 EXPORT_SYMBOL(single_release);