diff options
Diffstat (limited to 'fs/ocfs2/journal.c')
-rw-r--r-- | fs/ocfs2/journal.c | 173 |
1 files changed, 148 insertions, 25 deletions
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c index 57d7d25a2b9a..a20a0f1e37fd 100644 --- a/fs/ocfs2/journal.c +++ b/fs/ocfs2/journal.c | |||
@@ -65,6 +65,11 @@ static int ocfs2_trylock_journal(struct ocfs2_super *osb, | |||
65 | static int ocfs2_recover_orphans(struct ocfs2_super *osb, | 65 | static int ocfs2_recover_orphans(struct ocfs2_super *osb, |
66 | int slot); | 66 | int slot); |
67 | static int ocfs2_commit_thread(void *arg); | 67 | static int ocfs2_commit_thread(void *arg); |
68 | static void ocfs2_queue_recovery_completion(struct ocfs2_journal *journal, | ||
69 | int slot_num, | ||
70 | struct ocfs2_dinode *la_dinode, | ||
71 | struct ocfs2_dinode *tl_dinode, | ||
72 | struct ocfs2_quota_recovery *qrec); | ||
68 | 73 | ||
69 | static inline int ocfs2_wait_on_mount(struct ocfs2_super *osb) | 74 | static inline int ocfs2_wait_on_mount(struct ocfs2_super *osb) |
70 | { | 75 | { |
@@ -76,18 +81,97 @@ static inline int ocfs2_wait_on_quotas(struct ocfs2_super *osb) | |||
76 | return __ocfs2_wait_on_mount(osb, 1); | 81 | return __ocfs2_wait_on_mount(osb, 1); |
77 | } | 82 | } |
78 | 83 | ||
79 | |||
80 | |||
81 | /* | 84 | /* |
82 | * The recovery_list is a simple linked list of node numbers to recover. | 85 | * This replay_map is to track online/offline slots, so we could recover |
83 | * It is protected by the recovery_lock. | 86 | * offline slots during recovery and mount |
84 | */ | 87 | */ |
85 | 88 | ||
86 | struct ocfs2_recovery_map { | 89 | enum ocfs2_replay_state { |
87 | unsigned int rm_used; | 90 | REPLAY_UNNEEDED = 0, /* Replay is not needed, so ignore this map */ |
88 | unsigned int *rm_entries; | 91 | REPLAY_NEEDED, /* Replay slots marked in rm_replay_slots */ |
92 | REPLAY_DONE /* Replay was already queued */ | ||
89 | }; | 93 | }; |
90 | 94 | ||
95 | struct ocfs2_replay_map { | ||
96 | unsigned int rm_slots; | ||
97 | enum ocfs2_replay_state rm_state; | ||
98 | unsigned char rm_replay_slots[0]; | ||
99 | }; | ||
100 | |||
101 | void ocfs2_replay_map_set_state(struct ocfs2_super *osb, int state) | ||
102 | { | ||
103 | if (!osb->replay_map) | ||
104 | return; | ||
105 | |||
106 | /* If we've already queued the replay, we don't have any more to do */ | ||
107 | if (osb->replay_map->rm_state == REPLAY_DONE) | ||
108 | return; | ||
109 | |||
110 | osb->replay_map->rm_state = state; | ||
111 | } | ||
112 | |||
113 | int ocfs2_compute_replay_slots(struct ocfs2_super *osb) | ||
114 | { | ||
115 | struct ocfs2_replay_map *replay_map; | ||
116 | int i, node_num; | ||
117 | |||
118 | /* If replay map is already set, we don't do it again */ | ||
119 | if (osb->replay_map) | ||
120 | return 0; | ||
121 | |||
122 | replay_map = kzalloc(sizeof(struct ocfs2_replay_map) + | ||
123 | (osb->max_slots * sizeof(char)), GFP_KERNEL); | ||
124 | |||
125 | if (!replay_map) { | ||
126 | mlog_errno(-ENOMEM); | ||
127 | return -ENOMEM; | ||
128 | } | ||
129 | |||
130 | spin_lock(&osb->osb_lock); | ||
131 | |||
132 | replay_map->rm_slots = osb->max_slots; | ||
133 | replay_map->rm_state = REPLAY_UNNEEDED; | ||
134 | |||
135 | /* set rm_replay_slots for offline slot(s) */ | ||
136 | for (i = 0; i < replay_map->rm_slots; i++) { | ||
137 | if (ocfs2_slot_to_node_num_locked(osb, i, &node_num) == -ENOENT) | ||
138 | replay_map->rm_replay_slots[i] = 1; | ||
139 | } | ||
140 | |||
141 | osb->replay_map = replay_map; | ||
142 | spin_unlock(&osb->osb_lock); | ||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | void ocfs2_queue_replay_slots(struct ocfs2_super *osb) | ||
147 | { | ||
148 | struct ocfs2_replay_map *replay_map = osb->replay_map; | ||
149 | int i; | ||
150 | |||
151 | if (!replay_map) | ||
152 | return; | ||
153 | |||
154 | if (replay_map->rm_state != REPLAY_NEEDED) | ||
155 | return; | ||
156 | |||
157 | for (i = 0; i < replay_map->rm_slots; i++) | ||
158 | if (replay_map->rm_replay_slots[i]) | ||
159 | ocfs2_queue_recovery_completion(osb->journal, i, NULL, | ||
160 | NULL, NULL); | ||
161 | replay_map->rm_state = REPLAY_DONE; | ||
162 | } | ||
163 | |||
164 | void ocfs2_free_replay_slots(struct ocfs2_super *osb) | ||
165 | { | ||
166 | struct ocfs2_replay_map *replay_map = osb->replay_map; | ||
167 | |||
168 | if (!osb->replay_map) | ||
169 | return; | ||
170 | |||
171 | kfree(replay_map); | ||
172 | osb->replay_map = NULL; | ||
173 | } | ||
174 | |||
91 | int ocfs2_recovery_init(struct ocfs2_super *osb) | 175 | int ocfs2_recovery_init(struct ocfs2_super *osb) |
92 | { | 176 | { |
93 | struct ocfs2_recovery_map *rm; | 177 | struct ocfs2_recovery_map *rm; |
@@ -496,6 +580,22 @@ static struct ocfs2_triggers dq_triggers = { | |||
496 | }, | 580 | }, |
497 | }; | 581 | }; |
498 | 582 | ||
583 | static struct ocfs2_triggers dr_triggers = { | ||
584 | .ot_triggers = { | ||
585 | .t_commit = ocfs2_commit_trigger, | ||
586 | .t_abort = ocfs2_abort_trigger, | ||
587 | }, | ||
588 | .ot_offset = offsetof(struct ocfs2_dx_root_block, dr_check), | ||
589 | }; | ||
590 | |||
591 | static struct ocfs2_triggers dl_triggers = { | ||
592 | .ot_triggers = { | ||
593 | .t_commit = ocfs2_commit_trigger, | ||
594 | .t_abort = ocfs2_abort_trigger, | ||
595 | }, | ||
596 | .ot_offset = offsetof(struct ocfs2_dx_leaf, dl_check), | ||
597 | }; | ||
598 | |||
499 | static int __ocfs2_journal_access(handle_t *handle, | 599 | static int __ocfs2_journal_access(handle_t *handle, |
500 | struct inode *inode, | 600 | struct inode *inode, |
501 | struct buffer_head *bh, | 601 | struct buffer_head *bh, |
@@ -600,6 +700,20 @@ int ocfs2_journal_access_dq(handle_t *handle, struct inode *inode, | |||
600 | type); | 700 | type); |
601 | } | 701 | } |
602 | 702 | ||
703 | int ocfs2_journal_access_dr(handle_t *handle, struct inode *inode, | ||
704 | struct buffer_head *bh, int type) | ||
705 | { | ||
706 | return __ocfs2_journal_access(handle, inode, bh, &dr_triggers, | ||
707 | type); | ||
708 | } | ||
709 | |||
710 | int ocfs2_journal_access_dl(handle_t *handle, struct inode *inode, | ||
711 | struct buffer_head *bh, int type) | ||
712 | { | ||
713 | return __ocfs2_journal_access(handle, inode, bh, &dl_triggers, | ||
714 | type); | ||
715 | } | ||
716 | |||
603 | int ocfs2_journal_access(handle_t *handle, struct inode *inode, | 717 | int ocfs2_journal_access(handle_t *handle, struct inode *inode, |
604 | struct buffer_head *bh, int type) | 718 | struct buffer_head *bh, int type) |
605 | { | 719 | { |
@@ -1176,24 +1290,24 @@ static void ocfs2_queue_recovery_completion(struct ocfs2_journal *journal, | |||
1176 | } | 1290 | } |
1177 | 1291 | ||
1178 | /* Called by the mount code to queue recovery the last part of | 1292 | /* Called by the mount code to queue recovery the last part of |
1179 | * recovery for it's own slot. */ | 1293 | * recovery for it's own and offline slot(s). */ |
1180 | void ocfs2_complete_mount_recovery(struct ocfs2_super *osb) | 1294 | void ocfs2_complete_mount_recovery(struct ocfs2_super *osb) |
1181 | { | 1295 | { |
1182 | struct ocfs2_journal *journal = osb->journal; | 1296 | struct ocfs2_journal *journal = osb->journal; |
1183 | 1297 | ||
1184 | if (osb->dirty) { | 1298 | /* No need to queue up our truncate_log as regular cleanup will catch |
1185 | /* No need to queue up our truncate_log as regular | 1299 | * that */ |
1186 | * cleanup will catch that. */ | 1300 | ocfs2_queue_recovery_completion(journal, osb->slot_num, |
1187 | ocfs2_queue_recovery_completion(journal, | 1301 | osb->local_alloc_copy, NULL, NULL); |
1188 | osb->slot_num, | 1302 | ocfs2_schedule_truncate_log_flush(osb, 0); |
1189 | osb->local_alloc_copy, | ||
1190 | NULL, | ||
1191 | NULL); | ||
1192 | ocfs2_schedule_truncate_log_flush(osb, 0); | ||
1193 | 1303 | ||
1194 | osb->local_alloc_copy = NULL; | 1304 | osb->local_alloc_copy = NULL; |
1195 | osb->dirty = 0; | 1305 | osb->dirty = 0; |
1196 | } | 1306 | |
1307 | /* queue to recover orphan slots for all offline slots */ | ||
1308 | ocfs2_replay_map_set_state(osb, REPLAY_NEEDED); | ||
1309 | ocfs2_queue_replay_slots(osb); | ||
1310 | ocfs2_free_replay_slots(osb); | ||
1197 | } | 1311 | } |
1198 | 1312 | ||
1199 | void ocfs2_complete_quota_recovery(struct ocfs2_super *osb) | 1313 | void ocfs2_complete_quota_recovery(struct ocfs2_super *osb) |
@@ -1236,6 +1350,14 @@ restart: | |||
1236 | goto bail; | 1350 | goto bail; |
1237 | } | 1351 | } |
1238 | 1352 | ||
1353 | status = ocfs2_compute_replay_slots(osb); | ||
1354 | if (status < 0) | ||
1355 | mlog_errno(status); | ||
1356 | |||
1357 | /* queue recovery for our own slot */ | ||
1358 | ocfs2_queue_recovery_completion(osb->journal, osb->slot_num, NULL, | ||
1359 | NULL, NULL); | ||
1360 | |||
1239 | spin_lock(&osb->osb_lock); | 1361 | spin_lock(&osb->osb_lock); |
1240 | while (rm->rm_used) { | 1362 | while (rm->rm_used) { |
1241 | /* It's always safe to remove entry zero, as we won't | 1363 | /* It's always safe to remove entry zero, as we won't |
@@ -1301,11 +1423,8 @@ skip_recovery: | |||
1301 | 1423 | ||
1302 | ocfs2_super_unlock(osb, 1); | 1424 | ocfs2_super_unlock(osb, 1); |
1303 | 1425 | ||
1304 | /* We always run recovery on our own orphan dir - the dead | 1426 | /* queue recovery for offline slots */ |
1305 | * node(s) may have disallowd a previos inode delete. Re-processing | 1427 | ocfs2_queue_replay_slots(osb); |
1306 | * is therefore required. */ | ||
1307 | ocfs2_queue_recovery_completion(osb->journal, osb->slot_num, NULL, | ||
1308 | NULL, NULL); | ||
1309 | 1428 | ||
1310 | bail: | 1429 | bail: |
1311 | mutex_lock(&osb->recovery_lock); | 1430 | mutex_lock(&osb->recovery_lock); |
@@ -1314,6 +1433,7 @@ bail: | |||
1314 | goto restart; | 1433 | goto restart; |
1315 | } | 1434 | } |
1316 | 1435 | ||
1436 | ocfs2_free_replay_slots(osb); | ||
1317 | osb->recovery_thread_task = NULL; | 1437 | osb->recovery_thread_task = NULL; |
1318 | mb(); /* sync with ocfs2_recovery_thread_running */ | 1438 | mb(); /* sync with ocfs2_recovery_thread_running */ |
1319 | wake_up(&osb->recovery_event); | 1439 | wake_up(&osb->recovery_event); |
@@ -1465,6 +1585,9 @@ static int ocfs2_replay_journal(struct ocfs2_super *osb, | |||
1465 | goto done; | 1585 | goto done; |
1466 | } | 1586 | } |
1467 | 1587 | ||
1588 | /* we need to run complete recovery for offline orphan slots */ | ||
1589 | ocfs2_replay_map_set_state(osb, REPLAY_NEEDED); | ||
1590 | |||
1468 | mlog(ML_NOTICE, "Recovering node %d from slot %d on device (%u,%u)\n", | 1591 | mlog(ML_NOTICE, "Recovering node %d from slot %d on device (%u,%u)\n", |
1469 | node_num, slot_num, | 1592 | node_num, slot_num, |
1470 | MAJOR(osb->sb->s_dev), MINOR(osb->sb->s_dev)); | 1593 | MAJOR(osb->sb->s_dev), MINOR(osb->sb->s_dev)); |