From 26ee06c4bd9119a979627dccd71e3b8d58211aeb Mon Sep 17 00:00:00 2001 From: Krzysztof Mazur Date: Sat, 18 Dec 2010 22:56:36 +0100 Subject: [PATCH 09/84] lsbd: code cleanups --- drivers/block/lsbd.c | 273 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 229 insertions(+), 44 deletions(-) diff --git a/drivers/block/lsbd.c b/drivers/block/lsbd.c index 209dd93..bdc26b1 100644 --- a/drivers/block/lsbd.c +++ b/drivers/block/lsbd.c @@ -41,15 +41,20 @@ #define LSBD_MAX 8 #define PART_BITS 5 +/* + * LSBD block header must have 1024 bytes + */ struct __block_test { int a[(sizeof(struct lsbd_block) == 1024) ? 1 : -1]; }; - +/* + * Write queue priorities + */ enum { - LSBD_QUEUE_MOVE, - LSBD_QUEUE_HIGH, - LSBD_QUEUE_NORMAL, + LSBD_QUEUE_MOVE, /* rewrite of old data */ + LSBD_QUEUE_HIGH, /* high priority requests */ + LSBD_QUEUE_NORMAL, /* normal requests */ LSBD_QUEUE_COUNT, /* must be last */ }; @@ -121,11 +126,22 @@ static struct hd_struct lsbd_struct[LSBD_MAX << PART_BITS]; static int lsbd_thread(void *data); -unsigned int block_prev(struct lsbd *p, unsigned int block) +/** + * block_prev - compute id of previous block + * @p: LSBD device + * @block: block number + */ +static unsigned int block_prev(struct lsbd *p, unsigned int block) { return block ? block - 1 : p->blocks - 1; } +/** + * block_diff - compute distance between two blocks + * @p: LSBD device + * @a: later block + * @b: earlier block + */ unsigned int block_diff(struct lsbd *p, unsigned int a, unsigned int b) { if (a >= b) @@ -133,6 +149,15 @@ unsigned int block_diff(struct lsbd *p, unsigned int a, unsigned int b) return p->blocks + a - b; } +/** + * lsbd_map_sector - map sector in partition to global logical sector + * @p: LSBD device + * @partition: LSBD partition + * @sector: number of sector in selected partition + * + * This function returns logical sector id on success; LSBD_SECT_INVALID + * otherwise. + */ static unsigned int lsbd_map_sector(struct lsbd *p, unsigned int partition, unsigned int sector) { @@ -149,6 +174,9 @@ static unsigned int lsbd_map_sector(struct lsbd *p, unsigned int partition, return sector + p->part[partition].start; } +/* + * lsbd_open - open LSBD block device + */ static int lsbd_open(struct inode *inode, struct file *file) { int minor; @@ -169,6 +197,9 @@ static int lsbd_open(struct inode *inode, struct file *file) return 0; } +/* + * lsbd_release - release LSBD block device + */ static int lsbd_release(struct inode *inode, struct file *file) { int minor; @@ -189,22 +220,51 @@ static int lsbd_release(struct inode *inode, struct file *file) return 0; } -unsigned int lsbd_block_size(struct lsbd *p) +/** + * lsbd_block_size - compute physical block size + * @p: LSBD device + */ +static unsigned int lsbd_block_size(struct lsbd *p) { return p->sectors_per_block * p->sector_size; } +/** + * lsbs_bread - read block + * @p: LSBD device + * @block: block number + * @size: number of bytes to read + * + * This function NULL on failure; pointer to allocated buffer otherwise. + */ struct buffer_head *lsbd_bread(struct lsbd *p, int block, int size) { return bread(p->dev, block * p->sectors_per_block, size); } +/** + * lsbs_sread - read data sector + * @p: LSBD device + * @block: block number + * @sector: sector offset in block + * @size: number of bytes to read + * + * This function NULL on failure; pointer to allocated buffer otherwise. + */ struct buffer_head *lsbd_sread(struct lsbd *p, int block, unsigned int sector, int size) { return bread(p->dev, block * p->sectors_per_block + sector + 1, size); } +/** + * lsbs_checksum - compute LSBD checksum + * @buf: pointer to buffer + * @count: number of bytes to checksum, must be a multiple of 4 + * + * This checksum is used mostly for detecting corruptions caused + * by power failures. + */ static u32 lsbd_checksum(const void *buf, size_t count) { const u32 *b = buf; @@ -217,6 +277,13 @@ static u32 lsbd_checksum(const void *buf, size_t count) return csum; } +/** + * lsbd_block_verify_ok - verify LSBD block header checksum + * @p: LSBD device + * @b: LSBD block to check + * + * This function returns non-zero when checksum is correct; zero otherwise. + */ static int lsbd_block_verify_ok(struct lsbd *p, const struct lsbd_block *b) { u32 csum = lsbd_checksum(b, sizeof(*b) - 4); @@ -225,6 +292,13 @@ static int lsbd_block_verify_ok(struct lsbd *p, const struct lsbd_block *b) return (be32_to_cpu(b->checksum) == csum); } +/** + * lsbd_block_verify_ok - update LSBD block header checksum + * @p: LSBD device + * @b: LSBD block to check + * + * This function returns zero value on success; negative error-code otherwise. + */ static int lsbd_block_commit(struct lsbd *p, struct lsbd_block *b) { u32 csum = lsbd_checksum(b, sizeof(*b) - 4); @@ -234,8 +308,12 @@ static int lsbd_block_commit(struct lsbd *p, struct lsbd_block *b) return 0; } -/* +/** * lsbd_find_current_block - find current block + * @p: LSBD device + * + * This function finds block with the highest epoch. It assumes correct + * order of blocks. */ static int lsbd_find_current_block(struct lsbd *p) { @@ -249,7 +327,13 @@ static int lsbd_find_current_block(struct lsbd *p) unsigned long long e = 0; unsigned int reads = 0; - /* read first block */ + /* + * read first block + * + * FIXME: This may take some time on invalid devices. + * Maybe it's a good idea to do some sparse test to detect + * devices without valid structure. + */ for (i = 0; i < p->blocks; i++) { reads++; bh = lsbd_bread(p, i, sizeof(*b)); @@ -272,6 +356,12 @@ static int lsbd_find_current_block(struct lsbd *p) return -EINVAL; } + /* + * Binary search. + * + * FIXME: This should be O(log(blocks)), but on currupted devices + * it may degrade to O(blocks). + */ blocks = p->blocks - base; block = base + blocks / 2; while (blocks > 1) { @@ -323,8 +413,14 @@ static int lsbd_find_current_block(struct lsbd *p) return 0; } -/* +/** * lsbd_read_lcache - create lcache mapping + * @p: LSBD device + * + * This function creates lcache. It's O(logical_sectors). + * + * The lcache is generated using block sectors -> logical sector mappings + * and lcache chunks stored in metadata. */ int lsbd_read_lcache(struct lsbd *p) { @@ -371,6 +467,10 @@ int lsbd_read_lcache(struct lsbd *p) continue; } + /* + * Process sector -> logical sector mapping firts because + * they are never than lcache. + */ sects = (void *) (bh->b_data + be32_to_cpu(b->ptab_offset)); sectors = be32_to_cpu(b->sectors_per_block) - 1; if (sectors > sectors_max) @@ -389,6 +489,9 @@ int lsbd_read_lcache(struct lsbd *p) } } + /* + * Process lcache chunks stored in metadata. + */ lcache_offset = be32_to_cpu(b->lcache_offset); if (lcache_offset > p->sector_size) { brelse(bh); @@ -434,6 +537,11 @@ int lsbd_read_lcache(struct lsbd *p) return 0; } +/** + * lsbd_update_part - update partition informations + * @p: LSBD device + * @part: parition number + */ static int lsbd_update_part(struct lsbd *p, unsigned int part) { lsbd_debug(p, "partition %d: start %d MiB, size %d MiB\n", part, @@ -444,6 +552,11 @@ static int lsbd_update_part(struct lsbd *p, unsigned int part) return 0; } +/** + * lsbd_load_partitions - load paritions from specified block + * @p: LSBD device + * @b: LSBD block + */ static int lsbd_load_partitions(struct lsbd *p, struct lsbd_block *b) { unsigned int start; @@ -474,6 +587,11 @@ static int lsbd_load_partitions(struct lsbd *p, struct lsbd_block *b) return 0; } +/** + * lsbd_write_partitions - write paritions to specified block + * @p: LSBD device + * @b: LSBD block + */ static int lsbd_write_partitions(struct lsbd *p, struct lsbd_block *b) { unsigned int i; @@ -485,6 +603,10 @@ static int lsbd_write_partitions(struct lsbd *p, struct lsbd_block *b) return 0; } +/** + * lsbd_load_params - load LSBD parameters from device + * @p: LSBD device + */ static int lsbd_load_params(struct lsbd *p) { struct buffer_head *bh; @@ -532,7 +654,6 @@ static int lsbd_load_params(struct lsbd *p) lsbd_info(p, "changing sector size to %d\n", sector_size); p->sector_size = sector_size; -// p->blks_per_sector = p->sector_size / p->blksize; } if (blocks < p->blocks) { @@ -554,7 +675,7 @@ static int lsbd_load_params(struct lsbd *p) lsbd_sizes[p->id] = p->lsectors * (p->sector_size >> 10); p->blocks_to_write = 0; - + lsbd_load_partitions(p, b); brelse(bh); return 0; @@ -562,6 +683,12 @@ static int lsbd_load_params(struct lsbd *p) return 1; } +/** + * lsbd_stop - stop LSBD device + * @p: LSBD device + * + * TODO: Clean write queue. + */ static void lsbd_stop(struct lsbd *p) { struct completion event; @@ -576,6 +703,10 @@ static void lsbd_stop(struct lsbd *p) MOD_DEC_USE_COUNT; } +/** + * lsbd_mount - start LSBD device + * @p: LSBD device + */ static int lsbd_mount(struct lsbd *p) { int blksize; @@ -593,11 +724,15 @@ static int lsbd_mount(struct lsbd *p) if (!blksize) blksize = 1024; + /* + * Currently only 4kB sectors are supported. The minimal sector size + * for LSBD is 2kB. The maximal supported by block device layer + * is 4kB. + */ p->blksize = blksize; p->sector_size = blksize; if (p->sector_size) p->sector_size = 4096; -// p->blks_per_sector = p->sector_size / blksize; lsbd_debug(p, "assuming %d sector size\n", p->sector_size); p->sectors_per_block = 16; @@ -633,6 +768,12 @@ static int lsbd_mount(struct lsbd *p) return 0; } +/** + * lsbd_set_dev - set LSBD device + * @p: LSBD device + * @major: device major number + * @minor: device minor number + */ static int lsbd_set_dev(struct lsbd *p, int major, int minor) { kdev_t dev = MKDEV(major, minor); @@ -644,6 +785,11 @@ static int lsbd_set_dev(struct lsbd *p, int major, int minor) return lsbd_mount(p); } +/** + * lsbd_write_blocks - write @num blocks in near future + * @p: LSBD device + * @num: minimal number of blocks to write + */ static int lsbd_write_blocks(struct lsbd *p, unsigned int num) { unsigned long flags; @@ -652,7 +798,7 @@ static int lsbd_write_blocks(struct lsbd *p, unsigned int num) * increase number of block for redundancy */ num *= 2; - + spin_lock_irqsave(&p->wqueue_lock, flags); if (p->blocks_to_write < num) p->blocks_to_write = num; @@ -661,20 +807,31 @@ static int lsbd_write_blocks(struct lsbd *p, unsigned int num) return 0; } - + +/** + * lsbd_partition - modify LSBD partitions + * @p: LSBD device + * @part: partition info + */ static int lsbd_partition(struct lsbd *p, struct lsbd_part_info *part) { lsbd_debug(p, "part: %d %d %d %d\n", part->num, part->flags, part->start, part->size); if (part->num > 16) return -EINVAL; - + if (part->flags) return -EINVAL; + /* + * Partition 0 is special - it's whole device. + */ if (!part->num) { unsigned int sectors; + /* + * whole device partition must start at 0 + */ if (part->start) return -EINVAL; @@ -706,7 +863,7 @@ static int lsbd_partition(struct lsbd *p, struct lsbd_part_info *part) lsbd_write_blocks(p, p->lsectors / chunk); /* - * FIXME: implement lcache locking + * FIXME: implement lcache locking */ schedule_timeout(10); vfree(ol); @@ -720,9 +877,11 @@ static int lsbd_partition(struct lsbd *p, struct lsbd_part_info *part) if ((u64) part->start + part->size > p->lsectors) return -EINVAL; + /* + * Partition start and size must be 256 sectors aligned. + */ if (part->start & ~LSBD_PART_MASK) return -EINVAL; - if (part->size & ~LSBD_PART_MASK) return -EINVAL; @@ -730,7 +889,9 @@ static int lsbd_partition(struct lsbd *p, struct lsbd_part_info *part) p->part[part->num].size = part->size; lsbd_update_part(p, part->num); - /* write partition */ + /* + * write partition table to device + */ lsbd_write_blocks(p, 1); return 0; } @@ -818,6 +979,13 @@ static struct gendisk lsbd_gendisk = { .fops = &lsbd_fops, }; +/** + * lsbd_queue_bh - queue write operation + * @p: LSBD device + * @bh: buffer head + * @sector: sector number + * @prio: priority + */ static int lsbd_queue_bh(struct lsbd *p, struct buffer_head *bh, unsigned int sector, unsigned int prio) { @@ -834,7 +1002,7 @@ static int lsbd_queue_bh(struct lsbd *p, struct buffer_head *bh, if (!move) down(&p->req_sem); - /* queue non-read requests to daemon */ + r = kmalloc(sizeof(*r), GFP_NOIO); if (r == NULL) { if (!move) @@ -865,9 +1033,13 @@ static int lsbd_make_request(request_queue_t *q, int rw, unsigned int partition = lsbd_partition(MINOR(bh->b_rdev)); unsigned int lsector = LSBD_SECT_INVALID; + /* + * Reading is quite simple - request are just remapped to lower + * level device + */ if (rw == READA || rw == READ) { unsigned int sector; - + lsector = bh->b_rsector >> 3; lsbd_debug(p, "reading sector %d (%ld)\n", lsector, bh->b_rsector); @@ -904,6 +1076,10 @@ static int lsbd_make_request(request_queue_t *q, int rw, return 1; } + /* + * Writting to LSBD is quite complex. Because of this write + * requests are handled by single thread. + */ if (rw == WRITE) { unsigned int queue = LSBD_QUEUE_NORMAL; @@ -926,6 +1102,14 @@ static int lsbd_make_request(request_queue_t *q, int rw, return 0; } +/** + * lsbd_clean_block - clean next LSBD block + * @p: LSBD device + * + * The cleaning of blocks is quite simple. We just read block and + * add all recent sectors in this block to write queue. These sectors + * should be written at least 2 blocks before this block. + */ void lsbd_clean_block(struct lsbd *p) { unsigned long block = p->clean_block; @@ -943,14 +1127,6 @@ void lsbd_clean_block(struct lsbd *p) if (block >= p->blocks) block = 0; -#if 0 - /* - * do not clean mirror blocks - */ - if (p->mirror_offset && (block & 1)) - goto out; -#endif - bh = lsbd_bread(p, block, p->sector_size); if (bh == NULL) goto out; @@ -997,6 +1173,11 @@ out: p->clean_block = block; } +/** + * initialize_block - initialize LSBD block header + * @p: LSBD device + * @b: LSBD block + */ static int initialize_block(struct lsbd *p, struct lsbd_block *b) { unsigned int i; @@ -1006,9 +1187,9 @@ static int initialize_block(struct lsbd *p, struct lsbd_block *b) b->revision = cpu_to_be32(0); b->ctime = cpu_to_be64(0); b->mtime = cpu_to_be64(0); - + b->epoch = cpu_to_be64(0); - + /* FIXME: store age also in other blocks? */ b->age = cpu_to_be64(0); @@ -1023,6 +1204,11 @@ static int initialize_block(struct lsbd *p, struct lsbd_block *b) return 0; } +/** + * lsbd_write_lcache - write lcache chunk to LSBD block + * @p: LSBD device + * @bp: pointer to LSBD block + */ static int lsbd_write_lcache(struct lsbd *p, void *bp) { struct lsbd_block *b = bp; @@ -1055,7 +1241,7 @@ static int lsbd_write_lcache(struct lsbd *p, void *bp) /** * lsbd_request_dequeue - dequeue request - * @p: LSBD state + * @p: LSBD device */ static struct lsbd_request *lsbd_request_dequeue(struct lsbd *p) { @@ -1077,14 +1263,11 @@ static struct lsbd_request *lsbd_request_dequeue(struct lsbd *p) return r; } -static void lsbd_end_buffer_io_sync(struct buffer_head *bh, int uptodate) -{ - mark_buffer_uptodate(bh, uptodate); - unlock_buffer(bh); - put_bh(bh); -} - -int lsbd_write_block(struct lsbd *p) +/** + * lsbd_write_block - write block + * @p: LSBD device + */ +static int lsbd_write_block(struct lsbd *p) { struct buffer_head **bh; struct buffer_head **wbh; @@ -1117,7 +1300,6 @@ int lsbd_write_block(struct lsbd *p) bh[i] = getblk(p->dev, base_sector + i, p->sector_size); BUG_ON(bh[i] == NULL); lock_buffer(bh[i]); - bh[i]->b_end_io = lsbd_end_buffer_io_sync; } memset(bh[0]->b_data, 0, p->sector_size); @@ -1189,6 +1371,9 @@ int lsbd_write_block(struct lsbd *p) return 0; } +/** + * lsbd_thread - LSBD write thread + */ static int lsbd_thread(void *data) { struct lsbd *p = data; @@ -1205,7 +1390,7 @@ static int lsbd_thread(void *data) flush_signals(current); spin_unlock(¤t->sigmask_lock); p->tsk = current; - + /* * lsbd is a 'system-thread', it's priority should be very * high. @@ -1217,7 +1402,7 @@ static int lsbd_thread(void *data) complete(p->event); for (;;) { DECLARE_WAITQUEUE(wait, current); - + want_write = 0; want_clean = 0; @@ -1233,7 +1418,7 @@ static int lsbd_thread(void *data) schedule(); current->state = TASK_RUNNING; remove_wait_queue(&p->wqueue_wait, &wait); - + lsbd_debug(p, "lsbd_thread: reqs %d\n", len); if (signal_pending(current)) { @@ -1302,7 +1487,7 @@ int __init lsbd_init_module(void) for (i = 0; i < (LSBD_MAX << PART_BITS); i++) lsbd_blksizes[i] = 4096; blksize_size[MAJOR_NR] = lsbd_blksizes; - + for (i = 0; i < (LSBD_MAX << PART_BITS); i++) lsbd_sizes[i] = 0; blk_size[MAJOR_NR] = lsbd_sizes; -- 1.8.4.652.g0d6e0ce