NTFS: 2.1.28 - Fix deadlock reported by Sergey Vlasov due to ntfs_put_inode().

- Fix deadlock in fs/ntfs/inode.c::ntfs_put_inode().  Thanks to Sergey
  Vlasov for the report and detailed analysis of the deadlock.  The fix
  involved getting rid of ntfs_put_inode() altogether and hence NTFS no
  longer has a ->put_inode super operation.

Signed-off-by: Anton Altaparmakov <aia21@cantab.net>
This commit is contained in:
Anton Altaparmakov
2007-01-18 09:42:48 +00:00
parent a8b3485287
commit 8331191e56
6 changed files with 52 additions and 84 deletions

View File

@@ -1,7 +1,7 @@
/**
* dir.c - NTFS kernel directory operations. Part of the Linux-NTFS project.
*
* Copyright (c) 2001-2005 Anton Altaparmakov
* Copyright (c) 2001-2007 Anton Altaparmakov
* Copyright (c) 2002 Richard Russon
*
* This program/include file is free software; you can redistribute it and/or
@@ -1249,16 +1249,12 @@ skip_index_root:
/* Get the offset into the index allocation attribute. */
ia_pos = (s64)fpos - vol->mft_record_size;
ia_mapping = vdir->i_mapping;
bmp_vi = ndir->itype.index.bmp_ino;
if (unlikely(!bmp_vi)) {
ntfs_debug("Inode 0x%lx, regetting index bitmap.", vdir->i_ino);
bmp_vi = ntfs_attr_iget(vdir, AT_BITMAP, I30, 4);
if (IS_ERR(bmp_vi)) {
ntfs_error(sb, "Failed to get bitmap attribute.");
err = PTR_ERR(bmp_vi);
goto err_out;
}
ndir->itype.index.bmp_ino = bmp_vi;
ntfs_debug("Inode 0x%lx, getting index bitmap.", vdir->i_ino);
bmp_vi = ntfs_attr_iget(vdir, AT_BITMAP, I30, 4);
if (IS_ERR(bmp_vi)) {
ntfs_error(sb, "Failed to get bitmap attribute.");
err = PTR_ERR(bmp_vi);
goto err_out;
}
bmp_mapping = bmp_vi->i_mapping;
/* Get the starting bitmap bit position and sanity check it. */
@@ -1266,7 +1262,7 @@ skip_index_root:
if (unlikely(bmp_pos >> 3 >= i_size_read(bmp_vi))) {
ntfs_error(sb, "Current index allocation position exceeds "
"index bitmap size.");
goto err_out;
goto iput_err_out;
}
/* Get the starting bit position in the current bitmap page. */
cur_bmp_pos = bmp_pos & ((PAGE_CACHE_SIZE * 8) - 1);
@@ -1282,7 +1278,7 @@ get_next_bmp_page:
ntfs_error(sb, "Reading index bitmap failed.");
err = PTR_ERR(bmp_page);
bmp_page = NULL;
goto err_out;
goto iput_err_out;
}
bmp = (u8*)page_address(bmp_page);
/* Find next index block in use. */
@@ -1429,6 +1425,7 @@ find_next_index_buffer:
/* @ia_page is already unlocked in this case. */
ntfs_unmap_page(ia_page);
ntfs_unmap_page(bmp_page);
iput(bmp_vi);
goto abort;
}
}
@@ -1439,6 +1436,7 @@ unm_EOD:
ntfs_unmap_page(ia_page);
}
ntfs_unmap_page(bmp_page);
iput(bmp_vi);
EOD:
/* We are finished, set fpos to EOD. */
fpos = i_size + vol->mft_record_size;
@@ -1455,8 +1453,11 @@ done:
filp->f_pos = fpos;
return 0;
err_out:
if (bmp_page)
if (bmp_page) {
ntfs_unmap_page(bmp_page);
iput_err_out:
iput(bmp_vi);
}
if (ia_page) {
unlock_page(ia_page);
ntfs_unmap_page(ia_page);
@@ -1529,14 +1530,22 @@ static int ntfs_dir_open(struct inode *vi, struct file *filp)
static int ntfs_dir_fsync(struct file *filp, struct dentry *dentry,
int datasync)
{
struct inode *vi = dentry->d_inode;
ntfs_inode *ni = NTFS_I(vi);
struct inode *bmp_vi, *vi = dentry->d_inode;
int err, ret;
ntfs_attr na;
ntfs_debug("Entering for inode 0x%lx.", vi->i_ino);
BUG_ON(!S_ISDIR(vi->i_mode));
if (NInoIndexAllocPresent(ni) && ni->itype.index.bmp_ino)
write_inode_now(ni->itype.index.bmp_ino, !datasync);
/* If the bitmap attribute inode is in memory sync it, too. */
na.mft_no = vi->i_ino;
na.type = AT_BITMAP;
na.name = I30;
na.name_len = 4;
bmp_vi = ilookup5(vi->i_sb, vi->i_ino, (test_t)ntfs_test_inode, &na);
if (bmp_vi) {
write_inode_now(bmp_vi, !datasync);
iput(bmp_vi);
}
ret = ntfs_write_inode(vi, 1);
write_inode_now(vi, !datasync);
err = sync_blockdev(vi->i_sb->s_bdev);