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

📄 failsafe.c

📁 嵌入式linux下基于SRAM的内存文件系统
💻 C
字号:
#include <linux/fs.h>#include <linux/pram_fs.h>static inline struct pram_failsafe_block *pram_get_failsafe_block(struct pram_sb_info * sbi){	return sbi->virt_addr + sbi->super->s_size -		(PRAM_FAILSAFE_BLOCKS << sbi->sb->s_blocksize_bits);}static inline void pram_lock_failsafe_block(struct super_block * sb,					    struct pram_failsafe_block *fsb){	pram_lock_range(sb, fsb, sb->s_blocksize);}static inline void pram_unlock_failsafe_block(struct super_block * sb,					      struct pram_failsafe_block *fsb){	pram_unlock_range(sb, fsb, sb->s_blocksize);}static inline void pram_failsafe_mutex_lock(struct pram_sb_info *sbi){	mutex_lock(&sbi->failsafe_mutex);}static inline void pram_failsafe_mutex_unlock(struct pram_sb_info *sbi){	mutex_unlock(&sbi->failsafe_mutex);}static inline int pram_failsafe_mutex_is_locked(struct pram_sb_info *sbi){	return mutex_is_locked(&sbi->failsafe_mutex);}int pram_backup_add_block(struct super_block * sb, void * bp){	struct pram_sb_info *sbi = pram_get_sb_info(sb);	struct pram_failsafe_block *fsb = pram_get_failsafe_block(sbi);	unsigned long blocksize = sb->s_blocksize;	unsigned long blocksize_bits = sb->s_blocksize_bits;	unsigned long i, count = 0, free = PRAM_FAILSAFE_BACKUP_BLOCKS;	unsigned long blockid		= (unsigned long)(bp - sbi->virt_addr) >> blocksize_bits;	void * dst;	BUG_ON(!pram_failsafe_mutex_is_locked(sbi));	BUG_ON(blockid == 0 || bp < sbi->virt_addr || bp >= (void *)fsb);	for (i = 0; i < PRAM_FAILSAFE_BACKUP_BLOCKS; i++) {		unsigned long id = fsb->blocks[i];		if (id == blockid) /* if already backup it, ignorn it */			return 0;		if (id)			count++;		else if (free > i)			free = i;	}	if (count == PRAM_FAILSAFE_BACKUP_BLOCKS) {		pram_warn("failed to backup %ld, no space\n", blockid);		dump_stack();		return -1;	}	pram_dbg("backup %ld, total %ld\n", blockid, count);	if (count >= 5)		dump_stack();	/* copy data first */	dst = (void *)fsb + ((free + 1) << blocksize_bits);	pram_lock_range(sb, dst, blocksize);	memcpy(dst, bp, blocksize);	pram_unlock_range(sb, dst, blocksize);	/* set block id */	pram_lock_failsafe_block(sb, fsb);	fsb->blocks[free] = blockid;	fsb->valid = PRAM_FAILSAFE_VALID; /* set valid in the end */	pram_unlock_failsafe_block(sb, fsb);	return 0;}int pram_backup_add_range(struct super_block * sb, void * p, unsigned long len){	struct pram_sb_info *sbi = pram_get_sb_info(sb);	unsigned long blocksize = sb->s_blocksize;	unsigned long blocksize_bits = sb->s_blocksize_bits;	unsigned long block = (unsigned long)p, end, count;	if (sbi->super->s_magic != PRAM_SUPER_MAGIC)		return 0;	BUG_ON(!pram_failsafe_mutex_is_locked(sbi));	/* align to block size */	block = (block + blocksize - 1) & ~(blocksize - 1);	len = (len + blocksize - 1) & ~(blocksize - 1);	count = len >> blocksize_bits;	if (count > PRAM_FAILSAFE_BACKUP_BLOCKS) {		pram_warn("backup overflow %ld > %d\n",			  count, PRAM_FAILSAFE_BACKUP_BLOCKS);		dump_stack();		return 0;	}	end = block + len;	while (block < end) {		pram_backup_add_block(sb, (void *)block);		block += blocksize;	}	return 0;}int pram_backup_del_block(struct super_block * sb, void * bp){	struct pram_sb_info *sbi = pram_get_sb_info(sb);	struct pram_failsafe_block *fsb = pram_get_failsafe_block(sbi);	unsigned long blocksize = sb->s_blocksize;	unsigned long blocksize_bits = sb->s_blocksize_bits;	unsigned long i;	unsigned long blockid		= (unsigned long)(bp - sbi->virt_addr) >> blocksize_bits;	BUG_ON(!pram_failsafe_mutex_is_locked(sbi));	BUG_ON(blockid == 0 || bp < sbi->virt_addr || bp >= (void *)fsb);	for (i = 0; i < PRAM_FAILSAFE_BACKUP_BLOCKS; i++) {		if (fsb->blocks[i] == blockid) {			/* clear block id first */			pram_lock_failsafe_block(sb, fsb);			fsb->blocks[i] = 0;			pram_unlock_failsafe_block(sb, fsb);			/* clear data */			bp = (void *)fsb + ((i + 1) << blocksize_bits);			pram_lock_range(sb, bp, blocksize);			memset(bp, 0, blocksize);			pram_unlock_range(sb, bp, blocksize);			return 0;		}	}	return 0;}/* lock failsafe before calling! */static int pram_backup_del(struct super_block * sb){	struct pram_sb_info *sbi = pram_get_sb_info(sb);	struct pram_failsafe_block *fsb = pram_get_failsafe_block(sbi), fsb2;	unsigned long blocksize = sb->s_blocksize;	unsigned long blocksize_bits = sb->s_blocksize_bits;	unsigned long i;	if (sbi->super->s_magic != PRAM_SUPER_MAGIC)		return 0;	BUG_ON(!pram_failsafe_mutex_is_locked(sbi));	if (fsb->valid != PRAM_FAILSAFE_VALID)		return 0;	memcpy(&fsb2, fsb, sizeof(*fsb)); /* save blocks */	pram_lock_failsafe_block(sb, fsb);	fsb->valid = 0; /* clear valid first */	memset(fsb, 0, sizeof(*fsb));	pram_unlock_failsafe_block(sb, fsb);	for (i = 0; i < PRAM_FAILSAFE_BACKUP_BLOCKS; i++) {		void *bp;		if (!fsb2.blocks[i])			continue;		bp = (void *)fsb + ((i + 1) << blocksize_bits);		pram_lock_range(sb, bp, blocksize);		memset(bp, 0, blocksize);		pram_unlock_range(sb, bp, blocksize);	}	return 0;}void pram_lock_failsafe(struct super_block * sb, enum pram_failsafe_op op,			u32 arg0, u32 arg1, u32 arg2){	struct pram_sb_info *sbi = pram_get_sb_info(sb);	struct pram_failsafe_block *fsb = pram_get_failsafe_block(sbi);	pram_failsafe_mutex_lock(sbi);	BUG_ON(fsb->valid == PRAM_FAILSAFE_VALID);	switch (op) {	case PRAM_FAILSAFE_OP_SYMLINK:	case PRAM_FAILSAFE_OP_DIRECT_IO:	case PRAM_FAILSAFE_OP_ALLOC_BLOCKS:		pram_lock_failsafe_block(sb, fsb);		fsb->op = op;		fsb->valid = PRAM_FAILSAFE_VALID;		pram_unlock_failsafe_block(sb, fsb);		break;	case PRAM_FAILSAFE_OP_TRUNCATE:		pram_lock_failsafe_block(sb, fsb);		fsb->args[0] = arg0;		fsb->args[1] = arg1;		fsb->op = op;		fsb->valid = PRAM_FAILSAFE_VALID;		pram_unlock_failsafe_block(sb, fsb);		break;	case PRAM_FAILSAFE_OP_DELETE_INODE:		pram_lock_failsafe_block(sb, fsb);		fsb->args[0] = arg0;		fsb->op = op;		fsb->valid = PRAM_FAILSAFE_VALID;		pram_unlock_failsafe_block(sb, fsb);		break;	default:		break;	}}void pram_unlock_failsafe(struct super_block * sb){	pram_backup_del(sb);	pram_failsafe_mutex_unlock(pram_get_sb_info(sb));}/* remap full memory before calling! */int pram_powerfail_restore(struct super_block * sb){	struct pram_sb_info *sbi = pram_get_sb_info(sb);	struct pram_failsafe_block *fsb = pram_get_failsafe_block(sbi);	unsigned long blocksize = sb->s_blocksize;	unsigned long blocksize_bits = sb->s_blocksize_bits;	unsigned long i, count = 0;	void *src, *dst;	if (sbi->super->s_magic != PRAM_SUPER_MAGIC)		return -1;	for (i = 0; i < PRAM_FAILSAFE_BACKUP_BLOCKS; i++) {		if (fsb->blocks[i])			count++;	}	if (!count)		return 0;	if (fsb->valid == PRAM_FAILSAFE_VALID) {		pram_info("restore %ld blocks\n", count);		for (i = 0; i < PRAM_FAILSAFE_BACKUP_BLOCKS; i++) {			if (!fsb->blocks[i])				continue;			src = (void *)fsb + ((i + 1) << blocksize_bits);			dst = sbi->virt_addr				+ (fsb->blocks[i] << blocksize_bits);			pram_info("restore block %ld\n", fsb->blocks[i]);			pram_lock_range(sb, dst, blocksize);			memcpy(dst, src, blocksize);			pram_unlock_range(sb, dst, blocksize);		}	} else {		pram_info("have invalid backup, %ld blocks\n", count);	}	pram_dbg("restore del backup\n");	pram_lock_failsafe_block(sb, fsb);	memset(fsb->blocks, 0, sizeof(fsb->blocks));	pram_unlock_failsafe_block(sb, fsb);#if 0	for (i = 1; i <= PRAM_FAILSAFE_BACKUP_BLOCKS; i++) {		src = (void *)fsb + (i << blocksize_bits);		pram_lock_range(sb, src, blocksize);		memset(src, 0, blocksize);		pram_unlock_range(sb, src, blocksize);	}#endif	pram_info("restore finish\n");	return 0;}static int pram_failsafe_free_unused_block(struct super_block * sb){	struct pram_super_block * ps = pram_get_super(sb);	int N = sb->s_blocksize >> 2; // num block ptrs per block	int Nbits = sb->s_blocksize_bits - 2;	int n;	int blocks = ps->s_bitmap_blocks;	size_t bitmap_size = ps->s_bitmap_blocks << sb->s_blocksize_bits;	void * bitmap = kzalloc(bitmap_size, GFP_KERNEL);	void * pram_bitmap = pram_get_bitmap(sb);	if (!bitmap)		return -ENOMEM;	/* init bitmap */	while (blocks >= 32) {		*(u32 *)bitmap++ = 0xffffffff;		blocks -= 32;	}	if (blocks)		*(u32 *)bitmap = (1 << blocks) - 1;	/* scan all inodes */	for (n = 1; n < ps->s_inodes_count; n++) {		ino_t ino = PRAM_ROOT_INO + (n << PRAM_INODE_BITS);		struct pram_inode * pi = pram_get_inode(sb, ino);		pram_off_t * row; /* ptr to row block */		int i, first_blocknr, last_blocknr;		int first_row_index, last_row_index;		if (pram_inode_is_free(pi))			continue;		if (!pi->i_blocks || !pi->i_type.reg.row_block)			continue;		first_blocknr = 0;		last_blocknr = pi->i_blocks - 1;		first_row_index = first_blocknr >> Nbits;		last_row_index  = last_blocknr >> Nbits;		row = pram_get_block(sb, pi->i_type.reg.row_block);		set_bit(pram_get_blocknr(sb, pi->i_type.reg.row_block), bitmap);		for (i = first_row_index; i <= last_row_index; i++) {			int j;			pram_off_t * col; /* ptr to column blocks */			int first_col_index = (i == first_row_index) ?				first_blocknr & (N-1) : 0;			int last_col_index = (i == last_row_index) ?				last_blocknr & (N-1) : N-1;			col = pram_get_block(sb, row[i]);			set_bit(pram_get_blocknr(sb, row[i]), bitmap);			for (j = first_col_index; j <= last_col_index; j++) {				int blocknr = pram_get_blocknr(sb, col[j]);				set_bit(blocknr, bitmap);			}		}	}	if (memcmp(bitmap, pram_bitmap, bitmap_size)) {		pram_info("%s update bitmap\n", __FUNCTION__);		/* no need to backup */		pram_lock_range(sb, pram_bitmap, bitmap_size);		memcpy(pram_bitmap, bitmap, bitmap_size);		pram_unlock_range(sb, pram_bitmap, bitmap_size);	}	kfree(bitmap);	return 0;}static int pram_failsafe_truncate(struct super_block * sb,				  pram_off_t ino, size_t size){	struct pram_sb_info *sbi = pram_get_sb_info(sb);	struct pram_inode * pi = pram_get_inode(sb, ino);	struct inode * inode = pram_fill_new_inode(sb, pi);	int err = 0;	if (!inode) {		pram_warn("truncate: get inode %ld failed\n", ino);		return -EINVAL;	}	inode->i_size = size;	pram_failsafe_mutex_lock(sbi); /* hack */	err = pram_do_truncate(inode, 0 /* do_lock */);	pram_failsafe_mutex_unlock(sbi); /* hack */	iput(inode);	return err;}static int pram_failsafe_delete(struct super_block * sb, pram_off_t ino){	struct pram_sb_info *sbi = pram_get_sb_info(sb);	struct pram_inode * pi = pram_get_inode(sb, ino);	struct inode * inode = pram_fill_new_inode(sb, pi);	int err = 0;	if (!inode) {		pram_warn("delete: get inode %ld failed\n", ino);		return -EINVAL;	}	pram_failsafe_mutex_lock(sbi); /* hack */	// unlink from chain in the inode's directory	pram_remove_link(inode);	inode->i_size = 0;	if (inode->i_blocks)		err = pram_do_truncate(inode, 0 /* do_lock */);	//pram_free_inode(inode); //FIXME: no call clear_inode	pram_lock_inode(sb, pi);	pi->i_dtime = get_seconds();	pi->i_type.reg.row_block = 0;	pram_unlock_inode(sb, pi);	pram_failsafe_mutex_unlock(sbi); /* hack */	iput(inode);	return err;}int pram_fsck(struct super_block * sb){	int err = 0;	struct pram_sb_info *sbi = pram_get_sb_info(sb);	struct pram_failsafe_block *fsb = pram_get_failsafe_block(sbi);	if (fsb->valid == PRAM_FAILSAFE_VALID) {		pram_info("op: %d args: %d %d %d\n",			  fsb->op, fsb->args[0], fsb->args[1], fsb->args[2]);		switch (fsb->op) {		case PRAM_FAILSAFE_OP_SYMLINK:			/* after restore, no inode alloced */		case PRAM_FAILSAFE_OP_DIRECT_IO:		case PRAM_FAILSAFE_OP_ALLOC_BLOCKS:			/* some blocks have been alloced in pram_alloc_blocks,			 * free thess blocks in bitmap */			err = pram_failsafe_free_unused_block(sb);			break;		case PRAM_FAILSAFE_OP_TRUNCATE:			/* some block is clear in bitmap but not in index,			 * we can truncate it again */			{				pram_off_t ino = fsb->args[0];				size_t size = fsb->args[1];				err = pram_failsafe_truncate(sb, ino, size);			}			break;		case PRAM_FAILSAFE_OP_DELETE_INODE:			{				pram_off_t ino = fsb->args[0];				err = pram_failsafe_delete(sb, ino);			}			break;		default:			break;		case 0:			pram_info("zero op\n");			break;		}		if (err) {			pram_info("fsck failed\n");			return err;		}	}	if (fsb->valid	    || fsb->op || fsb->args[0] || fsb->args[1] || fsb->args[2]) {		pram_lock_failsafe_block(sb, fsb);		fsb->valid = 0; /* first */		fsb->op = 0;		fsb->args[0] = fsb->args[1] = fsb->args[2] = 0;		pram_unlock_failsafe_block(sb, fsb);	}	return 0;}

⌨️ 快捷键说明

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