天天看點

linux2.6硬碟扇區直接讀寫程式

下面的程式可以在linux2.6核心直接讀寫硬碟的指定扇區,也是根據網上一個朋友的做法做了修改的;

有兩個不是很明白的地方就是:1、bd_claim函數的使用,這個是個遞歸函數,像是比對記憶體指針和裝置,但是調用會傳回錯誤;2、bdev = open_by_devnum(0x00800000, fmode_read | fmode_write); 中0x00800000數字的确認,不知從何而來:

#include <linux/module.h>

#include <linux/init.h>

#include <linux/sched.h>

#include <linux/kernel.h>

#include <linux/fs.h>

#include <linux/types.h>

#include <linux/buffer_head.h>

#include <linux/blkdev.h>

#include <linux/msdos_fs.h>

#include <linux/fcntl.h>

#include <linux/delay.h>

static int set_size = 512;

static int nr = 0;

static char pages_addr[page_size];

static char pages_write_addr[page_size];

module_param(set_size,int,s_irugo);

module_parm_desc(set_size,"how many bytes you want to read,not more than 4096");

module_param(nr,long,s_irugo);

module_parm_desc(nr,"which sectors you want to read");

module_license("gpl");

static struct block_device *bdev;

static char *usage = "you can change the value:set_size nr devn";

int bdev_write_one_page(struct block_device *bdev, unsigned long blocknr, void *page_addr)

{

 int ret = -1;

 struct buffer_head *bh;

 if (!bdev || !page_addr)

 {

  printk("%s error ", __func__);

  return -1;

 }

 bh = __getblk(bdev, blocknr, page_size);

 if (!bh)

  printk("get blk failed ");

 memcpy(bh->b_data, page_addr, page_size);

 mark_buffer_dirty(bh);

 ll_rw_block(write, 1, &bh);

 brelse(bh);

 ret = 0;

 return ret;

}

int bdev_read_one_page(struct block_device *bdev, unsigned long blocknr, void *page_addr)

 if (!buffer_uptodate(bh))

  ll_rw_block(read, 1, &bh);

  wait_on_buffer(bh);

  if (!buffer_uptodate(bh))

  {

   ret = -1;

   goto out;

  }

 memcpy(page_addr, bh->b_data, page_size);

out:

void block_test(void)

 struct block_device *bdev;

// void *pages_addr = (void *)kmalloc(2048,gfp_kernel);

 void *holder = (void *)pages_addr;

 int cnt, ret;

 int blocknr;

 //bdev = bdget(mkdev(16, 0));

 int i = 0;

 printk("block_test:in ---------2010-03-22\n");

 //memset(pages_addr,0x00,sizeof(pages_addr));

 printk("pages_addr:%x\n",pages_addr);

 printk("holder:%x\n",holder);

#if 1 

 bdev = open_by_devnum(0x00800000, fmode_read | fmode_write);

    //    bdev=0x800;

 if (is_err(bdev))

  printk("bdget error, bdev=%08lx \n", (unsigned long)bdev);

  return;

 printk("bdev:%x\n",bdev);

 bdev->bd_holder = holder;

#if 0

 if (bd_claim(bdev, holder))

  printk("claim failed \n");

  goto out_bdev;

 } 

 printk("after bd_claim\n");

#endif 

// blocknr = *(unsigned long *)(pages_addr + 0x100000);

 //for (cnt = 0; cnt < 10 * 1024; cnt++, blocknr++)

  printk("nr=%d\n",nr);

  memset(pages_addr,0xff,page_size);

  ret = bdev_read_one_page(bdev,nr, (void *)pages_addr);

  if (ret)

   printk("blk read failed ");

 printk("after bdev_read_one_page\n");

// printk("get data:%0x,%0x\n,",pages_addr[510],pages_addr[511]);

 for( i = 0; i < 512; i++ )   

 {       

  printk( "%02x ",(unsigned char)pages_addr[ i ] );       

  if(( i % 16  ) == 15)       

  {           

   printk( "  \n" );       

  }   

 }   

 printk( "  \n" );

 printk("nr=%d\n",nr);

 memset(pages_write_addr,0xe7,page_size);

 ret = bdev_write_one_page(bdev,nr, (void *)pages_write_addr);

 if (ret)

  printk("blk write failed ");

#endif

out_bdev:

// bd_release(bdev);

// blkdev_put(bdev,fmode_read | fmode_write);

 blkdev_put(bdev);

 return;

static int __init disk_rw_init(void)

// nr = 0;

// set_size = page_size;

 block_test();

 return 0;

static void __exit disk_rw_exit(void)

 printk("disk_rw_exit\n");

module_init(disk_rw_init);

module_exit(disk_rw_exit);

makefile:

ifneq ($(kernelrelease),)

 obj-m:=hw_disk_rw26.o

else

 kdir =/usr/src/linux-2.6.33

#       kdir = /usr/src/kernels/2.6.9-5.el-i686

 pwd:=$(shell pwd)

default:

 $(make) -c $(kdir) m=$(pwd) modules

install:

 insmod hw_disk_rw26.ko

uninstall:

 rmmod hw_disk_rw26.ko

clean:

 $(make) -c $(kdir) m=$(pwd) clean

endif

繼續閱讀