Skip to content

Commit

Permalink
Merge branch 'linux-next' of git://git.infradead.org/ubifs-2.6
Browse files Browse the repository at this point in the history
* 'linux-next' of git://git.infradead.org/ubifs-2.6:
  UBIFS: do not allocate unneeded scan buffer
  UBIFS: do not forget to cancel timers
  UBIFS: remove a bit of unneeded code
  UBIFS: add a commentary about log recovery
  UBIFS: avoid kernel error if ubifs superblock read fails
  UBIFS: introduce new flags for RO mounts
  UBIFS: introduce new flag for RO due to errors
  UBIFS: check return code of pnode_lookup
  UBIFS: check return code of ubifs_lpt_lookup
  UBIFS: improve error reporting when reading bad node
  UBIFS: introduce list sorting debugging checks
  UBIFS: fix assertion warnings in comparison function
  UBIFS: mark unused key objects as invalid
  UBIFS: do not write rubbish into truncation scanning node
  UBIFS: improve assertion in node comparison functions
  UBIFS: do not use key type in list_sort
  UBIFS: do not look up truncation nodes
  UBIFS: fix assertion warning
  UBIFS: do not treat ENOSPC specially
  UBIFS: switch to RO mode after synchronizing
  • Loading branch information
torvalds committed Oct 22, 2010
2 parents f5d9d24 + 6599fcb commit 06d3629
Show file tree
Hide file tree
Showing 21 changed files with 362 additions and 112 deletions.
4 changes: 3 additions & 1 deletion fs/ubifs/commit.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ static int do_commit(struct ubifs_info *c)
struct ubifs_lp_stats lst;

dbg_cmt("start");
if (c->ro_media) {
ubifs_assert(!c->ro_media && !c->ro_mount);

if (c->ro_error) {
err = -EROFS;
goto out_up;
}
Expand Down
156 changes: 156 additions & 0 deletions fs/ubifs/debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -2239,6 +2239,162 @@ int dbg_check_filesystem(struct ubifs_info *c)
return err;
}

/**
* dbg_check_data_nodes_order - check that list of data nodes is sorted.
* @c: UBIFS file-system description object
* @head: the list of nodes ('struct ubifs_scan_node' objects)
*
* This function returns zero if the list of data nodes is sorted correctly,
* and %-EINVAL if not.
*/
int dbg_check_data_nodes_order(struct ubifs_info *c, struct list_head *head)
{
struct list_head *cur;
struct ubifs_scan_node *sa, *sb;

if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
return 0;

for (cur = head->next; cur->next != head; cur = cur->next) {
ino_t inuma, inumb;
uint32_t blka, blkb;

cond_resched();
sa = container_of(cur, struct ubifs_scan_node, list);
sb = container_of(cur->next, struct ubifs_scan_node, list);

if (sa->type != UBIFS_DATA_NODE) {
ubifs_err("bad node type %d", sa->type);
dbg_dump_node(c, sa->node);
return -EINVAL;
}
if (sb->type != UBIFS_DATA_NODE) {
ubifs_err("bad node type %d", sb->type);
dbg_dump_node(c, sb->node);
return -EINVAL;
}

inuma = key_inum(c, &sa->key);
inumb = key_inum(c, &sb->key);

if (inuma < inumb)
continue;
if (inuma > inumb) {
ubifs_err("larger inum %lu goes before inum %lu",
(unsigned long)inuma, (unsigned long)inumb);
goto error_dump;
}

blka = key_block(c, &sa->key);
blkb = key_block(c, &sb->key);

if (blka > blkb) {
ubifs_err("larger block %u goes before %u", blka, blkb);
goto error_dump;
}
if (blka == blkb) {
ubifs_err("two data nodes for the same block");
goto error_dump;
}
}

return 0;

error_dump:
dbg_dump_node(c, sa->node);
dbg_dump_node(c, sb->node);
return -EINVAL;
}

/**
* dbg_check_nondata_nodes_order - check that list of data nodes is sorted.
* @c: UBIFS file-system description object
* @head: the list of nodes ('struct ubifs_scan_node' objects)
*
* This function returns zero if the list of non-data nodes is sorted correctly,
* and %-EINVAL if not.
*/
int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head)
{
struct list_head *cur;
struct ubifs_scan_node *sa, *sb;

if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
return 0;

for (cur = head->next; cur->next != head; cur = cur->next) {
ino_t inuma, inumb;
uint32_t hasha, hashb;

cond_resched();
sa = container_of(cur, struct ubifs_scan_node, list);
sb = container_of(cur->next, struct ubifs_scan_node, list);

if (sa->type != UBIFS_INO_NODE && sa->type != UBIFS_DENT_NODE &&
sa->type != UBIFS_XENT_NODE) {
ubifs_err("bad node type %d", sa->type);
dbg_dump_node(c, sa->node);
return -EINVAL;
}
if (sa->type != UBIFS_INO_NODE && sa->type != UBIFS_DENT_NODE &&
sa->type != UBIFS_XENT_NODE) {
ubifs_err("bad node type %d", sb->type);
dbg_dump_node(c, sb->node);
return -EINVAL;
}

if (sa->type != UBIFS_INO_NODE && sb->type == UBIFS_INO_NODE) {
ubifs_err("non-inode node goes before inode node");
goto error_dump;
}

if (sa->type == UBIFS_INO_NODE && sb->type != UBIFS_INO_NODE)
continue;

if (sa->type == UBIFS_INO_NODE && sb->type == UBIFS_INO_NODE) {
/* Inode nodes are sorted in descending size order */
if (sa->len < sb->len) {
ubifs_err("smaller inode node goes first");
goto error_dump;
}
continue;
}

/*
* This is either a dentry or xentry, which should be sorted in
* ascending (parent ino, hash) order.
*/
inuma = key_inum(c, &sa->key);
inumb = key_inum(c, &sb->key);

if (inuma < inumb)
continue;
if (inuma > inumb) {
ubifs_err("larger inum %lu goes before inum %lu",
(unsigned long)inuma, (unsigned long)inumb);
goto error_dump;
}

hasha = key_block(c, &sa->key);
hashb = key_block(c, &sb->key);

if (hasha > hashb) {
ubifs_err("larger hash %u goes before %u", hasha, hashb);
goto error_dump;
}
}

return 0;

error_dump:
ubifs_msg("dumping first node");
dbg_dump_node(c, sa->node);
ubifs_msg("dumping second node");
dbg_dump_node(c, sb->node);
return -EINVAL;
return 0;
}

static int invocation_cnt;

int dbg_force_in_the_gaps(void)
Expand Down
4 changes: 4 additions & 0 deletions fs/ubifs/debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,8 @@ int dbg_check_lpt_nodes(struct ubifs_info *c, struct ubifs_cnode *cnode,
int row, int col);
int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode,
loff_t size);
int dbg_check_data_nodes_order(struct ubifs_info *c, struct list_head *head);
int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head);

/* Force the use of in-the-gaps method for testing */

Expand Down Expand Up @@ -465,6 +467,8 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c);
#define dbg_check_lprops(c) 0
#define dbg_check_lpt_nodes(c, cnode, row, col) 0
#define dbg_check_inode_size(c, inode, size) 0
#define dbg_check_data_nodes_order(c, head) 0
#define dbg_check_nondata_nodes_order(c, head) 0
#define dbg_force_in_the_gaps_enabled 0
#define dbg_force_in_the_gaps() 0
#define dbg_failure_mode 0
Expand Down
7 changes: 4 additions & 3 deletions fs/ubifs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -433,8 +433,9 @@ static int ubifs_write_begin(struct file *file, struct address_space *mapping,
struct page *page;

ubifs_assert(ubifs_inode(inode)->ui_size == inode->i_size);
ubifs_assert(!c->ro_media && !c->ro_mount);

if (unlikely(c->ro_media))
if (unlikely(c->ro_error))
return -EROFS;

/* Try out the fast-path part first */
Expand Down Expand Up @@ -1439,9 +1440,9 @@ static int ubifs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vm

dbg_gen("ino %lu, pg %lu, i_size %lld", inode->i_ino, page->index,
i_size_read(inode));
ubifs_assert(!(inode->i_sb->s_flags & MS_RDONLY));
ubifs_assert(!c->ro_media && !c->ro_mount);

if (unlikely(c->ro_media))
if (unlikely(c->ro_error))
return VM_FAULT_SIGBUS; /* -EROFS */

/*
Expand Down
82 changes: 61 additions & 21 deletions fs/ubifs/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,16 @@ int data_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
struct ubifs_scan_node *sa, *sb;

cond_resched();
if (a == b)
return 0;

sa = list_entry(a, struct ubifs_scan_node, list);
sb = list_entry(b, struct ubifs_scan_node, list);

ubifs_assert(key_type(c, &sa->key) == UBIFS_DATA_KEY);
ubifs_assert(key_type(c, &sb->key) == UBIFS_DATA_KEY);
ubifs_assert(sa->type == UBIFS_DATA_NODE);
ubifs_assert(sb->type == UBIFS_DATA_NODE);

inuma = key_inum(c, &sa->key);
inumb = key_inum(c, &sb->key);
Expand Down Expand Up @@ -157,28 +163,40 @@ int data_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
*/
int nondata_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
{
int typea, typeb;
ino_t inuma, inumb;
struct ubifs_info *c = priv;
struct ubifs_scan_node *sa, *sb;

cond_resched();
if (a == b)
return 0;

sa = list_entry(a, struct ubifs_scan_node, list);
sb = list_entry(b, struct ubifs_scan_node, list);
typea = key_type(c, &sa->key);
typeb = key_type(c, &sb->key);
ubifs_assert(typea != UBIFS_DATA_KEY && typeb != UBIFS_DATA_KEY);

ubifs_assert(key_type(c, &sa->key) != UBIFS_DATA_KEY &&
key_type(c, &sb->key) != UBIFS_DATA_KEY);
ubifs_assert(sa->type != UBIFS_DATA_NODE &&
sb->type != UBIFS_DATA_NODE);

/* Inodes go before directory entries */
if (typea == UBIFS_INO_KEY) {
if (typeb == UBIFS_INO_KEY)
if (sa->type == UBIFS_INO_NODE) {
if (sb->type == UBIFS_INO_NODE)
return sb->len - sa->len;
return -1;
}
if (typeb == UBIFS_INO_KEY)
if (sb->type == UBIFS_INO_NODE)
return 1;

ubifs_assert(typea == UBIFS_DENT_KEY && typeb == UBIFS_DENT_KEY);
ubifs_assert(key_type(c, &sa->key) == UBIFS_DENT_KEY ||
key_type(c, &sa->key) == UBIFS_XENT_KEY);
ubifs_assert(key_type(c, &sb->key) == UBIFS_DENT_KEY ||
key_type(c, &sb->key) == UBIFS_XENT_KEY);
ubifs_assert(sa->type == UBIFS_DENT_NODE ||
sa->type == UBIFS_XENT_NODE);
ubifs_assert(sb->type == UBIFS_DENT_NODE ||
sb->type == UBIFS_XENT_NODE);

inuma = key_inum(c, &sa->key);
inumb = key_inum(c, &sb->key);

Expand Down Expand Up @@ -224,17 +242,33 @@ int nondata_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
static int sort_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
struct list_head *nondata, int *min)
{
int err;
struct ubifs_scan_node *snod, *tmp;

*min = INT_MAX;

/* Separate data nodes and non-data nodes */
list_for_each_entry_safe(snod, tmp, &sleb->nodes, list) {
int err;
ubifs_assert(snod->type == UBIFS_INO_NODE ||
snod->type == UBIFS_DATA_NODE ||
snod->type == UBIFS_DENT_NODE ||
snod->type == UBIFS_XENT_NODE ||
snod->type == UBIFS_TRUN_NODE);

if (snod->type != UBIFS_INO_NODE &&
snod->type != UBIFS_DATA_NODE &&
snod->type != UBIFS_DENT_NODE &&
snod->type != UBIFS_XENT_NODE) {
/* Probably truncation node, zap it */
list_del(&snod->list);
kfree(snod);
continue;
}

ubifs_assert(snod->type != UBIFS_IDX_NODE);
ubifs_assert(snod->type != UBIFS_REF_NODE);
ubifs_assert(snod->type != UBIFS_CS_NODE);
ubifs_assert(key_type(c, &snod->key) == UBIFS_DATA_KEY ||
key_type(c, &snod->key) == UBIFS_INO_KEY ||
key_type(c, &snod->key) == UBIFS_DENT_KEY ||
key_type(c, &snod->key) == UBIFS_XENT_KEY);

err = ubifs_tnc_has_node(c, &snod->key, 0, sleb->lnum,
snod->offs, 0);
Expand All @@ -258,6 +292,13 @@ static int sort_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
/* Sort data and non-data nodes */
list_sort(c, &sleb->nodes, &data_nodes_cmp);
list_sort(c, nondata, &nondata_nodes_cmp);

err = dbg_check_data_nodes_order(c, &sleb->nodes);
if (err)
return err;
err = dbg_check_nondata_nodes_order(c, nondata);
if (err)
return err;
return 0;
}

Expand Down Expand Up @@ -575,13 +616,14 @@ int ubifs_garbage_collect(struct ubifs_info *c, int anyway)
struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf;

ubifs_assert_cmt_locked(c);
ubifs_assert(!c->ro_media && !c->ro_mount);

if (ubifs_gc_should_commit(c))
return -EAGAIN;

mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead);

if (c->ro_media) {
if (c->ro_error) {
ret = -EROFS;
goto out_unlock;
}
Expand Down Expand Up @@ -677,14 +719,12 @@ int ubifs_garbage_collect(struct ubifs_info *c, int anyway)

ret = ubifs_garbage_collect_leb(c, &lp);
if (ret < 0) {
if (ret == -EAGAIN || ret == -ENOSPC) {
if (ret == -EAGAIN) {
/*
* These codes are not errors, so we have to
* return the LEB to lprops. But if the
* 'ubifs_return_leb()' function fails, its
* failure code is propagated to the caller
* instead of the original '-EAGAIN' or
* '-ENOSPC'.
* This is not error, so we have to return the
* LEB to lprops. But if 'ubifs_return_leb()'
* fails, its failure code is propagated to the
* caller instead of the original '-EAGAIN'.
*/
err = ubifs_return_leb(c, lp.lnum);
if (err)
Expand Down Expand Up @@ -774,8 +814,8 @@ int ubifs_garbage_collect(struct ubifs_info *c, int anyway)
out:
ubifs_assert(ret < 0);
ubifs_assert(ret != -ENOSPC && ret != -EAGAIN);
ubifs_ro_mode(c, ret);
ubifs_wbuf_sync_nolock(wbuf);
ubifs_ro_mode(c, ret);
mutex_unlock(&wbuf->io_mutex);
ubifs_return_leb(c, lp.lnum);
return ret;
Expand Down
Loading

0 comments on commit 06d3629

Please sign in to comment.