aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--fs/xfs/xfs_aops.c30
-rw-r--r--fs/xfs/xfs_iomap.c45
2 files changed, 45 insertions, 30 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) {
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
index 71a464503c43..47e714a7bf92 100644
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -142,11 +142,7 @@ xfs_iomap_write_direct(
142 int committed; 142 int committed;
143 int error; 143 int error;
144 144
145 /* 145 error = xfs_qm_dqattach(ip, 0);
146 * Make sure that the dquots are there. This doesn't hold
147 * the ilock across a disk read.
148 */
149 error = xfs_qm_dqattach_locked(ip, 0);
150 if (error) 146 if (error)
151 return XFS_ERROR(error); 147 return XFS_ERROR(error);
152 148
@@ -158,7 +154,7 @@ xfs_iomap_write_direct(
158 if ((offset + count) > XFS_ISIZE(ip)) { 154 if ((offset + count) > XFS_ISIZE(ip)) {
159 error = xfs_iomap_eof_align_last_fsb(mp, ip, extsz, &last_fsb); 155 error = xfs_iomap_eof_align_last_fsb(mp, ip, extsz, &last_fsb);
160 if (error) 156 if (error)
161 goto error_out; 157 return XFS_ERROR(error);
162 } else { 158 } else {
163 if (nmaps && (imap->br_startblock == HOLESTARTBLOCK)) 159 if (nmaps && (imap->br_startblock == HOLESTARTBLOCK))
164 last_fsb = MIN(last_fsb, (xfs_fileoff_t) 160 last_fsb = MIN(last_fsb, (xfs_fileoff_t)
@@ -190,7 +186,6 @@ xfs_iomap_write_direct(
190 /* 186 /*
191 * Allocate and setup the transaction 187 * Allocate and setup the transaction
192 */ 188 */
193 xfs_iunlock(ip, XFS_ILOCK_EXCL);
194 tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT); 189 tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT);
195 error = xfs_trans_reserve(tp, resblks, 190 error = xfs_trans_reserve(tp, resblks,
196 XFS_WRITE_LOG_RES(mp), resrtextents, 191 XFS_WRITE_LOG_RES(mp), resrtextents,
@@ -199,15 +194,16 @@ xfs_iomap_write_direct(
199 /* 194 /*
200 * Check for running out of space, note: need lock to return 195 * Check for running out of space, note: need lock to return
201 */ 196 */
202 if (error) 197 if (error) {
203 xfs_trans_cancel(tp, 0); 198 xfs_trans_cancel(tp, 0);
199 return XFS_ERROR(error);
200 }
201
204 xfs_ilock(ip, XFS_ILOCK_EXCL); 202 xfs_ilock(ip, XFS_ILOCK_EXCL);
205 if (error)
206 goto error_out;
207 203
208 error = xfs_trans_reserve_quota_nblks(tp, ip, qblocks, 0, quota_flag); 204 error = xfs_trans_reserve_quota_nblks(tp, ip, qblocks, 0, quota_flag);
209 if (error) 205 if (error)
210 goto error1; 206 goto out_trans_cancel;
211 207
212 xfs_trans_ijoin(tp, ip, 0); 208 xfs_trans_ijoin(tp, ip, 0);
213 209
@@ -224,42 +220,39 @@ xfs_iomap_write_direct(
224 error = xfs_bmapi_write(tp, ip, offset_fsb, count_fsb, bmapi_flag, 220 error = xfs_bmapi_write(tp, ip, offset_fsb, count_fsb, bmapi_flag,
225 &firstfsb, 0, imap, &nimaps, &free_list); 221 &firstfsb, 0, imap, &nimaps, &free_list);
226 if (error) 222 if (error)
227 goto error0; 223 goto out_bmap_cancel;
228 224
229 /* 225 /*
230 * Complete the transaction 226 * Complete the transaction
231 */ 227 */
232 error = xfs_bmap_finish(&tp, &free_list, &committed); 228 error = xfs_bmap_finish(&tp, &free_list, &committed);
233 if (error) 229 if (error)
234 goto error0; 230 goto out_bmap_cancel;
235 error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); 231 error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
236 if (error) 232 if (error)
237 goto error_out; 233 goto out_unlock;
238 234
239 /* 235 /*
240 * Copy any maps to caller's array and return any error. 236 * Copy any maps to caller's array and return any error.
241 */ 237 */
242 if (nimaps == 0) { 238 if (nimaps == 0) {
243 error = ENOSPC; 239 error = XFS_ERROR(ENOSPC);
244 goto error_out; 240 goto out_unlock;
245 } 241 }
246 242
247 if (!(imap->br_startblock || XFS_IS_REALTIME_INODE(ip))) { 243 if (!(imap->br_startblock || XFS_IS_REALTIME_INODE(ip)))
248 error = xfs_alert_fsblock_zero(ip, imap); 244 error = xfs_alert_fsblock_zero(ip, imap);
249 goto error_out;
250 }
251 245
252 return 0; 246out_unlock:
247 xfs_iunlock(ip, XFS_ILOCK_EXCL);
248 return error;
253 249
254error0: /* Cancel bmap, unlock inode, unreserve quota blocks, cancel trans */ 250out_bmap_cancel:
255 xfs_bmap_cancel(&free_list); 251 xfs_bmap_cancel(&free_list);
256 xfs_trans_unreserve_quota_nblks(tp, ip, qblocks, 0, quota_flag); 252 xfs_trans_unreserve_quota_nblks(tp, ip, qblocks, 0, quota_flag);
257 253out_trans_cancel:
258error1: /* Just cancel transaction */
259 xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); 254 xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
260 255 goto out_unlock;
261error_out:
262 return XFS_ERROR(error);
263} 256}
264 257
265/* 258/*