Skip to contentSkip to conversation

iso9660 inodes Extended to 128GB

PATCH New Paul Serice 1 participant 1 message May 24, 2004 Isofs filesystem

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 iso9660 inodes Extended to 128GB

This patch addresses the problem that the iso9660 file system cannot reach inode information unless the information is located in the first 4GBs.

This is needed by growisofs to allow it to start additional sessions in the area after the first 4GBs:

    http://fy.chalmers.se/~appro/linux/DVD+RW/#isofs4gb

It is also needed by my pet project to write arbitrarily large streams of data to multiple DVDs without the need for intermediate files:

http://www.serice.net/shunt/

This patch works by incorporating an inode numbering scheme suggested by Sergey Vlasov. His scheme frees 5 bits of the inode number so that they can be used to address the block where the inode information is located. After the patch is applied, the inode information can be located anywhere in the first 128GB of the file system which is enough to accommodate the current generation of DVDs.

I am currently looking into a final solution that allows the iso9660 file system to be able to address inode information anywhere within its 32-bit address space, but I'm not sure how long it will take because I think it might require implementing the export operations. In the meantime, if this patch passes muster, please consider it as final.

Thanks,
Paul Serice

fs/isofs/dir.c +13 -5
diff -uprN -X dontdiff linux-2.6.6/fs/isofs/dir.c linux-2.6.6-isofs.2/fs/isofs/dir.c
@@ -106,7 +106,7 @@ static int do_isofs_readdir(struct inode
 {
 	unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
 	unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
-	unsigned int block, offset;
+	unsigned long block, offset;
 	int inode_number = 0;	/* Quiet GCC */
 	struct buffer_head *bh = NULL;
 	int len;
@@ -116,8 +116,9 @@ static int do_isofs_readdir(struct inode
 	struct iso_directory_record *de;
 	struct isofs_sb_info *sbi = ISOFS_SB(inode->i_sb);
 
-	offset = filp->f_pos & (bufsize - 1);
-	block = filp->f_pos >> bufbits;
+	/* ISO 9660 limits file sizes to 32 bits. */
+	offset = (unsigned long)(filp->f_pos & (bufsize - 1));
+	block = (unsigned long)(filp->f_pos >> bufbits);
 
 	while (filp->f_pos < inode->i_size) {
 		int de_len;
@@ -129,8 +130,15 @@ static int do_isofs_readdir(struct inode
 		}
 
 		de = (struct iso_directory_record *) (bh->b_data + offset);
-		if (first_de)
-			inode_number = (bh->b_blocknr << bufbits) + offset;
+		if (first_de) {
+			if (bh->b_blocknr > ISOFS_BLOCK_MAX) {
+				printk(KERN_ERR "isofs: dir.c: Attempt to set "
+				       "inode to an unsupported block.\n");
+				break;
+			}
+			inode_number = (bh->b_blocknr << 6)
+				       + isofs_offset_to_nrec(bh, offset);
+		}
 
 		de_len = *(unsigned char *) de;
 
fs/isofs/inode.c +61 -25

192 lines not on this page · raw message

fs/isofs/namei.c +12 -4
diff -uprN -X dontdiff linux-2.6.6/fs/isofs/namei.c linux-2.6.6-isofs.2/fs/isofs/namei.c
@@ -63,8 +63,7 @@ isofs_find_entry(struct inode *dir, stru
 {
 	unsigned long inode_number;
 	unsigned long bufsize = ISOFS_BUFFER_SIZE(dir);
-	unsigned char bufbits = ISOFS_BUFFER_BITS(dir);
-	unsigned int block, f_pos, offset;
+	unsigned long block, f_pos, offset, nrec;
 	struct buffer_head * bh = NULL;
 	struct isofs_sb_info *sbi = ISOFS_SB(dir->i_sb);
 
@@ -74,6 +73,7 @@ isofs_find_entry(struct inode *dir, stru
 	f_pos = 0;
 	offset = 0;
 	block = 0;
+        nrec = 0;   /* zero-based */
 
 	while (f_pos < dir->i_size) {
 		struct iso_directory_record * de;
@@ -86,21 +86,29 @@ isofs_find_entry(struct inode *dir, stru
 				return 0;
 		}
 
+                if (bh->b_blocknr > ISOFS_BLOCK_MAX) {
+			printk(KERN_ERR "isofs: namei.c: Attempt to set "
+			       "inode to an unsupported block.\n");
+			break;
+                }
+
 		de = (struct iso_directory_record *) (bh->b_data + offset);
-		inode_number = (bh->b_blocknr << bufbits) + offset;
+		inode_number = (bh->b_blocknr << 6) + nrec;
 
 		de_len = *(unsigned char *) de;
 		if (!de_len) {
 			brelse(bh);
 			bh = NULL;
 			f_pos = (f_pos + ISOFS_BLOCK_SIZE) & ~(ISOFS_BLOCK_SIZE - 1);
-			block = f_pos >> bufbits;
+			++block;
 			offset = 0;
+                        nrec = 0;
 			continue;
 		}
 
 		offset += de_len;
 		f_pos += de_len;
+                ++nrec;
 
 		/* Make sure we have a full directory entry */
 		if (offset >= bufsize) {
fs/isofs/rock.c +8 -8
diff -uprN -X dontdiff linux-2.6.6/fs/isofs/rock.c linux-2.6.6-isofs.2/fs/isofs/rock.c
@@ -306,9 +306,7 @@ int parse_rock_ridge_inode_internal(stru
 	goto out;
       case SIG('C','L'):
 	ISOFS_I(inode)->i_first_extent = isonum_733(rr->u.CL.location);
-	reloc = iget(inode->i_sb,
-		     (ISOFS_I(inode)->i_first_extent <<
-		      ISOFS_SB(inode->i_sb)->s_log_zone_size));
+	reloc = iget(inode->i_sb, (ISOFS_I(inode)->i_first_extent << 6));
 	if (!reloc)
 		goto out;
 	inode->i_mode = reloc->i_mode;
@@ -449,13 +447,13 @@ static int rock_ridge_symlink_readpage(s
 	struct inode *inode = page->mapping->host;
 	char *link = kmap(page);
 	unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
-	unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
 	struct buffer_head *bh;
 	char *rpnt = link;
 	unsigned char *pnt;
 	struct iso_directory_record *raw_inode;
 	CONTINUE_DECLS;
-	int block;
+	unsigned long block;
+        unsigned long offset;
 	int sig;
 	int len;
 	unsigned char *chr;
@@ -464,20 +462,22 @@ static int rock_ridge_symlink_readpage(s
 	if (!ISOFS_SB(inode->i_sb)->s_rock)
 		panic ("Cannot have symlink with high sierra variant of iso filesystem\n");
 
-	block = inode->i_ino >> bufbits;
+	block = inode->i_ino >> 6;
 	lock_kernel();
 	bh = sb_bread(inode->i_sb, block);
 	if (!bh)
 		goto out_noread;
 
-	pnt = (unsigned char *) bh->b_data + (inode->i_ino & (bufsize - 1));
+        offset = isofs_nrec_to_offset(bh, inode->i_ino & 63);
+
+	pnt = (unsigned char *) bh->b_data + offset;
 
 	raw_inode = (struct iso_directory_record *) pnt;
 
 	/*
 	 * If we go past the end of the buffer, there is some sort of error.
 	 */
-	if ((inode->i_ino & (bufsize - 1)) + *pnt > bufsize)
+	if (offset + *pnt > bufsize)
 		goto out_bad_span;
 
 	/* Now test for possible Rock Ridge extensions which will override
include/linux/iso_fs.h +50 -0

68 lines not on this page · raw message

include/linux/iso_fs_i.h +1 -1
diff -uprN -X dontdiff linux-2.6.6/include/linux/iso_fs_i.h linux-2.6.6-isofs.2/include/linux/iso_fs_i.h
@@ -13,7 +13,7 @@ enum isofs_file_format {
  * iso fs inode data in memory
  */
 struct iso_inode_info {
-	unsigned int i_first_extent;
+	unsigned long i_first_extent;
 	unsigned char i_file_format;
 	unsigned char i_format_parm[3];
 	unsigned long i_next_section_ino;