diff options
| -rw-r--r-- | drivers/block/Kconfig | 4 | ||||
| -rw-r--r-- | drivers/block/pktcdvd.c | 53 | ||||
| -rw-r--r-- | include/linux/pktcdvd.h | 4 | 
3 files changed, 32 insertions, 29 deletions
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index db6818fdf15..8b133167740 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -433,8 +433,8 @@ config CDROM_PKTCDVD_BUFFERS  	  This controls the maximum number of active concurrent packets. More  	  concurrent packets can increase write performance, but also require  	  more memory. Each concurrent packet will require approximately 64Kb -	  of non-swappable kernel memory, memory which will be allocated at -	  pktsetup time. +	  of non-swappable kernel memory, memory which will be allocated when +	  a disc is opened for writing.  config CDROM_PKTCDVD_WCACHE  	bool "Enable write caching (EXPERIMENTAL)" diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index cd16813effc..4e7dbcc425f 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -129,7 +129,7 @@ static struct bio *pkt_bio_alloc(int nr_iovecs)  /*   * Allocate a packet_data struct   */ -static struct packet_data *pkt_alloc_packet_data(void) +static struct packet_data *pkt_alloc_packet_data(int frames)  {  	int i;  	struct packet_data *pkt; @@ -138,11 +138,12 @@ static struct packet_data *pkt_alloc_packet_data(void)  	if (!pkt)  		goto no_pkt; -	pkt->w_bio = pkt_bio_alloc(PACKET_MAX_SIZE); +	pkt->frames = frames; +	pkt->w_bio = pkt_bio_alloc(frames);  	if (!pkt->w_bio)  		goto no_bio; -	for (i = 0; i < PAGES_PER_PACKET; i++) { +	for (i = 0; i < frames / FRAMES_PER_PAGE; i++) {  		pkt->pages[i] = alloc_page(GFP_KERNEL|__GFP_ZERO);  		if (!pkt->pages[i])  			goto no_page; @@ -150,7 +151,7 @@ static struct packet_data *pkt_alloc_packet_data(void)  	spin_lock_init(&pkt->lock); -	for (i = 0; i < PACKET_MAX_SIZE; i++) { +	for (i = 0; i < frames; i++) {  		struct bio *bio = pkt_bio_alloc(1);  		if (!bio)  			goto no_rd_bio; @@ -160,14 +161,14 @@ static struct packet_data *pkt_alloc_packet_data(void)  	return pkt;  no_rd_bio: -	for (i = 0; i < PACKET_MAX_SIZE; i++) { +	for (i = 0; i < frames; i++) {  		struct bio *bio = pkt->r_bios[i];  		if (bio)  			bio_put(bio);  	}  no_page: -	for (i = 0; i < PAGES_PER_PACKET; i++) +	for (i = 0; i < frames / FRAMES_PER_PAGE; i++)  		if (pkt->pages[i])  			__free_page(pkt->pages[i]);  	bio_put(pkt->w_bio); @@ -184,12 +185,12 @@ static void pkt_free_packet_data(struct packet_data *pkt)  {  	int i; -	for (i = 0; i < PACKET_MAX_SIZE; i++) { +	for (i = 0; i < pkt->frames; i++) {  		struct bio *bio = pkt->r_bios[i];  		if (bio)  			bio_put(bio);  	} -	for (i = 0; i < PAGES_PER_PACKET; i++) +	for (i = 0; i < pkt->frames / FRAMES_PER_PAGE; i++)  		__free_page(pkt->pages[i]);  	bio_put(pkt->w_bio);  	kfree(pkt); @@ -204,17 +205,17 @@ static void pkt_shrink_pktlist(struct pktcdvd_device *pd)  	list_for_each_entry_safe(pkt, next, &pd->cdrw.pkt_free_list, list) {  		pkt_free_packet_data(pkt);  	} +	INIT_LIST_HEAD(&pd->cdrw.pkt_free_list);  }  static int pkt_grow_pktlist(struct pktcdvd_device *pd, int nr_packets)  {  	struct packet_data *pkt; -	INIT_LIST_HEAD(&pd->cdrw.pkt_free_list); -	INIT_LIST_HEAD(&pd->cdrw.pkt_active_list); -	spin_lock_init(&pd->cdrw.active_list_lock); +	BUG_ON(!list_empty(&pd->cdrw.pkt_free_list)); +  	while (nr_packets > 0) { -		pkt = pkt_alloc_packet_data(); +		pkt = pkt_alloc_packet_data(pd->settings.size >> 2);  		if (!pkt) {  			pkt_shrink_pktlist(pd);  			return 0; @@ -949,7 +950,7 @@ try_next_bio:  	pd->current_sector = zone + pd->settings.size;  	pkt->sector = zone; -	pkt->frames = pd->settings.size >> 2; +	BUG_ON(pkt->frames != pd->settings.size >> 2);  	pkt->write_size = 0;  	/* @@ -1985,8 +1986,14 @@ static int pkt_open_dev(struct pktcdvd_device *pd, int write)  	if ((ret = pkt_set_segment_merging(pd, q)))  		goto out_unclaim; -	if (write) +	if (write) { +		if (!pkt_grow_pktlist(pd, CONFIG_CDROM_PKTCDVD_BUFFERS)) { +			printk("pktcdvd: not enough memory for buffers\n"); +			ret = -ENOMEM; +			goto out_unclaim; +		}  		printk("pktcdvd: %lukB available on disc\n", lba << 1); +	}  	return 0; @@ -2012,6 +2019,8 @@ static void pkt_release_dev(struct pktcdvd_device *pd, int flush)  	pkt_set_speed(pd, MAX_SPEED, MAX_SPEED);  	bd_release(pd->bdev);  	blkdev_put(pd->bdev); + +	pkt_shrink_pktlist(pd);  }  static struct pktcdvd_device *pkt_find_dev_from_minor(int dev_minor) @@ -2377,12 +2386,6 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)  	/* This is safe, since we have a reference from open(). */  	__module_get(THIS_MODULE); -	if (!pkt_grow_pktlist(pd, CONFIG_CDROM_PKTCDVD_BUFFERS)) { -		printk("pktcdvd: not enough memory for buffers\n"); -		ret = -ENOMEM; -		goto out_mem; -	} -  	pd->bdev = bdev;  	set_blocksize(bdev, CD_FRAMESIZE); @@ -2393,7 +2396,7 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)  	if (IS_ERR(pd->cdrw.thread)) {  		printk("pktcdvd: can't start kernel thread\n");  		ret = -ENOMEM; -		goto out_thread; +		goto out_mem;  	}  	proc = create_proc_entry(pd->name, 0, pkt_proc); @@ -2404,8 +2407,6 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)  	DPRINTK("pktcdvd: writer %s mapped to %s\n", pd->name, bdevname(bdev, b));  	return 0; -out_thread: -	pkt_shrink_pktlist(pd);  out_mem:  	blkdev_put(bdev);  	/* This is safe: open() is still holding a reference. */ @@ -2501,6 +2502,10 @@ static int pkt_setup_dev(struct pkt_ctrl_command *ctrl_cmd)  		goto out_mem;  	pd->disk = disk; +	INIT_LIST_HEAD(&pd->cdrw.pkt_free_list); +	INIT_LIST_HEAD(&pd->cdrw.pkt_active_list); +	spin_lock_init(&pd->cdrw.active_list_lock); +  	spin_lock_init(&pd->lock);  	spin_lock_init(&pd->iosched.lock);  	sprintf(pd->name, "pktcdvd%d", idx); @@ -2565,8 +2570,6 @@ static int pkt_remove_dev(struct pkt_ctrl_command *ctrl_cmd)  	blkdev_put(pd->bdev); -	pkt_shrink_pktlist(pd); -  	remove_proc_entry(pd->name, pkt_proc);  	DPRINTK("pktcdvd: writer %s unmapped\n", pd->name); diff --git a/include/linux/pktcdvd.h b/include/linux/pktcdvd.h index d1c9c4a86e5..1623da88d6f 100644 --- a/include/linux/pktcdvd.h +++ b/include/linux/pktcdvd.h @@ -170,7 +170,7 @@ struct packet_iosched  #error "PAGE_SIZE must be a multiple of CD_FRAMESIZE"  #endif  #define PACKET_MAX_SIZE		32 -#define PAGES_PER_PACKET	(PACKET_MAX_SIZE * CD_FRAMESIZE / PAGE_SIZE) +#define FRAMES_PER_PAGE		(PAGE_SIZE / CD_FRAMESIZE)  #define PACKET_MAX_SECTORS	(PACKET_MAX_SIZE * CD_FRAMESIZE >> 9)  enum packet_data_state { @@ -219,7 +219,7 @@ struct packet_data  	atomic_t		io_errors;	/* Number of read/write errors during IO */  	struct bio		*r_bios[PACKET_MAX_SIZE]; /* bios to use during data gathering */ -	struct page		*pages[PAGES_PER_PACKET]; +	struct page		*pages[PACKET_MAX_SIZE / FRAMES_PER_PAGE];  	int			cache_valid;	/* If non-zero, the data for the zone defined */  						/* by the sector variable is completely cached */  |