diff options
author | Anton Altaparmakov <aia21@cantab.net> | 2007-01-18 04:42:48 -0500 |
---|---|---|
committer | Anton Altaparmakov <aia21@cantab.net> | 2007-01-18 04:42:48 -0500 |
commit | 8331191e56802f0155772a3d56bc2a750acc38e1 (patch) | |
tree | 556f3b8f395d7c66b9eca9d35309644b9f1c027d /fs/ntfs/dir.c | |
parent | a8b3485287731978899ced11f24628c927890e78 (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.c | 45 |
1 files changed, 27 insertions, 18 deletions
diff --git a/fs/ntfs/dir.c b/fs/ntfs/dir.c index 8296c29ae3b8..74f99a6a369b 100644 --- a/fs/ntfs/dir.c +++ b/fs/ntfs/dir.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /** | 1 | /** |
2 | * dir.c - NTFS kernel directory operations. Part of the Linux-NTFS project. | 2 | * dir.c - NTFS kernel directory operations. Part of the Linux-NTFS project. |
3 | * | 3 | * |
4 | * Copyright (c) 2001-2005 Anton Altaparmakov | 4 | * Copyright (c) 2001-2007 Anton Altaparmakov |
5 | * Copyright (c) 2002 Richard Russon | 5 | * Copyright (c) 2002 Richard Russon |
6 | * | 6 | * |
7 | * This program/include file is free software; you can redistribute it and/or | 7 | * This program/include file is free software; you can redistribute it and/or |
@@ -1249,16 +1249,12 @@ skip_index_root: | |||
1249 | /* Get the offset into the index allocation attribute. */ | 1249 | /* Get the offset into the index allocation attribute. */ |
1250 | ia_pos = (s64)fpos - vol->mft_record_size; | 1250 | ia_pos = (s64)fpos - vol->mft_record_size; |
1251 | ia_mapping = vdir->i_mapping; | 1251 | ia_mapping = vdir->i_mapping; |
1252 | bmp_vi = ndir->itype.index.bmp_ino; | 1252 | ntfs_debug("Inode 0x%lx, getting index bitmap.", vdir->i_ino); |
1253 | if (unlikely(!bmp_vi)) { | 1253 | bmp_vi = ntfs_attr_iget(vdir, AT_BITMAP, I30, 4); |
1254 | ntfs_debug("Inode 0x%lx, regetting index bitmap.", vdir->i_ino); | 1254 | if (IS_ERR(bmp_vi)) { |
1255 | bmp_vi = ntfs_attr_iget(vdir, AT_BITMAP, I30, 4); | 1255 | ntfs_error(sb, "Failed to get bitmap attribute."); |
1256 | if (IS_ERR(bmp_vi)) { | 1256 | err = PTR_ERR(bmp_vi); |
1257 | ntfs_error(sb, "Failed to get bitmap attribute."); | 1257 | goto err_out; |
1258 | err = PTR_ERR(bmp_vi); | ||
1259 | goto err_out; | ||
1260 | } | ||
1261 | ndir->itype.index.bmp_ino = bmp_vi; | ||
1262 | } | 1258 | } |
1263 | bmp_mapping = bmp_vi->i_mapping; | 1259 | bmp_mapping = bmp_vi->i_mapping; |
1264 | /* Get the starting bitmap bit position and sanity check it. */ | 1260 | /* Get the starting bitmap bit position and sanity check it. */ |
@@ -1266,7 +1262,7 @@ skip_index_root: | |||
1266 | if (unlikely(bmp_pos >> 3 >= i_size_read(bmp_vi))) { | 1262 | if (unlikely(bmp_pos >> 3 >= i_size_read(bmp_vi))) { |
1267 | ntfs_error(sb, "Current index allocation position exceeds " | 1263 | ntfs_error(sb, "Current index allocation position exceeds " |
1268 | "index bitmap size."); | 1264 | "index bitmap size."); |
1269 | goto err_out; | 1265 | goto iput_err_out; |
1270 | } | 1266 | } |
1271 | /* Get the starting bit position in the current bitmap page. */ | 1267 | /* Get the starting bit position in the current bitmap page. */ |
1272 | cur_bmp_pos = bmp_pos & ((PAGE_CACHE_SIZE * 8) - 1); | 1268 | cur_bmp_pos = bmp_pos & ((PAGE_CACHE_SIZE * 8) - 1); |
@@ -1282,7 +1278,7 @@ get_next_bmp_page: | |||
1282 | ntfs_error(sb, "Reading index bitmap failed."); | 1278 | ntfs_error(sb, "Reading index bitmap failed."); |
1283 | err = PTR_ERR(bmp_page); | 1279 | err = PTR_ERR(bmp_page); |
1284 | bmp_page = NULL; | 1280 | bmp_page = NULL; |
1285 | goto err_out; | 1281 | goto iput_err_out; |
1286 | } | 1282 | } |
1287 | bmp = (u8*)page_address(bmp_page); | 1283 | bmp = (u8*)page_address(bmp_page); |
1288 | /* Find next index block in use. */ | 1284 | /* Find next index block in use. */ |
@@ -1429,6 +1425,7 @@ find_next_index_buffer: | |||
1429 | /* @ia_page is already unlocked in this case. */ | 1425 | /* @ia_page is already unlocked in this case. */ |
1430 | ntfs_unmap_page(ia_page); | 1426 | ntfs_unmap_page(ia_page); |
1431 | ntfs_unmap_page(bmp_page); | 1427 | ntfs_unmap_page(bmp_page); |
1428 | iput(bmp_vi); | ||
1432 | goto abort; | 1429 | goto abort; |
1433 | } | 1430 | } |
1434 | } | 1431 | } |
@@ -1439,6 +1436,7 @@ unm_EOD: | |||
1439 | ntfs_unmap_page(ia_page); | 1436 | ntfs_unmap_page(ia_page); |
1440 | } | 1437 | } |
1441 | ntfs_unmap_page(bmp_page); | 1438 | ntfs_unmap_page(bmp_page); |
1439 | iput(bmp_vi); | ||
1442 | EOD: | 1440 | EOD: |
1443 | /* We are finished, set fpos to EOD. */ | 1441 | /* We are finished, set fpos to EOD. */ |
1444 | fpos = i_size + vol->mft_record_size; | 1442 | fpos = i_size + vol->mft_record_size; |
@@ -1455,8 +1453,11 @@ done: | |||
1455 | filp->f_pos = fpos; | 1453 | filp->f_pos = fpos; |
1456 | return 0; | 1454 | return 0; |
1457 | err_out: | 1455 | err_out: |
1458 | if (bmp_page) | 1456 | if (bmp_page) { |
1459 | ntfs_unmap_page(bmp_page); | 1457 | ntfs_unmap_page(bmp_page); |
1458 | iput_err_out: | ||
1459 | iput(bmp_vi); | ||
1460 | } | ||
1460 | if (ia_page) { | 1461 | if (ia_page) { |
1461 | unlock_page(ia_page); | 1462 | unlock_page(ia_page); |
1462 | ntfs_unmap_page(ia_page); | 1463 | ntfs_unmap_page(ia_page); |
@@ -1529,14 +1530,22 @@ static int ntfs_dir_open(struct inode *vi, struct file *filp) | |||
1529 | static int ntfs_dir_fsync(struct file *filp, struct dentry *dentry, | 1530 | static int ntfs_dir_fsync(struct file *filp, struct dentry *dentry, |
1530 | int datasync) | 1531 | int datasync) |
1531 | { | 1532 | { |
1532 | struct inode *vi = dentry->d_inode; | 1533 | struct inode *bmp_vi, *vi = dentry->d_inode; |
1533 | ntfs_inode *ni = NTFS_I(vi); | ||
1534 | int err, ret; | 1534 | int err, ret; |
1535 | ntfs_attr na; | ||
1535 | 1536 | ||
1536 | ntfs_debug("Entering for inode 0x%lx.", vi->i_ino); | 1537 | ntfs_debug("Entering for inode 0x%lx.", vi->i_ino); |
1537 | BUG_ON(!S_ISDIR(vi->i_mode)); | 1538 | BUG_ON(!S_ISDIR(vi->i_mode)); |
1538 | if (NInoIndexAllocPresent(ni) && ni->itype.index.bmp_ino) | 1539 | /* If the bitmap attribute inode is in memory sync it, too. */ |
1539 | write_inode_now(ni->itype.index.bmp_ino, !datasync); | 1540 | na.mft_no = vi->i_ino; |
1541 | na.type = AT_BITMAP; | ||
1542 | na.name = I30; | ||
1543 | na.name_len = 4; | ||
1544 | bmp_vi = ilookup5(vi->i_sb, vi->i_ino, (test_t)ntfs_test_inode, &na); | ||
1545 | if (bmp_vi) { | ||
1546 | write_inode_now(bmp_vi, !datasync); | ||
1547 | iput(bmp_vi); | ||
1548 | } | ||
1540 | ret = ntfs_write_inode(vi, 1); | 1549 | ret = ntfs_write_inode(vi, 1); |
1541 | write_inode_now(vi, !datasync); | 1550 | write_inode_now(vi, !datasync); |
1542 | err = sync_blockdev(vi->i_sb->s_bdev); | 1551 | err = sync_blockdev(vi->i_sb->s_bdev); |