diff options
Diffstat (limited to 'fs/isofs/inode.c')
-rw-r--r-- | fs/isofs/inode.c | 68 |
1 files changed, 46 insertions, 22 deletions
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 09e3d306e96..875d37fb6c7 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -54,7 +54,7 @@ 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 struct kmem_cache *isofs_inode_cachep; @@ -107,7 +107,6 @@ static int isofs_remount(struct super_block *sb, int *flags, char *data) 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, @@ -552,7 +551,7 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) int joliet_level = 0; int iso_blknum, block; int orig_zonesize; - int table; + int table, error = -EINVAL; unsigned int vol_desc_start; sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); @@ -810,6 +809,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 @@ -829,6 +830,8 @@ root_found: "ISOFS: changing to secondary root\n"); iput(inode); inode = isofs_iget(s, sbi->s_firstdatazone, 0); + if (IS_ERR(inode)) + goto out_no_root; } } @@ -842,8 +845,6 @@ root_found: sbi->s_joliet_level = joliet_level; /* check the root inode */ - if (!inode) - goto out_no_root; if (!inode->i_op) goto out_bad_root; @@ -876,11 +877,14 @@ root_found: */ out_bad_root: printk(KERN_WARNING "%s: root inode not initialized\n", __func__); - goto out_iput; -out_no_root: - printk(KERN_WARNING "%s: get root inode failed\n", __func__); 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); @@ -908,7 +912,7 @@ 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) @@ -930,7 +934,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) @@ -940,11 +944,12 @@ 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(KERN_DEBUG "%s: block number too large\n", __func__); @@ -983,8 +988,10 @@ int isofs_get_blocks(struct inode *inode, sector_t iblock_s, offset += sect_size; ninode = isofs_iget(inode->i_sb, nextblk, nextoff); - if (!ninode) + 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; @@ -1015,9 +1022,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; } /* @@ -1026,12 +1034,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(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) @@ -1186,7 +1197,7 @@ out_toomany: 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); @@ -1199,6 +1210,7 @@ static void isofs_read_inode(struct inode *inode) 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); @@ -1216,6 +1228,7 @@ static void isofs_read_inode(struct inode *inode) tmpde = kmalloc(de_len, GFP_KERNEL); if (tmpde == NULL) { printk(KERN_INFO "%s: out of memory\n", __func__); + ret = -ENOMEM; goto fail; } memcpy(tmpde, bh->b_data + offset, frag1); @@ -1259,8 +1272,10 @@ static void isofs_read_inode(struct inode *inode) ei->i_section_size = isonum_733(de->size); if (de->flags[-high_sierra] & 0x80) { - if(isofs_read_level3_size(inode)) + 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; @@ -1346,16 +1361,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; } @@ -1394,9 +1409,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; @@ -1406,9 +1422,17 @@ struct inode *isofs_iget(struct super_block *sb, inode = iget5_locked(sb, hashval, &isofs_iget5_test, &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; |