提交 7e49b6f2 编写于 作者: J Jan Kara

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: NJan Kara <jack@suse.cz>
上级 4a508dd2
...@@ -123,8 +123,8 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov, ...@@ -123,8 +123,8 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
if (inode->i_sb->s_blocksize < if (inode->i_sb->s_blocksize <
(udf_file_entry_alloc_offset(inode) + (udf_file_entry_alloc_offset(inode) +
pos + count)) { pos + count)) {
udf_expand_file_adinicb(inode, pos + count, &err); err = udf_expand_file_adinicb(inode);
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { if (err) {
udf_debug("udf_expand_adinicb: err=%d\n", err); udf_debug("udf_expand_adinicb: err=%d\n", err);
up_write(&iinfo->i_data_sem); up_write(&iinfo->i_data_sem);
return err; return err;
...@@ -237,7 +237,7 @@ static int udf_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -237,7 +237,7 @@ static int udf_setattr(struct dentry *dentry, struct iattr *attr)
if ((attr->ia_valid & ATTR_SIZE) && if ((attr->ia_valid & ATTR_SIZE) &&
attr->ia_size != i_size_read(inode)) { attr->ia_size != i_size_read(inode)) {
error = vmtruncate(inode, attr->ia_size); error = udf_setsize(inode, attr->ia_size);
if (error) if (error)
return error; return error;
} }
...@@ -249,5 +249,4 @@ static int udf_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -249,5 +249,4 @@ static int udf_setattr(struct dentry *dentry, struct iattr *attr)
const struct inode_operations udf_file_inode_operations = { const struct inode_operations udf_file_inode_operations = {
.setattr = udf_setattr, .setattr = udf_setattr,
.truncate = udf_truncate,
}; };
...@@ -73,14 +73,12 @@ void udf_evict_inode(struct inode *inode) ...@@ -73,14 +73,12 @@ void udf_evict_inode(struct inode *inode)
struct udf_inode_info *iinfo = UDF_I(inode); struct udf_inode_info *iinfo = UDF_I(inode);
int want_delete = 0; int want_delete = 0;
truncate_inode_pages(&inode->i_data, 0);
if (!inode->i_nlink && !is_bad_inode(inode)) { if (!inode->i_nlink && !is_bad_inode(inode)) {
want_delete = 1; want_delete = 1;
inode->i_size = 0; udf_setsize(inode, 0);
udf_truncate(inode);
udf_update_inode(inode, IS_SYNC(inode)); udf_update_inode(inode, IS_SYNC(inode));
} } else
truncate_inode_pages(&inode->i_data, 0);
invalidate_inode_buffers(inode); invalidate_inode_buffers(inode);
end_writeback(inode); end_writeback(inode);
if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB && 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, ...@@ -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); ret = block_write_begin(mapping, pos, len, flags, pagep, udf_get_block);
if (unlikely(ret)) { if (unlikely(ret)) {
loff_t isize = mapping->host->i_size; struct inode *inode = mapping->host;
if (pos + len > isize) struct udf_inode_info *iinfo = UDF_I(inode);
vmtruncate(mapping->host, isize); 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; return ret;
...@@ -139,30 +146,31 @@ const struct address_space_operations udf_aops = { ...@@ -139,30 +146,31 @@ const struct address_space_operations udf_aops = {
.bmap = udf_bmap, .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; struct page *page;
char *kaddr; char *kaddr;
struct udf_inode_info *iinfo = UDF_I(inode); struct udf_inode_info *iinfo = UDF_I(inode);
int err;
struct writeback_control udf_wbc = { struct writeback_control udf_wbc = {
.sync_mode = WB_SYNC_NONE, .sync_mode = WB_SYNC_NONE,
.nr_to_write = 1, .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 (!iinfo->i_lenAlloc) {
if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD)) if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD))
iinfo->i_alloc_type = ICBTAG_FLAG_AD_SHORT; iinfo->i_alloc_type = ICBTAG_FLAG_AD_SHORT;
else else
iinfo->i_alloc_type = ICBTAG_FLAG_AD_LONG; 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); mark_inode_dirty(inode);
return; return 0;
} }
page = grab_cache_page(inode->i_mapping, 0); page = find_or_create_page(inode->i_mapping, 0, GFP_NOFS);
BUG_ON(!PageLocked(page)); if (!page)
return -ENOMEM;
if (!PageUptodate(page)) { if (!PageUptodate(page)) {
kaddr = kmap(page); kaddr = kmap(page);
...@@ -181,11 +189,24 @@ void udf_expand_file_adinicb(struct inode *inode, int newsize, int *err) ...@@ -181,11 +189,24 @@ void udf_expand_file_adinicb(struct inode *inode, int newsize, int *err)
iinfo->i_alloc_type = ICBTAG_FLAG_AD_SHORT; iinfo->i_alloc_type = ICBTAG_FLAG_AD_SHORT;
else else
iinfo->i_alloc_type = ICBTAG_FLAG_AD_LONG; iinfo->i_alloc_type = ICBTAG_FLAG_AD_LONG;
/* from now on we have normal address_space methods */
inode->i_data.a_ops->writepage(page, &udf_wbc); 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); page_cache_release(page);
mark_inode_dirty(inode); mark_inode_dirty(inode);
return err;
} }
struct buffer_head *udf_expand_dir_adinicb(struct inode *inode, int *block, 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, ...@@ -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 */ /* Extend the file by 'blocks' blocks, return the number of extents added */
int udf_extend_file(struct inode *inode, struct extent_position *last_pos, static int udf_do_extend_file(struct inode *inode,
struct kernel_long_ad *last_ext, sector_t blocks) struct extent_position *last_pos,
struct kernel_long_ad *last_ext,
sector_t blocks)
{ {
sector_t add; sector_t add;
int count = 0, fake = !(last_ext->extLength & UDF_EXTENT_LENGTH_MASK); 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, ...@@ -357,6 +380,7 @@ int udf_extend_file(struct inode *inode, struct extent_position *last_pos,
struct kernel_lb_addr prealloc_loc = {}; struct kernel_lb_addr prealloc_loc = {};
int prealloc_len = 0; int prealloc_len = 0;
struct udf_inode_info *iinfo; struct udf_inode_info *iinfo;
int err;
/* The previous extent is fake and we should not extend by anything /* The previous extent is fake and we should not extend by anything
* - there's nothing to do... */ * - there's nothing to do... */
...@@ -422,26 +446,29 @@ int udf_extend_file(struct inode *inode, struct extent_position *last_pos, ...@@ -422,26 +446,29 @@ int udf_extend_file(struct inode *inode, struct extent_position *last_pos,
/* Create enough extents to cover the whole hole */ /* Create enough extents to cover the whole hole */
while (blocks > add) { while (blocks > add) {
blocks -= add; blocks -= add;
if (udf_add_aext(inode, last_pos, &last_ext->extLocation, err = udf_add_aext(inode, last_pos, &last_ext->extLocation,
last_ext->extLength, 1) == -1) last_ext->extLength, 1);
return -1; if (err)
return err;
count++; count++;
} }
if (blocks) { if (blocks) {
last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED | last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
(blocks << sb->s_blocksize_bits); (blocks << sb->s_blocksize_bits);
if (udf_add_aext(inode, last_pos, &last_ext->extLocation, err = udf_add_aext(inode, last_pos, &last_ext->extLocation,
last_ext->extLength, 1) == -1) last_ext->extLength, 1);
return -1; if (err)
return err;
count++; count++;
} }
out: out:
/* Do we have some preallocated blocks saved? */ /* Do we have some preallocated blocks saved? */
if (prealloc_len) { if (prealloc_len) {
if (udf_add_aext(inode, last_pos, &prealloc_loc, err = udf_add_aext(inode, last_pos, &prealloc_loc,
prealloc_len, 1) == -1) prealloc_len, 1);
return -1; if (err)
return err;
last_ext->extLocation = prealloc_loc; last_ext->extLocation = prealloc_loc;
last_ext->extLength = prealloc_len; last_ext->extLength = prealloc_len;
count++; count++;
...@@ -453,11 +480,68 @@ int udf_extend_file(struct inode *inode, struct extent_position *last_pos, ...@@ -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) else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
last_pos->offset -= sizeof(struct long_ad); last_pos->offset -= sizeof(struct long_ad);
else else
return -1; return -EIO;
return count; 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, static struct buffer_head *inode_getblk(struct inode *inode, sector_t block,
int *err, sector_t *phys, int *new) int *err, sector_t *phys, int *new)
{ {
...@@ -540,7 +624,7 @@ static struct buffer_head *inode_getblk(struct inode *inode, sector_t block, ...@@ -540,7 +624,7 @@ static struct buffer_head *inode_getblk(struct inode *inode, sector_t block,
elen = EXT_RECORDED_ALLOCATED | elen = EXT_RECORDED_ALLOCATED |
((elen + inode->i_sb->s_blocksize - 1) & ((elen + inode->i_sb->s_blocksize - 1) &
~(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(prev_epos.bh);
brelse(cur_epos.bh); brelse(cur_epos.bh);
...@@ -564,19 +648,17 @@ static struct buffer_head *inode_getblk(struct inode *inode, sector_t block, ...@@ -564,19 +648,17 @@ static struct buffer_head *inode_getblk(struct inode *inode, sector_t block,
memset(&laarr[0].extLocation, 0x00, memset(&laarr[0].extLocation, 0x00,
sizeof(struct kernel_lb_addr)); sizeof(struct kernel_lb_addr));
laarr[0].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED; 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? */ a fake one? */
startnum = (offset > 0); startnum = (offset > 0);
} }
/* Create extents for the hole between EOF and offset */ /* Create extents for the hole between EOF and offset */
ret = udf_extend_file(inode, &prev_epos, laarr, offset); ret = udf_do_extend_file(inode, &prev_epos, laarr, offset);
if (ret == -1) { if (ret < 0) {
brelse(prev_epos.bh); brelse(prev_epos.bh);
brelse(cur_epos.bh); brelse(cur_epos.bh);
brelse(next_epos.bh); brelse(next_epos.bh);
/* We don't really know the error here so we just make *err = ret;
* something up */
*err = -ENOSPC;
return NULL; return NULL;
} }
c = 0; c = 0;
...@@ -1005,52 +1087,66 @@ struct buffer_head *udf_bread(struct inode *inode, int block, ...@@ -1005,52 +1087,66 @@ struct buffer_head *udf_bread(struct inode *inode, int block,
return NULL; return NULL;
} }
void udf_truncate(struct inode *inode) int udf_setsize(struct inode *inode, loff_t newsize)
{ {
int offset;
int err; int err;
struct udf_inode_info *iinfo; struct udf_inode_info *iinfo;
int bsize = 1 << inode->i_blkbits;
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
S_ISLNK(inode->i_mode))) S_ISLNK(inode->i_mode)))
return; return -EINVAL;
if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
return; return -EPERM;
iinfo = UDF_I(inode); 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); down_write(&iinfo->i_data_sem);
if (inode->i_sb->s_blocksize < if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
(udf_file_entry_alloc_offset(inode) + if (bsize <
inode->i_size)) { (udf_file_entry_alloc_offset(inode) + newsize)) {
udf_expand_file_adinicb(inode, inode->i_size, &err); err = udf_expand_file_adinicb(inode);
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { if (err) {
inode->i_size = iinfo->i_lenAlloc; up_write(&iinfo->i_data_sem);
up_write(&iinfo->i_data_sem); return err;
return; }
} else } else
udf_truncate_extents(inode); iinfo->i_lenAlloc = newsize;
} else { }
offset = inode->i_size & (inode->i_sb->s_blocksize - 1); err = udf_extend_file(inode, newsize);
memset(iinfo->i_ext.i_data + iinfo->i_lenEAttr + offset, if (err) {
0x00, inode->i_sb->s_blocksize - up_write(&iinfo->i_data_sem);
offset - udf_file_entry_alloc_offset(inode)); return err;
iinfo->i_lenAlloc = inode->i_size;
} }
truncate_setsize(inode, newsize);
up_write(&iinfo->i_data_sem); up_write(&iinfo->i_data_sem);
} else { } else {
block_truncate_page(inode->i_mapping, inode->i_size, if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
udf_get_block); 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); down_write(&iinfo->i_data_sem);
truncate_setsize(inode, newsize);
udf_truncate_extents(inode); udf_truncate_extents(inode);
up_write(&iinfo->i_data_sem); up_write(&iinfo->i_data_sem);
} }
update_time:
inode->i_mtime = inode->i_ctime = current_fs_time(inode->i_sb); inode->i_mtime = inode->i_ctime = current_fs_time(inode->i_sb);
if (IS_SYNC(inode)) if (IS_SYNC(inode))
udf_sync_inode(inode); udf_sync_inode(inode);
else else
mark_inode_dirty(inode); mark_inode_dirty(inode);
return 0;
} }
static void __udf_read_inode(struct inode *inode) 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) ...@@ -1637,14 +1733,13 @@ struct inode *udf_iget(struct super_block *sb, struct kernel_lb_addr *ino)
return NULL; return NULL;
} }
int8_t udf_add_aext(struct inode *inode, struct extent_position *epos, int udf_add_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)
{ {
int adsize; int adsize;
struct short_ad *sad = NULL; struct short_ad *sad = NULL;
struct long_ad *lad = NULL; struct long_ad *lad = NULL;
struct allocExtDesc *aed; struct allocExtDesc *aed;
int8_t etype;
uint8_t *ptr; uint8_t *ptr;
struct udf_inode_info *iinfo = UDF_I(inode); struct udf_inode_info *iinfo = UDF_I(inode);
...@@ -1660,7 +1755,7 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos, ...@@ -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) else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
adsize = sizeof(struct long_ad); adsize = sizeof(struct long_ad);
else else
return -1; return -EIO;
if (epos->offset + (2 * adsize) > inode->i_sb->s_blocksize) { if (epos->offset + (2 * adsize) > inode->i_sb->s_blocksize) {
unsigned char *sptr, *dptr; unsigned char *sptr, *dptr;
...@@ -1672,12 +1767,12 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos, ...@@ -1672,12 +1767,12 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,
obloc.partitionReferenceNum, obloc.partitionReferenceNum,
obloc.logicalBlockNum, &err); obloc.logicalBlockNum, &err);
if (!epos->block.logicalBlockNum) if (!epos->block.logicalBlockNum)
return -1; return -ENOSPC;
nbh = udf_tgetblk(inode->i_sb, udf_get_lb_pblock(inode->i_sb, nbh = udf_tgetblk(inode->i_sb, udf_get_lb_pblock(inode->i_sb,
&epos->block, &epos->block,
0)); 0));
if (!nbh) if (!nbh)
return -1; return -EIO;
lock_buffer(nbh); lock_buffer(nbh);
memset(nbh->b_data, 0x00, inode->i_sb->s_blocksize); memset(nbh->b_data, 0x00, inode->i_sb->s_blocksize);
set_buffer_uptodate(nbh); set_buffer_uptodate(nbh);
...@@ -1746,7 +1841,7 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos, ...@@ -1746,7 +1841,7 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,
epos->bh = nbh; epos->bh = nbh;
} }
etype = udf_write_aext(inode, epos, eloc, elen, inc); udf_write_aext(inode, epos, eloc, elen, inc);
if (!epos->bh) { if (!epos->bh) {
iinfo->i_lenAlloc += adsize; iinfo->i_lenAlloc += adsize;
...@@ -1764,11 +1859,11 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos, ...@@ -1764,11 +1859,11 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,
mark_buffer_dirty_inode(epos->bh, inode); mark_buffer_dirty_inode(epos->bh, inode);
} }
return etype; return 0;
} }
int8_t 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)
{ {
int adsize; int adsize;
uint8_t *ptr; uint8_t *ptr;
...@@ -1798,7 +1893,7 @@ int8_t udf_write_aext(struct inode *inode, struct extent_position *epos, ...@@ -1798,7 +1893,7 @@ int8_t udf_write_aext(struct inode *inode, struct extent_position *epos,
adsize = sizeof(struct long_ad); adsize = sizeof(struct long_ad);
break; break;
default: default:
return -1; return;
} }
if (epos->bh) { if (epos->bh) {
...@@ -1817,8 +1912,6 @@ int8_t udf_write_aext(struct inode *inode, struct extent_position *epos, ...@@ -1817,8 +1912,6 @@ int8_t udf_write_aext(struct inode *inode, struct extent_position *epos,
if (inc) if (inc)
epos->offset += adsize; epos->offset += adsize;
return (elen >> 30);
} }
int8_t udf_next_aext(struct inode *inode, struct extent_position *epos, 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, ...@@ -197,6 +197,11 @@ static void udf_update_alloc_ext_desc(struct inode *inode,
mark_buffer_dirty_inode(epos->bh, 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) void udf_truncate_extents(struct inode *inode)
{ {
struct extent_position epos; struct extent_position epos;
...@@ -219,96 +224,65 @@ void udf_truncate_extents(struct inode *inode) ...@@ -219,96 +224,65 @@ void udf_truncate_extents(struct inode *inode)
etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset); etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset);
byte_offset = (offset << sb->s_blocksize_bits) + byte_offset = (offset << sb->s_blocksize_bits) +
(inode->i_size & (sb->s_blocksize - 1)); (inode->i_size & (sb->s_blocksize - 1));
if (etype != -1) { if (etype == -1) {
epos.offset -= adsize; /* We should extend the file? */
extent_trunc(inode, &epos, &eloc, etype, elen, byte_offset); WARN_ON(byte_offset);
epos.offset += adsize; return;
if (byte_offset) }
lenalloc = epos.offset; epos.offset -= adsize;
else extent_trunc(inode, &epos, &eloc, etype, elen, byte_offset);
lenalloc = epos.offset - adsize; epos.offset += adsize;
if (byte_offset)
if (!epos.bh) lenalloc = epos.offset;
lenalloc -= udf_file_entry_alloc_offset(inode); else
else lenalloc = epos.offset - adsize;
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) { if (!epos.bh)
BUG_ON(!epos.bh); lenalloc -= udf_file_entry_alloc_offset(inode);
udf_free_blocks(sb, inode, &epos.block, 0, else
indirect_ext_len); lenalloc -= sizeof(struct allocExtDesc);
} 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;
/* while ((etype = udf_current_aext(inode, &epos, &eloc,
* OK, there is not extent covering inode->i_size and &elen, 0)) != -1) {
* no extent above inode->i_size => truncate is if (etype == (EXT_NEXT_EXTENT_ALLOCDECS >> 30)) {
* extending the file by 'offset' blocks. udf_write_aext(inode, &epos, &neloc, nelen, 0);
*/ if (indirect_ext_len) {
if ((!epos.bh && /* We managed to free all extents in the
epos.offset == * indirect extent - free it too */
udf_file_entry_alloc_offset(inode)) || BUG_ON(!epos.bh);
(epos.bh && epos.offset == udf_free_blocks(sb, inode, &epos.block,
sizeof(struct allocExtDesc))) { 0, indirect_ext_len);
/* File has no extents at all or has empty last } else if (!epos.bh) {
* indirect extent! Create a fake extent... */ iinfo->i_lenAlloc = lenalloc;
extent.extLocation.logicalBlockNum = 0; mark_inode_dirty(inode);
extent.extLocation.partitionReferenceNum = 0; } else
extent.extLength = udf_update_alloc_ext_desc(inode,
EXT_NOT_RECORDED_NOT_ALLOCATED; &epos, lenalloc);
} else { brelse(epos.bh);
epos.offset -= adsize; epos.offset = sizeof(struct allocExtDesc);
etype = udf_next_aext(inode, &epos, epos.block = eloc;
&extent.extLocation, epos.bh = udf_tread(sb,
&extent.extLength, 0); udf_get_lb_pblock(sb, &eloc, 0));
extent.extLength |= etype << 30; if (elen)
} indirect_ext_len =
udf_extend_file(inode, &epos, &extent, (elen + sb->s_blocksize - 1) >>
offset + sb->s_blocksize_bits;
((inode->i_size & else
(sb->s_blocksize - 1)) != 0)); 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; iinfo->i_lenExtents = inode->i_size;
brelse(epos.bh); brelse(epos.bh);
......
...@@ -136,22 +136,20 @@ extern int udf_write_fi(struct inode *inode, struct fileIdentDesc *, ...@@ -136,22 +136,20 @@ extern int udf_write_fi(struct inode *inode, struct fileIdentDesc *,
extern long udf_ioctl(struct file *, unsigned int, unsigned long); extern long udf_ioctl(struct file *, unsigned int, unsigned long);
/* inode.c */ /* 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 *);
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_expand_dir_adinicb(struct inode *, int *, int *);
extern struct buffer_head *udf_bread(struct inode *, int, 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_read_inode(struct inode *);
extern void udf_evict_inode(struct inode *); extern void udf_evict_inode(struct inode *);
extern int udf_write_inode(struct inode *, struct writeback_control *wbc); 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 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 *, 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 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); 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, extern int8_t udf_delete_aext(struct inode *, struct extent_position,
struct kernel_lb_addr, uint32_t); struct kernel_lb_addr, uint32_t);
extern int8_t udf_next_aext(struct inode *, struct extent_position *, extern int8_t udf_next_aext(struct inode *, struct extent_position *,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册