ソースを参照

[XFS] Fix ABBA deadlock between i_mutex and iolock. Avoid calling
__blockdev_direct_IO for the DIO_OWN_LOCKING case for direct I/O reads
since it drops and reacquires the i_mutex while holding the iolock and
this violates the locking order.

SGI-PV: 955696
SGI-Modid: xfs-linux-melb:xfs-kern:26898a

Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
Signed-off-by: David Chatterton <chatz@sgi.com>

Lachlan McIlroy 18 年 前
コミット
721259bce2
2 ファイル変更19 行追加10 行削除
  1. 13 5
      fs/xfs/linux-2.6/xfs_aops.c
  2. 6 5
      fs/xfs/linux-2.6/xfs_lrw.c

+ 13 - 5
fs/xfs/linux-2.6/xfs_aops.c

@@ -1390,11 +1390,19 @@ xfs_vm_direct_IO(
 
 	iocb->private = xfs_alloc_ioend(inode, IOMAP_UNWRITTEN);
 
-	ret = blockdev_direct_IO_own_locking(rw, iocb, inode,
-		iomap.iomap_target->bt_bdev,
-		iov, offset, nr_segs,
-		xfs_get_blocks_direct,
-		xfs_end_io_direct);
+	if (rw == WRITE) {
+		ret = blockdev_direct_IO_own_locking(rw, iocb, inode,
+			iomap.iomap_target->bt_bdev,
+			iov, offset, nr_segs,
+			xfs_get_blocks_direct,
+			xfs_end_io_direct);
+	} else {
+		ret = blockdev_direct_IO_no_locking(rw, iocb, inode,
+			iomap.iomap_target->bt_bdev,
+			iov, offset, nr_segs,
+			xfs_get_blocks_direct,
+			xfs_end_io_direct);
+	}
 
 	if (unlikely(ret <= 0 && iocb->private))
 		xfs_destroy_ioend(iocb->private);

+ 6 - 5
fs/xfs/linux-2.6/xfs_lrw.c

@@ -264,7 +264,9 @@ xfs_read(
 					dmflags, &locktype);
 		if (ret) {
 			xfs_iunlock(ip, XFS_IOLOCK_SHARED);
-			goto unlock_mutex;
+			if (unlikely(ioflags & IO_ISDIRECT))
+				mutex_unlock(&inode->i_mutex);
+			return ret;
 		}
 	}
 
@@ -272,6 +274,9 @@ xfs_read(
 		bhv_vop_flushinval_pages(vp, ctooff(offtoct(*offset)),
 						-1, FI_REMAPF_LOCKED);
 
+	if (unlikely(ioflags & IO_ISDIRECT))
+		mutex_unlock(&inode->i_mutex);
+
 	xfs_rw_enter_trace(XFS_READ_ENTER, &ip->i_iocore,
 				(void *)iovp, segs, *offset, ioflags);
 	ret = __generic_file_aio_read(iocb, iovp, segs, offset);
@@ -281,10 +286,6 @@ xfs_read(
 		XFS_STATS_ADD(xs_read_bytes, ret);
 
 	xfs_iunlock(ip, XFS_IOLOCK_SHARED);
-
-unlock_mutex:
-	if (unlikely(ioflags & IO_ISDIRECT))
-		mutex_unlock(&inode->i_mutex);
 	return ret;
 }