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

Commit fcea62ba authored by Jan Kara's avatar Jan Kara
Browse files

udf: Factor out code for creating indirect extent



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: default avatarJan Kara <jack@suse.cz>
parent b0918d9f
Loading
Loading
Loading
Loading
+5 −93
Original line number Original line Diff line number Diff line
@@ -447,9 +447,6 @@ static void udf_table_free_blocks(struct super_block *sb,
		 */
		 */


		int adsize;
		int adsize;
		struct short_ad *sad = NULL;
		struct long_ad *lad = NULL;
		struct allocExtDesc *aed;


		eloc.logicalBlockNum = start;
		eloc.logicalBlockNum = start;
		elen = EXT_RECORDED_ALLOCATED |
		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) {
		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 */
			/* Steal a block from the extent being free'd */
			epos.block.logicalBlockNum = eloc.logicalBlockNum;
			udf_setup_indirect_aext(table, eloc.logicalBlockNum,
						&epos);

			eloc.logicalBlockNum++;
			eloc.logicalBlockNum++;
			elen -= sb->s_blocksize;
			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 */
		/* It's possible that stealing the block emptied the extent */
		if (elen) {
		if (elen)
			udf_write_aext(table, &epos, &eloc, elen, 1);
			__udf_add_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);
			}
		}
	}
	}


	brelse(epos.bh);
	brelse(epos.bh);
+121 −96
Original line number Original line Diff line number Diff line
@@ -1866,112 +1866,102 @@ struct inode *__udf_iget(struct super_block *sb, struct kernel_lb_addr *ino,
	return inode;
	return inode;
}
}


int udf_add_aext(struct inode *inode, struct extent_position *epos,
int udf_setup_indirect_aext(struct inode *inode, int block,
		 struct kernel_lb_addr *eloc, uint32_t elen, int inc)
			    struct extent_position *epos)
{
{
	int adsize;
	struct super_block *sb = inode->i_sb;
	struct short_ad *sad = NULL;
	struct buffer_head *bh;
	struct long_ad *lad = NULL;
	struct allocExtDesc *aed;
	struct allocExtDesc *aed;
	uint8_t *ptr;
	struct extent_position nepos;
	struct udf_inode_info *iinfo = UDF_I(inode);
	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;
	else
		ptr = epos->bh->b_data + epos->offset;


	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
	if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
		adsize = sizeof(struct short_ad);
		adsize = sizeof(struct short_ad);
	else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
	else if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_LONG)
		adsize = sizeof(struct long_ad);
		adsize = sizeof(struct long_ad);
	else
		return -EIO;


	if (epos->offset + (2 * adsize) > inode->i_sb->s_blocksize) {
	neloc.logicalBlockNum = block;
		unsigned char *sptr, *dptr;
	neloc.partitionReferenceNum = epos->block.partitionReferenceNum;
		struct buffer_head *nbh;
		int err, loffset;
		struct kernel_lb_addr obloc = epos->block;


		epos->block.logicalBlockNum = udf_new_block(inode->i_sb, NULL,
	bh = udf_tgetblk(sb, udf_get_lb_pblock(sb, &neloc, 0));
						obloc.partitionReferenceNum,
	if (!bh)
						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;
		return -EIO;
		lock_buffer(nbh);
	lock_buffer(bh);
		memset(nbh->b_data, 0x00, inode->i_sb->s_blocksize);
	memset(bh->b_data, 0x00, sb->s_blocksize);
		set_buffer_uptodate(nbh);
	set_buffer_uptodate(bh);
		unlock_buffer(nbh);
	unlock_buffer(bh);
		mark_buffer_dirty_inode(nbh, inode);
	mark_buffer_dirty_inode(bh, inode);


		aed = (struct allocExtDesc *)(nbh->b_data);
	aed = (struct allocExtDesc *)(bh->b_data);
		if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT))
	if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT)) {
		aed->previousAllocExtLocation =
		aed->previousAllocExtLocation =
					cpu_to_le32(obloc.logicalBlockNum);
				cpu_to_le32(epos->block.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);
	aed->lengthAllocDescs = cpu_to_le32(0);
			sptr = ptr;
	if (UDF_SB(sb)->s_udfrev >= 0x0200)
			epos->offset = sizeof(struct allocExtDesc);
		ver = 3;
	else
		ver = 2;
	udf_new_tag(bh->b_data, TAG_IDENT_AED, ver, 1, block,
		    sizeof(struct tag));


			if (epos->bh) {
	nepos.block = neloc;
				aed = (struct allocExtDesc *)epos->bh->b_data;
	nepos.offset = sizeof(struct allocExtDesc);
				le32_add_cpu(&aed->lengthAllocDescs, adsize);
	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 {
	} else {
				iinfo->i_lenAlloc += adsize;
		__udf_add_aext(inode, epos, &nepos.block,
				mark_inode_dirty(inode);
			       sb->s_blocksize | EXT_NEXT_EXTENT_ALLOCDECS, 0);
	}
	}
		}

		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);
	brelse(epos->bh);
		} else {
	*epos = nepos;
			mark_inode_dirty(inode);

	return 0;
}
}
		epos->bh = nbh;

/*
 * 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);

	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);
	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;
	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,
void udf_write_aext(struct inode *inode, struct extent_position *epos,
		    struct kernel_lb_addr *eloc, uint32_t elen, int inc)
		    struct kernel_lb_addr *eloc, uint32_t elen, int inc)
{
{
+4 −0
Original line number Original line Diff line number Diff line
@@ -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 long udf_block_map(struct inode *, sector_t);
extern int8_t inode_bmap(struct inode *, sector_t, struct extent_position *,
extern int8_t inode_bmap(struct inode *, sector_t, struct extent_position *,
			 struct kernel_lb_addr *, uint32_t *, sector_t *);
			 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 *,
extern int udf_add_aext(struct inode *, struct extent_position *,
			struct kernel_lb_addr *, uint32_t, int);
			struct kernel_lb_addr *, uint32_t, int);
extern void udf_write_aext(struct inode *, struct extent_position *,
extern void udf_write_aext(struct inode *, struct extent_position *,