--- linux/drivers/md/lvm-snap.c.~1~ Fri Dec 21 17:41:54 2001 +++ linux/drivers/md/lvm-snap.c Wed Feb 27 15:37:02 2002 @@ -34,6 +34,8 @@ * o pv number is returned in new uint * arg * o -1 returned on error * lvm_snapshot_fill_COW_table has a return value too. + * 15/10/2001 - fix snapshot alignment problem [CM] + * - fix snapshot full oops (always check lv_block_exception) [CM] * */ @@ -45,6 +47,7 @@ #include #include #include +#include #include "lvm-internal.h" @@ -97,6 +100,8 @@ lv_block_exception_t * ret; int i = 0; + if (!hash_table) + BUG(); 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) @@ -133,6 +138,14 @@ list_add(&exception->hash, hash_table); } +/* + * Determine if we already have a snapshot chunk for this block. + * Return: 1 if it the chunk already exists + * 0 if we need to COW this block and allocate a new chunk + * -1 if the snapshot was disabled because it ran out of space + * + * We need to be holding at least a read lock on lv->lv_lock. + */ int lvm_snapshot_remap_block(kdev_t * org_dev, unsigned long * org_sector, unsigned long pe_start, lv_t * lv) { @@ -142,6 +155,9 @@ int chunk_size = lv->lv_chunk_size; lv_block_exception_t * exception; + if (!lv->lv_block_exception) + return -1; + pe_off = pe_start % chunk_size; pe_adjustment = (*org_sector-pe_off) % chunk_size; __org_start = *org_sector - pe_adjustment; @@ -286,6 +302,8 @@ /* * writes a COW exception table sector to disk (HM) + * + * We need to hold a write lock on lv_snap->lv_lock. */ int lvm_write_COW_table_block(vg_t * vg, lv_t *lv_snap) @@ -305,6 +323,10 @@ * if there is no exception storage space free any longer --> release snapshot. * * this routine gets called for each _first_ write to a physical chunk. + * + * We need to hold a write lock on lv_snap->lv_lock. It is assumed that + * lv->lv_block_exception is non-NULL (checked by lvm_snapshot_remap_block()) + * when this function is called. */ int lvm_snapshot_COW(kdev_t org_phys_dev, unsigned long org_phys_sector, @@ -313,6 +335,7 @@ vg_t *vg, lv_t* lv_snap) { const char * reason; + unsigned long phys_start; unsigned long org_start, snap_start, snap_phys_dev, virt_start, pe_off; int idx = lv_snap->lv_remap_ptr, chunk_size = lv_snap->lv_chunk_size; struct kiobuf * iobuf; @@ -347,8 +370,8 @@ iobuf = lv_snap->lv_iobuf; - blksize_org = lvm_get_blksize(org_phys_dev); - blksize_snap = lvm_get_blksize(snap_phys_dev); + blksize_org = get_hardsect_size(org_phys_dev); + blksize_snap = get_hardsect_size(snap_phys_dev); max_blksize = max(blksize_org, blksize_snap); min_blksize = min(blksize_org, blksize_snap); max_sectors = KIO_MAX_SECTORS * (min_blksize>>9); @@ -356,6 +379,9 @@ if (chunk_size % (max_blksize>>9)) goto fail_blksize; + /* Don't change org_start, we need it to fill in the exception table */ + phys_start = org_start; + while (chunk_size) { nr_sectors = min(chunk_size, max_sectors); @@ -363,7 +389,7 @@ iobuf->length = nr_sectors << 9; - if(!lvm_snapshot_prepare_blocks(iobuf->blocks, org_start, + if(!lvm_snapshot_prepare_blocks(iobuf->blocks, phys_start, nr_sectors, blksize_org)) goto fail_prepare; @@ -378,6 +404,9 @@ if (brw_kiovec(WRITE, 1, &iobuf, snap_phys_dev, iobuf->blocks, blksize_snap) != (nr_sectors<<9)) goto fail_raw_write; + + phys_start += nr_sectors; + snap_start += nr_sectors; } #ifdef DEBUG_SNAPSHOT @@ -534,8 +563,7 @@ unmap_kiobuf(lv_snap->lv_iobuf); free_kiovec(1, &lv_snap->lv_iobuf); lv_snap->lv_iobuf = NULL; - if (lv_snap->lv_snapshot_hash_table != NULL) - vfree(lv_snap->lv_snapshot_hash_table); + vfree(lv_snap->lv_snapshot_hash_table); lv_snap->lv_snapshot_hash_table = NULL; goto out; } @@ -592,7 +620,7 @@ 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); + blksize_snap = get_hardsect_size(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; @@ -640,7 +668,7 @@ idx++; 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); + blksize_snap = get_hardsect_size(snap_phys_dev); blocks[0] = snap_pe_start >> (blksize_snap >> 10); } else blocks[0]++; --- linux/drivers/md/lvm.c.~1~ Mon Nov 19 17:56:04 2001 +++ linux/drivers/md/lvm.c Wed Feb 27 15:37:09 2002 @@ -179,6 +179,8 @@ * (Jens Axboe) * - Defer writes to an extent that is being moved [JT + AD] * 28/05/2001 - implemented missing BLKSSZGET ioctl [AD] + * 12/10/2001 - Use add/del_gendisk() routines in 2.4.10+ + * 01/11/2001 - Backport read_ahead change from Linus kernel [AED] * */ @@ -224,9 +226,12 @@ #include "lvm-internal.h" -#define LVM_CORRECT_READ_AHEAD( a) \ - if ( a < LVM_MIN_READ_AHEAD || \ - a > LVM_MAX_READ_AHEAD) a = LVM_MAX_READ_AHEAD; +#define LVM_CORRECT_READ_AHEAD(a) \ +do { \ + if ((a) < LVM_MIN_READ_AHEAD || \ + (a) > LVM_MAX_READ_AHEAD) \ + (a) = LVM_DEFAULT_READ_AHEAD; \ +} while(0) #ifndef WRITEA # define WRITEA WRITE @@ -1222,13 +1227,10 @@ if (!(lv->lv_access & (LV_SNAPSHOT|LV_SNAPSHOT_ORG))) goto out; - if (lv->lv_access & LV_SNAPSHOT) { /* remap snapshot */ - if (lv->lv_block_exception) - lvm_snapshot_remap_block(&rdev_map, &rsector_map, - pe_start, lv); - else - goto bad; - + if (lv->lv_access & LV_SNAPSHOT) { /* remap snapshot */ + if (lvm_snapshot_remap_block + (&rdev_map, &rsector_map, pe_start, lv) < 0) + goto bad; } else if (rw == WRITE || rw == WRITEA) { /* snapshot origin */ lv_t *snap; @@ -1254,7 +1256,7 @@ return 1; bad: - buffer_IO_error(bh); + if (bh->b_end_io) buffer_IO_error(bh); up_read(&lv->lv_lock); return -1; } /* lvm_map() */ @@ -2020,6 +2022,7 @@ vg_lv_map[MINOR(lv_ptr->lv_dev)].vg_number = vg_ptr->vg_number; vg_lv_map[MINOR(lv_ptr->lv_dev)].lv_number = lv_ptr->lv_number; LVM_CORRECT_READ_AHEAD(lv_ptr->lv_read_ahead); + read_ahead[MAJOR_NR] = lv_ptr->lv_read_ahead; vg_ptr->lv_cur++; lv_ptr->lv_status = lv_status_save; @@ -2746,4 +2749,6 @@ module_init(lvm_init); module_exit(lvm_cleanup); +MODULE_AUTHOR("Heinz Mauelshagen, Sistina Software"); +MODULE_DESCRIPTION("Logical Volume Manager"); MODULE_LICENSE("GPL"); --- linux/include/linux/lvm.h.~1~ Sun Nov 11 18:09:32 2001 +++ linux/include/linux/lvm.h Wed Feb 27 15:37:13 2002 @@ -217,8 +217,9 @@ #define LVM_MAX_STRIPES 128 /* max # of stripes */ #define LVM_MAX_SIZE ( 1024LU * 1024 / SECTOR_SIZE * 1024 * 1024) /* 1TB[sectors] */ #define LVM_MAX_MIRRORS 2 /* future use */ -#define LVM_MIN_READ_AHEAD 2 /* minimum read ahead sectors */ -#define LVM_MAX_READ_AHEAD 120 /* maximum read ahead sectors */ +#define LVM_MIN_READ_AHEAD 0 /* minimum read ahead sectors */ +#define LVM_DEFAULT_READ_AHEAD 1024 /* sectors for 512k scsi segments */ +#define LVM_MAX_READ_AHEAD 10000 /* maximum read ahead sectors */ #define LVM_MAX_LV_IO_TIMEOUT 60 /* seconds I/O timeout (future use) */ #define LVM_PARTITION 0xfe /* LVM partition id */ #define LVM_NEW_PARTITION 0x8e /* new LVM partition id (10/09/1999) */