aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nilfs2/super.c
diff options
context:
space:
mode:
authorJiro SEKIBA <jir@unicus.jp>2010-06-28 04:49:33 -0400
committerRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>2010-07-22 21:02:11 -0400
commitb2ac86e1a8e3a3b0ab4449d062c582f07a078e7b (patch)
treeb681ea820685a278e06995ff23b58f7a85904b70 /fs/nilfs2/super.c
parentd26493b6f017c0b0063a15bf893411ddae85eee4 (diff)
nilfs2: sync super blocks in turns
This will sync super blocks in turns instead of syncing duplicate super blocks at the time. This will help searching valid super root when super block is written into disk before log is written, which is happen when barrier-less block devices are unmounted uncleanly. In the situation, old super block likely points to valid log. This patch introduces ns_sbwcount member to the nilfs object and adds nilfs_sb_will_flip() function; ns_sbwcount counts how many times super blocks write back to the disk. And, nilfs_sb_will_flip() decides whether flipping required or not based on the count of ns_sbwcount to sync super blocks asymmetrically. The following functions are also changed: - nilfs_prepare_super(): flips super blocks according to the argument. The argument is calculated by nilfs_sb_will_flip() function. - nilfs_cleanup_super(): sets "clean" flag to both super blocks if they point to the same checkpoint. To update both of super block information, caller of nilfs_commit_super must set the information on both super blocks. Signed-off-by: Jiro SEKIBA <jir@unicus.jp> Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
Diffstat (limited to 'fs/nilfs2/super.c')
-rw-r--r--fs/nilfs2/super.c95
1 files changed, 65 insertions, 30 deletions
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c
index eb7de40828c7..f2cfbbab2346 100644
--- a/fs/nilfs2/super.c
+++ b/fs/nilfs2/super.c
@@ -82,10 +82,12 @@ static void nilfs_set_error(struct nilfs_sb_info *sbi)
82 down_write(&nilfs->ns_sem); 82 down_write(&nilfs->ns_sem);
83 if (!(nilfs->ns_mount_state & NILFS_ERROR_FS)) { 83 if (!(nilfs->ns_mount_state & NILFS_ERROR_FS)) {
84 nilfs->ns_mount_state |= NILFS_ERROR_FS; 84 nilfs->ns_mount_state |= NILFS_ERROR_FS;
85 sbp = nilfs_prepare_super(sbi); 85 sbp = nilfs_prepare_super(sbi, 0);
86 if (likely(sbp)) { 86 if (likely(sbp)) {
87 sbp[0]->s_state |= cpu_to_le16(NILFS_ERROR_FS); 87 sbp[0]->s_state |= cpu_to_le16(NILFS_ERROR_FS);
88 nilfs_commit_super(sbi, 1); 88 if (sbp[1])
89 sbp[1]->s_state |= cpu_to_le16(NILFS_ERROR_FS);
90 nilfs_commit_super(sbi, NILFS_SB_COMMIT_ALL);
89 } 91 }
90 } 92 }
91 up_write(&nilfs->ns_sem); 93 up_write(&nilfs->ns_sem);
@@ -184,7 +186,7 @@ static void nilfs_clear_inode(struct inode *inode)
184 nilfs_btnode_cache_clear(&ii->i_btnode_cache); 186 nilfs_btnode_cache_clear(&ii->i_btnode_cache);
185} 187}
186 188
187static int nilfs_sync_super(struct nilfs_sb_info *sbi, int dupsb) 189static int nilfs_sync_super(struct nilfs_sb_info *sbi, int flag)
188{ 190{
189 struct the_nilfs *nilfs = sbi->s_nilfs; 191 struct the_nilfs *nilfs = sbi->s_nilfs;
190 int err; 192 int err;
@@ -210,12 +212,20 @@ static int nilfs_sync_super(struct nilfs_sb_info *sbi, int dupsb)
210 printk(KERN_ERR 212 printk(KERN_ERR
211 "NILFS: unable to write superblock (err=%d)\n", err); 213 "NILFS: unable to write superblock (err=%d)\n", err);
212 if (err == -EIO && nilfs->ns_sbh[1]) { 214 if (err == -EIO && nilfs->ns_sbh[1]) {
215 /*
216 * sbp[0] points to newer log than sbp[1],
217 * so copy sbp[0] to sbp[1] to take over sbp[0].
218 */
219 memcpy(nilfs->ns_sbp[1], nilfs->ns_sbp[0],
220 nilfs->ns_sbsize);
213 nilfs_fall_back_super_block(nilfs); 221 nilfs_fall_back_super_block(nilfs);
214 goto retry; 222 goto retry;
215 } 223 }
216 } else { 224 } else {
217 struct nilfs_super_block *sbp = nilfs->ns_sbp[0]; 225 struct nilfs_super_block *sbp = nilfs->ns_sbp[0];
218 226
227 nilfs->ns_sbwcount++;
228
219 /* 229 /*
220 * The latest segment becomes trailable from the position 230 * The latest segment becomes trailable from the position
221 * written in superblock. 231 * written in superblock.
@@ -224,20 +234,21 @@ static int nilfs_sync_super(struct nilfs_sb_info *sbi, int dupsb)
224 234
225 /* update GC protection for recent segments */ 235 /* update GC protection for recent segments */
226 if (nilfs->ns_sbh[1]) { 236 if (nilfs->ns_sbh[1]) {
227 sbp = NULL; 237 if (flag == NILFS_SB_COMMIT_ALL) {
228 if (dupsb) {
229 set_buffer_dirty(nilfs->ns_sbh[1]); 238 set_buffer_dirty(nilfs->ns_sbh[1]);
230 if (!sync_dirty_buffer(nilfs->ns_sbh[1])) 239 if (sync_dirty_buffer(nilfs->ns_sbh[1]) < 0)
231 sbp = nilfs->ns_sbp[1]; 240 goto out;
232 } 241 }
242 if (le64_to_cpu(nilfs->ns_sbp[1]->s_last_cno) <
243 le64_to_cpu(nilfs->ns_sbp[0]->s_last_cno))
244 sbp = nilfs->ns_sbp[1];
233 } 245 }
234 if (sbp) {
235 spin_lock(&nilfs->ns_last_segment_lock);
236 nilfs->ns_prot_seq = le64_to_cpu(sbp->s_last_seq);
237 spin_unlock(&nilfs->ns_last_segment_lock);
238 }
239 }
240 246
247 spin_lock(&nilfs->ns_last_segment_lock);
248 nilfs->ns_prot_seq = le64_to_cpu(sbp->s_last_seq);
249 spin_unlock(&nilfs->ns_last_segment_lock);
250 }
251 out:
241 return err; 252 return err;
242} 253}
243 254
@@ -257,7 +268,8 @@ void nilfs_set_log_cursor(struct nilfs_super_block *sbp,
257 spin_unlock(&nilfs->ns_last_segment_lock); 268 spin_unlock(&nilfs->ns_last_segment_lock);
258} 269}
259 270
260struct nilfs_super_block **nilfs_prepare_super(struct nilfs_sb_info *sbi) 271struct nilfs_super_block **nilfs_prepare_super(struct nilfs_sb_info *sbi,
272 int flip)
261{ 273{
262 struct the_nilfs *nilfs = sbi->s_nilfs; 274 struct the_nilfs *nilfs = sbi->s_nilfs;
263 struct nilfs_super_block **sbp = nilfs->ns_sbp; 275 struct nilfs_super_block **sbp = nilfs->ns_sbp;
@@ -266,38 +278,46 @@ struct nilfs_super_block **nilfs_prepare_super(struct nilfs_sb_info *sbi)
266 if (sbp[0]->s_magic != cpu_to_le16(NILFS_SUPER_MAGIC)) { 278 if (sbp[0]->s_magic != cpu_to_le16(NILFS_SUPER_MAGIC)) {
267 if (sbp[1] && 279 if (sbp[1] &&
268 sbp[1]->s_magic == cpu_to_le16(NILFS_SUPER_MAGIC)) { 280 sbp[1]->s_magic == cpu_to_le16(NILFS_SUPER_MAGIC)) {
269 nilfs_swap_super_block(nilfs); 281 memcpy(sbp[0], sbp[1], nilfs->ns_sbsize);
270 } else { 282 } else {
271 printk(KERN_CRIT "NILFS: superblock broke on dev %s\n", 283 printk(KERN_CRIT "NILFS: superblock broke on dev %s\n",
272 sbi->s_super->s_id); 284 sbi->s_super->s_id);
273 return NULL; 285 return NULL;
274 } 286 }
287 } else if (sbp[1] &&
288 sbp[1]->s_magic != cpu_to_le16(NILFS_SUPER_MAGIC)) {
289 memcpy(sbp[1], sbp[0], nilfs->ns_sbsize);
275 } 290 }
291
292 if (flip && sbp[1])
293 nilfs_swap_super_block(nilfs);
294
276 return sbp; 295 return sbp;
277} 296}
278 297
279int nilfs_commit_super(struct nilfs_sb_info *sbi, int dupsb) 298int nilfs_commit_super(struct nilfs_sb_info *sbi, int flag)
280{ 299{
281 struct the_nilfs *nilfs = sbi->s_nilfs; 300 struct the_nilfs *nilfs = sbi->s_nilfs;
282 struct nilfs_super_block **sbp = nilfs->ns_sbp; 301 struct nilfs_super_block **sbp = nilfs->ns_sbp;
283 time_t t; 302 time_t t;
284 303
285 /* nilfs->ns_sem must be locked by the caller. */ 304 /* nilfs->ns_sem must be locked by the caller. */
286 nilfs_set_log_cursor(sbp[0], nilfs);
287
288 t = get_seconds(); 305 t = get_seconds();
289 nilfs->ns_sbwtime[0] = t; 306 nilfs->ns_sbwtime = t;
290 sbp[0]->s_wtime = cpu_to_le64(t); 307 sbp[0]->s_wtime = cpu_to_le64(t);
291 sbp[0]->s_sum = 0; 308 sbp[0]->s_sum = 0;
292 sbp[0]->s_sum = cpu_to_le32(crc32_le(nilfs->ns_crc_seed, 309 sbp[0]->s_sum = cpu_to_le32(crc32_le(nilfs->ns_crc_seed,
293 (unsigned char *)sbp[0], 310 (unsigned char *)sbp[0],
294 nilfs->ns_sbsize)); 311 nilfs->ns_sbsize));
295 if (dupsb && sbp[1]) { 312 if (flag == NILFS_SB_COMMIT_ALL && sbp[1]) {
296 memcpy(sbp[1], sbp[0], nilfs->ns_sbsize); 313 sbp[1]->s_wtime = sbp[0]->s_wtime;
297 nilfs->ns_sbwtime[1] = t; 314 sbp[1]->s_sum = 0;
315 sbp[1]->s_sum = cpu_to_le32(crc32_le(nilfs->ns_crc_seed,
316 (unsigned char *)sbp[1],
317 nilfs->ns_sbsize));
298 } 318 }
299 clear_nilfs_sb_dirty(nilfs); 319 clear_nilfs_sb_dirty(nilfs);
300 return nilfs_sync_super(sbi, dupsb); 320 return nilfs_sync_super(sbi, flag);
301} 321}
302 322
303/** 323/**
@@ -311,12 +331,23 @@ int nilfs_commit_super(struct nilfs_sb_info *sbi, int dupsb)
311int nilfs_cleanup_super(struct nilfs_sb_info *sbi) 331int nilfs_cleanup_super(struct nilfs_sb_info *sbi)
312{ 332{
313 struct nilfs_super_block **sbp; 333 struct nilfs_super_block **sbp;
334 int flag = NILFS_SB_COMMIT;
314 int ret = -EIO; 335 int ret = -EIO;
315 336
316 sbp = nilfs_prepare_super(sbi); 337 sbp = nilfs_prepare_super(sbi, 0);
317 if (sbp) { 338 if (sbp) {
318 sbp[0]->s_state = cpu_to_le16(sbi->s_nilfs->ns_mount_state); 339 sbp[0]->s_state = cpu_to_le16(sbi->s_nilfs->ns_mount_state);
319 ret = nilfs_commit_super(sbi, 1); 340 nilfs_set_log_cursor(sbp[0], sbi->s_nilfs);
341 if (sbp[1] && sbp[0]->s_last_cno == sbp[1]->s_last_cno) {
342 /*
343 * make the "clean" flag also to the opposite
344 * super block if both super blocks point to
345 * the same checkpoint.
346 */
347 sbp[1]->s_state = sbp[0]->s_state;
348 flag = NILFS_SB_COMMIT_ALL;
349 }
350 ret = nilfs_commit_super(sbi, flag);
320 } 351 }
321 return ret; 352 return ret;
322} 353}
@@ -362,9 +393,11 @@ static int nilfs_sync_fs(struct super_block *sb, int wait)
362 393
363 down_write(&nilfs->ns_sem); 394 down_write(&nilfs->ns_sem);
364 if (nilfs_sb_dirty(nilfs)) { 395 if (nilfs_sb_dirty(nilfs)) {
365 sbp = nilfs_prepare_super(sbi); 396 sbp = nilfs_prepare_super(sbi, nilfs_sb_will_flip(nilfs));
366 if (likely(sbp)) 397 if (likely(sbp)) {
367 nilfs_commit_super(sbi, 1); 398 nilfs_set_log_cursor(sbp[0], nilfs);
399 nilfs_commit_super(sbi, NILFS_SB_COMMIT);
400 }
368 } 401 }
369 up_write(&nilfs->ns_sem); 402 up_write(&nilfs->ns_sem);
370 403
@@ -664,7 +697,7 @@ static int nilfs_setup_super(struct nilfs_sb_info *sbi)
664 int mnt_count; 697 int mnt_count;
665 698
666 /* nilfs->ns_sem must be locked by the caller. */ 699 /* nilfs->ns_sem must be locked by the caller. */
667 sbp = nilfs_prepare_super(sbi); 700 sbp = nilfs_prepare_super(sbi, 0);
668 if (!sbp) 701 if (!sbp)
669 return -EIO; 702 return -EIO;
670 703
@@ -687,7 +720,9 @@ static int nilfs_setup_super(struct nilfs_sb_info *sbi)
687 sbp[0]->s_state = 720 sbp[0]->s_state =
688 cpu_to_le16(le16_to_cpu(sbp[0]->s_state) & ~NILFS_VALID_FS); 721 cpu_to_le16(le16_to_cpu(sbp[0]->s_state) & ~NILFS_VALID_FS);
689 sbp[0]->s_mtime = cpu_to_le64(get_seconds()); 722 sbp[0]->s_mtime = cpu_to_le64(get_seconds());
690 return nilfs_commit_super(sbi, 1); 723 /* synchronize sbp[1] with sbp[0] */
724 memcpy(sbp[1], sbp[0], nilfs->ns_sbsize);
725 return nilfs_commit_super(sbi, NILFS_SB_COMMIT_ALL);
691} 726}
692 727
693struct nilfs_super_block *nilfs_read_super_block(struct super_block *sb, 728struct nilfs_super_block *nilfs_read_super_block(struct super_block *sb,