diff options
author | Jan Kara <jack@suse.cz> | 2014-10-09 06:52:16 -0400 |
---|---|---|
committer | Jan Kara <jack@suse.cz> | 2014-10-09 07:06:14 -0400 |
commit | 6174c2eb8ecef271159bdcde460ce8af54d8f72f (patch) | |
tree | fc00824fdd8231ac9ee32714fc86493149af29d1 /fs/udf | |
parent | c53f755d339b5546600c316333140d5fe958941d (diff) |
udf: Fix loading of special inodes
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
CC: stable@vger.kernel.org
Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/udf')
-rw-r--r-- | fs/udf/inode.c | 14 | ||||
-rw-r--r-- | fs/udf/super.c | 10 | ||||
-rw-r--r-- | fs/udf/udfdecl.h | 13 |
3 files changed, 26 insertions, 11 deletions
diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 08598843288f..c9b4df5810d5 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c | |||
@@ -1277,7 +1277,7 @@ update_time: | |||
1277 | */ | 1277 | */ |
1278 | #define UDF_MAX_ICB_NESTING 1024 | 1278 | #define UDF_MAX_ICB_NESTING 1024 |
1279 | 1279 | ||
1280 | static int udf_read_inode(struct inode *inode) | 1280 | static int udf_read_inode(struct inode *inode, bool hidden_inode) |
1281 | { | 1281 | { |
1282 | struct buffer_head *bh = NULL; | 1282 | struct buffer_head *bh = NULL; |
1283 | struct fileEntry *fe; | 1283 | struct fileEntry *fe; |
@@ -1436,8 +1436,11 @@ reread: | |||
1436 | 1436 | ||
1437 | link_count = le16_to_cpu(fe->fileLinkCount); | 1437 | link_count = le16_to_cpu(fe->fileLinkCount); |
1438 | if (!link_count) { | 1438 | if (!link_count) { |
1439 | ret = -ESTALE; | 1439 | if (!hidden_inode) { |
1440 | goto out; | 1440 | ret = -ESTALE; |
1441 | goto out; | ||
1442 | } | ||
1443 | link_count = 1; | ||
1441 | } | 1444 | } |
1442 | set_nlink(inode, link_count); | 1445 | set_nlink(inode, link_count); |
1443 | 1446 | ||
@@ -1826,7 +1829,8 @@ out: | |||
1826 | return err; | 1829 | return err; |
1827 | } | 1830 | } |
1828 | 1831 | ||
1829 | struct inode *udf_iget(struct super_block *sb, struct kernel_lb_addr *ino) | 1832 | struct inode *__udf_iget(struct super_block *sb, struct kernel_lb_addr *ino, |
1833 | bool hidden_inode) | ||
1830 | { | 1834 | { |
1831 | unsigned long block = udf_get_lb_pblock(sb, ino, 0); | 1835 | unsigned long block = udf_get_lb_pblock(sb, ino, 0); |
1832 | struct inode *inode = iget_locked(sb, block); | 1836 | struct inode *inode = iget_locked(sb, block); |
@@ -1839,7 +1843,7 @@ struct inode *udf_iget(struct super_block *sb, struct kernel_lb_addr *ino) | |||
1839 | return inode; | 1843 | return inode; |
1840 | 1844 | ||
1841 | memcpy(&UDF_I(inode)->i_location, ino, sizeof(struct kernel_lb_addr)); | 1845 | memcpy(&UDF_I(inode)->i_location, ino, sizeof(struct kernel_lb_addr)); |
1842 | err = udf_read_inode(inode); | 1846 | err = udf_read_inode(inode, hidden_inode); |
1843 | if (err < 0) { | 1847 | if (err < 0) { |
1844 | iget_failed(inode); | 1848 | iget_failed(inode); |
1845 | return ERR_PTR(err); | 1849 | return ERR_PTR(err); |
diff --git a/fs/udf/super.c b/fs/udf/super.c index 5401fc33f5cc..e229315bbf7a 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c | |||
@@ -959,7 +959,7 @@ struct inode *udf_find_metadata_inode_efe(struct super_block *sb, | |||
959 | addr.logicalBlockNum = meta_file_loc; | 959 | addr.logicalBlockNum = meta_file_loc; |
960 | addr.partitionReferenceNum = partition_num; | 960 | addr.partitionReferenceNum = partition_num; |
961 | 961 | ||
962 | metadata_fe = udf_iget(sb, &addr); | 962 | metadata_fe = udf_iget_special(sb, &addr); |
963 | 963 | ||
964 | if (IS_ERR(metadata_fe)) { | 964 | if (IS_ERR(metadata_fe)) { |
965 | udf_warn(sb, "metadata inode efe not found\n"); | 965 | udf_warn(sb, "metadata inode efe not found\n"); |
@@ -1020,7 +1020,7 @@ static int udf_load_metadata_files(struct super_block *sb, int partition) | |||
1020 | udf_debug("Bitmap file location: block = %d part = %d\n", | 1020 | udf_debug("Bitmap file location: block = %d part = %d\n", |
1021 | addr.logicalBlockNum, addr.partitionReferenceNum); | 1021 | addr.logicalBlockNum, addr.partitionReferenceNum); |
1022 | 1022 | ||
1023 | fe = udf_iget(sb, &addr); | 1023 | fe = udf_iget_special(sb, &addr); |
1024 | if (IS_ERR(fe)) { | 1024 | if (IS_ERR(fe)) { |
1025 | if (sb->s_flags & MS_RDONLY) | 1025 | if (sb->s_flags & MS_RDONLY) |
1026 | udf_warn(sb, "bitmap inode efe not found but it's ok since the disc is mounted read-only\n"); | 1026 | 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 super_block *sb, | |||
1119 | }; | 1119 | }; |
1120 | struct inode *inode; | 1120 | struct inode *inode; |
1121 | 1121 | ||
1122 | inode = udf_iget(sb, &loc); | 1122 | inode = udf_iget_special(sb, &loc); |
1123 | if (IS_ERR(inode)) { | 1123 | if (IS_ERR(inode)) { |
1124 | udf_debug("cannot load unallocSpaceTable (part %d)\n", | 1124 | udf_debug("cannot load unallocSpaceTable (part %d)\n", |
1125 | p_index); | 1125 | p_index); |
@@ -1154,7 +1154,7 @@ static int udf_fill_partdesc_info(struct super_block *sb, | |||
1154 | }; | 1154 | }; |
1155 | struct inode *inode; | 1155 | struct inode *inode; |
1156 | 1156 | ||
1157 | inode = udf_iget(sb, &loc); | 1157 | inode = udf_iget_special(sb, &loc); |
1158 | if (IS_ERR(inode)) { | 1158 | if (IS_ERR(inode)) { |
1159 | udf_debug("cannot load freedSpaceTable (part %d)\n", | 1159 | udf_debug("cannot load freedSpaceTable (part %d)\n", |
1160 | p_index); | 1160 | p_index); |
@@ -1198,7 +1198,7 @@ static void udf_find_vat_block(struct super_block *sb, int p_index, | |||
1198 | vat_block >= map->s_partition_root && | 1198 | vat_block >= map->s_partition_root && |
1199 | vat_block >= start_block - 3; vat_block--) { | 1199 | vat_block >= start_block - 3; vat_block--) { |
1200 | ino.logicalBlockNum = vat_block - map->s_partition_root; | 1200 | ino.logicalBlockNum = vat_block - map->s_partition_root; |
1201 | inode = udf_iget(sb, &ino); | 1201 | inode = udf_iget_special(sb, &ino); |
1202 | if (!IS_ERR(inode)) { | 1202 | if (!IS_ERR(inode)) { |
1203 | sbi->s_vat_inode = inode; | 1203 | sbi->s_vat_inode = inode; |
1204 | break; | 1204 | break; |
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index 742557be9936..1cc3c993ebd0 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h | |||
@@ -138,7 +138,18 @@ extern int udf_write_fi(struct inode *inode, struct fileIdentDesc *, | |||
138 | /* file.c */ | 138 | /* file.c */ |
139 | extern long udf_ioctl(struct file *, unsigned int, unsigned long); | 139 | extern long udf_ioctl(struct file *, unsigned int, unsigned long); |
140 | /* inode.c */ | 140 | /* inode.c */ |
141 | extern struct inode *udf_iget(struct super_block *, struct kernel_lb_addr *); | 141 | extern struct inode *__udf_iget(struct super_block *, struct kernel_lb_addr *, |
142 | bool hidden_inode); | ||
143 | static inline struct inode *udf_iget_special(struct super_block *sb, | ||
144 | struct kernel_lb_addr *ino) | ||
145 | { | ||
146 | return __udf_iget(sb, ino, true); | ||
147 | } | ||
148 | static inline struct inode *udf_iget(struct super_block *sb, | ||
149 | struct kernel_lb_addr *ino) | ||
150 | { | ||
151 | return __udf_iget(sb, ino, false); | ||
152 | } | ||
142 | extern int udf_expand_file_adinicb(struct inode *); | 153 | extern int udf_expand_file_adinicb(struct inode *); |
143 | extern struct buffer_head *udf_expand_dir_adinicb(struct inode *, int *, int *); | 154 | extern struct buffer_head *udf_expand_dir_adinicb(struct inode *, int *, int *); |
144 | extern struct buffer_head *udf_bread(struct inode *, int, int, int *); | 155 | extern struct buffer_head *udf_bread(struct inode *, int, int, int *); |