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 4071b91362 (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: 4071b91362
CC: stable@vger.kernel.org
Signed-off-by: Jan Kara <jack@suse.cz>
This commit is contained in:
Jan Kara 2014-10-09 12:52:16 +02:00
parent c53f755d33
commit 6174c2eb8e
3 changed files with 26 additions and 11 deletions

View File

@ -1277,7 +1277,7 @@ update_time:
*/ */
#define UDF_MAX_ICB_NESTING 1024 #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 buffer_head *bh = NULL;
struct fileEntry *fe; struct fileEntry *fe;
@ -1436,8 +1436,11 @@ reread:
link_count = le16_to_cpu(fe->fileLinkCount); link_count = le16_to_cpu(fe->fileLinkCount);
if (!link_count) { if (!link_count) {
ret = -ESTALE; if (!hidden_inode) {
goto out; ret = -ESTALE;
goto out;
}
link_count = 1;
} }
set_nlink(inode, link_count); set_nlink(inode, link_count);
@ -1826,7 +1829,8 @@ out:
return err; 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); unsigned long block = udf_get_lb_pblock(sb, ino, 0);
struct inode *inode = iget_locked(sb, block); struct inode *inode = iget_locked(sb, block);
@ -1839,7 +1843,7 @@ struct inode *udf_iget(struct super_block *sb, struct kernel_lb_addr *ino)
return inode; return inode;
memcpy(&UDF_I(inode)->i_location, ino, sizeof(struct kernel_lb_addr)); 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) { if (err < 0) {
iget_failed(inode); iget_failed(inode);
return ERR_PTR(err); return ERR_PTR(err);

View File

@ -959,7 +959,7 @@ struct inode *udf_find_metadata_inode_efe(struct super_block *sb,
addr.logicalBlockNum = meta_file_loc; addr.logicalBlockNum = meta_file_loc;
addr.partitionReferenceNum = partition_num; addr.partitionReferenceNum = partition_num;
metadata_fe = udf_iget(sb, &addr); metadata_fe = udf_iget_special(sb, &addr);
if (IS_ERR(metadata_fe)) { if (IS_ERR(metadata_fe)) {
udf_warn(sb, "metadata inode efe not found\n"); 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)
udf_debug("Bitmap file location: block = %d part = %d\n", udf_debug("Bitmap file location: block = %d part = %d\n",
addr.logicalBlockNum, addr.partitionReferenceNum); addr.logicalBlockNum, addr.partitionReferenceNum);
fe = udf_iget(sb, &addr); fe = udf_iget_special(sb, &addr);
if (IS_ERR(fe)) { if (IS_ERR(fe)) {
if (sb->s_flags & MS_RDONLY) 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"); 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,
}; };
struct inode *inode; struct inode *inode;
inode = udf_iget(sb, &loc); inode = udf_iget_special(sb, &loc);
if (IS_ERR(inode)) { if (IS_ERR(inode)) {
udf_debug("cannot load unallocSpaceTable (part %d)\n", udf_debug("cannot load unallocSpaceTable (part %d)\n",
p_index); p_index);
@ -1154,7 +1154,7 @@ static int udf_fill_partdesc_info(struct super_block *sb,
}; };
struct inode *inode; struct inode *inode;
inode = udf_iget(sb, &loc); inode = udf_iget_special(sb, &loc);
if (IS_ERR(inode)) { if (IS_ERR(inode)) {
udf_debug("cannot load freedSpaceTable (part %d)\n", udf_debug("cannot load freedSpaceTable (part %d)\n",
p_index); p_index);
@ -1198,7 +1198,7 @@ static void udf_find_vat_block(struct super_block *sb, int p_index,
vat_block >= map->s_partition_root && vat_block >= map->s_partition_root &&
vat_block >= start_block - 3; vat_block--) { vat_block >= start_block - 3; vat_block--) {
ino.logicalBlockNum = vat_block - map->s_partition_root; ino.logicalBlockNum = vat_block - map->s_partition_root;
inode = udf_iget(sb, &ino); inode = udf_iget_special(sb, &ino);
if (!IS_ERR(inode)) { if (!IS_ERR(inode)) {
sbi->s_vat_inode = inode; sbi->s_vat_inode = inode;
break; break;

View File

@ -138,7 +138,18 @@ extern int udf_write_fi(struct inode *inode, struct fileIdentDesc *,
/* file.c */ /* file.c */
extern long udf_ioctl(struct file *, unsigned int, unsigned long); extern long udf_ioctl(struct file *, unsigned int, unsigned long);
/* inode.c */ /* 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 int udf_expand_file_adinicb(struct inode *);
extern struct buffer_head *udf_expand_dir_adinicb(struct inode *, int *, int *); extern struct buffer_head *udf_expand_dir_adinicb(struct inode *, int *, int *);
extern struct buffer_head *udf_bread(struct inode *, int, int, int *); extern struct buffer_head *udf_bread(struct inode *, int, int, int *);