X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fblock%2Fbrd.c;h=f1bf79d9bc0a1c65df988ef4ec0b3c1eab907d93;hb=b7c335713ea130d707c22d7f7c57a8eca75ded7e;hp=24b97b0bef994411bda31e377c041da6471ed9a2;hpb=efedf51c866130945b5db755cb58670e60205d83;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/block/brd.c b/drivers/block/brd.c index 24b97b0..f1bf79d 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -15,9 +15,9 @@ #include #include #include -#include #include #include /* invalidate_bh_lrus() */ +#include #include @@ -133,6 +133,28 @@ static struct page *brd_insert_page(struct brd_device *brd, sector_t sector) return page; } +static void brd_free_page(struct brd_device *brd, sector_t sector) +{ + struct page *page; + pgoff_t idx; + + spin_lock(&brd->brd_lock); + idx = sector >> PAGE_SECTORS_SHIFT; + page = radix_tree_delete(&brd->brd_pages, idx); + spin_unlock(&brd->brd_lock); + if (page) + __free_page(page); +} + +static void brd_zero_page(struct brd_device *brd, sector_t sector) +{ + struct page *page; + + page = brd_lookup_page(brd, sector); + if (page) + clear_highpage(page); +} + /* * Free all backing store pages and radix tree. This must only be called when * there are no other users of the device. @@ -189,6 +211,24 @@ static int copy_to_brd_setup(struct brd_device *brd, sector_t sector, size_t n) return 0; } +static void discard_from_brd(struct brd_device *brd, + sector_t sector, size_t n) +{ + while (n >= PAGE_SIZE) { + /* + * Don't want to actually discard pages here because + * re-allocating the pages can result in writeback + * deadlocks under heavy load. + */ + if (0) + brd_free_page(brd, sector); + else + brd_zero_page(brd, sector); + sector += PAGE_SIZE >> SECTOR_SHIFT; + n -= PAGE_SIZE; + } +} + /* * Copy n bytes from src to the brd starting at sector. Does not sleep. */ @@ -275,8 +315,10 @@ static int brd_do_bvec(struct brd_device *brd, struct page *page, if (rw == READ) { copy_from_brd(mem + off, brd, sector, len); flush_dcache_page(page); - } else + } else { + flush_dcache_page(page); copy_to_brd(brd, mem + off, sector, len); + } kunmap_atomic(mem, KM_USER0); out: @@ -298,6 +340,12 @@ static int brd_make_request(struct request_queue *q, struct bio *bio) get_capacity(bdev->bd_disk)) goto out; + if (unlikely(bio_rw_flagged(bio, BIO_RW_DISCARD))) { + err = 0; + discard_from_brd(brd, sector, bio->bi_size); + goto out; + } + rw = bio_rw(bio); if (rw == READA) rw = READ; @@ -318,7 +366,7 @@ out: } #ifdef CONFIG_BLK_DEV_XIP -static int brd_direct_access (struct block_device *bdev, sector_t sector, +static int brd_direct_access(struct block_device *bdev, sector_t sector, void **kaddr, unsigned long *pfn) { struct brd_device *brd = bdev->bd_disk->private_data; @@ -340,11 +388,10 @@ static int brd_direct_access (struct block_device *bdev, sector_t sector, } #endif -static int brd_ioctl(struct inode *inode, struct file *file, +static int brd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { int error; - struct block_device *bdev = inode->i_bdev; struct brd_device *brd = bdev->bd_disk->private_data; if (cmd != BLKFLSBUF) @@ -374,9 +421,9 @@ static int brd_ioctl(struct inode *inode, struct file *file, return error; } -static struct block_device_operations brd_fops = { +static const struct block_device_operations brd_fops = { .owner = THIS_MODULE, - .ioctl = brd_ioctl, + .locked_ioctl = brd_ioctl, #ifdef CONFIG_BLK_DEV_XIP .direct_access = brd_direct_access, #endif @@ -406,12 +453,7 @@ static int __init ramdisk_size(char *str) rd_size = simple_strtol(str, NULL, 0); return 1; } -static int __init ramdisk_size2(char *str) -{ - return ramdisk_size(str); -} -__setup("ramdisk=", ramdisk_size); -__setup("ramdisk_size=", ramdisk_size2); +__setup("ramdisk_size=", ramdisk_size); #endif /* @@ -437,9 +479,15 @@ static struct brd_device *brd_alloc(int i) if (!brd->brd_queue) goto out_free_dev; blk_queue_make_request(brd->brd_queue, brd_make_request); - blk_queue_max_sectors(brd->brd_queue, 1024); + blk_queue_ordered(brd->brd_queue, QUEUE_ORDERED_TAG, NULL); + blk_queue_max_hw_sectors(brd->brd_queue, 1024); blk_queue_bounce_limit(brd->brd_queue, BLK_BOUNCE_ANY); + brd->brd_queue->limits.discard_granularity = PAGE_SIZE; + brd->brd_queue->limits.max_discard_sectors = UINT_MAX; + brd->brd_queue->limits.discard_zeroes_data = 1; + queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, brd->brd_queue); + disk = brd->brd_disk = alloc_disk(1 << part_shift); if (!disk) goto out_free_queue; @@ -571,8 +619,8 @@ out_free: list_del(&brd->brd_list); brd_free(brd); } + unregister_blkdev(RAMDISK_MAJOR, "ramdisk"); - unregister_blkdev(RAMDISK_MAJOR, "brd"); return -ENOMEM; }