?? bp.c
字號:
/* BLOCKED BASED CONTINUOUS DATA PROTECTION MODULE FOR THE LINUX KERNEL * * This module provides the functionality of Continuous Data Protection * at block level. Continuous Data Protection is a backup and recovery * technology that continuously captures all the IO requests and * timestamps them. It stores the changes made to data alongwith the * timestamps to enable recovery from any point in the past. Thus this * module provides Any Point In Time (APIT) Image of data. *
* * Copyright (C) <2006> < Sagar S Dixit > * < Shashank D Kharche > * < Sujay A Mahajan > * < Anup A Badhe > * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA * * Authors:- * Sagar S Dixit sagar.dixit@gmail.com * Shashank D Kharche shashank_pict@yahoo.com * Sujay A Mahajan sujaymahajan@gmail.com * Anup A Badhe anup_223@yahoo.com */
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/buffer_head.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/vmalloc.h>
#include <linux/genhd.h>
#include <linux/config.h>
#include <linux/syscalls.h>
#include <linux/mm.h>
#include <linux/percpu.h>
#include <linux/blkdev.h>
#include <linux/quotaops.h>
#include <linux/highmem.h>
#include <linux/writeback.h>
#include <linux/hash.h>
#include <linux/suspend.h>
#include <linux/bio.h>
#include <linux/cpu.h>
#include <linux/bitops.h>
#include <linux/mpage.h>
#include <linux/mempool.h>
#include <linux/mc146818rtc.h>
#include <linux/bcd.h>
#include <linux/delay.h>
#include <linux/list.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include "cdp_blk.h"/* cdp_device.h holds the major and minor numbers of Host Disk and * CDP Repository. The major and minor numbers, which this * file contains have to be set appropriately before running * the module */
#include "cdp_device.h"
/* START_METADATA holds the starting location of metadata on CDP * Repository */
#define START_METADATA 0/* This sets the size of sector to 512 bytes */
#define KERNEL_SECTOR_SIZE 512
MODULE_LICENSE("Dual BSD/GPL");
static int major_num = 0 ;
static int hardsect_size = 512;int hrs,min,sec;/* maddr holds the address(sector) of CDP Repository on which the next * IO will be performed */
unsigned int maddr = START_METADATA;/* taddr holds the address(sector) of CDP Repository on which the next * timestamp(metadata) will be stored */
unsigned int taddr = START_METADATA;
unsigned int tcount = 0 , tcount2=0;
atomic_t free_resources;
int ts_free_flag=0;int t_count;
dev_t dev[3];
static struct request_queue *Queue;
mempool_t *cdp_bio_pool= NULL;
mempool_t *pool_page = NULL;
struct page *gpage=NULL;
/* Set the number of sector according to your device size. Its now * 4MB * 512 = 2GB */
static int nsectors = 1UL << 21;
/* The specified time of recovery in Hours, Minutes and Seconds */
int R_hrs,R_min,R_sec;
int mount_on_host_disk( void *arg);
int data_restoration(void *arg);
/* ts1 and ts2 are tasklets which call the functions data_restoration * and mount_on_host_disk functions respectively at appropriate * time instants */
DECLARE_TASKLET(ts1,(void*)data_restoration,0);
DECLARE_TASKLET(ts2,(void*)mount_on_host_disk,0);
/* Internal Representation of our device */
static struct blk_device
{
unsigned long size;
spinlock_t lock;
short users;
struct gendisk *gd;
} Device;
/* This is the 'private' cdp bio.
* It contains information about what kind of IO operations were started
* for this Trapping operation, and about their status
*/
struct cdp_bio
{
/* to obtain original bio
*/
struct bio *master_bio ;
/* if the IO is WRITE , then multiple bios are used.
*/
struct bio *bios[3];
/* 'have we finished' count,used from IRQ handlers
*/
atomic_t remaining;
/* used in completion of I/O commitment
*/
unsigned long state;
};
/* metadata structure represents the metadata corresponding to * the data blocks on CDP Repository. It contains the timestamp * information in form of hrs:mins:sec at which the data block * arrived in the system. It also contains the size(in bytes) of * the IO request and the address of the data block on CDP * Repository and on Host Disk.
*/
struct metadata
{
int hrs,min,sec;
unsigned int bisize;
sector_t cdp_sector;
sector_t host_sector;
};
/* mapping_table structure represents an element of the mapping * table which is constructed at the time of recovery. * It contains the metadata information.
*/
struct mapping_table
{
struct metadata *metadata2;
struct list_head list;
};
struct list_head mt_home ;
struct list_head mr_bio_home;
/* most_recent_blocks holds the list of the most recent blocks * from the specified recovery point till the start of CDP. * This list is traversed and the bios in this list are extracted * and the blocks are mounted on Host Disk. */
struct most_recent_blocks
{
struct bio *mrbio;
struct list_head list;
};
struct page *cdp_page_alloc(int gfp_mask,void *pool_data)
{
return alloc_page(gfp_mask);
}
void cdp_page_free(void *element,void *pool_data)
{
free_page((unsigned long)(struct page*)pool_data);
}
static void * cdp_bio_pool_alloc(int gfp_mask,void *pool_data)
{
struct cdp_bio *cdp_bio1;
cdp_bio1 = kmalloc(sizeof(struct cdp_bio),gfp_mask);
if(cdp_bio1)
memset(cdp_bio1,0,sizeof(struct cdp_bio));
else
printk(KERN_ALERT " CDP_bio pool alloc err\n");
return (cdp_bio1);
}
static void cdp_bio_pool_free(void *cdp_bio1,void *pool_data)
{
kfree(cdp_bio1);
}
/* data_restoration_write_end_io is the end_io of * generic_make_request function called in the function * mount_on_host_disk. This function is responsible for * freeing of the resources allocated. */
static int data_restoration_write_end_io(struct bio *bio,unsigned int b,int er)
{
struct list_head *pos1,*n1;
struct list_head *pos2,*n2;
struct mapping_table *mt_t1=NULL;
struct most_recent_blocks *mt_t2=NULL;
int fr=0;
mempool_free(bio->bi_io_vec[0].bv_page,pool_page);
fr=atomic_read(&free_resources);
if(fr==0)
{
list_for_each_safe(pos1,n1,&mt_home)
{
mt_t1 = list_entry(pos1,struct mapping_table,list);
kfree(mt_t1->metadata2);
list_del(&(mt_t1->list));
kfree(mt_t1);
}
list_for_each_safe(pos2,n2,&mr_bio_home)
{
mt_t2 = list_entry(pos2,struct most_recent_blocks,list);
list_del(&(mt_t2->list));
kfree(mt_t2);
}
}
else
atomic_dec(&free_resources);
return 0;
}
/* mount_on_host_disk() is called to mount the recovered data blocks
* back on the Host Disk
*/
int mount_on_host_disk( void *arg)
{
struct most_recent_blocks *mt_temp=NULL;
struct list_head *pos;
list_for_each(pos,&mr_bio_home)
{
mt_temp = list_entry(pos,struct most_recent_blocks,list);
bio_get(mt_temp->mrbio);
generic_make_request(mt_temp->mrbio);
bio_put(mt_temp->mrbio);
}
return 0;
}
/* data_restoration_read_end_io is the end_io of * generic_make_request function called in the function * data_restoration. This function is responsible for * invoking the function mount_on_host_disk. */
static int data_restoration_read_end_io(struct bio *bio,unsigned int bd,int err)
{
struct most_recent_blocks *mt_tp =NULL;
unsigned int va1;
char str[10];
struct metadata *metadata2 = bio->bi_private;
printk(KERN_ALERT"Fields of Metadata structure :\n");
printk(KERN_ALERT"Time = %d:%d:%d\n",metadata2->hrs,metadata2->min,metadata2->sec);
printk(KERN_ALERT"Host Sector= %lu\n",(unsigned long)metadata2->host_sector);
mt_tp = kmalloc(sizeof(struct most_recent_blocks),GFP_ATOMIC);
if(!mt_tp)
{
printk(KERN_ALERT"\nMemory Allocation Problem\nMost recent block not formed");
return -ENOMEM;
}
mt_tp->mrbio = bio_clone(bio,GFP_NOIO);
mt_tp->mrbio->bi_bdev = (struct block_device *)dev[0];
mt_tp->mrbio->bi_rw = WRITE ;
mt_tp->mrbio->bi_sector = metadata2->host_sector;
mt_tp->mrbio->bi_size = metadata2->bisize;
mt_tp->mrbio->bi_end_io = data_restoration_write_end_io;
mt_tp->mrbio->bi_private = NULL;
va1 =((((mt_tp->mrbio->bi_io_vec[0].bv_page) - mem_map) << PAGE_SHIFT) + PAGE_OFFSET);
memcpy((unsigned int *)str,(unsigned int *)va1,8);
str[9]='\0';
printk(KERN_ALERT "Data in Recovered File =%s\n",str);
INIT_LIST_HEAD(&(mt_tp->list));
list_add(&(mt_tp->list),&mr_bio_home);
tcount2++;
t_count--;
if(t_count==0)
{
tasklet_enable(&ts2);
}
return 0;
}
/* data_restoration() is called to read the data blocks to be * recovered from CDP Repository.
*/
int data_restoration(void *arg)
{
struct mapping_table *mt_temp;
struct list_head *pos;
struct page *pg;
struct bio *r_drbio;
int v=0;
tasklet_disable(&ts2);
tasklet_schedule(&ts2);
list_for_each(pos,&mt_home)
{
atomic_set(&free_resources,v);
v++;
t_count = v;
mt_temp = list_entry(pos,struct mapping_table,list);
r_drbio=bio_alloc(GFP_NOIO,1);
r_drbio->bi_bdev = (struct block_device *)dev[1];
pg = mempool_alloc(pool_page,GFP_ATOMIC);
if(!pg)
{
printk(KERN_ALERT "Couldnt fill HighMem\n");
return -ENOMEM;
}
r_drbio->bi_io_vec[0].bv_page = pg;
r_drbio->bi_io_vec[0].bv_len = 4096;
r_drbio->bi_io_vec[0].bv_offset = 0 ;
r_drbio->bi_rw = READ ;
r_drbio->bi_vcnt = 1 ;
r_drbio->bi_idx = 0 ;
r_drbio->bi_sector = mt_temp->metadata2->cdp_sector;
r_drbio->bi_size = mt_temp->metadata2->bisize;
r_drbio->bi_end_io = data_restoration_read_end_io;
r_drbio->bi_private = mt_temp->metadata2;
bio_get(r_drbio);
generic_make_request(r_drbio); bio_put(r_drbio);
}
return 0;
}
/* display_mapping_table is used to display the mapping table * formed during recovery. It displays the timestamp information * in hrs:min:sec , the block address on CDP Repository and * the block address on Host Disk */
int display_mapping_table(void)
{
struct mapping_table *mt_temp=NULL;
struct list_head *pos;
printk(KERN_ALERT "\n------------ MAPPING TABLE --------------\n");
printk(KERN_ALERT "Hrs:Min:Sec CDP_Sector Host_Sector\n");
list_for_each(pos,&mt_home)
{
mt_temp = list_entry(pos,struct mapping_table,list);
printk(KERN_ALERT "%d:%d:%d ",mt_temp->metadata2->hrs,mt_temp->metadata2->min,mt_temp->metadata2->sec);
printk(KERN_ALERT " %lu ",(unsigned long)mt_temp->metadata2->cdp_sector);
printk(KERN_ALERT " %lu \n",(unsigned long)mt_temp->metadata2->host_sector);
}
printk(KERN_ALERT "----------------------------------------\n");
return 0;
}
/* construct_mapping_table() is called to construct the mapping table
* by retrieving the metadata structure from CDP Repository * This mapping table contains timestamp information alongwith * mapping of blocks on CDP Repository and Host disk.
*/
int construct_mapping_table(struct metadata *metadata1)
{
struct mapping_table *mt_temp =NULL;
struct mapping_table *mt_tp =NULL;
struct list_head *pos;
int lf=0;
mt_temp = kmalloc(sizeof(struct mapping_table),GFP_ATOMIC);
if(mt_temp)
memset(mt_temp,0,sizeof(struct mapping_table));
else
{
printk(KERN_ALERT " mt_temp: Memory Allocation Problem\n");
return -ENOMEM;
}
mt_temp->metadata2 = kmalloc(sizeof(struct metadata),GFP_ATOMIC);
if(mt_temp->metadata2)
memset(mt_temp->metadata2,0,sizeof(struct metadata));
else
{
printk(KERN_ALERT " mt_temp->metadata2: Memory Allocation Problem\n");
return -ENOMEM;
}
memcpy((unsigned int*)mt_temp->metadata2,(unsigned int*)metadata1,sizeof(struct metadata));
list_for_each(pos,&mt_home)
{
mt_tp = list_entry(pos,struct mapping_table,list);
if(mt_tp->metadata2->host_sector == mt_temp->metadata2->host_sector)
{
list_replace_rcu(&(mt_tp->list),&(mt_temp->list));
kfree(mt_tp->metadata2);
kfree(mt_tp);
lf=1;
break;
}
}
if(lf==0)
{
INIT_LIST_HEAD(&(mt_temp->list));
list_add(&(mt_temp->list),&mt_home);
}
return 0;
}
/* chk_time() is called to compare the specified recovery time * and the timestamps of the data blocks stored on CDP Repository
*/
int chk_time(struct metadata *metadata1)
{
if(metadata1->hrs<=R_hrs)
{
if(metadata1->hrs==R_hrs)
{
if(metadata1->min<=R_min)
{
if(metadata1->min==R_min)
{
if(metadata1->sec<= R_sec)
return 1;
else
return 0;
}
return 1;
}
return 0;
}
return 1;
}
return 0;
}
/* recovery_end_io is the end_io of generic_make_request called * in the recovery function. This function is responsible for * calling chk_time function and construct_mapping_table * function. It is also used to invoke the data_restoration * function to start with actual recovery of data blocks * on CDP Repository */
static int recovery_end_io(struct bio *bio,unsigned int bd,int err)
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -