aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_aops.c
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2012-03-27 10:34:50 -0400
committerBen Myers <bpm@sgi.com>2012-05-14 17:20:21 -0400
commit507630b29f13a3d8689895618b12015308402e22 (patch)
treec090f5d2592d6f453ab7dd0f2f61da2a7482e59a /fs/xfs/xfs_aops.c
parent193aec10504e4c24521449c46317282141fb36e8 (diff)
xfs: use shared ilock mode for direct IO writes by default
For the direct IO write path, we only really need the ilock to be taken in exclusive mode during IO submission if we need to do extent allocation instead of all the time. Change the block mapping code to take the ilock in shared mode for the initial block mapping, and only retake it exclusively when we actually have to perform extent allocations. We were already dropping the ilock for the transaction allocation, so this doesn't introduce new race windows. Based on an earlier patch from Dave Chinner. Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Mark Tinguely <tinguely@sgi.com> Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs/xfs/xfs_aops.c')
-rw-r--r--fs/xfs/xfs_aops.c30
1 files changed, 26 insertions, 4 deletions
diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c
index 0dbb9e70fe21..0fd7c2bfa402 100644
--- a/fs/xfs/xfs_aops.c
+++ b/fs/xfs/xfs_aops.c
@@ -1146,7 +1146,14 @@ __xfs_get_blocks(
1146 if (!create && direct && offset >= i_size_read(inode)) 1146 if (!create && direct && offset >= i_size_read(inode))
1147 return 0; 1147 return 0;
1148 1148
1149 if (create) { 1149 /*
1150 * Direct I/O is usually done on preallocated files, so try getting
1151 * a block mapping without an exclusive lock first. For buffered
1152 * writes we already have the exclusive iolock anyway, so avoiding
1153 * a lock roundtrip here by taking the ilock exclusive from the
1154 * beginning is a useful micro optimization.
1155 */
1156 if (create && !direct) {
1150 lockmode = XFS_ILOCK_EXCL; 1157 lockmode = XFS_ILOCK_EXCL;
1151 xfs_ilock(ip, lockmode); 1158 xfs_ilock(ip, lockmode);
1152 } else { 1159 } else {
@@ -1169,22 +1176,37 @@ __xfs_get_blocks(
1169 (imap.br_startblock == HOLESTARTBLOCK || 1176 (imap.br_startblock == HOLESTARTBLOCK ||
1170 imap.br_startblock == DELAYSTARTBLOCK))) { 1177 imap.br_startblock == DELAYSTARTBLOCK))) {
1171 if (direct) { 1178 if (direct) {
1179 /*
1180 * Drop the ilock in preparation for starting the block
1181 * allocation transaction. It will be retaken
1182 * exclusively inside xfs_iomap_write_direct for the
1183 * actual allocation.
1184 */
1185 xfs_iunlock(ip, lockmode);
1172 error = xfs_iomap_write_direct(ip, offset, size, 1186 error = xfs_iomap_write_direct(ip, offset, size,
1173 &imap, nimaps); 1187 &imap, nimaps);
1188 if (error)
1189 return -error;
1174 } else { 1190 } else {
1191 /*
1192 * Delalloc reservations do not require a transaction,
1193 * we can go on without dropping the lock here.
1194 */
1175 error = xfs_iomap_write_delay(ip, offset, size, &imap); 1195 error = xfs_iomap_write_delay(ip, offset, size, &imap);
1196 if (error)
1197 goto out_unlock;
1198
1199 xfs_iunlock(ip, lockmode);
1176 } 1200 }
1177 if (error)
1178 goto out_unlock;
1179 1201
1180 trace_xfs_get_blocks_alloc(ip, offset, size, 0, &imap); 1202 trace_xfs_get_blocks_alloc(ip, offset, size, 0, &imap);
1181 } else if (nimaps) { 1203 } else if (nimaps) {
1182 trace_xfs_get_blocks_found(ip, offset, size, 0, &imap); 1204 trace_xfs_get_blocks_found(ip, offset, size, 0, &imap);
1205 xfs_iunlock(ip, lockmode);
1183 } else { 1206 } else {
1184 trace_xfs_get_blocks_notfound(ip, offset, size); 1207 trace_xfs_get_blocks_notfound(ip, offset, size);
1185 goto out_unlock; 1208 goto out_unlock;
1186 } 1209 }
1187 xfs_iunlock(ip, lockmode);
1188 1210
1189 if (imap.br_startblock != HOLESTARTBLOCK && 1211 if (imap.br_startblock != HOLESTARTBLOCK &&
1190 imap.br_startblock != DELAYSTARTBLOCK) { 1212 imap.br_startblock != DELAYSTARTBLOCK) {