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 db6818fdf15d..8b1331677407 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig | |||
@@ -433,8 +433,8 @@ config CDROM_PKTCDVD_BUFFERS | |||
433 | This controls the maximum number of active concurrent packets. More | 433 | This controls the maximum number of active concurrent packets. More |
434 | concurrent packets can increase write performance, but also require | 434 | concurrent packets can increase write performance, but also require |
435 | more memory. Each concurrent packet will require approximately 64Kb | 435 | more memory. Each concurrent packet will require approximately 64Kb |
436 | of non-swappable kernel memory, memory which will be allocated at | 436 | of non-swappable kernel memory, memory which will be allocated when |
437 | pktsetup time. | 437 | a disc is opened for writing. |
438 | 438 | ||
439 | config CDROM_PKTCDVD_WCACHE | 439 | config CDROM_PKTCDVD_WCACHE |
440 | bool "Enable write caching (EXPERIMENTAL)" | 440 | bool "Enable write caching (EXPERIMENTAL)" |
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index cd16813effc5..4e7dbcc425ff 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c | |||
@@ -129,7 +129,7 @@ static struct bio *pkt_bio_alloc(int nr_iovecs) | |||
129 | /* | 129 | /* |
130 | * Allocate a packet_data struct | 130 | * Allocate a packet_data struct |
131 | */ | 131 | */ |
132 | static struct packet_data *pkt_alloc_packet_data(void) | 132 | static struct packet_data *pkt_alloc_packet_data(int frames) |
133 | { | 133 | { |
134 | int i; | 134 | int i; |
135 | struct packet_data *pkt; | 135 | struct packet_data *pkt; |
@@ -138,11 +138,12 @@ static struct packet_data *pkt_alloc_packet_data(void) | |||
138 | if (!pkt) | 138 | if (!pkt) |
139 | goto no_pkt; | 139 | goto no_pkt; |
140 | 140 | ||
141 | pkt->w_bio = pkt_bio_alloc(PACKET_MAX_SIZE); | 141 | pkt->frames = frames; |
142 | pkt->w_bio = pkt_bio_alloc(frames); | ||
142 | if (!pkt->w_bio) | 143 | if (!pkt->w_bio) |
143 | goto no_bio; | 144 | goto no_bio; |
144 | 145 | ||
145 | for (i = 0; i < PAGES_PER_PACKET; i++) { | 146 | for (i = 0; i < frames / FRAMES_PER_PAGE; i++) { |
146 | pkt->pages[i] = alloc_page(GFP_KERNEL|__GFP_ZERO); | 147 | pkt->pages[i] = alloc_page(GFP_KERNEL|__GFP_ZERO); |
147 | if (!pkt->pages[i]) | 148 | if (!pkt->pages[i]) |
148 | goto no_page; | 149 | goto no_page; |
@@ -150,7 +151,7 @@ static struct packet_data *pkt_alloc_packet_data(void) | |||
150 | 151 | ||
151 | spin_lock_init(&pkt->lock); | 152 | spin_lock_init(&pkt->lock); |
152 | 153 | ||
153 | for (i = 0; i < PACKET_MAX_SIZE; i++) { | 154 | for (i = 0; i < frames; i++) { |
154 | struct bio *bio = pkt_bio_alloc(1); | 155 | struct bio *bio = pkt_bio_alloc(1); |
155 | if (!bio) | 156 | if (!bio) |
156 | goto no_rd_bio; | 157 | goto no_rd_bio; |
@@ -160,14 +161,14 @@ static struct packet_data *pkt_alloc_packet_data(void) | |||
160 | return pkt; | 161 | return pkt; |
161 | 162 | ||
162 | no_rd_bio: | 163 | no_rd_bio: |
163 | for (i = 0; i < PACKET_MAX_SIZE; i++) { | 164 | for (i = 0; i < frames; i++) { |
164 | struct bio *bio = pkt->r_bios[i]; | 165 | struct bio *bio = pkt->r_bios[i]; |
165 | if (bio) | 166 | if (bio) |
166 | bio_put(bio); | 167 | bio_put(bio); |
167 | } | 168 | } |
168 | 169 | ||
169 | no_page: | 170 | no_page: |
170 | for (i = 0; i < PAGES_PER_PACKET; i++) | 171 | for (i = 0; i < frames / FRAMES_PER_PAGE; i++) |
171 | if (pkt->pages[i]) | 172 | if (pkt->pages[i]) |
172 | __free_page(pkt->pages[i]); | 173 | __free_page(pkt->pages[i]); |
173 | bio_put(pkt->w_bio); | 174 | bio_put(pkt->w_bio); |
@@ -184,12 +185,12 @@ static void pkt_free_packet_data(struct packet_data *pkt) | |||
184 | { | 185 | { |
185 | int i; | 186 | int i; |
186 | 187 | ||
187 | for (i = 0; i < PACKET_MAX_SIZE; i++) { | 188 | for (i = 0; i < pkt->frames; i++) { |
188 | struct bio *bio = pkt->r_bios[i]; | 189 | struct bio *bio = pkt->r_bios[i]; |
189 | if (bio) | 190 | if (bio) |
190 | bio_put(bio); | 191 | bio_put(bio); |
191 | } | 192 | } |
192 | for (i = 0; i < PAGES_PER_PACKET; i++) | 193 | for (i = 0; i < pkt->frames / FRAMES_PER_PAGE; i++) |
193 | __free_page(pkt->pages[i]); | 194 | __free_page(pkt->pages[i]); |
194 | bio_put(pkt->w_bio); | 195 | bio_put(pkt->w_bio); |
195 | kfree(pkt); | 196 | kfree(pkt); |
@@ -204,17 +205,17 @@ static void pkt_shrink_pktlist(struct pktcdvd_device *pd) | |||
204 | list_for_each_entry_safe(pkt, next, &pd->cdrw.pkt_free_list, list) { | 205 | list_for_each_entry_safe(pkt, next, &pd->cdrw.pkt_free_list, list) { |
205 | pkt_free_packet_data(pkt); | 206 | pkt_free_packet_data(pkt); |
206 | } | 207 | } |
208 | INIT_LIST_HEAD(&pd->cdrw.pkt_free_list); | ||
207 | } | 209 | } |
208 | 210 | ||
209 | static int pkt_grow_pktlist(struct pktcdvd_device *pd, int nr_packets) | 211 | static int pkt_grow_pktlist(struct pktcdvd_device *pd, int nr_packets) |
210 | { | 212 | { |
211 | struct packet_data *pkt; | 213 | struct packet_data *pkt; |
212 | 214 | ||
213 | INIT_LIST_HEAD(&pd->cdrw.pkt_free_list); | 215 | BUG_ON(!list_empty(&pd->cdrw.pkt_free_list)); |
214 | INIT_LIST_HEAD(&pd->cdrw.pkt_active_list); | 216 | |
215 | spin_lock_init(&pd->cdrw.active_list_lock); | ||
216 | while (nr_packets > 0) { | 217 | while (nr_packets > 0) { |
217 | pkt = pkt_alloc_packet_data(); | 218 | pkt = pkt_alloc_packet_data(pd->settings.size >> 2); |
218 | if (!pkt) { | 219 | if (!pkt) { |
219 | pkt_shrink_pktlist(pd); | 220 | pkt_shrink_pktlist(pd); |
220 | return 0; | 221 | return 0; |
@@ -949,7 +950,7 @@ try_next_bio: | |||
949 | 950 | ||
950 | pd->current_sector = zone + pd->settings.size; | 951 | pd->current_sector = zone + pd->settings.size; |
951 | pkt->sector = zone; | 952 | pkt->sector = zone; |
952 | pkt->frames = pd->settings.size >> 2; | 953 | BUG_ON(pkt->frames != pd->settings.size >> 2); |
953 | pkt->write_size = 0; | 954 | pkt->write_size = 0; |
954 | 955 | ||
955 | /* | 956 | /* |
@@ -1985,8 +1986,14 @@ static int pkt_open_dev(struct pktcdvd_device *pd, int write) | |||
1985 | if ((ret = pkt_set_segment_merging(pd, q))) | 1986 | if ((ret = pkt_set_segment_merging(pd, q))) |
1986 | goto out_unclaim; | 1987 | goto out_unclaim; |
1987 | 1988 | ||
1988 | if (write) | 1989 | if (write) { |
1990 | if (!pkt_grow_pktlist(pd, CONFIG_CDROM_PKTCDVD_BUFFERS)) { | ||
1991 | printk("pktcdvd: not enough memory for buffers\n"); | ||
1992 | ret = -ENOMEM; | ||
1993 | goto out_unclaim; | ||
1994 | } | ||
1989 | printk("pktcdvd: %lukB available on disc\n", lba << 1); | 1995 | printk("pktcdvd: %lukB available on disc\n", lba << 1); |
1996 | } | ||
1990 | 1997 | ||
1991 | return 0; | 1998 | return 0; |
1992 | 1999 | ||
@@ -2012,6 +2019,8 @@ static void pkt_release_dev(struct pktcdvd_device *pd, int flush) | |||
2012 | pkt_set_speed(pd, MAX_SPEED, MAX_SPEED); | 2019 | pkt_set_speed(pd, MAX_SPEED, MAX_SPEED); |
2013 | bd_release(pd->bdev); | 2020 | bd_release(pd->bdev); |
2014 | blkdev_put(pd->bdev); | 2021 | blkdev_put(pd->bdev); |
2022 | |||
2023 | pkt_shrink_pktlist(pd); | ||
2015 | } | 2024 | } |
2016 | 2025 | ||
2017 | static struct pktcdvd_device *pkt_find_dev_from_minor(int dev_minor) | 2026 | 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) | |||
2377 | /* This is safe, since we have a reference from open(). */ | 2386 | /* This is safe, since we have a reference from open(). */ |
2378 | __module_get(THIS_MODULE); | 2387 | __module_get(THIS_MODULE); |
2379 | 2388 | ||
2380 | if (!pkt_grow_pktlist(pd, CONFIG_CDROM_PKTCDVD_BUFFERS)) { | ||
2381 | printk("pktcdvd: not enough memory for buffers\n"); | ||
2382 | ret = -ENOMEM; | ||
2383 | goto out_mem; | ||
2384 | } | ||
2385 | |||
2386 | pd->bdev = bdev; | 2389 | pd->bdev = bdev; |
2387 | set_blocksize(bdev, CD_FRAMESIZE); | 2390 | set_blocksize(bdev, CD_FRAMESIZE); |
2388 | 2391 | ||
@@ -2393,7 +2396,7 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev) | |||
2393 | if (IS_ERR(pd->cdrw.thread)) { | 2396 | if (IS_ERR(pd->cdrw.thread)) { |
2394 | printk("pktcdvd: can't start kernel thread\n"); | 2397 | printk("pktcdvd: can't start kernel thread\n"); |
2395 | ret = -ENOMEM; | 2398 | ret = -ENOMEM; |
2396 | goto out_thread; | 2399 | goto out_mem; |
2397 | } | 2400 | } |
2398 | 2401 | ||
2399 | proc = create_proc_entry(pd->name, 0, pkt_proc); | 2402 | 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) | |||
2404 | DPRINTK("pktcdvd: writer %s mapped to %s\n", pd->name, bdevname(bdev, b)); | 2407 | DPRINTK("pktcdvd: writer %s mapped to %s\n", pd->name, bdevname(bdev, b)); |
2405 | return 0; | 2408 | return 0; |
2406 | 2409 | ||
2407 | out_thread: | ||
2408 | pkt_shrink_pktlist(pd); | ||
2409 | out_mem: | 2410 | out_mem: |
2410 | blkdev_put(bdev); | 2411 | blkdev_put(bdev); |
2411 | /* This is safe: open() is still holding a reference. */ | 2412 | /* This is safe: open() is still holding a reference. */ |
@@ -2501,6 +2502,10 @@ static int pkt_setup_dev(struct pkt_ctrl_command *ctrl_cmd) | |||
2501 | goto out_mem; | 2502 | goto out_mem; |
2502 | pd->disk = disk; | 2503 | pd->disk = disk; |
2503 | 2504 | ||
2505 | INIT_LIST_HEAD(&pd->cdrw.pkt_free_list); | ||
2506 | INIT_LIST_HEAD(&pd->cdrw.pkt_active_list); | ||
2507 | spin_lock_init(&pd->cdrw.active_list_lock); | ||
2508 | |||
2504 | spin_lock_init(&pd->lock); | 2509 | spin_lock_init(&pd->lock); |
2505 | spin_lock_init(&pd->iosched.lock); | 2510 | spin_lock_init(&pd->iosched.lock); |
2506 | sprintf(pd->name, "pktcdvd%d", idx); | 2511 | sprintf(pd->name, "pktcdvd%d", idx); |
@@ -2565,8 +2570,6 @@ static int pkt_remove_dev(struct pkt_ctrl_command *ctrl_cmd) | |||
2565 | 2570 | ||
2566 | blkdev_put(pd->bdev); | 2571 | blkdev_put(pd->bdev); |
2567 | 2572 | ||
2568 | pkt_shrink_pktlist(pd); | ||
2569 | |||
2570 | remove_proc_entry(pd->name, pkt_proc); | 2573 | remove_proc_entry(pd->name, pkt_proc); |
2571 | DPRINTK("pktcdvd: writer %s unmapped\n", pd->name); | 2574 | DPRINTK("pktcdvd: writer %s unmapped\n", pd->name); |
2572 | 2575 | ||
diff --git a/include/linux/pktcdvd.h b/include/linux/pktcdvd.h index d1c9c4a86e52..1623da88d6fe 100644 --- a/include/linux/pktcdvd.h +++ b/include/linux/pktcdvd.h | |||
@@ -170,7 +170,7 @@ struct packet_iosched | |||
170 | #error "PAGE_SIZE must be a multiple of CD_FRAMESIZE" | 170 | #error "PAGE_SIZE must be a multiple of CD_FRAMESIZE" |
171 | #endif | 171 | #endif |
172 | #define PACKET_MAX_SIZE 32 | 172 | #define PACKET_MAX_SIZE 32 |
173 | #define PAGES_PER_PACKET (PACKET_MAX_SIZE * CD_FRAMESIZE / PAGE_SIZE) | 173 | #define FRAMES_PER_PAGE (PAGE_SIZE / CD_FRAMESIZE) |
174 | #define PACKET_MAX_SECTORS (PACKET_MAX_SIZE * CD_FRAMESIZE >> 9) | 174 | #define PACKET_MAX_SECTORS (PACKET_MAX_SIZE * CD_FRAMESIZE >> 9) |
175 | 175 | ||
176 | enum packet_data_state { | 176 | enum packet_data_state { |
@@ -219,7 +219,7 @@ struct packet_data | |||
219 | atomic_t io_errors; /* Number of read/write errors during IO */ | 219 | atomic_t io_errors; /* Number of read/write errors during IO */ |
220 | 220 | ||
221 | struct bio *r_bios[PACKET_MAX_SIZE]; /* bios to use during data gathering */ | 221 | struct bio *r_bios[PACKET_MAX_SIZE]; /* bios to use during data gathering */ |
222 | struct page *pages[PAGES_PER_PACKET]; | 222 | struct page *pages[PACKET_MAX_SIZE / FRAMES_PER_PAGE]; |
223 | 223 | ||
224 | int cache_valid; /* If non-zero, the data for the zone defined */ | 224 | int cache_valid; /* If non-zero, the data for the zone defined */ |
225 | /* by the sector variable is completely cached */ | 225 | /* by the sector variable is completely cached */ |