summaryrefslogtreecommitdiffstats
path: root/fs/ntfs/dir.c
diff options
context:
space:
mode:
authorAnton Altaparmakov <aia21@cantab.net>2007-01-18 09:42:48 +0000
committerAnton Altaparmakov <aia21@cantab.net>2007-01-18 09:42:48 +0000
commit8331191e56802f0155772a3d56bc2a750acc38e1 (patch)
tree556f3b8f395d7c66b9eca9d35309644b9f1c027d /fs/ntfs/dir.c
parenta8b3485287731978899ced11f24628c927890e78 (diff)
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>
Diffstat (limited to 'fs/ntfs/dir.c')
-rw-r--r--fs/ntfs/dir.c45
1 files changed, 27 insertions, 18 deletions
diff --git a/fs/ntfs/dir.c b/fs/ntfs/dir.c
index 8296c29ae3b..74f99a6a369 100644
--- a/fs/ntfs/dir.c
+++ b/fs/ntfs/dir.c
@@ -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);