mirror of
https://github.com/torvalds/linux
synced 2024-11-05 18:23:50 +00:00
udf: Convert UDF to new truncate calling sequence
Use new truncation sequence in UDF and fix up error handling in the code. Signed-off-by: Jan Kara <jack@suse.cz>
This commit is contained in:
parent
4a508dd259
commit
7e49b6f248
4 changed files with 234 additions and 170 deletions
|
@ -123,8 +123,8 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
|
|||
if (inode->i_sb->s_blocksize <
|
||||
(udf_file_entry_alloc_offset(inode) +
|
||||
pos + count)) {
|
||||
udf_expand_file_adinicb(inode, pos + count, &err);
|
||||
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
|
||||
err = udf_expand_file_adinicb(inode);
|
||||
if (err) {
|
||||
udf_debug("udf_expand_adinicb: err=%d\n", err);
|
||||
up_write(&iinfo->i_data_sem);
|
||||
return err;
|
||||
|
@ -237,7 +237,7 @@ static int udf_setattr(struct dentry *dentry, struct iattr *attr)
|
|||
|
||||
if ((attr->ia_valid & ATTR_SIZE) &&
|
||||
attr->ia_size != i_size_read(inode)) {
|
||||
error = vmtruncate(inode, attr->ia_size);
|
||||
error = udf_setsize(inode, attr->ia_size);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
@ -249,5 +249,4 @@ static int udf_setattr(struct dentry *dentry, struct iattr *attr)
|
|||
|
||||
const struct inode_operations udf_file_inode_operations = {
|
||||
.setattr = udf_setattr,
|
||||
.truncate = udf_truncate,
|
||||
};
|
||||
|
|
239
fs/udf/inode.c
239
fs/udf/inode.c
|
@ -73,14 +73,12 @@ void udf_evict_inode(struct inode *inode)
|
|||
struct udf_inode_info *iinfo = UDF_I(inode);
|
||||
int want_delete = 0;
|
||||
|
||||
truncate_inode_pages(&inode->i_data, 0);
|
||||
|
||||
if (!inode->i_nlink && !is_bad_inode(inode)) {
|
||||
want_delete = 1;
|
||||
inode->i_size = 0;
|
||||
udf_truncate(inode);
|
||||
udf_setsize(inode, 0);
|
||||
udf_update_inode(inode, IS_SYNC(inode));
|
||||
}
|
||||
} else
|
||||
truncate_inode_pages(&inode->i_data, 0);
|
||||
invalidate_inode_buffers(inode);
|
||||
end_writeback(inode);
|
||||
if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB &&
|
||||
|
@ -117,9 +115,18 @@ static int udf_write_begin(struct file *file, struct address_space *mapping,
|
|||
|
||||
ret = block_write_begin(mapping, pos, len, flags, pagep, udf_get_block);
|
||||
if (unlikely(ret)) {
|
||||
loff_t isize = mapping->host->i_size;
|
||||
if (pos + len > isize)
|
||||
vmtruncate(mapping->host, isize);
|
||||
struct inode *inode = mapping->host;
|
||||
struct udf_inode_info *iinfo = UDF_I(inode);
|
||||
loff_t isize = inode->i_size;
|
||||
|
||||
if (pos + len > isize) {
|
||||
truncate_pagecache(inode, pos + len, isize);
|
||||
if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
|
||||
down_write(&iinfo->i_data_sem);
|
||||
udf_truncate_extents(inode);
|
||||
up_write(&iinfo->i_data_sem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -139,30 +146,31 @@ const struct address_space_operations udf_aops = {
|
|||
.bmap = udf_bmap,
|
||||
};
|
||||
|
||||
void udf_expand_file_adinicb(struct inode *inode, int newsize, int *err)
|
||||
int udf_expand_file_adinicb(struct inode *inode)
|
||||
{
|
||||
struct page *page;
|
||||
char *kaddr;
|
||||
struct udf_inode_info *iinfo = UDF_I(inode);
|
||||
int err;
|
||||
struct writeback_control udf_wbc = {
|
||||
.sync_mode = WB_SYNC_NONE,
|
||||
.nr_to_write = 1,
|
||||
};
|
||||
|
||||
/* from now on we have normal address_space methods */
|
||||
inode->i_data.a_ops = &udf_aops;
|
||||
|
||||
if (!iinfo->i_lenAlloc) {
|
||||
if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD))
|
||||
iinfo->i_alloc_type = ICBTAG_FLAG_AD_SHORT;
|
||||
else
|
||||
iinfo->i_alloc_type = ICBTAG_FLAG_AD_LONG;
|
||||
/* from now on we have normal address_space methods */
|
||||
inode->i_data.a_ops = &udf_aops;
|
||||
mark_inode_dirty(inode);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
page = grab_cache_page(inode->i_mapping, 0);
|
||||
BUG_ON(!PageLocked(page));
|
||||
page = find_or_create_page(inode->i_mapping, 0, GFP_NOFS);
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!PageUptodate(page)) {
|
||||
kaddr = kmap(page);
|
||||
|
@ -181,11 +189,24 @@ void udf_expand_file_adinicb(struct inode *inode, int newsize, int *err)
|
|||
iinfo->i_alloc_type = ICBTAG_FLAG_AD_SHORT;
|
||||
else
|
||||
iinfo->i_alloc_type = ICBTAG_FLAG_AD_LONG;
|
||||
|
||||
inode->i_data.a_ops->writepage(page, &udf_wbc);
|
||||
/* from now on we have normal address_space methods */
|
||||
inode->i_data.a_ops = &udf_aops;
|
||||
err = inode->i_data.a_ops->writepage(page, &udf_wbc);
|
||||
if (err) {
|
||||
/* Restore everything back so that we don't lose data... */
|
||||
lock_page(page);
|
||||
kaddr = kmap(page);
|
||||
memcpy(iinfo->i_ext.i_data + iinfo->i_lenEAttr, kaddr,
|
||||
inode->i_size);
|
||||
kunmap(page);
|
||||
unlock_page(page);
|
||||
iinfo->i_alloc_type = ICBTAG_FLAG_AD_IN_ICB;
|
||||
inode->i_data.a_ops = &udf_adinicb_aops;
|
||||
}
|
||||
page_cache_release(page);
|
||||
|
||||
mark_inode_dirty(inode);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
struct buffer_head *udf_expand_dir_adinicb(struct inode *inode, int *block,
|
||||
|
@ -348,8 +369,10 @@ static struct buffer_head *udf_getblk(struct inode *inode, long block,
|
|||
}
|
||||
|
||||
/* Extend the file by 'blocks' blocks, return the number of extents added */
|
||||
int udf_extend_file(struct inode *inode, struct extent_position *last_pos,
|
||||
struct kernel_long_ad *last_ext, sector_t blocks)
|
||||
static int udf_do_extend_file(struct inode *inode,
|
||||
struct extent_position *last_pos,
|
||||
struct kernel_long_ad *last_ext,
|
||||
sector_t blocks)
|
||||
{
|
||||
sector_t add;
|
||||
int count = 0, fake = !(last_ext->extLength & UDF_EXTENT_LENGTH_MASK);
|
||||
|
@ -357,6 +380,7 @@ int udf_extend_file(struct inode *inode, struct extent_position *last_pos,
|
|||
struct kernel_lb_addr prealloc_loc = {};
|
||||
int prealloc_len = 0;
|
||||
struct udf_inode_info *iinfo;
|
||||
int err;
|
||||
|
||||
/* The previous extent is fake and we should not extend by anything
|
||||
* - there's nothing to do... */
|
||||
|
@ -422,26 +446,29 @@ int udf_extend_file(struct inode *inode, struct extent_position *last_pos,
|
|||
/* Create enough extents to cover the whole hole */
|
||||
while (blocks > add) {
|
||||
blocks -= add;
|
||||
if (udf_add_aext(inode, last_pos, &last_ext->extLocation,
|
||||
last_ext->extLength, 1) == -1)
|
||||
return -1;
|
||||
err = udf_add_aext(inode, last_pos, &last_ext->extLocation,
|
||||
last_ext->extLength, 1);
|
||||
if (err)
|
||||
return err;
|
||||
count++;
|
||||
}
|
||||
if (blocks) {
|
||||
last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
|
||||
(blocks << sb->s_blocksize_bits);
|
||||
if (udf_add_aext(inode, last_pos, &last_ext->extLocation,
|
||||
last_ext->extLength, 1) == -1)
|
||||
return -1;
|
||||
err = udf_add_aext(inode, last_pos, &last_ext->extLocation,
|
||||
last_ext->extLength, 1);
|
||||
if (err)
|
||||
return err;
|
||||
count++;
|
||||
}
|
||||
|
||||
out:
|
||||
/* Do we have some preallocated blocks saved? */
|
||||
if (prealloc_len) {
|
||||
if (udf_add_aext(inode, last_pos, &prealloc_loc,
|
||||
prealloc_len, 1) == -1)
|
||||
return -1;
|
||||
err = udf_add_aext(inode, last_pos, &prealloc_loc,
|
||||
prealloc_len, 1);
|
||||
if (err)
|
||||
return err;
|
||||
last_ext->extLocation = prealloc_loc;
|
||||
last_ext->extLength = prealloc_len;
|
||||
count++;
|
||||
|
@ -453,11 +480,68 @@ int udf_extend_file(struct inode *inode, struct extent_position *last_pos,
|
|||
else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
|
||||
last_pos->offset -= sizeof(struct long_ad);
|
||||
else
|
||||
return -1;
|
||||
return -EIO;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int udf_extend_file(struct inode *inode, loff_t newsize)
|
||||
{
|
||||
|
||||
struct extent_position epos;
|
||||
struct kernel_lb_addr eloc;
|
||||
uint32_t elen;
|
||||
int8_t etype;
|
||||
struct super_block *sb = inode->i_sb;
|
||||
sector_t first_block = newsize >> sb->s_blocksize_bits, offset;
|
||||
int adsize;
|
||||
struct udf_inode_info *iinfo = UDF_I(inode);
|
||||
struct kernel_long_ad extent;
|
||||
int err;
|
||||
|
||||
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
|
||||
BUG();
|
||||
|
||||
etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset);
|
||||
|
||||
/* File has extent covering the new size (could happen when extending
|
||||
* inside a block)? */
|
||||
if (etype != -1)
|
||||
return 0;
|
||||
if (newsize & (sb->s_blocksize - 1))
|
||||
offset++;
|
||||
/* Extended file just to the boundary of the last file block? */
|
||||
if (offset == 0)
|
||||
return 0;
|
||||
|
||||
/* Truncate is extending the file by 'offset' blocks */
|
||||
if ((!epos.bh && epos.offset == udf_file_entry_alloc_offset(inode)) ||
|
||||
(epos.bh && epos.offset == sizeof(struct allocExtDesc))) {
|
||||
/* File has no extents at all or has empty last
|
||||
* indirect extent! Create a fake extent... */
|
||||
extent.extLocation.logicalBlockNum = 0;
|
||||
extent.extLocation.partitionReferenceNum = 0;
|
||||
extent.extLength = EXT_NOT_RECORDED_NOT_ALLOCATED;
|
||||
} else {
|
||||
epos.offset -= adsize;
|
||||
etype = udf_next_aext(inode, &epos, &extent.extLocation,
|
||||
&extent.extLength, 0);
|
||||
extent.extLength |= etype << 30;
|
||||
}
|
||||
err = udf_do_extend_file(inode, &epos, &extent, offset);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
err = 0;
|
||||
iinfo->i_lenExtents = newsize;
|
||||
out:
|
||||
brelse(epos.bh);
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct buffer_head *inode_getblk(struct inode *inode, sector_t block,
|
||||
int *err, sector_t *phys, int *new)
|
||||
{
|
||||
|
@ -540,7 +624,7 @@ static struct buffer_head *inode_getblk(struct inode *inode, sector_t block,
|
|||
elen = EXT_RECORDED_ALLOCATED |
|
||||
((elen + inode->i_sb->s_blocksize - 1) &
|
||||
~(inode->i_sb->s_blocksize - 1));
|
||||
etype = udf_write_aext(inode, &cur_epos, &eloc, elen, 1);
|
||||
udf_write_aext(inode, &cur_epos, &eloc, elen, 1);
|
||||
}
|
||||
brelse(prev_epos.bh);
|
||||
brelse(cur_epos.bh);
|
||||
|
@ -564,19 +648,17 @@ static struct buffer_head *inode_getblk(struct inode *inode, sector_t block,
|
|||
memset(&laarr[0].extLocation, 0x00,
|
||||
sizeof(struct kernel_lb_addr));
|
||||
laarr[0].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED;
|
||||
/* Will udf_extend_file() create real extent from
|
||||
/* Will udf_do_extend_file() create real extent from
|
||||
a fake one? */
|
||||
startnum = (offset > 0);
|
||||
}
|
||||
/* Create extents for the hole between EOF and offset */
|
||||
ret = udf_extend_file(inode, &prev_epos, laarr, offset);
|
||||
if (ret == -1) {
|
||||
ret = udf_do_extend_file(inode, &prev_epos, laarr, offset);
|
||||
if (ret < 0) {
|
||||
brelse(prev_epos.bh);
|
||||
brelse(cur_epos.bh);
|
||||
brelse(next_epos.bh);
|
||||
/* We don't really know the error here so we just make
|
||||
* something up */
|
||||
*err = -ENOSPC;
|
||||
*err = ret;
|
||||
return NULL;
|
||||
}
|
||||
c = 0;
|
||||
|
@ -1005,52 +1087,66 @@ struct buffer_head *udf_bread(struct inode *inode, int block,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void udf_truncate(struct inode *inode)
|
||||
int udf_setsize(struct inode *inode, loff_t newsize)
|
||||
{
|
||||
int offset;
|
||||
int err;
|
||||
struct udf_inode_info *iinfo;
|
||||
int bsize = 1 << inode->i_blkbits;
|
||||
|
||||
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
|
||||
S_ISLNK(inode->i_mode)))
|
||||
return;
|
||||
return -EINVAL;
|
||||
if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
|
||||
return;
|
||||
return -EPERM;
|
||||
|
||||
iinfo = UDF_I(inode);
|
||||
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
|
||||
if (newsize > inode->i_size) {
|
||||
down_write(&iinfo->i_data_sem);
|
||||
if (inode->i_sb->s_blocksize <
|
||||
(udf_file_entry_alloc_offset(inode) +
|
||||
inode->i_size)) {
|
||||
udf_expand_file_adinicb(inode, inode->i_size, &err);
|
||||
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
|
||||
inode->i_size = iinfo->i_lenAlloc;
|
||||
up_write(&iinfo->i_data_sem);
|
||||
return;
|
||||
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
|
||||
if (bsize <
|
||||
(udf_file_entry_alloc_offset(inode) + newsize)) {
|
||||
err = udf_expand_file_adinicb(inode);
|
||||
if (err) {
|
||||
up_write(&iinfo->i_data_sem);
|
||||
return err;
|
||||
}
|
||||
} else
|
||||
udf_truncate_extents(inode);
|
||||
} else {
|
||||
offset = inode->i_size & (inode->i_sb->s_blocksize - 1);
|
||||
memset(iinfo->i_ext.i_data + iinfo->i_lenEAttr + offset,
|
||||
0x00, inode->i_sb->s_blocksize -
|
||||
offset - udf_file_entry_alloc_offset(inode));
|
||||
iinfo->i_lenAlloc = inode->i_size;
|
||||
iinfo->i_lenAlloc = newsize;
|
||||
}
|
||||
err = udf_extend_file(inode, newsize);
|
||||
if (err) {
|
||||
up_write(&iinfo->i_data_sem);
|
||||
return err;
|
||||
}
|
||||
truncate_setsize(inode, newsize);
|
||||
up_write(&iinfo->i_data_sem);
|
||||
} else {
|
||||
block_truncate_page(inode->i_mapping, inode->i_size,
|
||||
udf_get_block);
|
||||
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
|
||||
down_write(&iinfo->i_data_sem);
|
||||
memset(iinfo->i_ext.i_data + iinfo->i_lenEAttr + newsize,
|
||||
0x00, bsize - newsize -
|
||||
udf_file_entry_alloc_offset(inode));
|
||||
iinfo->i_lenAlloc = newsize;
|
||||
truncate_setsize(inode, newsize);
|
||||
up_write(&iinfo->i_data_sem);
|
||||
goto update_time;
|
||||
}
|
||||
err = block_truncate_page(inode->i_mapping, newsize,
|
||||
udf_get_block);
|
||||
if (err)
|
||||
return err;
|
||||
down_write(&iinfo->i_data_sem);
|
||||
truncate_setsize(inode, newsize);
|
||||
udf_truncate_extents(inode);
|
||||
up_write(&iinfo->i_data_sem);
|
||||
}
|
||||
|
||||
update_time:
|
||||
inode->i_mtime = inode->i_ctime = current_fs_time(inode->i_sb);
|
||||
if (IS_SYNC(inode))
|
||||
udf_sync_inode(inode);
|
||||
else
|
||||
mark_inode_dirty(inode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __udf_read_inode(struct inode *inode)
|
||||
|
@ -1637,14 +1733,13 @@ struct inode *udf_iget(struct super_block *sb, struct kernel_lb_addr *ino)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,
|
||||
struct kernel_lb_addr *eloc, uint32_t elen, int inc)
|
||||
int udf_add_aext(struct inode *inode, struct extent_position *epos,
|
||||
struct kernel_lb_addr *eloc, uint32_t elen, int inc)
|
||||
{
|
||||
int adsize;
|
||||
struct short_ad *sad = NULL;
|
||||
struct long_ad *lad = NULL;
|
||||
struct allocExtDesc *aed;
|
||||
int8_t etype;
|
||||
uint8_t *ptr;
|
||||
struct udf_inode_info *iinfo = UDF_I(inode);
|
||||
|
||||
|
@ -1660,7 +1755,7 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,
|
|||
else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
|
||||
adsize = sizeof(struct long_ad);
|
||||
else
|
||||
return -1;
|
||||
return -EIO;
|
||||
|
||||
if (epos->offset + (2 * adsize) > inode->i_sb->s_blocksize) {
|
||||
unsigned char *sptr, *dptr;
|
||||
|
@ -1672,12 +1767,12 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,
|
|||
obloc.partitionReferenceNum,
|
||||
obloc.logicalBlockNum, &err);
|
||||
if (!epos->block.logicalBlockNum)
|
||||
return -1;
|
||||
return -ENOSPC;
|
||||
nbh = udf_tgetblk(inode->i_sb, udf_get_lb_pblock(inode->i_sb,
|
||||
&epos->block,
|
||||
0));
|
||||
if (!nbh)
|
||||
return -1;
|
||||
return -EIO;
|
||||
lock_buffer(nbh);
|
||||
memset(nbh->b_data, 0x00, inode->i_sb->s_blocksize);
|
||||
set_buffer_uptodate(nbh);
|
||||
|
@ -1746,7 +1841,7 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,
|
|||
epos->bh = nbh;
|
||||
}
|
||||
|
||||
etype = udf_write_aext(inode, epos, eloc, elen, inc);
|
||||
udf_write_aext(inode, epos, eloc, elen, inc);
|
||||
|
||||
if (!epos->bh) {
|
||||
iinfo->i_lenAlloc += adsize;
|
||||
|
@ -1764,11 +1859,11 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,
|
|||
mark_buffer_dirty_inode(epos->bh, inode);
|
||||
}
|
||||
|
||||
return etype;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int8_t udf_write_aext(struct inode *inode, struct extent_position *epos,
|
||||
struct kernel_lb_addr *eloc, uint32_t elen, int inc)
|
||||
void udf_write_aext(struct inode *inode, struct extent_position *epos,
|
||||
struct kernel_lb_addr *eloc, uint32_t elen, int inc)
|
||||
{
|
||||
int adsize;
|
||||
uint8_t *ptr;
|
||||
|
@ -1798,7 +1893,7 @@ int8_t udf_write_aext(struct inode *inode, struct extent_position *epos,
|
|||
adsize = sizeof(struct long_ad);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (epos->bh) {
|
||||
|
@ -1817,8 +1912,6 @@ int8_t udf_write_aext(struct inode *inode, struct extent_position *epos,
|
|||
|
||||
if (inc)
|
||||
epos->offset += adsize;
|
||||
|
||||
return (elen >> 30);
|
||||
}
|
||||
|
||||
int8_t udf_next_aext(struct inode *inode, struct extent_position *epos,
|
||||
|
|
|
@ -197,6 +197,11 @@ static void udf_update_alloc_ext_desc(struct inode *inode,
|
|||
mark_buffer_dirty_inode(epos->bh, inode);
|
||||
}
|
||||
|
||||
/*
|
||||
* Truncate extents of inode to inode->i_size. This function can be used only
|
||||
* for making file shorter. For making file longer, udf_extend_file() has to
|
||||
* be used.
|
||||
*/
|
||||
void udf_truncate_extents(struct inode *inode)
|
||||
{
|
||||
struct extent_position epos;
|
||||
|
@ -219,96 +224,65 @@ void udf_truncate_extents(struct inode *inode)
|
|||
etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset);
|
||||
byte_offset = (offset << sb->s_blocksize_bits) +
|
||||
(inode->i_size & (sb->s_blocksize - 1));
|
||||
if (etype != -1) {
|
||||
epos.offset -= adsize;
|
||||
extent_trunc(inode, &epos, &eloc, etype, elen, byte_offset);
|
||||
epos.offset += adsize;
|
||||
if (byte_offset)
|
||||
lenalloc = epos.offset;
|
||||
else
|
||||
lenalloc = epos.offset - adsize;
|
||||
if (etype == -1) {
|
||||
/* We should extend the file? */
|
||||
WARN_ON(byte_offset);
|
||||
return;
|
||||
}
|
||||
epos.offset -= adsize;
|
||||
extent_trunc(inode, &epos, &eloc, etype, elen, byte_offset);
|
||||
epos.offset += adsize;
|
||||
if (byte_offset)
|
||||
lenalloc = epos.offset;
|
||||
else
|
||||
lenalloc = epos.offset - adsize;
|
||||
|
||||
if (!epos.bh)
|
||||
lenalloc -= udf_file_entry_alloc_offset(inode);
|
||||
else
|
||||
lenalloc -= sizeof(struct allocExtDesc);
|
||||
if (!epos.bh)
|
||||
lenalloc -= udf_file_entry_alloc_offset(inode);
|
||||
else
|
||||
lenalloc -= sizeof(struct allocExtDesc);
|
||||
|
||||
while ((etype = udf_current_aext(inode, &epos, &eloc,
|
||||
&elen, 0)) != -1) {
|
||||
if (etype == (EXT_NEXT_EXTENT_ALLOCDECS >> 30)) {
|
||||
udf_write_aext(inode, &epos, &neloc, nelen, 0);
|
||||
if (indirect_ext_len) {
|
||||
/* We managed to free all extents in the
|
||||
* indirect extent - free it too */
|
||||
BUG_ON(!epos.bh);
|
||||
udf_free_blocks(sb, inode, &epos.block,
|
||||
0, indirect_ext_len);
|
||||
} else if (!epos.bh) {
|
||||
iinfo->i_lenAlloc = lenalloc;
|
||||
mark_inode_dirty(inode);
|
||||
} else
|
||||
udf_update_alloc_ext_desc(inode,
|
||||
&epos, lenalloc);
|
||||
brelse(epos.bh);
|
||||
epos.offset = sizeof(struct allocExtDesc);
|
||||
epos.block = eloc;
|
||||
epos.bh = udf_tread(sb,
|
||||
udf_get_lb_pblock(sb, &eloc, 0));
|
||||
if (elen)
|
||||
indirect_ext_len =
|
||||
(elen + sb->s_blocksize - 1) >>
|
||||
sb->s_blocksize_bits;
|
||||
else
|
||||
indirect_ext_len = 1;
|
||||
} else {
|
||||
extent_trunc(inode, &epos, &eloc, etype,
|
||||
elen, 0);
|
||||
epos.offset += adsize;
|
||||
}
|
||||
}
|
||||
|
||||
if (indirect_ext_len) {
|
||||
BUG_ON(!epos.bh);
|
||||
udf_free_blocks(sb, inode, &epos.block, 0,
|
||||
indirect_ext_len);
|
||||
} else if (!epos.bh) {
|
||||
iinfo->i_lenAlloc = lenalloc;
|
||||
mark_inode_dirty(inode);
|
||||
} else
|
||||
udf_update_alloc_ext_desc(inode, &epos, lenalloc);
|
||||
} else if (inode->i_size) {
|
||||
if (byte_offset) {
|
||||
struct kernel_long_ad extent;
|
||||
|
||||
/*
|
||||
* OK, there is not extent covering inode->i_size and
|
||||
* no extent above inode->i_size => truncate is
|
||||
* extending the file by 'offset' blocks.
|
||||
*/
|
||||
if ((!epos.bh &&
|
||||
epos.offset ==
|
||||
udf_file_entry_alloc_offset(inode)) ||
|
||||
(epos.bh && epos.offset ==
|
||||
sizeof(struct allocExtDesc))) {
|
||||
/* File has no extents at all or has empty last
|
||||
* indirect extent! Create a fake extent... */
|
||||
extent.extLocation.logicalBlockNum = 0;
|
||||
extent.extLocation.partitionReferenceNum = 0;
|
||||
extent.extLength =
|
||||
EXT_NOT_RECORDED_NOT_ALLOCATED;
|
||||
} else {
|
||||
epos.offset -= adsize;
|
||||
etype = udf_next_aext(inode, &epos,
|
||||
&extent.extLocation,
|
||||
&extent.extLength, 0);
|
||||
extent.extLength |= etype << 30;
|
||||
}
|
||||
udf_extend_file(inode, &epos, &extent,
|
||||
offset +
|
||||
((inode->i_size &
|
||||
(sb->s_blocksize - 1)) != 0));
|
||||
while ((etype = udf_current_aext(inode, &epos, &eloc,
|
||||
&elen, 0)) != -1) {
|
||||
if (etype == (EXT_NEXT_EXTENT_ALLOCDECS >> 30)) {
|
||||
udf_write_aext(inode, &epos, &neloc, nelen, 0);
|
||||
if (indirect_ext_len) {
|
||||
/* We managed to free all extents in the
|
||||
* indirect extent - free it too */
|
||||
BUG_ON(!epos.bh);
|
||||
udf_free_blocks(sb, inode, &epos.block,
|
||||
0, indirect_ext_len);
|
||||
} else if (!epos.bh) {
|
||||
iinfo->i_lenAlloc = lenalloc;
|
||||
mark_inode_dirty(inode);
|
||||
} else
|
||||
udf_update_alloc_ext_desc(inode,
|
||||
&epos, lenalloc);
|
||||
brelse(epos.bh);
|
||||
epos.offset = sizeof(struct allocExtDesc);
|
||||
epos.block = eloc;
|
||||
epos.bh = udf_tread(sb,
|
||||
udf_get_lb_pblock(sb, &eloc, 0));
|
||||
if (elen)
|
||||
indirect_ext_len =
|
||||
(elen + sb->s_blocksize - 1) >>
|
||||
sb->s_blocksize_bits;
|
||||
else
|
||||
indirect_ext_len = 1;
|
||||
} else {
|
||||
extent_trunc(inode, &epos, &eloc, etype, elen, 0);
|
||||
epos.offset += adsize;
|
||||
}
|
||||
}
|
||||
|
||||
if (indirect_ext_len) {
|
||||
BUG_ON(!epos.bh);
|
||||
udf_free_blocks(sb, inode, &epos.block, 0, indirect_ext_len);
|
||||
} else if (!epos.bh) {
|
||||
iinfo->i_lenAlloc = lenalloc;
|
||||
mark_inode_dirty(inode);
|
||||
} else
|
||||
udf_update_alloc_ext_desc(inode, &epos, lenalloc);
|
||||
iinfo->i_lenExtents = inode->i_size;
|
||||
|
||||
brelse(epos.bh);
|
||||
|
|
|
@ -136,22 +136,20 @@ extern int udf_write_fi(struct inode *inode, struct fileIdentDesc *,
|
|||
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 void udf_expand_file_adinicb(struct inode *, int, int *);
|
||||
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 *);
|
||||
extern void udf_truncate(struct inode *);
|
||||
extern int udf_setsize(struct inode *, loff_t);
|
||||
extern void udf_read_inode(struct inode *);
|
||||
extern void udf_evict_inode(struct inode *);
|
||||
extern int udf_write_inode(struct inode *, struct writeback_control *wbc);
|
||||
extern long udf_block_map(struct inode *, sector_t);
|
||||
extern int udf_extend_file(struct inode *, struct extent_position *,
|
||||
struct kernel_long_ad *, sector_t);
|
||||
extern int8_t inode_bmap(struct inode *, sector_t, struct extent_position *,
|
||||
struct kernel_lb_addr *, uint32_t *, sector_t *);
|
||||
extern int8_t 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);
|
||||
extern void udf_write_aext(struct inode *, struct extent_position *,
|
||||
struct kernel_lb_addr *, uint32_t, int);
|
||||
extern int8_t udf_write_aext(struct inode *, struct extent_position *,
|
||||
struct kernel_lb_addr *, uint32_t, int);
|
||||
extern int8_t udf_delete_aext(struct inode *, struct extent_position,
|
||||
struct kernel_lb_addr, uint32_t);
|
||||
extern int8_t udf_next_aext(struct inode *, struct extent_position *,
|
||||
|
|
Loading…
Reference in a new issue