大佬教程收集整理的这篇文章主要介绍了内核块设备 – 使用自旋锁落入死锁,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
我的设备只是一个内存区域,分为两个512字节扇区.
我正在使用全局结构来存储设备信息:
typedef struct { uint32_t hard_sector_size; // Size of a device sector uint32_t sector_number; // number of sector on device uint32_t size; // @R_856_10586@l size of virtual device in bytes uint8_t* data; // Device memory buffer spinlock_t device_lock; // Device structure access spinlock struct request_queue *queue; // Device request queue struct gendisk *gendisk; // Device "disk" representation int major; // Device major number attributed by kernel int minor; // Device minor number fixed at initialization uint32_t r_users; // number of read access uint32_t w_users; // number of write access }blk_mod_t; blk_mod_t self; [...]
现在我想保护这个结构免受并发访问.为此,我正在使用device_lock字段.
如果锁定,结构正在更新,所以我应该等到完成.
如果没有,我可以访问结构字段.
现在我只将这个螺旋锁用于以下三个功能
static int block_mod_open(struct block_device *bdev,fmode_t modE) { access_mode_t access_mode; DEBUG("Entering open function\n"); if((mode & FMODE_READ) && (mode & FMODE_WRITE)) { NOTICE("Oppened in read/write mode\n"); mode = ACCESS_RW; } else if(mode & FMODE_READ) { NOTICE("Oppened in read only mode\n"); mode = ACCESS_RONLY; } else if(mode & FMODE_WRITE) { NOTICE("Oppened in write only mode\n"); mode = ACCESS_WONLY; } DEBUG("<--\n"); spin_lock(&self.device_lock); if(ACCESS_RW == access_modE) { self.r_users++; self.w_users++; } else if(ACCESS_RONLY == access_modE) { self.r_users++; } else { self.w_users++; } NOTICE("Read access: %d\tWrite access: %d\n",self.r_users,self.w_users); DEBUG("-->\n"); spin_unlock(&self.device_lock); DEBUG("ExiTing open function\n"); return 0; } static void block_mod_release(struct gendisk *disk,fmode_t modE) { access_mode_t access_mode; DEBUG("Entering release function\n"); if((mode & FMODE_READ) && (mode & FMODE_WRITE)) { NOTICE("Closed read/write mode\n"); mode = ACCESS_RW; } else if(mode & FMODE_READ) { NOTICE("Closed read only mode\n"); mode = ACCESS_RONLY; } else if(mode & FMODE_WRITE) { NOTICE("Closed write only mode\n"); mode = ACCESS_WONLY; } DEBUG("<--\n"); spin_lock(&self.device_lock); if(ACCESS_RW == access_modE) { self.r_users--; self.w_users--; } else if(ACCESS_RONLY == access_modE) { self.r_users--; } else { self.w_users--; } NOTICE("Read access: %d\tWrite access: %d\n",self.w_users); DEBUG("-->\n"); spin_unlock(&self.device_lock); DEBUG("ExiTing release function\n"); return; } static void block_mod_transfer(unsigned long sector,unsigned long nsect,char *buffer,int writE) { unsigned long offset = sector*KERNEL_SECTOR_SIZE; unsigned long nbytes = nsect*KERNEL_SECTOR_SIZE; DEBUG("Entering transfer function\n"); DEBUG("<--\n"); spin_lock(&self.device_lock); if((offset + nbytes) > self.sizE) { WARNING("Beyond-end write (%ld %ld)\n",offset,nbytes); spin_unlock(&self.device_lock); return; } if(writE) { NOTICE("WriTing to device\n"); memcpy(self.data + offset,buffer,nbytes); } else { NOTICE("Reading from device\n"); memcpy(buffer,self.data + offset,nbytes); } DEBUG("-->\n"); spin_unlock(&self.device_lock); DEBUG("ExiTing transfer function\n"); }
我用以下函数处理请求
static void block_mod_request(struct request_queue *queuE) { DEBUG("Entering request function\n"); struct request *request; while(NULL != (request = blk_fetch_request(queuE))) { blk_mod_t *self = request->rq_disk->private_data; // check if request is a filesystem request (i.e. moves block of data) if(REQ_TYPE_FS != request->cmd_typE) { // Close request with unsuccessful status WARNING("Skip non-fs request\n"); __blk_end_request_cur(request,-EIO); conTinue; } // Treat request block_mod_transfer(blk_rq_pos(request),blk_rq_cur_sectors(request),bio_data(request->bio),rq_data_dir(request)); // Close request with successful status __blk_end_request_cur(request,0); } DEBUG("ExiTing request function\n"); return; }
加载模块时没有什么特别的事情发生.但是,如果我尝试从中读取,我陷入僵局,因为我的系统不再响应,我必须重新启动.
这是输出:
root@PC325:~# echo 8 > /proc/sys/kernel/printk root@PC325:~# insmod block_mod.ko [ 64.546791] block_mod: loading out-of-tree module taints kernel. [ 64.548197] block_mod: module license '(C) Test license' taints kernel. [ 64.549951] Disabling lock debugging due to kernel taint [ 64.552816] InserTing module 'blk_mod_test' [ 64.554085] Got major number : '254' [ 64.554940] Data allocated (size = 1024) [ 64.557378] request queue initialized [ 64.558178] Sent hard sector size to request queue [ 64.559188] gendisk allocated [ 64.559817] gendisk filled [ 64.560416] gendisk capacity set [ 64.563285] gendisk added root@PC325:~# [ 64.565280] Entering open function [ 64.566035] Oppened in read only mode [ 64.566773] <-- [ 64.567138] Read access: 1 Write access: 0 [ 64.567977] --> [ 64.568342] ExiTing open function [ 64.571080] Entering release function [ 64.571855] Closed read only mode [ 64.572531] <-- [ 64.572924] Read access: 0 Write access: 0 [ 64.573749] --> [ 64.574116] ExiTing release function root@PC325:~# cat /dev/blkmodtest [ 78.488228] Entering open function [ 78.488988] Oppened in read only mode [ 78.489733] <-- [ 78.490100] Read access: 1 Write access: 0 [ 78.490925] --> [ 78.491290] ExiTing open function [ 78.492026] Entering request function [ 78.492743] Entering transfer function [ 78.493469] <-- -------------- DEADLOCK HERE --------------
static int __init block_mod_init(void) { char* message = "abcdefghijklmnopqrstuvwxyz"; int i; INFO("InserTing module '%s'\n",MODULE_Name); // Initialize driver data structure memset(&self,sizeof(blk_mod_t)); self.hard_sector_size = DEVICE_HARD_SECTOR_SIZE; self.sector_number = DEVICE_SECTOR_numbER; self.size = self.sector_number*self.hard_sector_size; self.minor = 1; // Get a major number from kernel if(0 > (self.major = register_blkdev(self.major,MODULE_Name))) { ERROR("Unable to get major number for '%s'\n",MODULE_Name); unregister_blkdev(self.major,MODULE_Name); return -1; } DEBUG("Got major number : '%d'\n",self.major); // Allocate data space if(NULL == (self.data = vmalloc(self.sizE))) { ERROR("Unable to allocate memory for '%s'\n",MODULE_Name); return -2; } for(i=0;i<self.size;i++) { self.data[i] = message[i%strlen(messagE)]; } spin_lock_init(&self.device_lock); DEBUG("Data allocated (size = %d)\n",self.sizE); // Allocate the request queue if(NULL == (self.queue = blk_init_queue(block_mod_request,&self.device_lock))) { ERROR("Unable to initialize request queue for '%s'\n",MODULE_Name); vfree(self.data); unregister_blkdev(self.major,MODULE_Name); return -3; } DEBUG("request queue initialized\n"); // Send device hard sector size to request queue blk_queue_logical_BLOCK_SIZE(self.queue,self.hard_sector_sizE); self.queue->queuedata = &self; DEBUG("Sent hard sector size to request queue\n"); // Allocate the gendisk structure if(NULL == (self.gendisk = alloc_disk(self.minor))) { ERROR("Unable to initialize gendisk for '%s'\n",MODULE_Name); blk_cleanup_queue(self.queuE); vfree(self.data); unregister_blkdev(self.major,MODULE_Name); return -4; } DEBUG("gendisk allocated\n"); // Fill gendisk structure self.gendisk->major = self.major; self.gendisk->first_minor = self.minor; self.gendisk->fops = &self_ops; self.gendisk->queue = self.queue; self.gendisk->private_data = &self; snprintf(self.gendisk->disk_name,32,"blkmodtest"); DEBUG("gendisk filled\n"); set_capacity(self.gendisk,self.sector_number*(self.hard_sector_size/KERNEL_SECTOR_SIZE)); DEBUG("gendisk capacity set\n"); add_disk(self.gendisk); DEBUG("gendisk added\n"); return 0; } static void __exit block_mod_cleanup(void) { del_gendisk(self.gendisk); put_disk(self.gendisk); blk_cleanup_queue(self.queuE); vfree(self.data); unregister_blkdev(self.major,MODULE_Name); INFO("Removing module '%s'\n",MODULE_Name); return; }
更新:添加宏和枚举定义
#define MODULE_NAME "blk_mod_test" #define KERNEL_SECTOR_SIZE 512 #define DEVICE_HARD_SECTOR_SIZE 512 #define DEVICE_SECTOR_numbER 2 typedef enum { ACCESS_RONLY = 0,ACCESS_WONLY = 1,ACCESS_RW = 2,}access_mode_t;
我不明白的是,在我尝试将它锁定到block_mod_transfer之前,已经释放了自旋锁(在block_mod_open结束时).
因此,我不明白为什么当自旋锁似乎可用时,内核陷入死锁.
为什么我在这种情况下陷入僵局?我究竟做错了什么?
// Allocate the request queue if(NULL == (self.queue = blk_init_queue(block_mod_request,&self.device_lock))) { ERROR("Unable to initialize request queue for '%s'\n",MODULE_Name); vfree(self.data); unregister_blkdev(self.major,MODULE_Name); return -3; }
以上是大佬教程为你收集整理的内核块设备 – 使用自旋锁落入死锁全部内容,希望文章能够帮你解决内核块设备 – 使用自旋锁落入死锁所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。