diff options
-rw-r--r-- | fs/nilfs2/nilfs.h | 11 | ||||
-rw-r--r-- | fs/nilfs2/segment.c | 10 | ||||
-rw-r--r-- | fs/nilfs2/super.c | 95 | ||||
-rw-r--r-- | fs/nilfs2/the_nilfs.c | 4 | ||||
-rw-r--r-- | fs/nilfs2/the_nilfs.h | 17 |
5 files changed, 91 insertions, 46 deletions
diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h index 462651061b03..36998eaab02f 100644 --- a/fs/nilfs2/nilfs.h +++ b/fs/nilfs2/nilfs.h | |||
@@ -107,6 +107,14 @@ enum { | |||
107 | }; | 107 | }; |
108 | 108 | ||
109 | /* | 109 | /* |
110 | * commit flags for nilfs_commit_super and nilfs_sync_super | ||
111 | */ | ||
112 | enum { | ||
113 | NILFS_SB_COMMIT = 0, /* Commit a super block alternately */ | ||
114 | NILFS_SB_COMMIT_ALL /* Commit both super blocks */ | ||
115 | }; | ||
116 | |||
117 | /* | ||
110 | * Macros to check inode numbers | 118 | * Macros to check inode numbers |
111 | */ | 119 | */ |
112 | #define NILFS_MDT_INO_BITS \ | 120 | #define NILFS_MDT_INO_BITS \ |
@@ -272,7 +280,8 @@ extern int nilfs_store_magic_and_option(struct super_block *, | |||
272 | struct nilfs_super_block *, char *); | 280 | struct nilfs_super_block *, char *); |
273 | extern void nilfs_set_log_cursor(struct nilfs_super_block *, | 281 | extern void nilfs_set_log_cursor(struct nilfs_super_block *, |
274 | struct the_nilfs *); | 282 | struct the_nilfs *); |
275 | extern struct nilfs_super_block **nilfs_prepare_super(struct nilfs_sb_info *); | 283 | extern struct nilfs_super_block **nilfs_prepare_super(struct nilfs_sb_info *, |
284 | int flip); | ||
276 | extern int nilfs_commit_super(struct nilfs_sb_info *, int); | 285 | extern int nilfs_commit_super(struct nilfs_sb_info *, int); |
277 | extern int nilfs_cleanup_super(struct nilfs_sb_info *); | 286 | extern int nilfs_cleanup_super(struct nilfs_sb_info *); |
278 | extern int nilfs_attach_checkpoint(struct nilfs_sb_info *, __u64); | 287 | extern int nilfs_attach_checkpoint(struct nilfs_sb_info *, __u64); |
diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index 9e680a93b13a..04e04854a311 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c | |||
@@ -2425,10 +2425,12 @@ static int nilfs_segctor_construct(struct nilfs_sc_info *sci, int mode) | |||
2425 | nilfs_discontinued(nilfs)) { | 2425 | nilfs_discontinued(nilfs)) { |
2426 | down_write(&nilfs->ns_sem); | 2426 | down_write(&nilfs->ns_sem); |
2427 | err = -EIO; | 2427 | err = -EIO; |
2428 | sbp = nilfs_prepare_super(sbi); | 2428 | sbp = nilfs_prepare_super(sbi, |
2429 | if (likely(sbp)) | 2429 | nilfs_sb_will_flip(nilfs)); |
2430 | err = nilfs_commit_super( | 2430 | if (likely(sbp)) { |
2431 | sbi, nilfs_altsb_need_update(nilfs)); | 2431 | nilfs_set_log_cursor(sbp[0], nilfs); |
2432 | err = nilfs_commit_super(sbi, NILFS_SB_COMMIT); | ||
2433 | } | ||
2432 | up_write(&nilfs->ns_sem); | 2434 | up_write(&nilfs->ns_sem); |
2433 | } | 2435 | } |
2434 | } | 2436 | } |
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 | ||
187 | static int nilfs_sync_super(struct nilfs_sb_info *sbi, int dupsb) | 189 | static 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 | ||
260 | struct nilfs_super_block **nilfs_prepare_super(struct nilfs_sb_info *sbi) | 271 | struct 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 | ||
279 | int nilfs_commit_super(struct nilfs_sb_info *sbi, int dupsb) | 298 | int 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) | |||
311 | int nilfs_cleanup_super(struct nilfs_sb_info *sbi) | 331 | int 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 | ||
693 | struct nilfs_super_block *nilfs_read_super_block(struct super_block *sb, | 728 | struct nilfs_super_block *nilfs_read_super_block(struct super_block *sb, |
diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index ed58053b6f68..530d2777b4c7 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c | |||
@@ -513,8 +513,8 @@ static int nilfs_load_super_block(struct the_nilfs *nilfs, | |||
513 | nilfs_swap_super_block(nilfs); | 513 | nilfs_swap_super_block(nilfs); |
514 | } | 514 | } |
515 | 515 | ||
516 | nilfs->ns_sbwtime[0] = le64_to_cpu(sbp[0]->s_wtime); | 516 | nilfs->ns_sbwcount = 0; |
517 | nilfs->ns_sbwtime[1] = valid[!swp] ? le64_to_cpu(sbp[1]->s_wtime) : 0; | 517 | nilfs->ns_sbwtime = le64_to_cpu(sbp[0]->s_wtime); |
518 | nilfs->ns_prot_seq = le64_to_cpu(sbp[valid[1] & !swp]->s_last_seq); | 518 | nilfs->ns_prot_seq = le64_to_cpu(sbp[valid[1] & !swp]->s_last_seq); |
519 | *sbpp = sbp[0]; | 519 | *sbpp = sbp[0]; |
520 | return 0; | 520 | return 0; |
diff --git a/fs/nilfs2/the_nilfs.h b/fs/nilfs2/the_nilfs.h index 191560ec2e7f..32b4983b7458 100644 --- a/fs/nilfs2/the_nilfs.h +++ b/fs/nilfs2/the_nilfs.h | |||
@@ -57,7 +57,8 @@ enum { | |||
57 | * @ns_current: back pointer to current mount | 57 | * @ns_current: back pointer to current mount |
58 | * @ns_sbh: buffer heads of on-disk super blocks | 58 | * @ns_sbh: buffer heads of on-disk super blocks |
59 | * @ns_sbp: pointers to super block data | 59 | * @ns_sbp: pointers to super block data |
60 | * @ns_sbwtime: previous write time of super blocks | 60 | * @ns_sbwtime: previous write time of super block |
61 | * @ns_sbwcount: write count of super block | ||
61 | * @ns_sbsize: size of valid data in super block | 62 | * @ns_sbsize: size of valid data in super block |
62 | * @ns_supers: list of nilfs super block structs | 63 | * @ns_supers: list of nilfs super block structs |
63 | * @ns_seg_seq: segment sequence counter | 64 | * @ns_seg_seq: segment sequence counter |
@@ -119,7 +120,8 @@ struct the_nilfs { | |||
119 | */ | 120 | */ |
120 | struct buffer_head *ns_sbh[2]; | 121 | struct buffer_head *ns_sbh[2]; |
121 | struct nilfs_super_block *ns_sbp[2]; | 122 | struct nilfs_super_block *ns_sbp[2]; |
122 | time_t ns_sbwtime[2]; | 123 | time_t ns_sbwtime; |
124 | unsigned ns_sbwcount; | ||
123 | unsigned ns_sbsize; | 125 | unsigned ns_sbsize; |
124 | unsigned ns_mount_state; | 126 | unsigned ns_mount_state; |
125 | 127 | ||
@@ -203,20 +205,17 @@ THE_NILFS_FNS(SB_DIRTY, sb_dirty) | |||
203 | 205 | ||
204 | /* Minimum interval of periodical update of superblocks (in seconds) */ | 206 | /* Minimum interval of periodical update of superblocks (in seconds) */ |
205 | #define NILFS_SB_FREQ 10 | 207 | #define NILFS_SB_FREQ 10 |
206 | #define NILFS_ALTSB_FREQ 60 /* spare superblock */ | ||
207 | 208 | ||
208 | static inline int nilfs_sb_need_update(struct the_nilfs *nilfs) | 209 | static inline int nilfs_sb_need_update(struct the_nilfs *nilfs) |
209 | { | 210 | { |
210 | u64 t = get_seconds(); | 211 | u64 t = get_seconds(); |
211 | return t < nilfs->ns_sbwtime[0] || | 212 | return t < nilfs->ns_sbwtime || t > nilfs->ns_sbwtime + NILFS_SB_FREQ; |
212 | t > nilfs->ns_sbwtime[0] + NILFS_SB_FREQ; | ||
213 | } | 213 | } |
214 | 214 | ||
215 | static inline int nilfs_altsb_need_update(struct the_nilfs *nilfs) | 215 | static inline int nilfs_sb_will_flip(struct the_nilfs *nilfs) |
216 | { | 216 | { |
217 | u64 t = get_seconds(); | 217 | int flip_bits = nilfs->ns_sbwcount & 0x0FL; |
218 | struct nilfs_super_block **sbp = nilfs->ns_sbp; | 218 | return (flip_bits != 0x08 && flip_bits != 0x0F); |
219 | return sbp[1] && t > nilfs->ns_sbwtime[1] + NILFS_ALTSB_FREQ; | ||
220 | } | 219 | } |
221 | 220 | ||
222 | void nilfs_set_last_segment(struct the_nilfs *, sector_t, u64, __u64); | 221 | void nilfs_set_last_segment(struct the_nilfs *, sector_t, u64, __u64); |