iso9660 inodes Extended to 128GB
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:
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
@@ -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 inodestruct 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
@@ -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, strureturn 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
@@ -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(sstruct 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(sif (!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
@@ -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;