| From 6174c2eb8ecef271159bdcde460ce8af54d8f72f Mon Sep 17 00:00:00 2001 |
| From: Jan Kara <jack@suse.cz> |
| Date: Thu, 9 Oct 2014 12:52:16 +0200 |
| Subject: udf: Fix loading of special inodes |
| |
| From: Jan Kara <jack@suse.cz> |
| |
| commit 6174c2eb8ecef271159bdcde460ce8af54d8f72f upstream. |
| |
| Some UDF media have special inodes (like VAT or metadata partition |
| inodes) whose link_count is 0. Thus commit 4071b9136223 (udf: Properly |
| detect stale inodes) broke loading these inodes because udf_iget() |
| started returning -ESTALE for them. Since we still need to properly |
| detect stale inodes queried by NFS, create two variants of udf_iget() - |
| one which is used for looking up special inodes (which ignores |
| link_count == 0) and one which is used for other cases which return |
| ESTALE when link_count == 0. |
| |
| Fixes: 4071b913622316970d0e1919f7d82b4403fec5f2 |
| Signed-off-by: Jan Kara <jack@suse.cz> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/udf/inode.c | 14 +++++++++----- |
| fs/udf/super.c | 10 +++++----- |
| fs/udf/udfdecl.h | 13 ++++++++++++- |
| 3 files changed, 26 insertions(+), 11 deletions(-) |
| |
| --- a/fs/udf/inode.c |
| +++ b/fs/udf/inode.c |
| @@ -1277,7 +1277,7 @@ update_time: |
| */ |
| #define UDF_MAX_ICB_NESTING 1024 |
| |
| -static int udf_read_inode(struct inode *inode) |
| +static int udf_read_inode(struct inode *inode, bool hidden_inode) |
| { |
| struct buffer_head *bh = NULL; |
| struct fileEntry *fe; |
| @@ -1436,8 +1436,11 @@ reread: |
| |
| link_count = le16_to_cpu(fe->fileLinkCount); |
| if (!link_count) { |
| - ret = -ESTALE; |
| - goto out; |
| + if (!hidden_inode) { |
| + ret = -ESTALE; |
| + goto out; |
| + } |
| + link_count = 1; |
| } |
| set_nlink(inode, link_count); |
| |
| @@ -1826,7 +1829,8 @@ out: |
| return err; |
| } |
| |
| -struct inode *udf_iget(struct super_block *sb, struct kernel_lb_addr *ino) |
| +struct inode *__udf_iget(struct super_block *sb, struct kernel_lb_addr *ino, |
| + bool hidden_inode) |
| { |
| unsigned long block = udf_get_lb_pblock(sb, ino, 0); |
| struct inode *inode = iget_locked(sb, block); |
| @@ -1839,7 +1843,7 @@ struct inode *udf_iget(struct super_bloc |
| return inode; |
| |
| memcpy(&UDF_I(inode)->i_location, ino, sizeof(struct kernel_lb_addr)); |
| - err = udf_read_inode(inode); |
| + err = udf_read_inode(inode, hidden_inode); |
| if (err < 0) { |
| iget_failed(inode); |
| return ERR_PTR(err); |
| --- a/fs/udf/super.c |
| +++ b/fs/udf/super.c |
| @@ -959,7 +959,7 @@ struct inode *udf_find_metadata_inode_ef |
| addr.logicalBlockNum = meta_file_loc; |
| addr.partitionReferenceNum = partition_num; |
| |
| - metadata_fe = udf_iget(sb, &addr); |
| + metadata_fe = udf_iget_special(sb, &addr); |
| |
| if (IS_ERR(metadata_fe)) { |
| udf_warn(sb, "metadata inode efe not found\n"); |
| @@ -1020,7 +1020,7 @@ static int udf_load_metadata_files(struc |
| udf_debug("Bitmap file location: block = %d part = %d\n", |
| addr.logicalBlockNum, addr.partitionReferenceNum); |
| |
| - fe = udf_iget(sb, &addr); |
| + fe = udf_iget_special(sb, &addr); |
| if (IS_ERR(fe)) { |
| if (sb->s_flags & MS_RDONLY) |
| udf_warn(sb, "bitmap inode efe not found but it's ok since the disc is mounted read-only\n"); |
| @@ -1119,7 +1119,7 @@ static int udf_fill_partdesc_info(struct |
| }; |
| struct inode *inode; |
| |
| - inode = udf_iget(sb, &loc); |
| + inode = udf_iget_special(sb, &loc); |
| if (IS_ERR(inode)) { |
| udf_debug("cannot load unallocSpaceTable (part %d)\n", |
| p_index); |
| @@ -1154,7 +1154,7 @@ static int udf_fill_partdesc_info(struct |
| }; |
| struct inode *inode; |
| |
| - inode = udf_iget(sb, &loc); |
| + inode = udf_iget_special(sb, &loc); |
| if (IS_ERR(inode)) { |
| udf_debug("cannot load freedSpaceTable (part %d)\n", |
| p_index); |
| @@ -1198,7 +1198,7 @@ static void udf_find_vat_block(struct su |
| vat_block >= map->s_partition_root && |
| vat_block >= start_block - 3; vat_block--) { |
| ino.logicalBlockNum = vat_block - map->s_partition_root; |
| - inode = udf_iget(sb, &ino); |
| + inode = udf_iget_special(sb, &ino); |
| if (!IS_ERR(inode)) { |
| sbi->s_vat_inode = inode; |
| break; |
| --- a/fs/udf/udfdecl.h |
| +++ b/fs/udf/udfdecl.h |
| @@ -138,7 +138,18 @@ extern int udf_write_fi(struct inode *in |
| /* file.c */ |
| extern long udf_ioctl(struct file *, unsigned int, unsigned long); |
| /* inode.c */ |
| -extern struct inode *udf_iget(struct super_block *, struct kernel_lb_addr *); |
| +extern struct inode *__udf_iget(struct super_block *, struct kernel_lb_addr *, |
| + bool hidden_inode); |
| +static inline struct inode *udf_iget_special(struct super_block *sb, |
| + struct kernel_lb_addr *ino) |
| +{ |
| + return __udf_iget(sb, ino, true); |
| +} |
| +static inline struct inode *udf_iget(struct super_block *sb, |
| + struct kernel_lb_addr *ino) |
| +{ |
| + return __udf_iget(sb, ino, false); |
| +} |
| extern int udf_expand_file_adinicb(struct inode *); |
| extern struct buffer_head *udf_expand_dir_adinicb(struct inode *, int *, int *); |
| extern struct buffer_head *udf_bread(struct inode *, int, int, int *); |