From ffc97c5c68ac19121d316f65e69c4e8e1834fe2d Mon Sep 17 00:00:00 2001 From: Thomas Schoebel-Theuer Date: Wed, 25 Sep 2013 15:21:50 +0200 Subject: [PATCH] if: fix set_capacity() --- kernel/mars_if.c | 47 ++++++++++++++++++++++++++++++++++------------- kernel/mars_if.h | 2 +- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/kernel/mars_if.c b/kernel/mars_if.c index 308c911e..c9106b71 100644 --- a/kernel/mars_if.c +++ b/kernel/mars_if.c @@ -658,20 +658,41 @@ int mars_merge_bvec(struct request_queue *q, struct bvec_merge_data *bvm, struct } static -unsigned long compute_capacity(struct if_brick *brick) +loff_t if_get_capacity(struct if_brick *brick) { + /* Don't read always, read only when unknown. + * brick->dev_size may be different from underlying sizes, + * e.g. when the size symlink indicates a logically smaller + * device than physically. + */ if (brick->dev_size <= 0) { struct mars_info info = {}; struct if_input *input = brick->inputs[0]; int status; + status = GENERIC_INPUT_CALL(input, mars_get_info, &info); - if (status < 0) { + if (unlikely(status < 0)) { MARS_ERR("cannot get device info, status=%d\n", status); return 0; } + MARS_INF("determined default capacity: %lld bytes\n", info.current_size); brick->dev_size = info.current_size; } - return brick->dev_size >> 9; // TODO: make this dynamic + return brick->dev_size; +} + +static +void if_set_capacity(struct if_input *input, loff_t capacity) +{ + CHECK_PTR(input->disk, done); + CHECK_PTR(input->disk->disk_name, done); + MARS_INF("new capacity of '%s': %lld bytes\n", input->disk->disk_name, capacity); + input->capacity = capacity; + set_capacity(input->disk, capacity >> 9); + if (likely(input->bdev && input->bdev->bd_inode)) { + i_size_write(input->bdev->bd_inode, capacity); + } +done:; } static const struct block_device_operations if_blkdev_ops; @@ -682,27 +703,27 @@ static int if_switch(struct if_brick *brick) struct request_queue *q; struct gendisk *disk; int minor; - unsigned long capacity; int status = 0; down(&brick->switch_sem); // brick is in operation if (brick->power.button && brick->power.led_on) { - capacity = compute_capacity(brick); + loff_t capacity; + capacity = if_get_capacity(brick); if (capacity > 0 && capacity != input->capacity) { - MARS_INF("changing capacity from %lld to %lld\n", (long long)input->capacity * 2, (long long)capacity * 2); - input->capacity = capacity; - set_capacity(input->disk, capacity); + MARS_INF("changing capacity from %lld to %lld\n", (long long)input->capacity, (long long)capacity); + if_set_capacity(input, capacity); } } // brick should be switched on if (brick->power.button && brick->power.led_off) { + loff_t capacity; + mars_power_led_off((void*)brick, false); brick->say_channel = get_binding(current); - capacity = compute_capacity(brick); status = -ENOMEM; q = blk_alloc_queue(GFP_MARS); if (!q) { @@ -726,10 +747,11 @@ static int if_switch(struct if_brick *brick) disk->first_minor = minor; disk->fops = &if_blkdev_ops; snprintf(disk->disk_name, sizeof(disk->disk_name), "mars/%s", brick->brick_name); - MARS_DBG("created device name %s, capacity=%lu\n", disk->disk_name, capacity); disk->private_data = input; - input->capacity = capacity; - set_capacity(disk, capacity); + input->disk = disk; + capacity = if_get_capacity(brick); + MARS_DBG("created device name %s, capacity=%lld\n", disk->disk_name, capacity); + if_set_capacity(input, capacity); blk_queue_make_request(q, if_make_request); #ifdef USE_MAX_SECTORS @@ -800,7 +822,6 @@ static int if_switch(struct if_brick *brick) // point of no return MARS_DBG("add_disk()\n"); add_disk(disk); - input->disk = disk; #if 1 set_disk_ro(disk, false); #else diff --git a/kernel/mars_if.h b/kernel/mars_if.h index 66681a29..fbe1d3de 100644 --- a/kernel/mars_if.h +++ b/kernel/mars_if.h @@ -46,7 +46,7 @@ struct if_input { #ifdef USE_TIMER struct timer_list timer; #endif - unsigned long capacity; + loff_t capacity; atomic_t plugged_count; atomic_t flying_count; // only for statistics