Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6174c2eb authored by Jan Kara's avatar Jan Kara
Browse files

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 4071b913 (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: 4071b913
CC: stable@vger.kernel.org
Signed-off-by: default avatarJan Kara <jack@suse.cz>
parent c53f755d
Loading
Loading
Loading
Loading
+9 −5
Original line number Original line Diff line number Diff line
@@ -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,9 +1436,12 @@ reread:


	link_count = le16_to_cpu(fe->fileLinkCount);
	link_count = le16_to_cpu(fe->fileLinkCount);
	if (!link_count) {
	if (!link_count) {
		if (!hidden_inode) {
			ret = -ESTALE;
			ret = -ESTALE;
			goto out;
			goto out;
		}
		}
		link_count = 1;
	}
	set_nlink(inode, link_count);
	set_nlink(inode, link_count);


	inode->i_size = le64_to_cpu(fe->informationLength);
	inode->i_size = le64_to_cpu(fe->informationLength);
@@ -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);
+5 −5
Original line number Original line Diff line number Diff line
@@ -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;
+12 −1
Original line number Original line Diff line number Diff line
@@ -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 *);