diff options
author | Jan Kara <jack@suse.cz> | 2010-01-08 10:46:29 -0500 |
---|---|---|
committer | Jan Kara <jack@suse.cz> | 2010-03-09 11:15:17 -0500 |
commit | aae917cd188f397e9223001d9f6c0adfb339fd64 (patch) | |
tree | 7185f5f0b984145c1511ae657487e68504f185a7 /fs | |
parent | 57d54889cd00db2752994b389ba714138652e60c (diff) |
udf: Fix unalloc space handling in udf_update_inode
Writing of inode holding unallocated space info was broken because we first
cleared the buffer and after that checked whether it contains a tag meaning the
block holds unallocated space information. Fix the problem by checking
appropriate in memory flag instead.
Also cleanup the function a bit along the way - most importantly lock buffer
when modifying its contents, check for buffer_write_io_error instead of
!buffer_uptodate, etc..
Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/udf/inode.c | 28 |
1 files changed, 14 insertions, 14 deletions
diff --git a/fs/udf/inode.c b/fs/udf/inode.c index b57ab0402d89..a792a884b49c 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c | |||
@@ -1412,16 +1412,16 @@ static int udf_update_inode(struct inode *inode, int do_sync) | |||
1412 | udf_get_lb_pblock(inode->i_sb, | 1412 | udf_get_lb_pblock(inode->i_sb, |
1413 | &iinfo->i_location, 0)); | 1413 | &iinfo->i_location, 0)); |
1414 | if (!bh) { | 1414 | if (!bh) { |
1415 | udf_debug("bread failure\n"); | 1415 | udf_debug("getblk failure\n"); |
1416 | return -EIO; | 1416 | return -ENOMEM; |
1417 | } | 1417 | } |
1418 | 1418 | ||
1419 | memset(bh->b_data, 0x00, inode->i_sb->s_blocksize); | 1419 | lock_buffer(bh); |
1420 | 1420 | memset(bh->b_data, 0, inode->i_sb->s_blocksize); | |
1421 | fe = (struct fileEntry *)bh->b_data; | 1421 | fe = (struct fileEntry *)bh->b_data; |
1422 | efe = (struct extendedFileEntry *)bh->b_data; | 1422 | efe = (struct extendedFileEntry *)bh->b_data; |
1423 | 1423 | ||
1424 | if (fe->descTag.tagIdent == cpu_to_le16(TAG_IDENT_USE)) { | 1424 | if (iinfo->i_use) { |
1425 | struct unallocSpaceEntry *use = | 1425 | struct unallocSpaceEntry *use = |
1426 | (struct unallocSpaceEntry *)bh->b_data; | 1426 | (struct unallocSpaceEntry *)bh->b_data; |
1427 | 1427 | ||
@@ -1429,20 +1429,18 @@ static int udf_update_inode(struct inode *inode, int do_sync) | |||
1429 | memcpy(bh->b_data + sizeof(struct unallocSpaceEntry), | 1429 | memcpy(bh->b_data + sizeof(struct unallocSpaceEntry), |
1430 | iinfo->i_ext.i_data, inode->i_sb->s_blocksize - | 1430 | iinfo->i_ext.i_data, inode->i_sb->s_blocksize - |
1431 | sizeof(struct unallocSpaceEntry)); | 1431 | sizeof(struct unallocSpaceEntry)); |
1432 | use->descTag.tagIdent = cpu_to_le16(TAG_IDENT_USE); | ||
1433 | use->descTag.tagLocation = | ||
1434 | cpu_to_le32(iinfo->i_location.logicalBlockNum); | ||
1432 | crclen = sizeof(struct unallocSpaceEntry) + | 1435 | crclen = sizeof(struct unallocSpaceEntry) + |
1433 | iinfo->i_lenAlloc - sizeof(struct tag); | 1436 | iinfo->i_lenAlloc - sizeof(struct tag); |
1434 | use->descTag.tagLocation = cpu_to_le32( | ||
1435 | iinfo->i_location. | ||
1436 | logicalBlockNum); | ||
1437 | use->descTag.descCRCLength = cpu_to_le16(crclen); | 1437 | use->descTag.descCRCLength = cpu_to_le16(crclen); |
1438 | use->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)use + | 1438 | use->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)use + |
1439 | sizeof(struct tag), | 1439 | sizeof(struct tag), |
1440 | crclen)); | 1440 | crclen)); |
1441 | use->descTag.tagChecksum = udf_tag_checksum(&use->descTag); | 1441 | use->descTag.tagChecksum = udf_tag_checksum(&use->descTag); |
1442 | 1442 | ||
1443 | mark_buffer_dirty(bh); | 1443 | goto out; |
1444 | brelse(bh); | ||
1445 | return err; | ||
1446 | } | 1444 | } |
1447 | 1445 | ||
1448 | if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_UID_FORGET)) | 1446 | if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_UID_FORGET)) |
@@ -1597,18 +1595,20 @@ static int udf_update_inode(struct inode *inode, int do_sync) | |||
1597 | fe->descTag.tagSerialNum = cpu_to_le16(sbi->s_serial_number); | 1595 | fe->descTag.tagSerialNum = cpu_to_le16(sbi->s_serial_number); |
1598 | fe->descTag.tagLocation = cpu_to_le32( | 1596 | fe->descTag.tagLocation = cpu_to_le32( |
1599 | iinfo->i_location.logicalBlockNum); | 1597 | iinfo->i_location.logicalBlockNum); |
1600 | crclen += iinfo->i_lenEAttr + iinfo->i_lenAlloc - | 1598 | crclen += iinfo->i_lenEAttr + iinfo->i_lenAlloc - sizeof(struct tag); |
1601 | sizeof(struct tag); | ||
1602 | fe->descTag.descCRCLength = cpu_to_le16(crclen); | 1599 | fe->descTag.descCRCLength = cpu_to_le16(crclen); |
1603 | fe->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)fe + sizeof(struct tag), | 1600 | fe->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)fe + sizeof(struct tag), |
1604 | crclen)); | 1601 | crclen)); |
1605 | fe->descTag.tagChecksum = udf_tag_checksum(&fe->descTag); | 1602 | fe->descTag.tagChecksum = udf_tag_checksum(&fe->descTag); |
1606 | 1603 | ||
1604 | out: | ||
1605 | unlock_buffer(bh); | ||
1606 | |||
1607 | /* write the data blocks */ | 1607 | /* write the data blocks */ |
1608 | mark_buffer_dirty(bh); | 1608 | mark_buffer_dirty(bh); |
1609 | if (do_sync) { | 1609 | if (do_sync) { |
1610 | sync_dirty_buffer(bh); | 1610 | sync_dirty_buffer(bh); |
1611 | if (buffer_req(bh) && !buffer_uptodate(bh)) { | 1611 | if (buffer_write_io_error(bh)) { |
1612 | printk(KERN_WARNING "IO error syncing udf inode " | 1612 | printk(KERN_WARNING "IO error syncing udf inode " |
1613 | "[%s:%08lx]\n", inode->i_sb->s_id, | 1613 | "[%s:%08lx]\n", inode->i_sb->s_id, |
1614 | inode->i_ino); | 1614 | inode->i_ino); |