⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bp.c

📁 块级的连续数据保护系统
💻 C
📖 第 1 页 / 共 2 页
字号:

/*  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)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -