Submitted By: BLFS BOOK Date: 2003-10-09 Initial Package Version: 2.4.22 Origin: http://w1.894.telia.com/~u89404340/patches/packet/2.4/packet-2.4.20.patch.bz2 Description: Allow packet writing for CDROMs. diff -u -r -N ../../linus/2.4/linux/Documentation/Configure.help linux/Documentation/Configure.help --- ../../linus/2.4/linux/Documentation/Configure.help 2003-08-23 21:25:25.000000000 +0200 +++ linux/Documentation/Configure.help 2003-08-23 22:25:44.000000000 +0200 @@ -750,6 +750,27 @@ say M here and read . The module will be called ide-cd.o. + +Packet writing on CD/DVD media (EXPERIMENTAL) +CONFIG_CDROM_PKTCDVD + If you have a CDROM drive that supports packet writing, say Y to + include preliminary support. It should work with any MMC/Mt Fuji + compliant ATAPI or SCSI drive, which is just about any newer CD + writer. + + Currently only writing to CD-RW discs is possible. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called pktcdvd.o + +Write caching +CONFIG_CDROM_PKTCDVD_WCACHE + If enabled, write caching will be set for the CD-R/W device. For now + this option is dangerous unless the CD-RW media is known good, as we + don't do deferred write error handling yet. + Include IDE/ATAPI TAPE support CONFIG_BLK_DEV_IDETAPE If you have an IDE tape drive using the ATAPI protocol, say Y. diff -u -r -N ../../linus/2.4/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c --- ../../linus/2.4/linux/arch/sparc64/kernel/ioctl32.c 2003-08-03 23:21:54.000000000 +0200 +++ linux/arch/sparc64/kernel/ioctl32.c 2003-08-03 23:30:02.000000000 +0200 @@ -92,6 +92,7 @@ #include #include #include +#include #include #include @@ -819,6 +820,41 @@ return ret; } +struct packet_stats32 { + u32 bh_s; + u32 bh_e; + u32 bh_cache_hits; + u32 page_cache_hits; + u32 bh_w; + u32 bh_r; +}; + +static inline int pkt_getstats(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct packet_stats p; + struct packet_stats32 p32; + mm_segment_t old_fs = get_fs(); + int ret; + + ret = copy_from_user (&p32, (struct packet_stats32 *)arg, sizeof(struct packet_stats32)); + if (ret) + return -EFAULT; +#define P(x) (p.x = (unsigned long)p32.x) + P(bh_s); + P(bh_e); + P(bh_cache_hits); + P(page_cache_hits); + P(bh_w); + P(bh_r); +#undef P + + set_fs (KERNEL_DS); + ret = sys_ioctl (fd, cmd, (long)&p); + set_fs (old_fs); + + return ret; +} + struct hd_geometry32 { unsigned char heads; unsigned char sectors; @@ -5012,6 +5048,12 @@ COMPATIBLE_IOCTL(RNDADDENTROPY) COMPATIBLE_IOCTL(RNDZAPENTCNT) COMPATIBLE_IOCTL(RNDCLEARPOOL) +/* Big X, CDRW Packet Driver */ +#if defined(CONFIG_CDROM_PKTCDVD) +COMPATIBLE_IOCTL(PACKET_SETUP_DEV) +COMPATIBLE_IOCTL(PACKET_TEARDOWN_DEV) +HANDLE_IOCTL(PACKET_GET_STATS, pkt_getstats) +#endif /* CONFIG_CDROM_PKTCDVD */ /* Bluetooth ioctls */ COMPATIBLE_IOCTL(HCIDEVUP) COMPATIBLE_IOCTL(HCIDEVDOWN) diff -u -r -N ../../linus/2.4/linux/drivers/block/Config.in linux/drivers/block/Config.in --- ../../linus/2.4/linux/drivers/block/Config.in 2003-08-03 23:22:00.000000000 +0200 +++ linux/drivers/block/Config.in 2003-08-03 23:30:13.000000000 +0200 @@ -39,6 +39,11 @@ dep_tristate 'Mylex DAC960/DAC1100 PCI RAID Controller support' CONFIG_BLK_DEV_DAC960 $CONFIG_PCI dep_tristate 'Micro Memory MM5415 Battery Backed RAM support (EXPERIMENTAL)' CONFIG_BLK_DEV_UMEM $CONFIG_PCI $CONFIG_EXPERIMENTAL +tristate 'Packet writing on CD/DVD media' CONFIG_CDROM_PKTCDVD +if [ "$CONFIG_CDROM_PKTCDVD" != "n" ]; then + bool ' Enable write caching' CONFIG_CDROM_PKTCDVD_WCACHE n +fi + tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET diff -u -r -N ../../linus/2.4/linux/drivers/block/Makefile linux/drivers/block/Makefile --- ../../linus/2.4/linux/drivers/block/Makefile 2003-08-03 23:22:00.000000000 +0200 +++ linux/drivers/block/Makefile 2003-08-03 23:30:13.000000000 +0200 @@ -10,7 +10,7 @@ O_TARGET := block.o -export-objs := ll_rw_blk.o blkpg.o loop.o DAC960.o genhd.o acsi.o +export-objs := ll_rw_blk.o blkpg.o loop.o DAC960.o genhd.o acsi.o elevator.o obj-y := ll_rw_blk.o blkpg.o genhd.o elevator.o @@ -31,6 +31,7 @@ obj-$(CONFIG_BLK_DEV_DAC960) += DAC960.o obj-$(CONFIG_BLK_DEV_UMEM) += umem.o obj-$(CONFIG_BLK_DEV_NBD) += nbd.o +obj-$(CONFIG_CDROM_PKTCDVD) += pktcdvd.o subdir-$(CONFIG_PARIDE) += paride diff -u -r -N ../../linus/2.4/linux/drivers/block/elevator.c linux/drivers/block/elevator.c --- ../../linus/2.4/linux/drivers/block/elevator.c 2003-08-03 23:22:00.000000000 +0200 +++ linux/drivers/block/elevator.c 2003-08-03 23:30:14.000000000 +0200 @@ -219,3 +219,5 @@ *elevator = type; elevator->queue_ID = queue_ID++; } + +EXPORT_SYMBOL(elevator_init); diff -u -r -N ../../linus/2.4/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- ../../linus/2.4/linux/drivers/block/ll_rw_blk.c 2003-08-03 23:22:00.000000000 +0200 +++ linux/drivers/block/ll_rw_blk.c 2003-08-23 22:25:48.000000000 +0200 @@ -1210,6 +1210,7 @@ /* Test device size, when known. */ if (blk_size[major]) minorsize = blk_size[major][MINOR(bh->b_rdev)]; +#if 0 if (minorsize) { unsigned long maxsector = (minorsize << 1) + 1; unsigned long sector = bh->b_rsector; @@ -1232,6 +1233,7 @@ return; } } +#endif /* * Resolve the mapping until finished. (drivers are @@ -1440,8 +1442,8 @@ req->errors = 0; if (!uptodate) - printk("end_request: I/O error, dev %s (%s), sector %lu\n", - kdevname(req->rq_dev), name, req->sector); + printk("end_request: I/O error, cmd %d dev %s (%s), sector %lu\n", + req->cmd, kdevname(req->rq_dev), name, req->sector); if ((bh = req->bh) != NULL) { nsect = bh->b_size >> 9; diff -u -r -N ../../linus/2.4/linux/drivers/block/pktcdvd.c linux/drivers/block/pktcdvd.c --- ../../linus/2.4/linux/drivers/block/pktcdvd.c 1970-01-01 01:00:00.000000000 +0100 +++ linux/drivers/block/pktcdvd.c 2003-08-03 23:30:14.000000000 +0200 @@ -0,0 +1,2679 @@ +/* + * Copyright (C) 2000 Jens Axboe + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * Packet writing layer for ATAPI and SCSI CD-R, CD-RW, DVD-R, and + * DVD-RW devices (aka an exercise in block layer masturbation) + * + * + * TODO: (circa order of when I will fix it) + * - Only able to write on CD-RW media right now. + * - check host application code on media and set it in write page + * - Generic interface for UDF to submit large packets for variable length + * packet writing + * - interface for UDF <-> packet to negotiate a new location when a write + * fails. + * - handle OPC, especially for -RW media + * + * ------------------------------------------------------------------------ + * + * Newer changes -- see ChangeLog + * + * 0.0.2d (26/10/2000) + * - (scsi) use implicit segment recounting for all hba's + * - fix speed setting, was consistenly off on most drives + * - only print capacity when opening for write + * - fix off-by-two error in getting/setting write+read speed (affected + * reporting as well as actual speed used) + * - possible to enable write caching on drive + * - do ioctl marshalling on sparc64 from Ben Collins + * - avoid unaligned access on flags, should have been unsigned long of course + * - fixed missed wakeup in kpacketd + * - b_dev error (two places) + * - fix buffer head b_count bugs + * - fix hole merge bug, where tail could be added twice + * - fsync and invalidate buffers on close + * - check hash table for buffers first before using our own + * - add read-ahead + * - fixed several list races + * - fix proc reporting for more than one device + * - change to O_CREAT for creating devices + * - added media_change hook + * - added free buffers config option + * - pkt_lock_tray fails on failed open (and oopses), remove it. unlock + * is done explicitly in pkt_remove dev anyway. + * - added proper elevator insertion (should probably be part of elevator.c) + * - moved kernel thread info to private device, spawn one for each writer + * - added separate buffer list for dirty packet buffers + * - fixed nasty data corruption bug + * - remember to account request even when we don't gather data for it + * - add ioctl to force wakeup of kernel thread (for debug) + * - fixed packet size setting bug on zero detected + * - changed a lot of the proc reporting to be more readable to "humans" + * - set full speed for read-only opens + * + * 0.0.2c (08/09/2000) + * - inc usage count of buffer heads + * - add internal buffer pool to avoid deadlock on oom + * - gather data for as many buffers as we have, before initiating write. this + * allows the laser to stay on longer, giving better performance. + * - fix always busy when tray can't be locked + * - remove request duplication nastiness, inject directly into the target + * - adapted to devfs and elevator changes + * - added proc interface + * + * 0.0.2b (21/06/2000) + * - fix io_request_lock typos (missing '&') + * - grab pkt_sem before invoking pkt_handle_queue + * - SCSI uses queuedata too, mirror that in pd->queuedata (hack) + * - remove SCSI sr debug messages + * - really activate empty block querying (requires cvs UDF, CDRW branch) + * - make sure sync_buffers doesn't consider us, or we can deadlock + * - make sure people don't swap on us (for now ;) + * + * 0.0.2a (19/06/2000) + * - add kpacketd kernel thread to handle actual data gathering + * - pd->pkt_dev is now real device, not just minor + * - add support for super_operations block_empty fn, to query fs for + * unused blocks that don't need reading + * - "cache" blocks that are contained in the UDF file/dir packet + * - rewrite pkt_gather_data to a one-step solution + * - add private pktcdvd elevator + * - shutdown write access to device upon write failure + * - fix off-by-one bug in capacity + * - setup sourceforge project (packet-cd.sourceforge.net) + * - add more blk ioctls to pkt_ioctl + * - set inactive request queue head + * - change panic calls to BUG, better with kdb + * - have pkt_gather_data check correct block size and kill rq if wrong + * - rework locking + * - introduce per-pd queues, simplifies pkt_request + * - store pd in queuedata + * + *************************************************************************/ + +#define VERSION_CODE "v0.0.2p 03/03/2002 Jens Axboe (axboe@suse.de)" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* + * remove for next version -- for now, disable the mention option in the + * SCSI section + */ +#if defined(CONFIG_SCSI_DEBUG_QUEUES) +#error "Don't compile with 'Enable extra checks in new queueing code' enabled" +#endif + +#define SCSI_IOCTL_SEND_COMMAND 1 + +/* + * 32 buffers of 2048 bytes + */ +#define PACKET_MAX_SIZE 32 + +#define NEXT_BH(bh, nbh) \ + (((bh)->b_rsector + ((bh)->b_size >> 9)) == (nbh)->b_rsector) + +#define BH_IN_ORDER(b1, b2) \ + ((b1)->b_rsector < (b2)->b_rsector) + +#define CONTIG_BH(b1, b2) \ + ((b1)->b_data + (b1)->b_size == (b2)->b_data) + +#define ZONE(sector, pd) \ + (((sector) + ((pd)->offset)) - (((sector) + ((pd)->offset)) & (((pd)->settings.size - 1)))) + +static int *pkt_sizes; +static int *pkt_blksize; +static int *pkt_readahead; +static struct pktcdvd_device *pkt_devs; +static struct proc_dir_entry *pkt_proc; +static DECLARE_WAIT_QUEUE_HEAD(pd_bh_wait); + +/* + * a bit of a kludge, but we want to be able to pass both real and packet + * dev and get the right one. + */ +static inline struct pktcdvd_device *pkt_find_dev(kdev_t dev) +{ + int i; + + for (i = 0; i < MAX_WRITERS; i++) + if (pkt_devs[i].dev == dev || pkt_devs[i].pkt_dev == dev) + return &pkt_devs[i]; + + return NULL; +} + +/* + * The following functions are the plugins to the ll_rw_blk + * layer and decides whether a given request / buffer head can be + * merged. We differ in a couple of ways from "normal" block + * devices: + * + * - don't merge when the buffer / request crosses a packet block + * boundary + * - merge buffer head even though it can't be added directly to the + * front or back of the list. this gives us better performance, since + * what would otherwise require multiple requests can now be handled + * in one (hole merging) + * - at this point its just writes, reads have already been remapped + * + * The device original merge_ functions are stored in the packet device + * queue (pd->q) + * + */ +static inline int pkt_do_merge(request_queue_t *q, struct request *rq, + struct buffer_head *bh, int max_segs, + merge_request_fn *merge_fn, + struct pktcdvd_device *pd) +{ + void *ptr = q->queuedata; + int ret; + + if (rq->cmd != WRITE) + BUG(); + + if (ZONE(rq->sector, pd) != ZONE(bh->b_rsector, pd)) + return ELEVATOR_NO_MERGE; + + /* + * NOTE: this is done under the io_request_lock/queue_lock, hence + * it is safe + */ + q->queuedata = pd->cdrw.queuedata; + ret = merge_fn(q, rq, bh, max_segs); + q->queuedata = ptr; + return ret; +} + +static int pkt_front_merge_fn(request_queue_t *q, struct request *rq, + struct buffer_head *bh, int max_segs) +{ + struct pktcdvd_device *pd = &pkt_devs[MINOR(bh->b_rdev)]; + + return pkt_do_merge(q, rq, bh, max_segs, pd->cdrw.front_merge_fn, pd); +} + +static int pkt_back_merge_fn(request_queue_t *q, struct request *rq, + struct buffer_head *bh, int max_segs) +{ + struct pktcdvd_device *pd = &pkt_devs[MINOR(bh->b_rdev)]; + + return pkt_do_merge(q, rq, bh, max_segs, pd->cdrw.back_merge_fn, pd); +} + +/* + * rules similar to above + */ +static int pkt_merge_requests_fn(request_queue_t *q, struct request *rq, + struct request *nxt, int max_segs) +{ + struct pktcdvd_device *pd = pkt_find_dev(rq->rq_dev); + struct packet_cdrw *cdrw = &pd->cdrw; + void *ptr = q->queuedata; + int ret; + + if (ZONE(rq->sector, pd) != ZONE(nxt->sector + nxt->nr_sectors - 1, pd)) + return 0; + + q->queuedata = cdrw->queuedata; + ret = cdrw->merge_requests_fn(q, rq, nxt, max_segs); + q->queuedata = ptr; + return ret; +} + +static int pkt_grow_bhlist(struct pktcdvd_device *pd, int count) +{ + struct packet_cdrw *cdrw = &pd->cdrw; + struct buffer_head *bh; + int i = 0; + + VPRINTK("grow_bhlist: count=%d\n", count); + + while (i < count) { + bh = kmem_cache_alloc(bh_cachep, SLAB_KERNEL); + if (!bh) + break; + + bh->b_data = kmalloc(CD_FRAMESIZE, GFP_KERNEL); + if (!bh->b_data) { + kmem_cache_free(bh_cachep, bh); + break; + } + bh->b_page = virt_to_page(bh->b_data); + + spin_lock_irq(&pd->lock); + bh->b_pprev = &cdrw->bhlist; + bh->b_next = cdrw->bhlist; + cdrw->bhlist = bh; + spin_unlock_irq(&pd->lock); + + bh->b_size = CD_FRAMESIZE; + bh->b_list = PKT_BUF_LIST; + atomic_inc(&cdrw->free_bh); + i++; + } + + return i; +} + +static int pkt_shrink_bhlist(struct pktcdvd_device *pd, int count) +{ + struct packet_cdrw *cdrw = &pd->cdrw; + struct buffer_head *bh; + int i = 0; + + VPRINTK("shrink_bhlist: count=%d\n", count); + + while ((i < count) && cdrw->bhlist) { + spin_lock_irq(&pd->lock); + bh = cdrw->bhlist; + cdrw->bhlist = bh->b_next; + spin_unlock_irq(&pd->lock); + if (bh->b_list != PKT_BUF_LIST) + BUG(); + kfree(bh->b_data); + kmem_cache_free(bh_cachep, bh); + atomic_dec(&cdrw->free_bh); + i++; + } + + return i; +} + +/* + * These functions manage a simple pool of buffer_heads. + */ +static struct buffer_head *pkt_get_stacked_bh(struct pktcdvd_device *pd) +{ + unsigned long flags; + struct buffer_head *bh; + + spin_lock_irqsave(&pd->lock, flags); + bh = pd->stacked_bhlist; + if (bh) { + pd->stacked_bhlist = bh->b_next; + bh->b_next = NULL; + pd->stacked_bhcnt--; + BUG_ON(pd->stacked_bhcnt < 0); + } + spin_unlock_irqrestore(&pd->lock, flags); + + return bh; +} + +static void pkt_put_stacked_bh(struct pktcdvd_device *pd, struct buffer_head *bh) +{ + unsigned long flags; + + spin_lock_irqsave(&pd->lock, flags); + if (pd->stacked_bhcnt < STACKED_BH_POOL_SIZE) { + bh->b_next = pd->stacked_bhlist; + pd->stacked_bhlist = bh; + pd->stacked_bhcnt++; + bh = NULL; + } + spin_unlock_irqrestore(&pd->lock, flags); + if (bh) { + kmem_cache_free(bh_cachep, bh); + } +} + +static void pkt_shrink_stacked_bhlist(struct pktcdvd_device *pd) +{ + struct buffer_head *bh; + + while ((bh = pkt_get_stacked_bh(pd)) != NULL) { + kmem_cache_free(bh_cachep, bh); + } +} + +static int pkt_grow_stacked_bhlist(struct pktcdvd_device *pd) +{ + struct buffer_head *bh; + int i; + + for (i = 0; i < STACKED_BH_POOL_SIZE; i++) { + bh = kmem_cache_alloc(bh_cachep, GFP_KERNEL); + if (!bh) { + pkt_shrink_stacked_bhlist(pd); + return 0; + } + pkt_put_stacked_bh(pd, bh); + } + return 1; +} + + +static request_queue_t *pkt_get_queue(kdev_t dev) +{ + struct pktcdvd_device *pd = pkt_find_dev(dev); + if (!pd) + return NULL; + return &pd->cdrw.r_queue; +} + +static void pkt_put_buffer(struct buffer_head *bh) +{ + struct pktcdvd_device *pd = &pkt_devs[MINOR(bh->b_dev)]; + unsigned long flags; + + if (bh->b_list != PKT_BUF_LIST) + return; + + bh->b_state = 0; + bh->b_reqnext = NULL; + bh->b_end_io = NULL; + + spin_lock_irqsave(&pd->lock, flags); + bh->b_next = pd->cdrw.bhlist; + pd->cdrw.bhlist = bh; + spin_unlock_irqrestore(&pd->lock, flags); + atomic_inc(&pd->cdrw.free_bh); +} + +static inline void __pkt_inject_request(request_queue_t *q, struct request *rq) +{ + struct list_head *head = &q->queue_head; + + VPRINTK("__pkt_inject_request: list_empty == %d, size=%d, cmd=%d\n", + list_empty(&q->queue_head), rq->bh->b_size >> 9, rq->cmd); + + if (list_empty(&q->queue_head)) + q->plug_device_fn(q, rq->rq_dev); + + list_add_tail(&rq->queue, head); +} + +static void pkt_inject_request(request_queue_t *q, struct request *rq) +{ + spin_lock_irq(&io_request_lock); + __pkt_inject_request(q, rq); + spin_unlock_irq(&io_request_lock); +} + +static inline void __pkt_end_request(struct pktcdvd_device *pd) +{ + pd->rq = NULL; + clear_bit(PACKET_RQ, &pd->flags); + clear_bit(PACKET_BUSY, &pd->flags); +} + +/* + * io_request_lock must be held and interrupts disabled + */ +static void pkt_end_request(struct pktcdvd_device *pd) +{ + unsigned long flags; + + spin_lock_irqsave(&pd->lock, flags); + __pkt_end_request(pd); + spin_unlock_irqrestore(&pd->lock, flags); +} + + +static inline void __pkt_kill_request(struct request *rq, int uptodate, char *name) +{ + struct buffer_head *bh = rq->bh, *nbh; + + while (bh) { + nbh = bh->b_reqnext; + bh->b_reqnext = NULL; + + if (bh->b_end_io) { + bh->b_end_io(bh, uptodate); + } else { + mark_buffer_clean(bh); + mark_buffer_uptodate(bh, uptodate); + unlock_buffer(bh); + } + + bh = nbh; + } + + end_that_request_last(rq); +} + + +void pkt_kill_request(struct pktcdvd_device *pd, struct request *rq, int ok) +{ + printk("pktcdvd: killing request\n"); + spin_lock_irq(&io_request_lock); + __pkt_kill_request(rq, ok, pd->name); + spin_unlock_irq(&io_request_lock); + pkt_end_request(pd); +} + +static void pkt_end_io_read(struct buffer_head *bh, int uptodate) +{ + if (!uptodate) { + /* Obviously not correct, but it avoids locking up the kernel */ + printk("Ignoring read error on sector:%ld\n", bh->b_rsector); + uptodate = 1; + } + + mark_buffer_uptodate(bh, uptodate); + unlock_buffer(bh); +} + +/* + * if the buffer is already in the buffer cache, grab it if we can lock + * it down + */ +static struct buffer_head *pkt_get_hash(kdev_t dev, unsigned long block, int size) +{ + struct buffer_head *bh = NULL; + + bh = get_hash_table(dev, block, size); + if (bh) { + if (!test_and_set_bit(BH_Lock, &bh->b_state)) { + brelse(bh); + if (atomic_set_buffer_clean(bh)) + refile_buffer(bh); + SetPageReferenced(bh->b_page); + } else { + brelse(bh); + bh = NULL; + } + } + + return bh; +} + +static inline struct buffer_head *__pkt_get_buffer(struct pktcdvd_device *pd, + unsigned long sector) +{ + struct buffer_head *bh; + + if (!atomic_read(&pd->cdrw.free_bh)) + BUG(); + + atomic_dec(&pd->cdrw.free_bh); + + spin_lock_irq(&pd->lock); + bh = pd->cdrw.bhlist; + pd->cdrw.bhlist = bh->b_next; + bh->b_next = NULL; + spin_unlock_irq(&pd->lock); + + bh->b_next_free = NULL; + bh->b_prev_free = NULL; + bh->b_this_page = NULL; + bh->b_pprev = NULL; + bh->b_reqnext = NULL; + + init_waitqueue_head(&bh->b_wait); + atomic_set(&bh->b_count, 1); + bh->b_list = PKT_BUF_LIST; + bh->b_state = (1 << BH_Mapped) | (1 << BH_Lock) | (1 << BH_Req); + bh->b_dev = pd->pkt_dev; + + return bh; +} + +static void pkt_end_io_write(struct buffer_head *, int); + +static struct buffer_head *pkt_get_buffer(struct pktcdvd_device *pd, + unsigned long sector, int size) +{ + unsigned long block = sector / (size >> 9); + struct buffer_head *bh; + + VPRINTK("get_buffer: sector=%ld, size=%d\n", sector, size); + + bh = pkt_get_hash(pd->pkt_dev, block, size); + if (bh) + pd->stats.bh_cache_hits += (size >> 9); + else + bh = __pkt_get_buffer(pd, sector); + + blk_started_io(bh->b_size >> 9); + bh->b_blocknr = block; + bh->b_end_io = pkt_end_io_write; + bh->b_rsector = sector; + bh->b_rdev = pd->dev; + return bh; +} + +/* + * this rq is done -- io_request_lock must be held and interrupts disabled + */ +static void pkt_rq_end_io(struct pktcdvd_device *pd) +{ + unsigned long flags; + + VPRINTK("pkt_rq_end_io: rq=%p, cmd=%d, q=%p\n", pd->rq, pd->rq->cmd, pd->rq->q); + + spin_lock_irqsave(&pd->lock, flags); + + /* + * debug checks + */ + if (!test_bit(PACKET_RQ, &pd->flags)) + printk("pktcdvd: rq_end_io: RQ not set\n"); + if (!test_bit(PACKET_BUSY, &pd->flags)) + printk("pktcdvd: rq_end_io: BUSY not set\n"); + + __pkt_end_request(pd); + wake_up(&pd->wqueue); + spin_unlock_irqrestore(&pd->lock, flags); +} + +static inline void pkt_mark_readonly(struct pktcdvd_device *pd, int on) +{ + if (on) + set_bit(PACKET_READONLY, &pd->flags); + else + clear_bit(PACKET_READONLY, &pd->flags); +} + +static inline void __pkt_end_io_write(struct pktcdvd_device *pd, + struct buffer_head *bh, int uptodate) +{ + VPRINTK("end_io_write: bh=%ld, uptodate=%d\n", bh->b_blocknr, uptodate); + + /* + * general Linux bug, noone should clear the BH_Uptodate flag for + * a failed write... + */ + if (uptodate) + mark_buffer_uptodate(bh, uptodate); + else { + printk("pktcdvd: %s: WRITE error sector %lu\n", pd->name, bh->b_rsector); +#if 0 + set_bit(PACKET_RECOVERY, &pd->flags); + wake_up(&pd->wqueue); +#endif + } + + pd->stats.bh_e++; + + atomic_dec(&pd->wrqcnt); + if (atomic_read(&pd->wrqcnt) == 0) { + pkt_rq_end_io(pd); + } + + unlock_buffer(bh); +} + +/* + * we use this as our default b_end_io handler, since we need to take + * the entire request off the list if just one of the clusters fail. + * later on this should also talk to UDF about relocating blocks -- for + * now we just drop the rq entirely. when doing the relocating we must also + * lock the bh down to ensure that we can easily reconstruct the write should + * it fail. + */ +static void pkt_end_io_write(struct buffer_head *bh, int uptodate) +{ + struct pktcdvd_device *pd = &pkt_devs[MINOR(bh->b_rdev)]; + + __pkt_end_io_write(pd, bh, uptodate); + pkt_put_buffer(bh); +} + +static void pkt_end_io_write_stacked(struct buffer_head *bh, int uptodate) +{ + struct pktcdvd_device *pd = &pkt_devs[MINOR(bh->b_rdev)]; + struct buffer_head *rbh = bh->b_private; + + __pkt_end_io_write(pd, bh, uptodate); + rbh->b_end_io(rbh, uptodate); + pkt_put_stacked_bh(pd, bh); + wake_up(&pd_bh_wait); +} + +static int pkt_init_rq(struct pktcdvd_device *pd, struct request *rq) +{ + struct buffer_head *bh; + unsigned int cnt, nr_segments; + + cnt = 0; + nr_segments = 1; + bh = rq->bh; + while (bh) { + struct buffer_head *nbh = bh->b_reqnext; + + bh->b_rdev = pd->pkt_dev; + + /* + * the buffer better be mapped and locked! + */ + if (!buffer_locked(bh) || !buffer_mapped(bh)) { + printk("%lu, state %lx\n", bh->b_rsector, bh->b_state); + BUG(); + } + + if (nbh) { + if (!CONTIG_BH(bh, nbh)) + nr_segments++; + + /* + * if this happens, do report + */ + if ((bh->b_rsector + (bh->b_size >> 9))!=nbh->b_rsector) { + printk("%lu (%p)-> %lu (%p) (%lu in all)\n", + bh->b_rsector, bh, nbh->b_rsector, nbh, + rq->nr_sectors); + return 1; + } + } + + cnt += bh->b_size >> 9; + bh = nbh; + } + + rq->nr_segments = rq->nr_hw_segments = nr_segments; + + if (cnt != rq->nr_sectors) { + printk("botched request %u (%lu)\n", cnt, rq->nr_sectors); + return 1; + } + + return 0; +} + +/* + * really crude stats for now... + */ +static void pkt_account_rq(struct pktcdvd_device *pd, int read, int written, + int bs) +{ + pd->stats.bh_s += (written / bs); + pd->stats.secs_w += written; + pd->stats.secs_r += read; +} + +/* + * does request span two packets? 0 == yes, 1 == no + */ +static int pkt_one_zone(struct pktcdvd_device *pd, struct request *rq) +{ + if (!pd->settings.size) + return 0; + + if (!(rq->cmd & WRITE)) + return 1; + + return ZONE(rq->sector, pd) == ZONE(rq->sector + rq->nr_sectors -1, pd); +} + +#if defined(CONFIG_CDROM_PKTCDVD_BEMPTY) +static void pkt_init_buffer(struct buffer_head *bh) +{ + set_bit(BH_Uptodate, &bh->b_state); + set_bit(BH_Dirty, &bh->b_state); + memset(bh->b_data, 0, bh->b_size); +} + +static int pkt_sb_empty(struct pktcdvd_device *pd, struct buffer_head *bh) +{ + struct super_block *sb; + struct super_operations *sop; + unsigned long packet; + int ret; + + ret = 0; + if ((sb = get_super(pd->pkt_dev)) == NULL) + goto out; + if ((sop = sb->s_op) == NULL) + goto out; + if (sop->block_empty == NULL) + goto out; + + packet = 0; + if (sop->block_empty(sb, bh->b_blocknr, &packet)) { + pkt_init_buffer(pd, bh); + ret = 1; + } + +out: + return ret; +} + +#else /* defined(CONFIG_CDROM_PKTCDVD_BEMPTY) */ + +static int pkt_sb_empty(struct pktcdvd_device *pd, struct buffer_head *bh) +{ + return 0; +} + +#endif /* defined(CONFIG_CDROM_PKTCDVD_BEMPTY) */ + +static int pkt_flush_cache(struct pktcdvd_device *pd); + +static void pkt_flush_writes(struct pktcdvd_device *pd) +{ + if (pd->unflushed_writes) { + pd->unflushed_writes = 0; + pkt_flush_cache(pd); + } +} + +/* + * basically just does a ll_rw_block for the bhs given to use, but we + * don't return until we have them. + */ +static void pkt_read_bh(struct pktcdvd_device *pd, struct buffer_head *bh) +{ + /* + * UDF says it's empty, woohoo + */ + if (pkt_sb_empty(pd, bh)) + return; + + down(&pd->cache_sync_mutex); + pkt_flush_writes(pd); + generic_make_request(READ, bh); + up(&pd->cache_sync_mutex); +} + +static int pkt_index_bhs(struct buffer_head **bhs) +{ + struct buffer_head *bh; + int index; + int error = 0; + + /* + * now finish pending reads and connect the chain of buffers + */ + index = 0; + while (index < PACKET_MAX_SIZE) { + bh = bhs[index]; + + /* + * pin down private buffers (ie, force I/O to complete) + */ + if (bh->b_end_io == pkt_end_io_read) { + lock_buffer(bh); + bh->b_end_io = pkt_end_io_write; + if (!buffer_uptodate(bh)) { + printk("pktcdvd: read failure (%s, sec %lu)\n", + kdevname(bh->b_rdev), bh->b_rsector); + error = 1; + } + } + + if (!buffer_locked(bh)) + BUG(); + + /* + * attach previous + */ + if (index) { + struct buffer_head *pbh = bhs[index - 1]; + + if ((pbh->b_rsector + (pbh->b_size >> 9)) != bh->b_rsector) { + printk("%lu -> %lu\n", pbh->b_rsector, bh->b_rsector); + index = 0; + break; + } + pbh->b_reqnext = bh; + } + index++; + } + + if (error) + return 0; + + if (index) { + index--; + bhs[index]->b_reqnext = NULL; + } + + return index; +} + +/* + * fill in the holes of a request + * + * Returns: 0, keep 'em coming -- 1, stop queueing + */ +static int pkt_gather_data(struct pktcdvd_device *pd, struct request *rq) +{ + unsigned long start_s, end_s, sector; + struct buffer_head *bh; + unsigned int sectors, index; + struct buffer_head *bhs[PACKET_MAX_SIZE]; + + memset(bhs, 0, sizeof(bhs)); + + /* + * all calculations are done with 512 byte sectors + */ + sectors = pd->settings.size - rq->nr_sectors; + start_s = rq->sector - (rq->sector & (pd->settings.size - 1)); + end_s = start_s + pd->settings.size; + + VPRINTK("pkt_gather_data: cmd=%d\n", rq->cmd); + VPRINTK("need %d sectors for %s\n", sectors, kdevname(pd->dev)); + VPRINTK("from %lu to %lu ", start_s, end_s); + VPRINTK("(%lu - %lu)\n", rq->bh->b_rsector, rq->bhtail->b_rsector + + rq->current_nr_sectors); + + /* + * first fill-out map of the buffers we have + */ + bh = rq->bh; + while (bh) { + index = (bh->b_rsector & (pd->settings.size - 1)) / (bh->b_size >> 9); + + bhs[index] = bh; + bh = bh->b_reqnext; + + /* + * make sure to detach from list! + */ + bhs[index]->b_reqnext = NULL; + } + + /* + * now get buffers for missing blocks, and schedule reads for them + */ + for (index = 0, sector = start_s; sector < end_s; index++) { + if (bhs[index]) { + bh = bhs[index]; + goto next; + } + + bh = pkt_get_buffer(pd, sector, CD_FRAMESIZE); + + bhs[index] = bh; + rq->nr_sectors += bh->b_size >> 9; + rq->nr_segments++; + + if (!buffer_uptodate(bh)) { + bh->b_end_io = pkt_end_io_read; + pkt_read_bh(pd, bh); + } + + next: + sector += bh->b_size >> 9; + } + + index = pkt_index_bhs(bhs); +#if 0 + if (!index) + goto kill_it; +#endif + + rq->bh = bhs[0]; + rq->bhtail = bhs[index]; + rq->buffer = rq->bh->b_data; + rq->current_nr_sectors = rq->bh->b_size >> 9; + rq->hard_nr_sectors = rq->nr_sectors; + rq->sector = rq->hard_sector = start_s; + + VPRINTK("unlocked last %lu\n", rq->bhtail->b_rsector); + if (pkt_init_rq(pd, rq)) { + for (index = 0; index < PACKET_MAX_SIZE; index++) { + bh = bhs[index]; + printk("[%d] %lu %d (%p -> %p)\n", index, bh->b_rsector, + bh->b_size, bh, bh->b_reqnext); + } + goto kill_it; + } + + pkt_account_rq(pd, sectors, rq->nr_sectors, rq->current_nr_sectors); + + /* + * sanity check + */ + if (rq->nr_sectors != pd->settings.size) { + printk("pktcdvd: request mismatch %lu (should be %u)\n", + rq->nr_sectors, pd->settings.size); + BUG(); + } + + return 0; + + /* + * for now, just kill entire request and hope for the best... + */ +kill_it: + for (index = 0; index < PACKET_MAX_SIZE; index++) { + bh = bhs[index]; + buffer_IO_error(bh); + if (bh->b_list == PKT_BUF_LIST) + pkt_put_buffer(bh); + } + end_that_request_last(pd->rq); + return 1; +} + +/* + * Returns: 1, keep 'em coming -- 0, wait for wakeup + */ +static int pkt_do_request(struct pktcdvd_device *pd, struct request *rq) +{ + VPRINTK("do_request: bh=%ld, nr_sectors=%ld, size=%d, cmd=%d\n", rq->bh->b_blocknr, rq->nr_sectors, pd->settings.size, rq->cmd); + + /* + * perfect match. the merge_* functions have already made sure that + * a request doesn't cross a packet boundary, so if the sector + * count matches it's good. + */ + if (rq->nr_sectors == pd->settings.size) { + if (pkt_init_rq(pd, rq)) { + pkt_kill_request(pd, rq, 0); + return 1; + } + + pkt_account_rq(pd, 0, rq->nr_sectors, rq->current_nr_sectors); + return 0; + } + + /* + * paranoia... + */ + if (rq->nr_sectors > pd->settings.size) { + printk("pktcdvd: request too big! BUG! %lu\n", rq->nr_sectors); + BUG(); + } + + return pkt_gather_data(pd, rq); +} + +/* + * recover a failed write, query for relocation if possible + */ +static int pkt_start_recovery(struct pktcdvd_device *pd, struct request *rq) +{ +#if 0 + struct super_block *sb = get_super(pd->pkt_dev); + struct buffer_head *bhs[PACKET_MAX_SIZE], *bh, *obh; + unsigned long old_block, new_block, sector; + int i, sectors; + + if (!sb || !sb->s_op || !sb->s_op->relocate_blocks) + goto fail; + + old_block = (rq->sector & ~(pd->settings.size - 1)) / (rq->bh->b_size >> 9); + if (sb->s_op->relocate_blocks(sb, old_block, &new_block)) + goto fail; + + memset(bhs, 0, sizeof(bhs)); + bh = rq->bh; + while (bh) { + i = (bh->b_rsector & (pd->settings.size - 1)) / (bh->b_size >> 9); + + bhs[i] = bh; + bh = bh->b_reqnext; + bhs[i]->b_reqnext = NULL; + } + + sectors = 0; + sector = new_block * (rq->bh->b_size >> 9); + for (i = 0; i < PACKET_MAX_SIZE; i++) { + bh = bhs[i]; + + /* + * three cases --> + * 1) bh is not there at all + * 2) bh is there and not ours, get a new one and + * invalidate this block for the future + * 3) bh is there and ours, just change the sector + */ + if (!bh) { + obh = pkt_get_hash(pd->pkt_dev, new_block,CD_FRAMESIZE); + bh = __pkt_get_buffer(pd, sector); + if (obh) { + if (buffer_uptodate(obh)) { + memcpy(bh->b_data, obh->b_data, obh->b_size); + set_bit(BH_Uptodate, &bh->b_state); + } + unlock_buffer(obh); + bforget(obh); + } + bhs[i] = bh; + } else if (bh->b_list != PKT_BUF_LIST) { + bhs[i] = pkt_get_buffer(pd, sector, CD_FRAMESIZE); + memcpy(bhs[i]->b_data, bh->b_data, CD_FRAMESIZE); + unlock_buffer(bh); + bforget(bh); + bh = bhs[i]; + set_bit(BH_Uptodate, &bh->b_state); + } else { + bh->b_rsector = sector; + bh->b_blocknr = new_block; + } + + sector += (bh->b_size >> 9); + new_block++; + sectors += (bh->b_size >> 9); + } + + i = pkt_index_bhs(bhs); + if (!i) + goto fail; + + rq->bh = bhs[0]; + rq->bhtail = bhs[i]; + rq->buffer = rq->bh->b_data; + rq->current_nr_sectors = rq->bh->b_size >> 9; + rq->hard_nr_sectors = rq->nr_sectors = sectors; + rq->sector = rq->hard_sector = rq->bh->b_rsector; + rq->errors = 0; + clear_bit(PACKET_RECOVERY, &pd->flags); + clear_bit(PACKET_BUSY, &pd->flags); + return 0; + +fail: +#endif + printk("pktcdvd: rq recovery not possible\n"); + pkt_kill_request(pd, rq, 0); + clear_bit(PACKET_RECOVERY, &pd->flags); + return 1; +} + +/* + * handle the requests that got queued for this writer + * + * returns 0 for busy (already doing something), or 1 for queue new one + * + */ +static int pkt_handle_queue(struct pktcdvd_device *pd, request_queue_t *q) +{ + struct request *rq; + int ret; + + VPRINTK("handle_queue\n"); + + /* + * nothing for us to do + */ + if (!test_bit(PACKET_RQ, &pd->flags)) + return 1; + + spin_lock_irq(&pd->lock); + rq = pd->rq; + spin_unlock_irq(&pd->lock); + + if (test_bit(PACKET_RECOVERY, &pd->flags)) + if (pkt_start_recovery(pd, rq)) + return 1; + + /* + * already being processed + */ + if (test_and_set_bit(PACKET_BUSY, &pd->flags)) + return 0; + + /* + * nothing to do + */ + ret = 1; + if (rq == NULL) { + printk("handle_queue: pd BUSY+RQ, but no rq\n"); + clear_bit(PACKET_RQ, &pd->flags); + goto out; + } + + /* + * reads are shipped directly to cd-rom, so they should not + * pop up here + */ + if (rq->cmd == READ) + BUG(); + + if ((rq->current_nr_sectors << 9) != CD_FRAMESIZE) { + pkt_kill_request(pd, rq, 0); + goto out; + } + + if (!pkt_do_request(pd, rq)) { + atomic_add(PACKET_MAX_SIZE, &pd->wrqcnt); + down(&pd->cache_sync_mutex); + pkt_inject_request(q, rq); + pd->unflushed_writes = 1; + up(&pd->cache_sync_mutex); + return 0; + } + +out: + clear_bit(PACKET_BUSY, &pd->flags); + return ret; +} + +/* + * kpacketd is woken up, when writes have been queued for one of our + * registered devices + */ +static int kcdrwd(void *foobar) +{ + struct pktcdvd_device *pd = foobar; + request_queue_t *q, *my_queue; + + /* + * exit_files, mm (move to lazy-tlb, so context switches are come + * extremely cheap) etc + */ + daemonize(); + + current->policy = SCHED_OTHER; + current->nice = -20; + sprintf(current->comm, pd->name); + + spin_lock_irq(¤t->sigmask_lock); + siginitsetinv(¤t->blocked, sigmask(SIGKILL)); + flush_signals(current); + spin_unlock_irq(¤t->sigmask_lock); + + q = blk_get_queue(pd->dev); + my_queue = blk_get_queue(pd->pkt_dev); + + for (;;) { + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&pd->wqueue, &wait); + + /* + * if PACKET_BUSY is cleared, we can queue + * another request. otherwise we need to unplug the + * cd-rom queue and wait for buffers to be flushed + * (which will then wake us up again when done). + */ + do { + pkt_handle_queue(pd, q); + + set_current_state(TASK_INTERRUPTIBLE); + + if (test_bit(PACKET_BUSY, &pd->flags)) + break; + + spin_lock_irq(&io_request_lock); + if (list_empty(&my_queue->queue_head)) { + spin_unlock_irq(&io_request_lock); + break; + } + set_current_state(TASK_RUNNING); + + my_queue->request_fn(my_queue); + spin_unlock_irq(&io_request_lock); + } while (1); + + generic_unplug_device(q); + + schedule(); + remove_wait_queue(&pd->wqueue, &wait); + + if (signal_pending(current)) { + flush_signals(current); + } + if (pd->cdrw.time_to_die) + break; + } + + complete_and_exit(&pd->cdrw.thr_compl, 0); + return 0; +} + +static void pkt_attempt_remerge(struct pktcdvd_device *pd, request_queue_t *q, + struct request *rq) +{ + struct request *nxt; + + while (!list_empty(&q->queue_head)) { + if (rq->nr_sectors == pd->settings.size) + break; + + nxt = blkdev_entry_next_request(&q->queue_head); + + if (ZONE(rq->sector, pd) != ZONE(nxt->sector, pd)) + break; + else if (rq->sector + rq->nr_sectors > nxt->sector) + break; + + rq->nr_sectors = rq->hard_nr_sectors += nxt->nr_sectors; + rq->bhtail->b_reqnext = nxt->bh; + rq->bhtail = nxt->bhtail; + list_del(&nxt->queue); + blkdev_release_request(nxt); + } +} + +/* + * our request function. + * + * - reads are just tossed directly to the device, we don't care. + * - writes, regardless of size, are added as the current pd rq and + * kcdrwd is woken up to handle it. kcdrwd will also make sure to + * reinvoke this request handler, once the given request has been + * processed. + * + * Locks: io_request_lock held + * + * Notes: all writers have their own queue, so all requests are for the + * the same device + */ +static void pkt_request(request_queue_t *q) +{ + struct pktcdvd_device *pd = (struct pktcdvd_device *) q->queuedata; + unsigned long flags; + + if (list_empty(&q->queue_head)) + return; + + while (!list_empty(&q->queue_head)) { + struct request *rq = blkdev_entry_next_request(&q->queue_head); + + VPRINTK("pkt_request: cmd=%d, rq=%p, rq->sector=%ld, rq->nr_sectors=%ld\n", rq->cmd, rq, rq->sector, rq->nr_sectors); + + blkdev_dequeue_request(rq); + + rq->rq_dev = pd->dev; + + if (rq->cmd == READ) + BUG(); + + if (test_bit(PACKET_RECOVERY, &pd->flags)) + break; + + /* + * paranoia, shouldn't trigger... + */ + if (!pkt_one_zone(pd, rq)) { + printk("rq->cmd=%d, rq->sector=%ld, rq->nr_sectors=%ld\n", + rq->cmd, rq->sector, rq->nr_sectors); + BUG(); + } + + pkt_attempt_remerge(pd, q, rq); + + spin_lock_irqsave(&pd->lock, flags); + + /* + * already gathering data for another read. the + * rfn will be reinvoked once that is done + */ + if (test_and_set_bit(PACKET_RQ, &pd->flags)) { + list_add(&rq->queue, &q->queue_head); + spin_unlock_irqrestore(&pd->lock, flags); + break; + } + + if (pd->rq) + BUG(); + + pd->rq = rq; + spin_unlock_irqrestore(&pd->lock, flags); + break; + } + VPRINTK("wake up wait queue\n"); + wake_up(&pd->wqueue); +} + +static void pkt_print_settings(struct pktcdvd_device *pd) +{ + printk("pktcdvd: %s packets, ", pd->settings.fp ? "Fixed" : "Variable"); + printk("%u blocks, ", pd->settings.size >> 2); + printk("Mode-%c disc\n", pd->settings.block_mode == 8 ? '1' : '2'); +} + +/* + * A generic sense dump / resolve mechanism should be implemented across + * all ATAPI + SCSI devices. + */ +static void pkt_dump_sense(struct cdrom_generic_command *cgc) +{ + static char *info[9] = { "No sense", "Recovered error", "Not ready", + "Medium error", "Hardware error", "Illegal request", + "Unit attention", "Data protect", "Blank check" }; + int i; + struct request_sense *sense = cgc->sense; + + printk("pktcdvd:"); + for (i = 0; i < CDROM_PACKET_SIZE; i++) + printk(" %02x", cgc->cmd[i]); + printk(" - "); + + if (sense == NULL) { + printk("no sense\n"); + return; + } + + printk("sense %02x.%02x.%02x", sense->sense_key, sense->asc, sense->ascq); + + if (sense->sense_key > 8) { + printk(" (INVALID)\n"); + return; + } + + printk(" (%s)\n", info[sense->sense_key]); +} + +/* + * write mode select package based on pd->settings + */ +static int pkt_set_write_settings(struct pktcdvd_device *pd) +{ + struct cdrom_device_info *cdi = pd->cdi; + struct cdrom_generic_command cgc; + struct request_sense sense; + write_param_page *wp; + char buffer[128]; + int ret, size; + + memset(buffer, 0, sizeof(buffer)); + init_cdrom_command(&cgc, buffer, sizeof(*wp), CGC_DATA_READ); + cgc.sense = &sense; + if ((ret = cdrom_mode_sense(cdi, &cgc, GPMODE_WRITE_PARMS_PAGE, 0))) { + pkt_dump_sense(&cgc); + return ret; + } + + size = 2 + ((buffer[0] << 8) | (buffer[1] & 0xff)); + pd->mode_offset = (buffer[6] << 8) | (buffer[7] & 0xff); + if (size > sizeof(buffer)) + size = sizeof(buffer); + + /* + * now get it all + */ + init_cdrom_command(&cgc, buffer, size, CGC_DATA_READ); + cgc.sense = &sense; + if ((ret = cdrom_mode_sense(cdi, &cgc, GPMODE_WRITE_PARMS_PAGE, 0))) { + pkt_dump_sense(&cgc); + return ret; + } + + /* + * write page is offset header + block descriptor length + */ + wp = (write_param_page *) &buffer[sizeof(struct mode_page_header) + pd->mode_offset]; + + wp->fp = pd->settings.fp; + wp->track_mode = pd->settings.track_mode; + wp->write_type = pd->settings.write_type; + wp->data_block_type = pd->settings.block_mode; + + wp->multi_session = 0; + +#ifdef PACKET_USE_LS + wp->link_size = 7; + wp->ls_v = 1; +#endif + + if (wp->data_block_type == PACKET_BLOCK_MODE1) { + wp->session_format = 0; + wp->subhdr2 = 0x20; + } else if (wp->data_block_type == PACKET_BLOCK_MODE2) { + wp->session_format = 0x20; + wp->subhdr2 = 8; +#if 0 + wp->mcn[0] = 0x80; + memcpy(&wp->mcn[1], PACKET_MCN, sizeof(wp->mcn) - 1); +#endif + } else { + /* + * paranoia + */ + printk("pktcdvd: write mode wrong %d\n", wp->data_block_type); + return 1; + } + wp->packet_size = cpu_to_be32(pd->settings.size >> 2); + + cgc.buflen = cgc.cmd[8] = size; + if ((ret = cdrom_mode_select(cdi, &cgc))) { + pkt_dump_sense(&cgc); + return ret; + } + + pkt_print_settings(pd); + return 0; +} + +/* + * 0 -- we can write to this track, 1 -- we can't + */ +static int pkt_good_track(track_information *ti) +{ + /* + * only good for CD-RW at the moment, not DVD-RW + */ + + /* + * FIXME: only for FP + */ + if (ti->fp == 0) + return 0; + + /* + * "good" settings as per Mt Fuji. + */ + if (ti->rt == 0 && ti->blank == 0 && ti->packet == 1) + return 0; + + if (ti->rt == 0 && ti->blank == 1 && ti->packet == 1) + return 0; + + if (ti->rt == 1 && ti->blank == 0 && ti->packet == 1) + return 0; + + printk("pktcdvd: bad state %d-%d-%d\n", ti->rt, ti->blank, ti->packet); + return 1; +} + +/* + * 0 -- we can write to this disc, 1 -- we can't + */ +static int pkt_good_disc(struct pktcdvd_device *pd, disc_information *di) +{ + /* + * for disc type 0xff we should probably reserve a new track. + * but i'm not sure, should we leave this to user apps? probably. + */ + if (di->disc_type == 0xff) { + printk("pktcdvd: Unknown disc. No track?\n"); + return 1; + } + + if (di->disc_type != 0x20 && di->disc_type != 0) { + printk("pktcdvd: Wrong disc type (%x)\n", di->disc_type); + return 1; + } + + if (di->erasable == 0) { + printk("pktcdvd: Disc not erasable\n"); + return 1; + } + + if (pd->track_status == PACKET_SESSION_RESERVED) { + printk("pktcdvd: Can't write to last track (reserved)\n"); + return 1; + } + + return 0; +} + +static int pkt_probe_settings(struct pktcdvd_device *pd) +{ + disc_information di; + track_information ti; + int ret, track; + + memset(&di, 0, sizeof(disc_information)); + memset(&ti, 0, sizeof(track_information)); + + if ((ret = cdrom_get_disc_info(pd->dev, &di))) { + printk("failed get_disc\n"); + return ret; + } + + pd->disc_status = di.disc_status; + pd->track_status = di.border_status; + + if (pkt_good_disc(pd, &di)) + return -ENXIO; + + printk("pktcdvd: inserted media is CD-R%s\n", di.erasable ? "W" : ""); + pd->type = di.erasable ? PACKET_CDRW : PACKET_CDR; + + track = 1; /* (di.last_track_msb << 8) | di.last_track_lsb; */ + if ((ret = cdrom_get_track_info(pd->dev, track, 1, &ti))) { + printk("pktcdvd: failed get_track\n"); + return ret; + } + + if (pkt_good_track(&ti)) { + printk("pktcdvd: can't write to this track\n"); + return -ENXIO; + } + + /* + * we keep packet size in 512 byte units, makes it easier to + * deal with request calculations. + */ + pd->settings.size = be32_to_cpu(ti.fixed_packet_size) << 2; + if (pd->settings.size == 0) { + printk("pktcdvd: detected zero packet size!\n"); + pd->settings.size = 128; + } + pd->settings.fp = ti.fp; + pd->offset = (be32_to_cpu(ti.track_start) << 2) & (pd->settings.size - 1); + + if (ti.nwa_v) { + pd->nwa = be32_to_cpu(ti.next_writable); + set_bit(PACKET_NWA_VALID, &pd->flags); + } + + /* + * in theory we could use lra on -RW media as well and just zero + * blocks that haven't been written yet, but in practice that + * is just a no-go. we'll use that for -R, naturally. + */ + if (ti.lra_v) { + pd->lra = be32_to_cpu(ti.last_rec_address); + set_bit(PACKET_LRA_VALID, &pd->flags); + } else { + pd->lra = 0xffffffff; + set_bit(PACKET_LRA_VALID, &pd->flags); + } + + /* + * fine for now + */ + pd->settings.link_loss = 7; + pd->settings.write_type = 0; /* packet */ + pd->settings.track_mode = ti.track_mode; + + /* + * mode1 or mode2 disc + */ + switch (ti.data_mode) { + case PACKET_MODE1: + pd->settings.block_mode = PACKET_BLOCK_MODE1; + break; + case PACKET_MODE2: + pd->settings.block_mode = PACKET_BLOCK_MODE2; + break; + default: + printk("pktcdvd: unknown data mode\n"); + return 1; + } + return 0; +} + +/* + * enable/disable write caching on drive + */ +static int pkt_write_caching(struct pktcdvd_device *pd, int set) +{ + struct cdrom_generic_command cgc; + struct request_sense sense; + unsigned char buf[64]; + int ret; + + memset(buf, 0, sizeof(buf)); + init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ); + cgc.sense = &sense; + cgc.buflen = pd->mode_offset + 12; + + /* + * caching mode page might not be there, so quiet this command + */ + cgc.quiet = 1; + + if ((ret = cdrom_mode_sense(pd->cdi, &cgc, GPMODE_WCACHING_PAGE, 0))) + return ret; + + buf[pd->mode_offset + 10] |= (!!set << 2); + + cgc.buflen = cgc.cmd[8] = 2 + ((buf[0] << 8) | (buf[1] & 0xff)); + ret = cdrom_mode_select(pd->cdi, &cgc); + if (ret) { + printk("pktcdvd: write caching control failed\n"); + pkt_dump_sense(&cgc); + } else if (!ret && set) + printk("pktcdvd: enabled write caching on %s\n", pd->name); + return ret; +} + +/* + * flush the drive cache to media + */ +static int pkt_flush_cache(struct pktcdvd_device *pd) +{ + struct cdrom_generic_command cgc; + + init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); + cgc.cmd[0] = GPCMD_FLUSH_CACHE; + cgc.quiet = 1; + cgc.timeout = 60*HZ; + + /* + * the IMMED bit -- we default to not setting it, although that + * would allow a much faster close, this is safer + */ +#if 0 + cgc.cmd[1] = 1 << 1; +#endif + return pd->cdi->ops->generic_packet(pd->cdi, &cgc); +} + +/* + * Returns drive current write speed + */ +static int pkt_get_speed(struct pktcdvd_device *pd) +{ + struct cdrom_generic_command cgc; + struct request_sense sense; + unsigned char buf[64]; + int ret, offset; + + memset(buf, 0, sizeof(buf)); + init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_UNKNOWN); + cgc.sense = &sense; + + ret = cdrom_mode_sense(pd->cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0); + if (ret) { + cgc.buflen = pd->mode_offset + buf[pd->mode_offset + 9] + 2 + + sizeof(struct mode_page_header); + ret = cdrom_mode_sense(pd->cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0); + if (ret) { + pkt_dump_sense(&cgc); + return ret; + } + } + + /* find out the current write speed selected + * there are an obsoleted field for older drives (offset 20), + * and a new field for newer (high-speed) drives (offset 28). + */ + + if (buf[pd->mode_offset+9] >= 28) + offset = pd->mode_offset + 36; + else + offset = pd->mode_offset + 28; + + pd->speed = ((buf[offset] << 8) | buf[offset + 1]) / 0xb0; + return 0; +} + +/* These tables from cdrecord - I don't have orange book */ +/* standard speed CD-RW (1-4x) */ +static char clv_to_speed[16] = { + /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */ + 0, 2, 4, 6, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; +/* high speed CD-RW (-10x) */ +static char hs_clv_to_speed[16] = { + /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */ + 0, 2, 4, 6, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; +/* ultra high speed CD-RW */ +static char us_clv_to_speed[16] = { + /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */ + 0, 2, 4, 8, 0, 0,16, 0,24,32,40,48, 0, 0, 0, 0 +}; + +/* + * reads the maximum media speed from ATIP + */ +static int pkt_media_speed(struct pktcdvd_device *pd, unsigned *speed) +{ + struct cdrom_generic_command cgc; + struct request_sense sense; + unsigned char buf[64]; + unsigned int size, st, sp; + int ret; + + init_cdrom_command(&cgc, buf, 2, CGC_DATA_READ); + cgc.sense = &sense; + cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP; + cgc.cmd[1] = 2; + cgc.cmd[2] = 4; /* READ ATIP */ + cgc.cmd[8] = 2; + ret = pd->cdi->ops->generic_packet(pd->cdi, &cgc); + if (ret) { + pkt_dump_sense(&cgc); + return ret; + } + size = ((unsigned int) buf[0]<<8) + buf[1] + 2; + if (size > sizeof(buf)) + size = sizeof(buf); + + init_cdrom_command(&cgc, buf, size, CGC_DATA_READ); + cgc.sense = &sense; + cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP; + cgc.cmd[1] = 2; + cgc.cmd[2] = 4; + cgc.cmd[8] = size; + ret = pd->cdi->ops->generic_packet(pd->cdi, &cgc); + if (ret) { + pkt_dump_sense(&cgc); + return ret; + } + + if (!buf[6] & 0x40) { + printk("pktcdvd: Disc type is not CD-RW\n"); + return 1; + } + if (!buf[6] & 0x4) { + printk("pktcdvd: A1 values on media are not valid, maybe not CDRW?\n"); + return 1; + } + + st = (buf[6] >> 3) & 0x7; /* disc sub-type */ + + sp = buf[16] & 0xf; /* max speed from ATIP A1 field */ + + /* Info from cdrecord */ + switch (st) { + case 0: /* standard speed */ + *speed = clv_to_speed[sp]; + break; + case 1: /* high speed */ + *speed = hs_clv_to_speed[sp]; + break; + case 2: /* ultra high speed */ + *speed = us_clv_to_speed[sp]; + break; + default: + printk("pktcdvd: Unknown disc sub-type %d\n",st); + return 1; + } + if (*speed) { + printk("pktcdvd: Max. media speed: %d\n",*speed); + return 0; + } else { + printk("pktcdvd: Unknown speed %d for sub-type %d\n",sp,st); + return 1; + } +} + +/* + * speed is given as the normal factor, e.g. 4 for 4x + */ +static int pkt_set_speed(struct pktcdvd_device *pd, unsigned write_speed) +{ + struct cdrom_generic_command cgc; + struct request_sense sense; + unsigned read_speed; + int ret; + + /* + * we set read and write time so that read spindle speed is one and + * a half as fast as write. although a drive can typically read much + * faster than write, this minimizes the spin up/down when we write + * and gather data. maybe 1/1 factor is faster, needs a bit of testing. + */ + write_speed = write_speed * 0xb1; /* should be 176.4, but CD-RWs rounds down */ + write_speed = min_t(unsigned, write_speed, 0xffff); + read_speed = (write_speed * 3) >> 1; + read_speed = min_t(unsigned, read_speed, 0xffff); + + init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); + cgc.sense = &sense; + cgc.cmd[0] = GPCMD_SET_SPEED; + cgc.cmd[2] = (read_speed >> 8) & 0xff; + cgc.cmd[3] = read_speed & 0xff; + cgc.cmd[4] = (write_speed >> 8) & 0xff; + cgc.cmd[5] = write_speed & 0xff; + + if ((ret = pd->cdi->ops->generic_packet(pd->cdi, &cgc))) + pkt_dump_sense(&cgc); + return ret; +} + +/* + * Give me full power, Captain + */ +static int pkt_adjust_speed(struct pktcdvd_device *pd, int speed) +{ + disc_information dummy; + int ret; + + /* + * FIXME: do proper unified cap page, also, this isn't proper + * Mt Fuji, but I think we can safely assume all drives support + * it. A hell of a lot more than support the GET_PERFORMANCE + * command (besides, we also use the old set speed command, + * not the streaming feature). + */ + if ((ret = pkt_set_speed(pd, speed))) + return ret; + + /* + * just do something with the disc -- next read will contain the + * maximum speed with this media + */ + if ((ret = cdrom_get_disc_info(pd->dev, &dummy))) + return ret; + + if ((ret = pkt_get_speed(pd))) { + printk("pktcdvd: failed get speed\n"); + return ret; + } + + DPRINTK("pktcdvd: speed (R/W) %u/%u\n", (pd->speed * 3) / 2, pd->speed); + return 0; +} + +static int pkt_perform_opc(struct pktcdvd_device *pd) +{ + struct cdrom_generic_command cgc; + struct request_sense sense; + int ret; + + VPRINTK("pktcdvd: Performing OPC\n"); + + init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); + cgc.sense = &sense; + cgc.timeout = 60*HZ; + cgc.cmd[0] = GPCMD_SEND_OPC; + cgc.cmd[1] = 1; + if ((ret = pd->cdi->ops->generic_packet(pd->cdi, &cgc))) + pkt_dump_sense(&cgc); + return ret; +} + +static int pkt_open_write(struct pktcdvd_device *pd) +{ + int ret; + unsigned int speed; + + if ((ret = pkt_probe_settings(pd))) { + DPRINTK("pktcdvd: %s failed probe\n", pd->name); + return -EIO; + } + + if ((ret = pkt_set_write_settings(pd))) { + DPRINTK("pktcdvd: %s failed saving write settings\n", pd->name); + return -EIO; + } + + (void) pkt_write_caching(pd, USE_WCACHING); + + ret = pkt_media_speed(pd, &speed); + speed = ret ? 16 : speed; + + if ((ret = pkt_adjust_speed(pd, speed))) { + DPRINTK("pktcdvd: %s couldn't set write speed\n", pd->name); + return -EIO; + } + + if ((ret = pkt_perform_opc(pd))) { + DPRINTK("pktcdvd: %s Optimum Power Calibration failed\n", pd->name); + } + + return 0; +} + +/* + * called at open time. + */ +static int pkt_open_dev(struct pktcdvd_device *pd, int write) +{ + int ret; + long lba; + + if (!pd->dev) + return -ENXIO; + + pd->bdev = bdget(kdev_t_to_nr(pd->dev)); + if (!pd->bdev) { + printk("pktcdvd: can't find cdrom block device\n"); + return -ENXIO; + } + + if ((ret = blkdev_get(pd->bdev, FMODE_READ, 0, BDEV_FILE))) { + pd->bdev = NULL; + return ret; + } + + if ((ret = cdrom_get_last_written(pd->dev, &lba))) { + printk("pktcdvd: cdrom_get_last_written failed\n"); + return ret; + } + + pkt_sizes[MINOR(pd->pkt_dev)] = lba << 1; + + if (write) { + if ((ret = pkt_open_write(pd))) + return ret; + pkt_mark_readonly(pd, 0); + } else { + (void) pkt_adjust_speed(pd, 0xffff); + pkt_mark_readonly(pd, 1); + } + + if (write) + printk("pktcdvd: %lukB available on disc\n", lba << 1); + + return 0; +} + +/* + * called when the device is closed. makes sure that the device flushes + * the internal cache before we close. + */ +static void pkt_release_dev(struct pktcdvd_device *pd, int flush) +{ + atomic_dec(&pd->refcnt); + if (atomic_read(&pd->refcnt) > 0) + return; + + fsync_dev(pd->pkt_dev); + + if (flush && pkt_flush_cache(pd)) + DPRINTK("pktcdvd: %s not flushing cache\n", pd->name); + + pkt_set_speed(pd, 0xffff); + + if (pd->bdev) { + blkdev_put(pd->bdev, BDEV_FILE); + pd->bdev = NULL; + } +} + +static int pkt_open(struct inode *inode, struct file *file) +{ + struct pktcdvd_device *pd = NULL; + int ret; + + VPRINTK("pktcdvd: entering open\n"); + + if (MINOR(inode->i_rdev) >= MAX_WRITERS) { + printk("pktcdvd: max %d writers supported\n", MAX_WRITERS); + ret = -ENODEV; + goto out; + } + + /* + * either device is not configured, or pktsetup is old and doesn't + * use O_CREAT to create device + */ + pd = &pkt_devs[MINOR(inode->i_rdev)]; + if (!pd->dev && !(file->f_flags & O_CREAT)) { + VPRINTK("pktcdvd: not configured and O_CREAT not set\n"); + ret = -ENXIO; + goto out; + } + + atomic_inc(&pd->refcnt); + if (atomic_read(&pd->refcnt) > 1) { + if (file->f_mode & FMODE_WRITE) { + VPRINTK("pktcdvd: busy open for write\n"); + ret = -EBUSY; + goto out_dec; + } + + /* + * Not first open, everything is already set up + */ + return 0; + } + + if (((file->f_flags & O_ACCMODE) != O_RDONLY) || !(file->f_flags & O_CREAT)) { + if (pkt_open_dev(pd, file->f_mode & FMODE_WRITE)) { + ret = -EIO; + goto out_dec; + } + } + + /* + * needed here as well, since ext2 (among others) may change + * the blocksize at mount time + */ + set_blocksize(pd->pkt_dev, CD_FRAMESIZE); + return 0; + +out_dec: + atomic_dec(&pd->refcnt); + if (atomic_read(&pd->refcnt) == 0) { + if (pd->bdev) { + blkdev_put(pd->bdev, BDEV_FILE); + pd->bdev = NULL; + } + } +out: + VPRINTK("pktcdvd: failed open (%d)\n", ret); + return ret; +} + +static int pkt_close(struct inode *inode, struct file *file) +{ + struct pktcdvd_device *pd = &pkt_devs[MINOR(inode->i_rdev)]; + int ret = 0; + + if (pd->dev) { + int flush = !test_bit(PACKET_READONLY, &pd->flags); + pkt_release_dev(pd, flush); + } + + return ret; +} + +/* + * pktcdvd i/o elevator parts + */ +static inline int pkt_bh_rq_ordered(struct buffer_head *bh, struct request *rq, + struct list_head *head) +{ + struct list_head *next; + struct request *next_rq; + + next = rq->queue.next; + if (next == head) + return 0; + + next_rq = blkdev_entry_to_request(next); + if (next_rq->rq_dev != rq->rq_dev) + return bh->b_rsector > rq->sector; + + if (bh->b_rsector < next_rq->sector && bh->b_rsector > rq->sector) + return 1; + + if (next_rq->sector > rq->sector) + return 0; + + if (bh->b_rsector > rq->sector || bh->b_rsector < next_rq->sector) + return 1; + + return 0; +} + +static int pkt_elevator_merge(request_queue_t *q, struct request **req, + struct list_head *head, + struct buffer_head *bh, int rw, + int max_sectors) +{ + struct list_head *entry = &q->queue_head; + unsigned int count = bh->b_size >> 9, ret = ELEVATOR_NO_MERGE; + + if (bh->b_reqnext) + BUG(); + + VPRINTK("pkt_elevator_merge: rw=%d, ms=%d, bh=%lu, dev=%d\n", rw, max_sectors, bh->b_rsector, bh->b_rdev); + + while ((entry = entry->prev) != head) { + struct request *__rq = blkdev_entry_to_request(entry); + if (__rq->waiting) + continue; + if (__rq->rq_dev != bh->b_rdev) + continue; + if (!*req && pkt_bh_rq_ordered(bh, __rq, &q->queue_head)) + *req = __rq; + if (__rq->cmd != rw) + continue; + if (__rq->nr_sectors + count > max_sectors) + continue; + if (__rq->sector + __rq->nr_sectors == bh->b_rsector) { + ret = ELEVATOR_BACK_MERGE; + *req = __rq; + break; + } else if (__rq->sector - count == bh->b_rsector) { + ret = ELEVATOR_FRONT_MERGE; + *req = __rq; + break; + } +#if 0 /* makes sense, chance of two matches probably slim */ + else if (*req) + break; +#endif + } + VPRINTK("*req=%p, ret=%d\n", *req, ret); + + return ret; +} + +static int pkt_make_request(request_queue_t *q, int rw, struct buffer_head *bh) +{ + struct pktcdvd_device *pd; + struct buffer_head *new_bh; + + if (MINOR(bh->b_rdev) >= MAX_WRITERS) { + printk("pktcdvd: %s out of range\n", kdevname(bh->b_rdev)); + goto end_io; + } + + pd = &pkt_devs[MINOR(bh->b_rdev)]; + if (!pd->dev) { + printk("pktcdvd: request received for non-active pd\n"); + goto end_io; + } + + /* + * quick remap a READ + */ + if (rw == READ || rw == READA) { + down(&pd->cache_sync_mutex); + pkt_flush_writes(pd); + bh->b_rdev = pd->dev; + generic_make_request(rw, bh); + up(&pd->cache_sync_mutex); + return 0; + } + + if (!(rw & WRITE)) + BUG(); + + if (test_bit(PACKET_READONLY, &pd->flags)) { + printk("pktcdvd: WRITE for ro device %s (%lu)\n", + pd->name, bh->b_rsector); + goto end_io; + } + + VPRINTK("pkt_make_request: bh:%p block:%ld size:%d\n", + bh, bh->b_blocknr, bh->b_size); + + if (bh->b_size != CD_FRAMESIZE) { + printk("pktcdvd: wrong bh size\n"); + goto end_io; + } + + /* + * This is deadlock safe, since pkt_get_stacked_bh can only + * fail if there are already buffers in flight for this + * packet device. When the in-flight buffers finish, we + * will be woken up and try again. + */ + new_bh = kmem_cache_alloc(bh_cachep, GFP_ATOMIC); + while (!new_bh) { + DECLARE_WAITQUEUE(wait, current); + + generic_unplug_device(q); + + add_wait_queue(&pd_bh_wait, &wait); + set_current_state(TASK_UNINTERRUPTIBLE); + + new_bh = pkt_get_stacked_bh(pd); + if (!new_bh) + schedule(); + + set_current_state(TASK_RUNNING); + remove_wait_queue(&pd_bh_wait, &wait); + } + + new_bh->b_size = bh->b_size; + new_bh->b_list = PKT_BUF_LIST + 1; + new_bh->b_dev = bh->b_dev; + atomic_set(&new_bh->b_count, 1); + new_bh->b_rdev = bh->b_rdev; + new_bh->b_state = bh->b_state; + new_bh->b_page = bh->b_page; + new_bh->b_data = bh->b_data; + new_bh->b_private = bh; + new_bh->b_end_io = pkt_end_io_write_stacked; + new_bh->b_rsector = bh->b_rsector; + + return pd->make_request_fn(q, rw, new_bh); + +end_io: + buffer_IO_error(bh); + return 0; +} + +static void show_requests(request_queue_t *q) +{ + struct list_head *entry; + + spin_lock_irq(&io_request_lock); + + list_for_each(entry, &q->queue_head) { + struct request *rq = blkdev_entry_to_request(entry); + int zone = rq->sector & ~127; + int hole; + + hole = 0; + if ((rq->sector + rq->nr_sectors - (rq->bhtail->b_size >> 9)) + != rq->bhtail->b_rsector) + hole = 1; + + printk("rq: cmd %d, sector %lu (-> %lu), zone %u, hole %d, nr_sectors %lu\n", rq->cmd, rq->sector, rq->sector + rq->nr_sectors - 1, zone, hole, rq->nr_sectors); + } + + spin_unlock_irq(&io_request_lock); +} + +static void sysrq_handle_show_requests(int key, struct pt_regs *pt_regs, + struct kbd_struct *kbd, struct tty_struct *tty) +{ + /* + * quick hack to show pending requests in /dev/pktcdvd0 queue + */ + queue_proc *qp = blk_dev[PACKET_MAJOR].queue; + if (qp) { + request_queue_t *q = qp(MKDEV(PACKET_MAJOR, 0)); + if (q) + show_requests(q); + } +} +static struct sysrq_key_op sysrq_show_requests_op = { + handler: sysrq_handle_show_requests, + help_msg: "showreQuests", + action_msg: "Show requests", +}; + +static void pkt_init_queue(struct pktcdvd_device *pd) +{ + request_queue_t *q = &pd->cdrw.r_queue; + + blk_init_queue(q, pkt_request); + elevator_init(&q->elevator, ELEVATOR_PKTCDVD); + pd->make_request_fn = q->make_request_fn; + blk_queue_make_request(q, pkt_make_request); + blk_queue_headactive(q, 0); + q->front_merge_fn = pkt_front_merge_fn; + q->back_merge_fn = pkt_back_merge_fn; + q->merge_requests_fn = pkt_merge_requests_fn; + q->queuedata = pd; +} + +static int pkt_proc_device(struct pktcdvd_device *pd, char *buf) +{ + char *b = buf, *msg; + struct list_head *foo; + int i; + + b += sprintf(b, "\nWriter %s (%s):\n", pd->name, kdevname(pd->dev)); + + b += sprintf(b, "\nSettings:\n"); + b += sprintf(b, "\tpacket size:\t\t%dkB\n", pd->settings.size / 2); + + if (pd->settings.write_type == 0) + msg = "Packet"; + else + msg = "Unknown"; + b += sprintf(b, "\twrite type:\t\t%s\n", msg); + + b += sprintf(b, "\tpacket type:\t\t%s\n", pd->settings.fp ? "Fixed" : "Variable"); + b += sprintf(b, "\tlink loss:\t\t%d\n", pd->settings.link_loss); + + b += sprintf(b, "\ttrack mode:\t\t%d\n", pd->settings.track_mode); + + if (pd->settings.block_mode == PACKET_BLOCK_MODE1) + msg = "Mode 1"; + else if (pd->settings.block_mode == PACKET_BLOCK_MODE2) + msg = "Mode 2"; + else + msg = "Unknown"; + b += sprintf(b, "\tblock mode:\t\t%s\n", msg); + + b += sprintf(b, "\nStatistics:\n"); + b += sprintf(b, "\tbuffers started:\t%lu\n", pd->stats.bh_s); + b += sprintf(b, "\tbuffers ended:\t\t%lu\n", pd->stats.bh_e); + b += sprintf(b, "\tsectors written:\t%lu\n", pd->stats.secs_w); + b += sprintf(b, "\tsectors read:\t\t%lu\n", pd->stats.secs_r); + b += sprintf(b, "\tbuffer cache hits:\t%lu\n", pd->stats.bh_cache_hits); + b += sprintf(b, "\tpage cache hits:\t%lu\n", pd->stats.page_cache_hits); + + b += sprintf(b, "\nMisc:\n"); + b += sprintf(b, "\treference count:\t%d\n", atomic_read(&pd->refcnt)); + b += sprintf(b, "\tflags:\t\t\t0x%lx\n", pd->flags); + b += sprintf(b, "\twrite speed:\t\t%ukB/s\n", pd->speed * 150); + b += sprintf(b, "\tstart offset:\t\t%lu\n", pd->offset); + b += sprintf(b, "\tmode page offset:\t%u\n", pd->mode_offset); + + b += sprintf(b, "\nQueue state:\n"); + b += sprintf(b, "\tfree buffers:\t\t%u\n", atomic_read(&pd->cdrw.free_bh)); + b += sprintf(b, "\trequest active:\t\t%s\n", pd->rq ? "yes" : "no"); + b += sprintf(b, "\twrite rq depth:\t\t%d\n", atomic_read(&pd->wrqcnt)); + + spin_lock_irq(&io_request_lock); + i = 0; + list_for_each(foo, &pd->cdrw.r_queue.queue_head) + i++; + spin_unlock_irq(&io_request_lock); + b += sprintf(b, "\tqueue requests:\t\t%u\n", i); + + return b - buf; +} + +static int pkt_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + struct pktcdvd_device *pd = data; + char *buf = page; + int len; + + len = pkt_proc_device(pd, buf); + buf += len; + + if (len <= off + count) + *eof = 1; + + *start = page + off; + len -= off; + if (len > count) + len = count; + if (len < 0) + len = 0; + + return len; +} + +static int pkt_new_dev(struct pktcdvd_device *pd, kdev_t dev) +{ + struct cdrom_device_info *cdi; + request_queue_t *q; + int i; + + for (i = 0; i < MAX_WRITERS; i++) { + if (pkt_devs[i].dev == dev) { + printk("pktcdvd: %s already setup\n", kdevname(dev)); + return -EBUSY; + } + } + + for (i = 0; i < MAX_WRITERS; i++) + if (pd == &pkt_devs[i]) + break; + BUG_ON(i == MAX_WRITERS); + + cdi = cdrom_find_device(dev); + if (cdi == NULL) { + printk("pktcdvd: %s is not a CD-ROM\n", kdevname(dev)); + return -ENXIO; + } + + MOD_INC_USE_COUNT; + + memset(pd, 0, sizeof(struct pktcdvd_device)); + atomic_set(&pd->cdrw.free_bh, 0); + + spin_lock_init(&pd->lock); + if (pkt_grow_bhlist(pd, PACKET_MAX_SIZE) < PACKET_MAX_SIZE) { + MOD_DEC_USE_COUNT; + printk("pktcdvd: not enough memory for buffers\n"); + return -ENOMEM; + } + + pd->stacked_bhcnt = 0; + if (!pkt_grow_stacked_bhlist(pd)) { + MOD_DEC_USE_COUNT; + printk("pktcdvd: not enough memory for buffer heads\n"); + return -ENOMEM; + } + + set_blocksize(dev, CD_FRAMESIZE); + pd->cdi = cdi; + pd->dev = dev; + pd->bdev = NULL; + pd->pkt_dev = MKDEV(PACKET_MAJOR, i); + sprintf(pd->name, "pktcdvd%d", i); + atomic_set(&pd->refcnt, 0); + atomic_set(&pd->wrqcnt, 0); + init_MUTEX(&pd->cache_sync_mutex); + pd->unflushed_writes = 0; + init_waitqueue_head(&pd->wqueue); + init_completion(&pd->cdrw.thr_compl); + + /* + * store device merge functions (SCSI uses their own to build + * scatter-gather tables) + */ + q = blk_get_queue(dev); + pkt_init_queue(pd); + pd->cdrw.front_merge_fn = q->front_merge_fn; + pd->cdrw.back_merge_fn = q->back_merge_fn; + pd->cdrw.merge_requests_fn = q->merge_requests_fn; + pd->cdrw.queuedata = q->queuedata; + + pd->cdrw.time_to_die = 0; + pd->cdrw.pid = kernel_thread(kcdrwd, pd, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + if (pd->cdrw.pid < 0) { + MOD_DEC_USE_COUNT; + printk("pktcdvd: can't start kernel thread\n"); + blk_cleanup_queue(&pd->cdrw.r_queue); + pkt_shrink_stacked_bhlist(pd); + pkt_shrink_bhlist(pd, PACKET_MAX_SIZE); + memset(pd, 0, sizeof(*pd)); + return -EBUSY; + } + + create_proc_read_entry(pd->name, 0, pkt_proc, pkt_read_proc, pd); + DPRINTK("pktcdvd: writer %s sucessfully registered\n", cdi->name); + return 0; +} + +/* + * arg contains file descriptor of CD-ROM device. + */ +static int pkt_setup_dev(struct pktcdvd_device *pd, unsigned int arg) +{ + struct inode *inode; + struct file *file; + int ret; + + if ((file = fget(arg)) == NULL) { + printk("pktcdvd: bad file descriptor passed\n"); + return -EBADF; + } + + ret = -EINVAL; + if ((inode = file->f_dentry->d_inode) == NULL) { + printk("pktcdvd: huh? file descriptor contains no inode?\n"); + goto out; + } + ret = -ENOTBLK; + if (!S_ISBLK(inode->i_mode)) { + printk("pktcdvd: device is not a block device (duh)\n"); + goto out; + } + ret = -EROFS; + if (IS_RDONLY(inode)) { + printk("pktcdvd: Can't write to read-only dev\n"); + goto out; + } + if ((ret = pkt_new_dev(pd, inode->i_rdev))) { + printk("pktcdvd: all booked up\n"); + goto out; + } + + atomic_inc(&pd->refcnt); + +out: + fput(file); + return ret; +} + +static int pkt_remove_dev(struct pktcdvd_device *pd) +{ + int ret; + + if (pd->cdrw.pid >= 0) { + pd->cdrw.time_to_die = 1; + wmb(); + ret = kill_proc(pd->cdrw.pid, SIGKILL, 1); + if (ret) { + printk("pkt_exit: can't kill kernel thread\n"); + return ret; + } + wait_for_completion(&pd->cdrw.thr_compl); + } + + /* + * will also invalidate buffers for CD-ROM + */ + invalidate_device(pd->pkt_dev, 1); + + pkt_shrink_stacked_bhlist(pd); + if ((ret = pkt_shrink_bhlist(pd, PACKET_MAX_SIZE)) != PACKET_MAX_SIZE) + printk("pktcdvd: leaked %d buffers\n", PACKET_MAX_SIZE - ret); + + blk_cleanup_queue(&pd->cdrw.r_queue); + remove_proc_entry(pd->name, pkt_proc); + DPRINTK("pktcdvd: writer %s unregistered\n", pd->cdi->name); + memset(pd, 0, sizeof(struct pktcdvd_device)); + MOD_DEC_USE_COUNT; + return 0; +} + +static int pkt_media_change(kdev_t dev) +{ + struct pktcdvd_device *pd = pkt_find_dev(dev); + if (!pd) + return 0; + return cdrom_media_changed(pd->dev); +} + +static int pkt_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct pktcdvd_device *pd = &pkt_devs[MINOR(inode->i_rdev)]; + + VPRINTK("pkt_ioctl: cmd %d, dev %x\n", cmd, inode->i_rdev); + + if ((cmd != PACKET_SETUP_DEV) && !pd->dev) { + DPRINTK("pktcdvd: dev not setup\n"); + return -ENXIO; + } + + switch (cmd) { + case PACKET_GET_STATS: + if (copy_to_user(&arg, &pd->stats, sizeof(struct packet_stats))) + return -EFAULT; + break; + + case PACKET_SETUP_DEV: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (pd->dev) { + printk("pktcdvd: dev already setup\n"); + return -EBUSY; + } + return pkt_setup_dev(pd, arg); + + case PACKET_TEARDOWN_DEV: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (atomic_read(&pd->refcnt) != 1) + return -EBUSY; + return pkt_remove_dev(pd); + + case BLKGETSIZE: + return put_user(blk_size[PACKET_MAJOR][MINOR(inode->i_rdev)] << 1, (unsigned long *)arg); + + case BLKGETSIZE64: + return put_user((u64)blk_size[PACKET_MAJOR][MINOR(inode->i_rdev)] << 10, + (u64 *)arg); + + case BLKROSET: + if (capable(CAP_SYS_ADMIN)) + set_bit(PACKET_READONLY, &pd->flags); + case BLKROGET: + case BLKSSZGET: + case BLKRASET: + case BLKRAGET: + case BLKFLSBUF: + if (!pd->bdev) + return -ENXIO; + return blk_ioctl(inode->i_rdev, cmd, arg); + + /* + * forward selected CDROM ioctls to CD-ROM, for UDF + */ + case CDROMMULTISESSION: + case CDROMREADTOCENTRY: + case CDROM_LAST_WRITTEN: + case CDROM_SEND_PACKET: + case SCSI_IOCTL_SEND_COMMAND: + if (!pd->bdev) + return -ENXIO; + return ioctl_by_bdev(pd->bdev, cmd, arg); + + default: + printk("pktcdvd: Unknown ioctl for %s (%x)\n", pd->name, cmd); + return -ENOTTY; + } + + return 0; +} + +static struct block_device_operations pktcdvd_ops = { + owner: THIS_MODULE, + open: pkt_open, + release: pkt_close, + ioctl: pkt_ioctl, + check_media_change: pkt_media_change, +}; + +int pkt_init(void) +{ + int i; + + devfs_register(NULL, "pktcdvd", DEVFS_FL_DEFAULT, PACKET_MAJOR, 0, + S_IFBLK | S_IRUSR | S_IWUSR, &pktcdvd_ops, NULL); + if (devfs_register_blkdev(PACKET_MAJOR, "pktcdvd", &pktcdvd_ops)) { + printk("unable to register pktcdvd device\n"); + return -EIO; + } + + pkt_sizes = kmalloc(MAX_WRITERS * sizeof(int), GFP_KERNEL); + if (pkt_sizes == NULL) + goto err; + + pkt_blksize = kmalloc(MAX_WRITERS * sizeof(int), GFP_KERNEL); + if (pkt_blksize == NULL) + goto err; + + pkt_readahead = kmalloc(MAX_WRITERS * sizeof(int), GFP_KERNEL); + if (pkt_readahead == NULL) + goto err; + + pkt_devs = kmalloc(MAX_WRITERS * sizeof(struct pktcdvd_device), GFP_KERNEL); + if (pkt_devs == NULL) + goto err; + + memset(pkt_devs, 0, MAX_WRITERS * sizeof(struct pktcdvd_device)); + memset(pkt_sizes, 0, MAX_WRITERS * sizeof(int)); + memset(pkt_blksize, 0, MAX_WRITERS * sizeof(int)); + + for (i = 0; i < MAX_WRITERS; i++) + pkt_readahead[i] = vm_max_readahead; + + blk_size[PACKET_MAJOR] = pkt_sizes; + blksize_size[PACKET_MAJOR] = pkt_blksize; + max_readahead[PACKET_MAJOR] = pkt_readahead; + read_ahead[PACKET_MAJOR] = 128; + set_blocksize(MKDEV(PACKET_MAJOR, 0), CD_FRAMESIZE); + + blk_dev[PACKET_MAJOR].queue = pkt_get_queue; + + pkt_proc = proc_mkdir("pktcdvd", proc_root_driver); + + register_sysrq_key('q', &sysrq_show_requests_op); + + DPRINTK("pktcdvd: %s\n", VERSION_CODE); + return 0; + +err: + printk("pktcdvd: out of memory\n"); + devfs_unregister(devfs_find_handle(NULL, "pktcdvd", 0, 0, + DEVFS_SPECIAL_BLK, 0)); + devfs_unregister_blkdev(PACKET_MAJOR, "pktcdvd"); + kfree(pkt_devs); + kfree(pkt_sizes); + kfree(pkt_blksize); + kfree(pkt_readahead); + return -ENOMEM; +} + +void pkt_exit(void) +{ + unregister_sysrq_key('q', &sysrq_show_requests_op); + + devfs_unregister(devfs_find_handle(NULL, "pktcdvd", 0, 0, + DEVFS_SPECIAL_BLK, 0)); + devfs_unregister_blkdev(PACKET_MAJOR, "pktcdvd"); + blk_dev[PACKET_MAJOR].queue = NULL; + + remove_proc_entry("pktcdvd", proc_root_driver); + kfree(pkt_sizes); + kfree(pkt_blksize); + kfree(pkt_devs); + kfree(pkt_readahead); +} + +MODULE_DESCRIPTION("Packet writing layer for CD/DVD drives"); +MODULE_AUTHOR("Jens Axboe "); +MODULE_LICENSE("GPL"); + +module_init(pkt_init); +module_exit(pkt_exit); diff -u -r -N ../../linus/2.4/linux/drivers/cdrom/Makefile linux/drivers/cdrom/Makefile --- ../../linus/2.4/linux/drivers/cdrom/Makefile 2003-08-03 23:22:01.000000000 +0200 +++ linux/drivers/cdrom/Makefile 2003-08-03 23:30:14.000000000 +0200 @@ -27,6 +27,7 @@ obj-$(CONFIG_BLK_DEV_IDECD) += cdrom.o obj-$(CONFIG_BLK_DEV_SR) += cdrom.o obj-$(CONFIG_PARIDE_PCD) += cdrom.o +obj-$(CONFIG_CDROM_PKTCDVD) += cdrom.o obj-$(CONFIG_AZTCD) += aztcd.o obj-$(CONFIG_CDU31A) += cdu31a.o cdrom.o diff -u -r -N ../../linus/2.4/linux/drivers/ide/ide-cd.c linux/drivers/ide/ide-cd.c --- ../../linus/2.4/linux/drivers/ide/ide-cd.c 2003-08-23 21:25:25.000000000 +0200 +++ linux/drivers/ide/ide-cd.c 2003-08-23 22:26:42.000000000 +0200 @@ -292,9 +292,11 @@ * correctly reporting tray status -- from * Michael D Johnson * + * 4.99 - Added write support for packet writing. + * *************************************************************************/ -#define IDECD_VERSION "4.59-ac1" +#define IDECD_VERSION "4.99" #include #include @@ -526,7 +528,7 @@ memset(pc, 0, sizeof(struct packet_command)); pc->c[0] = GPCMD_REQUEST_SENSE; - pc->c[4] = pc->buflen = 18; + pc->c[4] = pc->buflen = 14; pc->buffer = (char *) sense; pc->sense = (struct request_sense *) failed_command; @@ -774,7 +776,7 @@ cdrom_saw_media_change (drive); /* Fail the request. */ - printk ("%s: tray open\n", drive->name); + /* printk ("%s: tray open\n", drive->name); */ do_end_request = 1; } else if (sense_key == UNIT_ATTENTION) { /* Media change. */ @@ -1351,6 +1353,8 @@ * partitions not really working, but better check anyway... */ if (rq->cmd == nxt->cmd && rq->rq_dev == nxt->rq_dev) { + if (rq->cmd == WRITE) + printk("merged write\n"); rq->nr_sectors += nxt->nr_sectors; rq->hard_nr_sectors += nxt->nr_sectors; rq->bhtail->b_reqnext = nxt->bh; @@ -2657,6 +2661,12 @@ static void ide_cdrom_release_real (struct cdrom_device_info *cdi) { + struct cdrom_generic_command cgc; + + init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); + cgc.cmd[0] = GPCMD_FLUSH_CACHE; + cgc.quiet = 1; + (void) ide_cdrom_packet(cdi, &cgc); } @@ -2844,15 +2854,10 @@ printk(" %dX", CDROM_CONFIG_FLAGS(drive)->max_speed); printk(" %s", CDROM_CONFIG_FLAGS(drive)->dvd ? "DVD-ROM" : "CD-ROM"); - if (CDROM_CONFIG_FLAGS(drive)->dvd_r|CDROM_CONFIG_FLAGS(drive)->dvd_ram) - printk(" DVD%s%s", - (CDROM_CONFIG_FLAGS(drive)->dvd_r)? "-R" : "", - (CDROM_CONFIG_FLAGS(drive)->dvd_ram)? "-RAM" : ""); - - if (CDROM_CONFIG_FLAGS(drive)->cd_r|CDROM_CONFIG_FLAGS(drive)->cd_rw) - printk(" CD%s%s", - (CDROM_CONFIG_FLAGS(drive)->cd_r)? "-R" : "", - (CDROM_CONFIG_FLAGS(drive)->cd_rw)? "/RW" : ""); + if (CDROM_CONFIG_FLAGS(drive)->dvd_r || CDROM_CONFIG_FLAGS(drive)->dvd_ram) + printk (" DVD-R%s", (CDROM_CONFIG_FLAGS (drive)->dvd_ram)? "AM" : ""); + if (CDROM_CONFIG_FLAGS(drive)->cd_r ||CDROM_CONFIG_FLAGS(drive)->cd_rw) + printk (" CD-R%s", (CDROM_CONFIG_FLAGS (drive)->cd_rw)? "/RW" : ""); if (CDROM_CONFIG_FLAGS(drive)->is_changer) printk(" changer w/%d slots", nslots); @@ -2875,7 +2880,7 @@ int major = HWIF(drive)->major; int minor = drive->select.b.unit << PARTN_BITS; - ide_add_setting(drive, "breada_readahead", SETTING_RW, BLKRAGET, BLKRASET, TYPE_INT, 0, 255, 1, 2, &read_ahead[major], NULL); + ide_add_setting(drive, "breada_readahead", SETTING_RW, BLKRAGET, BLKRASET, TYPE_INT, 0, 255, 1, 1024, &read_ahead[major], NULL); ide_add_setting(drive, "file_readahead", SETTING_RW, BLKFRAGET, BLKFRASET, TYPE_INTA, 0, INT_MAX, 1, 1024, &max_readahead[major][minor], NULL); ide_add_setting(drive, "max_kb_per_request", SETTING_RW, BLKSECTGET, BLKSECTSET, TYPE_INTA, 1, 255, 1, 2, &max_sectors[major][minor], NULL); ide_add_setting(drive, "dsc_overlap", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->dsc_overlap, NULL); @@ -2892,7 +2897,7 @@ /* * default to read-only always and fix latter at the bottom */ - set_device_ro(MKDEV(HWIF(drive)->major, minor), 1); + set_device_ro(MKDEV(HWIF(drive)->major, minor), 0); set_blocksize(MKDEV(HWIF(drive)->major, minor), CD_FRAMESIZE); drive->special.all = 0; diff -u -r -N ../../linus/2.4/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in --- ../../linus/2.4/linux/drivers/scsi/Config.in 2003-08-23 21:25:26.000000000 +0200 +++ linux/drivers/scsi/Config.in 2003-08-23 22:26:59.000000000 +0200 @@ -20,10 +20,6 @@ comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs' -#if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool ' Enable extra checks in new queueing code' CONFIG_SCSI_DEBUG_QUEUES -#fi - bool ' Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN bool ' Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS diff -u -r -N ../../linus/2.4/linux/drivers/scsi/scsi_merge.c linux/drivers/scsi/scsi_merge.c --- ../../linus/2.4/linux/drivers/scsi/scsi_merge.c 2003-08-03 23:22:55.000000000 +0200 +++ linux/drivers/scsi/scsi_merge.c 2003-08-03 23:31:05.000000000 +0200 @@ -77,11 +77,6 @@ */ #define DMA_SEGMENT_SIZE_LIMITED -#ifdef CONFIG_SCSI_DEBUG_QUEUES -/* - * Enable a bunch of additional consistency checking. Turn this off - * if you are benchmarking. - */ static int dump_stats(struct request *req, int use_clustering, int dma_host, @@ -106,22 +101,6 @@ panic("Ththththaats all folks. Too dangerous to continue.\n"); } - -/* - * Simple sanity check that we will use for the first go around - * in order to ensure that we are doing the counting correctly. - * This can be removed for optimization. - */ -#define SANITY_CHECK(req, _CLUSTER, _DMA) \ - if( req->nr_segments != __count_segments(req, _CLUSTER, _DMA, NULL) ) \ - { \ - printk("Incorrect segment count at 0x%p", current_text_addr()); \ - dump_stats(req, _CLUSTER, _DMA, __count_segments(req, _CLUSTER, _DMA, NULL)); \ - } -#else -#define SANITY_CHECK(req, _CLUSTER, _DMA) -#endif - static void dma_exhausted(Scsi_Cmnd * SCpnt, int i) { int jj; @@ -537,7 +516,6 @@ int max_segments) \ { \ int ret; \ - SANITY_CHECK(req, _CLUSTER, _DMA); \ ret = __scsi_ ## _BACK_FRONT ## _merge_fn(q, \ req, \ bh, \ @@ -747,7 +725,6 @@ int max_segments) \ { \ int ret; \ - SANITY_CHECK(req, _CLUSTER, _DMA); \ ret = __scsi_merge_requests_fn(q, req, next, max_segments, _CLUSTER, _DMA); \ return ret; \ } @@ -810,11 +787,7 @@ /* * First we need to know how many scatter gather segments are needed. */ - if (!sg_count_valid) { - count = __count_segments(req, use_clustering, dma_host, NULL); - } else { - count = req->nr_segments; - } + count = __count_segments(req, use_clustering, dma_host, NULL); /* * If the dma pool is nearly empty, then queue a minimal request @@ -956,9 +929,7 @@ */ if (count != SCpnt->use_sg) { printk("Incorrect number of segments after building list\n"); -#ifdef CONFIG_SCSI_DEBUG_QUEUES dump_stats(req, use_clustering, dma_host, count); -#endif } if (!dma_host) { return 1; diff -u -r -N ../../linus/2.4/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c --- ../../linus/2.4/linux/drivers/scsi/sr.c 2003-08-03 23:22:55.000000000 +0200 +++ linux/drivers/scsi/sr.c 2003-08-03 23:31:05.000000000 +0200 @@ -28,12 +28,16 @@ * Modified by Jens Axboe - support DVD-RAM * transparently and loose the GHOST hack * + * Modified by Jens Axboe - support packet writing + * through generic packet layer. + * * Modified by Arnaldo Carvalho de Melo * check resource allocation in sr_init and some cleanups * */ #include +#include #include #include @@ -719,7 +723,7 @@ cmd[2] = 0x2a; cmd[4] = 128; cmd[3] = cmd[5] = 0; - rc = sr_do_ioctl(i, cmd, buffer, 128, 1, SCSI_DATA_READ, NULL); + rc = sr_do_ioctl(i, cmd, buffer, 128, 1, SCSI_DATA_READ, NULL, SR_TIMEOUT); if (rc) { /* failed, drive doesn't have capabilities mode page */ @@ -751,16 +755,13 @@ if ((buffer[n + 2] & 0x8) == 0) /* not a DVD drive */ scsi_CDs[i].cdi.mask |= CDC_DVD; - if ((buffer[n + 3] & 0x20) == 0) { + if ((buffer[n + 3] & 0x20) == 0) /* can't write DVD-RAM media */ scsi_CDs[i].cdi.mask |= CDC_DVD_RAM; - } else { - scsi_CDs[i].device->writeable = 1; - } if ((buffer[n + 3] & 0x10) == 0) /* can't write DVD-R media */ scsi_CDs[i].cdi.mask |= CDC_DVD_R; - if ((buffer[n + 3] & 0x2) == 0) + if ((buffer[n + 3] & 0x02) == 0) /* can't write CD-RW media */ scsi_CDs[i].cdi.mask |= CDC_CD_RW; if ((buffer[n + 3] & 0x1) == 0) @@ -780,6 +781,10 @@ /*else I don't think it can close its tray scsi_CDs[i].cdi.mask |= CDC_CLOSE_TRAY; */ + if (~scsi_CDs[i].cdi.mask & (CDC_DVD_RAM | CDC_CD_RW)) + /* can write to DVD-RAM or CD-RW */ + scsi_CDs[i].device->writeable = 1; + scsi_free(buffer, 512); } @@ -795,7 +800,10 @@ if (device->scsi_level <= SCSI_2) cgc->cmd[1] |= device->lun << 5; - cgc->stat = sr_do_ioctl(MINOR(cdi->dev), cgc->cmd, cgc->buffer, cgc->buflen, cgc->quiet, cgc->data_direction, cgc->sense); + if (cgc->timeout <= 0) + cgc->timeout = 5 * HZ; + + cgc->stat = sr_do_ioctl(MINOR(cdi->dev), cgc->cmd, cgc->buffer, cgc->buflen, cgc->quiet, cgc->data_direction, cgc->sense, cgc->timeout); return cgc->stat; } diff -u -r -N ../../linus/2.4/linux/drivers/scsi/sr.h linux/drivers/scsi/sr.h --- ../../linus/2.4/linux/drivers/scsi/sr.h 2003-08-03 23:22:55.000000000 +0200 +++ linux/drivers/scsi/sr.h 2003-08-03 23:31:05.000000000 +0200 @@ -36,7 +36,7 @@ extern Scsi_CD *scsi_CDs; -int sr_do_ioctl(int, unsigned char *, void *, unsigned, int, int, struct request_sense *); +int sr_do_ioctl(int, unsigned char *, void *, unsigned, int, int, struct request_sense *, int); int sr_lock_door(struct cdrom_device_info *, int); int sr_tray_move(struct cdrom_device_info *, int); diff -u -r -N ../../linus/2.4/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c --- ../../linus/2.4/linux/drivers/scsi/sr_ioctl.c 2003-08-03 23:22:55.000000000 +0200 +++ linux/drivers/scsi/sr_ioctl.c 2003-08-03 23:31:05.000000000 +0200 @@ -68,14 +68,14 @@ sr_cmd[6] = trk1_te.cdte_addr.msf.minute; sr_cmd[7] = trk1_te.cdte_addr.msf.second; sr_cmd[8] = trk1_te.cdte_addr.msf.frame; - return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL); + return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL, IOCTL_TIMEOUT); } /* We do our own retries because we want to know what the specific error code is. Normally the UNIT_ATTENTION code will automatically clear after one error */ -int sr_do_ioctl(int target, unsigned char *sr_cmd, void *buffer, unsigned buflength, int quiet, int readwrite, struct request_sense *sense) +int sr_do_ioctl(int target, unsigned char *sr_cmd, void *buffer, unsigned buflength, int quiet, int readwrite, struct request_sense *sense, int timeout) { Scsi_Request *SRpnt; Scsi_Device *SDev; @@ -109,7 +109,7 @@ scsi_wait_req(SRpnt, (void *) sr_cmd, (void *) buffer, buflength, - IOCTL_TIMEOUT, IOCTL_RETRIES); + timeout, IOCTL_RETRIES); req = &SRpnt->sr_request; if (SRpnt->sr_buffer && req->buffer && SRpnt->sr_buffer != req->buffer) { @@ -196,7 +196,7 @@ sr_cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ? ((scsi_CDs[minor].device->lun) << 5) : 0; sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0; - return sr_do_ioctl(minor, sr_cmd, NULL, 0, 1, SCSI_DATA_NONE, NULL); + return sr_do_ioctl(minor, sr_cmd, NULL, 0, 1, SCSI_DATA_NONE, NULL, IOCTL_TIMEOUT); } int sr_tray_move(struct cdrom_device_info *cdi, int pos) @@ -209,7 +209,7 @@ sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0; sr_cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */ ; - return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL); + return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL, IOCTL_TIMEOUT); } int sr_lock_door(struct cdrom_device_info *cdi, int lock) @@ -287,7 +287,7 @@ sr_cmd[8] = 24; sr_cmd[9] = 0; - result = sr_do_ioctl(MINOR(cdi->dev), sr_cmd, buffer, 24, 0, SCSI_DATA_READ, NULL); + result = sr_do_ioctl(MINOR(cdi->dev), sr_cmd, buffer, 24, 0, SCSI_DATA_READ, NULL, IOCTL_TIMEOUT); memcpy(mcn->medium_catalog_number, buffer + 9, 13); mcn->medium_catalog_number[13] = 0; @@ -317,7 +317,7 @@ sr_cmd[2] = (speed >> 8) & 0xff; /* MSB for speed (in kbytes/sec) */ sr_cmd[3] = speed & 0xff; /* LSB */ - if (sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL)) + if (sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL, IOCTL_TIMEOUT)) return -EIO; return 0; } @@ -347,7 +347,7 @@ sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0; sr_cmd[8] = 12; /* LSB of length */ - result = sr_do_ioctl(target, sr_cmd, buffer, 12, 1, SCSI_DATA_READ, NULL); + result = sr_do_ioctl(target, sr_cmd, buffer, 12, 1, SCSI_DATA_READ, NULL, IOCTL_TIMEOUT); tochdr->cdth_trk0 = buffer[2]; tochdr->cdth_trk1 = buffer[3]; @@ -367,7 +367,7 @@ sr_cmd[6] = tocentry->cdte_track; sr_cmd[8] = 12; /* LSB of length */ - result = sr_do_ioctl(target, sr_cmd, buffer, 12, 0, SCSI_DATA_READ, NULL); + result = sr_do_ioctl(target, sr_cmd, buffer, 12, 0, SCSI_DATA_READ, NULL, IOCTL_TIMEOUT); tocentry->cdte_ctrl = buffer[5] & 0xf; tocentry->cdte_adr = buffer[5] >> 4; @@ -394,7 +394,7 @@ sr_cmd[7] = ti->cdti_trk1; sr_cmd[8] = ti->cdti_ind1; - result = sr_do_ioctl(target, sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL); + result = sr_do_ioctl(target, sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL, IOCTL_TIMEOUT); if (result == -EDRIVE_CANT_DO_THIS) result = sr_fake_playtrkind(cdi, ti); @@ -460,7 +460,7 @@ cmd[9] = 0x10; break; } - return sr_do_ioctl(minor, cmd, dest, blksize, 0, SCSI_DATA_READ, NULL); + return sr_do_ioctl(minor, cmd, dest, blksize, 0, SCSI_DATA_READ, NULL, IOCTL_TIMEOUT); } /* @@ -499,7 +499,7 @@ cmd[4] = (unsigned char) (lba >> 8) & 0xff; cmd[5] = (unsigned char) lba & 0xff; cmd[8] = 1; - rc = sr_do_ioctl(minor, cmd, dest, blksize, 0, SCSI_DATA_READ, NULL); + rc = sr_do_ioctl(minor, cmd, dest, blksize, 0, SCSI_DATA_READ, NULL, IOCTL_TIMEOUT); return rc; } diff -u -r -N ../../linus/2.4/linux/drivers/scsi/sr_vendor.c linux/drivers/scsi/sr_vendor.c --- ../../linus/2.4/linux/drivers/scsi/sr_vendor.c 2003-08-03 23:22:55.000000000 +0200 +++ linux/drivers/scsi/sr_vendor.c 2003-08-03 23:31:05.000000000 +0200 @@ -60,6 +60,8 @@ #define VENDOR_ID (scsi_CDs[minor].vendor) +#define VENDOR_TIMEOUT 30*HZ + void sr_vendor_init(int minor) { #ifndef CONFIG_BLK_DEV_SR_VENDOR @@ -134,7 +136,7 @@ modesel->density = density; modesel->block_length_med = (blocklength >> 8) & 0xff; modesel->block_length_lo = blocklength & 0xff; - if (0 == (rc = sr_do_ioctl(minor, cmd, buffer, sizeof(*modesel), 0, SCSI_DATA_WRITE, NULL))) { + if (0 == (rc = sr_do_ioctl(minor, cmd, buffer, sizeof(*modesel), 0, SCSI_DATA_WRITE, NULL, VENDOR_TIMEOUT))) { scsi_CDs[minor].device->sector_size = blocklength; } #ifdef DEBUG @@ -179,7 +181,7 @@ (scsi_CDs[minor].device->lun << 5) : 0; cmd[8] = 12; cmd[9] = 0x40; - rc = sr_do_ioctl(minor, cmd, buffer, 12, 1, SCSI_DATA_READ, NULL); + rc = sr_do_ioctl(minor, cmd, buffer, 12, 1, SCSI_DATA_READ, NULL, VENDOR_TIMEOUT); if (rc != 0) break; if ((buffer[0] << 8) + buffer[1] < 0x0a) { @@ -205,7 +207,7 @@ (scsi_CDs[minor].device->lun << 5) : 0; cmd[1] |= 0x03; cmd[2] = 0xb0; - rc = sr_do_ioctl(minor, cmd, buffer, 0x16, 1, SCSI_DATA_READ, NULL); + rc = sr_do_ioctl(minor, cmd, buffer, 0x16, 1, SCSI_DATA_READ, NULL, VENDOR_TIMEOUT); if (rc != 0) break; if (buffer[14] != 0 && buffer[14] != 0xb0) { @@ -231,7 +233,7 @@ cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ? (scsi_CDs[minor].device->lun << 5) : 0; cmd[1] |= 0x03; - rc = sr_do_ioctl(minor, cmd, buffer, 4, 1, SCSI_DATA_READ, NULL); + rc = sr_do_ioctl(minor, cmd, buffer, 4, 1, SCSI_DATA_READ, NULL, VENDOR_TIMEOUT); if (rc == -EINVAL) { printk(KERN_INFO "sr%d: Hmm, seems the drive " "doesn't support multisession CD's\n", minor); @@ -257,7 +259,7 @@ (scsi_CDs[minor].device->lun << 5) : 0; cmd[8] = 0x04; cmd[9] = 0x40; - rc = sr_do_ioctl(minor, cmd, buffer, 0x04, 1, SCSI_DATA_READ, NULL); + rc = sr_do_ioctl(minor, cmd, buffer, 0x04, 1, SCSI_DATA_READ, NULL, VENDOR_TIMEOUT); if (rc != 0) { break; } @@ -272,7 +274,7 @@ cmd[6] = rc & 0x7f; /* number of last session */ cmd[8] = 0x0c; cmd[9] = 0x40; - rc = sr_do_ioctl(minor, cmd, buffer, 12, 1, SCSI_DATA_READ, NULL); + rc = sr_do_ioctl(minor, cmd, buffer, 12, 1, SCSI_DATA_READ, NULL, VENDOR_TIMEOUT); if (rc != 0) { break; } diff -u -r -N ../../linus/2.4/linux/fs/udf/balloc.c linux/fs/udf/balloc.c --- ../../linus/2.4/linux/fs/udf/balloc.c 2003-08-03 23:23:24.000000000 +0200 +++ linux/fs/udf/balloc.c 2003-08-03 23:31:41.000000000 +0200 @@ -144,7 +144,11 @@ } static void udf_bitmap_free_blocks(struct super_block * sb, +#ifndef OLD_QUOTA struct inode * inode, +#else + const struct inode * inode, +#endif struct udf_bitmap *bitmap, lb_addr bloc, uint32_t offset, uint32_t count) { struct buffer_head * bh = NULL; @@ -195,7 +199,11 @@ else { if (inode) +#ifndef OLD_QUOTA DQUOT_FREE_BLOCK(inode, 1); +#else + DQUOT_FREE_BLOCK(sb, inode, 1); +#endif if (UDF_SB_LVIDBH(sb)) { UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)] = @@ -219,7 +227,11 @@ } static int udf_bitmap_prealloc_blocks(struct super_block * sb, +#ifndef OLD_QUOTA struct inode * inode, +#else + const struct inode * inode, +#endif struct udf_bitmap *bitmap, uint16_t partition, uint32_t first_block, uint32_t block_count) { @@ -254,12 +266,20 @@ { if (!udf_test_bit(bit, bh->b_data)) goto out; +#ifndef OLD_QUOTA else if (DQUOT_PREALLOC_BLOCK(inode, 1)) +#else + else if (DQUOT_PREALLOC_BLOCK(sb, inode, 1)) +#endif goto out; else if (!udf_clear_bit(bit, bh->b_data)) { udf_debug("bit already cleared for block %d\n", bit); +#ifndef OLD_QUOTA DQUOT_FREE_BLOCK(inode, 1); +#else + DQUOT_FREE_BLOCK(sb, inode, 1); +#endif goto out; } block_count --; @@ -283,7 +303,11 @@ } static int udf_bitmap_new_block(struct super_block * sb, +#ifndef OLD_QUOTA struct inode * inode, +#else + const struct inode * inode, +#endif struct udf_bitmap *bitmap, uint16_t partition, uint32_t goal, int *err) { int newbit, bit=0, block, block_group, group_start; @@ -387,7 +411,11 @@ /* * Check quota for allocation of this block. */ +#ifndef OLD_QUOTA if (inode && DQUOT_ALLOC_BLOCK(inode, 1)) +#else + if (inode && DQUOT_ALLOC_BLOCK(sb, inode, 1)) +#endif { unlock_super(sb); *err = -EDQUOT; @@ -423,7 +451,11 @@ } static void udf_table_free_blocks(struct super_block * sb, +#ifndef OLD_QUOTA struct inode * inode, +#else + const struct inode * inode, +#endif struct inode * table, lb_addr bloc, uint32_t offset, uint32_t count) { uint32_t start, end; @@ -446,7 +478,11 @@ /* We do this up front - There are some error conditions that could occure, but.. oh well */ if (inode) +#ifndef OLD_QUOTA DQUOT_FREE_BLOCK(inode, count); +#else + DQUOT_FREE_BLOCK(sb, inode, count); +#endif if (UDF_SB_LVIDBH(sb)) { UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)] = @@ -461,8 +497,7 @@ elen = 0; obloc = nbloc = UDF_I_LOCATION(table); - obh = nbh = udf_tread(sb, udf_get_lb_pblock(sb, nbloc, 0)); - atomic_inc(&nbh->b_count); + obh = nbh = NULL; while (count && (etype = udf_next_aext(table, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1)) != -1) @@ -506,7 +541,7 @@ udf_write_aext(table, obloc, &oextoffset, eloc, elen, obh, 1); } - if (memcmp(&nbloc, &obloc, sizeof(lb_addr))) + if (nbh != obh) { i = -1; obloc = nbloc; @@ -580,7 +615,10 @@ { loffset = nextoffset; aed->lengthAllocDescs = cpu_to_le32(adsize); - sptr = (obh)->b_data + nextoffset - adsize; + if (obh) + sptr = UDF_I_DATA(inode) + nextoffset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode) - adsize; + else + sptr = obh->b_data + nextoffset - adsize; dptr = nbh->b_data + sizeof(struct allocExtDesc); memcpy(dptr, sptr, adsize); nextoffset = sizeof(struct allocExtDesc) + adsize; @@ -591,8 +629,8 @@ aed->lengthAllocDescs = cpu_to_le32(0); sptr = (obh)->b_data + nextoffset; nextoffset = sizeof(struct allocExtDesc); - - if (memcmp(&UDF_I_LOCATION(table), &obloc, sizeof(lb_addr))) + + if (obh) { aed = (struct allocExtDesc *)(obh)->b_data; aed->lengthAllocDescs = @@ -631,15 +669,20 @@ break; } } - udf_update_tag(obh->b_data, loffset); - mark_buffer_dirty(obh); + if (obh) + { + udf_update_tag(obh->b_data, loffset); + mark_buffer_dirty(obh); + } + else + mark_inode_dirty(table); } if (elen) /* It's possible that stealing the block emptied the extent */ { udf_write_aext(table, nbloc, &nextoffset, eloc, elen, nbh, 1); - if (!memcmp(&UDF_I_LOCATION(table), &nbloc, sizeof(lb_addr))) + if (!nbh) { UDF_I_LENALLOC(table) += adsize; mark_inode_dirty(table); @@ -665,7 +708,11 @@ } static int udf_table_prealloc_blocks(struct super_block * sb, +#ifndef OLD_QUOTA struct inode * inode, +#else + const struct inode * inode, +#endif struct inode *table, uint16_t partition, uint32_t first_block, uint32_t block_count) { @@ -690,7 +737,7 @@ extoffset = sizeof(struct unallocSpaceEntry); bloc = UDF_I_LOCATION(table); - bh = udf_tread(sb, udf_get_lb_pblock(sb, bloc, 0)); + bh = NULL; eloc.logicalBlockNum = 0xFFFFFFFF; while (first_block != eloc.logicalBlockNum && (etype = @@ -706,7 +753,11 @@ extoffset -= adsize; alloc_count = (elen >> sb->s_blocksize_bits); +#ifndef OLD_QUOTA if (inode && DQUOT_PREALLOC_BLOCK(inode, alloc_count > block_count ? block_count : alloc_count)) +#else + if (inode && DQUOT_PREALLOC_BLOCK(sb, inode, alloc_count > block_count ? block_count : alloc_count)) +#endif alloc_count = 0; else if (alloc_count > block_count) { @@ -735,7 +786,11 @@ } static int udf_table_new_block(struct super_block * sb, +#ifndef OLD_QUOTA struct inode * inode, +#else + const struct inode * inode, +#endif struct inode *table, uint16_t partition, uint32_t goal, int *err) { uint32_t spread = 0xFFFFFFFF, nspread = 0xFFFFFFFF; @@ -768,8 +823,7 @@ extoffset = sizeof(struct unallocSpaceEntry); bloc = UDF_I_LOCATION(table); - goal_bh = bh = udf_tread(sb, udf_get_lb_pblock(sb, bloc, 0)); - atomic_inc(&goal_bh->b_count); + goal_bh = bh = NULL; while (spread && (etype = udf_next_aext(table, &bloc, &extoffset, &eloc, &elen, &bh, 1)) != -1) @@ -819,7 +873,11 @@ goal_eloc.logicalBlockNum ++; goal_elen -= sb->s_blocksize; +#ifndef OLD_QUOTA if (inode && DQUOT_ALLOC_BLOCK(inode, 1)) +#else + if (inode && DQUOT_ALLOC_BLOCK(sb, inode, 1)) +#endif { udf_release_data(goal_bh); unlock_super(sb); @@ -847,7 +905,11 @@ } inline void udf_free_blocks(struct super_block * sb, +#ifndef OLD_QUOTA struct inode * inode, +#else + const struct inode * inode, +#endif lb_addr bloc, uint32_t offset, uint32_t count) { uint16_t partition = bloc.partitionReferenceNum; @@ -881,7 +943,11 @@ } inline int udf_prealloc_blocks(struct super_block * sb, +#ifndef OLD_QUOTA struct inode * inode, +#else + const struct inode * inode, +#endif uint16_t partition, uint32_t first_block, uint32_t block_count) { if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP) @@ -913,7 +979,11 @@ } inline int udf_new_block(struct super_block * sb, +#ifndef OLD_QUOTA struct inode * inode, +#else + const struct inode * inode, +#endif uint16_t partition, uint32_t goal, int *err) { if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP) diff -u -r -N ../../linus/2.4/linux/fs/udf/dir.c linux/fs/udf/dir.c --- ../../linus/2.4/linux/fs/udf/dir.c 2003-08-03 23:23:24.000000000 +0200 +++ linux/fs/udf/dir.c 2003-08-03 23:31:41.000000000 +0200 @@ -104,7 +104,7 @@ int block, iblock; loff_t nf_pos = filp->f_pos - 1; int flen; - char fname[255]; + char fname[UDF_NAME_LEN]; char *nameptr; uint16_t liu; uint8_t lfi; @@ -122,7 +122,9 @@ nf_pos = (udf_ext0_offset(dir) >> 2); fibh.soffset = fibh.eoffset = (nf_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2; - if (inode_bmap(dir, nf_pos >> (dir->i_sb->s_blocksize_bits - 2), + if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) + fibh.sbh = fibh.ebh = NULL; + else if (inode_bmap(dir, nf_pos >> (dir->i_sb->s_blocksize_bits - 2), &bloc, &extoffset, &eloc, &elen, &offset, &bh) == (EXT_RECORDED_ALLOCATED >> 30)) { offset >>= dir->i_sb->s_blocksize_bits; @@ -136,6 +138,34 @@ } else offset = 0; + + if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block))) + { + udf_release_data(bh); + return -EIO; + } + + if (!(offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9))-1))) + { + i = 16 >> (dir->i_sb->s_blocksize_bits - 9); + if (i+offset > (elen >> dir->i_sb->s_blocksize_bits)) + i = (elen >> dir->i_sb->s_blocksize_bits)-offset; + for (num=0; i>0; i--) + { + block = udf_get_lb_pblock(dir->i_sb, eloc, offset+i); + tmp = udf_tgetblk(dir->i_sb, block); + if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp)) + bha[num++] = tmp; + else + brelse(tmp); + } + if (num) + { + ll_rw_block(READA, num, bha); + for (i=0; ii_sb, block))) - { - udf_release_data(bh); - return -EIO; - } - - if (!(offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9))-1))) - { - i = 16 >> (dir->i_sb->s_blocksize_bits - 9); - if (i+offset > (elen >> dir->i_sb->s_blocksize_bits)) - i = (elen >> dir->i_sb->s_blocksize_bits)-offset; - for (num=0; i>0; i--) - { - block = udf_get_lb_pblock(dir->i_sb, eloc, offset+i); - tmp = udf_tgetblk(dir->i_sb, block); - if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp)) - bha[num++] = tmp; - else - brelse(tmp); - } - if (num) - { - ll_rw_block(READA, num, bha); - for (i=0; if_pos = nf_pos + 1; diff -u -r -N ../../linus/2.4/linux/fs/udf/directory.c linux/fs/udf/directory.c --- ../../linus/2.4/linux/fs/udf/directory.c 2003-08-03 23:23:24.000000000 +0200 +++ linux/fs/udf/directory.c 2003-08-03 23:31:41.000000000 +0200 @@ -17,6 +17,7 @@ */ #include "udfdecl.h" +#include "udf_i.h" #include #include @@ -84,6 +85,24 @@ fibh->soffset = fibh->eoffset; + if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) + { + fi = udf_get_fileident(UDF_I_DATA(dir) - + (UDF_I_EFE(dir) ? + sizeof(struct extendedFileEntry) : + sizeof(struct fileEntry)), + dir->i_sb->s_blocksize, &(fibh->eoffset)); + + if (!fi) + return NULL; + + *nf_pos += ((fibh->eoffset - fibh->soffset) >> 2); + + memcpy((uint8_t *)cfi, (uint8_t *)fi, sizeof(struct fileIdentDesc)); + + return fi; + } + if (fibh->eoffset == dir->i_sb->s_blocksize) { int lextoffset = *extoffset; @@ -275,53 +294,43 @@ } short_ad * -udf_get_fileshortad(void * buffer, int maxoffset, int *offset, int inc) +udf_get_fileshortad(uint8_t *ptr, int maxoffset, int *offset, int inc) { - short_ad * sa; - uint8_t * ptr; + short_ad *sa; - if ( (!buffer) || (!offset) ) + if ( (!ptr) || (!offset) ) { printk(KERN_ERR "udf: udf_get_fileshortad() invalidparms\n"); return NULL; } - ptr = (uint8_t *)buffer; - - if ( (*offset > 0) && (*offset < maxoffset) ) - ptr += *offset; - else + if ( (*offset < 0) || ((*offset + sizeof(short_ad)) > maxoffset) ) return NULL; - - if ((sa = (short_ad *)ptr)->extLength == 0) + else if ((sa = (short_ad *)ptr)->extLength == 0) return NULL; - else if (inc) - (*offset) += sizeof(short_ad); + + if (inc) + *offset += sizeof(short_ad); return sa; } long_ad * -udf_get_filelongad(void * buffer, int maxoffset, int * offset, int inc) +udf_get_filelongad(uint8_t *ptr, int maxoffset, int * offset, int inc) { - long_ad * la; - uint8_t * ptr; + long_ad *la; - if ( (!buffer) || !(offset) ) + if ( (!ptr) || (!offset) ) { printk(KERN_ERR "udf: udf_get_filelongad() invalidparms\n"); return NULL; } - ptr = (uint8_t *)buffer; - - if ( (*offset > 0) && (*offset < maxoffset) ) - ptr += *offset; - else + if ( (*offset < 0) || ((*offset + sizeof(long_ad)) > maxoffset) ) return NULL; - - if ((la = (long_ad *)ptr)->extLength == 0) + else if ((la = (long_ad *)ptr)->extLength == 0) return NULL; - else if (inc) - (*offset) += sizeof(long_ad); + + if (inc) + *offset += sizeof(long_ad); return la; } diff -u -r -N ../../linus/2.4/linux/fs/udf/ecma_167.h linux/fs/udf/ecma_167.h --- ../../linus/2.4/linux/fs/udf/ecma_167.h 2003-08-03 23:23:24.000000000 +0200 +++ linux/fs/udf/ecma_167.h 2003-08-03 23:31:41.000000000 +0200 @@ -606,7 +606,7 @@ #define FE_RECORD_FMT_CRLF 0x0A #define FE_RECORD_FMT_LFCR 0x0B -#define Record Display Attributes (ECMA 167r3 4/14.9.8) */ +/* Record Display Attributes (ECMA 167r3 4/14.9.8) */ #define FE_RECORD_DISPLAY_ATTR_UNDEF 0x00 #define FE_RECORD_DISPLAY_ATTR_1 0x01 #define FE_RECORD_DISPLAY_ATTR_2 0x02 diff -u -r -N ../../linus/2.4/linux/fs/udf/file.c linux/fs/udf/file.c --- ../../linus/2.4/linux/fs/udf/file.c 2003-08-03 23:23:24.000000000 +0200 +++ linux/fs/udf/file.c 2003-08-03 23:31:41.000000000 +0200 @@ -46,64 +46,36 @@ static int udf_adinicb_readpage(struct file *file, struct page * page) { struct inode *inode = page->mapping->host; - - struct buffer_head *bh; - int block; char *kaddr; - int err = 0; if (!PageLocked(page)) PAGE_BUG(page); kaddr = kmap(page); memset(kaddr, 0, PAGE_CACHE_SIZE); - block = udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0); - bh = sb_bread(inode->i_sb, block); - if (!bh) - { - SetPageError(page); - err = -EIO; - goto out; - } - memcpy(kaddr, bh->b_data + udf_ext0_offset(inode), inode->i_size); - brelse(bh); + memcpy(kaddr, UDF_I_DATA(inode) + UDF_I_LENEATTR(inode), inode->i_size); flush_dcache_page(page); SetPageUptodate(page); -out: kunmap(page); UnlockPage(page); - return err; + return 0; } static int udf_adinicb_writepage(struct page *page) { struct inode *inode = page->mapping->host; - - struct buffer_head *bh; - int block; char *kaddr; - int err = 0; if (!PageLocked(page)) PAGE_BUG(page); kaddr = kmap(page); - block = udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0); - bh = sb_bread(inode->i_sb, block); - if (!bh) - { - SetPageError(page); - err = -EIO; - goto out; - } - memcpy(bh->b_data + udf_ext0_offset(inode), kaddr, inode->i_size); - mark_buffer_dirty(bh); - brelse(bh); + memcpy(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode), kaddr, inode->i_size); + mark_inode_dirty(inode); SetPageUptodate(page); -out: kunmap(page); UnlockPage(page); - return err; + return 0; } static int udf_adinicb_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to) @@ -115,31 +87,17 @@ static int udf_adinicb_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to) { struct inode *inode = page->mapping->host; - - struct buffer_head *bh; - int block; char *kaddr = page_address(page); - int err = 0; - block = udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0); - bh = sb_bread(inode->i_sb, block); - if (!bh) - { - SetPageError(page); - err = -EIO; - goto out; - } - memcpy(bh->b_data + udf_file_entry_alloc_offset(inode) + offset, + memcpy(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode) + offset, kaddr + offset, to - offset); - mark_buffer_dirty(bh); - brelse(bh); + mark_inode_dirty(inode); SetPageUptodate(page); -out: kunmap(page); /* only one page here */ if (to > inode->i_size) inode->i_size = to; - return err; + return 0; } struct address_space_operations udf_adinicb_aops = { @@ -231,9 +189,6 @@ unsigned long arg) { int result = -EINVAL; - struct buffer_head *bh = NULL; - long_ad eaicb; - uint8_t *ea = NULL; if ( permission(inode, MAY_READ) != 0 ) { @@ -248,7 +203,6 @@ return -EINVAL; } - /* first, do ioctls that don't need to udf_read */ switch (cmd) { case UDF_GETVOLIDENT: @@ -266,50 +220,16 @@ return result; } - } - - /* ok, we need to read the inode */ - bh = udf_tread(inode->i_sb, - udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0)); - - if (!bh) - { - udf_debug("bread failed (inode=%ld)\n", inode->i_ino); - return -EIO; - } - - if (UDF_I_EXTENDED_FE(inode) == 0) - { - struct fileEntry *fe; - - fe = (struct fileEntry *)bh->b_data; - eaicb = lela_to_cpu(fe->extendedAttrICB); - if (UDF_I_LENEATTR(inode)) - ea = fe->extendedAttr; - } - else - { - struct extendedFileEntry *efe; - - efe = (struct extendedFileEntry *)bh->b_data; - eaicb = lela_to_cpu(efe->extendedAttrICB); - if (UDF_I_LENEATTR(inode)) - ea = efe->extendedAttr; - } - - switch (cmd) - { case UDF_GETEASIZE: result = put_user(UDF_I_LENEATTR(inode), (int *)arg); break; case UDF_GETEABLOCK: - result = copy_to_user((char *)arg, ea, + result = copy_to_user((char *)arg, UDF_I_DATA(inode), UDF_I_LENEATTR(inode)) ? -EFAULT : 0; break; } - udf_release_data(bh); return result; } diff -u -r -N ../../linus/2.4/linux/fs/udf/fsync.c linux/fs/udf/fsync.c --- ../../linus/2.4/linux/fs/udf/fsync.c 2003-08-03 23:23:24.000000000 +0200 +++ linux/fs/udf/fsync.c 2003-08-03 23:31:41.000000000 +0200 @@ -45,7 +45,9 @@ int err; err = fsync_inode_buffers(inode); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,15) err |= fsync_inode_data_buffers(inode); +#endif if (!(inode->i_state & I_DIRTY)) return err; if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) diff -u -r -N ../../linus/2.4/linux/fs/udf/ialloc.c linux/fs/udf/ialloc.c --- ../../linus/2.4/linux/fs/udf/ialloc.c 2003-08-03 23:23:24.000000000 +0200 +++ linux/fs/udf/ialloc.c 2003-08-03 23:31:41.000000000 +0200 @@ -28,6 +28,7 @@ #include #include #include +#include #include "udf_i.h" #include "udf_sb.h" @@ -44,7 +45,12 @@ * Note: we must free any quota before locking the superblock, * as writing the quota to disk may need the lock as well. */ +#ifndef OLD_QUOTA DQUOT_FREE_INODE(inode); +#else + DQUOT_INIT(inode); + DQUOT_FREE_INODE(sb, inode); +#endif DQUOT_DROP(inode); lock_super(sb); @@ -69,7 +75,11 @@ udf_free_blocks(sb, NULL, UDF_I_LOCATION(inode), 0, 1); } +#ifndef OLD_QUOTA struct inode * udf_new_inode (struct inode *dir, int mode, int * err) +#else +struct inode * udf_new_inode (const struct inode *dir, int mode, int * err) +#endif { struct super_block *sb; struct inode * inode; @@ -130,13 +140,20 @@ inode->i_blocks = 0; UDF_I_LENEATTR(inode) = 0; UDF_I_LENALLOC(inode) = 0; + UDF_I_USE(inode) = 0; if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_EXTENDED_FE)) { - UDF_I_EXTENDED_FE(inode) = 1; + UDF_I_EFE(inode) = 1; UDF_UPDATE_UDFREV(inode->i_sb, UDF_VERS_USE_EXTENDED_FE); + UDF_I_DATA(inode) = kmalloc(inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry), GFP_KERNEL); + memset(UDF_I_DATA(inode), 0x00, inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry)); } else - UDF_I_EXTENDED_FE(inode) = 0; + { + UDF_I_EFE(inode) = 0; + UDF_I_DATA(inode) = kmalloc(inode->i_sb->s_blocksize - sizeof(struct fileEntry), GFP_KERNEL); + memset(UDF_I_DATA(inode), 0x00, inode->i_sb->s_blocksize - sizeof(struct fileEntry)); + } if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_AD_IN_ICB)) UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_IN_ICB; else if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD)) @@ -147,15 +164,20 @@ UDF_I_CRTIME(inode) = CURRENT_TIME; UDF_I_UMTIME(inode) = UDF_I_UCTIME(inode) = UDF_I_UCRTIME(inode) = CURRENT_UTIME; - UDF_I_NEW_INODE(inode) = 1; insert_inode_hash(inode); mark_inode_dirty(inode); unlock_super(sb); +#ifndef OLD_QUOTA if (DQUOT_ALLOC_INODE(inode)) +#else + if (DQUOT_ALLOC_INODE(sb, inode)) +#endif { DQUOT_DROP(inode); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10) inode->i_flags |= S_NOQUOTA; +#endif inode->i_nlink = 0; iput(inode); *err = -EDQUOT; diff -u -r -N ../../linus/2.4/linux/fs/udf/inode.c linux/fs/udf/inode.c --- ../../linus/2.4/linux/fs/udf/inode.c 2003-08-03 23:23:24.000000000 +0200 +++ linux/fs/udf/inode.c 2003-08-03 23:31:41.000000000 +0200 @@ -38,13 +38,16 @@ #include #include #include +#include #include "udf_i.h" #include "udf_sb.h" MODULE_AUTHOR("Ben Fennema"); MODULE_DESCRIPTION("Universal Disk Format Filesystem"); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10) MODULE_LICENSE("GPL"); +#endif #define EXTENT_MERGE_SIZE 5 @@ -122,6 +125,11 @@ clear_inode(inode); } +void udf_clear_inode(struct inode *inode) +{ + kfree(UDF_I_DATA(inode)); +} + void udf_discard_prealloc(struct inode * inode) { if (inode->i_size && inode->i_size != UDF_I_LENEXTENTS(inode) && @@ -162,10 +170,8 @@ void udf_expand_file_adinicb(struct inode * inode, int newsize, int * err) { - struct buffer_head *bh = NULL; struct page *page; char *kaddr; - int block; /* from now on we have normal address_space methods */ inode->i_data.a_ops = &udf_aops; @@ -180,10 +186,6 @@ return; } - block = udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0); - bh = udf_tread(inode->i_sb, block); - if (!bh) - return; page = grab_cache_page(inode->i_mapping, 0); if (!PageLocked(page)) PAGE_BUG(page); @@ -192,21 +194,19 @@ kaddr = kmap(page); memset(kaddr + UDF_I_LENALLOC(inode), 0x00, PAGE_CACHE_SIZE - UDF_I_LENALLOC(inode)); - memcpy(kaddr, bh->b_data + udf_file_entry_alloc_offset(inode), + memcpy(kaddr, UDF_I_DATA(inode) + UDF_I_LENEATTR(inode), UDF_I_LENALLOC(inode)); flush_dcache_page(page); SetPageUptodate(page); kunmap(page); } - memset(bh->b_data + udf_file_entry_alloc_offset(inode), - 0, UDF_I_LENALLOC(inode)); + memset(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode), 0x00, + UDF_I_LENALLOC(inode)); UDF_I_LENALLOC(inode) = 0; if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD)) UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_SHORT; else UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_LONG; - mark_buffer_dirty_inode(bh, inode); - udf_release_data(bh); inode->i_data.a_ops->writepage(page); page_cache_release(page); @@ -221,18 +221,21 @@ struct buffer_head *sbh = NULL, *dbh = NULL; lb_addr bloc, eloc; uint32_t elen, extoffset; + uint8_t alloctype; struct udf_fileident_bh sfibh, dfibh; loff_t f_pos = udf_ext0_offset(inode) >> 2; int size = (udf_ext0_offset(inode) + inode->i_size) >> 2; struct fileIdentDesc cfi, *sfi, *dfi; + if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD)) + alloctype = ICBTAG_FLAG_AD_SHORT; + else + alloctype = ICBTAG_FLAG_AD_LONG; + if (!inode->i_size) { - if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD)) - UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_SHORT; - else - UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_LONG; + UDF_I_ALLOCTYPE(inode) = alloctype; mark_inode_dirty(inode); return NULL; } @@ -248,9 +251,6 @@ UDF_I_LOCATION(inode).partitionReferenceNum, 0); if (!newblock) return NULL; - sbh = udf_tread(inode->i_sb, inode->i_ino); - if (!sbh) - return NULL; dbh = udf_tgetblk(inode->i_sb, newblock); if (!dbh) return NULL; @@ -261,18 +261,19 @@ mark_buffer_dirty_inode(dbh, inode); sfibh.soffset = sfibh.eoffset = (f_pos & ((inode->i_sb->s_blocksize - 1) >> 2)) << 2; - sfibh.sbh = sfibh.ebh = sbh; + sbh = sfibh.sbh = sfibh.ebh = NULL; dfibh.soffset = dfibh.eoffset = 0; dfibh.sbh = dfibh.ebh = dbh; while ( (f_pos < size) ) { + UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_IN_ICB; sfi = udf_fileident_read(inode, &f_pos, &sfibh, &cfi, NULL, NULL, NULL, NULL, NULL, NULL); if (!sfi) { - udf_release_data(sbh); udf_release_data(dbh); return NULL; } + UDF_I_ALLOCTYPE(inode) = alloctype; sfi->descTag.tagLocation = *block; dfibh.soffset = dfibh.eoffset; dfibh.eoffset += (sfibh.eoffset - sfibh.soffset); @@ -280,21 +281,15 @@ if (udf_write_fi(inode, sfi, dfi, &dfibh, sfi->impUse, sfi->fileIdent + sfi->lengthOfImpUse)) { - udf_release_data(sbh); + UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_IN_ICB; udf_release_data(dbh); return NULL; } } mark_buffer_dirty_inode(dbh, inode); - memset(sbh->b_data + udf_file_entry_alloc_offset(inode), - 0, UDF_I_LENALLOC(inode)); - + memset(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode), 0, UDF_I_LENALLOC(inode)); UDF_I_LENALLOC(inode) = 0; - if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD)) - UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_SHORT; - else - UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_LONG; bloc = UDF_I_LOCATION(inode); eloc.logicalBlockNum = *block; eloc.partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum; @@ -304,7 +299,9 @@ udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &sbh, 0); /* UniqueID stuff */ - mark_buffer_dirty(sbh); +#ifdef OLD_QUOTA + inode->i_blocks = inode->i_sb->s_blocksize / 512; +#endif udf_release_data(sbh); mark_inode_dirty(inode); inode->i_version ++; @@ -589,6 +586,9 @@ UDF_I_NEXT_ALLOC_GOAL(inode) = newblocknum; inode->i_ctime = CURRENT_TIME; UDF_I_UCTIME(inode) = CURRENT_UTIME; +#ifdef OLD_QUOTA + inode->i_blocks += inode->i_sb->s_blocksize / 512; +#endif if (IS_SYNC(inode)) udf_sync_inode(inode); @@ -732,7 +732,7 @@ if (elen > numalloc) { - laarr[c].extLength -= + laarr[i].extLength -= (numalloc << inode->i_sb->s_blocksize_bits); numalloc = 0; } @@ -854,7 +854,6 @@ void udf_truncate(struct inode * inode) { int offset; - struct buffer_head *bh; int err; if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || @@ -879,16 +878,8 @@ } else { - offset = (inode->i_size & (inode->i_sb->s_blocksize - 1)) + - udf_file_entry_alloc_offset(inode); - - if ((bh = udf_tread(inode->i_sb, - udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0)))) - { - memset(bh->b_data + offset, 0x00, inode->i_sb->s_blocksize - offset); - mark_buffer_dirty(bh); - udf_release_data(bh); - } + offset = inode->i_size & (inode->i_sb->s_blocksize - 1); + memset(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode) + offset, 0x00, inode->i_sb->s_blocksize - offset - udf_file_entry_alloc_offset(inode)); UDF_I_LENALLOC(inode) = inode->i_size; } } @@ -1034,10 +1025,9 @@ struct extendedFileEntry *efe; time_t convtime; long convtime_usec; - int offset, alen; + int offset; inode->i_version = ++event; - UDF_I_NEW_INODE(inode) = 0; fe = (struct fileEntry *)bh->b_data; efe = (struct extendedFileEntry *)bh->b_data; @@ -1049,14 +1039,28 @@ UDF_I_ALLOCTYPE(inode) = le16_to_cpu(fe->icbTag.flags) & ICBTAG_FLAG_AD_MASK; if (le16_to_cpu(fe->descTag.tagIdent) == TAG_IDENT_EFE) - UDF_I_EXTENDED_FE(inode) = 1; + { + UDF_I_EFE(inode) = 1; + UDF_I_USE(inode) = 0; + UDF_I_DATA(inode) = kmalloc(inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry), GFP_KERNEL); + memcpy(UDF_I_DATA(inode), bh->b_data + sizeof(struct extendedFileEntry), inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry)); + } else if (le16_to_cpu(fe->descTag.tagIdent) == TAG_IDENT_FE) - UDF_I_EXTENDED_FE(inode) = 0; + { + UDF_I_EFE(inode) = 0; + UDF_I_USE(inode) = 0; + UDF_I_DATA(inode) = kmalloc(inode->i_sb->s_blocksize - sizeof(struct fileEntry), GFP_KERNEL); + memcpy(UDF_I_DATA(inode), bh->b_data + sizeof(struct fileEntry), inode->i_sb->s_blocksize - sizeof(struct fileEntry)); + } else if (le16_to_cpu(fe->descTag.tagIdent) == TAG_IDENT_USE) { + UDF_I_EFE(inode) = 0; + UDF_I_USE(inode) = 1; UDF_I_LENALLOC(inode) = le32_to_cpu( ((struct unallocSpaceEntry *)bh->b_data)->lengthAllocDescs); + UDF_I_DATA(inode) = kmalloc(inode->i_sb->s_blocksize - sizeof(struct unallocSpaceEntry), GFP_KERNEL); + memcpy(UDF_I_DATA(inode), bh->b_data + sizeof(struct unallocSpaceEntry), inode->i_sb->s_blocksize - sizeof(struct unallocSpaceEntry)); return; } @@ -1079,7 +1083,7 @@ UDF_I_NEXT_ALLOC_BLOCK(inode) = 0; UDF_I_NEXT_ALLOC_GOAL(inode) = 0; - if (UDF_I_EXTENDED_FE(inode) == 0) + if (UDF_I_EFE(inode) == 0) { inode->i_blocks = le64_to_cpu(fe->logicalBlocksRecorded) << (inode->i_sb->s_blocksize_bits - 9); @@ -1122,7 +1126,6 @@ UDF_I_LENEATTR(inode) = le32_to_cpu(fe->lengthExtendedAttr); UDF_I_LENALLOC(inode) = le32_to_cpu(fe->lengthAllocDescs); offset = sizeof(struct fileEntry) + UDF_I_LENEATTR(inode); - alen = offset + UDF_I_LENALLOC(inode); } else { @@ -1179,7 +1182,6 @@ UDF_I_LENEATTR(inode) = le32_to_cpu(efe->lengthExtendedAttr); UDF_I_LENALLOC(inode) = le32_to_cpu(efe->lengthAllocDescs); offset = sizeof(struct extendedFileEntry) + UDF_I_LENEATTR(inode); - alen = offset + UDF_I_LENALLOC(inode); } switch (fe->icbTag.fileType) @@ -1220,6 +1222,11 @@ init_special_inode(inode, inode->i_mode | S_IFIFO, 0); break; } + case ICBTAG_FILE_TYPE_SOCKET: + { + init_special_inode(inode, inode->i_mode | S_IFSOCK, 0); + break; + } case ICBTAG_FILE_TYPE_SYMLINK: { inode->i_data.a_ops = &udf_symlink_aops; @@ -1237,10 +1244,9 @@ } if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { - struct buffer_head *tbh = NULL; struct deviceSpec *dsea = (struct deviceSpec *) - udf_get_extendedattr(inode, 12, 1, &tbh); + udf_get_extendedattr(inode, 12, 1); if (dsea) { @@ -1248,7 +1254,6 @@ ((le32_to_cpu(dsea->majorDeviceIdent)) << 8) | (le32_to_cpu(dsea->minorDeviceIdent) & 0xFF)); /* Developer ID ??? */ - udf_release_data(tbh); } else { @@ -1325,19 +1330,11 @@ udf_debug("bread failure\n"); return -EIO; } + + memset(bh->b_data, 0x00, inode->i_sb->s_blocksize); + fe = (struct fileEntry *)bh->b_data; efe = (struct extendedFileEntry *)bh->b_data; - if (UDF_I_NEW_INODE(inode) == 1) - { - if (UDF_I_EXTENDED_FE(inode) == 0) - memset(bh->b_data, 0x00, sizeof(struct fileEntry)); - else - memset(bh->b_data, 0x00, sizeof(struct extendedFileEntry)); - memset(bh->b_data + udf_file_entry_alloc_offset(inode) + - UDF_I_LENALLOC(inode), 0x0, inode->i_sb->s_blocksize - - udf_file_entry_alloc_offset(inode) - UDF_I_LENALLOC(inode)); - UDF_I_NEW_INODE(inode) = 0; - } if (le16_to_cpu(fe->descTag.tagIdent) == TAG_IDENT_USE) { @@ -1345,6 +1342,7 @@ (struct unallocSpaceEntry *)bh->b_data; use->lengthAllocDescs = cpu_to_le32(UDF_I_LENALLOC(inode)); + memcpy(bh->b_data + sizeof(struct unallocSpaceEntry), UDF_I_DATA(inode), inode->i_sb->s_blocksize - sizeof(struct unallocSpaceEntry)); crclen = sizeof(struct unallocSpaceEntry) + UDF_I_LENALLOC(inode) - sizeof(tag); use->descTag.tagLocation = cpu_to_le32(UDF_I_LOCATION(inode).logicalBlockNum); @@ -1387,17 +1385,16 @@ if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { regid *eid; - struct buffer_head *tbh = NULL; struct deviceSpec *dsea = (struct deviceSpec *) - udf_get_extendedattr(inode, 12, 1, &tbh); + udf_get_extendedattr(inode, 12, 1); if (!dsea) { dsea = (struct deviceSpec *) udf_add_extendedattr(inode, sizeof(struct deviceSpec) + - sizeof(regid), 12, 0x3, &tbh); + sizeof(regid), 12, 0x3); dsea->attrType = 12; dsea->attrSubtype = 1; dsea->attrLength = sizeof(struct deviceSpec) + @@ -1411,12 +1408,11 @@ eid->identSuffix[1] = UDF_OS_ID_LINUX; dsea->majorDeviceIdent = kdev_t_to_nr(inode->i_rdev) >> 8; dsea->minorDeviceIdent = kdev_t_to_nr(inode->i_rdev) & 0xFF; - mark_buffer_dirty_inode(tbh, inode); - udf_release_data(tbh); } - if (UDF_I_EXTENDED_FE(inode) == 0) + if (UDF_I_EFE(inode) == 0) { + memcpy(bh->b_data + sizeof(struct fileEntry), UDF_I_DATA(inode), inode->i_sb->s_blocksize - sizeof(struct fileEntry)); fe->logicalBlocksRecorded = cpu_to_le64( (inode->i_blocks + (1 << (inode->i_sb->s_blocksize_bits - 9)) - 1) >> (inode->i_sb->s_blocksize_bits - 9)); @@ -1439,6 +1435,7 @@ } else { + memcpy(bh->b_data + sizeof(struct extendedFileEntry), UDF_I_DATA(inode), inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry)); efe->objectSize = cpu_to_le64(inode->i_size); efe->logicalBlocksRecorded = cpu_to_le64( (inode->i_blocks + (1 << (inode->i_sb->s_blocksize_bits - 9)) - 1) >> @@ -1507,6 +1504,8 @@ fe->icbTag.fileType = ICBTAG_FILE_TYPE_CHAR; else if (S_ISFIFO(inode->i_mode)) fe->icbTag.fileType = ICBTAG_FILE_TYPE_FIFO; + else if (S_ISSOCK(inode->i_mode)) + fe->icbTag.fileType = ICBTAG_FILE_TYPE_SOCKET; icbflags = UDF_I_ALLOCTYPE(inode) | ((inode->i_mode & S_ISUID) ? ICBTAG_FLAG_SETUID : 0) | @@ -1619,17 +1618,12 @@ long_ad *lad = NULL; struct allocExtDesc *aed; int8_t etype; + uint8_t *ptr; - if (!(*bh)) - { - if (!(*bh = udf_tread(inode->i_sb, - udf_get_lb_pblock(inode->i_sb, *bloc, 0)))) - { - udf_debug("reading block %d failed!\n", - udf_get_lb_pblock(inode->i_sb, *bloc, 0)); - return -1; - } - } + if (!*bh) + ptr = UDF_I_DATA(inode) + *extoffset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode); + else + ptr = (*bh)->b_data + *extoffset; if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT) adsize = sizeof(short_ad); @@ -1668,7 +1662,7 @@ { loffset = *extoffset; aed->lengthAllocDescs = cpu_to_le32(adsize); - sptr = (*bh)->b_data + *extoffset - adsize; + sptr = ptr - adsize; dptr = nbh->b_data + sizeof(struct allocExtDesc); memcpy(dptr, sptr, adsize); *extoffset = sizeof(struct allocExtDesc) + adsize; @@ -1677,10 +1671,10 @@ { loffset = *extoffset + adsize; aed->lengthAllocDescs = cpu_to_le32(0); - sptr = (*bh)->b_data + *extoffset; + sptr = ptr; *extoffset = sizeof(struct allocExtDesc); - if (memcmp(&UDF_I_LOCATION(inode), &obloc, sizeof(lb_addr))) + if (*bh) { aed = (struct allocExtDesc *)(*bh)->b_data; aed->lengthAllocDescs = @@ -1720,18 +1714,23 @@ break; } } - if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) - udf_update_tag((*bh)->b_data, loffset); + if (*bh) + { + if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) + udf_update_tag((*bh)->b_data, loffset); + else + udf_update_tag((*bh)->b_data, sizeof(struct allocExtDesc)); + mark_buffer_dirty_inode(*bh, inode); + udf_release_data(*bh); + } else - udf_update_tag((*bh)->b_data, sizeof(struct allocExtDesc)); - mark_buffer_dirty_inode(*bh, inode); - udf_release_data(*bh); + mark_inode_dirty(inode); *bh = nbh; } etype = udf_write_aext(inode, *bloc, extoffset, eloc, elen, *bh, inc); - if (!memcmp(&UDF_I_LOCATION(inode), bloc, sizeof(lb_addr))) + if (!*bh) { UDF_I_LENALLOC(inode) += adsize; mark_inode_dirty(inode); @@ -1755,49 +1754,40 @@ lb_addr eloc, uint32_t elen, struct buffer_head *bh, int inc) { int adsize; - short_ad *sad = NULL; - long_ad *lad = NULL; + uint8_t *ptr; - if (!(bh)) - { - if (!(bh = udf_tread(inode->i_sb, - udf_get_lb_pblock(inode->i_sb, bloc, 0)))) - { - udf_debug("reading block %d failed!\n", - udf_get_lb_pblock(inode->i_sb, bloc, 0)); - return -1; - } - } + if (!bh) + ptr = UDF_I_DATA(inode) + *extoffset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode); else + { + ptr = bh->b_data + *extoffset; atomic_inc(&bh->b_count); - - if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT) - adsize = sizeof(short_ad); - else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG) - adsize = sizeof(long_ad); - else - return -1; + } switch (UDF_I_ALLOCTYPE(inode)) { case ICBTAG_FLAG_AD_SHORT: { - sad = (short_ad *)((bh)->b_data + *extoffset); + short_ad *sad = (short_ad *)ptr; sad->extLength = cpu_to_le32(elen); sad->extPosition = cpu_to_le32(eloc.logicalBlockNum); + adsize = sizeof(short_ad); break; } case ICBTAG_FLAG_AD_LONG: { - lad = (long_ad *)((bh)->b_data + *extoffset); + long_ad *lad = (long_ad *)ptr; lad->extLength = cpu_to_le32(elen); lad->extLocation = cpu_to_lelb(eloc); memset(lad->impUse, 0x00, sizeof(lad->impUse)); + adsize = sizeof(long_ad); break; } + default: + return -1; } - if (memcmp(&UDF_I_LOCATION(inode), &bloc, sizeof(lb_addr))) + if (bh) { if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) { @@ -1806,30 +1796,28 @@ le32_to_cpu(aed->lengthAllocDescs) + sizeof(struct allocExtDesc)); } mark_buffer_dirty_inode(bh, inode); + udf_release_data(bh); } else - { mark_inode_dirty(inode); - mark_buffer_dirty(bh); - } if (inc) *extoffset += adsize; - udf_release_data(bh); return (elen >> 30); } int8_t udf_next_aext(struct inode *inode, lb_addr *bloc, int *extoffset, lb_addr *eloc, uint32_t *elen, struct buffer_head **bh, int inc) { - uint16_t tagIdent; - int pos, alen; int8_t etype; - if (!(*bh)) + while ((etype = udf_current_aext(inode, bloc, extoffset, eloc, elen, bh, inc)) == + (EXT_NEXT_EXTENT_ALLOCDECS >> 30)) { - if (!(*bh = udf_tread(inode->i_sb, - udf_get_lb_pblock(inode->i_sb, *bloc, 0)))) + *bloc = *eloc; + *extoffset = sizeof(struct allocExtDesc); + udf_release_data(*bh); + if (!(*bh = udf_tread(inode->i_sb, udf_get_lb_pblock(inode->i_sb, *bloc, 0)))) { udf_debug("reading block %d failed!\n", udf_get_lb_pblock(inode->i_sb, *bloc, 0)); @@ -1837,154 +1825,38 @@ } } - tagIdent = le16_to_cpu(((tag *)(*bh)->b_data)->tagIdent); - - if (!memcmp(&UDF_I_LOCATION(inode), bloc, sizeof(lb_addr))) - { - if (tagIdent == TAG_IDENT_FE || tagIdent == TAG_IDENT_EFE || - UDF_I_NEW_INODE(inode)) - { - pos = udf_file_entry_alloc_offset(inode); - alen = UDF_I_LENALLOC(inode) + pos; - } - else if (tagIdent == TAG_IDENT_USE) - { - pos = sizeof(struct unallocSpaceEntry); - alen = UDF_I_LENALLOC(inode) + pos; - } - else - return -1; - } - else if (tagIdent == TAG_IDENT_AED) - { - struct allocExtDesc *aed = (struct allocExtDesc *)(*bh)->b_data; - - pos = sizeof(struct allocExtDesc); - alen = le32_to_cpu(aed->lengthAllocDescs) + pos; - } - else - return -1; - - if (!(*extoffset)) - *extoffset = pos; - - switch (UDF_I_ALLOCTYPE(inode)) - { - case ICBTAG_FLAG_AD_SHORT: - { - short_ad *sad; - - if (!(sad = udf_get_fileshortad((*bh)->b_data, alen, extoffset, inc))) - return -1; - - if ((etype = le32_to_cpu(sad->extLength) >> 30) == (EXT_NEXT_EXTENT_ALLOCDECS >> 30)) - { - bloc->logicalBlockNum = le32_to_cpu(sad->extPosition); - *extoffset = 0; - udf_release_data(*bh); - *bh = NULL; - return udf_next_aext(inode, bloc, extoffset, eloc, elen, bh, inc); - } - else - { - eloc->logicalBlockNum = le32_to_cpu(sad->extPosition); - eloc->partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum; - *elen = le32_to_cpu(sad->extLength) & UDF_EXTENT_LENGTH_MASK; - } - break; - } - case ICBTAG_FLAG_AD_LONG: - { - long_ad *lad; - - if (!(lad = udf_get_filelongad((*bh)->b_data, alen, extoffset, inc))) - return -1; - - if ((etype = le32_to_cpu(lad->extLength) >> 30) == (EXT_NEXT_EXTENT_ALLOCDECS >> 30)) - { - *bloc = lelb_to_cpu(lad->extLocation); - *extoffset = 0; - udf_release_data(*bh); - *bh = NULL; - return udf_next_aext(inode, bloc, extoffset, eloc, elen, bh, inc); - } - else - { - *eloc = lelb_to_cpu(lad->extLocation); - *elen = le32_to_cpu(lad->extLength) & UDF_EXTENT_LENGTH_MASK; - } - break; - } - case ICBTAG_FLAG_AD_IN_ICB: - { - if (UDF_I_LENALLOC(inode) == 0) - return -1; - etype = (EXT_RECORDED_ALLOCATED >> 30); - *eloc = UDF_I_LOCATION(inode); - *elen = UDF_I_LENALLOC(inode); - break; - } - default: - { - udf_debug("alloc_type = %d unsupported\n", UDF_I_ALLOCTYPE(inode)); - return -1; - } - } - if (*elen) - return etype; - - udf_debug("Empty Extent, inode=%ld, alloctype=%d, eloc=%d, elen=%d, etype=%d, extoffset=%d\n", - inode->i_ino, UDF_I_ALLOCTYPE(inode), eloc->logicalBlockNum, *elen, etype, *extoffset); - if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT) - *extoffset -= sizeof(short_ad); - else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG) - *extoffset -= sizeof(long_ad); - return -1; + return etype; } int8_t udf_current_aext(struct inode *inode, lb_addr *bloc, int *extoffset, lb_addr *eloc, uint32_t *elen, struct buffer_head **bh, int inc) { - int pos, alen; + int alen; int8_t etype; + uint8_t *ptr; - if (!(*bh)) - { - if (!(*bh = udf_tread(inode->i_sb, - udf_get_lb_pblock(inode->i_sb, *bloc, 0)))) - { - udf_debug("reading block %d failed!\n", - udf_get_lb_pblock(inode->i_sb, *bloc, 0)); - return -1; - } - } - - if (!memcmp(&UDF_I_LOCATION(inode), bloc, sizeof(lb_addr))) + if (!*bh) { - if (!(UDF_I_EXTENDED_FE(inode))) - pos = sizeof(struct fileEntry) + UDF_I_LENEATTR(inode); - else - pos = sizeof(struct extendedFileEntry) + UDF_I_LENEATTR(inode); - alen = UDF_I_LENALLOC(inode) + pos; + if (!(*extoffset)) + *extoffset = udf_file_entry_alloc_offset(inode); + ptr = UDF_I_DATA(inode) + *extoffset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode); + alen = udf_file_entry_alloc_offset(inode) + UDF_I_LENALLOC(inode); } else { - struct allocExtDesc *aed = (struct allocExtDesc *)(*bh)->b_data; - - pos = sizeof(struct allocExtDesc); - alen = le32_to_cpu(aed->lengthAllocDescs) + pos; + if (!(*extoffset)) + *extoffset = sizeof(struct allocExtDesc); + ptr = (*bh)->b_data + *extoffset; + alen = le32_to_cpu(((struct allocExtDesc *)(*bh)->b_data)->lengthAllocDescs); } - if (!(*extoffset)) - *extoffset = pos; - switch (UDF_I_ALLOCTYPE(inode)) { case ICBTAG_FLAG_AD_SHORT: { short_ad *sad; - if (!(sad = udf_get_fileshortad((*bh)->b_data, alen, extoffset, inc))) + if (!(sad = udf_get_fileshortad(ptr, alen, extoffset, inc))) return -1; etype = le32_to_cpu(sad->extLength) >> 30; @@ -1997,7 +1869,7 @@ { long_ad *lad; - if (!(lad = udf_get_filelongad((*bh)->b_data, alen, extoffset, inc))) + if (!(lad = udf_get_filelongad(ptr, alen, extoffset, inc))) return -1; etype = le32_to_cpu(lad->extLength) >> 30; @@ -2011,15 +1883,8 @@ return -1; } } - if (*elen) - return etype; - udf_debug("Empty Extent!\n"); - if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT) - *extoffset -= sizeof(short_ad); - else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG) - *extoffset -= sizeof(long_ad); - return -1; + return etype; } int8_t udf_insert_aext(struct inode *inode, lb_addr bloc, int extoffset, @@ -2029,17 +1894,7 @@ uint32_t oelen; int8_t etype; - if (!bh) - { - if (!(bh = udf_tread(inode->i_sb, - udf_get_lb_pblock(inode->i_sb, bloc, 0)))) - { - udf_debug("reading block %d failed!\n", - udf_get_lb_pblock(inode->i_sb, bloc, 0)); - return -1; - } - } - else + if (bh) atomic_inc(&bh->b_count); while ((etype = udf_next_aext(inode, &bloc, &extoffset, &oeloc, &oelen, &bh, 0)) != -1) @@ -2063,19 +1918,11 @@ int8_t etype; struct allocExtDesc *aed; - if (!(nbh)) + if (nbh) { - if (!(nbh = udf_tread(inode->i_sb, - udf_get_lb_pblock(inode->i_sb, nbloc, 0)))) - { - udf_debug("reading block %d failed!\n", - udf_get_lb_pblock(inode->i_sb, nbloc, 0)); - return -1; - } - } - else atomic_inc(&nbh->b_count); - atomic_inc(&nbh->b_count); + atomic_inc(&nbh->b_count); + } if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT) adsize = sizeof(short_ad); @@ -2094,7 +1941,7 @@ while ((etype = udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1)) != -1) { udf_write_aext(inode, obloc, &oextoffset, eloc, (etype << 30) | elen, obh, 1); - if (memcmp(&nbloc, &obloc, sizeof(lb_addr))) + if (obh != nbh) { obloc = nbloc; udf_release_data(obh); @@ -2106,12 +1953,12 @@ memset(&eloc, 0x00, sizeof(lb_addr)); elen = 0; - if (memcmp(&nbloc, &obloc, sizeof(lb_addr))) + if (nbh != obh) { udf_free_blocks(inode->i_sb, inode, nbloc, 0, 1); udf_write_aext(inode, obloc, &oextoffset, eloc, elen, obh, 1); udf_write_aext(inode, obloc, &oextoffset, eloc, elen, obh, 1); - if (!memcmp(&UDF_I_LOCATION(inode), &obloc, sizeof(lb_addr))) + if (!obh) { UDF_I_LENALLOC(inode) -= (adsize * 2); mark_inode_dirty(inode); @@ -2131,7 +1978,7 @@ else { udf_write_aext(inode, obloc, &oextoffset, eloc, elen, obh, 1); - if (!memcmp(&UDF_I_LOCATION(inode), &obloc, sizeof(lb_addr))) + if (!obh) { UDF_I_LENALLOC(inode) -= adsize; mark_inode_dirty(inode); @@ -2206,9 +2053,7 @@ ret = 0; unlock_kernel(); - - if (bh) - udf_release_data(bh); + udf_release_data(bh); if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_VARCONV)) return udf_fixed_to_variable(ret); diff -u -r -N ../../linus/2.4/linux/fs/udf/misc.c linux/fs/udf/misc.c --- ../../linus/2.4/linux/fs/udf/misc.c 2003-08-03 23:23:24.000000000 +0200 +++ linux/fs/udf/misc.c 2003-08-03 23:31:41.000000000 +0200 @@ -33,18 +33,6 @@ #include "udf_i.h" #include "udf_sb.h" -uint32_t -udf64_low32(uint64_t indat) -{ - return indat & 0x00000000FFFFFFFFULL; -} - -uint32_t -udf64_high32(uint64_t indat) -{ - return indat >> 32; -} - extern struct buffer_head * udf_tgetblk(struct super_block *sb, int block) { @@ -65,42 +53,24 @@ extern struct genericFormat * udf_add_extendedattr(struct inode * inode, uint32_t size, uint32_t type, - uint8_t loc, struct buffer_head **bh) + uint8_t loc) { uint8_t *ea = NULL, *ad = NULL; - long_ad eaicb; int offset; + uint16_t crclen; + int i; - *bh = udf_tread(inode->i_sb, inode->i_ino); - - if (UDF_I_EXTENDED_FE(inode) == 0) - { - struct fileEntry *fe; - - fe = (struct fileEntry *)(*bh)->b_data; - eaicb = lela_to_cpu(fe->extendedAttrICB); - offset = sizeof(struct fileEntry); - } - else - { - struct extendedFileEntry *efe; - - efe = (struct extendedFileEntry *)(*bh)->b_data; - eaicb = lela_to_cpu(efe->extendedAttrICB); - offset = sizeof(struct extendedFileEntry); - } - - ea = &(*bh)->b_data[offset]; + ea = UDF_I_DATA(inode); if (UDF_I_LENEATTR(inode)) - offset += UDF_I_LENEATTR(inode); + ad = UDF_I_DATA(inode) + UDF_I_LENEATTR(inode); else + { + ad = ea; size += sizeof(struct extendedAttrHeaderDesc); + } - ad = &(*bh)->b_data[offset]; - if (UDF_I_LENALLOC(inode)) - offset += UDF_I_LENALLOC(inode); - - offset = inode->i_sb->s_blocksize - offset; + offset = inode->i_sb->s_blocksize - udf_file_entry_alloc_offset(inode) - + UDF_I_LENALLOC(inode); /* TODO - Check for FreeEASpace */ @@ -120,7 +90,6 @@ if (le16_to_cpu(eahd->descTag.tagIdent) != TAG_IDENT_EAHD || le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum) { - udf_release_data(*bh); return NULL; } } @@ -129,8 +98,11 @@ size -= sizeof(struct extendedAttrHeaderDesc); UDF_I_LENEATTR(inode) += sizeof(struct extendedAttrHeaderDesc); eahd->descTag.tagIdent = cpu_to_le16(TAG_IDENT_EAHD); - eahd->descTag.descVersion = cpu_to_le16(2); - eahd->descTag.tagSerialNum = cpu_to_le16(1); + if (UDF_SB_UDFREV(inode->i_sb) >= 0x0200) + eahd->descTag.descVersion = cpu_to_le16(3); + else + eahd->descTag.descVersion = cpu_to_le16(2); + eahd->descTag.tagSerialNum = cpu_to_le16(UDF_SB_SERIALNUM(inode->i_sb)); eahd->descTag.tagLocation = cpu_to_le32(UDF_I_LOCATION(inode).logicalBlockNum); eahd->impAttrLocation = cpu_to_le32(0xFFFFFFFF); eahd->appAttrLocation = cpu_to_le32(0xFFFFFFFF); @@ -168,45 +140,30 @@ } } /* rewrite CRC + checksum of eahd */ + crclen = sizeof(struct extendedAttrHeaderDesc) - sizeof(tag); + eahd->descTag.descCRCLength = cpu_to_le16(crclen); + eahd->descTag.descCRC = cpu_to_le16(udf_crc((char *)eahd + sizeof(tag), crclen, 0)); + eahd->descTag.tagChecksum = 0; + for (i=0; i<16; i++) + if (i != 4) + eahd->descTag.tagChecksum += ((uint8_t *)&(eahd->descTag))[i]; UDF_I_LENEATTR(inode) += size; return (struct genericFormat *)&ea[offset]; } if (loc & 0x02) { } - udf_release_data(*bh); return NULL; } extern struct genericFormat * -udf_get_extendedattr(struct inode * inode, uint32_t type, uint8_t subtype, - struct buffer_head **bh) +udf_get_extendedattr(struct inode *inode, uint32_t type, uint8_t subtype) { struct genericFormat *gaf; uint8_t *ea = NULL; - long_ad eaicb; uint32_t offset; - *bh = udf_tread(inode->i_sb, inode->i_ino); - - if (UDF_I_EXTENDED_FE(inode) == 0) - { - struct fileEntry *fe; - - fe = (struct fileEntry *)(*bh)->b_data; - eaicb = lela_to_cpu(fe->extendedAttrICB); - if (UDF_I_LENEATTR(inode)) - ea = fe->extendedAttr; - } - else - { - struct extendedFileEntry *efe; - - efe = (struct extendedFileEntry *)(*bh)->b_data; - eaicb = lela_to_cpu(efe->extendedAttrICB); - if (UDF_I_LENEATTR(inode)) - ea = efe->extendedAttr; - } + ea = UDF_I_DATA(inode); if (UDF_I_LENEATTR(inode)) { @@ -217,7 +174,6 @@ if (le16_to_cpu(eahd->descTag.tagIdent) != TAG_IDENT_EAHD || le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum) { - udf_release_data(*bh); return NULL; } @@ -237,12 +193,6 @@ offset += le32_to_cpu(gaf->attrLength); } } - - udf_release_data(*bh); - if (eaicb.extLength) - { - /* TODO */ - } return NULL; } @@ -268,10 +218,10 @@ if (block == 0xFFFFFFFF) return NULL; - bh = udf_tread(sb, block); + bh = udf_tread(sb, block + UDF_SB_SESSION(sb)); if (!bh) { - udf_debug("block=%d, location=%d: read failed\n", block, location); + udf_debug("block=%d, location=%d: read failed\n", block + UDF_SB_SESSION(sb), location); return NULL; } @@ -282,7 +232,7 @@ if ( location != le32_to_cpu(tag_p->tagLocation) ) { udf_debug("location mismatch block %u, tag %u != %u\n", - block, le32_to_cpu(tag_p->tagLocation), location); + block + UDF_SB_SESSION(sb), le32_to_cpu(tag_p->tagLocation), location); goto error_out; } @@ -314,7 +264,7 @@ return bh; } udf_debug("Crc failure block %d: crc = %d, crclen = %d\n", - block, le16_to_cpu(tag_p->descCRC), le16_to_cpu(tag_p->descCRCLength)); + block + UDF_SB_SESSION(sb), le16_to_cpu(tag_p->descCRC), le16_to_cpu(tag_p->descCRCLength)); error_out: brelse(bh); diff -u -r -N ../../linus/2.4/linux/fs/udf/namei.c linux/fs/udf/namei.c --- ../../linus/2.4/linux/fs/udf/namei.c 2003-08-03 23:23:24.000000000 +0200 +++ linux/fs/udf/namei.c 2003-08-03 23:31:41.000000000 +0200 @@ -56,12 +56,16 @@ uint8_t lfi = cfi->lengthFileIdent; int padlen = fibh->eoffset - fibh->soffset - liu - lfi - sizeof(struct fileIdentDesc); + int adinicb = 0; + + if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB) + adinicb = 1; offset = fibh->soffset + sizeof(struct fileIdentDesc); if (impuse) { - if (offset + liu < 0) + if (adinicb || (offset + liu < 0)) memcpy((uint8_t *)sfi->impUse, impuse, liu); else if (offset >= 0) memcpy(fibh->ebh->b_data + offset, impuse, liu); @@ -76,7 +80,7 @@ if (fileident) { - if (offset + lfi < 0) + if (adinicb || (offset + lfi < 0)) memcpy((uint8_t *)sfi->fileIdent + liu, fileident, lfi); else if (offset >= 0) memcpy(fibh->ebh->b_data + offset, fileident, lfi); @@ -89,7 +93,7 @@ offset += lfi; - if (offset + padlen < 0) + if (adinicb || (offset + padlen < 0)) memset((uint8_t *)sfi->padding + liu + lfi, 0x00, padlen); else if (offset >= 0) memset(fibh->ebh->b_data + offset, 0x00, padlen); @@ -123,7 +127,7 @@ checksum += ((uint8_t *)&cfi->descTag)[i]; cfi->descTag.tagChecksum = checksum; - if (sizeof(struct fileIdentDesc) <= -fibh->soffset) + if (adinicb || (sizeof(struct fileIdentDesc) <= -fibh->soffset)) memcpy((uint8_t *)sfi, (uint8_t *)cfi, sizeof(struct fileIdentDesc)); else { @@ -132,9 +136,14 @@ sizeof(struct fileIdentDesc) + fibh->soffset); } - if (fibh->sbh != fibh->ebh) - mark_buffer_dirty_inode(fibh->ebh, inode); - mark_buffer_dirty_inode(fibh->sbh, inode); + if (adinicb) + mark_inode_dirty(inode); + else + { + if (fibh->sbh != fibh->ebh) + mark_buffer_dirty_inode(fibh->ebh, inode); + mark_buffer_dirty_inode(fibh->sbh, inode); + } return 0; } @@ -146,7 +155,7 @@ struct fileIdentDesc *fi=NULL; loff_t f_pos; int block, flen; - char fname[255]; + char fname[UDF_NAME_LEN]; char *nameptr; uint8_t lfi; uint16_t liu; @@ -161,7 +170,9 @@ f_pos = (udf_ext0_offset(dir) >> 2); fibh->soffset = fibh->eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2; - if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2), + if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) + fibh->sbh = fibh->ebh = NULL; + else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2), &bloc, &extoffset, &eloc, &elen, &offset, &bh) == (EXT_RECORDED_ALLOCATED >> 30)) { offset >>= dir->i_sb->s_blocksize_bits; @@ -175,6 +186,12 @@ } else offset = 0; + + if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block))) + { + udf_release_data(bh); + return NULL; + } } else { @@ -182,12 +199,6 @@ return NULL; } - if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block))) - { - udf_release_data(bh); - return NULL; - } - while ( (f_pos < size) ) { fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &bloc, &extoffset, &eloc, &elen, &offset, &bh); @@ -294,7 +305,7 @@ struct fileIdentDesc cfi, *fi; struct udf_fileident_bh fibh; - if (dentry->d_name.len > UDF_NAME_LEN) + if (dentry->d_name.len > UDF_NAME_LEN-2) return ERR_PTR(-ENAMETOOLONG); #ifdef UDF_RECOVERY @@ -330,7 +341,6 @@ { struct super_block *sb; struct fileIdentDesc *fi=NULL; - struct ustr unifilename; char name[UDF_NAME_LEN], fname[UDF_NAME_LEN]; int namelen; loff_t f_pos; @@ -355,30 +365,11 @@ return NULL; } - if ( !(udf_char_to_ustr(&unifilename, dentry->d_name.name, dentry->d_name.len)) ) + if ( !(namelen = udf_put_filename(sb, dentry->d_name.name, name, dentry->d_name.len))) { *err = -ENAMETOOLONG; return NULL; } - - if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) - { - if ( !(namelen = udf_UTF8toCS0(name, &unifilename, UDF_NAME_LEN)) ) - { - *err = -ENAMETOOLONG; - return NULL; - } - } - else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) - { - if ( !(namelen = udf_NLStoCS0(UDF_SB(sb)->s_nls_map, name, &unifilename, UDF_NAME_LEN)) ) - { - *err = -ENAMETOOLONG; - return NULL; - } - } - else - return NULL; } else namelen = 0; @@ -388,7 +379,9 @@ f_pos = (udf_ext0_offset(dir) >> 2); fibh->soffset = fibh->eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2; - if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2), + if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) + fibh->sbh = fibh->ebh = NULL; + else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2), &bloc, &extoffset, &eloc, &elen, &offset, &bh) == (EXT_RECORDED_ALLOCATED >> 30)) { offset >>= dir->i_sb->s_blocksize_bits; @@ -409,94 +402,89 @@ *err = -EIO; return NULL; } - + block = UDF_I_LOCATION(dir).logicalBlockNum; - - while ( (f_pos < size) ) + + } + else + { + block = udf_get_lb_pblock(dir->i_sb, UDF_I_LOCATION(dir), 0); + fibh->sbh = fibh->ebh = NULL; + fibh->soffset = fibh->eoffset = sb->s_blocksize; + goto add; + } + + while ( (f_pos < size) ) + { + fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &bloc, &extoffset, &eloc, &elen, &offset, &bh); + + if (!fi) { - fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &bloc, &extoffset, &eloc, &elen, &offset, &bh); - - if (!fi) - { - if (fibh->sbh != fibh->ebh) - udf_release_data(fibh->ebh); - udf_release_data(fibh->sbh); - udf_release_data(bh); - *err = -EIO; - return NULL; - } - - liu = le16_to_cpu(cfi->lengthOfImpUse); - lfi = cfi->lengthFileIdent; - - if (fibh->sbh == fibh->ebh) - nameptr = fi->fileIdent + liu; + if (fibh->sbh != fibh->ebh) + udf_release_data(fibh->ebh); + udf_release_data(fibh->sbh); + udf_release_data(bh); + *err = -EIO; + return NULL; + } + + liu = le16_to_cpu(cfi->lengthOfImpUse); + lfi = cfi->lengthFileIdent; + + if (fibh->sbh == fibh->ebh) + nameptr = fi->fileIdent + liu; + else + { + int poffset; /* Unpaded ending offset */ + + poffset = fibh->soffset + sizeof(struct fileIdentDesc) + liu + lfi; + + if (poffset >= lfi) + nameptr = (char *)(fibh->ebh->b_data + poffset - lfi); else { - int poffset; /* Unpaded ending offset */ - - poffset = fibh->soffset + sizeof(struct fileIdentDesc) + liu + lfi; - - if (poffset >= lfi) - nameptr = (char *)(fibh->ebh->b_data + poffset - lfi); - else - { - nameptr = fname; - memcpy(nameptr, fi->fileIdent + liu, lfi - poffset); - memcpy(nameptr + lfi - poffset, fibh->ebh->b_data, poffset); - } + nameptr = fname; + memcpy(nameptr, fi->fileIdent + liu, lfi - poffset); + memcpy(nameptr + lfi - poffset, fibh->ebh->b_data, poffset); } - - if ( (cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0 ) + } + + if ( (cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0 ) + { + if (((sizeof(struct fileIdentDesc) + liu + lfi + 3) & ~3) == nfidlen) { - if (((sizeof(struct fileIdentDesc) + liu + lfi + 3) & ~3) == nfidlen) + udf_release_data(bh); + cfi->descTag.tagSerialNum = cpu_to_le16(1); + cfi->fileVersionNum = cpu_to_le16(1); + cfi->fileCharacteristics = 0; + cfi->lengthFileIdent = namelen; + cfi->lengthOfImpUse = cpu_to_le16(0); + if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name)) + return fi; + else { - udf_release_data(bh); - cfi->descTag.tagSerialNum = cpu_to_le16(1); - cfi->fileVersionNum = cpu_to_le16(1); - cfi->fileCharacteristics = 0; - cfi->lengthFileIdent = namelen; - cfi->lengthOfImpUse = cpu_to_le16(0); - if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name)) - return fi; - else - { - *err = -EIO; - return NULL; - } + *err = -EIO; + return NULL; } } + } - if (!lfi || !dentry) - continue; + if (!lfi || !dentry) + continue; - if ((flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi)) && - udf_match(flen, fname, &(dentry->d_name))) - { - if (fibh->sbh != fibh->ebh) - udf_release_data(fibh->ebh); - udf_release_data(fibh->sbh); - udf_release_data(bh); - *err = -EEXIST; - return NULL; - } - } - } - else - { - block = udf_get_lb_pblock(dir->i_sb, UDF_I_LOCATION(dir), 0); - if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) + if ((flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi)) && + udf_match(flen, fname, &(dentry->d_name))) { - fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block); - fibh->soffset = fibh->eoffset = udf_file_entry_alloc_offset(dir); - } - else - { - fibh->sbh = fibh->ebh = NULL; - fibh->soffset = fibh->eoffset = sb->s_blocksize; + if (fibh->sbh != fibh->ebh) + udf_release_data(fibh->ebh); + udf_release_data(fibh->sbh); + udf_release_data(bh); + *err = -EEXIST; + return NULL; } } +add: f_pos += nfidlen; if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB && @@ -533,13 +521,17 @@ fibh->sbh = fibh->ebh; } - if (UDF_I_ALLOCTYPE(dir) != ICBTAG_FLAG_AD_IN_ICB) + if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) + { + block = UDF_I_LOCATION(dir).logicalBlockNum; + fi = (struct fileIdentDesc *)(UDF_I_DATA(dir) + fibh->soffset - udf_ext0_offset(dir) + UDF_I_LENEATTR(dir)); + } + else + { block = eloc.logicalBlockNum + ((elen - 1) >> dir->i_sb->s_blocksize_bits); - else - block = UDF_I_LOCATION(dir).logicalBlockNum; - - fi = (struct fileIdentDesc *)(fibh->sbh->b_data + fibh->soffset); + fi = (struct fileIdentDesc *)(fibh->sbh->b_data + fibh->soffset); + } } else { @@ -784,7 +776,10 @@ f_pos = (udf_ext0_offset(dir) >> 2); fibh.soffset = fibh.eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2; - if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2), + + if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) + fibh.sbh = fibh.ebh = NULL; + else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2), &bloc, &extoffset, &eloc, &elen, &offset, &bh) == (EXT_RECORDED_ALLOCATED >> 30)) { offset >>= dir->i_sb->s_blocksize_bits; @@ -798,6 +793,12 @@ } else offset = 0; + + if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block))) + { + udf_release_data(bh); + return 0; + } } else { @@ -805,8 +806,6 @@ return 0; } - if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block))) - return 0; while ( (f_pos < size) ) { @@ -823,6 +822,9 @@ if (cfi.lengthFileIdent && (cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) == 0) { + if (fibh.sbh != fibh.ebh) + udf_release_data(fibh.ebh); + udf_release_data(fibh.sbh); udf_release_data(bh); return 0; } @@ -936,6 +938,8 @@ char *ea; int err; int block; + char name[UDF_NAME_LEN]; + int namelen; if (!(inode = udf_new_inode(dir, S_IFLNK, &err))) goto out; @@ -964,6 +968,9 @@ udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &bh, 0); udf_release_data(bh); +#ifdef OLD_QUOTA + inode->i_blocks = inode->i_sb->s_blocksize / 512; +#endif block = udf_get_pblock(inode->i_sb, block, UDF_I_LOCATION(inode).partitionReferenceNum, 0); bh = udf_tread(inode->i_sb, block); @@ -972,13 +979,10 @@ mark_buffer_uptodate(bh, 1); unlock_buffer(bh); mark_buffer_dirty_inode(bh, inode); + ea = bh->b_data + udf_ext0_offset(inode); } else - { - block = udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0); - bh = udf_tread(inode->i_sb, block); - } - ea = bh->b_data + udf_ext0_offset(inode); + ea = UDF_I_DATA(inode) + UDF_I_LENEATTR(inode); eoffset = inode->i_sb->s_blocksize - udf_ext0_offset(inode); pc = (struct pathComponent *)ea; @@ -1016,22 +1020,25 @@ pc->componentType = 5; pc->lengthComponentIdent = 0; pc->componentFileVersionNum = 0; - if (pc->componentIdent[0] == '.') + if (compstart[0] == '.') { - if (pc->lengthComponentIdent == 1) + if ((symname-compstart) == 1) pc->componentType = 4; - else if (pc->lengthComponentIdent == 2 && pc->componentIdent[1] == '.') + else if ((symname-compstart) == 2 && compstart[1] == '.') pc->componentType = 3; } if (pc->componentType == 5) { - if (elen + sizeof(struct pathComponent) + symname - compstart > eoffset) + if ( !(namelen = udf_put_filename(inode->i_sb, compstart, name, symname-compstart))) + goto out_no_entry; + + if (elen + sizeof(struct pathComponent) + namelen > eoffset) goto out_no_entry; else - pc->lengthComponentIdent = symname - compstart; + pc->lengthComponentIdent = namelen; - memcpy(pc->componentIdent, compstart, pc->lengthComponentIdent); + memcpy(pc->componentIdent, name, namelen); } elen += sizeof(struct pathComponent) + pc->lengthComponentIdent; @@ -1186,10 +1193,21 @@ goto end_rename; } retval = -EIO; - dir_bh = udf_bread(old_inode, 0, 0, &retval); - if (!dir_bh) - goto end_rename; - dir_fi = udf_get_fileident(dir_bh->b_data, old_inode->i_sb->s_blocksize, &offset); + if (UDF_I_ALLOCTYPE(old_inode) == ICBTAG_FLAG_AD_IN_ICB) + { + dir_fi = udf_get_fileident(UDF_I_DATA(old_inode) - + (UDF_I_EFE(old_inode) ? + sizeof(struct extendedFileEntry) : + sizeof(struct fileEntry)), + old_inode->i_sb->s_blocksize, &offset); + } + else + { + dir_bh = udf_bread(old_inode, 0, 0, &retval); + if (!dir_bh) + goto end_rename; + dir_fi = udf_get_fileident(dir_bh->b_data, old_inode->i_sb->s_blocksize, &offset); + } if (!dir_fi) goto end_rename; if (udf_get_lb_pblock(old_inode->i_sb, cpu_to_lelb(dir_fi->icb.extLocation), 0) != @@ -1241,7 +1259,7 @@ UDF_I_UCTIME(old_dir) = UDF_I_UMTIME(old_dir) = CURRENT_UTIME; mark_inode_dirty(old_dir); - if (dir_bh) + if (dir_fi) { dir_fi->icb.extLocation = lelb_to_cpu(UDF_I_LOCATION(new_dir)); udf_update_tag((char *)dir_fi, (sizeof(struct fileIdentDesc) + diff -u -r -N ../../linus/2.4/linux/fs/udf/super.c linux/fs/udf/super.c --- ../../linus/2.4/linux/fs/udf/super.c 2003-08-03 23:23:24.000000000 +0200 +++ linux/fs/udf/super.c 2003-08-03 23:31:41.000000000 +0200 @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -104,6 +105,7 @@ write_inode: udf_write_inode, put_inode: udf_put_inode, delete_inode: udf_delete_inode, + clear_inode: udf_clear_inode, put_super: udf_put_super, write_super: udf_write_super, statfs: udf_statfs, @@ -313,10 +315,6 @@ UDF_SB(sb)->s_gid = uopt.gid; UDF_SB(sb)->s_umask = uopt.umask; -#if UDFFS_RW != 1 - *flags |= MS_RDONLY; -#endif - if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) return 0; if (*flags & MS_RDONLY) @@ -540,14 +538,14 @@ { if (location == last[i] - UDF_SB_SESSION(sb)) { - lastblock = UDF_SB_ANCHOR(sb)[0] = last[i]; - UDF_SB_ANCHOR(sb)[1] = last[i] - 256; + lastblock = UDF_SB_ANCHOR(sb)[0] = last[i] - UDF_SB_SESSION(sb); + UDF_SB_ANCHOR(sb)[1] = last[i] - 256 - UDF_SB_SESSION(sb); } else if (location == udf_variable_to_fixed(last[i]) - UDF_SB_SESSION(sb)) { UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); - lastblock = UDF_SB_ANCHOR(sb)[0] = udf_variable_to_fixed(last[i]); - UDF_SB_ANCHOR(sb)[1] = lastblock - 256; + lastblock = UDF_SB_ANCHOR(sb)[0] = udf_variable_to_fixed(last[i]) - UDF_SB_SESSION(sb); + UDF_SB_ANCHOR(sb)[1] = lastblock - 256 - UDF_SB_SESSION(sb); } else udf_debug("Anchor found at block %d, location mismatch %d.\n", @@ -556,7 +554,7 @@ else if (ident == TAG_IDENT_FE || ident == TAG_IDENT_EFE) { lastblock = last[i]; - UDF_SB_ANCHOR(sb)[3] = 512 + UDF_SB_SESSION(sb); + UDF_SB_ANCHOR(sb)[3] = 512; } else { @@ -801,7 +799,7 @@ if (UDF_SB_PARTMAPS(sb)[i].s_partition_num == le16_to_cpu(p->partitionNumber)) { UDF_SB_PARTLEN(sb,i) = le32_to_cpu(p->partitionLength); /* blocks */ - UDF_SB_PARTROOT(sb,i) = le32_to_cpu(p->partitionStartingLocation) + UDF_SB_SESSION(sb); + UDF_SB_PARTROOT(sb,i) = le32_to_cpu(p->partitionStartingLocation); if (le32_to_cpu(p->accessType) == PD_ACCESS_TYPE_READ_ONLY) UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_READ_ONLY; if (le32_to_cpu(p->accessType) == PD_ACCESS_TYPE_WRITE_ONCE) @@ -1373,10 +1371,6 @@ memset(UDF_SB(sb), 0x00, sizeof(struct udf_sb_info)); -#if UDFFS_RW != 1 - sb->s_flags |= MS_RDONLY; -#endif - if (!udf_parse_options((char *)options, &uopt)) goto error_out; @@ -1423,7 +1417,7 @@ UDF_SB_LASTBLOCK(sb) = uopt.lastblock; UDF_SB_ANCHOR(sb)[0] = UDF_SB_ANCHOR(sb)[1] = 0; UDF_SB_ANCHOR(sb)[2] = uopt.anchor; - UDF_SB_ANCHOR(sb)[3] = UDF_SB_SESSION(sb) + 256; + UDF_SB_ANCHOR(sb)[3] = 256; if (udf_check_valid(sb, uopt.novrs, silent)) /* read volume recognition sequences */ { @@ -1488,8 +1482,8 @@ { timestamp ts; udf_time_to_stamp(&ts, UDF_SB_RECORDTIME(sb), 0); - udf_info("UDF %s-%s (%s) Mounting volume '%s', timestamp %04u/%02u/%02u %02u:%02u (%x)\n", - UDFFS_VERSION, UDFFS_RW ? "rw" : "ro", UDFFS_DATE, + udf_info("UDF %s (%s) Mounting volume '%s', timestamp %04u/%02u/%02u %02u:%02u (%x)\n", + UDFFS_VERSION, UDFFS_DATE, UDF_SB_VOLIDENT(sb), ts.year, ts.month, ts.day, ts.hour, ts.minute, ts.typeAndTimezone); } @@ -1515,7 +1509,11 @@ iput(inode); goto error_out; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19) sb->s_maxbytes = MAX_LFS_FILESIZE; +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,3) + sb->s_maxbytes = ~0ULL; +#endif return sb; error_out: @@ -1528,23 +1526,9 @@ if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_TABLE) iput(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_table); if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_BITMAP) - { - for (i=0; inumDirs)) : 0) + buf->f_bfree; buf->f_ffree = buf->f_bfree; /* __kernel_fsid_t f_fsid */ - buf->f_namelen = UDF_NAME_LEN; + buf->f_namelen = UDF_NAME_LEN-2; return 0; } diff -u -r -N ../../linus/2.4/linux/fs/udf/symlink.c linux/fs/udf/symlink.c --- ../../linus/2.4/linux/fs/udf/symlink.c 2003-08-03 23:23:24.000000000 +0200 +++ linux/fs/udf/symlink.c 2003-08-03 23:31:41.000000000 +0200 @@ -37,7 +37,7 @@ #include #include "udf_i.h" -static void udf_pc_to_char(char *from, int fromlen, char *to) +static void udf_pc_to_char(struct super_block *sb, char *from, int fromlen, char *to) { struct pathComponent *pc; int elen = 0; @@ -65,9 +65,9 @@ /* that would be . - just ignore */ break; case 5: - memcpy(p, pc->componentIdent, pc->lengthComponentIdent); - p += pc->lengthComponentIdent; + p += udf_get_filename(sb, pc->componentIdent, p, pc->lengthComponentIdent); *p++ = '/'; + break; } elen += sizeof(struct pathComponent) + pc->lengthComponentIdent; } @@ -84,17 +84,10 @@ char *symlink; int err = -EIO; char *p = kmap(page); - + lock_kernel(); if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB) - { - bh = udf_tread(inode->i_sb, inode->i_ino); - - if (!bh) - goto out; - - symlink = bh->b_data + udf_file_entry_alloc_offset(inode); - } + symlink = UDF_I_DATA(inode) + UDF_I_LENEATTR(inode); else { bh = sb_bread(inode->i_sb, udf_block_map(inode, 0)); @@ -105,7 +98,7 @@ symlink = bh->b_data; } - udf_pc_to_char(symlink, inode->i_size, p); + udf_pc_to_char(inode->i_sb, symlink, inode->i_size, p); udf_release_data(bh); unlock_kernel(); diff -u -r -N ../../linus/2.4/linux/fs/udf/truncate.c linux/fs/udf/truncate.c --- ../../linus/2.4/linux/fs/udf/truncate.c 2003-08-03 23:23:24.000000000 +0200 +++ linux/fs/udf/truncate.c 2003-08-03 23:31:41.000000000 +0200 @@ -57,7 +57,12 @@ if (last_block - first_block > 0) { if (etype == (EXT_RECORDED_ALLOCATED >> 30)) + { +#ifdef OLD_QUOTA + inode->i_blocks -= ((inode->i_sb->s_blocksize / 512) * (last_block - first_block)); +#endif mark_inode_dirty(inode); + } if (etype != (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)) udf_free_blocks(inode->i_sb, inode, eloc, first_block, last_block - first_block); @@ -94,7 +99,7 @@ else lenalloc = extoffset - adsize; - if (!memcmp(&UDF_I_LOCATION(inode), &bloc, sizeof(lb_addr))) + if (!bh) lenalloc -= udf_file_entry_alloc_offset(inode); else lenalloc -= sizeof(struct allocExtDesc); @@ -107,15 +112,15 @@ extoffset = 0; if (lelen) { - if (!memcmp(&UDF_I_LOCATION(inode), &bloc, sizeof(lb_addr))) - memset(bh->b_data, 0x00, udf_file_entry_alloc_offset(inode)); + if (!bh) + BUG(); else memset(bh->b_data, 0x00, sizeof(struct allocExtDesc)); udf_free_blocks(inode->i_sb, inode, bloc, 0, lelen); } else { - if (!memcmp(&UDF_I_LOCATION(inode), &bloc, sizeof(lb_addr))) + if (!bh) { UDF_I_LENALLOC(inode) = lenalloc; mark_inode_dirty(inode); @@ -134,9 +139,9 @@ } udf_release_data(bh); - bh = NULL; - + extoffset = sizeof(struct allocExtDesc); bloc = eloc; + bh = udf_tread(inode->i_sb, udf_get_lb_pblock(inode->i_sb, bloc, 0)); if (elen) lelen = (elen + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits; @@ -152,15 +157,15 @@ if (lelen) { - if (!memcmp(&UDF_I_LOCATION(inode), &bloc, sizeof(lb_addr))) - memset(bh->b_data, 0x00, udf_file_entry_alloc_offset(inode)); + if (!bh) + BUG(); else memset(bh->b_data, 0x00, sizeof(struct allocExtDesc)); udf_free_blocks(inode->i_sb, inode, bloc, 0, lelen); } else { - if (!memcmp(&UDF_I_LOCATION(inode), &bloc, sizeof(lb_addr))) + if (!bh) { UDF_I_LENALLOC(inode) = lenalloc; mark_inode_dirty(inode); diff -u -r -N ../../linus/2.4/linux/fs/udf/udf_i.h linux/fs/udf/udf_i.h --- ../../linus/2.4/linux/fs/udf/udf_i.h 2003-08-03 23:23:24.000000000 +0200 +++ linux/fs/udf/udf_i.h 2003-08-03 23:31:41.000000000 +0200 @@ -9,14 +9,17 @@ #define UDF_I_LENEXTENTS(X) ( UDF_I(X)->i_lenExtents ) #define UDF_I_UNIQUE(X) ( UDF_I(X)->i_unique ) #define UDF_I_ALLOCTYPE(X) ( UDF_I(X)->i_alloc_type ) -#define UDF_I_EXTENDED_FE(X) ( UDF_I(X)->i_extended_fe ) -#define UDF_I_STRAT4096(X) ( UDF_I(X)->i_strat_4096 ) -#define UDF_I_NEW_INODE(X) ( UDF_I(X)->i_new_inode ) +#define UDF_I_EFE(X) ( UDF_I(X)->i_efe ) +#define UDF_I_USE(X) ( UDF_I(X)->i_use ) +#define UDF_I_STRAT4096(X) ( UDF_I(X)->i_strat4096 ) #define UDF_I_NEXT_ALLOC_BLOCK(X) ( UDF_I(X)->i_next_alloc_block ) #define UDF_I_NEXT_ALLOC_GOAL(X) ( UDF_I(X)->i_next_alloc_goal ) #define UDF_I_UMTIME(X) ( UDF_I(X)->i_umtime ) #define UDF_I_UCTIME(X) ( UDF_I(X)->i_uctime ) #define UDF_I_CRTIME(X) ( UDF_I(X)->i_crtime ) #define UDF_I_UCRTIME(X) ( UDF_I(X)->i_ucrtime ) +#define UDF_I_SAD(X) ( UDF_I(X)->i_ext.i_sad ) +#define UDF_I_LAD(X) ( UDF_I(X)->i_ext.i_lad ) +#define UDF_I_DATA(X) ( UDF_I(X)->i_ext.i_data ) #endif /* !defined(_LINUX_UDF_I_H) */ diff -u -r -N ../../linus/2.4/linux/fs/udf/udf_sb.h linux/fs/udf/udf_sb.h --- ../../linus/2.4/linux/fs/udf/udf_sb.h 2003-08-03 23:23:24.000000000 +0200 +++ linux/fs/udf/udf_sb.h 2003-08-03 23:31:41.000000000 +0200 @@ -60,13 +60,14 @@ {\ int nr_groups = ((UDF_SB_PARTLEN((X),(Y)) + (sizeof(struct spaceBitmapDesc) << 3) +\ ((X)->s_blocksize * 8) - 1) / ((X)->s_blocksize * 8));\ - UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap = kmalloc(sizeof(struct udf_bitmap) +\ - sizeof(struct buffer_head *) * nr_groups,\ - GFP_KERNEL);\ + int size = sizeof(struct udf_bitmap) + (sizeof(struct buffer_head *) * nr_groups);\ + if (size <= PAGE_SIZE)\ + UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap = kmalloc(size, GFP_KERNEL);\ + else\ + UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap = vmalloc(size);\ if (UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap != NULL)\ {\ - memset(UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap, 0x00,\ - sizeof(struct udf_bitmap) + sizeof(struct buffer_head *) * nr_groups);\ + memset(UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap, 0x00, size);\ UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_block_bitmap =\ (struct buffer_head **)(UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap + 1);\ UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_nr_groups = nr_groups;\ @@ -77,6 +78,21 @@ }\ } +#define UDF_SB_FREE_BITMAP(X,Y,Z)\ +{\ + int i;\ + int nr_groups = UDF_SB_BITMAP_NR_GROUPS(X,Y,Z);\ + int size = sizeof(struct udf_bitmap) + (sizeof(struct buffer_head *) * nr_groups);\ + for (i=0; is_flags & ( 1 << (Y) ) ) #define UDF_SET_FLAG(X,Y) ( UDF_SB(X)->s_flags |= ( 1 << (Y) ) ) @@ -95,7 +111,7 @@ #define UDF_SB_PARTFUNC(X,Y) ( UDF_SB_PARTMAPS(X)[(Y)].s_partition_func ) #define UDF_SB_PARTFLAGS(X,Y) ( UDF_SB_PARTMAPS(X)[(Y)].s_partition_flags ) #define UDF_SB_BITMAP(X,Y,Z,I) ( UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_block_bitmap[I] ) -#define UDF_SB_BITMAP_NR_GROUPS(X,Y,Z) ( UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_nr_groups ) +#define UDF_SB_BITMAP_NR_GROUPS(X,Y,Z) ( UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_nr_groups ) #define UDF_SB_VOLIDENT(X) ( UDF_SB(X)->s_volident ) #define UDF_SB_NUMPARTS(X) ( UDF_SB(X)->s_partitions ) diff -u -r -N ../../linus/2.4/linux/fs/udf/udfdecl.h linux/fs/udf/udfdecl.h --- ../../linus/2.4/linux/fs/udf/udfdecl.h 2003-08-03 23:23:24.000000000 +0200 +++ linux/fs/udf/udfdecl.h 2003-08-03 23:31:41.000000000 +0200 @@ -28,15 +28,17 @@ #define UDF_EXTENT_FLAG_MASK 0xC0000000 #define UDF_NAME_PAD 4 -#define UDF_NAME_LEN 255 +#define UDF_NAME_LEN 256 #define UDF_PATH_LEN 1023 #define CURRENT_UTIME (xtime.tv_usec) #define udf_file_entry_alloc_offset(inode)\ - ((UDF_I_EXTENDED_FE(inode) ?\ - sizeof(struct extendedFileEntry) :\ - sizeof(struct fileEntry)) + UDF_I_LENEATTR(inode)) + (UDF_I_USE(inode) ?\ + sizeof(struct unallocSpaceEntry) :\ + ((UDF_I_EFE(inode) ?\ + sizeof(struct extendedFileEntry) :\ + sizeof(struct fileEntry)) + UDF_I_LENEATTR(inode))) #define udf_ext0_offset(inode)\ (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB ?\ @@ -66,13 +68,6 @@ int eoffset; }; -struct udf_directory_record -{ - uint32_t d_parent; - uint32_t d_inode; - uint32_t d_name[255]; -}; - struct udf_vds_record { uint32_t block; @@ -88,7 +83,7 @@ struct ustr { uint8_t u_cmpID; - uint8_t u_name[UDF_NAME_LEN]; + uint8_t u_name[UDF_NAME_LEN-2]; uint8_t u_len; }; @@ -113,6 +108,7 @@ extern void udf_read_inode(struct inode *); extern void udf_put_inode(struct inode *); extern void udf_delete_inode(struct inode *); +extern void udf_clear_inode(struct inode *); extern void udf_write_inode(struct inode *, int); extern long udf_block_map(struct inode *, long); extern int8_t inode_bmap(struct inode *, int, lb_addr *, uint32_t *, lb_addr *, uint32_t *, uint32_t *, struct buffer_head **); @@ -128,11 +124,13 @@ extern int udf_read_tagged_data(char *, int size, int fd, int block, int partref); extern struct buffer_head *udf_tgetblk(struct super_block *, int); extern struct buffer_head *udf_tread(struct super_block *, int); -extern struct genericFormat *udf_add_extendedattr(struct inode *, uint32_t, uint32_t, uint8_t, struct buffer_head **); -extern struct genericFormat *udf_get_extendedattr(struct inode *, uint32_t, uint8_t, struct buffer_head **); +extern struct genericFormat *udf_add_extendedattr(struct inode *, uint32_t, uint32_t, uint8_t); +extern struct genericFormat *udf_get_extendedattr(struct inode *, uint32_t, uint8_t); extern struct buffer_head *udf_read_tagged(struct super_block *, uint32_t, uint32_t, uint16_t *); extern struct buffer_head *udf_read_ptagged(struct super_block *, lb_addr, uint32_t, uint16_t *); extern void udf_release_data(struct buffer_head *); +extern void udf_update_tag(char *, int); +extern void udf_new_tag(char *, uint16_t, uint16_t, uint16_t, uint32_t, int); /* lowlevel.c */ extern unsigned int udf_get_last_session(struct super_block *); @@ -147,18 +145,31 @@ /* unicode.c */ extern int udf_get_filename(struct super_block *, uint8_t *, uint8_t *, int); +extern int udf_put_filename(struct super_block *, const uint8_t *, uint8_t *, int); +extern int udf_build_ustr(struct ustr *, dstring *, int); +extern int udf_CS0toUTF8(struct ustr *, struct ustr *); /* ialloc.c */ extern void udf_free_inode(struct inode *); +#ifndef OLD_QUOTA extern struct inode * udf_new_inode (struct inode *, int, int *); +#else +extern struct inode * udf_new_inode (const struct inode *, int, int *); +#endif /* truncate.c */ extern void udf_truncate_extents(struct inode *); /* balloc.c */ +#ifndef OLD_QUOTA extern void udf_free_blocks(struct super_block *, struct inode *, lb_addr, uint32_t, uint32_t); extern int udf_prealloc_blocks(struct super_block *, struct inode *, uint16_t, uint32_t, uint32_t); extern int udf_new_block(struct super_block *, struct inode *, uint16_t, uint32_t, int *); +#else +extern void udf_free_blocks(struct super_block *, const struct inode *, lb_addr, uint32_t, uint32_t); +extern int udf_prealloc_blocks(struct super_block *, const struct inode *, uint16_t, uint32_t, uint32_t); +extern int udf_new_block(struct super_block *, const struct inode *, uint16_t, uint32_t, int *); +#endif /* fsync.c */ extern int udf_fsync_file(struct file *, struct dentry *, int); @@ -167,40 +178,28 @@ /* directory.c */ extern uint8_t * udf_filead_read(struct inode *, uint8_t *, uint8_t, lb_addr, int *, int *, struct buffer_head **, int *); extern struct fileIdentDesc * udf_fileident_read(struct inode *, loff_t *, struct udf_fileident_bh *, struct fileIdentDesc *, lb_addr *, uint32_t *, lb_addr *, uint32_t *, uint32_t *, struct buffer_head **); - -/* unicode.c */ -extern int udf_ustr_to_dchars(uint8_t *, const struct ustr *, int); -extern int udf_ustr_to_char(uint8_t *, const struct ustr *, int); -extern int udf_ustr_to_dstring(dstring *, const struct ustr *, int); -extern int udf_dchars_to_ustr(struct ustr *, const uint8_t *, int); -extern int udf_char_to_ustr(struct ustr *, const uint8_t *, int); -extern int udf_dstring_to_ustr(struct ustr *, const dstring *, int); -extern int udf_translate_to_linux(uint8_t *, uint8_t *, int, uint8_t *, int); -extern int udf_build_ustr(struct ustr *, dstring *, int); -extern int udf_build_ustr_exact(struct ustr *, dstring *, int); -extern int udf_CS0toUTF8(struct ustr *, struct ustr *); -extern int udf_UTF8toCS0(dstring *, struct ustr *, int); -extern int udf_CS0toNLS(struct nls_table *, struct ustr *, struct ustr *); -extern int udf_NLStoCS0(struct nls_table *, dstring *, struct ustr *, int); +extern struct fileIdentDesc * udf_get_fileident(void * buffer, int bufsize, int * offset); +extern extent_ad * udf_get_fileextent(void * buffer, int bufsize, int * offset); +extern long_ad * udf_get_filelongad(uint8_t *, int, int *, int); +extern short_ad * udf_get_fileshortad(uint8_t *, int, int *, int); +extern uint8_t * udf_get_filead(struct fileEntry *, uint8_t *, int, int, int, int *); /* crc.c */ extern uint16_t udf_crc(uint8_t *, uint32_t, uint16_t); -/* misc.c */ -extern uint32_t udf64_low32(uint64_t); -extern uint32_t udf64_high32(uint64_t); -extern void udf_update_tag(char *, int); -extern void udf_new_tag(char *, uint16_t, uint16_t, uint16_t, uint32_t, int); - /* udftime.c */ extern time_t *udf_stamp_to_time(time_t *, long *, timestamp); extern timestamp *udf_time_to_stamp(timestamp *, time_t, long); -/* directory.c */ -extern struct fileIdentDesc * udf_get_fileident(void * buffer, int bufsize, int * offset); -extern extent_ad * udf_get_fileextent(void * buffer, int bufsize, int * offset); -extern long_ad * udf_get_filelongad(void * buffer, int bufsize, int * offset, int); -extern short_ad * udf_get_fileshortad(void * buffer, int bufsize, int * offset, int); -extern uint8_t * udf_get_filead(struct fileEntry *, uint8_t *, int, int, int, int *); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18) +static inline struct buffer_head * sb_bread(struct super_block *sb, int block) +{ + return bread(sb->s_dev, block, sb->s_blocksize); +} +static inline struct buffer_head * sb_getblk(struct super_block *sb, int block) +{ + return getblk(sb->s_dev, block, sb->s_blocksize); +} +#endif #endif /* __UDF_DECL_H */ diff -u -r -N ../../linus/2.4/linux/fs/udf/udftime.c linux/fs/udf/udftime.c --- ../../linus/2.4/linux/fs/udf/udftime.c 2003-08-03 23:23:24.000000000 +0200 +++ linux/fs/udf/udftime.c 2003-08-03 23:31:41.000000000 +0200 @@ -33,7 +33,6 @@ */ #include -#include #include "udfdecl.h" #define EPOCH_YEAR 1970 diff -u -r -N ../../linus/2.4/linux/fs/udf/unicode.c linux/fs/udf/unicode.c --- ../../linus/2.4/linux/fs/udf/unicode.c 2003-08-03 23:23:24.000000000 +0200 +++ linux/fs/udf/unicode.c 2003-08-03 23:31:41.000000000 +0200 @@ -32,48 +32,11 @@ #include "udf_sb.h" -int udf_ustr_to_dchars(uint8_t *dest, const struct ustr *src, int strlen) -{ - if ( (!dest) || (!src) || (!strlen) || (src->u_len > strlen) ) - return 0; - memcpy(dest+1, src->u_name, src->u_len); - dest[0] = src->u_cmpID; - return src->u_len + 1; -} +static int udf_translate_to_linux(uint8_t *, uint8_t *, int, uint8_t *, int); -int udf_ustr_to_char(uint8_t *dest, const struct ustr *src, int strlen) +static int udf_char_to_ustr(struct ustr *dest, const uint8_t *src, int strlen) { - if ( (!dest) || (!src) || (!strlen) || (src->u_len >= strlen) ) - return 0; - memcpy(dest, src->u_name, src->u_len); - return src->u_len; -} - -int udf_ustr_to_dstring(dstring *dest, const struct ustr *src, int dlength) -{ - if ( udf_ustr_to_dchars(dest, src, dlength-1) ) - { - dest[dlength-1] = src->u_len + 1; - return dlength; - } - else - return 0; -} - -int udf_dchars_to_ustr(struct ustr *dest, const uint8_t *src, int strlen) -{ - if ( (!dest) || (!src) || (!strlen) || (strlen > UDF_NAME_LEN) ) - return 0; - memset(dest, 0, sizeof(struct ustr)); - memcpy(dest->u_name, src+1, strlen-1); - dest->u_cmpID = src[0]; - dest->u_len = strlen-1; - return strlen-1; -} - -int udf_char_to_ustr(struct ustr *dest, const uint8_t *src, int strlen) -{ - if ( (!dest) || (!src) || (!strlen) || (strlen >= UDF_NAME_LEN) ) + if ( (!dest) || (!src) || (!strlen) || (strlen > UDF_NAME_LEN-2) ) return 0; memset(dest, 0, sizeof(struct ustr)); memcpy(dest->u_name, src, strlen); @@ -82,15 +45,6 @@ return strlen; } - -int udf_dstring_to_ustr(struct ustr *dest, const dstring *src, int dlength) -{ - if ( dlength && udf_dchars_to_ustr(dest, src, src[dlength-1]) ) - return dlength; - else - return 0; -} - /* * udf_build_ustr */ @@ -112,7 +66,7 @@ /* * udf_build_ustr_exact */ -int udf_build_ustr_exact(struct ustr *dest, dstring *ptr, int exactsize) +static int udf_build_ustr_exact(struct ustr *dest, dstring *ptr, int exactsize) { if ( (!dest) || (!ptr) || (!exactsize) ) return -1; @@ -224,17 +178,17 @@ * November 12, 1997 - Andrew E. Mileski * Written, tested, and released. */ -int udf_UTF8toCS0(dstring *ocu, struct ustr *utf, int length) +static int udf_UTF8toCS0(dstring *ocu, struct ustr *utf, int length) { unsigned c, i, max_val, utf_char; - int utf_cnt; - int u_len = 0; + int utf_cnt, u_len; memset(ocu, 0, sizeof(dstring) * length); ocu[0] = 8; max_val = 0xffU; try_again: + u_len = 0U; utf_char = 0U; utf_cnt = 0U; for (i = 0U; i < utf->u_len; i++) @@ -318,7 +272,7 @@ return u_len + 1; } -int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o, struct ustr *ocu_i) +static int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o, struct ustr *ocu_i) { uint8_t *ocu; uint32_t c; @@ -360,25 +314,25 @@ return utf_o->u_len; } -int udf_NLStoCS0(struct nls_table *nls, dstring *ocu, struct ustr *uni, int length) +static int udf_NLStoCS0(struct nls_table *nls, dstring *ocu, struct ustr *uni, int length) { unsigned len, i, max_val; uint16_t uni_char; - int uni_cnt; - int u_len = 0; + int u_len; memset(ocu, 0, sizeof(dstring) * length); ocu[0] = 8; max_val = 0xffU; try_again: - uni_char = 0U; - uni_cnt = 0U; + u_len = 0U; for (i = 0U; i < uni->u_len; i++) { len = nls->char2uni(&uni->u_name[i], uni->u_len-i, &uni_char); + if (len <= 0) + continue; - if (len == 2 && max_val == 0xff) + if (uni_char > max_val) { max_val = 0xffffU; ocu[0] = (uint8_t)0x10U; @@ -386,11 +340,9 @@ } if (max_val == 0xffffU) - { ocu[++u_len] = (uint8_t)(uni_char >> 8); - i++; - } ocu[++u_len] = (uint8_t)(uni_char & 0xffU); + i += len - 1; } ocu[length - 1] = (uint8_t)u_len + 1; @@ -434,12 +386,42 @@ return 0; } +int udf_put_filename(struct super_block *sb, const uint8_t *sname, uint8_t *dname, int flen) +{ + struct ustr unifilename; + int namelen; + + if ( !(udf_char_to_ustr(&unifilename, sname, flen)) ) + { + return 0; + } + + if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) + { + if ( !(namelen = udf_UTF8toCS0(dname, &unifilename, UDF_NAME_LEN)) ) + { + return 0; + } + } + else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) + { + if ( !(namelen = udf_NLStoCS0(UDF_SB(sb)->s_nls_map, dname, &unifilename, UDF_NAME_LEN)) ) + { + return 0; + } + } + else + return 0; + + return namelen; +} + #define ILLEGAL_CHAR_MARK '_' #define EXT_MARK '.' #define CRC_MARK '#' #define EXT_SIZE 5 -int udf_translate_to_linux(uint8_t *newName, uint8_t *udfName, int udfLen, uint8_t *fidName, int fidNameLen) +static int udf_translate_to_linux(uint8_t *newName, uint8_t *udfName, int udfLen, uint8_t *fidName, int fidNameLen) { int index, newIndex = 0, needsCRC = 0; int extIndex = 0, newExtIndex = 0, hasExt = 0; diff -u -r -N ../../linus/2.4/linux/include/linux/cdrom.h linux/include/linux/cdrom.h --- ../../linus/2.4/linux/include/linux/cdrom.h 2003-08-03 23:24:05.000000000 +0200 +++ linux/include/linux/cdrom.h 2003-08-03 23:32:18.000000000 +0200 @@ -494,6 +494,7 @@ /* Mode page codes for mode sense/set */ #define GPMODE_R_W_ERROR_PAGE 0x01 #define GPMODE_WRITE_PARMS_PAGE 0x05 +#define GPMODE_WCACHING_PAGE 0x08 #define GPMODE_AUDIO_CTL_PAGE 0x0e #define GPMODE_POWER_PAGE 0x1a #define GPMODE_FAULT_FAIL_PAGE 0x1c @@ -504,6 +505,11 @@ * of MODE_SENSE_POWER_PAGE */ #define GPMODE_CDROM_PAGE 0x0d +#define GPMODE_PAGE_CURRENT 0 +#define GPMODE_PAGE_CHANGE 1 +#define GPMODE_PAGE_DEFAULT 2 +#define GPMODE_PAGE_SAVE 3 + /* DVD struct types */ diff -u -r -N ../../linus/2.4/linux/include/linux/major.h linux/include/linux/major.h --- ../../linus/2.4/linux/include/linux/major.h 2003-08-03 23:24:07.000000000 +0200 +++ linux/include/linux/major.h 2003-08-03 23:32:19.000000000 +0200 @@ -109,6 +109,8 @@ #define SPECIALIX_NORMAL_MAJOR 75 #define SPECIALIX_CALLOUT_MAJOR 76 +#define PACKET_MAJOR 97 + #define COMPAQ_CISS_MAJOR 104 #define COMPAQ_CISS_MAJOR1 105 #define COMPAQ_CISS_MAJOR2 106 diff -u -r -N ../../linus/2.4/linux/include/linux/pktcdvd.h linux/include/linux/pktcdvd.h --- ../../linus/2.4/linux/include/linux/pktcdvd.h 1970-01-01 01:00:00.000000000 +0100 +++ linux/include/linux/pktcdvd.h 2003-08-03 23:32:25.000000000 +0200 @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2000 Jens Axboe + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * Packet writing layer for ATAPI and SCSI CD-R, CD-RW, DVD-R, and + * DVD-RW devices. + * + */ +#ifndef __PKTCDVD_H +#define __PKTCDVD_H + +/* + * 1 for normal debug messages, 2 is very verbose. 0 to turn it off. + */ +#define PACKET_DEBUG 1 + +#define MAX_WRITERS 8 + +#define STACKED_BH_POOL_SIZE 64 + +/* + * use drive write caching -- we need deferred error handling to be + * able to sucessfully recover with this option (drive will return good + * status as soon as the cdb is validated). + */ +#if defined(CONFIG_CDROM_PKTCDVD_WCACHE) +#warning Enabling write caching, use at your own risk +#define USE_WCACHING 1 +#else +#define USE_WCACHING 0 +#endif + +/* + * No user-servicable parts beyond this point -> + */ + +#if PACKET_DEBUG +#define DPRINTK(fmt, args...) printk(KERN_NOTICE fmt, ##args) +#else +#define DPRINTK(fmt, args...) +#endif + +#if PACKET_DEBUG > 1 +#define VPRINTK(fmt, args...) printk(KERN_NOTICE fmt, ##args) +#else +#define VPRINTK(fmt, args...) +#endif + +#define PKT_BUF_LIST 0x89 + +/* + * device types + */ +#define PACKET_CDR 1 +#define PACKET_CDRW 2 +#define PACKET_DVDR 3 +#define PACKET_DVDRW 4 + +/* + * flags + */ +#define PACKET_WRITEABLE 1 /* pd is writeable */ +#define PACKET_NWA_VALID 2 /* next writeable address valid */ +#define PACKET_LRA_VALID 3 /* last recorded address valid */ +#define PACKET_READONLY 4 /* read only pd */ +#define PACKET_RECOVERY 5 /* rq recovery in progress */ +#define PACKET_RQ 6 /* current rq is set */ +#define PACKET_BUSY 7 /* current rq is being processed */ + +/* + * Disc status -- from READ_DISC_INFO + */ +#define PACKET_DISC_EMPTY 0 +#define PACKET_DISC_INCOMPLETE 1 +#define PACKET_DISC_COMPLETE 2 +#define PACKET_DISC_OTHER 3 + +/* + * write type, and corresponding data block type + */ +#define PACKET_MODE1 1 +#define PACKET_MODE2 2 +#define PACKET_BLOCK_MODE1 8 +#define PACKET_BLOCK_MODE2 10 + +/* + * Last session/border status + */ +#define PACKET_SESSION_EMPTY 0 +#define PACKET_SESSION_INCOMPLETE 1 +#define PACKET_SESSION_RESERVED 2 +#define PACKET_SESSION_COMPLETE 3 + +#define PACKET_MCN "4a656e734178626f65323030300000" + +#undef PACKET_USE_LS + +/* + * special requests + */ +#define PKT_THROTTLE_SPEED 1 + +#define PKT_TRAY_UNLOCK 0 +#define PKT_TRAY_LOCK 1 + +/* + * Very crude stats for now + */ +struct packet_stats +{ + unsigned long bh_s; + unsigned long bh_e; + unsigned long bh_cache_hits; + unsigned long page_cache_hits; + unsigned long secs_w; + unsigned long secs_r; +}; + +/* + * packet ioctls + */ +#define PACKET_IOCTL_MAGIC ('X') +#define PACKET_GET_STATS _IOR(PACKET_IOCTL_MAGIC, 0, struct packet_stats) +#define PACKET_SETUP_DEV _IOW(PACKET_IOCTL_MAGIC, 1, unsigned int) +#define PACKET_TEARDOWN_DEV _IOW(PACKET_IOCTL_MAGIC, 2, unsigned int) + +#ifdef __KERNEL__ +#include +#include + +struct packet_settings +{ + __u8 size; /* packet size in frames */ + __u8 fp; /* fixed packets */ + __u8 link_loss; /* the rest is specified + * as per Mt Fuji */ + __u8 write_type; + __u8 track_mode; + __u8 block_mode; +}; + +struct packet_cdrw +{ + struct buffer_head *bhlist; /* string of bhs */ + atomic_t free_bh; + merge_request_fn *front_merge_fn; + merge_request_fn *back_merge_fn; + merge_requests_fn *merge_requests_fn; + request_queue_t r_queue; + void *queuedata; + pid_t pid; + int time_to_die; + struct completion thr_compl; +}; + +struct pktcdvd_device +{ + struct block_device *bdev; + kdev_t dev; /* dev attached */ + kdev_t pkt_dev; /* our dev */ + char name[20]; + struct cdrom_device_info *cdi; /* cdrom matching dev */ + struct packet_settings settings; + struct packet_stats stats; + atomic_t refcnt; + __u8 speed; /* cur write speed */ + unsigned long offset; /* start offset */ + __u8 mode_offset; /* 0 / 8 */ + __u8 type; + unsigned long flags; + __u8 disc_status; + __u8 track_status; /* last one */ + __u32 nwa; /* next writable address */ + __u32 lra; /* last recorded address */ + spinlock_t lock; + struct packet_cdrw cdrw; + wait_queue_head_t wqueue; + struct request *rq; + atomic_t wrqcnt; + struct buffer_head *stacked_bhlist; + int stacked_bhcnt; + + struct semaphore cache_sync_mutex; + int unflushed_writes; + + make_request_fn *make_request_fn; +}; + +/* + * following possibly belongs in cdrom.h + */ + +struct cdvd_capacity +{ + __u32 lba; + __u32 block_length; +}; + +void pkt_elevator_merge_req(struct request *rq, struct request *nxt) {} + +#define ELEVATOR_PKTCDVD \ +((elevator_t) { \ + 0, /* not used */ \ + 0, /* not used */ \ + \ + pkt_elevator_merge, /* elevator_merge_fn */ \ + pkt_elevator_merge_req, \ + }) + +#endif /* __KERNEL__ */ + +#endif /* __PKTCDVD_H */ diff -u -r -N ../../linus/2.4/linux/include/linux/udf_fs.h linux/include/linux/udf_fs.h --- ../../linus/2.4/linux/include/linux/udf_fs.h 2003-08-03 23:24:12.000000000 +0200 +++ linux/include/linux/udf_fs.h 2003-08-03 23:32:26.000000000 +0200 @@ -30,7 +30,6 @@ * HISTORY * */ -#include #ifndef _UDF_FS_H #define _UDF_FS_H 1 @@ -38,18 +37,8 @@ #define UDF_PREALLOCATE #define UDF_DEFAULT_PREALLOC_BLOCKS 8 -#define UDFFS_DATE "2002/03/11" -#define UDFFS_VERSION "0.9.6" - -#if !defined(UDFFS_RW) - -#if defined(CONFIG_UDF_RW) -#define UDFFS_RW 1 -#else /* !defined(CONFIG_UDF_RW) */ -#define UDFFS_RW 0 -#endif /* defined(CONFIG_UDF_RW) */ - -#endif /* !defined(UDFFS_RW) */ +#define UDFFS_DATE "2003/01/05" +#define UDFFS_VERSION "0.9.7" #define UDFFS_DEBUG @@ -67,4 +56,12 @@ #define udf_info(f, a...) \ printk (KERN_INFO "UDF-fs INFO " f, ##a); +#ifdef __KERNEL__ + +#ifndef LINUX_VERSION_CODE +#include +#endif + +#endif /* __KERNEL__ */ + #endif /* _UDF_FS_H */ diff -u -r -N ../../linus/2.4/linux/include/linux/udf_fs_i.h linux/include/linux/udf_fs_i.h --- ../../linus/2.4/linux/include/linux/udf_fs_i.h 2003-08-03 23:24:12.000000000 +0200 +++ linux/include/linux/udf_fs_i.h 2003-08-03 23:32:26.000000000 +0200 @@ -23,30 +23,49 @@ #ifndef _ECMA_167_H typedef struct { - __u32 logicalBlockNum; - __u16 partitionReferenceNum; + __u32 logicalBlockNum; + __u16 partitionReferenceNum; } __attribute__ ((packed)) lb_addr; + +typedef struct +{ + __u32 extLength; + __u32 extPosition; +} __attribute__ ((packed)) short_ad; + +typedef struct +{ + __u32 extLength; + lb_addr extLocation; + __u8 impUse[6]; +} __attribute__ ((packed)) long_ad; #endif struct udf_inode_info { - long i_umtime; - long i_uctime; - long i_crtime; - long i_ucrtime; + long i_umtime; + long i_uctime; + long i_crtime; + long i_ucrtime; /* Physical address of inode */ - lb_addr i_location; - __u64 i_unique; - __u32 i_lenEAttr; - __u32 i_lenAlloc; - __u64 i_lenExtents; - __u32 i_next_alloc_block; - __u32 i_next_alloc_goal; - unsigned i_alloc_type : 3; - unsigned i_extended_fe : 1; - unsigned i_strat_4096 : 1; - unsigned i_new_inode : 1; - unsigned reserved : 26; + lb_addr i_location; + __u64 i_unique; + __u32 i_lenEAttr; + __u32 i_lenAlloc; + __u64 i_lenExtents; + __u32 i_next_alloc_block; + __u32 i_next_alloc_goal; + unsigned i_alloc_type : 3; + unsigned i_efe : 1; + unsigned i_use : 1; + unsigned i_strat4096 : 1; + unsigned reserved : 26; + union + { + short_ad *i_sad; + long_ad *i_lad; + __u8 *i_data; + } i_ext; }; #endif