From 96feccc47d23423d84ebfa6c24d88875d6d0d3c8 Mon Sep 17 00:00:00 2001 From: Krzysztof Mazur Date: Wed, 18 May 2011 20:34:09 +0200 Subject: [PATCH 34/84] lsbd: fix online logical resizing --- drivers/block/lsbd.c | 73 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 56 insertions(+), 17 deletions(-) diff --git a/drivers/block/lsbd.c b/drivers/block/lsbd.c index b666bfa..448a88d 100644 --- a/drivers/block/lsbd.c +++ b/drivers/block/lsbd.c @@ -947,23 +947,48 @@ static int lsbd_load_params(struct lsbd *p) * * TODO: Clean write queue. */ -static void lsbd_stop(struct lsbd *p, struct block_device *bdev) +static void lsbd_stop(struct lsbd *p) { struct completion event; - kdev_t dev = to_kdev_t(bdev->bd_dev); + unsigned int i; lsbd_info(p, "stopping lsbd task (pid = %d)\n", p->tsk->pid); init_completion(&event); + for (i = 0; i < 1 << PART_BITS; i++) + fsync_dev(MKDEV(LSBD_MAJOR, (p->id << PART_BITS) + i)); + p->event = &event; p->stop = 1; - fsync_dev(dev); send_sig(SIGKILL, p->tsk, 1); wait_for_completion(&event); p->tsk = NULL; - invalidate_bdev(bdev, 1); - MOD_DEC_USE_COUNT; + + for (i = 0; i < 1 << PART_BITS; i++) + invalidate_buffers(MKDEV(LSBD_MAJOR, (p->id << PART_BITS) + i)); +} + +/** + * lsbd_start - start LDBD device + * @p: LSBD device to start + */ +static int lsbd_start(struct lsbd *p) +{ + struct completion event; + int ret; + + lsbd_info(p, "starting lsbd task\n"); + p->stop = 0; + init_completion(&event); + p->event = &event; + ret = kernel_thread(lsbd_thread, p, 0); + if (ret < 0) { + lsbd_error(p, "cannot start LSBD thread: %d\n", ret); + return ret; + } + wait_for_completion(&event); + return 0; } /** @@ -975,10 +1000,8 @@ static int lsbd_mount(struct lsbd *p) int blksize; int size; int ret; - struct completion event; BUG_ON(p->tsk != NULL); - p->stop = 0; blksize = 0; if (blksize_size[MAJOR(p->dev)]) blksize = blksize_size[MAJOR(p->dev)][MINOR(p->dev)]; @@ -1026,14 +1049,11 @@ static int lsbd_mount(struct lsbd *p) lsbd_read_lcache(p); MOD_INC_USE_COUNT; - init_completion(&event); - p->event = &event; - ret = kernel_thread(lsbd_thread, p, 0); - if (ret < 0) { + ret = lsbd_start(p); + if (ret) { MOD_DEC_USE_COUNT; return ret; } - wait_for_completion(&event); return 0; } @@ -1131,19 +1151,36 @@ static int lsbd_partition(struct lsbd *p, struct lsbd_part_info *part) l = vmalloc(part->size * sizeof(l[0])); if (l == NULL) return -ENOMEM; + + /* initialize zeroed new sectors */ for (i = p->lsectors; i < part->size; i++) l[i] = LSBD_SECT_ZERO; + + /* + * during lcache rebuild it's better to stop LSBD + * thread for a while. Because of this we don't + * need synchronization with LSBD thread. We need + * only synchronization with lsbd_make_request(). + */ + lsbd_stop(p); + + /* copy lcache for existing sectors */ + for (i = 0; i < p->lsectors; i++) + l[i] = p->lcache[i]; + ol = p->lcache; p->lcache = l; + lsbd_start(p); + p->lsectors = part->size; chunk = (p->sector_size - 0x800) / sizeof(*l); lsbd_write_blocks(p, p->lsectors / chunk); - /* - * FIXME: implement lcache locking - */ + /* + * FIXME: implement lcache locking + */ schedule_timeout(10); vfree(ol); } else { @@ -1212,8 +1249,10 @@ static int lsbd_ioctl(struct inode *inode, struct file *file, unsigned int major = arg >> 20; unsigned int minor = arg & 0xfffff; - if (p->tsk != NULL) - lsbd_stop(p, inode->i_bdev); + if (p->tsk != NULL) { + lsbd_stop(p); + MOD_DEC_USE_COUNT; + } err = lsbd_set_dev(p, major, minor); break; -- 1.8.4.652.g0d6e0ce