* [PATCH] ext4: work around deleting a file with i_nlink == 0 safely
@ 2019-11-12 3:29 Theodore Ts'o
2019-11-13 21:25 ` Andreas Dilger
0 siblings, 1 reply; 2+ messages in thread
From: Theodore Ts'o @ 2019-11-12 3:29 UTC (permalink / raw)
To: Ext4 Developers List; +Cc: Theodore Ts'o, stable
If the file system is corrupted such that a file's i_links_count is
too small, then it's possible that when unlinking that file, i_nlink
will already be zero. Previously we were working around this kind of
corruption by forcing i_nlink to one; but we were doing this before
trying to delete the directory entry --- and if the file system is
corrupted enough that ext4_delete_entry() fails, then we exit with
i_nlink elevated, and this causes the orphan inode list handling to be
FUBAR'ed, such that when we unmount the file system, the orphan inode
list can get corrupted.
A better way to fix this is to simply skip trying to call drop_nlink()
if i_nlink is already zero, thus moving the check to the place where
it makes the most sense.
https://bugzilla.kernel.org/show_bug.cgi?id=205433
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Cc: stable@kernel.org
---
fs/ext4/namei.c | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index a67cae3c8ff5..a856997d87b5 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -3196,18 +3196,17 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry)
if (IS_DIRSYNC(dir))
ext4_handle_sync(handle);
- if (inode->i_nlink == 0) {
- ext4_warning_inode(inode, "Deleting file '%.*s' with no links",
- dentry->d_name.len, dentry->d_name.name);
- set_nlink(inode, 1);
- }
retval = ext4_delete_entry(handle, dir, de, bh);
if (retval)
goto end_unlink;
dir->i_ctime = dir->i_mtime = current_time(dir);
ext4_update_dx_flag(dir);
ext4_mark_inode_dirty(handle, dir);
- drop_nlink(inode);
+ if (inode->i_nlink == 0)
+ ext4_warning_inode(inode, "Deleting file '%.*s' with no links",
+ dentry->d_name.len, dentry->d_name.name);
+ else
+ drop_nlink(inode);
if (!inode->i_nlink)
ext4_orphan_add(handle, inode);
inode->i_ctime = current_time(inode);
--
2.23.0
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH] ext4: work around deleting a file with i_nlink == 0 safely
2019-11-12 3:29 [PATCH] ext4: work around deleting a file with i_nlink == 0 safely Theodore Ts'o
@ 2019-11-13 21:25 ` Andreas Dilger
0 siblings, 0 replies; 2+ messages in thread
From: Andreas Dilger @ 2019-11-13 21:25 UTC (permalink / raw)
To: Theodore Ts'o; +Cc: Ext4 Developers List, stable
[-- Attachment #1: Type: text/plain, Size: 2201 bytes --]
On Nov 11, 2019, at 8:29 PM, Theodore Ts'o <tytso@mit.edu> wrote:
>
> If the file system is corrupted such that a file's i_links_count is
> too small, then it's possible that when unlinking that file, i_nlink
> will already be zero. Previously we were working around this kind of
> corruption by forcing i_nlink to one; but we were doing this before
> trying to delete the directory entry --- and if the file system is
> corrupted enough that ext4_delete_entry() fails, then we exit with
> i_nlink elevated, and this causes the orphan inode list handling to be
> FUBAR'ed, such that when we unmount the file system, the orphan inode
> list can get corrupted.
>
> A better way to fix this is to simply skip trying to call drop_nlink()
> if i_nlink is already zero, thus moving the check to the place where
> it makes the most sense.
>
> https://bugzilla.kernel.org/show_bug.cgi?id=205433
>
> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Reviewed-by: Andreas Dilger <adilger@dilger.ca>
> Cc: stable@kernel.org
> ---
> fs/ext4/namei.c | 11 +++++------
> 1 file changed, 5 insertions(+), 6 deletions(-)
>
> diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
> index a67cae3c8ff5..a856997d87b5 100644
> --- a/fs/ext4/namei.c
> +++ b/fs/ext4/namei.c
> @@ -3196,18 +3196,17 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry)
> if (IS_DIRSYNC(dir))
> ext4_handle_sync(handle);
>
> - if (inode->i_nlink == 0) {
> - ext4_warning_inode(inode, "Deleting file '%.*s' with no links",
> - dentry->d_name.len, dentry->d_name.name);
> - set_nlink(inode, 1);
> - }
> retval = ext4_delete_entry(handle, dir, de, bh);
> if (retval)
> goto end_unlink;
> dir->i_ctime = dir->i_mtime = current_time(dir);
> ext4_update_dx_flag(dir);
> ext4_mark_inode_dirty(handle, dir);
> - drop_nlink(inode);
> + if (inode->i_nlink == 0)
> + ext4_warning_inode(inode, "Deleting file '%.*s' with no links",
> + dentry->d_name.len, dentry->d_name.name);
> + else
> + drop_nlink(inode);
> if (!inode->i_nlink)
> ext4_orphan_add(handle, inode);
> inode->i_ctime = current_time(inode);
> --
> 2.23.0
>
Cheers, Andreas
[-- Attachment #2: Message signed with OpenPGP --]
[-- Type: application/pgp-signature, Size: 873 bytes --]
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2019-11-13 21:25 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-12 3:29 [PATCH] ext4: work around deleting a file with i_nlink == 0 safely Theodore Ts'o
2019-11-13 21:25 ` Andreas Dilger
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).