]> git.karo-electronics.de Git - linux-beck.git/commitdiff
udf: Factor out code for creating indirect extent
authorJan Kara <jack@suse.cz>
Wed, 23 Dec 2015 13:21:13 +0000 (14:21 +0100)
committerJan Kara <jack@suse.cz>
Wed, 23 Dec 2015 17:04:52 +0000 (18:04 +0100)
Factor out code for creating indirect extent from udf_add_aext(). It was
mostly duplicated in two places. Also remove some opencoded versions
of udf_write_aext().

Signed-off-by: Jan Kara <jack@suse.cz>
fs/udf/balloc.c
fs/udf/inode.c
fs/udf/udfdecl.h

index 6d6a96b4e73fe20ba15edc1213564613cb201bbd..e0fd65fe73e82bc4efb5f3f841b6ed8d0f75f0c7 100644 (file)
@@ -447,9 +447,6 @@ static void udf_table_free_blocks(struct super_block *sb,
                 */
 
                int adsize;
-               struct short_ad *sad = NULL;
-               struct long_ad *lad = NULL;
-               struct allocExtDesc *aed;
 
                eloc.logicalBlockNum = start;
                elen = EXT_RECORDED_ALLOCATED |
@@ -466,102 +463,17 @@ static void udf_table_free_blocks(struct super_block *sb,
                }
 
                if (epos.offset + (2 * adsize) > sb->s_blocksize) {
-                       unsigned char *sptr, *dptr;
-                       int loffset;
-
-                       brelse(oepos.bh);
-                       oepos = epos;
-
                        /* Steal a block from the extent being free'd */
-                       epos.block.logicalBlockNum = eloc.logicalBlockNum;
+                       udf_setup_indirect_aext(table, eloc.logicalBlockNum,
+                                               &epos);
+
                        eloc.logicalBlockNum++;
                        elen -= sb->s_blocksize;
-
-                       epos.bh = udf_tread(sb,
-                                       udf_get_lb_pblock(sb, &epos.block, 0));
-                       if (!epos.bh) {
-                               brelse(oepos.bh);
-                               goto error_return;
-                       }
-                       aed = (struct allocExtDesc *)(epos.bh->b_data);
-                       aed->previousAllocExtLocation =
-                               cpu_to_le32(oepos.block.logicalBlockNum);
-                       if (epos.offset + adsize > sb->s_blocksize) {
-                               loffset = epos.offset;
-                               aed->lengthAllocDescs = cpu_to_le32(adsize);
-                               sptr = iinfo->i_ext.i_data + epos.offset
-                                                               - adsize;
-                               dptr = epos.bh->b_data +
-                                       sizeof(struct allocExtDesc);
-                               memcpy(dptr, sptr, adsize);
-                               epos.offset = sizeof(struct allocExtDesc) +
-                                               adsize;
-                       } else {
-                               loffset = epos.offset + adsize;
-                               aed->lengthAllocDescs = cpu_to_le32(0);
-                               if (oepos.bh) {
-                                       sptr = oepos.bh->b_data + epos.offset;
-                                       aed = (struct allocExtDesc *)
-                                               oepos.bh->b_data;
-                                       le32_add_cpu(&aed->lengthAllocDescs,
-                                                       adsize);
-                               } else {
-                                       sptr = iinfo->i_ext.i_data +
-                                                               epos.offset;
-                                       iinfo->i_lenAlloc += adsize;
-                                       mark_inode_dirty(table);
-                               }
-                               epos.offset = sizeof(struct allocExtDesc);
-                       }
-                       if (sbi->s_udfrev >= 0x0200)
-                               udf_new_tag(epos.bh->b_data, TAG_IDENT_AED,
-                                           3, 1, epos.block.logicalBlockNum,
-                                           sizeof(struct tag));
-                       else
-                               udf_new_tag(epos.bh->b_data, TAG_IDENT_AED,
-                                           2, 1, epos.block.logicalBlockNum,
-                                           sizeof(struct tag));
-
-                       switch (iinfo->i_alloc_type) {
-                       case ICBTAG_FLAG_AD_SHORT:
-                               sad = (struct short_ad *)sptr;
-                               sad->extLength = cpu_to_le32(
-                                       EXT_NEXT_EXTENT_ALLOCDECS |
-                                       sb->s_blocksize);
-                               sad->extPosition =
-                                       cpu_to_le32(epos.block.logicalBlockNum);
-                               break;
-                       case ICBTAG_FLAG_AD_LONG:
-                               lad = (struct long_ad *)sptr;
-                               lad->extLength = cpu_to_le32(
-                                       EXT_NEXT_EXTENT_ALLOCDECS |
-                                       sb->s_blocksize);
-                               lad->extLocation =
-                                       cpu_to_lelb(epos.block);
-                               break;
-                       }
-                       if (oepos.bh) {
-                               udf_update_tag(oepos.bh->b_data, loffset);
-                               mark_buffer_dirty(oepos.bh);
-                       } else {
-                               mark_inode_dirty(table);
-                       }
                }
 
                /* It's possible that stealing the block emptied the extent */
-               if (elen) {
-                       udf_write_aext(table, &epos, &eloc, elen, 1);
-
-                       if (!epos.bh) {
-                               iinfo->i_lenAlloc += adsize;
-                               mark_inode_dirty(table);
-                       } else {
-                               aed = (struct allocExtDesc *)epos.bh->b_data;
-                               le32_add_cpu(&aed->lengthAllocDescs, adsize);
-                               udf_update_tag(epos.bh->b_data, epos.offset);
-                               mark_buffer_dirty(epos.bh);
-                       }
-               }
+               if (elen)
+                       __udf_add_aext(table, &epos, &eloc, elen, 1);
        }
 
        brelse(epos.bh);
index 566df9b5a6cb6db53cd375e5211299d7fa6e92e3..34c2d2b795942ee0b7453988cb1862e0f4fb0223 100644 (file)
@@ -1866,112 +1866,102 @@ struct inode *__udf_iget(struct super_block *sb, struct kernel_lb_addr *ino,
        return inode;
 }
 
-int udf_add_aext(struct inode *inode, struct extent_position *epos,
-                struct kernel_lb_addr *eloc, uint32_t elen, int inc)
+int udf_setup_indirect_aext(struct inode *inode, int block,
+                           struct extent_position *epos)
 {
-       int adsize;
-       struct short_ad *sad = NULL;
-       struct long_ad *lad = NULL;
+       struct super_block *sb = inode->i_sb;
+       struct buffer_head *bh;
        struct allocExtDesc *aed;
-       uint8_t *ptr;
-       struct udf_inode_info *iinfo = UDF_I(inode);
+       struct extent_position nepos;
+       struct kernel_lb_addr neloc;
+       int ver, adsize;
 
-       if (!epos->bh)
-               ptr = iinfo->i_ext.i_data + epos->offset -
-                       udf_file_entry_alloc_offset(inode) +
-                       iinfo->i_lenEAttr;
+       if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
+               adsize = sizeof(struct short_ad);
+       else if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_LONG)
+               adsize = sizeof(struct long_ad);
+
+       neloc.logicalBlockNum = block;
+       neloc.partitionReferenceNum = epos->block.partitionReferenceNum;
+
+       bh = udf_tgetblk(sb, udf_get_lb_pblock(sb, &neloc, 0));
+       if (!bh)
+               return -EIO;
+       lock_buffer(bh);
+       memset(bh->b_data, 0x00, sb->s_blocksize);
+       set_buffer_uptodate(bh);
+       unlock_buffer(bh);
+       mark_buffer_dirty_inode(bh, inode);
+
+       aed = (struct allocExtDesc *)(bh->b_data);
+       if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT)) {
+               aed->previousAllocExtLocation =
+                               cpu_to_le32(epos->block.logicalBlockNum);
+       }
+       aed->lengthAllocDescs = cpu_to_le32(0);
+       if (UDF_SB(sb)->s_udfrev >= 0x0200)
+               ver = 3;
        else
-               ptr = epos->bh->b_data + epos->offset;
+               ver = 2;
+       udf_new_tag(bh->b_data, TAG_IDENT_AED, ver, 1, block,
+                   sizeof(struct tag));
+
+       nepos.block = neloc;
+       nepos.offset = sizeof(struct allocExtDesc);
+       nepos.bh = bh;
+
+       /*
+        * Do we have to copy current last extent to make space for indirect
+        * one?
+        */
+       if (epos->offset + adsize > sb->s_blocksize) {
+               struct kernel_lb_addr cp_loc;
+               uint32_t cp_len;
+               int cp_type;
+
+               epos->offset -= adsize;
+               cp_type = udf_current_aext(inode, epos, &cp_loc, &cp_len, 0);
+               cp_len |= ((uint32_t)cp_type) << 30;
+
+               __udf_add_aext(inode, &nepos, &cp_loc, cp_len, 1);
+               udf_write_aext(inode, epos, &nepos.block,
+                              sb->s_blocksize | EXT_NEXT_EXTENT_ALLOCDECS, 0);
+       } else {
+               __udf_add_aext(inode, epos, &nepos.block,
+                              sb->s_blocksize | EXT_NEXT_EXTENT_ALLOCDECS, 0);
+       }
+
+       brelse(epos->bh);
+       *epos = nepos;
+
+       return 0;
+}
+
+/*
+ * Append extent at the given position - should be the first free one in inode
+ * / indirect extent. This function assumes there is enough space in the inode
+ * or indirect extent. Use udf_add_aext() if you didn't check for this before.
+ */
+int __udf_add_aext(struct inode *inode, struct extent_position *epos,
+                  struct kernel_lb_addr *eloc, uint32_t elen, int inc)
+{
+       struct udf_inode_info *iinfo = UDF_I(inode);
+       struct allocExtDesc *aed;
+       int adsize;
 
        if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
                adsize = sizeof(struct short_ad);
        else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
                adsize = sizeof(struct long_ad);
-       else
-               return -EIO;
-
-       if (epos->offset + (2 * adsize) > inode->i_sb->s_blocksize) {
-               unsigned char *sptr, *dptr;
-               struct buffer_head *nbh;
-               int err, loffset;
-               struct kernel_lb_addr obloc = epos->block;
 
-               epos->block.logicalBlockNum = udf_new_block(inode->i_sb, NULL,
-                                               obloc.partitionReferenceNum,
-                                               obloc.logicalBlockNum, &err);
-               if (!epos->block.logicalBlockNum)
-                       return -ENOSPC;
-               nbh = udf_tgetblk(inode->i_sb, udf_get_lb_pblock(inode->i_sb,
-                                                                &epos->block,
-                                                                0));
-               if (!nbh)
-                       return -EIO;
-               lock_buffer(nbh);
-               memset(nbh->b_data, 0x00, inode->i_sb->s_blocksize);
-               set_buffer_uptodate(nbh);
-               unlock_buffer(nbh);
-               mark_buffer_dirty_inode(nbh, inode);
-
-               aed = (struct allocExtDesc *)(nbh->b_data);
-               if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT))
-                       aed->previousAllocExtLocation =
-                                       cpu_to_le32(obloc.logicalBlockNum);
-               if (epos->offset + adsize > inode->i_sb->s_blocksize) {
-                       loffset = epos->offset;
-                       aed->lengthAllocDescs = cpu_to_le32(adsize);
-                       sptr = ptr - adsize;
-                       dptr = nbh->b_data + sizeof(struct allocExtDesc);
-                       memcpy(dptr, sptr, adsize);
-                       epos->offset = sizeof(struct allocExtDesc) + adsize;
-               } else {
-                       loffset = epos->offset + adsize;
-                       aed->lengthAllocDescs = cpu_to_le32(0);
-                       sptr = ptr;
-                       epos->offset = sizeof(struct allocExtDesc);
-
-                       if (epos->bh) {
-                               aed = (struct allocExtDesc *)epos->bh->b_data;
-                               le32_add_cpu(&aed->lengthAllocDescs, adsize);
-                       } else {
-                               iinfo->i_lenAlloc += adsize;
-                               mark_inode_dirty(inode);
-                       }
-               }
-               if (UDF_SB(inode->i_sb)->s_udfrev >= 0x0200)
-                       udf_new_tag(nbh->b_data, TAG_IDENT_AED, 3, 1,
-                                   epos->block.logicalBlockNum, sizeof(struct tag));
-               else
-                       udf_new_tag(nbh->b_data, TAG_IDENT_AED, 2, 1,
-                                   epos->block.logicalBlockNum, sizeof(struct tag));
-               switch (iinfo->i_alloc_type) {
-               case ICBTAG_FLAG_AD_SHORT:
-                       sad = (struct short_ad *)sptr;
-                       sad->extLength = cpu_to_le32(EXT_NEXT_EXTENT_ALLOCDECS |
-                                                    inode->i_sb->s_blocksize);
-                       sad->extPosition =
-                               cpu_to_le32(epos->block.logicalBlockNum);
-                       break;
-               case ICBTAG_FLAG_AD_LONG:
-                       lad = (struct long_ad *)sptr;
-                       lad->extLength = cpu_to_le32(EXT_NEXT_EXTENT_ALLOCDECS |
-                                                    inode->i_sb->s_blocksize);
-                       lad->extLocation = cpu_to_lelb(epos->block);
-                       memset(lad->impUse, 0x00, sizeof(lad->impUse));
-                       break;
-               }
-               if (epos->bh) {
-                       if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
-                           UDF_SB(inode->i_sb)->s_udfrev >= 0x0201)
-                               udf_update_tag(epos->bh->b_data, loffset);
-                       else
-                               udf_update_tag(epos->bh->b_data,
-                                               sizeof(struct allocExtDesc));
-                       mark_buffer_dirty_inode(epos->bh, inode);
-                       brelse(epos->bh);
-               } else {
-                       mark_inode_dirty(inode);
-               }
-               epos->bh = nbh;
+       if (!epos->bh) {
+               WARN_ON(iinfo->i_lenAlloc !=
+                       epos->offset - udf_file_entry_alloc_offset(inode));
+       } else {
+               aed = (struct allocExtDesc *)epos->bh->b_data;
+               WARN_ON(le32_to_cpu(aed->lengthAllocDescs) !=
+                       epos->offset - sizeof(struct allocExtDesc));
+               WARN_ON(epos->offset + adsize > inode->i_sb->s_blocksize);
        }
 
        udf_write_aext(inode, epos, eloc, elen, inc);
@@ -1995,6 +1985,41 @@ int udf_add_aext(struct inode *inode, struct extent_position *epos,
        return 0;
 }
 
+/*
+ * Append extent at given position - should be the first free one in inode
+ * / indirect extent. Takes care of allocating and linking indirect blocks.
+ */
+int udf_add_aext(struct inode *inode, struct extent_position *epos,
+                struct kernel_lb_addr *eloc, uint32_t elen, int inc)
+{
+       int adsize;
+       struct super_block *sb = inode->i_sb;
+
+       if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
+               adsize = sizeof(struct short_ad);
+       else if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_LONG)
+               adsize = sizeof(struct long_ad);
+       else
+               return -EIO;
+
+       if (epos->offset + (2 * adsize) > sb->s_blocksize) {
+               int err;
+               int new_block;
+
+               new_block = udf_new_block(sb, NULL,
+                                         epos->block.partitionReferenceNum,
+                                         epos->block.logicalBlockNum, &err);
+               if (!new_block)
+                       return -ENOSPC;
+
+               err = udf_setup_indirect_aext(inode, new_block, epos);
+               if (err)
+                       return err;
+       }
+
+       return __udf_add_aext(inode, epos, eloc, elen, inc);
+}
+
 void udf_write_aext(struct inode *inode, struct extent_position *epos,
                    struct kernel_lb_addr *eloc, uint32_t elen, int inc)
 {
index 47bb3f5ca360d4f1be8f92036685278868ab99e3..269ad3fb2fab80803903071c846d4d56e935fde1 100644 (file)
@@ -159,6 +159,10 @@ extern int udf_write_inode(struct inode *, struct writeback_control *wbc);
 extern long udf_block_map(struct inode *, sector_t);
 extern int8_t inode_bmap(struct inode *, sector_t, struct extent_position *,
                         struct kernel_lb_addr *, uint32_t *, sector_t *);
+extern int udf_setup_indirect_aext(struct inode *inode, int block,
+                                  struct extent_position *epos);
+extern int __udf_add_aext(struct inode *inode, struct extent_position *epos,
+                         struct kernel_lb_addr *eloc, uint32_t elen, int inc);
 extern int udf_add_aext(struct inode *, struct extent_position *,
                        struct kernel_lb_addr *, uint32_t, int);
 extern void udf_write_aext(struct inode *, struct extent_position *,