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: Jan Kara <jack@suse.cz>
This commit is contained in:
parent
b0918d9f47
commit
fcea62babc
|
@ -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);
|
||||
|
|
217
fs/udf/inode.c
217
fs/udf/inode.c
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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 *,
|
||||
|
|
Loading…
Reference in New Issue