From: Ben Fennema <bfennema@falcon.csc.calpoly.edu>

- added udf 2.5 #defines

- fixed prealloc discard race

- fixed several bugs in inode_getblk

- added S_IFSOCK support

- fix unicode encoding bug

- change partition allocation from kmalloc to vmalloc for large
  allocations


---

 25-akpm/CREDITS                           |    3 
 25-akpm/Documentation/filesystems/udf.txt |   12 -
 25-akpm/MAINTAINERS                       |    2 
 25-akpm/fs/udf/dir.c                      |    4 
 25-akpm/fs/udf/file.c                     |    6 
 25-akpm/fs/udf/inode.c                    |  106 ++++++++------
 25-akpm/fs/udf/misc.c                     |  100 +++----------
 25-akpm/fs/udf/namei.c                    |   36 ++--
 25-akpm/fs/udf/osta_udf.h                 |   81 +++++++---
 25-akpm/fs/udf/super.c                    |  227 +++++++++++++-----------------
 25-akpm/fs/udf/truncate.c                 |   63 ++++++++
 25-akpm/fs/udf/udf_sb.h                   |   28 ++-
 25-akpm/fs/udf/udfdecl.h                  |   19 --
 25-akpm/fs/udf/unicode.c                  |   24 +--
 25-akpm/include/linux/udf_fs.h            |    8 -
 15 files changed, 376 insertions(+), 343 deletions(-)

diff -puN CREDITS~udffs-update CREDITS
--- 25/CREDITS~udffs-update	Wed Mar 10 11:47:52 2004
+++ 25-akpm/CREDITS	Wed Mar 10 11:47:52 2004
@@ -974,8 +974,7 @@ N: Ben Fennema
 E: bfennema@falcon.csc.calpoly.edu
 W: http://www.csc.calpoly.edu/~bfennema
 D: UDF filesystem
-S: 21760 Irma Lyle Drive
-S: Los Gatos, CA 95033-8942
+S: (ask for current address)
 S: USA
 
 N: Jürgen Fischer
diff -puN Documentation/filesystems/udf.txt~udffs-update Documentation/filesystems/udf.txt
--- 25/Documentation/filesystems/udf.txt~udffs-update	Wed Mar 10 11:47:52 2004
+++ 25-akpm/Documentation/filesystems/udf.txt	Wed Mar 10 11:47:52 2004
@@ -1,7 +1,7 @@
 *
 * ./Documentation/filesystems/udf.txt
 *
-UDF Filesystem version 0.9.5
+UDF Filesystem version 0.9.8.1
 
 If you encounter problems with reading UDF discs using this driver,
 please report them to linux_udf@hpesjro.fc.hp.com, which is the
@@ -16,7 +16,7 @@ The following mount options are supporte
 	gid=		Set the default group.
 	umask=		Set the default umask.
 	uid=		Set the default user.
-	bs=			Set the block size. 
+	bs=		Set the block size.
 	unhide		Show otherwise hidden files.
 	undelete	Show deleted files in lists.
 	adinicb		Embed data in the inode (default)
@@ -47,15 +47,11 @@ The following expect a offset from the p
 -------------------------------------------------------------------------------
 
 
-For more information see:
-	http://www.trylinux.com/projects/udf/index.html
-
 For the latest version and toolset see:
-	http://www.csc.calpoly.edu/~bfennema/udf.html
 	http://linux-udf.sourceforge.net/
 
 Documentation on UDF and ECMA 167 is available FREE from:
-    http://www.osta.org/
-    http://www.ecma.ch/
+	http://www.osta.org/
+	http://www.ecma-international.org/
 
 Ben Fennema <bfennema@falcon.csc.calpoly.edu>
diff -puN fs/udf/dir.c~udffs-update fs/udf/dir.c
--- 25/fs/udf/dir.c~udffs-update	Wed Mar 10 11:47:52 2004
+++ 25-akpm/fs/udf/dir.c	Wed Mar 10 11:47:52 2004
@@ -15,7 +15,7 @@
  *		ftp://prep.ai.mit.edu/pub/gnu/GPL
  *	Each contributing author retains all rights to their own work.
  *
- *  (C) 1998-2001 Ben Fennema
+ *  (C) 1998-2004 Ben Fennema
  *
  * HISTORY
  *
@@ -111,7 +111,7 @@ do_udf_readdir(struct inode * dir, struc
 	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;
diff -puN fs/udf/file.c~udffs-update fs/udf/file.c
--- 25/fs/udf/file.c~udffs-update	Wed Mar 10 11:47:52 2004
+++ 25-akpm/fs/udf/file.c	Wed Mar 10 11:47:52 2004
@@ -16,7 +16,7 @@
  *  Each contributing author retains all rights to their own work.
  *
  *  (C) 1998-1999 Dave Boynton
- *  (C) 1998-2001 Ben Fennema
+ *  (C) 1998-2004 Ben Fennema
  *  (C) 1999-2000 Stelias Computing Inc
  *
  * HISTORY
@@ -247,9 +247,9 @@ static int udf_release_file(struct inode
 {
 	if (filp->f_mode & FMODE_WRITE)
 	{
-		lock_kernel();
+		down(&inode->i_sem);
 		udf_discard_prealloc(inode);
-		unlock_kernel();
+		up(&inode->i_sem);
 	}
 	return 0;
 }
diff -puN fs/udf/inode.c~udffs-update fs/udf/inode.c
--- 25/fs/udf/inode.c~udffs-update	Wed Mar 10 11:47:52 2004
+++ 25-akpm/fs/udf/inode.c	Wed Mar 10 11:47:52 2004
@@ -16,7 +16,7 @@
  *  Each contributing author retains all rights to their own work.
  *
  *  (C) 1998 Dave Boynton
- *  (C) 1998-2001 Ben Fennema
+ *  (C) 1998-2004 Ben Fennema
  *  (C) 1999-2000 Stelias Computing Inc
  *
  * HISTORY
@@ -84,9 +84,9 @@ void udf_put_inode(struct inode * inode)
 {
 	if (!(inode->i_sb->s_flags & MS_RDONLY))
 	{
-		lock_kernel();
+		down(&inode->i_sem);
 		udf_discard_prealloc(inode);
-		unlock_kernel();
+		up(&inode->i_sem);
 	}
 }
 
@@ -130,15 +130,6 @@ void udf_clear_inode(struct inode *inode
 	UDF_I_DATA(inode) = NULL;
 }
 
-void udf_discard_prealloc(struct inode * inode)
-{
-	if (inode->i_size && inode->i_size != UDF_I_LENEXTENTS(inode) &&
-		UDF_I_ALLOCTYPE(inode) != ICBTAG_FLAG_AD_IN_ICB)
-	{
-		udf_truncate_extents(inode);
-	}
-}
-
 static int udf_writepage(struct page *page, struct writeback_control *wbc)
 {
 	return block_write_full_page(page, udf_get_block, wbc);
@@ -516,11 +507,8 @@ static struct buffer_head * inode_getblk
 		else
 			lastblock = 1;
 	}
+	udf_release_data(cbh);
 	udf_release_data(nbh);
-	if (!pbh)
-		pbh = cbh;
-	else
-		udf_release_data(cbh);
 
 	/* if the current extent is not recorded but allocated, get the
 		block in the extent corresponding to the requested block */
@@ -595,7 +583,7 @@ static void udf_split_extents(struct ino
 		int curr = *c;
 		int blen = ((laarr[curr].extLength & UDF_EXTENT_LENGTH_MASK) +
 			inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
-		int type = laarr[curr].extLength & ~UDF_EXTENT_LENGTH_MASK;
+		int8_t etype = (laarr[curr].extLength >> 30);
 
 		if (blen == 1)
 			;
@@ -612,7 +600,7 @@ static void udf_split_extents(struct ino
 
 		if (offset)
 		{
-			if ((type >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30))
+			if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30))
 			{
 				udf_free_blocks(inode->i_sb, inode, laarr[curr].extLocation, 0, offset);
 				laarr[curr].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
@@ -621,7 +609,7 @@ static void udf_split_extents(struct ino
 				laarr[curr].extLocation.partitionReferenceNum = 0;
 			}
 			else
-				laarr[curr].extLength = type |
+				laarr[curr].extLength = (etype << 30) |
 					(offset << inode->i_sb->s_blocksize_bits);
 			curr ++;
 			(*c) ++;
@@ -629,7 +617,7 @@ static void udf_split_extents(struct ino
 		}
 		
 		laarr[curr].extLocation.logicalBlockNum = newblocknum;
-		if ((type >> 30) == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
+		if (etype == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
 			laarr[curr].extLocation.partitionReferenceNum =
 				UDF_I_LOCATION(inode).partitionReferenceNum;
 		laarr[curr].extLength = EXT_RECORDED_ALLOCATED |
@@ -638,9 +626,9 @@ static void udf_split_extents(struct ino
 
 		if (blen != offset + 1)
 		{
-			if ((type >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30))
+			if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30))
 				laarr[curr].extLocation.logicalBlockNum += (offset + 1);
-			laarr[curr].extLength = type |
+			laarr[curr].extLength = (etype << 30) |
 				((blen - (offset + 1)) << inode->i_sb->s_blocksize_bits);
 			curr ++;
 			(*endnum) ++;
@@ -761,8 +749,8 @@ static void udf_merge_extents(struct ino
 					laarr[i+1].extLength = (laarr[i+1].extLength -
 						(laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
 						UDF_EXTENT_LENGTH_MASK) & ~(inode->i_sb->s_blocksize-1);
-					laarr[i].extLength = (UDF_EXTENT_LENGTH_MASK + 1) -
-						inode->i_sb->s_blocksize;
+					laarr[i].extLength = (laarr[i].extLength & UDF_EXTENT_FLAG_MASK) +
+						(UDF_EXTENT_LENGTH_MASK + 1) - inode->i_sb->s_blocksize;
 					laarr[i+1].extLocation.logicalBlockNum =
 						laarr[i].extLocation.logicalBlockNum +
 						((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) >>
@@ -781,6 +769,47 @@ static void udf_merge_extents(struct ino
 				}
 			}
 		}
+		else if (((laarr[i].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30)) &&
+			((laarr[i+1].extLength >> 30) == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)))
+		{
+			udf_free_blocks(inode->i_sb, inode, laarr[i].extLocation, 0,
+				((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+				inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
+			laarr[i].extLocation.logicalBlockNum = 0;
+			laarr[i].extLocation.partitionReferenceNum = 0;
+
+			if (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+				(laarr[i+1].extLength & UDF_EXTENT_LENGTH_MASK) +
+				inode->i_sb->s_blocksize - 1) & ~UDF_EXTENT_LENGTH_MASK)
+			{
+				laarr[i+1].extLength = (laarr[i+1].extLength -
+					(laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+					UDF_EXTENT_LENGTH_MASK) & ~(inode->i_sb->s_blocksize-1);
+				laarr[i].extLength = (laarr[i].extLength & UDF_EXTENT_FLAG_MASK) +
+					(UDF_EXTENT_LENGTH_MASK + 1) - inode->i_sb->s_blocksize;
+			}
+			else
+			{
+				laarr[i].extLength = laarr[i+1].extLength +
+					(((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+					inode->i_sb->s_blocksize - 1) & ~(inode->i_sb->s_blocksize-1));
+				if (*endnum > (i+2))
+					memmove(&laarr[i+1], &laarr[i+2],
+						sizeof(long_ad) * (*endnum - (i+2)));
+				i --;
+				(*endnum) --;
+			}
+		}
+		else if ((laarr[i].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30))
+		{
+			udf_free_blocks(inode->i_sb, inode, laarr[i].extLocation, 0,
+				((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+			       inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
+			laarr[i].extLocation.logicalBlockNum = 0;
+			laarr[i].extLocation.partitionReferenceNum = 0;
+			laarr[i].extLength = (laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) |
+				EXT_NOT_RECORDED_NOT_ALLOCATED;
+		}
 	}
 }
 
@@ -1014,7 +1043,7 @@ static void udf_fill_inode(struct inode 
 	struct extendedFileEntry *efe;
 	time_t convtime;
 	long convtime_usec;
-	int offset, alen;
+	int offset;
 
 	fe = (struct fileEntry *)bh->b_data;
 	efe = (struct extendedFileEntry *)bh->b_data;
@@ -1115,7 +1144,6 @@ static void udf_fill_inode(struct inode 
 		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
 	{
@@ -1170,7 +1198,6 @@ static void udf_fill_inode(struct inode 
 		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)
@@ -1211,6 +1238,11 @@ static void udf_fill_inode(struct inode 
 			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;
@@ -1228,19 +1260,16 @@ static void udf_fill_inode(struct inode 
 	}
 	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)
 		{
 			init_special_inode(inode, inode->i_mode, MKDEV(
 				le32_to_cpu(dsea->majorDeviceIdent),
-				le32_to_cpu(dsea->minorDeviceIdent)
-			));
+				le32_to_cpu(dsea->minorDeviceIdent)));
 			/* Developer ID ??? */
-			udf_release_data(tbh);
 		}
 		else
 		{
@@ -1372,17 +1401,16 @@ udf_update_inode(struct inode *inode, in
 	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) +
@@ -1396,8 +1424,6 @@ udf_update_inode(struct inode *inode, in
 		eid->identSuffix[1] = UDF_OS_ID_LINUX;
 		dsea->majorDeviceIdent = cpu_to_le32(imajor(inode));
 		dsea->minorDeviceIdent = cpu_to_le32(iminor(inode));
-		mark_buffer_dirty_inode(tbh, inode);
-		udf_release_data(tbh);
 	}
 
 	if (UDF_I_EFE(inode) == 0)
@@ -1493,6 +1519,8 @@ udf_update_inode(struct inode *inode, in
 		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) |
@@ -1625,7 +1653,7 @@ int8_t udf_add_aext(struct inode *inode,
 		int err, loffset;
 		lb_addr obloc = *bloc;
 
-		if (!(bloc->logicalBlockNum = udf_new_block(inode->i_sb, inode,
+		if (!(bloc->logicalBlockNum = udf_new_block(inode->i_sb, NULL,
 			obloc.partitionReferenceNum, obloc.logicalBlockNum, &err)))
 		{
 			return -1;
@@ -1833,7 +1861,7 @@ int8_t udf_current_aext(struct inode *in
 		if (!(*extoffset))
 			*extoffset = sizeof(struct allocExtDesc);
 		ptr = (*bh)->b_data + *extoffset;
-		alen = le32_to_cpu(((struct allocExtDesc *)(*bh)->b_data)->lengthAllocDescs);
+		alen = sizeof(struct allocExtDesc) + le32_to_cpu(((struct allocExtDesc *)(*bh)->b_data)->lengthAllocDescs);
 	}
 
 	switch (UDF_I_ALLOCTYPE(inode))
diff -puN fs/udf/misc.c~udffs-update fs/udf/misc.c
--- 25/fs/udf/misc.c~udffs-update	Wed Mar 10 11:47:52 2004
+++ 25-akpm/fs/udf/misc.c	Wed Mar 10 11:47:52 2004
@@ -16,7 +16,7 @@
  *	Each contributing author retains all rights to their own work.
  *
  *  (C) 1998 Dave Boynton
- *  (C) 1998-2001 Ben Fennema
+ *  (C) 1998-2004 Ben Fennema
  *  (C) 1999-2000 Stelias Computing Inc
  *
  * HISTORY
@@ -34,18 +34,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)
 {
@@ -66,42 +54,24 @@ udf_tread(struct super_block *sb, int bl
 
 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_EFE(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 */
 
@@ -121,7 +91,6 @@ udf_add_extendedattr(struct inode * inod
 			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;
 			}
 		}
@@ -130,8 +99,11 @@ udf_add_extendedattr(struct inode * inod
 			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);
@@ -169,45 +141,30 @@ udf_add_extendedattr(struct inode * inod
 			}
 		}
 		/* 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_EFE(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))
 	{
@@ -218,7 +175,6 @@ udf_get_extendedattr(struct inode * inod
 		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;
 		}
 	
@@ -238,12 +194,6 @@ udf_get_extendedattr(struct inode * inod
 				offset += le32_to_cpu(gaf->attrLength);
 		}
 	}
-
-	udf_release_data(*bh);
-	if (eaicb.extLength)
-	{
-		/* TODO */
-	}
 	return NULL;
 }
 
diff -puN fs/udf/namei.c~udffs-update fs/udf/namei.c
--- 25/fs/udf/namei.c~udffs-update	Wed Mar 10 11:47:52 2004
+++ 25-akpm/fs/udf/namei.c	Wed Mar 10 11:47:52 2004
@@ -15,7 +15,7 @@
  *              ftp://prep.ai.mit.edu/pub/gnu/GPL
  *      Each contributing author retains all rights to their own work.
  *
- *  (C) 1998-2001 Ben Fennema
+ *  (C) 1998-2004 Ben Fennema
  *  (C) 1999-2000 Stelias Computing Inc
  *
  * HISTORY
@@ -36,11 +36,11 @@
 #include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
 
-static inline int udf_match(int len, const char * const name, struct qstr *qs)
+static inline int udf_match(int len1, const char *name1, int len2, const char *name2)
 {
-	if (len != qs->len)
+	if (len1 != len2)
 		return 0;
-	return !memcmp(name, qs->name, len);
+	return !memcmp(name1, name2, len1);
 }
 
 int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi,
@@ -154,8 +154,8 @@ udf_find_entry(struct inode *dir, struct
 {
 	struct fileIdentDesc *fi=NULL;
 	loff_t f_pos;
-	int block, flen;
-	char fname[255];
+	int block, namelen;
+	char name[UDF_NAME_LEN], fname[UDF_NAME_LEN];
 	char *nameptr;
 	uint8_t lfi;
 	uint16_t liu;
@@ -167,6 +167,9 @@ udf_find_entry(struct inode *dir, struct
 	if (!dir)
 		return NULL;
 
+	if ( !(namelen = udf_put_filename(dir->i_sb, dentry->d_name.name, name, dentry->d_name.len)))
+		return NULL;
+
 	f_pos = (udf_ext0_offset(dir) >> 2);
 
 	fibh->soffset = fibh->eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
@@ -250,13 +253,10 @@ udf_find_entry(struct inode *dir, struct
 		if (!lfi)
 			continue;
 
-		if ((flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi)))
+		if (udf_match(namelen, name, lfi, nameptr))
 		{
-			if (udf_match(flen, fname, &(dentry->d_name)))
-			{
-				udf_release_data(bh);
-				return fi;
-			}
+			udf_release_data(bh);
+			return fi;
 		}
 	}
 	if (fibh->sbh != fibh->ebh)
@@ -306,7 +306,7 @@ udf_lookup(struct inode *dir, struct den
 	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);
 
 	lock_kernel();
@@ -353,7 +353,6 @@ udf_add_entry(struct inode *dir, struct 
 	char name[UDF_NAME_LEN], fname[UDF_NAME_LEN];
 	int namelen;
 	loff_t f_pos;
-	int flen;
 	char *nameptr;
 	loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
 	int nfidlen;
@@ -481,8 +480,7 @@ udf_add_entry(struct inode *dir, struct 
 		if (!lfi || !dentry)
 			continue;
 
-		if ((flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi)) &&
-			udf_match(flen, fname, &(dentry->d_name)))
+		if (udf_match(namelen, name, lfi, nameptr))
 		{
 			if (fibh->sbh != fibh->ebh)
 				udf_release_data(fibh->ebh);
@@ -674,8 +672,8 @@ static int udf_mknod(struct inode * dir,
 {
 	struct inode * inode;
 	struct udf_fileident_bh fibh;
-	int err;
 	struct fileIdentDesc cfi, *fi;
+	int err;
 
 	if (!old_valid_dev(rdev))
 		return -EINVAL;
@@ -721,8 +719,8 @@ static int udf_mkdir(struct inode * dir,
 {
 	struct inode * inode;
 	struct udf_fileident_bh fibh;
-	int err;
 	struct fileIdentDesc cfi, *fi;
+	int err;
 
 	lock_kernel();
 	err = -EMLINK;
@@ -1119,8 +1117,8 @@ static int udf_link(struct dentry * old_
 {
 	struct inode *inode = old_dentry->d_inode;
 	struct udf_fileident_bh fibh;
-	int err;
 	struct fileIdentDesc cfi, *fi;
+	int err;
 
 	lock_kernel();
 	if (inode->i_nlink >= (256<<sizeof(inode->i_nlink))-1)
diff -puN fs/udf/osta_udf.h~udffs-update fs/udf/osta_udf.h
--- 25/fs/udf/osta_udf.h~udffs-update	Wed Mar 10 11:47:52 2004
+++ 25-akpm/fs/udf/osta_udf.h	Wed Mar 10 11:47:52 2004
@@ -1,10 +1,10 @@
 /*
  * osta_udf.h
  *
- * This file is based on OSTA UDF(tm) 2.01 (March 15, 2000)
+ * This file is based on OSTA UDF(tm) 2.50 (April 30, 2003)
  * http://www.osta.org
  *
- * Copyright (c) 2001-2002  Ben Fennema <bfennema@falcon.csc.calpoly.edu>
+ * Copyright (c) 2001-2004  Ben Fennema <bfennema@falcon.csc.calpoly.edu>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -37,12 +37,12 @@
 #ifndef _OSTA_UDF_H
 #define _OSTA_UDF_H 1
 
-/* OSTA CS0 Charspec (UDF 2.01 2.1.2) */
+/* OSTA CS0 Charspec (UDF 2.50 2.1.2) */
 #define UDF_CHAR_SET_TYPE		0
 #define UDF_CHAR_SET_INFO		"OSTA Compressed Unicode"
 
-/* Entity Identifier (UDF 2.01 2.1.5) */
-/* Identifiers (UDF 2.01 2.1.5.2) */
+/* Entity Identifier (UDF 2.50 2.1.5) */
+/* Identifiers (UDF 2.50 2.1.5.2) */
 #define UDF_ID_DEVELOPER		"*Linux UDFFS"
 #define	UDF_ID_COMPLIANT		"*OSTA UDF Compliant"
 #define UDF_ID_LV_INFO			"*UDF LV Info"
@@ -59,8 +59,9 @@
 #define UDF_ID_SPARABLE			"*UDF Sparable Partition"
 #define UDF_ID_ALLOC			"*UDF Virtual Alloc Tbl"
 #define UDF_ID_SPARING			"*UDF Sparing Table"
+#define UDF_ID_METADATA			"*UDF Metadata Partition"
 
-/* Identifier Suffix (UDF 2.01 2.1.5.3) */
+/* Identifier Suffix (UDF 2.50 2.1.5.3) */
 #define IS_DF_HARD_WRITE_PROTECT	0x01
 #define IS_DF_SOFT_WRITE_PROTECT	0x02
 
@@ -84,8 +85,8 @@ struct appIdentSuffix
 	uint8_t		impUse[8];
 } __attribute__ ((packed));
 
-/* Logical Volume Integrity Descriptor (UDF 2.01 2.2.6) */
-/* Implementation Use (UDF 2.01 2.2.6.4) */
+/* Logical Volume Integrity Descriptor (UDF 2.50 2.2.6) */
+/* Implementation Use (UDF 2.50 2.2.6.4) */
 struct logicalVolIntegrityDescImpUse
 {
 	regid		impIdent;
@@ -97,8 +98,8 @@ struct logicalVolIntegrityDescImpUse
 	uint8_t		impUse[0];
 } __attribute__ ((packed));
 
-/* Implementation Use Volume Descriptor (UDF 2.01 2.2.7) */
-/* Implementation Use (UDF 2.01 2.2.7.2) */
+/* Implementation Use Volume Descriptor (UDF 2.50 2.2.7) */
+/* Implementation Use (UDF 2.50 2.2.7.2) */
 struct impUseVolDescImpUse
 {
 	charspec	LVICharset;
@@ -120,7 +121,7 @@ struct udfPartitionMap2
 	uint16_t	partitionNum;
 } __attribute__ ((packed));
 
-/* Virtual Partition Map (UDF 2.01 2.2.8) */
+/* Virtual Partition Map (UDF 2.50 2.2.8) */
 struct virtualPartitionMap
 {
 	uint8_t		partitionMapType;
@@ -132,7 +133,7 @@ struct virtualPartitionMap
 	uint8_t		reserved2[24];
 } __attribute__ ((packed));
 
-/* Sparable Partition Map (UDF 2.01 2.2.9) */
+/* Sparable Partition Map (UDF 2.50 2.2.9) */
 struct sparablePartitionMap
 {
 	uint8_t		partitionMapType;
@@ -148,25 +149,43 @@ struct sparablePartitionMap
 	uint32_t	locSparingTable[4];
 } __attribute__ ((packed));
 
+/* Metadata Partition Map (UDF 2.4.0 2.2.10) */
+struct metadataPartitionMap
+{
+	uint8_t		partitionMapType;
+	uint8_t		partitionMapLength;
+	uint8_t		reserved1[2];
+	regid		partIdent;
+	uint16_t	volSeqNum;
+	uint16_t	partitionNum;
+	uint32_t	metadataFileLoc;
+	uint32_t	metadataMirrorFileLoc;
+	uint32_t	metadataBitmapFileLoc;
+	uint32_t	allocUnitSize;
+	uint16_t	alignUnitSize;
+	uint8_t		flags;
+	uint8_t		reserved2[5];
+} __attribute__ ((packed));
+
 /* Virtual Allocation Table (UDF 1.5 2.2.10) */
 struct virtualAllocationTable15
 {
 	uint32_t	VirtualSector[0];
-	regid		ident;
-	uint32_t	previousVATICB;
+	regid		vatIdent;
+	uint32_t	previousVATICBLoc;
 } __attribute__ ((packed));  
 
 #define ICBTAG_FILE_TYPE_VAT15		0x00U
 
-/* Virtual Allocation Table (UDF 2.01 2.2.10) */
+/* Virtual Allocation Table (UDF 2.50 2.2.11) */
 struct virtualAllocationTable20
 {
 	uint16_t	lengthHeader;
 	uint16_t	lengthImpUse;
 	dstring		logicalVolIdent[128];
-	uint32_t	previousVatICBLoc;
-	uint32_t	numFIDSFiles;
-	uint32_t	numFIDSDirectories;
+	uint32_t	previousVATICBLoc;
+	uint32_t	numFiles;
+	uint32_t	numDirs;
 	uint16_t	minReadRevision;
 	uint16_t	minWriteRevision;
 	uint16_t	maxWriteRevision;
@@ -177,7 +196,7 @@ struct virtualAllocationTable20
 
 #define ICBTAG_FILE_TYPE_VAT20		0xF8U
 
-/* Sparing Table (UDF 2.01 2.2.11) */
+/* Sparing Table (UDF 2.50 2.2.12) */
 struct sparingEntry
 {
 	uint32_t	origLocation;
@@ -195,7 +214,12 @@ struct sparingTable
 			mapEntry[0];
 } __attribute__ ((packed));
 
-/* struct long_ad ICB - ADImpUse (UDF 2.01 2.2.4.3) */
+/* Metadata File (and Metadata Mirror File) (UDF 2.50 2.2.13.1) */
+#define ICBTAG_FILE_TYPE_MAIN		0xFA
+#define ICBTAG_FILE_TYPE_MIRROR		0xFB
+#define ICBTAG_FILE_TYPE_BITMAP		0xFC
+
+/* struct long_ad ICB - ADImpUse (UDF 2.50 2.2.4.3) */
 struct allocDescImpUse
 {
 	uint16_t	flags;
@@ -204,18 +228,18 @@ struct allocDescImpUse
 
 #define AD_IU_EXT_ERASED		0x0001
 
-/* Real-Time Files (UDF 2.01 6.11) */
+/* Real-Time Files (UDF 2.50 6.11) */
 #define ICBTAG_FILE_TYPE_REALTIME	0xF9U
 
-/* Implementation Use Extended Attribute (UDF 2.01 3.3.4.5) */
-/* FreeEASpace (UDF 2.01 3.3.4.5.1.1) */
+/* Implementation Use Extended Attribute (UDF 2.50 3.3.4.5) */
+/* FreeEASpace (UDF 2.50 3.3.4.5.1.1) */
 struct freeEaSpace
 {
 	uint16_t	headerChecksum;
 	uint8_t		freeEASpace[0];
 } __attribute__ ((packed));
 
-/* DVD Copyright Management Information (UDF 2.01 3.3.4.5.1.2) */
+/* DVD Copyright Management Information (UDF 2.50 3.3.4.5.1.2) */
 struct DVDCopyrightImpUse 
 {
 	uint16_t	headerChecksum;
@@ -224,21 +248,21 @@ struct DVDCopyrightImpUse 
 	uint8_t		protectionSystemInfo[4];
 } __attribute__ ((packed));
 
-/* Application Use Extended Attribute (UDF 2.01 3.3.4.6) */
-/* FreeAppEASpace (UDF 2.01 3.3.4.6.1) */
+/* Application Use Extended Attribute (UDF 2.50 3.3.4.6) */
+/* FreeAppEASpace (UDF 2.50 3.3.4.6.1) */
 struct freeAppEASpace
 {
 	uint16_t	headerChecksum;
 	uint8_t		freeEASpace[0];
 } __attribute__ ((packed));
 
-/* UDF Defined System Stream (UDF 2.01 3.3.7) */
+/* UDF Defined System Stream (UDF 2.50 3.3.7) */
 #define UDF_ID_UNIQUE_ID		"*UDF Unique ID Mapping Data"
 #define UDF_ID_NON_ALLOC		"*UDF Non-Allocatable Space"
 #define UDF_ID_POWER_CAL		"*UDF Power Cal Table"
 #define UDF_ID_BACKUP			"*UDF Backup"
 
-/* Operating System Identifiers (UDF 2.01 6.3) */
+/* Operating System Identifiers (UDF 2.50 6.3) */
 #define UDF_OS_CLASS_UNDEF		0x00U
 #define UDF_OS_CLASS_DOS		0x01U
 #define UDF_OS_CLASS_OS2		0x02U
@@ -254,6 +278,7 @@ struct freeAppEASpace
 #define UDF_OS_ID_DOS			0x00U
 #define UDF_OS_ID_OS2			0x00U
 #define UDF_OS_ID_MAC			0x00U
+#define UDF_OS_ID_MAX_OSX		0x01U
 #define UDF_OS_ID_UNIX			0x00U
 #define UDF_OS_ID_AIX			0x01U
 #define UDF_OS_ID_SOLARIS		0x02U
diff -puN fs/udf/super.c~udffs-update fs/udf/super.c
--- 25/fs/udf/super.c~udffs-update	Wed Mar 10 11:47:52 2004
+++ 25-akpm/fs/udf/super.c	Wed Mar 10 11:47:52 2004
@@ -26,7 +26,7 @@
  *  Each contributing author retains all rights to their own work.
  *
  *  (C) 1998 Dave Boynton
- *  (C) 1998-2001 Ben Fennema
+ *  (C) 1998-2004 Ben Fennema
  *  (C) 2000 Stelias Computing Inc
  *
  * HISTORY
@@ -133,7 +133,8 @@ static void init_once(void * foo, kmem_c
 	struct udf_inode_info *ei = (struct udf_inode_info *) foo;
 
 	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR) {
+	    SLAB_CTOR_CONSTRUCTOR)
+	{
 		ei->i_ext.i_data = NULL;
 		inode_init_once(&ei->vfs_inode);
 	}
@@ -324,106 +325,106 @@ udf_parse_options(char *options, struct 
 	if (!options)
 		return 1;
 
-	while ((p = strsep(&options, ",")) != NULL) {
+	while ((p = strsep(&options, ",")) != NULL)
+	{
 		substring_t args[MAX_OPT_ARGS];
 		int token;
 		if (!*p)
 			continue;
 
 		token = match_token(p, tokens, args);
-		switch (token) {
-		case Opt_novrs:
-			uopt->novrs = 1;
-			break;
-		case Opt_bs:
-			if (match_int(&args[0], &option))
-				return 0;
-			uopt->blocksize = option;
-			break;
-		case Opt_unhide:
-			uopt->flags |= (1 << UDF_FLAG_UNHIDE);
-			break;
-		case Opt_undelete:
-			uopt->flags |= (1 << UDF_FLAG_UNDELETE);
-			break;
-		case Opt_noadinicb:
-			uopt->flags &= ~(1 << UDF_FLAG_USE_AD_IN_ICB);
-			break;
-		case Opt_adinicb:
-			uopt->flags |= (1 << UDF_FLAG_USE_AD_IN_ICB);
-			break;
-		case Opt_shortad:
-			uopt->flags |= (1 << UDF_FLAG_USE_SHORT_AD);
-			break;
-		case Opt_longad:
-			uopt->flags &= ~(1 << UDF_FLAG_USE_SHORT_AD);
-			break;
-		case Opt_gid:
-			if (match_int(args, &option))
-				return 0;
-			uopt->gid = option;
-			break;
-		case Opt_uid:
-			if (match_int(args, &option))
-				return 0;
-			uopt->uid = option;
-			break;
-		case Opt_umask:
-			if (match_octal(args, &option))
-				return 0;
-			uopt->umask = option;
-			break;
-		case Opt_nostrict:
-			uopt->flags &= ~(1 << UDF_FLAG_STRICT);
-			break;
-		case Opt_session:
-			if (match_int(args, &option))
-				return 0;
-			uopt->session = option;
-			break;
-		case Opt_lastblock:
-			if (match_int(args, &option))
-				return 0;
-			uopt->lastblock = option;
-			break;
-		case Opt_anchor:
-			if (match_int(args, &option))
-				return 0;
-			uopt->anchor = option;
-			break;
-		case Opt_volume:
-			if (match_int(args, &option))
-				return 0;
-			uopt->volume = option;
-			break;
-		case Opt_partition:
-			if (match_int(args, &option))
-				return 0;
-			uopt->partition = option;
-			break;
-		case Opt_fileset:
-			if (match_int(args, &option))
-				return 0;
-			uopt->fileset = option;
-			break;
-		case Opt_rootdir:
-			if (match_int(args, &option))
-				return 0;
-			uopt->rootdir = option;
-			break;
-		case Opt_utf8:
-			uopt->flags |= (1 << UDF_FLAG_UTF8);
-			break;
+		switch (token)
+		{
+			case Opt_novrs:
+				uopt->novrs = 1;
+			case Opt_bs:
+				if (match_int(&args[0], &option))
+					return 0;
+				uopt->blocksize = option;
+				break;
+			case Opt_unhide:
+				uopt->flags |= (1 << UDF_FLAG_UNHIDE);
+				break;
+			case Opt_undelete:
+				uopt->flags |= (1 << UDF_FLAG_UNDELETE);
+				break;
+			case Opt_noadinicb:
+				uopt->flags &= ~(1 << UDF_FLAG_USE_AD_IN_ICB);
+				break;
+			case Opt_adinicb:
+				uopt->flags |= (1 << UDF_FLAG_USE_AD_IN_ICB);
+				break;
+			case Opt_shortad:
+				uopt->flags |= (1 << UDF_FLAG_USE_SHORT_AD);
+				break;
+			case Opt_longad:
+				uopt->flags &= ~(1 << UDF_FLAG_USE_SHORT_AD);
+				break;
+			case Opt_gid:
+				if (match_int(args, &option))
+					return 0;
+				uopt->gid = option;
+				break;
+			case Opt_uid:
+				if (match_int(args, &option))
+					return 0;
+				uopt->uid = option;
+				break;
+			case Opt_umask:
+				if (match_octal(args, &option))
+					return 0;
+				uopt->umask = option;
+				break;
+			case Opt_nostrict:
+				uopt->flags &= ~(1 << UDF_FLAG_STRICT);
+				break;
+			case Opt_session:
+				if (match_int(args, &option))
+					return 0;
+				uopt->session = option;
+				break;
+			case Opt_lastblock:
+				if (match_int(args, &option))
+					return 0;
+				uopt->lastblock = option;
+				break;
+			case Opt_anchor:
+				if (match_int(args, &option))
+					return 0;
+				uopt->anchor = option;
+				break;
+			case Opt_volume:
+				if (match_int(args, &option))
+					return 0;
+				uopt->volume = option;
+				break;
+			case Opt_partition:
+				if (match_int(args, &option))
+					return 0;
+				uopt->partition = option;
+				break;
+			case Opt_fileset:
+				if (match_int(args, &option))
+					return 0;
+				uopt->fileset = option;
+				break;
+			case Opt_rootdir:
+				if (match_int(args, &option))
+					return 0;
+				uopt->rootdir = option;
+				break;
+			case Opt_utf8:
+				uopt->flags |= (1 << UDF_FLAG_UTF8);
+				break;
 #if defined(CONFIG_NLS) || defined(CONFIG_NLS_MODULE)
-		case Opt_iocharset:
-			uopt->nls_map = load_nls(args[0].from);
-			uopt->flags |= (1 << UDF_FLAG_NLS_MAP);
-			break;
+			case Opt_iocharset:
+				uopt->nls_map = load_nls(args[0].from);
+				uopt->flags |= (1 << UDF_FLAG_NLS_MAP);
+				break;
 #endif
-		default:
-			printk(KERN_ERR "udf: bad mount option \"%s\" "
-					"or missing value\n",
-				p);
+			default:
+				printk(KERN_ERR "udf: bad mount option \"%s\" "
+						"or missing value\n", p);
 			return 0;
 		}
 	}
@@ -1651,23 +1652,9 @@ error_out:
 		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++)
@@ -1743,23 +1730,9 @@ udf_put_super(struct super_block *sb)
 		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++)
@@ -1804,7 +1777,7 @@ udf_statfs(struct super_block *sb, struc
 		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 -puN fs/udf/truncate.c~udffs-update fs/udf/truncate.c
--- 25/fs/udf/truncate.c~udffs-update	Wed Mar 10 11:47:52 2004
+++ 25-akpm/fs/udf/truncate.c	Wed Mar 10 11:47:52 2004
@@ -15,7 +15,7 @@
  *		ftp://prep.ai.mit.edu/pub/gnu/GPL
  *	Each contributing author retains all rights to their own work.
  *
- *  (C) 1999-2001 Ben Fennema
+ *  (C) 1999-2004 Ben Fennema
  *  (C) 1999 Stelias Computing Inc
  *
  * HISTORY
@@ -66,6 +66,67 @@ static void extent_trunc(struct inode * 
 	}
 }
 
+void udf_discard_prealloc(struct inode * inode)
+{
+	lb_addr bloc, eloc;
+	uint32_t extoffset = 0, elen, nelen;
+	uint64_t lbcount = 0;
+	int8_t etype = -1, netype;
+	struct buffer_head *bh = NULL;
+	int adsize;
+
+	if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB ||
+		inode->i_size == UDF_I_LENEXTENTS(inode))
+	{
+		return;
+	}
+
+	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
+		adsize = 0;
+
+	bloc = UDF_I_LOCATION(inode);
+
+	while ((netype = udf_next_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 1)) != -1)
+	{
+		etype = netype;
+		lbcount += elen;
+		if (lbcount > inode->i_size && lbcount - inode->i_size < inode->i_sb->s_blocksize)
+		{
+			nelen = elen - (lbcount - inode->i_size);
+			extent_trunc(inode, bloc, extoffset-adsize, eloc, etype, elen, bh, nelen);
+			lbcount = inode->i_size;
+		}
+	}
+	if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30))
+	{
+		extoffset -= adsize;
+		lbcount -= elen;
+		extent_trunc(inode, bloc, extoffset, eloc, etype, elen, bh, 0);
+		if (!bh)
+		{
+			UDF_I_LENALLOC(inode) = extoffset - udf_file_entry_alloc_offset(inode);
+			mark_inode_dirty(inode);
+		}
+		else
+		{
+			struct allocExtDesc *aed = (struct allocExtDesc *)(bh->b_data);
+			aed->lengthAllocDescs = cpu_to_le32(extoffset - sizeof(struct allocExtDesc));
+			if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
+				udf_update_tag(bh->b_data, extoffset);
+			else
+				udf_update_tag(bh->b_data, sizeof(struct allocExtDesc));
+			mark_buffer_dirty_inode(bh, inode);
+		}
+	}
+	UDF_I_LENEXTENTS(inode) = lbcount;
+
+	udf_release_data(bh);
+}
+
 void udf_truncate_extents(struct inode * inode)
 {
 	lb_addr bloc, eloc, neloc = { 0, 0 };
diff -puN fs/udf/udfdecl.h~udffs-update fs/udf/udfdecl.h
--- 25/fs/udf/udfdecl.h~udffs-update	Wed Mar 10 11:47:52 2004
+++ 25-akpm/fs/udf/udfdecl.h	Wed Mar 10 11:47:52 2004
@@ -21,7 +21,7 @@
 #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 udf_file_entry_alloc_offset(inode)\
@@ -59,13 +59,6 @@ struct udf_fileident_bh
 	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;
@@ -81,7 +74,7 @@ struct generic_desc
 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;
 };
 
@@ -116,19 +109,16 @@ extern int8_t udf_insert_aext(struct ino
 extern int8_t udf_delete_aext(struct inode *, lb_addr, int, lb_addr, uint32_t, struct buffer_head *);
 extern int8_t udf_next_aext(struct inode *, lb_addr *, int *, lb_addr *, uint32_t *, struct buffer_head **, int);
 extern int8_t udf_current_aext(struct inode *, lb_addr *, int *, lb_addr *, uint32_t *, struct buffer_head **, int);
-extern void udf_discard_prealloc(struct inode *);
 
 /* misc.c */
 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 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);
 
@@ -154,6 +144,7 @@ extern void udf_free_inode(struct inode 
 extern struct inode * udf_new_inode (struct inode *, int, int *);
 
 /* truncate.c */
+extern void udf_discard_prealloc(struct inode *);
 extern void udf_truncate_extents(struct inode *);
 
 /* balloc.c */
diff -puN fs/udf/udf_sb.h~udffs-update fs/udf/udf_sb.h
--- 25/fs/udf/udf_sb.h~udffs-update	Wed Mar 10 11:47:52 2004
+++ 25-akpm/fs/udf/udf_sb.h	Wed Mar 10 11:47:52 2004
@@ -64,13 +64,14 @@ static inline struct udf_sb_info *UDF_SB
 {\
 	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;\
@@ -81,6 +82,21 @@ static inline struct udf_sb_info *UDF_SB
 	}\
 }
 
+#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) ) )
@@ -99,7 +115,7 @@ static inline struct udf_sb_info *UDF_SB
 #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 -puN fs/udf/unicode.c~udffs-update fs/udf/unicode.c
--- 25/fs/udf/unicode.c~udffs-update	Wed Mar 10 11:47:52 2004
+++ 25-akpm/fs/udf/unicode.c	Wed Mar 10 11:47:52 2004
@@ -36,7 +36,7 @@ static int udf_translate_to_linux(uint8_
 
 static 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);
@@ -181,14 +181,14 @@ int udf_CS0toUTF8(struct ustr *utf_o, st
 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++)
@@ -264,8 +264,8 @@ try_again:
 	if (utf_cnt)
 	{
 error_out:
-		printk(KERN_ERR "udf: bad UTF-8 character\n");
-		return 0;
+		ocu[++u_len] = '?';
+		printk(KERN_DEBUG "udf: bad UTF-8 character\n");
 	}
 
 	ocu[length - 1] = (uint8_t)u_len + 1;
@@ -318,21 +318,21 @@ static int udf_NLStoCS0(struct nls_table
 {
 	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;
@@ -340,11 +340,9 @@ try_again:
 		}
 		
 		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;
diff -puN include/linux/udf_fs.h~udffs-update include/linux/udf_fs.h
--- 25/include/linux/udf_fs.h~udffs-update	Wed Mar 10 11:47:52 2004
+++ 25-akpm/include/linux/udf_fs.h	Wed Mar 10 11:47:52 2004
@@ -8,7 +8,7 @@
  *  OSTA-UDF(tm) = Optical Storage Technology Association
  *  Universal Disk Format.
  *
- *  This code is based on version 2.00 of the UDF specification,
+ *  This code is based on version 2.50 of the UDF specification,
  *  and revision 3 of the ECMA 167 standard [equivalent to ISO 13346].
  *    http://www.osta.org/ *    http://www.ecma.ch/
  *    http://www.iso.org/
@@ -24,7 +24,7 @@
  *		ftp://prep.ai.mit.edu/pub/gnu/GPL
  *	Each contributing author retains all rights to their own work.
  *
- *  (C) 1999-2000 Ben Fennema
+ *  (C) 1999-2004 Ben Fennema
  *  (C) 1999-2000 Stelias Computing Inc
  *
  * HISTORY
@@ -37,8 +37,8 @@
 #define UDF_PREALLOCATE
 #define UDF_DEFAULT_PREALLOC_BLOCKS	8
 
-#define UDFFS_DATE			"2002/11/15"
-#define UDFFS_VERSION			"0.9.7"
+#define UDFFS_DATE			"2004/29/09"
+#define UDFFS_VERSION			"0.9.8.1"
 
 #define UDFFS_DEBUG
 
diff -puN MAINTAINERS~udffs-update MAINTAINERS
--- 25/MAINTAINERS~udffs-update	Wed Mar 10 11:47:52 2004
+++ 25-akpm/MAINTAINERS	Wed Mar 10 11:47:52 2004
@@ -2036,8 +2036,6 @@ S:	Maintained
 UDF FILESYSTEM
 P:	Ben Fennema
 M:	bfennema@falcon.csc.calpoly.edu
-P:	Dave Boynton
-M:	dave@trylinux.com
 L:	linux_udf@hpesjro.fc.hp.com
 W:	http://linux-udf.sourceforge.net
 S:	Maintained

_