Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 206340
b: refs/heads/master
c: b2ac86e
h: refs/heads/master
v: v3
  • Loading branch information
Jiro SEKIBA authored and Ryusuke Konishi committed Jul 23, 2010
1 parent 64ad491 commit 2160508
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 47 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: d26493b6f017c0b0063a15bf893411ddae85eee4
refs/heads/master: b2ac86e1a8e3a3b0ab4449d062c582f07a078e7b
11 changes: 10 additions & 1 deletion trunk/fs/nilfs2/nilfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,14 @@ enum {
NILFS_I_GCDAT, /* shadow DAT, on memory only */
};

/*
* commit flags for nilfs_commit_super and nilfs_sync_super
*/
enum {
NILFS_SB_COMMIT = 0, /* Commit a super block alternately */
NILFS_SB_COMMIT_ALL /* Commit both super blocks */
};

/*
* Macros to check inode numbers
*/
Expand Down Expand Up @@ -272,7 +280,8 @@ extern int nilfs_store_magic_and_option(struct super_block *,
struct nilfs_super_block *, char *);
extern void nilfs_set_log_cursor(struct nilfs_super_block *,
struct the_nilfs *);
extern struct nilfs_super_block **nilfs_prepare_super(struct nilfs_sb_info *);
extern struct nilfs_super_block **nilfs_prepare_super(struct nilfs_sb_info *,
int flip);
extern int nilfs_commit_super(struct nilfs_sb_info *, int);
extern int nilfs_cleanup_super(struct nilfs_sb_info *);
extern int nilfs_attach_checkpoint(struct nilfs_sb_info *, __u64);
Expand Down
10 changes: 6 additions & 4 deletions trunk/fs/nilfs2/segment.c
Original file line number Diff line number Diff line change
Expand Up @@ -2425,10 +2425,12 @@ static int nilfs_segctor_construct(struct nilfs_sc_info *sci, int mode)
nilfs_discontinued(nilfs)) {
down_write(&nilfs->ns_sem);
err = -EIO;
sbp = nilfs_prepare_super(sbi);
if (likely(sbp))
err = nilfs_commit_super(
sbi, nilfs_altsb_need_update(nilfs));
sbp = nilfs_prepare_super(sbi,
nilfs_sb_will_flip(nilfs));
if (likely(sbp)) {
nilfs_set_log_cursor(sbp[0], nilfs);
err = nilfs_commit_super(sbi, NILFS_SB_COMMIT);
}
up_write(&nilfs->ns_sem);
}
}
Expand Down
95 changes: 65 additions & 30 deletions trunk/fs/nilfs2/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,12 @@ static void nilfs_set_error(struct nilfs_sb_info *sbi)
down_write(&nilfs->ns_sem);
if (!(nilfs->ns_mount_state & NILFS_ERROR_FS)) {
nilfs->ns_mount_state |= NILFS_ERROR_FS;
sbp = nilfs_prepare_super(sbi);
sbp = nilfs_prepare_super(sbi, 0);
if (likely(sbp)) {
sbp[0]->s_state |= cpu_to_le16(NILFS_ERROR_FS);
nilfs_commit_super(sbi, 1);
if (sbp[1])
sbp[1]->s_state |= cpu_to_le16(NILFS_ERROR_FS);
nilfs_commit_super(sbi, NILFS_SB_COMMIT_ALL);
}
}
up_write(&nilfs->ns_sem);
Expand Down Expand Up @@ -184,7 +186,7 @@ static void nilfs_clear_inode(struct inode *inode)
nilfs_btnode_cache_clear(&ii->i_btnode_cache);
}

static int nilfs_sync_super(struct nilfs_sb_info *sbi, int dupsb)
static int nilfs_sync_super(struct nilfs_sb_info *sbi, int flag)
{
struct the_nilfs *nilfs = sbi->s_nilfs;
int err;
Expand All @@ -210,12 +212,20 @@ static int nilfs_sync_super(struct nilfs_sb_info *sbi, int dupsb)
printk(KERN_ERR
"NILFS: unable to write superblock (err=%d)\n", err);
if (err == -EIO && nilfs->ns_sbh[1]) {
/*
* sbp[0] points to newer log than sbp[1],
* so copy sbp[0] to sbp[1] to take over sbp[0].
*/
memcpy(nilfs->ns_sbp[1], nilfs->ns_sbp[0],
nilfs->ns_sbsize);
nilfs_fall_back_super_block(nilfs);
goto retry;
}
} else {
struct nilfs_super_block *sbp = nilfs->ns_sbp[0];

nilfs->ns_sbwcount++;

/*
* The latest segment becomes trailable from the position
* written in superblock.
Expand All @@ -224,20 +234,21 @@ static int nilfs_sync_super(struct nilfs_sb_info *sbi, int dupsb)

/* update GC protection for recent segments */
if (nilfs->ns_sbh[1]) {
sbp = NULL;
if (dupsb) {
if (flag == NILFS_SB_COMMIT_ALL) {
set_buffer_dirty(nilfs->ns_sbh[1]);
if (!sync_dirty_buffer(nilfs->ns_sbh[1]))
sbp = nilfs->ns_sbp[1];
if (sync_dirty_buffer(nilfs->ns_sbh[1]) < 0)
goto out;
}
if (le64_to_cpu(nilfs->ns_sbp[1]->s_last_cno) <
le64_to_cpu(nilfs->ns_sbp[0]->s_last_cno))
sbp = nilfs->ns_sbp[1];
}
if (sbp) {
spin_lock(&nilfs->ns_last_segment_lock);
nilfs->ns_prot_seq = le64_to_cpu(sbp->s_last_seq);
spin_unlock(&nilfs->ns_last_segment_lock);
}
}

spin_lock(&nilfs->ns_last_segment_lock);
nilfs->ns_prot_seq = le64_to_cpu(sbp->s_last_seq);
spin_unlock(&nilfs->ns_last_segment_lock);
}
out:
return err;
}

Expand All @@ -257,7 +268,8 @@ void nilfs_set_log_cursor(struct nilfs_super_block *sbp,
spin_unlock(&nilfs->ns_last_segment_lock);
}

struct nilfs_super_block **nilfs_prepare_super(struct nilfs_sb_info *sbi)
struct nilfs_super_block **nilfs_prepare_super(struct nilfs_sb_info *sbi,
int flip)
{
struct the_nilfs *nilfs = sbi->s_nilfs;
struct nilfs_super_block **sbp = nilfs->ns_sbp;
Expand All @@ -266,38 +278,46 @@ struct nilfs_super_block **nilfs_prepare_super(struct nilfs_sb_info *sbi)
if (sbp[0]->s_magic != cpu_to_le16(NILFS_SUPER_MAGIC)) {
if (sbp[1] &&
sbp[1]->s_magic == cpu_to_le16(NILFS_SUPER_MAGIC)) {
nilfs_swap_super_block(nilfs);
memcpy(sbp[0], sbp[1], nilfs->ns_sbsize);
} else {
printk(KERN_CRIT "NILFS: superblock broke on dev %s\n",
sbi->s_super->s_id);
return NULL;
}
} else if (sbp[1] &&
sbp[1]->s_magic != cpu_to_le16(NILFS_SUPER_MAGIC)) {
memcpy(sbp[1], sbp[0], nilfs->ns_sbsize);
}

if (flip && sbp[1])
nilfs_swap_super_block(nilfs);

return sbp;
}

int nilfs_commit_super(struct nilfs_sb_info *sbi, int dupsb)
int nilfs_commit_super(struct nilfs_sb_info *sbi, int flag)
{
struct the_nilfs *nilfs = sbi->s_nilfs;
struct nilfs_super_block **sbp = nilfs->ns_sbp;
time_t t;

/* nilfs->ns_sem must be locked by the caller. */
nilfs_set_log_cursor(sbp[0], nilfs);

t = get_seconds();
nilfs->ns_sbwtime[0] = t;
nilfs->ns_sbwtime = t;
sbp[0]->s_wtime = cpu_to_le64(t);
sbp[0]->s_sum = 0;
sbp[0]->s_sum = cpu_to_le32(crc32_le(nilfs->ns_crc_seed,
(unsigned char *)sbp[0],
nilfs->ns_sbsize));
if (dupsb && sbp[1]) {
memcpy(sbp[1], sbp[0], nilfs->ns_sbsize);
nilfs->ns_sbwtime[1] = t;
if (flag == NILFS_SB_COMMIT_ALL && sbp[1]) {
sbp[1]->s_wtime = sbp[0]->s_wtime;
sbp[1]->s_sum = 0;
sbp[1]->s_sum = cpu_to_le32(crc32_le(nilfs->ns_crc_seed,
(unsigned char *)sbp[1],
nilfs->ns_sbsize));
}
clear_nilfs_sb_dirty(nilfs);
return nilfs_sync_super(sbi, dupsb);
return nilfs_sync_super(sbi, flag);
}

/**
Expand All @@ -311,12 +331,23 @@ int nilfs_commit_super(struct nilfs_sb_info *sbi, int dupsb)
int nilfs_cleanup_super(struct nilfs_sb_info *sbi)
{
struct nilfs_super_block **sbp;
int flag = NILFS_SB_COMMIT;
int ret = -EIO;

sbp = nilfs_prepare_super(sbi);
sbp = nilfs_prepare_super(sbi, 0);
if (sbp) {
sbp[0]->s_state = cpu_to_le16(sbi->s_nilfs->ns_mount_state);
ret = nilfs_commit_super(sbi, 1);
nilfs_set_log_cursor(sbp[0], sbi->s_nilfs);
if (sbp[1] && sbp[0]->s_last_cno == sbp[1]->s_last_cno) {
/*
* make the "clean" flag also to the opposite
* super block if both super blocks point to
* the same checkpoint.
*/
sbp[1]->s_state = sbp[0]->s_state;
flag = NILFS_SB_COMMIT_ALL;
}
ret = nilfs_commit_super(sbi, flag);
}
return ret;
}
Expand Down Expand Up @@ -362,9 +393,11 @@ static int nilfs_sync_fs(struct super_block *sb, int wait)

down_write(&nilfs->ns_sem);
if (nilfs_sb_dirty(nilfs)) {
sbp = nilfs_prepare_super(sbi);
if (likely(sbp))
nilfs_commit_super(sbi, 1);
sbp = nilfs_prepare_super(sbi, nilfs_sb_will_flip(nilfs));
if (likely(sbp)) {
nilfs_set_log_cursor(sbp[0], nilfs);
nilfs_commit_super(sbi, NILFS_SB_COMMIT);
}
}
up_write(&nilfs->ns_sem);

Expand Down Expand Up @@ -664,7 +697,7 @@ static int nilfs_setup_super(struct nilfs_sb_info *sbi)
int mnt_count;

/* nilfs->ns_sem must be locked by the caller. */
sbp = nilfs_prepare_super(sbi);
sbp = nilfs_prepare_super(sbi, 0);
if (!sbp)
return -EIO;

Expand All @@ -687,7 +720,9 @@ static int nilfs_setup_super(struct nilfs_sb_info *sbi)
sbp[0]->s_state =
cpu_to_le16(le16_to_cpu(sbp[0]->s_state) & ~NILFS_VALID_FS);
sbp[0]->s_mtime = cpu_to_le64(get_seconds());
return nilfs_commit_super(sbi, 1);
/* synchronize sbp[1] with sbp[0] */
memcpy(sbp[1], sbp[0], nilfs->ns_sbsize);
return nilfs_commit_super(sbi, NILFS_SB_COMMIT_ALL);
}

struct nilfs_super_block *nilfs_read_super_block(struct super_block *sb,
Expand Down
4 changes: 2 additions & 2 deletions trunk/fs/nilfs2/the_nilfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -513,8 +513,8 @@ static int nilfs_load_super_block(struct the_nilfs *nilfs,
nilfs_swap_super_block(nilfs);
}

nilfs->ns_sbwtime[0] = le64_to_cpu(sbp[0]->s_wtime);
nilfs->ns_sbwtime[1] = valid[!swp] ? le64_to_cpu(sbp[1]->s_wtime) : 0;
nilfs->ns_sbwcount = 0;
nilfs->ns_sbwtime = le64_to_cpu(sbp[0]->s_wtime);
nilfs->ns_prot_seq = le64_to_cpu(sbp[valid[1] & !swp]->s_last_seq);
*sbpp = sbp[0];
return 0;
Expand Down
17 changes: 8 additions & 9 deletions trunk/fs/nilfs2/the_nilfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ enum {
* @ns_current: back pointer to current mount
* @ns_sbh: buffer heads of on-disk super blocks
* @ns_sbp: pointers to super block data
* @ns_sbwtime: previous write time of super blocks
* @ns_sbwtime: previous write time of super block
* @ns_sbwcount: write count of super block
* @ns_sbsize: size of valid data in super block
* @ns_supers: list of nilfs super block structs
* @ns_seg_seq: segment sequence counter
Expand Down Expand Up @@ -119,7 +120,8 @@ struct the_nilfs {
*/
struct buffer_head *ns_sbh[2];
struct nilfs_super_block *ns_sbp[2];
time_t ns_sbwtime[2];
time_t ns_sbwtime;
unsigned ns_sbwcount;
unsigned ns_sbsize;
unsigned ns_mount_state;

Expand Down Expand Up @@ -203,20 +205,17 @@ THE_NILFS_FNS(SB_DIRTY, sb_dirty)

/* Minimum interval of periodical update of superblocks (in seconds) */
#define NILFS_SB_FREQ 10
#define NILFS_ALTSB_FREQ 60 /* spare superblock */

static inline int nilfs_sb_need_update(struct the_nilfs *nilfs)
{
u64 t = get_seconds();
return t < nilfs->ns_sbwtime[0] ||
t > nilfs->ns_sbwtime[0] + NILFS_SB_FREQ;
return t < nilfs->ns_sbwtime || t > nilfs->ns_sbwtime + NILFS_SB_FREQ;
}

static inline int nilfs_altsb_need_update(struct the_nilfs *nilfs)
static inline int nilfs_sb_will_flip(struct the_nilfs *nilfs)
{
u64 t = get_seconds();
struct nilfs_super_block **sbp = nilfs->ns_sbp;
return sbp[1] && t > nilfs->ns_sbwtime[1] + NILFS_ALTSB_FREQ;
int flip_bits = nilfs->ns_sbwcount & 0x0FL;
return (flip_bits != 0x08 && flip_bits != 0x0F);
}

void nilfs_set_last_segment(struct the_nilfs *, sector_t, u64, __u64);
Expand Down

0 comments on commit 2160508

Please sign in to comment.