cvs commit: patches/linux linux-2.4.22-packet.patch

tushar at linuxfromscratch.org tushar at linuxfromscratch.org
Thu Oct 9 19:08:42 PDT 2003


tushar      03/10/09 20:08:41

  Added:       linux    linux-2.4.22-packet.patch
  Log:
  Added Patch linux-2.4.22-packet.patch
  
  Revision  Changes    Path
  1.1                  patches/linux/linux-2.4.22-packet.patch
  
  Index: linux-2.4.22-packet.patch
  ===================================================================
  Submitted By: BLFS BOOK <blfs-book at linuxfromscratch.org>
  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 <file:Documentation/modules.txt>.  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 <linux/atm_tcp.h>
   #include <linux/sonet.h>
   #include <linux/atm_suni.h>
  +#include <linux/pktcdvd.h>
   #include <linux/mtd/mtd.h>
   
   #include <net/bluetooth/bluetooth.h>
  @@ -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 <axboe at suse.de>
  + *
  + * 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 <bcollins at debian.org>
  + * - 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 at suse.de)"
  +
  +#include <linux/config.h>
  +#include <linux/module.h>
  +#include <linux/types.h>
  +#include <linux/kernel.h>
  +#include <linux/slab.h>
  +#include <linux/errno.h>
  +#include <linux/delay.h>
  +#include <linux/locks.h>
  +#include <linux/spinlock.h>
  +#include <linux/interrupt.h>
  +#include <linux/file.h>
  +#include <linux/blk.h>
  +#include <linux/blkpg.h>
  +#include <linux/cdrom.h>
  +#include <linux/ide.h>
  +#include <linux/smp_lock.h>
  +#include <linux/pktcdvd.h>
  +#include <linux/kernel_stat.h>
  +#include <linux/sysrq.h>
  +
  +#include <asm/unaligned.h>
  +#include <asm/uaccess.h>
  +
  +/*
  + * 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(&current->sigmask_lock);
  +	siginitsetinv(&current->blocked, sigmask(SIGKILL));
  +	flush_signals(current);
  +	spin_unlock_irq(&current->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 <axboe at suse.de>");
  +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 <johnsom at orst.edu>
    *
  + * 4.99			- Added write support for packet writing.
  + *
    *************************************************************************/
    
  -#define IDECD_VERSION "4.59-ac1"
  +#define IDECD_VERSION "4.99"
   
   #include <linux/config.h>
   #include <linux/module.h>
  @@ -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 <axboe at suse.de> - support DVD-RAM
    *	 transparently and loose the GHOST hack
    *
  + *          Modified by Jens Axboe <axboe at suse.de> - support packet writing
  + *          through generic packet layer.
  + *
    *	 Modified by Arnaldo Carvalho de Melo <acme at conectiva.com.br>
    *	 check resource allocation in sr_init and some cleanups
    *
    */
   
   #include <linux/module.h>
  +#include <linux/config.h>
   
   #include <linux/fs.h>
   #include <linux/kernel.h>
  @@ -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; i<num; i++)
  +					brelse(bha[i]);
  +			}
  +		}
   	}
   	else
   	{
  @@ -143,34 +173,6 @@
   		return -ENOENT;
   	}
   
  -	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; i<num; i++)
  -				brelse(bha[i]);
  -		}
  -	}
  -
   	while ( nf_pos < size )
   	{
   		filp->f_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 <linux/fs.h>
   #include <linux/string.h>
  @@ -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 <linux/locks.h>
   #include <linux/quotaops.h>
   #include <linux/udf_fs.h>
  +#include <linux/slab.h>
   
   #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 <linux/mm.h>
   #include <linux/smp_lock.h>
   #include <linux/module.h>
  +#include <linux/slab.h>
   
   #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 <linux/version.h>
   #include <linux/blkdev.h>
   #include <linux/slab.h>
  +#include <linux/vmalloc.h>
   #include <linux/kernel.h>
   #include <linux/locks.h>
   #include <linux/module.h>
  @@ -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; i<UDF_SB_BITMAP_NR_GROUPS(sb,UDF_SB_PARTITION(sb),s_uspace); i++)
  -			{
  -				if (UDF_SB_BITMAP(sb,UDF_SB_PARTITION(sb),s_uspace,i))
  -					udf_release_data(UDF_SB_BITMAP(sb,UDF_SB_PARTITION(sb),s_uspace,i));
  -			}
  -			kfree(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_bitmap);
  -		}
  +			UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb),s_uspace);
   		if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_BITMAP)
  -		{
  -			for (i=0; i<UDF_SB_BITMAP_NR_GROUPS(sb,UDF_SB_PARTITION(sb),s_fspace); i++)
  -			{
  -				if (UDF_SB_BITMAP(sb,UDF_SB_PARTITION(sb),s_fspace,i))
  -					udf_release_data(UDF_SB_BITMAP(sb,UDF_SB_PARTITION(sb),s_fspace,i));
  -			}
  -			kfree(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_bitmap);
  -		}
  +			UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb),s_fspace);
   		if (UDF_SB_PARTTYPE(sb, UDF_SB_PARTITION(sb)) == UDF_SPARABLE_MAP15)
   		{
   			for (i=0; i<4; i++)
  @@ -1618,23 +1602,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; i<UDF_SB_BITMAP_NR_GROUPS(sb,UDF_SB_PARTITION(sb),s_uspace); i++)
  -			{
  -				if (UDF_SB_BITMAP(sb,UDF_SB_PARTITION(sb),s_uspace,i))
  -					udf_release_data(UDF_SB_BITMAP(sb,UDF_SB_PARTITION(sb),s_uspace,i));
  -			}
  -			kfree(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_bitmap);
  -		}
  +			UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb),s_uspace);
   		if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_BITMAP)
  -		{
  -			for (i=0; i<UDF_SB_BITMAP_NR_GROUPS(sb,UDF_SB_PARTITION(sb),s_fspace); i++)
  -			{
  -				if (UDF_SB_BITMAP(sb,UDF_SB_PARTITION(sb),s_fspace,i))
  -					udf_release_data(UDF_SB_BITMAP(sb,UDF_SB_PARTITION(sb),s_fspace,i));
  -			}
  -			kfree(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_bitmap);
  -		}
  +			UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb),s_fspace);
   		if (UDF_SB_PARTTYPE(sb, UDF_SB_PARTITION(sb)) == UDF_SPARABLE_MAP15)
   		{
   			for (i=0; i<4; i++)
  @@ -1677,7 +1647,7 @@
   		le32_to_cpu(UDF_SB_LVIDIU(sb)->numDirs)) : 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 <linux/smp_lock.h>
   #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; i<nr_groups; i++)\
  +	{\
  +		if (UDF_SB_BITMAP(X,Y,Z,i))\
  +			udf_release_data(UDF_SB_BITMAP(X,Y,Z,i));\
  +	}\
  +	if (size <= PAGE_SIZE)\
  +		kfree(UDF_SB_PARTMAPS(X)[Y].Z.s_bitmap);\
  +	else\
  +		vfree(UDF_SB_PARTMAPS(X)[Y].Z.s_bitmap);\
  +}
   
   #define UDF_QUERY_FLAG(X,Y)			( UDF_SB(X)->s_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 <linux/types.h>
  -#include <linux/kernel.h>
   #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 <axboe at suse.de>
  + *
  + * 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 <linux/blkdev.h>
  +#include <linux/completion.h>
  +
  +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 <linux/config.h>
   
   #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 <linux/version.h>
  +#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
  
  
  



More information about the patches mailing list