📄 failsafe.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 + -