diff options
-rw-r--r-- | fs/nilfs2/segbuf.c | 16 | ||||
-rw-r--r-- | fs/nilfs2/segbuf.h | 2 | ||||
-rw-r--r-- | fs/nilfs2/segment.c | 240 | ||||
-rw-r--r-- | fs/nilfs2/segment.h | 2 |
4 files changed, 165 insertions, 95 deletions
diff --git a/fs/nilfs2/segbuf.c b/fs/nilfs2/segbuf.c index d856d62bf886..645c78656aa0 100644 --- a/fs/nilfs2/segbuf.c +++ b/fs/nilfs2/segbuf.c | |||
@@ -100,6 +100,22 @@ void nilfs_segbuf_map(struct nilfs_segment_buffer *segbuf, __u64 segnum, | |||
100 | segbuf->sb_fseg_end - segbuf->sb_pseg_start + 1; | 100 | segbuf->sb_fseg_end - segbuf->sb_pseg_start + 1; |
101 | } | 101 | } |
102 | 102 | ||
103 | /** | ||
104 | * nilfs_segbuf_map_cont - map a new log behind a given log | ||
105 | * @segbuf: new segment buffer | ||
106 | * @prev: segment buffer containing a log to be continued | ||
107 | */ | ||
108 | void nilfs_segbuf_map_cont(struct nilfs_segment_buffer *segbuf, | ||
109 | struct nilfs_segment_buffer *prev) | ||
110 | { | ||
111 | segbuf->sb_segnum = prev->sb_segnum; | ||
112 | segbuf->sb_fseg_start = prev->sb_fseg_start; | ||
113 | segbuf->sb_fseg_end = prev->sb_fseg_end; | ||
114 | segbuf->sb_pseg_start = prev->sb_pseg_start + prev->sb_sum.nblocks; | ||
115 | segbuf->sb_rest_blocks = | ||
116 | segbuf->sb_fseg_end - segbuf->sb_pseg_start + 1; | ||
117 | } | ||
118 | |||
103 | void nilfs_segbuf_set_next_segnum(struct nilfs_segment_buffer *segbuf, | 119 | void nilfs_segbuf_set_next_segnum(struct nilfs_segment_buffer *segbuf, |
104 | __u64 nextnum, struct the_nilfs *nilfs) | 120 | __u64 nextnum, struct the_nilfs *nilfs) |
105 | { | 121 | { |
diff --git a/fs/nilfs2/segbuf.h b/fs/nilfs2/segbuf.h index 7fbaf5eee016..6af1630fb401 100644 --- a/fs/nilfs2/segbuf.h +++ b/fs/nilfs2/segbuf.h | |||
@@ -128,6 +128,8 @@ struct nilfs_segment_buffer *nilfs_segbuf_new(struct super_block *); | |||
128 | void nilfs_segbuf_free(struct nilfs_segment_buffer *); | 128 | void nilfs_segbuf_free(struct nilfs_segment_buffer *); |
129 | void nilfs_segbuf_map(struct nilfs_segment_buffer *, __u64, unsigned long, | 129 | void nilfs_segbuf_map(struct nilfs_segment_buffer *, __u64, unsigned long, |
130 | struct the_nilfs *); | 130 | struct the_nilfs *); |
131 | void nilfs_segbuf_map_cont(struct nilfs_segment_buffer *segbuf, | ||
132 | struct nilfs_segment_buffer *prev); | ||
131 | void nilfs_segbuf_set_next_segnum(struct nilfs_segment_buffer *, __u64, | 133 | void nilfs_segbuf_set_next_segnum(struct nilfs_segment_buffer *, __u64, |
132 | struct the_nilfs *); | 134 | struct the_nilfs *); |
133 | int nilfs_segbuf_reset(struct nilfs_segment_buffer *, unsigned, time_t); | 135 | int nilfs_segbuf_reset(struct nilfs_segment_buffer *, unsigned, time_t); |
diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index 689deb9d41d1..17584c524486 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c | |||
@@ -1273,48 +1273,69 @@ static int nilfs_segctor_collect_blocks(struct nilfs_sc_info *sci, int mode) | |||
1273 | return err; | 1273 | return err; |
1274 | } | 1274 | } |
1275 | 1275 | ||
1276 | /** | ||
1277 | * nilfs_segctor_begin_construction - setup segment buffer to make a new log | ||
1278 | * @sci: nilfs_sc_info | ||
1279 | * @nilfs: nilfs object | ||
1280 | */ | ||
1276 | static int nilfs_segctor_begin_construction(struct nilfs_sc_info *sci, | 1281 | static int nilfs_segctor_begin_construction(struct nilfs_sc_info *sci, |
1277 | struct the_nilfs *nilfs) | 1282 | struct the_nilfs *nilfs) |
1278 | { | 1283 | { |
1279 | struct nilfs_segment_buffer *segbuf; | 1284 | struct nilfs_segment_buffer *segbuf, *prev; |
1280 | __u64 nextnum; | 1285 | __u64 nextnum; |
1281 | int err; | 1286 | int err, alloc = 0; |
1282 | 1287 | ||
1283 | if (list_empty(&sci->sc_segbufs)) { | 1288 | segbuf = nilfs_segbuf_new(sci->sc_super); |
1284 | segbuf = nilfs_segbuf_new(sci->sc_super); | 1289 | if (unlikely(!segbuf)) |
1285 | if (unlikely(!segbuf)) | 1290 | return -ENOMEM; |
1286 | return -ENOMEM; | ||
1287 | list_add(&segbuf->sb_list, &sci->sc_segbufs); | ||
1288 | } else | ||
1289 | segbuf = NILFS_FIRST_SEGBUF(&sci->sc_segbufs); | ||
1290 | 1291 | ||
1291 | nilfs_segbuf_map(segbuf, nilfs->ns_segnum, nilfs->ns_pseg_offset, | 1292 | if (list_empty(&sci->sc_write_logs)) { |
1292 | nilfs); | 1293 | nilfs_segbuf_map(segbuf, nilfs->ns_segnum, |
1294 | nilfs->ns_pseg_offset, nilfs); | ||
1295 | if (segbuf->sb_rest_blocks < NILFS_PSEG_MIN_BLOCKS) { | ||
1296 | nilfs_shift_to_next_segment(nilfs); | ||
1297 | nilfs_segbuf_map(segbuf, nilfs->ns_segnum, 0, nilfs); | ||
1298 | } | ||
1293 | 1299 | ||
1294 | if (segbuf->sb_rest_blocks < NILFS_PSEG_MIN_BLOCKS) { | 1300 | segbuf->sb_sum.seg_seq = nilfs->ns_seg_seq; |
1295 | nilfs_shift_to_next_segment(nilfs); | 1301 | nextnum = nilfs->ns_nextnum; |
1296 | nilfs_segbuf_map(segbuf, nilfs->ns_segnum, 0, nilfs); | 1302 | |
1303 | if (nilfs->ns_segnum == nilfs->ns_nextnum) | ||
1304 | /* Start from the head of a new full segment */ | ||
1305 | alloc++; | ||
1306 | } else { | ||
1307 | /* Continue logs */ | ||
1308 | prev = NILFS_LAST_SEGBUF(&sci->sc_write_logs); | ||
1309 | nilfs_segbuf_map_cont(segbuf, prev); | ||
1310 | segbuf->sb_sum.seg_seq = prev->sb_sum.seg_seq; | ||
1311 | nextnum = prev->sb_nextnum; | ||
1312 | |||
1313 | if (segbuf->sb_rest_blocks < NILFS_PSEG_MIN_BLOCKS) { | ||
1314 | nilfs_segbuf_map(segbuf, prev->sb_nextnum, 0, nilfs); | ||
1315 | segbuf->sb_sum.seg_seq++; | ||
1316 | alloc++; | ||
1317 | } | ||
1297 | } | 1318 | } |
1298 | sci->sc_segbuf_nblocks = segbuf->sb_rest_blocks; | ||
1299 | 1319 | ||
1300 | err = nilfs_sufile_mark_dirty(nilfs->ns_sufile, segbuf->sb_segnum); | 1320 | err = nilfs_sufile_mark_dirty(nilfs->ns_sufile, segbuf->sb_segnum); |
1301 | if (unlikely(err)) | 1321 | if (err) |
1302 | return err; | 1322 | goto failed; |
1303 | 1323 | ||
1304 | if (nilfs->ns_segnum == nilfs->ns_nextnum) { | 1324 | if (alloc) { |
1305 | /* Start from the head of a new full segment */ | ||
1306 | err = nilfs_sufile_alloc(nilfs->ns_sufile, &nextnum); | 1325 | err = nilfs_sufile_alloc(nilfs->ns_sufile, &nextnum); |
1307 | if (unlikely(err)) | 1326 | if (err) |
1308 | return err; | 1327 | goto failed; |
1309 | } else | 1328 | } |
1310 | nextnum = nilfs->ns_nextnum; | ||
1311 | |||
1312 | segbuf->sb_sum.seg_seq = nilfs->ns_seg_seq; | ||
1313 | nilfs_segbuf_set_next_segnum(segbuf, nextnum, nilfs); | 1329 | nilfs_segbuf_set_next_segnum(segbuf, nextnum, nilfs); |
1314 | 1330 | ||
1315 | /* truncating segment buffers */ | 1331 | BUG_ON(!list_empty(&sci->sc_segbufs)); |
1316 | nilfs_truncate_logs(&sci->sc_segbufs, segbuf); | 1332 | list_add_tail(&segbuf->sb_list, &sci->sc_segbufs); |
1333 | sci->sc_segbuf_nblocks = segbuf->sb_rest_blocks; | ||
1317 | return 0; | 1334 | return 0; |
1335 | |||
1336 | failed: | ||
1337 | nilfs_segbuf_free(segbuf); | ||
1338 | return err; | ||
1318 | } | 1339 | } |
1319 | 1340 | ||
1320 | static int nilfs_segctor_extend_segments(struct nilfs_sc_info *sci, | 1341 | static int nilfs_segctor_extend_segments(struct nilfs_sc_info *sci, |
@@ -1373,15 +1394,16 @@ static int nilfs_segctor_extend_segments(struct nilfs_sc_info *sci, | |||
1373 | return err; | 1394 | return err; |
1374 | } | 1395 | } |
1375 | 1396 | ||
1376 | static void nilfs_segctor_free_incomplete_segments(struct nilfs_sc_info *sci, | 1397 | static void nilfs_free_incomplete_logs(struct list_head *logs, |
1377 | struct the_nilfs *nilfs) | 1398 | struct the_nilfs *nilfs) |
1378 | { | 1399 | { |
1379 | struct nilfs_segment_buffer *segbuf; | 1400 | struct nilfs_segment_buffer *segbuf, *prev; |
1401 | struct inode *sufile = nilfs->ns_sufile; | ||
1380 | int ret; | 1402 | int ret; |
1381 | 1403 | ||
1382 | segbuf = NILFS_FIRST_SEGBUF(&sci->sc_segbufs); | 1404 | segbuf = NILFS_FIRST_SEGBUF(logs); |
1383 | if (nilfs->ns_nextnum != segbuf->sb_nextnum) { | 1405 | if (nilfs->ns_nextnum != segbuf->sb_nextnum) { |
1384 | ret = nilfs_sufile_free(nilfs->ns_sufile, segbuf->sb_nextnum); | 1406 | ret = nilfs_sufile_free(sufile, segbuf->sb_nextnum); |
1385 | WARN_ON(ret); /* never fails */ | 1407 | WARN_ON(ret); /* never fails */ |
1386 | } | 1408 | } |
1387 | if (atomic_read(&segbuf->sb_err)) { | 1409 | if (atomic_read(&segbuf->sb_err)) { |
@@ -1395,34 +1417,18 @@ static void nilfs_segctor_free_incomplete_segments(struct nilfs_sc_info *sci, | |||
1395 | set_nilfs_discontinued(nilfs); | 1417 | set_nilfs_discontinued(nilfs); |
1396 | } | 1418 | } |
1397 | 1419 | ||
1398 | list_for_each_entry_continue(segbuf, &sci->sc_segbufs, sb_list) { | 1420 | prev = segbuf; |
1399 | ret = nilfs_sufile_free(nilfs->ns_sufile, segbuf->sb_nextnum); | 1421 | list_for_each_entry_continue(segbuf, logs, sb_list) { |
1400 | WARN_ON(ret); /* never fails */ | 1422 | if (prev->sb_nextnum != segbuf->sb_nextnum) { |
1423 | ret = nilfs_sufile_free(sufile, segbuf->sb_nextnum); | ||
1424 | WARN_ON(ret); /* never fails */ | ||
1425 | } | ||
1401 | if (atomic_read(&segbuf->sb_err) && | 1426 | if (atomic_read(&segbuf->sb_err) && |
1402 | segbuf->sb_segnum != nilfs->ns_nextnum) | 1427 | segbuf->sb_segnum != nilfs->ns_nextnum) |
1403 | /* Case 2: extended segment (!= next) failed */ | 1428 | /* Case 2: extended segment (!= next) failed */ |
1404 | nilfs_sufile_set_error(nilfs->ns_sufile, | 1429 | nilfs_sufile_set_error(sufile, segbuf->sb_segnum); |
1405 | segbuf->sb_segnum); | 1430 | prev = segbuf; |
1406 | } | ||
1407 | } | ||
1408 | |||
1409 | static void nilfs_segctor_end_construction(struct nilfs_sc_info *sci, | ||
1410 | struct the_nilfs *nilfs, int err) | ||
1411 | { | ||
1412 | if (unlikely(err)) { | ||
1413 | nilfs_segctor_free_incomplete_segments(sci, nilfs); | ||
1414 | if (sci->sc_stage.flags & NILFS_CF_SUFREED) { | ||
1415 | int ret; | ||
1416 | |||
1417 | ret = nilfs_sufile_cancel_freev(nilfs->ns_sufile, | ||
1418 | sci->sc_freesegs, | ||
1419 | sci->sc_nfreesegs, | ||
1420 | NULL); | ||
1421 | WARN_ON(ret); /* do not happen */ | ||
1422 | } | ||
1423 | } | 1431 | } |
1424 | nilfs_clear_logs(&sci->sc_segbufs); | ||
1425 | sci->sc_super_root = NULL; | ||
1426 | } | 1432 | } |
1427 | 1433 | ||
1428 | static void nilfs_segctor_update_segusage(struct nilfs_sc_info *sci, | 1434 | static void nilfs_segctor_update_segusage(struct nilfs_sc_info *sci, |
@@ -1442,19 +1448,18 @@ static void nilfs_segctor_update_segusage(struct nilfs_sc_info *sci, | |||
1442 | } | 1448 | } |
1443 | } | 1449 | } |
1444 | 1450 | ||
1445 | static void nilfs_segctor_cancel_segusage(struct nilfs_sc_info *sci, | 1451 | static void nilfs_cancel_segusage(struct list_head *logs, struct inode *sufile) |
1446 | struct inode *sufile) | ||
1447 | { | 1452 | { |
1448 | struct nilfs_segment_buffer *segbuf; | 1453 | struct nilfs_segment_buffer *segbuf; |
1449 | int ret; | 1454 | int ret; |
1450 | 1455 | ||
1451 | segbuf = NILFS_FIRST_SEGBUF(&sci->sc_segbufs); | 1456 | segbuf = NILFS_FIRST_SEGBUF(logs); |
1452 | ret = nilfs_sufile_set_segment_usage(sufile, segbuf->sb_segnum, | 1457 | ret = nilfs_sufile_set_segment_usage(sufile, segbuf->sb_segnum, |
1453 | segbuf->sb_pseg_start - | 1458 | segbuf->sb_pseg_start - |
1454 | segbuf->sb_fseg_start, 0); | 1459 | segbuf->sb_fseg_start, 0); |
1455 | WARN_ON(ret); /* always succeed because the segusage is dirty */ | 1460 | WARN_ON(ret); /* always succeed because the segusage is dirty */ |
1456 | 1461 | ||
1457 | list_for_each_entry_continue(segbuf, &sci->sc_segbufs, sb_list) { | 1462 | list_for_each_entry_continue(segbuf, logs, sb_list) { |
1458 | ret = nilfs_sufile_set_segment_usage(sufile, segbuf->sb_segnum, | 1463 | ret = nilfs_sufile_set_segment_usage(sufile, segbuf->sb_segnum, |
1459 | 0, 0); | 1464 | 0, 0); |
1460 | WARN_ON(ret); /* always succeed */ | 1465 | WARN_ON(ret); /* always succeed */ |
@@ -1760,17 +1765,15 @@ static int nilfs_segctor_write(struct nilfs_sc_info *sci, | |||
1760 | struct the_nilfs *nilfs) | 1765 | struct the_nilfs *nilfs) |
1761 | { | 1766 | { |
1762 | struct nilfs_segment_buffer *segbuf; | 1767 | struct nilfs_segment_buffer *segbuf; |
1763 | int err, res; | 1768 | int ret = 0; |
1764 | 1769 | ||
1765 | list_for_each_entry(segbuf, &sci->sc_segbufs, sb_list) { | 1770 | list_for_each_entry(segbuf, &sci->sc_segbufs, sb_list) { |
1766 | err = nilfs_segbuf_write(segbuf, nilfs); | 1771 | ret = nilfs_segbuf_write(segbuf, nilfs); |
1767 | 1772 | if (ret) | |
1768 | res = nilfs_segbuf_wait(segbuf); | 1773 | break; |
1769 | err = err ? : res; | ||
1770 | if (err) | ||
1771 | return err; | ||
1772 | } | 1774 | } |
1773 | return 0; | 1775 | list_splice_tail_init(&sci->sc_segbufs, &sci->sc_write_logs); |
1776 | return ret; | ||
1774 | } | 1777 | } |
1775 | 1778 | ||
1776 | static void __nilfs_end_page_io(struct page *page, int err) | 1779 | static void __nilfs_end_page_io(struct page *page, int err) |
@@ -1848,15 +1851,17 @@ static void nilfs_clear_copied_buffers(struct list_head *list, int err) | |||
1848 | } | 1851 | } |
1849 | } | 1852 | } |
1850 | 1853 | ||
1851 | static void nilfs_segctor_abort_write(struct nilfs_sc_info *sci, | 1854 | static void nilfs_abort_logs(struct list_head *logs, struct page *failed_page, |
1852 | struct page *failed_page, int err) | 1855 | struct buffer_head *bh_sr, int err) |
1853 | { | 1856 | { |
1854 | struct nilfs_segment_buffer *segbuf; | 1857 | struct nilfs_segment_buffer *segbuf; |
1855 | struct page *bd_page = NULL, *fs_page = NULL; | 1858 | struct page *bd_page = NULL, *fs_page = NULL; |
1859 | struct buffer_head *bh; | ||
1856 | 1860 | ||
1857 | list_for_each_entry(segbuf, &sci->sc_segbufs, sb_list) { | 1861 | if (list_empty(logs)) |
1858 | struct buffer_head *bh; | 1862 | return; |
1859 | 1863 | ||
1864 | list_for_each_entry(segbuf, logs, sb_list) { | ||
1860 | list_for_each_entry(bh, &segbuf->sb_segsum_buffers, | 1865 | list_for_each_entry(bh, &segbuf->sb_segsum_buffers, |
1861 | b_assoc_buffers) { | 1866 | b_assoc_buffers) { |
1862 | if (bh->b_page != bd_page) { | 1867 | if (bh->b_page != bd_page) { |
@@ -1868,7 +1873,7 @@ static void nilfs_segctor_abort_write(struct nilfs_sc_info *sci, | |||
1868 | 1873 | ||
1869 | list_for_each_entry(bh, &segbuf->sb_payload_buffers, | 1874 | list_for_each_entry(bh, &segbuf->sb_payload_buffers, |
1870 | b_assoc_buffers) { | 1875 | b_assoc_buffers) { |
1871 | if (bh == sci->sc_super_root) { | 1876 | if (bh == bh_sr) { |
1872 | if (bh->b_page != bd_page) { | 1877 | if (bh->b_page != bd_page) { |
1873 | end_page_writeback(bd_page); | 1878 | end_page_writeback(bd_page); |
1874 | bd_page = bh->b_page; | 1879 | bd_page = bh->b_page; |
@@ -1878,7 +1883,7 @@ static void nilfs_segctor_abort_write(struct nilfs_sc_info *sci, | |||
1878 | if (bh->b_page != fs_page) { | 1883 | if (bh->b_page != fs_page) { |
1879 | nilfs_end_page_io(fs_page, err); | 1884 | nilfs_end_page_io(fs_page, err); |
1880 | if (fs_page && fs_page == failed_page) | 1885 | if (fs_page && fs_page == failed_page) |
1881 | goto done; | 1886 | return; |
1882 | fs_page = bh->b_page; | 1887 | fs_page = bh->b_page; |
1883 | } | 1888 | } |
1884 | } | 1889 | } |
@@ -1887,8 +1892,34 @@ static void nilfs_segctor_abort_write(struct nilfs_sc_info *sci, | |||
1887 | end_page_writeback(bd_page); | 1892 | end_page_writeback(bd_page); |
1888 | 1893 | ||
1889 | nilfs_end_page_io(fs_page, err); | 1894 | nilfs_end_page_io(fs_page, err); |
1890 | done: | 1895 | } |
1896 | |||
1897 | static void nilfs_segctor_abort_construction(struct nilfs_sc_info *sci, | ||
1898 | struct the_nilfs *nilfs, int err) | ||
1899 | { | ||
1900 | LIST_HEAD(logs); | ||
1901 | int ret; | ||
1902 | |||
1903 | list_splice_tail_init(&sci->sc_write_logs, &logs); | ||
1904 | ret = nilfs_wait_on_logs(&logs); | ||
1905 | if (ret) | ||
1906 | nilfs_abort_logs(&logs, NULL, sci->sc_super_root, ret); | ||
1907 | |||
1908 | list_splice_tail_init(&sci->sc_segbufs, &logs); | ||
1909 | nilfs_cancel_segusage(&logs, nilfs->ns_sufile); | ||
1910 | nilfs_free_incomplete_logs(&logs, nilfs); | ||
1891 | nilfs_clear_copied_buffers(&sci->sc_copied_buffers, err); | 1911 | nilfs_clear_copied_buffers(&sci->sc_copied_buffers, err); |
1912 | |||
1913 | if (sci->sc_stage.flags & NILFS_CF_SUFREED) { | ||
1914 | ret = nilfs_sufile_cancel_freev(nilfs->ns_sufile, | ||
1915 | sci->sc_freesegs, | ||
1916 | sci->sc_nfreesegs, | ||
1917 | NULL); | ||
1918 | WARN_ON(ret); /* do not happen */ | ||
1919 | } | ||
1920 | |||
1921 | nilfs_destroy_logs(&logs); | ||
1922 | sci->sc_super_root = NULL; | ||
1892 | } | 1923 | } |
1893 | 1924 | ||
1894 | static void nilfs_set_next_segment(struct the_nilfs *nilfs, | 1925 | static void nilfs_set_next_segment(struct the_nilfs *nilfs, |
@@ -1910,7 +1941,7 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci) | |||
1910 | struct the_nilfs *nilfs = sbi->s_nilfs; | 1941 | struct the_nilfs *nilfs = sbi->s_nilfs; |
1911 | int update_sr = (sci->sc_super_root != NULL); | 1942 | int update_sr = (sci->sc_super_root != NULL); |
1912 | 1943 | ||
1913 | list_for_each_entry(segbuf, &sci->sc_segbufs, sb_list) { | 1944 | list_for_each_entry(segbuf, &sci->sc_write_logs, sb_list) { |
1914 | struct buffer_head *bh; | 1945 | struct buffer_head *bh; |
1915 | 1946 | ||
1916 | list_for_each_entry(bh, &segbuf->sb_segsum_buffers, | 1947 | list_for_each_entry(bh, &segbuf->sb_segsum_buffers, |
@@ -1983,7 +2014,7 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci) | |||
1983 | 2014 | ||
1984 | sci->sc_nblk_inc += sci->sc_nblk_this_inc; | 2015 | sci->sc_nblk_inc += sci->sc_nblk_this_inc; |
1985 | 2016 | ||
1986 | segbuf = NILFS_LAST_SEGBUF(&sci->sc_segbufs); | 2017 | segbuf = NILFS_LAST_SEGBUF(&sci->sc_write_logs); |
1987 | nilfs_set_next_segment(nilfs, segbuf); | 2018 | nilfs_set_next_segment(nilfs, segbuf); |
1988 | 2019 | ||
1989 | if (update_sr) { | 2020 | if (update_sr) { |
@@ -1994,10 +2025,23 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci) | |||
1994 | clear_bit(NILFS_SC_HAVE_DELTA, &sci->sc_flags); | 2025 | clear_bit(NILFS_SC_HAVE_DELTA, &sci->sc_flags); |
1995 | clear_bit(NILFS_SC_DIRTY, &sci->sc_flags); | 2026 | clear_bit(NILFS_SC_DIRTY, &sci->sc_flags); |
1996 | set_bit(NILFS_SC_SUPER_ROOT, &sci->sc_flags); | 2027 | set_bit(NILFS_SC_SUPER_ROOT, &sci->sc_flags); |
2028 | nilfs_segctor_clear_metadata_dirty(sci); | ||
1997 | } else | 2029 | } else |
1998 | clear_bit(NILFS_SC_SUPER_ROOT, &sci->sc_flags); | 2030 | clear_bit(NILFS_SC_SUPER_ROOT, &sci->sc_flags); |
1999 | } | 2031 | } |
2000 | 2032 | ||
2033 | static int nilfs_segctor_wait(struct nilfs_sc_info *sci) | ||
2034 | { | ||
2035 | int ret; | ||
2036 | |||
2037 | ret = nilfs_wait_on_logs(&sci->sc_write_logs); | ||
2038 | if (!ret) { | ||
2039 | nilfs_segctor_complete_write(sci); | ||
2040 | nilfs_destroy_logs(&sci->sc_write_logs); | ||
2041 | } | ||
2042 | return ret; | ||
2043 | } | ||
2044 | |||
2001 | static int nilfs_segctor_check_in_files(struct nilfs_sc_info *sci, | 2045 | static int nilfs_segctor_check_in_files(struct nilfs_sc_info *sci, |
2002 | struct nilfs_sb_info *sbi) | 2046 | struct nilfs_sb_info *sbi) |
2003 | { | 2047 | { |
@@ -2110,7 +2154,7 @@ static int nilfs_segctor_do_construct(struct nilfs_sc_info *sci, int mode) | |||
2110 | /* Avoid empty segment */ | 2154 | /* Avoid empty segment */ |
2111 | if (sci->sc_stage.scnt == NILFS_ST_DONE && | 2155 | if (sci->sc_stage.scnt == NILFS_ST_DONE && |
2112 | NILFS_SEG_EMPTY(&sci->sc_curseg->sb_sum)) { | 2156 | NILFS_SEG_EMPTY(&sci->sc_curseg->sb_sum)) { |
2113 | nilfs_segctor_end_construction(sci, nilfs, 1); | 2157 | nilfs_segctor_abort_construction(sci, nilfs, 1); |
2114 | goto out; | 2158 | goto out; |
2115 | } | 2159 | } |
2116 | 2160 | ||
@@ -2124,7 +2168,7 @@ static int nilfs_segctor_do_construct(struct nilfs_sc_info *sci, int mode) | |||
2124 | if (has_sr) { | 2168 | if (has_sr) { |
2125 | err = nilfs_segctor_fill_in_checkpoint(sci); | 2169 | err = nilfs_segctor_fill_in_checkpoint(sci); |
2126 | if (unlikely(err)) | 2170 | if (unlikely(err)) |
2127 | goto failed_to_make_up; | 2171 | goto failed_to_write; |
2128 | 2172 | ||
2129 | nilfs_segctor_fill_in_super_root(sci, nilfs); | 2173 | nilfs_segctor_fill_in_super_root(sci, nilfs); |
2130 | } | 2174 | } |
@@ -2132,42 +2176,46 @@ static int nilfs_segctor_do_construct(struct nilfs_sc_info *sci, int mode) | |||
2132 | 2176 | ||
2133 | /* Write partial segments */ | 2177 | /* Write partial segments */ |
2134 | err = nilfs_segctor_prepare_write(sci, &failed_page); | 2178 | err = nilfs_segctor_prepare_write(sci, &failed_page); |
2135 | if (unlikely(err)) | 2179 | if (err) { |
2180 | nilfs_abort_logs(&sci->sc_segbufs, failed_page, | ||
2181 | sci->sc_super_root, err); | ||
2136 | goto failed_to_write; | 2182 | goto failed_to_write; |
2137 | 2183 | } | |
2138 | nilfs_segctor_fill_in_checksums(sci, nilfs->ns_crc_seed); | 2184 | nilfs_segctor_fill_in_checksums(sci, nilfs->ns_crc_seed); |
2139 | 2185 | ||
2140 | err = nilfs_segctor_write(sci, nilfs); | 2186 | err = nilfs_segctor_write(sci, nilfs); |
2141 | if (unlikely(err)) | 2187 | if (unlikely(err)) |
2142 | goto failed_to_write; | 2188 | goto failed_to_write; |
2143 | 2189 | ||
2144 | nilfs_segctor_complete_write(sci); | 2190 | if (sci->sc_stage.scnt == NILFS_ST_DONE || |
2145 | 2191 | nilfs->ns_blocksize_bits != PAGE_CACHE_SHIFT) { | |
2146 | /* Commit segments */ | 2192 | /* |
2147 | if (has_sr) | 2193 | * At this point, we avoid double buffering |
2148 | nilfs_segctor_clear_metadata_dirty(sci); | 2194 | * for blocksize < pagesize because page dirty |
2149 | 2195 | * flag is turned off during write and dirty | |
2150 | nilfs_segctor_end_construction(sci, nilfs, 0); | 2196 | * buffers are not properly collected for |
2151 | 2197 | * pages crossing over segments. | |
2198 | */ | ||
2199 | err = nilfs_segctor_wait(sci); | ||
2200 | if (err) | ||
2201 | goto failed_to_write; | ||
2202 | } | ||
2152 | } while (sci->sc_stage.scnt != NILFS_ST_DONE); | 2203 | } while (sci->sc_stage.scnt != NILFS_ST_DONE); |
2153 | 2204 | ||
2205 | sci->sc_super_root = NULL; | ||
2206 | |||
2154 | out: | 2207 | out: |
2155 | nilfs_destroy_logs(&sci->sc_segbufs); | ||
2156 | nilfs_segctor_check_out_files(sci, sbi); | 2208 | nilfs_segctor_check_out_files(sci, sbi); |
2157 | return err; | 2209 | return err; |
2158 | 2210 | ||
2159 | failed_to_write: | 2211 | failed_to_write: |
2160 | nilfs_segctor_abort_write(sci, failed_page, err); | ||
2161 | nilfs_segctor_cancel_segusage(sci, nilfs->ns_sufile); | ||
2162 | |||
2163 | failed_to_make_up: | ||
2164 | if (sci->sc_stage.flags & NILFS_CF_IFILE_STARTED) | 2212 | if (sci->sc_stage.flags & NILFS_CF_IFILE_STARTED) |
2165 | nilfs_redirty_inodes(&sci->sc_dirty_files); | 2213 | nilfs_redirty_inodes(&sci->sc_dirty_files); |
2166 | 2214 | ||
2167 | failed: | 2215 | failed: |
2168 | if (nilfs_doing_gc()) | 2216 | if (nilfs_doing_gc()) |
2169 | nilfs_redirty_inodes(&sci->sc_gc_inodes); | 2217 | nilfs_redirty_inodes(&sci->sc_gc_inodes); |
2170 | nilfs_segctor_end_construction(sci, nilfs, err); | 2218 | nilfs_segctor_abort_construction(sci, nilfs, err); |
2171 | goto out; | 2219 | goto out; |
2172 | } | 2220 | } |
2173 | 2221 | ||
@@ -2725,6 +2773,7 @@ static struct nilfs_sc_info *nilfs_segctor_new(struct nilfs_sb_info *sbi) | |||
2725 | spin_lock_init(&sci->sc_state_lock); | 2773 | spin_lock_init(&sci->sc_state_lock); |
2726 | INIT_LIST_HEAD(&sci->sc_dirty_files); | 2774 | INIT_LIST_HEAD(&sci->sc_dirty_files); |
2727 | INIT_LIST_HEAD(&sci->sc_segbufs); | 2775 | INIT_LIST_HEAD(&sci->sc_segbufs); |
2776 | INIT_LIST_HEAD(&sci->sc_write_logs); | ||
2728 | INIT_LIST_HEAD(&sci->sc_gc_inodes); | 2777 | INIT_LIST_HEAD(&sci->sc_gc_inodes); |
2729 | INIT_LIST_HEAD(&sci->sc_copied_buffers); | 2778 | INIT_LIST_HEAD(&sci->sc_copied_buffers); |
2730 | 2779 | ||
@@ -2792,6 +2841,7 @@ static void nilfs_segctor_destroy(struct nilfs_sc_info *sci) | |||
2792 | } | 2841 | } |
2793 | 2842 | ||
2794 | WARN_ON(!list_empty(&sci->sc_segbufs)); | 2843 | WARN_ON(!list_empty(&sci->sc_segbufs)); |
2844 | WARN_ON(!list_empty(&sci->sc_write_logs)); | ||
2795 | 2845 | ||
2796 | down_write(&sbi->s_nilfs->ns_segctor_sem); | 2846 | down_write(&sbi->s_nilfs->ns_segctor_sem); |
2797 | 2847 | ||
diff --git a/fs/nilfs2/segment.h b/fs/nilfs2/segment.h index 0d2a475a741b..3d3ab2f9864c 100644 --- a/fs/nilfs2/segment.h +++ b/fs/nilfs2/segment.h | |||
@@ -97,6 +97,7 @@ struct nilfs_segsum_pointer { | |||
97 | * @sc_dsync_start: start byte offset of data pages | 97 | * @sc_dsync_start: start byte offset of data pages |
98 | * @sc_dsync_end: end byte offset of data pages (inclusive) | 98 | * @sc_dsync_end: end byte offset of data pages (inclusive) |
99 | * @sc_segbufs: List of segment buffers | 99 | * @sc_segbufs: List of segment buffers |
100 | * @sc_write_logs: List of segment buffers to hold logs under writing | ||
100 | * @sc_segbuf_nblocks: Number of available blocks in segment buffers. | 101 | * @sc_segbuf_nblocks: Number of available blocks in segment buffers. |
101 | * @sc_curseg: Current segment buffer | 102 | * @sc_curseg: Current segment buffer |
102 | * @sc_super_root: Pointer to the super root buffer | 103 | * @sc_super_root: Pointer to the super root buffer |
@@ -143,6 +144,7 @@ struct nilfs_sc_info { | |||
143 | 144 | ||
144 | /* Segment buffers */ | 145 | /* Segment buffers */ |
145 | struct list_head sc_segbufs; | 146 | struct list_head sc_segbufs; |
147 | struct list_head sc_write_logs; | ||
146 | unsigned long sc_segbuf_nblocks; | 148 | unsigned long sc_segbuf_nblocks; |
147 | struct nilfs_segment_buffer *sc_curseg; | 149 | struct nilfs_segment_buffer *sc_curseg; |
148 | struct buffer_head *sc_super_root; | 150 | struct buffer_head *sc_super_root; |