Skip to contentSkip to conversation

UDF: fix deadlock on inode being dropped

PATCH In review Cyrill Gorcunov 2 participants 7 messages Jun 6, 2007 – Jun 11, 2007 UDF filesystem

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 UDF: fix deadlock on inode being dropped

This patch prevents from deadlock on inode being dropped. The deadlock is caused by inderect call of mark_inode_dirty() within udf_drop_inode() but inode lock is already kept by the kernel. So moving code from udf_drop_inode() to udf_delete_inode() we save its functionality and avoid deadlock.

---
Andrew the patch is over Jan's two patches you have dropped. AFAIS a such code moving is quite safe but I'm waiting for Jan's comments anyway.

 fs/udf/inode.c |   20 ++++++++------------
 fs/udf/super.c |    1 -
 2 files changed, 8 insertions(+), 13 deletions(-)
fs/udf/inode.c +8 -12
index 9fcd76c..ae56f25 100644
@@ -83,6 +83,14 @@ static int udf_get_block(struct inode *, sector_t, struct buffer_head *, int);
  */
 void udf_delete_inode(struct inode *inode)
 {
+	if (!(inode->i_sb->s_flags & MS_RDONLY)) {
+		lock_kernel();
+		/* Discard preallocation for directories, symlinks, etc. */
+		udf_discard_prealloc(inode);
+		udf_truncate_tail_extent(inode);
+		unlock_kernel();
+	}
+
 	truncate_inode_pages(&inode->i_data, 0);
 
 	if (is_bad_inode(inode))
@@ -102,18 +110,6 @@ no_delete:
 	clear_inode(inode);
 }
 
-void udf_drop_inode(struct inode *inode)
-{
-	if (!(inode->i_sb->s_flags & MS_RDONLY)) {
-		lock_kernel();
-		/* Discard preallocation for directories, symlinks, etc. */
-		udf_discard_prealloc(inode);
-		udf_truncate_tail_extent(inode);
-		unlock_kernel();
-	}
-	generic_drop_inode(inode);
-}
-
 void udf_clear_inode(struct inode *inode)
 {
 	kfree(UDF_I_DATA(inode));
fs/udf/super.c +0 -1
index b02d2c2..deb0d29 100644
@@ -166,7 +166,6 @@ static const struct super_operations udf_sb_ops = {
 	.write_inode		= udf_write_inode,
 	.delete_inode		= udf_delete_inode,
 	.clear_inode		= udf_clear_inode,
-	.drop_inode		= udf_drop_inode,
 	.put_super		= udf_put_super,
 	.write_super		= udf_write_super,
 	.statfs			= udf_statfs,
#1 lore raw

Hi Cyrill!

Quoted 6 lines · Cyrill Gorcunov

This patch prevents from deadlock on inode being dropped. The deadlock is caused by inderect call of mark_inode_dirty() within udf_drop_inode() but inode lock is already kept by the kernel. So moving code from udf_drop_inode() to udf_delete_inode() we save its functionality and avoid deadlock.

The patch is wrong. You cannot truncate the extent just in delete_inode.
That would lead to inodes with untruncated last extent on disk after unmounting, which is forbidden in the specification. You need to truncate the last extent whenever inode is being removed from memory or something like that... I'm already thinking how to do it and avoid calling mark_inode_dirty()...

Honza

Signature · 2 lines
Jan Kara <[email protected]>
SuSE CR Labs
#2 lore raw

[Jan Kara - Thu, Jun 07, 2007 at 11:36:07AM +0200]

|   Hi Cyrill!
| 
| On Wed 06-06-07 21:53:51, Cyrill Gorcunov wrote:
| > This patch prevents from deadlock on inode being dropped.
| > The deadlock is caused by inderect call of mark_inode_dirty()
| > within udf_drop_inode() but inode lock is already kept
| > by the kernel. So moving code from udf_drop_inode() to
| > udf_delete_inode() we save its functionality and avoid
| > deadlock.
|   The patch is wrong. You cannot truncate the extent just in delete_inode.
| That would lead to inodes with untruncated last extent on disk after
| unmounting, which is forbidden in the specification. You need to truncate
| the last extent whenever inode is being removed from memory or something
| like that... I'm already thinking how to do it and avoid calling
| mark_inode_dirty()...
| 
| 
| 							Honza
| -- 
| Jan Kara <[email protected]>
| SuSE CR Labs
| 

Arh, thanks... Jan, actually the reason I've moved the code into 'delete' section was that I found no reasonable difference for our case between 'drop' and 'delete'. Moreover, by seeing into VFS code the only diff between 'drop' and 'delete' is that
inside generic_delete_inode() a few inode structure elements are being destroyed and then our udf_drop_inode is called. So assuming, that you're right in drop_inode I've code just moved to 'delete' section.

Cyrill

#3 lore raw
Quoted 18 lines · Cyrill Gorcunov

[Jan Kara - Thu, Jun 07, 2007 at 11:36:07AM +0200]

|   Hi Cyrill!
| 
| On Wed 06-06-07 21:53:51, Cyrill Gorcunov wrote:
| > This patch prevents from deadlock on inode being dropped.
| > The deadlock is caused by inderect call of mark_inode_dirty()
| > within udf_drop_inode() but inode lock is already kept
| > by the kernel. So moving code from udf_drop_inode() to
| > udf_delete_inode() we save its functionality and avoid
| > deadlock.
|   The patch is wrong. You cannot truncate the extent just in delete_inode.
| That would lead to inodes with untruncated last extent on disk after
| unmounting, which is forbidden in the specification. You need to truncate
| the last extent whenever inode is being removed from memory or something
| like that... I'm already thinking how to do it and avoid calling
| mark_inode_dirty()...
| 
Quoted 7 lines

Arh, thanks... Jan, actually the reason I've moved the code into 'delete' section was that I found no reasonable difference for our case between 'drop' and 'delete'. Moreover, by seeing into VFS code the only diff between 'drop' and 'delete' is that
inside generic_delete_inode() a few inode structure elements are being destroyed and then our udf_drop_inode is called. So assuming, that you're right in drop_inode I've code just moved to 'delete' section.

The difference is that udf_delete_inode() is called only when inode has
i_nlink == 0 and thus it's being deleted on disk. udf_drop_inode() is called whenever inode is removed from memory which is what we want.
I'm already testing a patch which should fix the problem...

Honza

Signature · 2 lines
Jan Kara <[email protected]>
SuSE CR Labs
#4 lore raw

[Jan Kara - Thu, Jun 07, 2007 at 04:41:21PM +0200]

| On Thu 07-06-07 17:54:58, Cyrill Gorcunov wrote:
| > [Jan Kara - Thu, Jun 07, 2007 at 11:36:07AM +0200]
| > |   Hi Cyrill!
| > | 
| > | On Wed 06-06-07 21:53:51, Cyrill Gorcunov wrote:
| > | > This patch prevents from deadlock on inode being dropped.
| > | > The deadlock is caused by inderect call of mark_inode_dirty()
| > | > within udf_drop_inode() but inode lock is already kept
| > | > by the kernel. So moving code from udf_drop_inode() to
| > | > udf_delete_inode() we save its functionality and avoid
| > | > deadlock.
| > |   The patch is wrong. You cannot truncate the extent just in delete_inode.
| > | That would lead to inodes with untruncated last extent on disk after
| > | unmounting, which is forbidden in the specification. You need to truncate
| > | the last extent whenever inode is being removed from memory or something
| > | like that... I'm already thinking how to do it and avoid calling
| > | mark_inode_dirty()...
| > | 
| > 
| > Arh, thanks... Jan, actually the reason I've moved the code into
| > 'delete' section was that I found no reasonable difference for our
| > case between 'drop' and 'delete'. Moreover, by seeing into VFS code
| > the only diff between 'drop' and 'delete' is that
| > inside generic_delete_inode() a few inode structure elements
| > are being destroyed and then our udf_drop_inode is called. So assuming,
| > that you're right in drop_inode I've code just moved to 'delete' section.
|   The difference is that udf_delete_inode() is called only when inode has
| i_nlink == 0 and thus it's being deleted on disk. udf_drop_inode() is
| called whenever inode is removed from memory which is what we want.
|   I'm already testing a patch which should fix the problem...
| 
| 								Honza
| -- 
| Jan Kara <[email protected]>
| SuSE CR Labs
| 

Thanks for eplanation, Jan

Cyrill

#5 lore raw
In reply to Jan Kara

[Jan Kara - Thu, Jun 07, 2007 at 04:41:21PM +0200]

| On Thu 07-06-07 17:54:58, Cyrill Gorcunov wrote:
| > [Jan Kara - Thu, Jun 07, 2007 at 11:36:07AM +0200]
| > |   Hi Cyrill!
| > | 
| > | On Wed 06-06-07 21:53:51, Cyrill Gorcunov wrote:
| > | > This patch prevents from deadlock on inode being dropped.
| > | > The deadlock is caused by inderect call of mark_inode_dirty()
| > | > within udf_drop_inode() but inode lock is already kept
| > | > by the kernel. So moving code from udf_drop_inode() to
| > | > udf_delete_inode() we save its functionality and avoid
| > | > deadlock.
| > |   The patch is wrong. You cannot truncate the extent just in delete_inode.
| > | That would lead to inodes with untruncated last extent on disk after
| > | unmounting, which is forbidden in the specification. You need to truncate
| > | the last extent whenever inode is being removed from memory or something
| > | like that... I'm already thinking how to do it and avoid calling
| > | mark_inode_dirty()...
| > | 
| > 
| > Arh, thanks... Jan, actually the reason I've moved the code into
| > 'delete' section was that I found no reasonable difference for our
| > case between 'drop' and 'delete'. Moreover, by seeing into VFS code
| > the only diff between 'drop' and 'delete' is that
| > inside generic_delete_inode() a few inode structure elements
| > are being destroyed and then our udf_drop_inode is called. So assuming,
| > that you're right in drop_inode I've code just moved to 'delete' section.
|   The difference is that udf_delete_inode() is called only when inode has
| i_nlink == 0 and thus it's being deleted on disk. udf_drop_inode() is
| called whenever inode is removed from memory which is what we want.
|   I'm already testing a patch which should fix the problem...
| 
| 								Honza
| -- 
| Jan Kara <[email protected]>
| SuSE CR Labs
| 

Hi Jan,

how your progress? Could I help with something?

Cyrill

#6 lore raw
Quoted 32 lines · Cyrill Gorcunov

[Jan Kara - Thu, Jun 07, 2007 at 04:41:21PM +0200]

| On Thu 07-06-07 17:54:58, Cyrill Gorcunov wrote:
| > [Jan Kara - Thu, Jun 07, 2007 at 11:36:07AM +0200]
| > |   Hi Cyrill!
| > | 
| > | On Wed 06-06-07 21:53:51, Cyrill Gorcunov wrote:
| > | > This patch prevents from deadlock on inode being dropped.
| > | > The deadlock is caused by inderect call of mark_inode_dirty()
| > | > within udf_drop_inode() but inode lock is already kept
| > | > by the kernel. So moving code from udf_drop_inode() to
| > | > udf_delete_inode() we save its functionality and avoid
| > | > deadlock.
| > |   The patch is wrong. You cannot truncate the extent just in delete_inode.
| > | That would lead to inodes with untruncated last extent on disk after
| > | unmounting, which is forbidden in the specification. You need to truncate
| > | the last extent whenever inode is being removed from memory or something
| > | like that... I'm already thinking how to do it and avoid calling
| > | mark_inode_dirty()...
| > | 
| > 
| > Arh, thanks... Jan, actually the reason I've moved the code into
| > 'delete' section was that I found no reasonable difference for our
| > case between 'drop' and 'delete'. Moreover, by seeing into VFS code
| > the only diff between 'drop' and 'delete' is that
| > inside generic_delete_inode() a few inode structure elements
| > are being destroyed and then our udf_drop_inode is called. So assuming,
| > that you're right in drop_inode I've code just moved to 'delete' section.
|   The difference is that udf_delete_inode() is called only when inode has
| i_nlink == 0 and thus it's being deleted on disk. udf_drop_inode() is
| called whenever inode is removed from memory which is what we want.
|   I'm already testing a patch which should fix the problem...
Quoted 1 line

how your progress? Could I help with something?

Eric has run his UDF test suite on it and it seems to survive fine so I'm
going to submit the patch to Andrew in a while.

Honza

Signature · 2 lines
Jan Kara <[email protected]>
SuSE CR Labs