aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>2009-04-28 08:04:59 -0400
committerRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>2009-05-09 00:36:57 -0400
commit201913ed746c7724a40d33ee5a0b6a1fd2ef3193 (patch)
tree149cd7552a854055a2ed278234649a77914aaf96
parent85c2a74fabadfc561b75fbd7decc6bcbfe873d57 (diff)
nilfs2: fix circular locking dependency of writer mutex
This fixes the following circular locking dependency problem: ======================================================= [ INFO: possible circular locking dependency detected ] 2.6.30-rc3 #5 ------------------------------------------------------- segctord/3895 is trying to acquire lock: (&nilfs->ns_writer_mutex){+.+...}, at: [<d0d02172>] nilfs_mdt_get_block+0x89/0x20f [nilfs2] but task is already holding lock: (&bmap->b_sem){++++..}, at: [<d0d02d99>] nilfs_bmap_propagate+0x14/0x2e [nilfs2] which lock already depends on the new lock. The bugfix is done by replacing call sites of nilfs_get_writer() which are never called from read-only context with direct dereferencing of pointer to a writable FS-instance. Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
-rw-r--r--fs/nilfs2/ioctl.c8
-rw-r--r--fs/nilfs2/mdt.c13
2 files changed, 12 insertions, 9 deletions
diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c
index 108d281ebca5..be387c6b2d46 100644
--- a/fs/nilfs2/ioctl.c
+++ b/fs/nilfs2/ioctl.c
@@ -516,14 +516,16 @@ static ssize_t
516nilfs_ioctl_do_free_segments(struct the_nilfs *nilfs, __u64 *posp, int flags, 516nilfs_ioctl_do_free_segments(struct the_nilfs *nilfs, __u64 *posp, int flags,
517 void *buf, size_t size, size_t nmembs) 517 void *buf, size_t size, size_t nmembs)
518{ 518{
519 struct nilfs_sb_info *sbi = nilfs_get_writer(nilfs); 519 struct nilfs_sb_info *sbi = nilfs->ns_writer;
520 int ret; 520 int ret;
521 521
522 if (unlikely(!sbi)) 522 if (unlikely(!sbi)) {
523 /* never happens because called for a writable mount */
524 WARN_ON(1);
523 return -EROFS; 525 return -EROFS;
526 }
524 ret = nilfs_segctor_add_segments_to_be_freed( 527 ret = nilfs_segctor_add_segments_to_be_freed(
525 NILFS_SC(sbi), buf, nmembs); 528 NILFS_SC(sbi), buf, nmembs);
526 nilfs_put_writer(nilfs);
527 529
528 return (ret < 0) ? ret : nmembs; 530 return (ret < 0) ? ret : nmembs;
529} 531}
diff --git a/fs/nilfs2/mdt.c b/fs/nilfs2/mdt.c
index 47dd815433fd..e1c6777931b7 100644
--- a/fs/nilfs2/mdt.c
+++ b/fs/nilfs2/mdt.c
@@ -77,19 +77,22 @@ static int nilfs_mdt_create_block(struct inode *inode, unsigned long block,
77 void *)) 77 void *))
78{ 78{
79 struct the_nilfs *nilfs = NILFS_MDT(inode)->mi_nilfs; 79 struct the_nilfs *nilfs = NILFS_MDT(inode)->mi_nilfs;
80 struct nilfs_sb_info *writer = NULL;
81 struct super_block *sb = inode->i_sb; 80 struct super_block *sb = inode->i_sb;
82 struct nilfs_transaction_info ti; 81 struct nilfs_transaction_info ti;
83 struct buffer_head *bh; 82 struct buffer_head *bh;
84 int err; 83 int err;
85 84
86 if (!sb) { 85 if (!sb) {
87 writer = nilfs_get_writer(nilfs); 86 /*
88 if (!writer) { 87 * Make sure this function is not called from any
88 * read-only context.
89 */
90 if (!nilfs->ns_writer) {
91 WARN_ON(1);
89 err = -EROFS; 92 err = -EROFS;
90 goto out; 93 goto out;
91 } 94 }
92 sb = writer->s_super; 95 sb = nilfs->ns_writer->s_super;
93 } 96 }
94 97
95 nilfs_transaction_begin(sb, &ti, 0); 98 nilfs_transaction_begin(sb, &ti, 0);
@@ -127,8 +130,6 @@ static int nilfs_mdt_create_block(struct inode *inode, unsigned long block,
127 err = nilfs_transaction_commit(sb); 130 err = nilfs_transaction_commit(sb);
128 else 131 else
129 nilfs_transaction_abort(sb); 132 nilfs_transaction_abort(sb);
130 if (writer)
131 nilfs_put_writer(nilfs);
132 out: 133 out:
133 return err; 134 return err;
134} 135}