aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nilfs2/nilfs.h11
-rw-r--r--fs/nilfs2/segment.c10
-rw-r--r--fs/nilfs2/super.c95
-rw-r--r--fs/nilfs2/the_nilfs.c4
-rw-r--r--fs/nilfs2/the_nilfs.h17
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 */
112enum {
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 *);
273extern void nilfs_set_log_cursor(struct nilfs_super_block *, 281extern void nilfs_set_log_cursor(struct nilfs_super_block *,
274 struct the_nilfs *); 282 struct the_nilfs *);
275extern struct nilfs_super_block **nilfs_prepare_super(struct nilfs_sb_info *); 283extern struct nilfs_super_block **nilfs_prepare_super(struct nilfs_sb_info *,
284 int flip);
276extern int nilfs_commit_super(struct nilfs_sb_info *, int); 285extern int nilfs_commit_super(struct nilfs_sb_info *, int);
277extern int nilfs_cleanup_super(struct nilfs_sb_info *); 286extern int nilfs_cleanup_super(struct nilfs_sb_info *);
278extern int nilfs_attach_checkpoint(struct nilfs_sb_info *, __u64); 287extern 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
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,
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
208static inline int nilfs_sb_need_update(struct the_nilfs *nilfs) 209static 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
215static inline int nilfs_altsb_need_update(struct the_nilfs *nilfs) 215static 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
222void nilfs_set_last_segment(struct the_nilfs *, sector_t, u64, __u64); 221void nilfs_set_last_segment(struct the_nilfs *, sector_t, u64, __u64);