mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Rich Coe <Richard.Coe@med.ge.com>
To: torvalds@osdl.org, jack@suse.cz
Cc: linux-kernel@vger.kernel.org
Subject: PATCH: udf fs corruption on linux-2.6
Date: Wed, 13 Jun 2007 15:48:03 -0500	[thread overview]
Message-ID: <20070613154803.a1ad874a.Richard.Coe@med.ge.com> (raw)

Hi Linus, 

This patch fixes directory and missing files corruption in fs/udf which
occurs on all known 2.6 releases.

The corruption occurs because blocks which were pre-alloc'd for a directory 
are released back to the fs freelist, but the inode's alloc block information
is not updated to reflect this.

You would not see corruption if the number of files in any directory is 
less than 41, because the pre-alloc routine does not allocate blocks for the
directory until the number of files is over 40.

The problem occurs during unmounting because fs/udf incorrectly calls 
udf_discard_prealloc() from udf_clear_inode().  udf_discard_prealloc() will
update the inode and schedule it for write, but no write will ever occur 
because the fs is in the process of being umount'd. 

The solution is to add a put_inode routine to update the inode contents
and release the pre-alloc'd blocks to disk prior to clearing the inode
from the kernel.

Test case:
    mkuddfs /dev/scd0
    mount -o sync /dev/scd0 /mnt/cdrom
    mkdir /mnt/cdrom/A /mnt/cdrom/B
    cp A/* /mnt/cdrom/A		[ A contains 90 files of various sizes ]
    cp B/* /mnt/cdrom/B 	[ B contains 20 or fewer files ]
    umount /mnt/cdrom

Here you can see how 7 blocks starting at sector 139 are free and listed in the
directory entry for 'A'.  I used udfdump to get the following information:
    [ ... ]
    Free space found on this partition
	[00000139 - 00000159]   [00000161 - 00000191]   [00000193 - 00000223]   
	[00004464 - 00004475]   [00004485 - 00524286]   [00524287 - 01048573]
	[01048574 - 01572860]   [01572861 - 02097147]   [02097148 - 02235039]   
    [ ... ]
    Filename `A`
    [ ... ]
    [ blob at sector     2038 for     2048 bytes in logical partion 0 ] 
    [ blob at sector      137 for     4096 bytes in logical partion 0 ] 
    [ blob at sector      139 for    14336 bytes in logical partion 0 flags 1 ] 

-- 
Rich Coe		richard.coe@med.ge.com
Virtual Principle Engineer  General Electric Healthcare Technologies
Global Software Platforms, Computer Technology Team

Signed-off-by: Rich Coe <richard.coe@med.ge.com>
---
diff -urNp linux-2.6.20.orig/fs/udf/inode.c linux-2.6.20/fs/udf/inode.c
--- linux-2.6.20.orig/fs/udf/inode.c	2007-02-04 12:44:54.000000000 -0600
+++ linux-2.6.20/fs/udf/inode.c	2007-06-13 11:32:41.930983471 -0500
@@ -102,14 +102,17 @@ no_delete:
 
 void udf_clear_inode(struct inode *inode)
 {
+	kfree(UDF_I_DATA(inode));
+	UDF_I_DATA(inode) = NULL;
+}
+
+void udf_put_inode(struct inode *inode)
+{
 	if (!(inode->i_sb->s_flags & MS_RDONLY)) {
 		lock_kernel();
 		udf_discard_prealloc(inode);
 		unlock_kernel();
 	}
-
-	kfree(UDF_I_DATA(inode));
-	UDF_I_DATA(inode) = NULL;
 }
 
 static int udf_writepage(struct page *page, struct writeback_control *wbc)
diff -urNp linux-2.6.20.orig/fs/udf/super.c linux-2.6.20/fs/udf/super.c
--- linux-2.6.20.orig/fs/udf/super.c	2007-02-04 12:44:54.000000000 -0600
+++ linux-2.6.20/fs/udf/super.c	2007-06-13 11:31:23.793017185 -0500
@@ -166,6 +166,7 @@ static struct super_operations udf_sb_op
 	.write_inode		= udf_write_inode,
 	.delete_inode		= udf_delete_inode,
 	.clear_inode		= udf_clear_inode,
+	.put_inode		= udf_put_inode,
 	.put_super		= udf_put_super,
 	.write_super		= udf_write_super,
 	.statfs			= udf_statfs,
diff -urNp linux-2.6.20.orig/fs/udf/udfdecl.h linux-2.6.20/fs/udf/udfdecl.h
--- linux-2.6.20.orig/fs/udf/udfdecl.h	2007-02-04 12:44:54.000000000 -0600
+++ linux-2.6.20/fs/udf/udfdecl.h	2007-06-13 11:31:16.684293910 -0500
@@ -97,6 +97,7 @@ extern void udf_truncate(struct inode *)
 extern void udf_read_inode(struct inode *);
 extern void udf_delete_inode(struct inode *);
 extern void udf_clear_inode(struct inode *);
+extern void udf_put_inode(struct inode *);
 extern int udf_write_inode(struct inode *, int);
 extern long udf_block_map(struct inode *, long);
 extern int8_t inode_bmap(struct inode *, int, kernel_lb_addr *, uint32_t *, kernel_lb_addr *, uint32_t *, uint32_t *, struct buffer_head **);

             reply	other threads:[~2007-06-13 20:56 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-06-13 20:48 Rich Coe [this message]
2007-06-13 21:27 ` Chuck Ebbert
2007-06-14  8:25 ` Jan Kara
2007-06-14 21:32 ` RFC: " Rich Coe
2007-06-14 22:12   ` Linus Torvalds
2007-06-15 16:09     ` Jan Kara
2007-06-15 23:23       ` Linus Torvalds

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20070613154803.a1ad874a.Richard.Coe@med.ge.com \
    --to=richard.coe@med.ge.com \
    --cc=jack@suse.cz \
    --cc=linux-kernel@vger.kernel.org \
    --cc=torvalds@osdl.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®