I wrote a small kernel module to bring a file's contents into memory. Once there, I verify the contents and attempt to make a small change (i.e. like replace a's with b's). After I change the contents, I mark the buffer dirty and attempt to write the buffer back to disk. Unfortunately it currently does not write it back to disk right now. My teacher stated he wanted to look at my code. I sent it to him but he attempted to compile it on a 2.6 kernel, but it was written for 2.4. I eventually was able to port it to 2.6, but it wasn't easy. The 2.4 kernel provided a very easy way of getting the logical block number of a file. It was removed in the 2.6 kernel. I had to pull out code from the ext2 inode.c file to convert a regular inode to an ext2 inode. I was sure that it wasn't going to work, but luckly it did. Finally I replaced the 2.4 bread() function with 2.6 __bread() function. Great, now I can read the file's contents in memory again.
I am now focusing on writing the data back to disk after making the adjustments.
My code looks like this:
/**************************************************************************
* Name: poke26.c
* Info: Open a file and manipulate the file's data within
* the memory area it is stored in. Works for kernel 2.6
*
* Compile: Use Makefile
*
* Makefile
* ------------------------------------------------------------------------
* obj-m += poke26.o
* poke:
* make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
* ------------------------------------------------------------------------
*
*
* Install: insmod poke26.o src=SomeFile
* Remove: rmmod poke26
*
*/
#define DRIVER_DESC "Read and write to a file via memory"
#include < linux/module.h >
#include < linux/moduleparam.h >
#include < linux/kernel.h >
#include < linux/init.h >
#include < linux/fs.h >
#include < linux/buffer_head.h >
#include < linux/ext2_fs.h >
#include < linux/ext2_fs_sb.h >
#include < linux/byteorder/generic.h >
#include < linux/genhd.h >
#include < linux/stat.h > //?
static char *src = NULL;
module_param(src, charp, 0);
MODULE_PARM_DESC(src, "An input file");
struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb,
unsigned int block_group,
struct buffer_head ** bh)
{
unsigned long group_desc;
unsigned long offset;
struct ext2_group_desc * desc;
struct ext2_sb_info *sbi = EXT2_SB(sb);
if (block_group >= sbi->s_groups_count) return NULL;
group_desc = block_group >> EXT2_DESC_PER_BLOCK_BITS(sb);
offset = block_group & (EXT2_DESC_PER_BLOCK(sb) - 1);
if (!sbi->s_group_desc[group_desc]) return NULL;
desc = (struct ext2_group_desc *) sbi->s_group_desc[group_desc]->b_data;
if (bh) *bh = sbi->s_group_desc[group_desc];
return desc + offset;
}
static struct ext2_inode *ext2_get_inode(struct super_block *sb, ino_t ino,
struct buffer_head **p)
{
struct buffer_head * bh;
unsigned long block_group;
unsigned long block;
unsigned long offset;
struct ext2_group_desc * gdp;
*p = NULL;
if ((ino != EXT2_ROOT_INO && ino < EXT2_FIRST_INO(sb)) ||
ino > le32_to_cpu(EXT2_SB(sb)->s_es->s_inodes_count))
return NULL;
block_group = (ino - 1) / EXT2_INODES_PER_GROUP(sb);
gdp = ext2_get_group_desc(sb, block_group, &bh);
if (!gdp)
return NULL;
// Figure out the offset within the block group inode table
offset = ((ino - 1) % EXT2_INODES_PER_GROUP(sb)) * EXT2_INODE_SIZE(sb);
block = le32_to_cpu(gdp->bg_inode_table) +
(offset >> EXT2_BLOCK_SIZE_BITS(sb));
if (!(bh = sb_bread(sb, block)))
return NULL;
*p = bh;
offset &= (EXT2_BLOCK_SIZE(sb) - 1);
return (struct ext2_inode *) (bh->b_data + offset);
}
void poke(void)
{
struct file *f;
struct inode *inode;
struct buffer_head * bh;
struct buffer_head * bj;
int i, count;
unsigned long lbn = 0;
unsigned long blocksize;
struct ext2_inode *ext2i;
// Open the file passed in
f = filp_open(src, O_WRONLY, 0);
inode = f->f_dentry->d_inode;
// 3 days of pain
ext2i = ext2_get_inode(inode->i_sb, inode->i_ino, &bh);
if (ext2i == NULL)
printk("*** Poke Error: ext2 inode is null\n");
// I am only handling small files for now
for ( i = 0 ; i < 12; i++)
if (ext2i->i_block[i])
lbn = ext2i->i_block[i];
if (!lbn)
{
printk("*** Poke Error: No logical block number");
return;
}
blocksize = inode->i_blksize;
//printk("*** Poke lbn:%lu\n", lbn);
//printk("*** Poke bs:%lu\n", blocksize);
//printk("*** Poke ino:%lu\n", inode->i_ino);
// Use the buffer_head's not inode's block_device
if (bh->b_bdev == NULL)
{
printk("*** Poke DISCOVERY block_device struct NULL\n");
return;
}
// Bring the block into memory
bj = __bread(bh->b_bdev, lbn, blocksize);
if (!bj)
{
printk("*** Poke Error: Buffer Head Null");
return;
}
count = 0;
// Replace a's for b's and count them
for (i = 0; i < bj->b_size; i++)
{
if (*(bj->b_data + i) == 'a')
{
// *(bj->b_data + i) = 'b'; // make a change
count++;
}
//printk("b_data pointer: 0x%x\n", *(bj->b_data + i));
}
/*
// Set Dirty Bits
// Set inode struct to dirty
mark_inode_dirty(inode);
// Set buffer_head struct dirty
mark_buffer_dirty(bh);
// Set page struct dirty
SetPageDirty(bh->b_page);
// Flush the pages back to disk
sync_dev(device);
fsync_inode_buffers(inode);
fsync_inode_data_buffers(inode);
write_inode_now(inode, 1);
//block_sync_page(bh->b_page);
//f->f_op->fsync(f, f->f_dentry, 1);
*/
printk("*** Poke count: %i\n", count);
filp_close(f, NULL);
}
// Enter module function
static int __init init_poke(void)
{
if ( src == NULL )
{
printk("*** Poke Usage: insmod poke.o src=file");
return 0;
}
printk("*** Poke started\n");
poke();
return 0;
}
// Exit module function
static void __exit cleanup_poke(void)
{
printk("*** Poke Ended\n");
}
module_init(init_poke);
module_exit(cleanup_poke);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
Just FYI: if you want your code to look nice use the "code" and "pre" html tags.
Sorry is not work!!!!
Hello!
You have solved this problem? You Can show as?
Thanks a lot!