diff options
-rw-r--r-- | fs/ocfs2/aops.c | 120 |
1 files changed, 80 insertions, 40 deletions
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index 3e5758ebd932..fc723fb9c981 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c | |||
@@ -849,7 +849,7 @@ static void ocfs2_free_write_ctxt(struct ocfs2_write_ctxt *wc) | |||
849 | 849 | ||
850 | static int ocfs2_alloc_write_ctxt(struct ocfs2_write_ctxt **wcp, | 850 | static int ocfs2_alloc_write_ctxt(struct ocfs2_write_ctxt **wcp, |
851 | struct ocfs2_super *osb, loff_t pos, | 851 | struct ocfs2_super *osb, loff_t pos, |
852 | unsigned len) | 852 | unsigned len, struct buffer_head *di_bh) |
853 | { | 853 | { |
854 | struct ocfs2_write_ctxt *wc; | 854 | struct ocfs2_write_ctxt *wc; |
855 | 855 | ||
@@ -859,6 +859,8 @@ static int ocfs2_alloc_write_ctxt(struct ocfs2_write_ctxt **wcp, | |||
859 | 859 | ||
860 | wc->w_cpos = pos >> osb->s_clustersize_bits; | 860 | wc->w_cpos = pos >> osb->s_clustersize_bits; |
861 | wc->w_clen = ocfs2_clusters_for_bytes(osb->sb, len); | 861 | wc->w_clen = ocfs2_clusters_for_bytes(osb->sb, len); |
862 | get_bh(di_bh); | ||
863 | wc->w_di_bh = di_bh; | ||
862 | 864 | ||
863 | if (unlikely(PAGE_CACHE_SHIFT > osb->s_clustersize_bits)) | 865 | if (unlikely(PAGE_CACHE_SHIFT > osb->s_clustersize_bits)) |
864 | wc->w_large_pages = 1; | 866 | wc->w_large_pages = 1; |
@@ -1211,9 +1213,10 @@ static void ocfs2_set_target_boundaries(struct ocfs2_super *osb, | |||
1211 | } | 1213 | } |
1212 | } | 1214 | } |
1213 | 1215 | ||
1214 | int ocfs2_write_begin(struct file *file, struct address_space *mapping, | 1216 | static int ocfs2_write_begin_nolock(struct address_space *mapping, |
1215 | loff_t pos, unsigned len, unsigned flags, | 1217 | loff_t pos, unsigned len, unsigned flags, |
1216 | struct page **pagep, void **fsdata) | 1218 | struct page **pagep, void **fsdata, |
1219 | struct buffer_head *di_bh) | ||
1217 | { | 1220 | { |
1218 | int ret, i, credits = OCFS2_INODE_UPDATE_CREDITS; | 1221 | int ret, i, credits = OCFS2_INODE_UPDATE_CREDITS; |
1219 | unsigned int num_clusters = 0, clusters_to_alloc = 0; | 1222 | unsigned int num_clusters = 0, clusters_to_alloc = 0; |
@@ -1227,28 +1230,14 @@ int ocfs2_write_begin(struct file *file, struct address_space *mapping, | |||
1227 | handle_t *handle; | 1230 | handle_t *handle; |
1228 | struct ocfs2_write_cluster_desc *desc; | 1231 | struct ocfs2_write_cluster_desc *desc; |
1229 | 1232 | ||
1230 | ret = ocfs2_alloc_write_ctxt(&wc, osb, pos, len); | 1233 | ret = ocfs2_alloc_write_ctxt(&wc, osb, pos, len, di_bh); |
1231 | if (ret) { | 1234 | if (ret) { |
1232 | mlog_errno(ret); | 1235 | mlog_errno(ret); |
1233 | return ret; | 1236 | return ret; |
1234 | } | 1237 | } |
1235 | 1238 | ||
1236 | ret = ocfs2_meta_lock(inode, &wc->w_di_bh, 1); | ||
1237 | if (ret) { | ||
1238 | mlog_errno(ret); | ||
1239 | goto out; | ||
1240 | } | ||
1241 | di = (struct ocfs2_dinode *)wc->w_di_bh->b_data; | 1239 | di = (struct ocfs2_dinode *)wc->w_di_bh->b_data; |
1242 | 1240 | ||
1243 | /* | ||
1244 | * Take alloc sem here to prevent concurrent lookups. That way | ||
1245 | * the mapping, zeroing and tree manipulation within | ||
1246 | * ocfs2_write() will be safe against ->readpage(). This | ||
1247 | * should also serve to lock out allocation from a shared | ||
1248 | * writeable region. | ||
1249 | */ | ||
1250 | down_write(&OCFS2_I(inode)->ip_alloc_sem); | ||
1251 | |||
1252 | for (i = 0; i < wc->w_clen; i++) { | 1241 | for (i = 0; i < wc->w_clen; i++) { |
1253 | desc = &wc->w_desc[i]; | 1242 | desc = &wc->w_desc[i]; |
1254 | desc->c_cpos = wc->w_cpos + i; | 1243 | desc->c_cpos = wc->w_cpos + i; |
@@ -1258,7 +1247,7 @@ int ocfs2_write_begin(struct file *file, struct address_space *mapping, | |||
1258 | &num_clusters, NULL); | 1247 | &num_clusters, NULL); |
1259 | if (ret) { | 1248 | if (ret) { |
1260 | mlog_errno(ret); | 1249 | mlog_errno(ret); |
1261 | goto out_meta; | 1250 | goto out; |
1262 | } | 1251 | } |
1263 | } else if (phys) { | 1252 | } else if (phys) { |
1264 | /* | 1253 | /* |
@@ -1293,7 +1282,7 @@ int ocfs2_write_begin(struct file *file, struct address_space *mapping, | |||
1293 | &data_ac, &meta_ac); | 1282 | &data_ac, &meta_ac); |
1294 | if (ret) { | 1283 | if (ret) { |
1295 | mlog_errno(ret); | 1284 | mlog_errno(ret); |
1296 | goto out_meta; | 1285 | goto out; |
1297 | } | 1286 | } |
1298 | 1287 | ||
1299 | credits = ocfs2_calc_extend_credits(inode->i_sb, di, | 1288 | credits = ocfs2_calc_extend_credits(inode->i_sb, di, |
@@ -1303,17 +1292,11 @@ int ocfs2_write_begin(struct file *file, struct address_space *mapping, | |||
1303 | 1292 | ||
1304 | ocfs2_set_target_boundaries(osb, wc, pos, len, clusters_to_alloc); | 1293 | ocfs2_set_target_boundaries(osb, wc, pos, len, clusters_to_alloc); |
1305 | 1294 | ||
1306 | ret = ocfs2_data_lock(inode, 1); | ||
1307 | if (ret) { | ||
1308 | mlog_errno(ret); | ||
1309 | goto out_meta; | ||
1310 | } | ||
1311 | |||
1312 | handle = ocfs2_start_trans(osb, credits); | 1295 | handle = ocfs2_start_trans(osb, credits); |
1313 | if (IS_ERR(handle)) { | 1296 | if (IS_ERR(handle)) { |
1314 | ret = PTR_ERR(handle); | 1297 | ret = PTR_ERR(handle); |
1315 | mlog_errno(ret); | 1298 | mlog_errno(ret); |
1316 | goto out_data; | 1299 | goto out; |
1317 | } | 1300 | } |
1318 | 1301 | ||
1319 | wc->w_handle = handle; | 1302 | wc->w_handle = handle; |
@@ -1363,13 +1346,6 @@ int ocfs2_write_begin(struct file *file, struct address_space *mapping, | |||
1363 | out_commit: | 1346 | out_commit: |
1364 | ocfs2_commit_trans(osb, handle); | 1347 | ocfs2_commit_trans(osb, handle); |
1365 | 1348 | ||
1366 | out_data: | ||
1367 | ocfs2_data_unlock(inode, 1); | ||
1368 | |||
1369 | out_meta: | ||
1370 | up_write(&OCFS2_I(inode)->ip_alloc_sem); | ||
1371 | ocfs2_meta_unlock(inode, 1); | ||
1372 | |||
1373 | out: | 1349 | out: |
1374 | ocfs2_free_write_ctxt(wc); | 1350 | ocfs2_free_write_ctxt(wc); |
1375 | 1351 | ||
@@ -1380,9 +1356,60 @@ out: | |||
1380 | return ret; | 1356 | return ret; |
1381 | } | 1357 | } |
1382 | 1358 | ||
1383 | int ocfs2_write_end(struct file *file, struct address_space *mapping, | 1359 | int ocfs2_write_begin(struct file *file, struct address_space *mapping, |
1384 | loff_t pos, unsigned len, unsigned copied, | 1360 | loff_t pos, unsigned len, unsigned flags, |
1385 | struct page *page, void *fsdata) | 1361 | struct page **pagep, void **fsdata) |
1362 | { | ||
1363 | int ret; | ||
1364 | struct buffer_head *di_bh = NULL; | ||
1365 | struct inode *inode = mapping->host; | ||
1366 | |||
1367 | ret = ocfs2_meta_lock(inode, &di_bh, 1); | ||
1368 | if (ret) { | ||
1369 | mlog_errno(ret); | ||
1370 | return ret; | ||
1371 | } | ||
1372 | |||
1373 | /* | ||
1374 | * Take alloc sem here to prevent concurrent lookups. That way | ||
1375 | * the mapping, zeroing and tree manipulation within | ||
1376 | * ocfs2_write() will be safe against ->readpage(). This | ||
1377 | * should also serve to lock out allocation from a shared | ||
1378 | * writeable region. | ||
1379 | */ | ||
1380 | down_write(&OCFS2_I(inode)->ip_alloc_sem); | ||
1381 | |||
1382 | ret = ocfs2_data_lock(inode, 1); | ||
1383 | if (ret) { | ||
1384 | mlog_errno(ret); | ||
1385 | goto out_fail; | ||
1386 | } | ||
1387 | |||
1388 | ret = ocfs2_write_begin_nolock(mapping, pos, len, flags, pagep, | ||
1389 | fsdata, di_bh); | ||
1390 | if (ret) { | ||
1391 | mlog_errno(ret); | ||
1392 | goto out_fail_data; | ||
1393 | } | ||
1394 | |||
1395 | brelse(di_bh); | ||
1396 | |||
1397 | return 0; | ||
1398 | |||
1399 | out_fail_data: | ||
1400 | ocfs2_data_unlock(inode, 1); | ||
1401 | out_fail: | ||
1402 | up_write(&OCFS2_I(inode)->ip_alloc_sem); | ||
1403 | |||
1404 | brelse(di_bh); | ||
1405 | ocfs2_meta_unlock(inode, 1); | ||
1406 | |||
1407 | return ret; | ||
1408 | } | ||
1409 | |||
1410 | static int ocfs2_write_end_nolock(struct address_space *mapping, | ||
1411 | loff_t pos, unsigned len, unsigned copied, | ||
1412 | struct page *page, void *fsdata) | ||
1386 | { | 1413 | { |
1387 | int i; | 1414 | int i; |
1388 | unsigned from, to, start = pos & (PAGE_CACHE_SIZE - 1); | 1415 | unsigned from, to, start = pos & (PAGE_CACHE_SIZE - 1); |
@@ -1444,12 +1471,25 @@ int ocfs2_write_end(struct file *file, struct address_space *mapping, | |||
1444 | ocfs2_journal_dirty(handle, wc->w_di_bh); | 1471 | ocfs2_journal_dirty(handle, wc->w_di_bh); |
1445 | 1472 | ||
1446 | ocfs2_commit_trans(osb, handle); | 1473 | ocfs2_commit_trans(osb, handle); |
1474 | ocfs2_free_write_ctxt(wc); | ||
1475 | |||
1476 | return copied; | ||
1477 | } | ||
1478 | |||
1479 | int ocfs2_write_end(struct file *file, struct address_space *mapping, | ||
1480 | loff_t pos, unsigned len, unsigned copied, | ||
1481 | struct page *page, void *fsdata) | ||
1482 | { | ||
1483 | int ret; | ||
1484 | struct inode *inode = mapping->host; | ||
1485 | |||
1486 | ret = ocfs2_write_end_nolock(mapping, pos, len, copied, page, fsdata); | ||
1487 | |||
1447 | ocfs2_data_unlock(inode, 1); | 1488 | ocfs2_data_unlock(inode, 1); |
1448 | up_write(&OCFS2_I(inode)->ip_alloc_sem); | 1489 | up_write(&OCFS2_I(inode)->ip_alloc_sem); |
1449 | ocfs2_meta_unlock(inode, 1); | 1490 | ocfs2_meta_unlock(inode, 1); |
1450 | ocfs2_free_write_ctxt(wc); | ||
1451 | 1491 | ||
1452 | return copied; | 1492 | return ret; |
1453 | } | 1493 | } |
1454 | 1494 | ||
1455 | const struct address_space_operations ocfs2_aops = { | 1495 | const struct address_space_operations ocfs2_aops = { |