udf: Fix loading of special inodes
authorJan Kara <jack@suse.cz>
Thu, 9 Oct 2014 10:52:16 +0000 (12:52 +0200)
committerJan Kara <jack@suse.cz>
Thu, 9 Oct 2014 11:06:14 +0000 (13:06 +0200)
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>
fs/udf/inode.c
fs/udf/super.c
fs/udf/udfdecl.h

index 08598843288fe0c2dd206940d6437c606ef41c1f..c9b4df5810d52560b084b9557150faf8cfbe6e29 100644 (file)
@@ -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_block *sb, struct kernel_lb_addr *ino)
                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);
index 5401fc33f5cc906b76b846e62f74751cabd50a68..e229315bbf7adab01933827a68b59ccb8831dec7 100644 (file)
@@ -959,7 +959,7 @@ struct inode *udf_find_metadata_inode_efe(struct super_block *sb,
        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(struct super_block *sb, int partition)
                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 super_block *sb,
                };
                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 super_block *sb,
                };
                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 super_block *sb, int p_index,
             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;
index 742557be9936399fba764f645c04b969d2a3cfd5..1cc3c993ebd04f4adb7b425f500e40d1185aae9f 100644 (file)
@@ -138,7 +138,18 @@ extern int udf_write_fi(struct inode *inode, struct fileIdentDesc *,
 /* 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 *);