forked from Minki/linux
udf: Fix loading of special inodes
Some UDF media have special inodes (like VAT or metadata partition inodes) whose link_count is 0. Thus commit4071b91362
(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:
parent
c53f755d33
commit
6174c2eb8e
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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 *);
|
||||||
|
Loading…
Reference in New Issue
Block a user