diff options
author | Steven J. Magnani <steve.magnani@digidescorp.com> | 2015-07-07 14:06:05 -0400 |
---|---|---|
committer | Jan Kara <jack@suse.com> | 2015-07-09 10:38:57 -0400 |
commit | 70f19f5869c5accfd9f371c099f21c71516591b2 (patch) | |
tree | 8d2cdfd87f32a18b168a9f7c511e8b0f32b05467 /fs/udf | |
parent | 45820c294fe1b1a9df495d57f40585ef2d069a39 (diff) |
udf: Don't corrupt unalloc spacetable when writing it
For a UDF filesystem configured with an Unallocated Space Table,
a filesystem operation that triggers an update to the table results
in on-disk corruption that prevents remounting:
udf_read_tagged: tag version 0x0000 != 0x0002 || 0x0003, block 274
For example:
1. Create a filesystem
$ mkudffs --media-type=hd --blocksize=512 --lvid=BUGTEST \
--vid=BUGTEST --fsid=BUGTEST --space=unalloctable \
/dev/mmcblk0
2. Mount it
# mount /dev/mmcblk0 /mnt
3. Create a file
$ echo "No corruption, please" > /mnt/new.file
4. Umount
# umount /mnt
5. Attempt remount
# mount /dev/mmcblk0 /mnt
This appears to be a longstanding bug caused by zero-initialization of
the Unallocated Space Entry block buffer and only partial repopulation
of required fields before writing to disk.
Commit 0adfb339fd64 ("udf: Fix unalloc space handling in udf_update_inode")
addressed one such field, but several others are required.
Signed-off-by: Steven J. Magnani <steve@digidescorp.com>
Signed-off-by: Jan Kara <jack@suse.com>
Diffstat (limited to 'fs/udf')
-rw-r--r-- | fs/udf/inode.c | 19 |
1 files changed, 7 insertions, 12 deletions
diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 6afac3d561ac..8d0b3ade0ff0 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c | |||
@@ -1652,17 +1652,9 @@ static int udf_update_inode(struct inode *inode, int do_sync) | |||
1652 | iinfo->i_ext.i_data, inode->i_sb->s_blocksize - | 1652 | iinfo->i_ext.i_data, inode->i_sb->s_blocksize - |
1653 | sizeof(struct unallocSpaceEntry)); | 1653 | sizeof(struct unallocSpaceEntry)); |
1654 | use->descTag.tagIdent = cpu_to_le16(TAG_IDENT_USE); | 1654 | use->descTag.tagIdent = cpu_to_le16(TAG_IDENT_USE); |
1655 | use->descTag.tagLocation = | 1655 | crclen = sizeof(struct unallocSpaceEntry); |
1656 | cpu_to_le32(iinfo->i_location.logicalBlockNum); | ||
1657 | crclen = sizeof(struct unallocSpaceEntry) + | ||
1658 | iinfo->i_lenAlloc - sizeof(struct tag); | ||
1659 | use->descTag.descCRCLength = cpu_to_le16(crclen); | ||
1660 | use->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)use + | ||
1661 | sizeof(struct tag), | ||
1662 | crclen)); | ||
1663 | use->descTag.tagChecksum = udf_tag_checksum(&use->descTag); | ||
1664 | 1656 | ||
1665 | goto out; | 1657 | goto finish; |
1666 | } | 1658 | } |
1667 | 1659 | ||
1668 | if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_UID_FORGET)) | 1660 | if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_UID_FORGET)) |
@@ -1782,6 +1774,8 @@ static int udf_update_inode(struct inode *inode, int do_sync) | |||
1782 | efe->descTag.tagIdent = cpu_to_le16(TAG_IDENT_EFE); | 1774 | efe->descTag.tagIdent = cpu_to_le16(TAG_IDENT_EFE); |
1783 | crclen = sizeof(struct extendedFileEntry); | 1775 | crclen = sizeof(struct extendedFileEntry); |
1784 | } | 1776 | } |
1777 | |||
1778 | finish: | ||
1785 | if (iinfo->i_strat4096) { | 1779 | if (iinfo->i_strat4096) { |
1786 | fe->icbTag.strategyType = cpu_to_le16(4096); | 1780 | fe->icbTag.strategyType = cpu_to_le16(4096); |
1787 | fe->icbTag.strategyParameter = cpu_to_le16(1); | 1781 | fe->icbTag.strategyParameter = cpu_to_le16(1); |
@@ -1791,7 +1785,9 @@ static int udf_update_inode(struct inode *inode, int do_sync) | |||
1791 | fe->icbTag.numEntries = cpu_to_le16(1); | 1785 | fe->icbTag.numEntries = cpu_to_le16(1); |
1792 | } | 1786 | } |
1793 | 1787 | ||
1794 | if (S_ISDIR(inode->i_mode)) | 1788 | if (iinfo->i_use) |
1789 | fe->icbTag.fileType = ICBTAG_FILE_TYPE_USE; | ||
1790 | else if (S_ISDIR(inode->i_mode)) | ||
1795 | fe->icbTag.fileType = ICBTAG_FILE_TYPE_DIRECTORY; | 1791 | fe->icbTag.fileType = ICBTAG_FILE_TYPE_DIRECTORY; |
1796 | else if (S_ISREG(inode->i_mode)) | 1792 | else if (S_ISREG(inode->i_mode)) |
1797 | fe->icbTag.fileType = ICBTAG_FILE_TYPE_REGULAR; | 1793 | fe->icbTag.fileType = ICBTAG_FILE_TYPE_REGULAR; |
@@ -1828,7 +1824,6 @@ static int udf_update_inode(struct inode *inode, int do_sync) | |||
1828 | crclen)); | 1824 | crclen)); |
1829 | fe->descTag.tagChecksum = udf_tag_checksum(&fe->descTag); | 1825 | fe->descTag.tagChecksum = udf_tag_checksum(&fe->descTag); |
1830 | 1826 | ||
1831 | out: | ||
1832 | set_buffer_uptodate(bh); | 1827 | set_buffer_uptodate(bh); |
1833 | unlock_buffer(bh); | 1828 | unlock_buffer(bh); |
1834 | 1829 | ||