string: factorize skip_spaces and export it to be generally available
[safe/jmp/linux-2.6] / fs / isofs / inode.c
index bb11c7f..6b4dcd4 100644 (file)
@@ -3,7 +3,7 @@
  *
  *  (C) 1991  Linus Torvalds - minix filesystem
  *      1992, 1993, 1994  Eric Youngdale Modified for ISO 9660 filesystem.
- *      1994  Eberhard Moenkeberg - multi session handling.
+ *      1994  Eberhard Mรถnkeberg - multi session handling.
  *      1995  Mark Dobie - allow mounting of some weird VideoCDs and PhotoCDs.
  *     1997  Gordon Chaffee - Joliet CDs
  *     1998  Eric Lammerts - ISO 9660 Level 3
@@ -11,7 +11,6 @@
  *     2004  Paul Serice - NFS Export Operations
  */
 
-#include <linux/config.h>
 #include <linux/init.h>
 #include <linux/module.h>
 
@@ -43,11 +42,13 @@ static int isofs_dentry_cmp_ms(struct dentry *dentry, struct qstr *a, struct qst
 static void isofs_put_super(struct super_block *sb)
 {
        struct isofs_sb_info *sbi = ISOFS_SB(sb);
+
 #ifdef CONFIG_JOLIET
-       if (sbi->s_nls_iocharset) {
-               unload_nls(sbi->s_nls_iocharset);
-               sbi->s_nls_iocharset = NULL;
-       }
+       lock_kernel();
+
+       unload_nls(sbi->s_nls_iocharset);
+
+       unlock_kernel();
 #endif
 
        kfree(sbi);
@@ -55,15 +56,15 @@ static void isofs_put_super(struct super_block *sb)
        return;
 }
 
-static void isofs_read_inode(struct inode *);
+static int isofs_read_inode(struct inode *);
 static int isofs_statfs (struct dentry *, struct kstatfs *);
 
-static kmem_cache_t *isofs_inode_cachep;
+static struct kmem_cache *isofs_inode_cachep;
 
 static struct inode *isofs_alloc_inode(struct super_block *sb)
 {
        struct iso_inode_info *ei;
-       ei = kmem_cache_alloc(isofs_inode_cachep, SLAB_KERNEL);
+       ei = kmem_cache_alloc(isofs_inode_cachep, GFP_KERNEL);
        if (!ei)
                return NULL;
        return &ei->vfs_inode;
@@ -74,22 +75,20 @@ static void isofs_destroy_inode(struct inode *inode)
        kmem_cache_free(isofs_inode_cachep, ISOFS_I(inode));
 }
 
-static void init_once(void *foo, kmem_cache_t * cachep, unsigned long flags)
+static void init_once(void *foo)
 {
        struct iso_inode_info *ei = foo;
 
-       if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-           SLAB_CTOR_CONSTRUCTOR)
-               inode_init_once(&ei->vfs_inode);
+       inode_init_once(&ei->vfs_inode);
 }
+
 static int init_inodecache(void)
 {
        isofs_inode_cachep = kmem_cache_create("isofs_inode_cache",
-                                            sizeof(struct iso_inode_info),
-                                            0, (SLAB_RECLAIM_ACCOUNT|
-                                               SLAB_MEM_SPREAD),
-                                            init_once, NULL);
+                                       sizeof(struct iso_inode_info),
+                                       0, (SLAB_RECLAIM_ACCOUNT|
+                                       SLAB_MEM_SPREAD),
+                                       init_once);
        if (isofs_inode_cachep == NULL)
                return -ENOMEM;
        return 0;
@@ -97,9 +96,7 @@ static int init_inodecache(void)
 
 static void destroy_inodecache(void)
 {
-       if (kmem_cache_destroy(isofs_inode_cachep))
-               printk(KERN_INFO "iso_inode_cache: not all structures were "
-                                       "freed\n");
+       kmem_cache_destroy(isofs_inode_cachep);
 }
 
 static int isofs_remount(struct super_block *sb, int *flags, char *data)
@@ -109,17 +106,17 @@ static int isofs_remount(struct super_block *sb, int *flags, char *data)
        return 0;
 }
 
-static struct super_operations isofs_sops = {
+static const struct super_operations isofs_sops = {
        .alloc_inode    = isofs_alloc_inode,
        .destroy_inode  = isofs_destroy_inode,
-       .read_inode     = isofs_read_inode,
        .put_super      = isofs_put_super,
        .statfs         = isofs_statfs,
        .remount_fs     = isofs_remount,
+       .show_options   = generic_show_options,
 };
 
 
-static struct dentry_operations isofs_dentry_ops[] = {
+static const struct dentry_operations isofs_dentry_ops[] = {
        {
                .d_hash         = isofs_hash,
                .d_compare      = isofs_dentry_cmp,
@@ -141,23 +138,27 @@ static struct dentry_operations isofs_dentry_ops[] = {
 };
 
 struct iso9660_options{
-       char map;
-       char rock;
-       char joliet;
-       char cruft;
-       char hide;
-       char showassoc;
-       char nocompress;
+       unsigned int rock:1;
+       unsigned int joliet:1;
+       unsigned int cruft:1;
+       unsigned int hide:1;
+       unsigned int showassoc:1;
+       unsigned int nocompress:1;
+       unsigned int overriderockperm:1;
+       unsigned int uid_set:1;
+       unsigned int gid_set:1;
+       unsigned int utf8:1;
+       unsigned char map;
        unsigned char check;
        unsigned int blocksize;
-       mode_t mode;
+       mode_t fmode;
+       mode_t dmode;
        gid_t gid;
        uid_t uid;
        char *iocharset;
-       unsigned char utf8;
-        /* LVE */
-        s32 session;
-        s32 sbsector;
+       /* LVE */
+       s32 session;
+       s32 sbsector;
 };
 
 /*
@@ -202,7 +203,7 @@ isofs_hashi_common(struct dentry *dentry, struct qstr *qstr, int ms)
        hash = init_name_hash();
        while (len--) {
                c = tolower(*name++);
-               hash = partial_name_hash(tolower(c), hash);
+               hash = partial_name_hash(c, hash);
        }
        qstr->hash = end_name_hash(hash);
 
@@ -311,10 +312,10 @@ enum {
        Opt_block, Opt_check_r, Opt_check_s, Opt_cruft, Opt_gid, Opt_ignore,
        Opt_iocharset, Opt_map_a, Opt_map_n, Opt_map_o, Opt_mode, Opt_nojoliet,
        Opt_norock, Opt_sb, Opt_session, Opt_uid, Opt_unhide, Opt_utf8, Opt_err,
-       Opt_nocompress, Opt_hide, Opt_showassoc,
+       Opt_nocompress, Opt_hide, Opt_showassoc, Opt_dmode, Opt_overriderockperm,
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
        {Opt_norock, "norock"},
        {Opt_nojoliet, "nojoliet"},
        {Opt_unhide, "unhide"},
@@ -338,6 +339,8 @@ static match_table_t tokens = {
        {Opt_uid, "uid=%u"},
        {Opt_gid, "gid=%u"},
        {Opt_mode, "mode=%u"},
+       {Opt_dmode, "dmode=%u"},
+       {Opt_overriderockperm, "overriderockperm"},
        {Opt_block, "block=%u"},
        {Opt_ignore, "conv=binary"},
        {Opt_ignore, "conv=b"},
@@ -357,22 +360,22 @@ static int parse_options(char *options, struct iso9660_options *popt)
        int option;
 
        popt->map = 'n';
-       popt->rock = 'y';
-       popt->joliet = 'y';
-       popt->cruft = 'n';
-       popt->hide = 'n';
-       popt->showassoc = 'n';
+       popt->rock = 1;
+       popt->joliet = 1;
+       popt->cruft = 0;
+       popt->hide = 0;
+       popt->showassoc = 0;
        popt->check = 'u';              /* unset */
        popt->nocompress = 0;
        popt->blocksize = 1024;
-       popt->mode = S_IRUGO | S_IXUGO; /* r-x for all.  The disc could
-                                          be shared with DOS machines so
-                                          virtually anything could be
-                                          a valid executable. */
+       popt->fmode = popt->dmode = ISOFS_INVALID_MODE;
+       popt->uid_set = 0;
+       popt->gid_set = 0;
        popt->gid = 0;
        popt->uid = 0;
        popt->iocharset = NULL;
        popt->utf8 = 0;
+       popt->overriderockperm = 0;
        popt->session=-1;
        popt->sbsector=-1;
        if (!options)
@@ -389,20 +392,20 @@ static int parse_options(char *options, struct iso9660_options *popt)
                token = match_token(p, tokens, args);
                switch (token) {
                case Opt_norock:
-                       popt->rock = 'n';
+                       popt->rock = 0;
                        break;
                case Opt_nojoliet:
-                       popt->joliet = 'n';
+                       popt->joliet = 0;
                        break;
                case Opt_hide:
-                       popt->hide = 'y';
+                       popt->hide = 1;
                        break;
                case Opt_unhide:
                case Opt_showassoc:
-                       popt->showassoc = 'y';
+                       popt->showassoc = 1;
                        break;
                case Opt_cruft:
-                       popt->cruft = 'y';
+                       popt->cruft = 1;
                        break;
                case Opt_utf8:
                        popt->utf8 = 1;
@@ -446,16 +449,26 @@ static int parse_options(char *options, struct iso9660_options *popt)
                        if (match_int(&args[0], &option))
                                return 0;
                        popt->uid = option;
+                       popt->uid_set = 1;
                        break;
                case Opt_gid:
                        if (match_int(&args[0], &option))
                                return 0;
                        popt->gid = option;
+                       popt->gid_set = 1;
                        break;
                case Opt_mode:
                        if (match_int(&args[0], &option))
                                return 0;
-                       popt->mode = option;
+                       popt->fmode = option;
+                       break;
+               case Opt_dmode:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       popt->dmode = option;
+                       break;
+               case Opt_overriderockperm:
+                       popt->overriderockperm = 1;
                        break;
                case Opt_block:
                        if (match_int(&args[0], &option))
@@ -508,30 +521,30 @@ static unsigned int isofs_get_last_session(struct super_block *sb, s32 session)
                Te.cdte_format=CDROM_LBA;
                i = ioctl_by_bdev(bdev, CDROMREADTOCENTRY, (unsigned long) &Te);
                if (!i) {
-                       printk(KERN_DEBUG "Session %d start %d type %d\n",
-                              session, Te.cdte_addr.lba,
-                              Te.cdte_ctrl&CDROM_DATA_TRACK);
+                       printk(KERN_DEBUG "ISOFS: Session %d start %d type %d\n",
+                               session, Te.cdte_addr.lba,
+                               Te.cdte_ctrl&CDROM_DATA_TRACK);
                        if ((Te.cdte_ctrl&CDROM_DATA_TRACK) == 4)
                                return Te.cdte_addr.lba;
                }
-                       
-               printk(KERN_ERR "Invalid session number or type of track\n");
+
+               printk(KERN_ERR "ISOFS: Invalid session number or type of track\n");
        }
        i = ioctl_by_bdev(bdev, CDROMMULTISESSION, (unsigned long) &ms_info);
        if (session > 0)
-               printk(KERN_ERR "Invalid session number\n");
+               printk(KERN_ERR "ISOFS: Invalid session number\n");
 #if 0
-       printk("isofs.inode: CDROMMULTISESSION: rc=%d\n",i);
+       printk(KERN_DEBUG "isofs.inode: CDROMMULTISESSION: rc=%d\n",i);
        if (i==0) {
-               printk("isofs.inode: XA disk: %s\n",ms_info.xa_flag?"yes":"no");
-               printk("isofs.inode: vol_desc_start = %d\n", ms_info.addr.lba);
+               printk(KERN_DEBUG "isofs.inode: XA disk: %s\n",ms_info.xa_flag?"yes":"no");
+               printk(KERN_DEBUG "isofs.inode: vol_desc_start = %d\n", ms_info.addr.lba);
        }
 #endif
        if (i==0)
 #if WE_OBEY_THE_WRITTEN_STANDARDS
-        if (ms_info.xa_flag) /* necessary for a valid ms_info.addr */
+               if (ms_info.xa_flag) /* necessary for a valid ms_info.addr */
 #endif
-               vol_desc_start=ms_info.addr.lba;
+                       vol_desc_start=ms_info.addr.lba;
        return vol_desc_start;
 }
 
@@ -543,26 +556,27 @@ static unsigned int isofs_get_last_session(struct super_block *sb, s32 session)
  */
 static int isofs_fill_super(struct super_block *s, void *data, int silent)
 {
-       struct buffer_head            * bh = NULL, *pri_bh = NULL;
-       struct hs_primary_descriptor  * h_pri = NULL;
-       struct iso_primary_descriptor * pri = NULL;
+       struct buffer_head *bh = NULL, *pri_bh = NULL;
+       struct hs_primary_descriptor *h_pri = NULL;
+       struct iso_primary_descriptor *pri = NULL;
        struct iso_supplementary_descriptor *sec = NULL;
-       struct iso_directory_record   * rootp;
-       int                             joliet_level = 0;
-       int                             iso_blknum, block;
-       int                             orig_zonesize;
-       int                             table;
-       unsigned int                    vol_desc_start;
-       unsigned long                   first_data_zone;
-       struct inode                  * inode;
-       struct iso9660_options          opt;
-       struct isofs_sb_info          * sbi;
-
-       sbi = kmalloc(sizeof(*sbi), GFP_KERNEL);
+       struct iso_directory_record *rootp;
+       struct inode *inode;
+       struct iso9660_options opt;
+       struct isofs_sb_info *sbi;
+       unsigned long first_data_zone;
+       int joliet_level = 0;
+       int iso_blknum, block;
+       int orig_zonesize;
+       int table, error = -EINVAL;
+       unsigned int vol_desc_start;
+
+       save_mount_options(s, data);
+
+       sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
        if (!sbi)
                return -ENOMEM;
        s->s_fs_info = sbi;
-       memset(sbi, 0, sizeof(*sbi));
 
        if (!parse_options((char *)data, &opt))
                goto out_freesbi;
@@ -583,72 +597,73 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent)
        vol_desc_start = (opt.sbsector != -1) ?
                opt.sbsector : isofs_get_last_session(s,opt.session);
 
-       for (iso_blknum = vol_desc_start+16;
-             iso_blknum < vol_desc_start+100; iso_blknum++)
-       {
-           struct hs_volume_descriptor   * hdp;
-           struct iso_volume_descriptor  * vdp;
-
-           block = iso_blknum << (ISOFS_BLOCK_BITS - s->s_blocksize_bits);
-           if (!(bh = sb_bread(s, block)))
-               goto out_no_read;
-
-           vdp = (struct iso_volume_descriptor *)bh->b_data;
-           hdp = (struct hs_volume_descriptor *)bh->b_data;
-           
-           /* Due to the overlapping physical location of the descriptors, 
-            * ISO CDs can match hdp->id==HS_STANDARD_ID as well. To ensure 
-            * proper identification in this case, we first check for ISO.
-            */
-           if (strncmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) {
-               if (isonum_711 (vdp->type) == ISO_VD_END)
-                   break;
-               if (isonum_711 (vdp->type) == ISO_VD_PRIMARY) {
-                   if (pri == NULL) {
-                       pri = (struct iso_primary_descriptor *)vdp;
-                       /* Save the buffer in case we need it ... */
-                       pri_bh = bh;
-                       bh = NULL;
-                   }
-               }
+       for (iso_blknum = vol_desc_start+16;
+               iso_blknum < vol_desc_start+100; iso_blknum++) {
+               struct hs_volume_descriptor *hdp;
+               struct iso_volume_descriptor  *vdp;
+
+               block = iso_blknum << (ISOFS_BLOCK_BITS - s->s_blocksize_bits);
+               if (!(bh = sb_bread(s, block)))
+                       goto out_no_read;
+
+               vdp = (struct iso_volume_descriptor *)bh->b_data;
+               hdp = (struct hs_volume_descriptor *)bh->b_data;
+
+               /*
+                * Due to the overlapping physical location of the descriptors,
+                * ISO CDs can match hdp->id==HS_STANDARD_ID as well. To ensure
+                * proper identification in this case, we first check for ISO.
+                */
+               if (strncmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) {
+                       if (isonum_711(vdp->type) == ISO_VD_END)
+                               break;
+                       if (isonum_711(vdp->type) == ISO_VD_PRIMARY) {
+                               if (pri == NULL) {
+                                       pri = (struct iso_primary_descriptor *)vdp;
+                                       /* Save the buffer in case we need it ... */
+                                       pri_bh = bh;
+                                       bh = NULL;
+                               }
+                       }
 #ifdef CONFIG_JOLIET
-               else if (isonum_711 (vdp->type) == ISO_VD_SUPPLEMENTARY) {
-                   sec = (struct iso_supplementary_descriptor *)vdp;
-                   if (sec->escape[0] == 0x25 && sec->escape[1] == 0x2f) {
-                       if (opt.joliet == 'y') {
-                           if (sec->escape[2] == 0x40) {
-                               joliet_level = 1;
-                           } else if (sec->escape[2] == 0x43) {
-                               joliet_level = 2;
-                           } else if (sec->escape[2] == 0x45) {
-                               joliet_level = 3;
-                           }
-                           printk(KERN_DEBUG"ISO 9660 Extensions: Microsoft Joliet Level %d\n",
-                                  joliet_level);
+                       else if (isonum_711(vdp->type) == ISO_VD_SUPPLEMENTARY) {
+                               sec = (struct iso_supplementary_descriptor *)vdp;
+                               if (sec->escape[0] == 0x25 && sec->escape[1] == 0x2f) {
+                                       if (opt.joliet) {
+                                               if (sec->escape[2] == 0x40)
+                                                       joliet_level = 1;
+                                               else if (sec->escape[2] == 0x43)
+                                                       joliet_level = 2;
+                                               else if (sec->escape[2] == 0x45)
+                                                       joliet_level = 3;
+
+                                               printk(KERN_DEBUG "ISO 9660 Extensions: "
+                                                       "Microsoft Joliet Level %d\n",
+                                                       joliet_level);
+                                       }
+                                       goto root_found;
+                               } else {
+                               /* Unknown supplementary volume descriptor */
+                               sec = NULL;
+                               }
                        }
-                       goto root_found;
-                   } else {
-                       /* Unknown supplementary volume descriptor */
-                       sec = NULL;
-                   }
-               }
 #endif
-           } else {
-               if (strncmp (hdp->id, HS_STANDARD_ID, sizeof hdp->id) == 0) {
-                   if (isonum_711 (hdp->type) != ISO_VD_PRIMARY)
-                       goto out_freebh;
-               
-                   sbi->s_high_sierra = 1;
-                   opt.rock = 'n';
-                   h_pri = (struct hs_primary_descriptor *)vdp;
-                   goto root_found;
+               } else {
+                       if (strncmp (hdp->id, HS_STANDARD_ID, sizeof hdp->id) == 0) {
+                               if (isonum_711(hdp->type) != ISO_VD_PRIMARY)
+                                       goto out_freebh;
+
+                               sbi->s_high_sierra = 1;
+                               opt.rock = 0;
+                               h_pri = (struct hs_primary_descriptor *)vdp;
+                               goto root_found;
+                       }
                }
-           }
 
-            /* Just skip any volume descriptors we don't recognize */
+               /* Just skip any volume descriptors we don't recognize */
 
-           brelse(bh);
-           bh = NULL;
+               brelse(bh);
+               bh = NULL;
        }
        /*
         * If we fall through, either no volume descriptor was found,
@@ -662,25 +677,25 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent)
 
 root_found:
 
-       if (joliet_level && (pri == NULL || opt.rock == 'n')) {
-           /* This is the case of Joliet with the norock mount flag.
-            * A disc with both Joliet and Rock Ridge is handled later
-            */
-           pri = (struct iso_primary_descriptor *) sec;
+       if (joliet_level && (pri == NULL || !opt.rock)) {
+               /* This is the case of Joliet with the norock mount flag.
+                * A disc with both Joliet and Rock Ridge is handled later
+                */
+               pri = (struct iso_primary_descriptor *) sec;
        }
 
        if(sbi->s_high_sierra){
-         rootp = (struct iso_directory_record *) h_pri->root_directory_record;
-         sbi->s_nzones = isonum_733 (h_pri->volume_space_size);
-         sbi->s_log_zone_size = isonum_723 (h_pri->logical_block_size);
-         sbi->s_max_size = isonum_733(h_pri->volume_space_size);
+               rootp = (struct iso_directory_record *) h_pri->root_directory_record;
+               sbi->s_nzones = isonum_733(h_pri->volume_space_size);
+               sbi->s_log_zone_size = isonum_723(h_pri->logical_block_size);
+               sbi->s_max_size = isonum_733(h_pri->volume_space_size);
        } else {
-         if (!pri)
-           goto out_freebh;
-         rootp = (struct iso_directory_record *) pri->root_directory_record;
-         sbi->s_nzones = isonum_733 (pri->volume_space_size);
-         sbi->s_log_zone_size = isonum_723 (pri->logical_block_size);
-         sbi->s_max_size = isonum_733(pri->volume_space_size);
+               if (!pri)
+                       goto out_freebh;
+               rootp = (struct iso_directory_record *) pri->root_directory_record;
+               sbi->s_nzones = isonum_733(pri->volume_space_size);
+               sbi->s_log_zone_size = isonum_723(pri->logical_block_size);
+               sbi->s_max_size = isonum_733(pri->volume_space_size);
        }
 
        sbi->s_ninodes = 0; /* No way to figure this out easily */
@@ -693,42 +708,43 @@ root_found:
         * blocks that were 512 bytes (which should only very rarely
         * happen.)
         */
-       if(orig_zonesize < opt.blocksize)
+       if (orig_zonesize < opt.blocksize)
                goto out_bad_size;
 
        /* RDE: convert log zone size to bit shift */
-       switch (sbi->s_log_zone_size)
-         { case  512: sbi->s_log_zone_size =  9; break;
-           case 1024: sbi->s_log_zone_size = 10; break;
-           case 2048: sbi->s_log_zone_size = 11; break;
+       switch (sbi->s_log_zone_size) {
+       case  512: sbi->s_log_zone_size =  9; break;
+       case 1024: sbi->s_log_zone_size = 10; break;
+       case 2048: sbi->s_log_zone_size = 11; break;
 
-           default:
+       default:
                goto out_bad_zone_size;
-         }
+       }
 
        s->s_magic = ISOFS_SUPER_MAGIC;
        s->s_maxbytes = 0xffffffff; /* We can handle files up to 4 GB */
 
-       /* The CDROM is read-only, has no nodes (devices) on it, and since
-          all of the files appear to be owned by root, we really do not want
-          to allow suid.  (suid or devices will not show up unless we have
-          Rock Ridge extensions) */
+       /*
+        * The CDROM is read-only, has no nodes (devices) on it, and since
+        * all of the files appear to be owned by root, we really do not want
+        * to allow suid.  (suid or devices will not show up unless we have
+        * Rock Ridge extensions)
+        */
 
        s->s_flags |= MS_RDONLY /* | MS_NODEV | MS_NOSUID */;
 
        /* Set this for reference. Its not currently used except on write
           which we don't have .. */
-          
-       first_data_zone = isonum_733 (rootp->extent) +
-                         isonum_711 (rootp->ext_attr_length);
+
+       first_data_zone = isonum_733(rootp->extent) +
+                         isonum_711(rootp->ext_attr_length);
        sbi->s_firstdatazone = first_data_zone;
 #ifndef BEQUIET
-       printk(KERN_DEBUG "Max size:%ld   Log zone size:%ld\n",
-              sbi->s_max_size,
-              1UL << sbi->s_log_zone_size);
-       printk(KERN_DEBUG "First datazone:%ld\n", sbi->s_firstdatazone);
+       printk(KERN_DEBUG "ISOFS: Max size:%ld   Log zone size:%ld\n",
+               sbi->s_max_size, 1UL << sbi->s_log_zone_size);
+       printk(KERN_DEBUG "ISOFS: First datazone:%ld\n", sbi->s_firstdatazone);
        if(sbi->s_high_sierra)
-               printk(KERN_DEBUG "Disc in High Sierra format.\n");
+               printk(KERN_DEBUG "ISOFS: Disc in High Sierra format.\n");
 #endif
 
        /*
@@ -743,8 +759,8 @@ root_found:
                pri = (struct iso_primary_descriptor *) sec;
                rootp = (struct iso_directory_record *)
                        pri->root_directory_record;
-               first_data_zone = isonum_733 (rootp->extent) +
-                               isonum_711 (rootp->ext_attr_length);
+               first_data_zone = isonum_733(rootp->extent) +
+                               isonum_711(rootp->ext_attr_length);
        }
 
        /*
@@ -777,7 +793,7 @@ root_found:
 
 #ifdef CONFIG_JOLIET
        if (joliet_level && opt.utf8 == 0) {
-               char * p = opt.iocharset ? opt.iocharset : CONFIG_NLS_DEFAULT;
+               char *p = opt.iocharset ? opt.iocharset : CONFIG_NLS_DEFAULT;
                sbi->s_nls_iocharset = load_nls(p);
                if (! sbi->s_nls_iocharset) {
                        /* Fail only if explicit charset specified */
@@ -790,21 +806,31 @@ root_found:
        s->s_op = &isofs_sops;
        s->s_export_op = &isofs_export_ops;
        sbi->s_mapping = opt.map;
-       sbi->s_rock = (opt.rock == 'y' ? 2 : 0);
+       sbi->s_rock = (opt.rock ? 2 : 0);
        sbi->s_rock_offset = -1; /* initial offset, will guess until SP is found*/
        sbi->s_cruft = opt.cruft;
        sbi->s_hide = opt.hide;
        sbi->s_showassoc = opt.showassoc;
        sbi->s_uid = opt.uid;
        sbi->s_gid = opt.gid;
+       sbi->s_uid_set = opt.uid_set;
+       sbi->s_gid_set = opt.gid_set;
        sbi->s_utf8 = opt.utf8;
        sbi->s_nocompress = opt.nocompress;
+       sbi->s_overriderockperm = opt.overriderockperm;
        /*
         * It would be incredibly stupid to allow people to mark every file
         * on the disk as suid, so we merely allow them to set the default
         * permissions.
         */
-       sbi->s_mode = opt.mode & 0777;
+       if (opt.fmode != ISOFS_INVALID_MODE)
+               sbi->s_fmode = opt.fmode & 0777;
+       else
+               sbi->s_fmode = ISOFS_INVALID_MODE;
+       if (opt.dmode != ISOFS_INVALID_MODE)
+               sbi->s_dmode = opt.dmode & 0777;
+       else
+               sbi->s_dmode = ISOFS_INVALID_MODE;
 
        /*
         * Read the root inode, which _may_ result in changing
@@ -812,6 +838,8 @@ root_found:
         * we then decide whether to use the Joliet descriptor.
         */
        inode = isofs_iget(s, sbi->s_firstdatazone, 0);
+       if (IS_ERR(inode))
+               goto out_no_root;
 
        /*
         * If this disk has both Rock Ridge and Joliet on it, then we
@@ -827,33 +855,42 @@ root_found:
                sbi->s_rock = 0;
                if (sbi->s_firstdatazone != first_data_zone) {
                        sbi->s_firstdatazone = first_data_zone;
-                       printk(KERN_DEBUG 
+                       printk(KERN_DEBUG
                                "ISOFS: changing to secondary root\n");
                        iput(inode);
                        inode = isofs_iget(s, sbi->s_firstdatazone, 0);
+                       if (IS_ERR(inode))
+                               goto out_no_root;
                }
        }
 
        if (opt.check == 'u') {
                /* Only Joliet is case insensitive by default */
-               if (joliet_level) opt.check = 'r';
-               else opt.check = 's';
+               if (joliet_level)
+                       opt.check = 'r';
+               else
+                       opt.check = 's';
        }
        sbi->s_joliet_level = joliet_level;
 
-       /* check the root inode */
-       if (!inode)
-               goto out_no_root;
-       if (!inode->i_op)
-               goto out_bad_root;
+       /* Make sure the root inode is a directory */
+       if (!S_ISDIR(inode->i_mode)) {
+               printk(KERN_WARNING
+                       "isofs_fill_super: root inode is not a directory. "
+                       "Corrupted media?\n");
+               goto out_iput;
+       }
+
        /* get the root dentry */
        s->s_root = d_alloc_root(inode);
        if (!(s->s_root))
                goto out_no_root;
 
        table = 0;
-       if (joliet_level) table += 2;
-       if (opt.check == 'r') table++;
+       if (joliet_level)
+               table += 2;
+       if (opt.check == 'r')
+               table++;
        s->s_root->d_op = &isofs_dentry_ops[table];
 
        kfree(opt.iocharset);
@@ -863,34 +900,33 @@ root_found:
        /*
         * Display error messages and free resources.
         */
-out_bad_root:
-       printk(KERN_WARNING "isofs_fill_super: root inode not initialized\n");
-       goto out_iput;
-out_no_root:
-       printk(KERN_WARNING "isofs_fill_super: get root inode failed\n");
 out_iput:
        iput(inode);
+       goto out_no_inode;
+out_no_root:
+       error = PTR_ERR(inode);
+       if (error != -ENOMEM)
+               printk(KERN_WARNING "%s: get root inode failed\n", __func__);
+out_no_inode:
 #ifdef CONFIG_JOLIET
-       if (sbi->s_nls_iocharset)
-               unload_nls(sbi->s_nls_iocharset);
+       unload_nls(sbi->s_nls_iocharset);
 #endif
        goto out_freesbi;
 out_no_read:
-       printk(KERN_WARNING "isofs_fill_super: "
-               "bread failed, dev=%s, iso_blknum=%d, block=%d\n",
-               s->s_id, iso_blknum, block);
+       printk(KERN_WARNING "%s: bread failed, dev=%s, iso_blknum=%d, block=%d\n",
+               __func__, s->s_id, iso_blknum, block);
        goto out_freesbi;
 out_bad_zone_size:
-       printk(KERN_WARNING "Bad logical zone size %ld\n",
+       printk(KERN_WARNING "ISOFS: Bad logical zone size %ld\n",
                sbi->s_log_zone_size);
        goto out_freebh;
 out_bad_size:
-       printk(KERN_WARNING "Logical zone size(%d) < hardware blocksize(%u)\n",
+       printk(KERN_WARNING "ISOFS: Logical zone size(%d) < hardware blocksize(%u)\n",
                orig_zonesize, opt.blocksize);
        goto out_freebh;
 out_unknown_format:
        if (!silent)
-               printk(KERN_WARNING "Unable to identify CD-ROM format.\n");
+               printk(KERN_WARNING "ISOFS: Unable to identify CD-ROM format.\n");
 
 out_freebh:
        brelse(bh);
@@ -898,21 +934,24 @@ out_freesbi:
        kfree(opt.iocharset);
        kfree(sbi);
        s->s_fs_info = NULL;
-       return -EINVAL;
+       return error;
 }
 
 static int isofs_statfs (struct dentry *dentry, struct kstatfs *buf)
 {
        struct super_block *sb = dentry->d_sb;
+       u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
 
        buf->f_type = ISOFS_SUPER_MAGIC;
        buf->f_bsize = sb->s_blocksize;
        buf->f_blocks = (ISOFS_SB(sb)->s_nzones
-                  << (ISOFS_SB(sb)->s_log_zone_size - sb->s_blocksize_bits));
+               << (ISOFS_SB(sb)->s_log_zone_size - sb->s_blocksize_bits));
        buf->f_bfree = 0;
        buf->f_bavail = 0;
        buf->f_files = ISOFS_SB(sb)->s_ninodes;
        buf->f_ffree = 0;
+       buf->f_fsid.val[0] = (u32)id;
+       buf->f_fsid.val[1] = (u32)(id >> 32);
        buf->f_namelen = NAME_MAX;
        return 0;
 }
@@ -920,7 +959,7 @@ static int isofs_statfs (struct dentry *dentry, struct kstatfs *buf)
 /*
  * Get a set of blocks; filling in buffer_heads if already allocated
  * or getblk() if they are not.  Returns the number of blocks inserted
- * (0 == error.)
+ * (-ve == error.)
  */
 int isofs_get_blocks(struct inode *inode, sector_t iblock_s,
                     struct buffer_head **bh, unsigned long nblocks)
@@ -930,27 +969,28 @@ int isofs_get_blocks(struct inode *inode, sector_t iblock_s,
        unsigned int firstext;
        unsigned long nextblk, nextoff;
        long iblock = (long)iblock_s;
-       int section, rv;
+       int section, rv, error;
        struct iso_inode_info *ei = ISOFS_I(inode);
 
        lock_kernel();
 
+       error = -EIO;
        rv = 0;
        if (iblock < 0 || iblock != iblock_s) {
-               printk("isofs_get_blocks: block number too large\n");
+               printk(KERN_DEBUG "%s: block number too large\n", __func__);
                goto abort;
        }
 
        b_off = iblock;
-       
-       offset    = 0;
-       firstext  = ei->i_first_extent;
+
+       offset = 0;
+       firstext = ei->i_first_extent;
        sect_size = ei->i_section_size >> ISOFS_BUFFER_BITS(inode);
-       nextblk   = ei->i_next_section_block;
-       nextoff   = ei->i_next_section_offset;
-       section   = 0;
+       nextblk = ei->i_next_section_block;
+       nextoff = ei->i_next_section_offset;
+       section = 0;
 
-       while ( nblocks ) {
+       while (nblocks) {
                /* If we are *way* beyond the end of the file, print a message.
                 * Access beyond the end of the file up to the next page boundary
                 * is normal, however because of the way the page cache works.
@@ -959,43 +999,46 @@ int isofs_get_blocks(struct inode *inode, sector_t iblock_s,
                 * I/O errors.
                 */
                if (b_off > ((inode->i_size + PAGE_CACHE_SIZE - 1) >> ISOFS_BUFFER_BITS(inode))) {
-                       printk("isofs_get_blocks: block >= EOF (%ld, %ld)\n",
-                              iblock, (unsigned long) inode->i_size);
+                       printk(KERN_DEBUG "%s: block >= EOF (%ld, %ld)\n",
+                               __func__, iblock, (unsigned long) inode->i_size);
                        goto abort;
                }
-               
-               if (nextblk) {
-                       while (b_off >= (offset + sect_size)) {
-                               struct inode *ninode;
-                               
-                               offset += sect_size;
-                               if (nextblk == 0)
-                                       goto abort;
-                               ninode = isofs_iget(inode->i_sb, nextblk, nextoff);
-                               if (!ninode)
-                                       goto abort;
-                               firstext  = ISOFS_I(ninode)->i_first_extent;
-                               sect_size = ISOFS_I(ninode)->i_section_size >> ISOFS_BUFFER_BITS(ninode);
-                               nextblk   = ISOFS_I(ninode)->i_next_section_block;
-                               nextoff   = ISOFS_I(ninode)->i_next_section_offset;
-                               iput(ninode);
-                               
-                               if (++section > 100) {
-                                       printk("isofs_get_blocks: More than 100 file sections ?!?, aborting...\n");
-                                       printk("isofs_get_blocks: block=%ld firstext=%u sect_size=%u "
-                                              "nextblk=%lu nextoff=%lu\n",
-                                              iblock, firstext, (unsigned) sect_size,
-                                              nextblk, nextoff);
-                                       goto abort;
-                               }
+
+               /* On the last section, nextblk == 0, section size is likely to
+                * exceed sect_size by a partial block, and access beyond the
+                * end of the file will reach beyond the section size, too.
+                */
+               while (nextblk && (b_off >= (offset + sect_size))) {
+                       struct inode *ninode;
+
+                       offset += sect_size;
+                       ninode = isofs_iget(inode->i_sb, nextblk, nextoff);
+                       if (IS_ERR(ninode)) {
+                               error = PTR_ERR(ninode);
+                               goto abort;
+                       }
+                       firstext  = ISOFS_I(ninode)->i_first_extent;
+                       sect_size = ISOFS_I(ninode)->i_section_size >> ISOFS_BUFFER_BITS(ninode);
+                       nextblk   = ISOFS_I(ninode)->i_next_section_block;
+                       nextoff   = ISOFS_I(ninode)->i_next_section_offset;
+                       iput(ninode);
+
+                       if (++section > 100) {
+                               printk(KERN_DEBUG "%s: More than 100 file sections ?!?"
+                                       " aborting...\n", __func__);
+                               printk(KERN_DEBUG "%s: block=%ld firstext=%u sect_size=%u "
+                                       "nextblk=%lu nextoff=%lu\n", __func__,
+                                       iblock, firstext, (unsigned) sect_size,
+                                       nextblk, nextoff);
+                               goto abort;
                        }
                }
-               
-               if ( *bh ) {
+
+               if (*bh) {
                        map_bh(*bh, inode->i_sb, firstext + b_off - offset);
                } else {
                        *bh = sb_getblk(inode->i_sb, firstext+b_off-offset);
-                       if ( !*bh )
+                       if (!*bh)
                                goto abort;
                }
                bh++;   /* Next buffer head */
@@ -1004,9 +1047,10 @@ int isofs_get_blocks(struct inode *inode, sector_t iblock_s,
                rv++;
        }
 
+       error = 0;
 abort:
        unlock_kernel();
-       return rv;
+       return rv != 0 ? rv : error;
 }
 
 /*
@@ -1015,12 +1059,15 @@ abort:
 static int isofs_get_block(struct inode *inode, sector_t iblock,
                    struct buffer_head *bh_result, int create)
 {
+       int ret;
+
        if (create) {
-               printk("isofs_get_block: Kernel tries to allocate a block\n");
+               printk(KERN_DEBUG "%s: Kernel tries to allocate a block\n", __func__);
                return -EROFS;
        }
 
-       return isofs_get_blocks(inode, iblock, &bh_result, 1) ? 0 : -EIO;
+       ret = isofs_get_blocks(inode, iblock, &bh_result, 1);
+       return ret < 0 ? ret : 0;
 }
 
 static int isofs_bmap(struct inode *inode, sector_t block)
@@ -1060,27 +1107,15 @@ static const struct address_space_operations isofs_aops = {
        .bmap = _isofs_bmap
 };
 
-static inline void test_and_set_uid(uid_t *p, uid_t value)
-{
-       if (value)
-               *p = value;
-}
-
-static inline void test_and_set_gid(gid_t *p, gid_t value)
-{
-        if (value)
-                *p = value;
-}
-
 static int isofs_read_level3_size(struct inode *inode)
 {
        unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
        int high_sierra = ISOFS_SB(inode->i_sb)->s_high_sierra;
-       struct buffer_head * bh = NULL;
+       struct buffer_head *bh = NULL;
        unsigned long block, offset, block_saved, offset_saved;
        int i = 0;
        int more_entries = 0;
-       struct iso_directory_record * tmpde = NULL;
+       struct iso_directory_record *tmpde = NULL;
        struct iso_inode_info *ei = ISOFS_I(inode);
 
        inode->i_size = 0;
@@ -1095,7 +1130,7 @@ static int isofs_read_level3_size(struct inode *inode)
        offset = ei->i_iget5_offset;
 
        do {
-               struct iso_directory_record * de;
+               struct iso_directory_record *de;
                unsigned int de_len;
 
                if (!bh) {
@@ -1169,26 +1204,26 @@ out_noread:
        return -EIO;
 
 out_toomany:
-       printk(KERN_INFO "isofs_read_level3_size: "
-               "More than 100 file sections ?!?, aborting...\n"
-               "isofs_read_level3_size: inode=%lu\n",
-               inode->i_ino);
+       printk(KERN_INFO "%s: More than 100 file sections ?!?, aborting...\n"
+               "isofs_read_level3_size: inode=%lu\n",
+               __func__, inode->i_ino);
        goto out;
 }
 
-static void isofs_read_inode(struct inode *inode)
+static int isofs_read_inode(struct inode *inode)
 {
        struct super_block *sb = inode->i_sb;
        struct isofs_sb_info *sbi = ISOFS_SB(sb);
        unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
        unsigned long block;
        int high_sierra = sbi->s_high_sierra;
-       struct buffer_head * bh = NULL;
-       struct iso_directory_record * de;
-       struct iso_directory_record * tmpde = NULL;
+       struct buffer_head *bh = NULL;
+       struct iso_directory_record *de;
+       struct iso_directory_record *tmpde = NULL;
        unsigned int de_len;
        unsigned long offset;
        struct iso_inode_info *ei = ISOFS_I(inode);
+       int ret = -EIO;
 
        block = ei->i_iget5_block;
        bh = sb_bread(inode->i_sb, block);
@@ -1205,7 +1240,8 @@ static void isofs_read_inode(struct inode *inode)
 
                tmpde = kmalloc(de_len, GFP_KERNEL);
                if (tmpde == NULL) {
-                       printk(KERN_INFO "isofs_read_inode: out of memory\n");
+                       printk(KERN_INFO "%s: out of memory\n", __func__);
+                       ret = -ENOMEM;
                        goto fail;
                }
                memcpy(tmpde, bh->b_data + offset, frag1);
@@ -1218,40 +1254,55 @@ static void isofs_read_inode(struct inode *inode)
        }
 
        inode->i_ino = isofs_get_ino(ei->i_iget5_block,
-                                    ei->i_iget5_offset,
-                                    ISOFS_BUFFER_BITS(inode));
+                                       ei->i_iget5_offset,
+                                       ISOFS_BUFFER_BITS(inode));
 
        /* Assume it is a normal-format file unless told otherwise */
        ei->i_file_format = isofs_file_normal;
 
        if (de->flags[-high_sierra] & 2) {
-               inode->i_mode = S_IRUGO | S_IXUGO | S_IFDIR;
-               inode->i_nlink = 1; /* Set to 1.  We know there are 2, but
-                                      the find utility tries to optimize
-                                      if it is 2, and it screws up.  It is
-                                      easier to give 1 which tells find to
-                                      do it the hard way. */
+               if (sbi->s_dmode != ISOFS_INVALID_MODE)
+                       inode->i_mode = S_IFDIR | sbi->s_dmode;
+               else
+                       inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
+               inode->i_nlink = 1;     /*
+                                        * Set to 1.  We know there are 2, but
+                                        * the find utility tries to optimize
+                                        * if it is 2, and it screws up.  It is
+                                        * easier to give 1 which tells find to
+                                        * do it the hard way.
+                                        */
        } else {
-               /* Everybody gets to read the file. */
-               inode->i_mode = sbi->s_mode;
+               if (sbi->s_fmode != ISOFS_INVALID_MODE) {
+                       inode->i_mode = S_IFREG | sbi->s_fmode;
+               } else {
+                       /*
+                        * Set default permissions: r-x for all.  The disc
+                        * could be shared with DOS machines so virtually
+                        * anything could be a valid executable.
+                        */
+                       inode->i_mode = S_IFREG | S_IRUGO | S_IXUGO;
+               }
                inode->i_nlink = 1;
-               inode->i_mode |= S_IFREG;
        }
        inode->i_uid = sbi->s_uid;
        inode->i_gid = sbi->s_gid;
-       inode->i_blocks = inode->i_blksize = 0;
+       inode->i_blocks = 0;
 
        ei->i_format_parm[0] = 0;
        ei->i_format_parm[1] = 0;
        ei->i_format_parm[2] = 0;
 
-       ei->i_section_size = isonum_733 (de->size);
+       ei->i_section_size = isonum_733(de->size);
        if (de->flags[-high_sierra] & 0x80) {
-               if(isofs_read_level3_size(inode)) goto fail;
+               ret = isofs_read_level3_size(inode);
+               if (ret < 0)
+                       goto fail;
+               ret = -EIO;
        } else {
                ei->i_next_section_block = 0;
                ei->i_next_section_offset = 0;
-               inode->i_size = isonum_733 (de->size);
+               inode->i_size = isonum_733(de->size);
        }
 
        /*
@@ -1260,27 +1311,28 @@ static void isofs_read_inode(struct inode *inode)
         * this CDROM was mounted with the cruft option.
         */
 
-       if (sbi->s_cruft == 'y')
+       if (sbi->s_cruft)
                inode->i_size &= 0x00ffffff;
 
        if (de->interleave[0]) {
-               printk("Interleaved files not (yet) supported.\n");
+               printk(KERN_DEBUG "ISOFS: Interleaved files not (yet) supported.\n");
                inode->i_size = 0;
        }
 
        /* I have no idea what file_unit_size is used for, so
           we will flag it for now */
        if (de->file_unit_size[0] != 0) {
-               printk("File unit size != 0 for ISO file (%ld).\n",
-                      inode->i_ino);
+               printk(KERN_DEBUG "ISOFS: File unit size != 0 for ISO file (%ld).\n",
+                       inode->i_ino);
        }
 
        /* I have no idea what other flag bits are used for, so
           we will flag it for now */
 #ifdef DEBUG
        if((de->flags[-high_sierra] & ~2)!= 0){
-               printk("Unusual flag settings for ISO file (%ld %x).\n",
-                      inode->i_ino, de->flags[-high_sierra]);
+               printk(KERN_DEBUG "ISOFS: Unusual flag settings for ISO file "
+                               "(%ld %x).\n",
+                       inode->i_ino, de->flags[-high_sierra]);
        }
 #endif
 
@@ -1291,12 +1343,11 @@ static void isofs_read_inode(struct inode *inode)
        inode->i_atime.tv_nsec =
        inode->i_ctime.tv_nsec = 0;
 
-       ei->i_first_extent = (isonum_733 (de->extent) +
-                             isonum_711 (de->ext_attr_length));
+       ei->i_first_extent = (isonum_733(de->extent) +
+                       isonum_711(de->ext_attr_length));
 
        /* Set the number of blocks for stat() - should be done before RR */
-       inode->i_blksize = PAGE_CACHE_SIZE; /* For stat() only */
-       inode->i_blocks  = (inode->i_size + 511) >> 9;
+       inode->i_blocks = (inode->i_size + 511) >> 9;
 
        /*
         * Now test for possible Rock Ridge extensions which will override
@@ -1306,14 +1357,23 @@ static void isofs_read_inode(struct inode *inode)
        if (!high_sierra) {
                parse_rock_ridge_inode(de, inode);
                /* if we want uid/gid set, override the rock ridge setting */
-               test_and_set_uid(&inode->i_uid, sbi->s_uid);
-               test_and_set_gid(&inode->i_gid, sbi->s_gid);
+               if (sbi->s_uid_set)
+                       inode->i_uid = sbi->s_uid;
+               if (sbi->s_gid_set)
+                       inode->i_gid = sbi->s_gid;
        }
+       /* Now set final access rights if overriding rock ridge setting */
+       if (S_ISDIR(inode->i_mode) && sbi->s_overriderockperm &&
+           sbi->s_dmode != ISOFS_INVALID_MODE)
+               inode->i_mode = S_IFDIR | sbi->s_dmode;
+       if (S_ISREG(inode->i_mode) && sbi->s_overriderockperm &&
+           sbi->s_fmode != ISOFS_INVALID_MODE)
+               inode->i_mode = S_IFREG | sbi->s_fmode;
 
        /* Install the inode operations vector */
        if (S_ISREG(inode->i_mode)) {
                inode->i_fop = &generic_ro_fops;
-               switch ( ei->i_file_format ) {
+               switch (ei->i_file_format) {
 #ifdef CONFIG_ZISOFS
                case isofs_file_compressed:
                        inode->i_data.a_ops = &zisofs_aops;
@@ -1333,16 +1393,16 @@ static void isofs_read_inode(struct inode *inode)
                /* XXX - parse_rock_ridge_inode() had already set i_rdev. */
                init_special_inode(inode, inode->i_mode, inode->i_rdev);
 
+       ret = 0;
 out:
        kfree(tmpde);
        if (bh)
                brelse(bh);
-       return;
+       return ret;
 
 out_badread:
        printk(KERN_WARNING "ISOFS: unable to read i-node block\n");
 fail:
-       make_bad_inode(inode);
        goto out;
 }
 
@@ -1357,7 +1417,7 @@ static int isofs_iget5_test(struct inode *ino, void *data)
        struct isofs_iget5_callback_data *d =
                (struct isofs_iget5_callback_data*)data;
        return (i->i_iget5_block == d->block)
-              && (i->i_iget5_offset == d->offset);
+               && (i->i_iget5_offset == d->offset);
 }
 
 static int isofs_iget5_set(struct inode *ino, void *data)
@@ -1381,9 +1441,10 @@ struct inode *isofs_iget(struct super_block *sb,
        unsigned long hashval;
        struct inode *inode;
        struct isofs_iget5_callback_data data;
+       long ret;
 
        if (offset >= 1ul << sb->s_blocksize_bits)
-               return NULL;
+               return ERR_PTR(-EINVAL);
 
        data.block = block;
        data.offset = offset;
@@ -1391,11 +1452,19 @@ struct inode *isofs_iget(struct super_block *sb,
        hashval = (block << sb->s_blocksize_bits) | offset;
 
        inode = iget5_locked(sb, hashval, &isofs_iget5_test,
-                            &isofs_iget5_set, &data);
+                               &isofs_iget5_set, &data);
 
-       if (inode && (inode->i_state & I_NEW)) {
-               sb->s_op->read_inode(inode);
-               unlock_new_inode(inode);
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
+
+       if (inode->i_state & I_NEW) {
+               ret = isofs_read_inode(inode);
+               if (ret < 0) {
+                       iget_failed(inode);
+                       inode = ERR_PTR(ret);
+               } else {
+                       unlock_new_inode(inode);
+               }
        }
 
        return inode;
@@ -1405,7 +1474,7 @@ static int isofs_get_sb(struct file_system_type *fs_type,
        int flags, const char *dev_name, void *data, struct vfsmount *mnt)
 {
        return get_sb_bdev(fs_type, flags, dev_name, data, isofs_fill_super,
-                          mnt);
+                               mnt);
 }
 
 static struct file_system_type iso9660_fs_type = {