summaryrefslogtreecommitdiff
path: root/include/linux/iso_fs.h
diff options
context:
space:
mode:
authorPaul Serice <paul@serice.net>2004-06-17 18:01:34 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-06-17 18:01:34 -0700
commit9210c204fb0456310a5bc4e70f0571f7f6555490 (patch)
treeef0e146d7b9ebd03d2517a89640a45bbd8230c72 /include/linux/iso_fs.h
parentf38928f424ef877fb2f1133a9318595178291b4b (diff)
[PATCH] iso9660: fix handling of inodes beyond 4GB
This is my fourth attempt to patch the isofs code. It is similar to the last posting except this one implements the NFS get_parent() method which has always been missing. The original problem I set out to addresses is that the current iso9660 file system cannot reach inodes located beyond the 4GB barrier. This is caused by using the inode number as the byte offset of the inode data. Being 32-bits wide, the inode number is unable to reach inode data that does not reside on the first 4GB of the file system. This causes real problems with "growisofs" http://fy.chalmers.se/~appro/linux/DVD+RW/#isofs4gb and my pet project "shunt" http://www.serice.net/shunt/ This patch switches the isofs code from iget() to iget5_locked() which allows extra data to be passed into isofs_read_inode() so that inode data anywhere on the disk can be reached. The inode number scheme was also changed. Continuing to use the byte offset would have resulted in non-unique inodes in many common situations, but because the inode number no longer plays any role in reading the meta-data off the disk, I was free to set the inode number to some unique characteristic of the file. I have chosen to use the block offset which is also 32-bits wide. Lastly, the pre-patch code uses the default export_operations to handle accessing the file system through NFS. The problem with this is that the default NFS operations assume that iget() works which is no longer the case because of the necessity of switching to iget5_locked(). So, I had to implement the NFS operations too. As a bonus, I went ahead and implemented the NFS get_parent() method which has always been missing. Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'include/linux/iso_fs.h')
-rw-r--r--include/linux/iso_fs.h66
1 files changed, 66 insertions, 0 deletions
diff --git a/include/linux/iso_fs.h b/include/linux/iso_fs.h
index 223f161da018..2f0acb0542d8 100644
--- a/include/linux/iso_fs.h
+++ b/include/linux/iso_fs.h
@@ -231,9 +231,75 @@ extern struct dentry *isofs_lookup(struct inode *, struct dentry *, struct namei
extern struct buffer_head *isofs_bread(struct inode *, sector_t);
extern int isofs_get_blocks(struct inode *, sector_t, struct buffer_head **, unsigned long);
+extern struct inode *isofs_iget(struct super_block *sb,
+ unsigned long block,
+ unsigned long offset);
+
+/* Because the inode number is no longer relevant to finding the
+ * underlying meta-data for an inode, we are free to choose a more
+ * convenient 32-bit number as the inode number. Because directories
+ * and files are block aligned (except in a few very unusual cases)
+ * and because blocks are limited to 32-bits, I've chosen the starting
+ * block that holds the file or directory data as the inode number.
+ *
+ * One nice side effect of this is that you can use "ls -i" to get the
+ * inode number which will tell you exactly where you need to start a
+ * hex dump if you want to see the contents of the directory or
+ * file. */
+static inline unsigned long isofs_get_ino(struct iso_directory_record *d)
+{
+ return (unsigned long)isonum_733(d->extent)
+ + (unsigned long)isonum_711(d->ext_attr_length);
+}
+
+/* Every directory can have many redundant directory entries scattered
+ * throughout the directory tree. First there is the directory entry
+ * with the name of the directory stored in the parent directory.
+ * Then, there is the "." directory entry stored in the directory
+ * itself. Finally, there are possibly many ".." directory entries
+ * stored in all the subdirectories.
+ *
+ * In order for the NFS get_parent() method to work and for the
+ * general consistency of the dcache, we need to make sure the
+ * "i_iget5_block" and "i_iget5_offset" all point to exactly one of
+ * the many redundant entries for each directory. We normalize the
+ * block and offset by always making them point to the "." directory.
+ *
+ * Notice that we do not use the entry for the directory with the name
+ * that is located in the parent directory. Even though choosing this
+ * first directory is more natural, it is much easier to find the "."
+ * entry in the NFS get_parent() method because it is implicitly
+ * encoded in the "extent + ext_attr_length" fields of _all_ the
+ * redundant entries for the directory. Thus, it can always be
+ * reached regardless of which directory entry you have in hand.
+ *
+ * This works because the "." entry is simply the first directory
+ * record when you start reading the file that holds all the directory
+ * records, and this file starts at "extent + ext_attr_length" blocks.
+ * Because the "." entry is always the first entry listed in the
+ * directories file, the normalized "offset" value is always 0.
+ *
+ * You should pass the directory entry in "de". On return, "block"
+ * and "offset" will hold normalized values. Only directories are
+ * affected making it safe to call even for non-directory file
+ * types. */
+static void inline
+isofs_normalize_block_and_offset(struct iso_directory_record* de,
+ unsigned long *block,
+ unsigned long *offset)
+{
+ /* Only directories are normalized. */
+ if (de->flags[0] & 2) {
+ *offset = 0;
+ *block = (unsigned long)isonum_733(de->extent)
+ + (unsigned long)isonum_711(de->ext_attr_length);
+ }
+}
+
extern struct inode_operations isofs_dir_inode_operations;
extern struct file_operations isofs_dir_operations;
extern struct address_space_operations isofs_symlink_aops;
+extern struct export_operations isofs_export_ops;
/* The following macros are used to check for memory leaks. */
#ifdef LEAK_CHECK