📄 lvm-snap.c
字号:
/* * kernel/lvm-snap.c * * Copyright (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE * Heinz Mauelshagen, Sistina Software (persistent snapshots) * * LVM snapshot driver 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, or (at your option) * any later version. * * LVM snapshot driver 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 GNU CC; see the file COPYING. If not, write to * the Free Software Foundation, 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * */#include <linux/kernel.h>#include <linux/vmalloc.h>#include <linux/blkdev.h>#include <linux/smp_lock.h>#include <linux/types.h>#include <linux/iobuf.h>#include <linux/lvm.h>static char *lvm_snap_version __attribute__ ((unused)) = "LVM 0.9 snapshot code (13/11/2000)\n";extern const char *const lvm_name;extern int lvm_blocksizes[];void lvm_snapshot_release(lv_t *);uint lvm_pv_get_number(vg_t * vg, kdev_t rdev){ uint p; for ( p = 0; p < vg->pv_max; p++) { if ( vg->pv[p] == NULL) continue; if ( vg->pv[p]->pv_dev == rdev) break; } return vg->pv[p]->pv_number;}#define hashfn(dev,block,mask,chunk_size) \ ((HASHDEV(dev)^((block)/(chunk_size))) & (mask))static inline lv_block_exception_t *lvm_find_exception_table(kdev_t org_dev, unsigned long org_start, lv_t * lv){ struct list_head * hash_table = lv->lv_snapshot_hash_table, * next; unsigned long mask = lv->lv_snapshot_hash_mask; int chunk_size = lv->lv_chunk_size; lv_block_exception_t * ret; int i = 0; hash_table = &hash_table[hashfn(org_dev, org_start, mask, chunk_size)]; ret = NULL; for (next = hash_table->next; next != hash_table; next = next->next) { lv_block_exception_t * exception; exception = list_entry(next, lv_block_exception_t, hash); if (exception->rsector_org == org_start && exception->rdev_org == org_dev) { if (i) { /* fun, isn't it? :) */ list_del(next); list_add(next, hash_table); } ret = exception; break; } i++; } return ret;}inline void lvm_hash_link(lv_block_exception_t * exception, kdev_t org_dev, unsigned long org_start, lv_t * lv){ struct list_head * hash_table = lv->lv_snapshot_hash_table; unsigned long mask = lv->lv_snapshot_hash_mask; int chunk_size = lv->lv_chunk_size; hash_table = &hash_table[hashfn(org_dev, org_start, mask, chunk_size)]; list_add(&exception->hash, hash_table);}int lvm_snapshot_remap_block(kdev_t * org_dev, unsigned long * org_sector, unsigned long pe_start, lv_t * lv){ int ret; unsigned long pe_off, pe_adjustment, __org_start; kdev_t __org_dev; int chunk_size = lv->lv_chunk_size; lv_block_exception_t * exception; pe_off = pe_start % chunk_size; pe_adjustment = (*org_sector-pe_off) % chunk_size; __org_start = *org_sector - pe_adjustment; __org_dev = *org_dev; ret = 0; exception = lvm_find_exception_table(__org_dev, __org_start, lv); if (exception) { *org_dev = exception->rdev_new; *org_sector = exception->rsector_new + pe_adjustment; ret = 1; } return ret;}void lvm_drop_snapshot(lv_t * lv_snap, const char * reason){ kdev_t last_dev; int i; /* no exception storage space available for this snapshot or error on this snapshot --> release it */ invalidate_buffers(lv_snap->lv_dev); for (i = last_dev = 0; i < lv_snap->lv_remap_ptr; i++) { if ( lv_snap->lv_block_exception[i].rdev_new != last_dev) { last_dev = lv_snap->lv_block_exception[i].rdev_new; invalidate_buffers(last_dev); } } lvm_snapshot_release(lv_snap); printk(KERN_INFO "%s -- giving up to snapshot %s on %s due %s\n", lvm_name, lv_snap->lv_snapshot_org->lv_name, lv_snap->lv_name, reason);}static inline void lvm_snapshot_prepare_blocks(unsigned long * blocks, unsigned long start, int nr_sectors, int blocksize){ int i, sectors_per_block, nr_blocks; sectors_per_block = blocksize >> 9; nr_blocks = nr_sectors / sectors_per_block; start /= sectors_per_block; for (i = 0; i < nr_blocks; i++) blocks[i] = start++;}inline int lvm_get_blksize(kdev_t dev){ int correct_size = BLOCK_SIZE, i, major; major = MAJOR(dev); if (blksize_size[major]) { i = blksize_size[major][MINOR(dev)]; if (i) correct_size = i; } return correct_size;}#ifdef DEBUG_SNAPSHOTstatic inline void invalidate_snap_cache(unsigned long start, unsigned long nr, kdev_t dev){ struct buffer_head * bh; int sectors_per_block, i, blksize, minor; minor = MINOR(dev); blksize = lvm_blocksizes[minor]; sectors_per_block = blksize >> 9; nr /= sectors_per_block; start /= sectors_per_block; for (i = 0; i < nr; i++) { bh = get_hash_table(dev, start++, blksize); if (bh) bforget(bh); }}#endifvoid lvm_snapshot_fill_COW_page(vg_t * vg, lv_t * lv_snap){ int id = 0, is = lv_snap->lv_remap_ptr; ulong blksize_snap; lv_COW_table_disk_t * lv_COW_table = ( lv_COW_table_disk_t *) page_address(lv_snap->lv_COW_table_page); if (is == 0) return; is--; blksize_snap = lvm_get_blksize(lv_snap->lv_block_exception[is].rdev_new); is -= is % (blksize_snap / sizeof(lv_COW_table_disk_t)); memset(lv_COW_table, 0, blksize_snap); for ( ; is < lv_snap->lv_remap_ptr; is++, id++) { /* store new COW_table entry */ lv_COW_table[id].pv_org_number = LVM_TO_DISK64(lvm_pv_get_number(vg, lv_snap->lv_block_exception[is].rdev_org)); lv_COW_table[id].pv_org_rsector = LVM_TO_DISK64(lv_snap->lv_block_exception[is].rsector_org); lv_COW_table[id].pv_snap_number = LVM_TO_DISK64(lvm_pv_get_number(vg, lv_snap->lv_block_exception[is].rdev_new)); lv_COW_table[id].pv_snap_rsector = LVM_TO_DISK64(lv_snap->lv_block_exception[is].rsector_new); }}/* * writes a COW exception table sector to disk (HM) * */int lvm_write_COW_table_block(vg_t * vg, lv_t * lv_snap){ int blksize_snap; int end_of_table; int idx = lv_snap->lv_remap_ptr, idx_COW_table; int nr_pages_tmp; int length_tmp; ulong snap_pe_start, COW_table_sector_offset, COW_entries_per_pe, COW_chunks_per_pe, COW_entries_per_block; ulong blocks[1]; const char * reason; kdev_t snap_phys_dev; struct kiobuf * iobuf = lv_snap->lv_iobuf; struct page * page_tmp; lv_COW_table_disk_t * lv_COW_table = ( lv_COW_table_disk_t *) page_address(lv_snap->lv_COW_table_page); idx--; COW_chunks_per_pe = LVM_GET_COW_TABLE_CHUNKS_PER_PE(vg, lv_snap); COW_entries_per_pe = LVM_GET_COW_TABLE_ENTRIES_PER_PE(vg, lv_snap); /* get physical addresse of destination chunk */ snap_phys_dev = lv_snap->lv_block_exception[idx].rdev_new; snap_pe_start = lv_snap->lv_block_exception[idx - (idx % COW_entries_per_pe)].rsector_new - lv_snap->lv_chunk_size; blksize_snap = lvm_get_blksize(snap_phys_dev); COW_entries_per_block = blksize_snap / sizeof(lv_COW_table_disk_t); idx_COW_table = idx % COW_entries_per_pe % COW_entries_per_block; if ( idx_COW_table == 0) memset(lv_COW_table, 0, blksize_snap); /* sector offset into the on disk COW table */ COW_table_sector_offset = (idx % COW_entries_per_pe) / (SECTOR_SIZE / sizeof(lv_COW_table_disk_t)); /* COW table block to write next */ blocks[0] = (snap_pe_start + COW_table_sector_offset) >> (blksize_snap >> 10); /* store new COW_table entry */ lv_COW_table[idx_COW_table].pv_org_number = LVM_TO_DISK64(lvm_pv_get_number(vg, lv_snap->lv_block_exception[idx].rdev_org)); lv_COW_table[idx_COW_table].pv_org_rsector = LVM_TO_DISK64(lv_snap->lv_block_exception[idx].rsector_org); lv_COW_table[idx_COW_table].pv_snap_number = LVM_TO_DISK64(lvm_pv_get_number(vg, snap_phys_dev)); lv_COW_table[idx_COW_table].pv_snap_rsector = LVM_TO_DISK64(lv_snap->lv_block_exception[idx].rsector_new); length_tmp = iobuf->length; iobuf->length = blksize_snap; page_tmp = iobuf->maplist[0]; iobuf->maplist[0] = lv_snap->lv_COW_table_page; nr_pages_tmp = iobuf->nr_pages; iobuf->nr_pages = 1; if (brw_kiovec(WRITE, 1, &iobuf, snap_phys_dev, blocks, blksize_snap) != blksize_snap) goto fail_raw_write; /* initialization of next COW exception table block with zeroes */ end_of_table = idx % COW_entries_per_pe == COW_entries_per_pe - 1; if (idx_COW_table % COW_entries_per_block == COW_entries_per_block - 1 || end_of_table) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -