Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932553AbbGGSGa (ORCPT ); Tue, 7 Jul 2015 14:06:30 -0400 Received: from mail-ig0-f182.google.com ([209.85.213.182]:33311 "EHLO mail-ig0-f182.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932315AbbGGSGW (ORCPT ); Tue, 7 Jul 2015 14:06:22 -0400 From: "Steven J. Magnani" X-Google-Original-From: "Steven J. Magnani" To: jack@suse.cz Cc: linux-kernel@vger.kernel.org, "Steven J. Magnani" Subject: [PATCH] udf: Don't corrupt unalloc spacetable when writing it Date: Tue, 7 Jul 2015 13:06:05 -0500 Message-Id: <1436292365-4395-1-git-send-email-steve@digidescorp.com> X-Mailer: git-send-email 1.9.1 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 3097 Lines: 89 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 --- diff -uprN a/fs/udf/inode.c b/fs/udf/inode.c --- a/fs/udf/inode.c 2015-07-06 13:42:08.861499890 -0500 +++ b/fs/udf/inode.c 2015-07-06 13:42:18.153499469 -0500 @@ -1652,17 +1652,9 @@ static int udf_update_inode(struct inode iinfo->i_ext.i_data, inode->i_sb->s_blocksize - sizeof(struct unallocSpaceEntry)); use->descTag.tagIdent = cpu_to_le16(TAG_IDENT_USE); - use->descTag.tagLocation = - cpu_to_le32(iinfo->i_location.logicalBlockNum); - crclen = sizeof(struct unallocSpaceEntry) + - iinfo->i_lenAlloc - sizeof(struct tag); - use->descTag.descCRCLength = cpu_to_le16(crclen); - use->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)use + - sizeof(struct tag), - crclen)); - use->descTag.tagChecksum = udf_tag_checksum(&use->descTag); + crclen = sizeof(struct unallocSpaceEntry); - goto out; + goto finish; } if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_UID_FORGET)) @@ -1782,6 +1774,8 @@ static int udf_update_inode(struct inode efe->descTag.tagIdent = cpu_to_le16(TAG_IDENT_EFE); crclen = sizeof(struct extendedFileEntry); } + +finish: if (iinfo->i_strat4096) { fe->icbTag.strategyType = cpu_to_le16(4096); fe->icbTag.strategyParameter = cpu_to_le16(1); @@ -1791,7 +1785,9 @@ static int udf_update_inode(struct inode fe->icbTag.numEntries = cpu_to_le16(1); } - if (S_ISDIR(inode->i_mode)) + if (iinfo->i_use) + fe->icbTag.fileType = ICBTAG_FILE_TYPE_USE; + else if (S_ISDIR(inode->i_mode)) fe->icbTag.fileType = ICBTAG_FILE_TYPE_DIRECTORY; else if (S_ISREG(inode->i_mode)) fe->icbTag.fileType = ICBTAG_FILE_TYPE_REGULAR; @@ -1828,7 +1824,6 @@ static int udf_update_inode(struct inode crclen)); fe->descTag.tagChecksum = udf_tag_checksum(&fe->descTag); -out: set_buffer_uptodate(bh); unlock_buffer(bh); -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/