Merge branch 'linux-next' of git://git.infradead.org/ubifs-2.6
* 'linux-next' of git://git.infradead.org/ubifs-2.6: (25 commits) UBIFS: fix ubifs_compress commentary UBIFS: amend printk UBIFS: do not read unnecessary bytes when unpacking bits UBIFS: check buffer length when scanning for LPT nodes UBIFS: correct condition to eliminate unecessary assignment UBIFS: add more debugging messages for LPT UBIFS: fix bulk-read handling uptodate pages UBIFS: improve garbage collection UBIFS: allow for sync_fs when read-only UBIFS: commit on sync_fs UBIFS: correct comment for commit_on_unmount UBIFS: update dbg_dump_inode UBIFS: fix commentary UBIFS: fix races in bit-fields UBIFS: ensure data read beyond i_size is zeroed out correctly UBIFS: correct key comparison UBIFS: use bit-fields when possible UBIFS: check data CRC when in error state UBIFS: improve znode splitting rules UBIFS: add no_chk_data_crc mount option ...
This commit is contained in:
Коммит
396b122f6a
|
@ -86,6 +86,15 @@ norm_unmount (*) commit on unmount; the journal is committed
|
|||
fast_unmount do not commit on unmount; this option makes
|
||||
unmount faster, but the next mount slower
|
||||
because of the need to replay the journal.
|
||||
bulk_read read more in one go to take advantage of flash
|
||||
media that read faster sequentially
|
||||
no_bulk_read (*) do not bulk-read
|
||||
no_chk_data_crc skip checking of CRCs on data nodes in order to
|
||||
improve read performance. Use this option only
|
||||
if the flash media is highly reliable. The effect
|
||||
of this option is that corruption of the contents
|
||||
of a file can go unnoticed.
|
||||
chk_data_crc (*) do not skip checking CRCs on data nodes
|
||||
|
||||
|
||||
Quick usage instructions
|
||||
|
|
|
@ -414,19 +414,21 @@ static int do_budget_space(struct ubifs_info *c)
|
|||
* @c->lst.empty_lebs + @c->freeable_cnt + @c->idx_gc_cnt -
|
||||
* @c->lst.taken_empty_lebs
|
||||
*
|
||||
* @empty_lebs are available because they are empty. @freeable_cnt are
|
||||
* available because they contain only free and dirty space and the
|
||||
* index allocation always occurs after wbufs are synch'ed.
|
||||
* @idx_gc_cnt are available because they are index LEBs that have been
|
||||
* garbage collected (including trivial GC) and are awaiting the commit
|
||||
* before they can be unmapped - note that the in-the-gaps method will
|
||||
* grab these if it needs them. @taken_empty_lebs are empty_lebs that
|
||||
* have already been allocated for some purpose (also includes those
|
||||
* LEBs on the @idx_gc list).
|
||||
* @c->lst.empty_lebs are available because they are empty.
|
||||
* @c->freeable_cnt are available because they contain only free and
|
||||
* dirty space, @c->idx_gc_cnt are available because they are index
|
||||
* LEBs that have been garbage collected and are awaiting the commit
|
||||
* before they can be used. And the in-the-gaps method will grab these
|
||||
* if it needs them. @c->lst.taken_empty_lebs are empty LEBs that have
|
||||
* already been allocated for some purpose.
|
||||
*
|
||||
* Note, @taken_empty_lebs may temporarily be higher by one because of
|
||||
* the way we serialize LEB allocations and budgeting. See a comment in
|
||||
* 'ubifs_find_free_space()'.
|
||||
* Note, @c->idx_gc_cnt is included to both @c->lst.empty_lebs (because
|
||||
* these LEBs are empty) and to @c->lst.taken_empty_lebs (because they
|
||||
* are taken until after the commit).
|
||||
*
|
||||
* Note, @c->lst.taken_empty_lebs may temporarily be higher by one
|
||||
* because of the way we serialize LEB allocations and budgeting. See a
|
||||
* comment in 'ubifs_find_free_space()'.
|
||||
*/
|
||||
lebs = c->lst.empty_lebs + c->freeable_cnt + c->idx_gc_cnt -
|
||||
c->lst.taken_empty_lebs;
|
||||
|
|
|
@ -91,8 +91,6 @@ struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];
|
|||
*
|
||||
* Note, if the input buffer was not compressed, it is copied to the output
|
||||
* buffer and %UBIFS_COMPR_NONE is returned in @compr_type.
|
||||
*
|
||||
* This functions returns %0 on success or a negative error code on failure.
|
||||
*/
|
||||
void ubifs_compress(const void *in_buf, int in_len, void *out_buf, int *out_len,
|
||||
int *compr_type)
|
||||
|
|
|
@ -222,30 +222,38 @@ void dbg_dump_inode(const struct ubifs_info *c, const struct inode *inode)
|
|||
{
|
||||
const struct ubifs_inode *ui = ubifs_inode(inode);
|
||||
|
||||
printk(KERN_DEBUG "inode %lu\n", inode->i_ino);
|
||||
printk(KERN_DEBUG "size %llu\n",
|
||||
printk(KERN_DEBUG "Dump in-memory inode:");
|
||||
printk(KERN_DEBUG "\tinode %lu\n", inode->i_ino);
|
||||
printk(KERN_DEBUG "\tsize %llu\n",
|
||||
(unsigned long long)i_size_read(inode));
|
||||
printk(KERN_DEBUG "nlink %u\n", inode->i_nlink);
|
||||
printk(KERN_DEBUG "uid %u\n", (unsigned int)inode->i_uid);
|
||||
printk(KERN_DEBUG "gid %u\n", (unsigned int)inode->i_gid);
|
||||
printk(KERN_DEBUG "atime %u.%u\n",
|
||||
printk(KERN_DEBUG "\tnlink %u\n", inode->i_nlink);
|
||||
printk(KERN_DEBUG "\tuid %u\n", (unsigned int)inode->i_uid);
|
||||
printk(KERN_DEBUG "\tgid %u\n", (unsigned int)inode->i_gid);
|
||||
printk(KERN_DEBUG "\tatime %u.%u\n",
|
||||
(unsigned int)inode->i_atime.tv_sec,
|
||||
(unsigned int)inode->i_atime.tv_nsec);
|
||||
printk(KERN_DEBUG "mtime %u.%u\n",
|
||||
printk(KERN_DEBUG "\tmtime %u.%u\n",
|
||||
(unsigned int)inode->i_mtime.tv_sec,
|
||||
(unsigned int)inode->i_mtime.tv_nsec);
|
||||
printk(KERN_DEBUG "ctime %u.%u\n",
|
||||
printk(KERN_DEBUG "\tctime %u.%u\n",
|
||||
(unsigned int)inode->i_ctime.tv_sec,
|
||||
(unsigned int)inode->i_ctime.tv_nsec);
|
||||
printk(KERN_DEBUG "creat_sqnum %llu\n", ui->creat_sqnum);
|
||||
printk(KERN_DEBUG "xattr_size %u\n", ui->xattr_size);
|
||||
printk(KERN_DEBUG "xattr_cnt %u\n", ui->xattr_cnt);
|
||||
printk(KERN_DEBUG "xattr_names %u\n", ui->xattr_names);
|
||||
printk(KERN_DEBUG "dirty %u\n", ui->dirty);
|
||||
printk(KERN_DEBUG "xattr %u\n", ui->xattr);
|
||||
printk(KERN_DEBUG "flags %d\n", ui->flags);
|
||||
printk(KERN_DEBUG "compr_type %d\n", ui->compr_type);
|
||||
printk(KERN_DEBUG "data_len %d\n", ui->data_len);
|
||||
printk(KERN_DEBUG "\tcreat_sqnum %llu\n", ui->creat_sqnum);
|
||||
printk(KERN_DEBUG "\txattr_size %u\n", ui->xattr_size);
|
||||
printk(KERN_DEBUG "\txattr_cnt %u\n", ui->xattr_cnt);
|
||||
printk(KERN_DEBUG "\txattr_names %u\n", ui->xattr_names);
|
||||
printk(KERN_DEBUG "\tdirty %u\n", ui->dirty);
|
||||
printk(KERN_DEBUG "\txattr %u\n", ui->xattr);
|
||||
printk(KERN_DEBUG "\tbulk_read %u\n", ui->xattr);
|
||||
printk(KERN_DEBUG "\tsynced_i_size %llu\n",
|
||||
(unsigned long long)ui->synced_i_size);
|
||||
printk(KERN_DEBUG "\tui_size %llu\n",
|
||||
(unsigned long long)ui->ui_size);
|
||||
printk(KERN_DEBUG "\tflags %d\n", ui->flags);
|
||||
printk(KERN_DEBUG "\tcompr_type %d\n", ui->compr_type);
|
||||
printk(KERN_DEBUG "\tlast_page_read %lu\n", ui->last_page_read);
|
||||
printk(KERN_DEBUG "\tread_in_a_row %lu\n", ui->read_in_a_row);
|
||||
printk(KERN_DEBUG "\tdata_len %d\n", ui->data_len);
|
||||
}
|
||||
|
||||
void dbg_dump_node(const struct ubifs_info *c, const void *node)
|
||||
|
@ -647,6 +655,43 @@ void dbg_dump_lprops(struct ubifs_info *c)
|
|||
}
|
||||
}
|
||||
|
||||
void dbg_dump_lpt_info(struct ubifs_info *c)
|
||||
{
|
||||
int i;
|
||||
|
||||
spin_lock(&dbg_lock);
|
||||
printk(KERN_DEBUG "\tlpt_sz: %lld\n", c->lpt_sz);
|
||||
printk(KERN_DEBUG "\tpnode_sz: %d\n", c->pnode_sz);
|
||||
printk(KERN_DEBUG "\tnnode_sz: %d\n", c->nnode_sz);
|
||||
printk(KERN_DEBUG "\tltab_sz: %d\n", c->ltab_sz);
|
||||
printk(KERN_DEBUG "\tlsave_sz: %d\n", c->lsave_sz);
|
||||
printk(KERN_DEBUG "\tbig_lpt: %d\n", c->big_lpt);
|
||||
printk(KERN_DEBUG "\tlpt_hght: %d\n", c->lpt_hght);
|
||||
printk(KERN_DEBUG "\tpnode_cnt: %d\n", c->pnode_cnt);
|
||||
printk(KERN_DEBUG "\tnnode_cnt: %d\n", c->nnode_cnt);
|
||||
printk(KERN_DEBUG "\tdirty_pn_cnt: %d\n", c->dirty_pn_cnt);
|
||||
printk(KERN_DEBUG "\tdirty_nn_cnt: %d\n", c->dirty_nn_cnt);
|
||||
printk(KERN_DEBUG "\tlsave_cnt: %d\n", c->lsave_cnt);
|
||||
printk(KERN_DEBUG "\tspace_bits: %d\n", c->space_bits);
|
||||
printk(KERN_DEBUG "\tlpt_lnum_bits: %d\n", c->lpt_lnum_bits);
|
||||
printk(KERN_DEBUG "\tlpt_offs_bits: %d\n", c->lpt_offs_bits);
|
||||
printk(KERN_DEBUG "\tlpt_spc_bits: %d\n", c->lpt_spc_bits);
|
||||
printk(KERN_DEBUG "\tpcnt_bits: %d\n", c->pcnt_bits);
|
||||
printk(KERN_DEBUG "\tlnum_bits: %d\n", c->lnum_bits);
|
||||
printk(KERN_DEBUG "\tLPT root is at %d:%d\n", c->lpt_lnum, c->lpt_offs);
|
||||
printk(KERN_DEBUG "\tLPT head is at %d:%d\n",
|
||||
c->nhead_lnum, c->nhead_offs);
|
||||
printk(KERN_DEBUG "\tLPT ltab is at %d:%d\n", c->ltab_lnum, c->ltab_offs);
|
||||
if (c->big_lpt)
|
||||
printk(KERN_DEBUG "\tLPT lsave is at %d:%d\n",
|
||||
c->lsave_lnum, c->lsave_offs);
|
||||
for (i = 0; i < c->lpt_lebs; i++)
|
||||
printk(KERN_DEBUG "\tLPT LEB %d free %d dirty %d tgc %d "
|
||||
"cmt %d\n", i + c->lpt_first, c->ltab[i].free,
|
||||
c->ltab[i].dirty, c->ltab[i].tgc, c->ltab[i].cmt);
|
||||
spin_unlock(&dbg_lock);
|
||||
}
|
||||
|
||||
void dbg_dump_leb(const struct ubifs_info *c, int lnum)
|
||||
{
|
||||
struct ubifs_scan_leb *sleb;
|
||||
|
|
|
@ -224,6 +224,7 @@ void dbg_dump_lstats(const struct ubifs_lp_stats *lst);
|
|||
void dbg_dump_budg(struct ubifs_info *c);
|
||||
void dbg_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp);
|
||||
void dbg_dump_lprops(struct ubifs_info *c);
|
||||
void dbg_dump_lpt_info(struct ubifs_info *c);
|
||||
void dbg_dump_leb(const struct ubifs_info *c, int lnum);
|
||||
void dbg_dump_znode(const struct ubifs_info *c,
|
||||
const struct ubifs_znode *znode);
|
||||
|
@ -249,6 +250,8 @@ int dbg_old_index_check_init(struct ubifs_info *c, struct ubifs_zbranch *zroot);
|
|||
int dbg_check_old_index(struct ubifs_info *c, struct ubifs_zbranch *zroot);
|
||||
int dbg_check_cats(struct ubifs_info *c);
|
||||
int dbg_check_ltab(struct ubifs_info *c);
|
||||
int dbg_chk_lpt_free_spc(struct ubifs_info *c);
|
||||
int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len);
|
||||
int dbg_check_synced_i_size(struct inode *inode);
|
||||
int dbg_check_dir_size(struct ubifs_info *c, const struct inode *dir);
|
||||
int dbg_check_tnc(struct ubifs_info *c, int extra);
|
||||
|
@ -367,6 +370,7 @@ static inline int dbg_change(struct ubi_volume_desc *desc, int lnum,
|
|||
#define dbg_dump_budg(c) ({})
|
||||
#define dbg_dump_lprop(c, lp) ({})
|
||||
#define dbg_dump_lprops(c) ({})
|
||||
#define dbg_dump_lpt_info(c) ({})
|
||||
#define dbg_dump_leb(c, lnum) ({})
|
||||
#define dbg_dump_znode(c, znode) ({})
|
||||
#define dbg_dump_heap(c, heap, cat) ({})
|
||||
|
@ -379,6 +383,8 @@ static inline int dbg_change(struct ubi_volume_desc *desc, int lnum,
|
|||
#define dbg_check_old_index(c, zroot) 0
|
||||
#define dbg_check_cats(c) 0
|
||||
#define dbg_check_ltab(c) 0
|
||||
#define dbg_chk_lpt_free_spc(c) 0
|
||||
#define dbg_chk_lpt_sz(c, action, len) 0
|
||||
#define dbg_check_synced_i_size(inode) 0
|
||||
#define dbg_check_dir_size(c, dir) 0
|
||||
#define dbg_check_tnc(c, x) 0
|
||||
|
|
260
fs/ubifs/file.c
260
fs/ubifs/file.c
|
@ -147,6 +147,12 @@ static int do_readpage(struct page *page)
|
|||
err = ret;
|
||||
if (err != -ENOENT)
|
||||
break;
|
||||
} else if (block + 1 == beyond) {
|
||||
int dlen = le32_to_cpu(dn->size);
|
||||
int ilen = i_size & (UBIFS_BLOCK_SIZE - 1);
|
||||
|
||||
if (ilen && ilen < dlen)
|
||||
memset(addr + ilen, 0, dlen - ilen);
|
||||
}
|
||||
}
|
||||
if (++i >= UBIFS_BLOCKS_PER_PAGE)
|
||||
|
@ -577,8 +583,262 @@ out:
|
|||
return copied;
|
||||
}
|
||||
|
||||
/**
|
||||
* populate_page - copy data nodes into a page for bulk-read.
|
||||
* @c: UBIFS file-system description object
|
||||
* @page: page
|
||||
* @bu: bulk-read information
|
||||
* @n: next zbranch slot
|
||||
*
|
||||
* This function returns %0 on success and a negative error code on failure.
|
||||
*/
|
||||
static int populate_page(struct ubifs_info *c, struct page *page,
|
||||
struct bu_info *bu, int *n)
|
||||
{
|
||||
int i = 0, nn = *n, offs = bu->zbranch[0].offs, hole = 0, read = 0;
|
||||
struct inode *inode = page->mapping->host;
|
||||
loff_t i_size = i_size_read(inode);
|
||||
unsigned int page_block;
|
||||
void *addr, *zaddr;
|
||||
pgoff_t end_index;
|
||||
|
||||
dbg_gen("ino %lu, pg %lu, i_size %lld, flags %#lx",
|
||||
inode->i_ino, page->index, i_size, page->flags);
|
||||
|
||||
addr = zaddr = kmap(page);
|
||||
|
||||
end_index = (i_size - 1) >> PAGE_CACHE_SHIFT;
|
||||
if (!i_size || page->index > end_index) {
|
||||
hole = 1;
|
||||
memset(addr, 0, PAGE_CACHE_SIZE);
|
||||
goto out_hole;
|
||||
}
|
||||
|
||||
page_block = page->index << UBIFS_BLOCKS_PER_PAGE_SHIFT;
|
||||
while (1) {
|
||||
int err, len, out_len, dlen;
|
||||
|
||||
if (nn >= bu->cnt) {
|
||||
hole = 1;
|
||||
memset(addr, 0, UBIFS_BLOCK_SIZE);
|
||||
} else if (key_block(c, &bu->zbranch[nn].key) == page_block) {
|
||||
struct ubifs_data_node *dn;
|
||||
|
||||
dn = bu->buf + (bu->zbranch[nn].offs - offs);
|
||||
|
||||
ubifs_assert(dn->ch.sqnum >
|
||||
ubifs_inode(inode)->creat_sqnum);
|
||||
|
||||
len = le32_to_cpu(dn->size);
|
||||
if (len <= 0 || len > UBIFS_BLOCK_SIZE)
|
||||
goto out_err;
|
||||
|
||||
dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
|
||||
out_len = UBIFS_BLOCK_SIZE;
|
||||
err = ubifs_decompress(&dn->data, dlen, addr, &out_len,
|
||||
le16_to_cpu(dn->compr_type));
|
||||
if (err || len != out_len)
|
||||
goto out_err;
|
||||
|
||||
if (len < UBIFS_BLOCK_SIZE)
|
||||
memset(addr + len, 0, UBIFS_BLOCK_SIZE - len);
|
||||
|
||||
nn += 1;
|
||||
read = (i << UBIFS_BLOCK_SHIFT) + len;
|
||||
} else if (key_block(c, &bu->zbranch[nn].key) < page_block) {
|
||||
nn += 1;
|
||||
continue;
|
||||
} else {
|
||||
hole = 1;
|
||||
memset(addr, 0, UBIFS_BLOCK_SIZE);
|
||||
}
|
||||
if (++i >= UBIFS_BLOCKS_PER_PAGE)
|
||||
break;
|
||||
addr += UBIFS_BLOCK_SIZE;
|
||||
page_block += 1;
|
||||
}
|
||||
|
||||
if (end_index == page->index) {
|
||||
int len = i_size & (PAGE_CACHE_SIZE - 1);
|
||||
|
||||
if (len && len < read)
|
||||
memset(zaddr + len, 0, read - len);
|
||||
}
|
||||
|
||||
out_hole:
|
||||
if (hole) {
|
||||
SetPageChecked(page);
|
||||
dbg_gen("hole");
|
||||
}
|
||||
|
||||
SetPageUptodate(page);
|
||||
ClearPageError(page);
|
||||
flush_dcache_page(page);
|
||||
kunmap(page);
|
||||
*n = nn;
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
ClearPageUptodate(page);
|
||||
SetPageError(page);
|
||||
flush_dcache_page(page);
|
||||
kunmap(page);
|
||||
ubifs_err("bad data node (block %u, inode %lu)",
|
||||
page_block, inode->i_ino);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* ubifs_do_bulk_read - do bulk-read.
|
||||
* @c: UBIFS file-system description object
|
||||
* @page1: first page
|
||||
*
|
||||
* This function returns %1 if the bulk-read is done, otherwise %0 is returned.
|
||||
*/
|
||||
static int ubifs_do_bulk_read(struct ubifs_info *c, struct page *page1)
|
||||
{
|
||||
pgoff_t offset = page1->index, end_index;
|
||||
struct address_space *mapping = page1->mapping;
|
||||
struct inode *inode = mapping->host;
|
||||
struct ubifs_inode *ui = ubifs_inode(inode);
|
||||
struct bu_info *bu;
|
||||
int err, page_idx, page_cnt, ret = 0, n = 0;
|
||||
loff_t isize;
|
||||
|
||||
bu = kmalloc(sizeof(struct bu_info), GFP_NOFS);
|
||||
if (!bu)
|
||||
return 0;
|
||||
|
||||
bu->buf_len = c->bulk_read_buf_size;
|
||||
bu->buf = kmalloc(bu->buf_len, GFP_NOFS);
|
||||
if (!bu->buf)
|
||||
goto out_free;
|
||||
|
||||
data_key_init(c, &bu->key, inode->i_ino,
|
||||
offset << UBIFS_BLOCKS_PER_PAGE_SHIFT);
|
||||
|
||||
err = ubifs_tnc_get_bu_keys(c, bu);
|
||||
if (err)
|
||||
goto out_warn;
|
||||
|
||||
if (bu->eof) {
|
||||
/* Turn off bulk-read at the end of the file */
|
||||
ui->read_in_a_row = 1;
|
||||
ui->bulk_read = 0;
|
||||
}
|
||||
|
||||
page_cnt = bu->blk_cnt >> UBIFS_BLOCKS_PER_PAGE_SHIFT;
|
||||
if (!page_cnt) {
|
||||
/*
|
||||
* This happens when there are multiple blocks per page and the
|
||||
* blocks for the first page we are looking for, are not
|
||||
* together. If all the pages were like this, bulk-read would
|
||||
* reduce performance, so we turn it off for a while.
|
||||
*/
|
||||
ui->read_in_a_row = 0;
|
||||
ui->bulk_read = 0;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
if (bu->cnt) {
|
||||
err = ubifs_tnc_bulk_read(c, bu);
|
||||
if (err)
|
||||
goto out_warn;
|
||||
}
|
||||
|
||||
err = populate_page(c, page1, bu, &n);
|
||||
if (err)
|
||||
goto out_warn;
|
||||
|
||||
unlock_page(page1);
|
||||
ret = 1;
|
||||
|
||||
isize = i_size_read(inode);
|
||||
if (isize == 0)
|
||||
goto out_free;
|
||||
end_index = ((isize - 1) >> PAGE_CACHE_SHIFT);
|
||||
|
||||
for (page_idx = 1; page_idx < page_cnt; page_idx++) {
|
||||
pgoff_t page_offset = offset + page_idx;
|
||||
struct page *page;
|
||||
|
||||
if (page_offset > end_index)
|
||||
break;
|
||||
page = find_or_create_page(mapping, page_offset,
|
||||
GFP_NOFS | __GFP_COLD);
|
||||
if (!page)
|
||||
break;
|
||||
if (!PageUptodate(page))
|
||||
err = populate_page(c, page, bu, &n);
|
||||
unlock_page(page);
|
||||
page_cache_release(page);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
|
||||
ui->last_page_read = offset + page_idx - 1;
|
||||
|
||||
out_free:
|
||||
kfree(bu->buf);
|
||||
kfree(bu);
|
||||
return ret;
|
||||
|
||||
out_warn:
|
||||
ubifs_warn("ignoring error %d and skipping bulk-read", err);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
/**
|
||||
* ubifs_bulk_read - determine whether to bulk-read and, if so, do it.
|
||||
* @page: page from which to start bulk-read.
|
||||
*
|
||||
* Some flash media are capable of reading sequentially at faster rates. UBIFS
|
||||
* bulk-read facility is designed to take advantage of that, by reading in one
|
||||
* go consecutive data nodes that are also located consecutively in the same
|
||||
* LEB. This function returns %1 if a bulk-read is done and %0 otherwise.
|
||||
*/
|
||||
static int ubifs_bulk_read(struct page *page)
|
||||
{
|
||||
struct inode *inode = page->mapping->host;
|
||||
struct ubifs_info *c = inode->i_sb->s_fs_info;
|
||||
struct ubifs_inode *ui = ubifs_inode(inode);
|
||||
pgoff_t index = page->index, last_page_read = ui->last_page_read;
|
||||
int ret = 0;
|
||||
|
||||
ui->last_page_read = index;
|
||||
|
||||
if (!c->bulk_read)
|
||||
return 0;
|
||||
/*
|
||||
* Bulk-read is protected by ui_mutex, but it is an optimization, so
|
||||
* don't bother if we cannot lock the mutex.
|
||||
*/
|
||||
if (!mutex_trylock(&ui->ui_mutex))
|
||||
return 0;
|
||||
if (index != last_page_read + 1) {
|
||||
/* Turn off bulk-read if we stop reading sequentially */
|
||||
ui->read_in_a_row = 1;
|
||||
if (ui->bulk_read)
|
||||
ui->bulk_read = 0;
|
||||
goto out_unlock;
|
||||
}
|
||||
if (!ui->bulk_read) {
|
||||
ui->read_in_a_row += 1;
|
||||
if (ui->read_in_a_row < 3)
|
||||
goto out_unlock;
|
||||
/* Three reads in a row, so switch on bulk-read */
|
||||
ui->bulk_read = 1;
|
||||
}
|
||||
ret = ubifs_do_bulk_read(c, page);
|
||||
out_unlock:
|
||||
mutex_unlock(&ui->ui_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ubifs_readpage(struct file *file, struct page *page)
|
||||
{
|
||||
if (ubifs_bulk_read(page))
|
||||
return 0;
|
||||
do_readpage(page);
|
||||
unlock_page(page);
|
||||
return 0;
|
||||
|
|
|
@ -901,11 +901,11 @@ static int get_idx_gc_leb(struct ubifs_info *c)
|
|||
* it is needed now for this commit.
|
||||
*/
|
||||
lp = ubifs_lpt_lookup_dirty(c, lnum);
|
||||
if (unlikely(IS_ERR(lp)))
|
||||
if (IS_ERR(lp))
|
||||
return PTR_ERR(lp);
|
||||
lp = ubifs_change_lp(c, lp, LPROPS_NC, LPROPS_NC,
|
||||
lp->flags | LPROPS_INDEX, -1);
|
||||
if (unlikely(IS_ERR(lp)))
|
||||
if (IS_ERR(lp))
|
||||
return PTR_ERR(lp);
|
||||
dbg_find("LEB %d, dirty %d and free %d flags %#x",
|
||||
lp->lnum, lp->dirty, lp->free, lp->flags);
|
||||
|
|
|
@ -95,6 +95,48 @@ static int switch_gc_head(struct ubifs_info *c)
|
|||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* joinup - bring data nodes for an inode together.
|
||||
* @c: UBIFS file-system description object
|
||||
* @sleb: describes scanned LEB
|
||||
* @inum: inode number
|
||||
* @blk: block number
|
||||
* @data: list to which to add data nodes
|
||||
*
|
||||
* This function looks at the first few nodes in the scanned LEB @sleb and adds
|
||||
* them to @data if they are data nodes from @inum and have a larger block
|
||||
* number than @blk. This function returns %0 on success and a negative error
|
||||
* code on failure.
|
||||
*/
|
||||
static int joinup(struct ubifs_info *c, struct ubifs_scan_leb *sleb, ino_t inum,
|
||||
unsigned int blk, struct list_head *data)
|
||||
{
|
||||
int err, cnt = 6, lnum = sleb->lnum, offs;
|
||||
struct ubifs_scan_node *snod, *tmp;
|
||||
union ubifs_key *key;
|
||||
|
||||
list_for_each_entry_safe(snod, tmp, &sleb->nodes, list) {
|
||||
key = &snod->key;
|
||||
if (key_inum(c, key) == inum &&
|
||||
key_type(c, key) == UBIFS_DATA_KEY &&
|
||||
key_block(c, key) > blk) {
|
||||
offs = snod->offs;
|
||||
err = ubifs_tnc_has_node(c, key, 0, lnum, offs, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
list_del(&snod->list);
|
||||
if (err) {
|
||||
list_add_tail(&snod->list, data);
|
||||
blk = key_block(c, key);
|
||||
} else
|
||||
kfree(snod);
|
||||
cnt = 6;
|
||||
} else if (--cnt == 0)
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* move_nodes - move nodes.
|
||||
* @c: UBIFS file-system description object
|
||||
|
@ -116,16 +158,21 @@ static int switch_gc_head(struct ubifs_info *c)
|
|||
static int move_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb)
|
||||
{
|
||||
struct ubifs_scan_node *snod, *tmp;
|
||||
struct list_head large, medium, small;
|
||||
struct list_head data, large, medium, small;
|
||||
struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf;
|
||||
int avail, err, min = INT_MAX;
|
||||
unsigned int blk = 0;
|
||||
ino_t inum = 0;
|
||||
|
||||
INIT_LIST_HEAD(&data);
|
||||
INIT_LIST_HEAD(&large);
|
||||
INIT_LIST_HEAD(&medium);
|
||||
INIT_LIST_HEAD(&small);
|
||||
|
||||
list_for_each_entry_safe(snod, tmp, &sleb->nodes, list) {
|
||||
struct list_head *lst;
|
||||
while (!list_empty(&sleb->nodes)) {
|
||||
struct list_head *lst = sleb->nodes.next;
|
||||
|
||||
snod = list_entry(lst, struct ubifs_scan_node, list);
|
||||
|
||||
ubifs_assert(snod->type != UBIFS_IDX_NODE);
|
||||
ubifs_assert(snod->type != UBIFS_REF_NODE);
|
||||
|
@ -136,7 +183,6 @@ static int move_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb)
|
|||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
lst = &snod->list;
|
||||
list_del(lst);
|
||||
if (!err) {
|
||||
/* The node is obsolete, remove it from the list */
|
||||
|
@ -145,15 +191,30 @@ static int move_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb)
|
|||
}
|
||||
|
||||
/*
|
||||
* Sort the list of nodes so that large nodes go first, and
|
||||
* small nodes go last.
|
||||
* Sort the list of nodes so that data nodes go first, large
|
||||
* nodes go second, and small nodes go last.
|
||||
*/
|
||||
if (snod->len > MEDIUM_NODE_WM)
|
||||
list_add(lst, &large);
|
||||
if (key_type(c, &snod->key) == UBIFS_DATA_KEY) {
|
||||
if (inum != key_inum(c, &snod->key)) {
|
||||
if (inum) {
|
||||
/*
|
||||
* Try to move data nodes from the same
|
||||
* inode together.
|
||||
*/
|
||||
err = joinup(c, sleb, inum, blk, &data);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
inum = key_inum(c, &snod->key);
|
||||
blk = key_block(c, &snod->key);
|
||||
}
|
||||
list_add_tail(lst, &data);
|
||||
} else if (snod->len > MEDIUM_NODE_WM)
|
||||
list_add_tail(lst, &large);
|
||||
else if (snod->len > SMALL_NODE_WM)
|
||||
list_add(lst, &medium);
|
||||
list_add_tail(lst, &medium);
|
||||
else
|
||||
list_add(lst, &small);
|
||||
list_add_tail(lst, &small);
|
||||
|
||||
/* And find the smallest node */
|
||||
if (snod->len < min)
|
||||
|
@ -164,6 +225,7 @@ static int move_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb)
|
|||
* Join the tree lists so that we'd have one roughly sorted list
|
||||
* ('large' will be the head of the joined list).
|
||||
*/
|
||||
list_splice(&data, &large);
|
||||
list_splice(&medium, large.prev);
|
||||
list_splice(&small, large.prev);
|
||||
|
||||
|
@ -653,7 +715,7 @@ int ubifs_gc_start_commit(struct ubifs_info *c)
|
|||
*/
|
||||
while (1) {
|
||||
lp = ubifs_fast_find_freeable(c);
|
||||
if (unlikely(IS_ERR(lp))) {
|
||||
if (IS_ERR(lp)) {
|
||||
err = PTR_ERR(lp);
|
||||
goto out;
|
||||
}
|
||||
|
@ -665,7 +727,7 @@ int ubifs_gc_start_commit(struct ubifs_info *c)
|
|||
if (err)
|
||||
goto out;
|
||||
lp = ubifs_change_lp(c, lp, c->leb_size, 0, lp->flags, 0);
|
||||
if (unlikely(IS_ERR(lp))) {
|
||||
if (IS_ERR(lp)) {
|
||||
err = PTR_ERR(lp);
|
||||
goto out;
|
||||
}
|
||||
|
@ -680,7 +742,7 @@ int ubifs_gc_start_commit(struct ubifs_info *c)
|
|||
/* Record index freeable LEBs for unmapping after commit */
|
||||
while (1) {
|
||||
lp = ubifs_fast_find_frdi_idx(c);
|
||||
if (unlikely(IS_ERR(lp))) {
|
||||
if (IS_ERR(lp)) {
|
||||
err = PTR_ERR(lp);
|
||||
goto out;
|
||||
}
|
||||
|
@ -696,7 +758,7 @@ int ubifs_gc_start_commit(struct ubifs_info *c)
|
|||
/* Don't release the LEB until after the next commit */
|
||||
flags = (lp->flags | LPROPS_TAKEN) ^ LPROPS_INDEX;
|
||||
lp = ubifs_change_lp(c, lp, c->leb_size, 0, flags, 1);
|
||||
if (unlikely(IS_ERR(lp))) {
|
||||
if (IS_ERR(lp)) {
|
||||
err = PTR_ERR(lp);
|
||||
kfree(idx_gc);
|
||||
goto out;
|
||||
|
|
|
@ -62,6 +62,7 @@ void ubifs_ro_mode(struct ubifs_info *c, int err)
|
|||
{
|
||||
if (!c->ro_media) {
|
||||
c->ro_media = 1;
|
||||
c->no_chk_data_crc = 0;
|
||||
ubifs_warn("switched to read-only mode, error %d", err);
|
||||
dbg_dump_stack();
|
||||
}
|
||||
|
@ -74,6 +75,7 @@ void ubifs_ro_mode(struct ubifs_info *c, int err)
|
|||
* @lnum: logical eraseblock number
|
||||
* @offs: offset within the logical eraseblock
|
||||
* @quiet: print no messages
|
||||
* @chk_crc: indicates whether to always check the CRC
|
||||
*
|
||||
* This function checks node magic number and CRC checksum. This function also
|
||||
* validates node length to prevent UBIFS from becoming crazy when an attacker
|
||||
|
@ -85,7 +87,7 @@ void ubifs_ro_mode(struct ubifs_info *c, int err)
|
|||
* or magic.
|
||||
*/
|
||||
int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
|
||||
int offs, int quiet)
|
||||
int offs, int quiet, int chk_crc)
|
||||
{
|
||||
int err = -EINVAL, type, node_len;
|
||||
uint32_t crc, node_crc, magic;
|
||||
|
@ -121,6 +123,10 @@ int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
|
|||
node_len > c->ranges[type].max_len)
|
||||
goto out_len;
|
||||
|
||||
if (!chk_crc && type == UBIFS_DATA_NODE && !c->always_chk_crc)
|
||||
if (c->no_chk_data_crc)
|
||||
return 0;
|
||||
|
||||
crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8);
|
||||
node_crc = le32_to_cpu(ch->crc);
|
||||
if (crc != node_crc) {
|
||||
|
@ -722,7 +728,7 @@ int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len,
|
|||
goto out;
|
||||
}
|
||||
|
||||
err = ubifs_check_node(c, buf, lnum, offs, 0);
|
||||
err = ubifs_check_node(c, buf, lnum, offs, 0, 0);
|
||||
if (err) {
|
||||
ubifs_err("expected node type %d", type);
|
||||
return err;
|
||||
|
@ -781,7 +787,7 @@ int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len,
|
|||
goto out;
|
||||
}
|
||||
|
||||
err = ubifs_check_node(c, buf, lnum, offs, 0);
|
||||
err = ubifs_check_node(c, buf, lnum, offs, 0, 0);
|
||||
if (err) {
|
||||
ubifs_err("expected node type %d", type);
|
||||
return err;
|
||||
|
|
|
@ -484,7 +484,7 @@ static inline void key_copy(const struct ubifs_info *c,
|
|||
* @key2: the second key to compare
|
||||
*
|
||||
* This function compares 2 keys and returns %-1 if @key1 is less than
|
||||
* @key2, 0 if the keys are equivalent and %1 if @key1 is greater than @key2.
|
||||
* @key2, %0 if the keys are equivalent and %1 if @key1 is greater than @key2.
|
||||
*/
|
||||
static inline int keys_cmp(const struct ubifs_info *c,
|
||||
const union ubifs_key *key1,
|
||||
|
@ -502,6 +502,26 @@ static inline int keys_cmp(const struct ubifs_info *c,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* keys_eq - determine if keys are equivalent.
|
||||
* @c: UBIFS file-system description object
|
||||
* @key1: the first key to compare
|
||||
* @key2: the second key to compare
|
||||
*
|
||||
* This function compares 2 keys and returns %1 if @key1 is equal to @key2 and
|
||||
* %0 if not.
|
||||
*/
|
||||
static inline int keys_eq(const struct ubifs_info *c,
|
||||
const union ubifs_key *key1,
|
||||
const union ubifs_key *key2)
|
||||
{
|
||||
if (key1->u32[0] != key2->u32[0])
|
||||
return 0;
|
||||
if (key1->u32[1] != key2->u32[1])
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* is_hash_key - is a key vulnerable to hash collisions.
|
||||
* @c: UBIFS file-system description object
|
||||
|
|
|
@ -125,6 +125,7 @@ static void adjust_lpt_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Not greater than parent, so compare to children */
|
||||
while (1) {
|
||||
/* Compare to left child */
|
||||
|
@ -459,18 +460,6 @@ static void change_category(struct ubifs_info *c, struct ubifs_lprops *lprops)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ubifs_get_lprops - get reference to LEB properties.
|
||||
* @c: the UBIFS file-system description object
|
||||
*
|
||||
* This function locks lprops. Lprops have to be unlocked by
|
||||
* 'ubifs_release_lprops()'.
|
||||
*/
|
||||
void ubifs_get_lprops(struct ubifs_info *c)
|
||||
{
|
||||
mutex_lock(&c->lp_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* calc_dark - calculate LEB dark space size.
|
||||
* @c: the UBIFS file-system description object
|
||||
|
@ -576,7 +565,6 @@ const struct ubifs_lprops *ubifs_change_lp(struct ubifs_info *c,
|
|||
ubifs_assert(!(lprops->free & 7) && !(lprops->dirty & 7));
|
||||
|
||||
spin_lock(&c->space_lock);
|
||||
|
||||
if ((lprops->flags & LPROPS_TAKEN) && lprops->free == c->leb_size)
|
||||
c->lst.taken_empty_lebs -= 1;
|
||||
|
||||
|
@ -637,30 +625,11 @@ const struct ubifs_lprops *ubifs_change_lp(struct ubifs_info *c,
|
|||
c->lst.taken_empty_lebs += 1;
|
||||
|
||||
change_category(c, lprops);
|
||||
|
||||
c->idx_gc_cnt += idx_gc_cnt;
|
||||
|
||||
spin_unlock(&c->space_lock);
|
||||
|
||||
return lprops;
|
||||
}
|
||||
|
||||
/**
|
||||
* ubifs_release_lprops - release lprops lock.
|
||||
* @c: the UBIFS file-system description object
|
||||
*
|
||||
* This function has to be called after each 'ubifs_get_lprops()' call to
|
||||
* unlock lprops.
|
||||
*/
|
||||
void ubifs_release_lprops(struct ubifs_info *c)
|
||||
{
|
||||
ubifs_assert(mutex_is_locked(&c->lp_mutex));
|
||||
ubifs_assert(c->lst.empty_lebs >= 0 &&
|
||||
c->lst.empty_lebs <= c->main_lebs);
|
||||
|
||||
mutex_unlock(&c->lp_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* ubifs_get_lp_stats - get lprops statistics.
|
||||
* @c: UBIFS file-system description object
|
||||
|
@ -1262,7 +1231,6 @@ static int scan_check_cb(struct ubifs_info *c,
|
|||
}
|
||||
|
||||
ubifs_scan_destroy(sleb);
|
||||
|
||||
return LPT_SCAN_CONTINUE;
|
||||
|
||||
out_print:
|
||||
|
|
|
@ -109,6 +109,7 @@ static void do_calc_lpt_geom(struct ubifs_info *c)
|
|||
c->lpt_sz = (long long)c->pnode_cnt * c->pnode_sz;
|
||||
c->lpt_sz += (long long)c->nnode_cnt * c->nnode_sz;
|
||||
c->lpt_sz += c->ltab_sz;
|
||||
if (c->big_lpt)
|
||||
c->lpt_sz += c->lsave_sz;
|
||||
|
||||
/* Add wastage */
|
||||
|
@ -287,25 +288,56 @@ uint32_t ubifs_unpack_bits(uint8_t **addr, int *pos, int nrbits)
|
|||
const int k = 32 - nrbits;
|
||||
uint8_t *p = *addr;
|
||||
int b = *pos;
|
||||
uint32_t val;
|
||||
uint32_t uninitialized_var(val);
|
||||
const int bytes = (nrbits + b + 7) >> 3;
|
||||
|
||||
ubifs_assert(nrbits > 0);
|
||||
ubifs_assert(nrbits <= 32);
|
||||
ubifs_assert(*pos >= 0);
|
||||
ubifs_assert(*pos < 8);
|
||||
if (b) {
|
||||
val = p[1] | ((uint32_t)p[2] << 8) | ((uint32_t)p[3] << 16) |
|
||||
switch (bytes) {
|
||||
case 2:
|
||||
val = p[1];
|
||||
break;
|
||||
case 3:
|
||||
val = p[1] | ((uint32_t)p[2] << 8);
|
||||
break;
|
||||
case 4:
|
||||
val = p[1] | ((uint32_t)p[2] << 8) |
|
||||
((uint32_t)p[3] << 16);
|
||||
break;
|
||||
case 5:
|
||||
val = p[1] | ((uint32_t)p[2] << 8) |
|
||||
((uint32_t)p[3] << 16) |
|
||||
((uint32_t)p[4] << 24);
|
||||
}
|
||||
val <<= (8 - b);
|
||||
val |= *p >> b;
|
||||
nrbits += b;
|
||||
} else
|
||||
val = p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) |
|
||||
} else {
|
||||
switch (bytes) {
|
||||
case 1:
|
||||
val = p[0];
|
||||
break;
|
||||
case 2:
|
||||
val = p[0] | ((uint32_t)p[1] << 8);
|
||||
break;
|
||||
case 3:
|
||||
val = p[0] | ((uint32_t)p[1] << 8) |
|
||||
((uint32_t)p[2] << 16);
|
||||
break;
|
||||
case 4:
|
||||
val = p[0] | ((uint32_t)p[1] << 8) |
|
||||
((uint32_t)p[2] << 16) |
|
||||
((uint32_t)p[3] << 24);
|
||||
break;
|
||||
}
|
||||
}
|
||||
val <<= k;
|
||||
val >>= k;
|
||||
b = nrbits & 7;
|
||||
p += nrbits / 8;
|
||||
p += nrbits >> 3;
|
||||
*addr = p;
|
||||
*pos = b;
|
||||
ubifs_assert((val >> nrbits) == 0 || nrbits - b == 32);
|
||||
|
|
|
@ -177,8 +177,6 @@ static int alloc_lpt_leb(struct ubifs_info *c, int *lnum)
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
dbg_err("last LEB %d", *lnum);
|
||||
dump_stack();
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
|
@ -193,6 +191,9 @@ static int layout_cnodes(struct ubifs_info *c)
|
|||
int lnum, offs, len, alen, done_lsave, done_ltab, err;
|
||||
struct ubifs_cnode *cnode;
|
||||
|
||||
err = dbg_chk_lpt_sz(c, 0, 0);
|
||||
if (err)
|
||||
return err;
|
||||
cnode = c->lpt_cnext;
|
||||
if (!cnode)
|
||||
return 0;
|
||||
|
@ -206,6 +207,7 @@ static int layout_cnodes(struct ubifs_info *c)
|
|||
c->lsave_lnum = lnum;
|
||||
c->lsave_offs = offs;
|
||||
offs += c->lsave_sz;
|
||||
dbg_chk_lpt_sz(c, 1, c->lsave_sz);
|
||||
}
|
||||
|
||||
if (offs + c->ltab_sz <= c->leb_size) {
|
||||
|
@ -213,6 +215,7 @@ static int layout_cnodes(struct ubifs_info *c)
|
|||
c->ltab_lnum = lnum;
|
||||
c->ltab_offs = offs;
|
||||
offs += c->ltab_sz;
|
||||
dbg_chk_lpt_sz(c, 1, c->ltab_sz);
|
||||
}
|
||||
|
||||
do {
|
||||
|
@ -226,9 +229,10 @@ static int layout_cnodes(struct ubifs_info *c)
|
|||
while (offs + len > c->leb_size) {
|
||||
alen = ALIGN(offs, c->min_io_size);
|
||||
upd_ltab(c, lnum, c->leb_size - alen, alen - offs);
|
||||
dbg_chk_lpt_sz(c, 2, alen - offs);
|
||||
err = alloc_lpt_leb(c, &lnum);
|
||||
if (err)
|
||||
return err;
|
||||
goto no_space;
|
||||
offs = 0;
|
||||
ubifs_assert(lnum >= c->lpt_first &&
|
||||
lnum <= c->lpt_last);
|
||||
|
@ -238,6 +242,7 @@ static int layout_cnodes(struct ubifs_info *c)
|
|||
c->lsave_lnum = lnum;
|
||||
c->lsave_offs = offs;
|
||||
offs += c->lsave_sz;
|
||||
dbg_chk_lpt_sz(c, 1, c->lsave_sz);
|
||||
continue;
|
||||
}
|
||||
if (!done_ltab) {
|
||||
|
@ -245,6 +250,7 @@ static int layout_cnodes(struct ubifs_info *c)
|
|||
c->ltab_lnum = lnum;
|
||||
c->ltab_offs = offs;
|
||||
offs += c->ltab_sz;
|
||||
dbg_chk_lpt_sz(c, 1, c->ltab_sz);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
@ -257,6 +263,7 @@ static int layout_cnodes(struct ubifs_info *c)
|
|||
c->lpt_offs = offs;
|
||||
}
|
||||
offs += len;
|
||||
dbg_chk_lpt_sz(c, 1, len);
|
||||
cnode = cnode->cnext;
|
||||
} while (cnode && cnode != c->lpt_cnext);
|
||||
|
||||
|
@ -265,9 +272,10 @@ static int layout_cnodes(struct ubifs_info *c)
|
|||
if (offs + c->lsave_sz > c->leb_size) {
|
||||
alen = ALIGN(offs, c->min_io_size);
|
||||
upd_ltab(c, lnum, c->leb_size - alen, alen - offs);
|
||||
dbg_chk_lpt_sz(c, 2, alen - offs);
|
||||
err = alloc_lpt_leb(c, &lnum);
|
||||
if (err)
|
||||
return err;
|
||||
goto no_space;
|
||||
offs = 0;
|
||||
ubifs_assert(lnum >= c->lpt_first &&
|
||||
lnum <= c->lpt_last);
|
||||
|
@ -276,6 +284,7 @@ static int layout_cnodes(struct ubifs_info *c)
|
|||
c->lsave_lnum = lnum;
|
||||
c->lsave_offs = offs;
|
||||
offs += c->lsave_sz;
|
||||
dbg_chk_lpt_sz(c, 1, c->lsave_sz);
|
||||
}
|
||||
|
||||
/* Make sure to place LPT's own lprops table */
|
||||
|
@ -283,9 +292,10 @@ static int layout_cnodes(struct ubifs_info *c)
|
|||
if (offs + c->ltab_sz > c->leb_size) {
|
||||
alen = ALIGN(offs, c->min_io_size);
|
||||
upd_ltab(c, lnum, c->leb_size - alen, alen - offs);
|
||||
dbg_chk_lpt_sz(c, 2, alen - offs);
|
||||
err = alloc_lpt_leb(c, &lnum);
|
||||
if (err)
|
||||
return err;
|
||||
goto no_space;
|
||||
offs = 0;
|
||||
ubifs_assert(lnum >= c->lpt_first &&
|
||||
lnum <= c->lpt_last);
|
||||
|
@ -294,11 +304,23 @@ static int layout_cnodes(struct ubifs_info *c)
|
|||
c->ltab_lnum = lnum;
|
||||
c->ltab_offs = offs;
|
||||
offs += c->ltab_sz;
|
||||
dbg_chk_lpt_sz(c, 1, c->ltab_sz);
|
||||
}
|
||||
|
||||
alen = ALIGN(offs, c->min_io_size);
|
||||
upd_ltab(c, lnum, c->leb_size - alen, alen - offs);
|
||||
dbg_chk_lpt_sz(c, 4, alen - offs);
|
||||
err = dbg_chk_lpt_sz(c, 3, alen);
|
||||
if (err)
|
||||
return err;
|
||||
return 0;
|
||||
|
||||
no_space:
|
||||
ubifs_err("LPT out of space");
|
||||
dbg_err("LPT out of space at LEB %d:%d needing %d, done_ltab %d, "
|
||||
"done_lsave %d", lnum, offs, len, done_ltab, done_lsave);
|
||||
dbg_dump_lpt_info(c);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -333,8 +355,6 @@ static int realloc_lpt_leb(struct ubifs_info *c, int *lnum)
|
|||
*lnum = i + c->lpt_first;
|
||||
return 0;
|
||||
}
|
||||
dbg_err("last LEB %d", *lnum);
|
||||
dump_stack();
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
|
@ -369,12 +389,14 @@ static int write_cnodes(struct ubifs_info *c)
|
|||
done_lsave = 1;
|
||||
ubifs_pack_lsave(c, buf + offs, c->lsave);
|
||||
offs += c->lsave_sz;
|
||||
dbg_chk_lpt_sz(c, 1, c->lsave_sz);
|
||||
}
|
||||
|
||||
if (offs + c->ltab_sz <= c->leb_size) {
|
||||
done_ltab = 1;
|
||||
ubifs_pack_ltab(c, buf + offs, c->ltab_cmt);
|
||||
offs += c->ltab_sz;
|
||||
dbg_chk_lpt_sz(c, 1, c->ltab_sz);
|
||||
}
|
||||
|
||||
/* Loop for each cnode */
|
||||
|
@ -392,10 +414,12 @@ static int write_cnodes(struct ubifs_info *c)
|
|||
alen, UBI_SHORTTERM);
|
||||
if (err)
|
||||
return err;
|
||||
dbg_chk_lpt_sz(c, 4, alen - wlen);
|
||||
}
|
||||
dbg_chk_lpt_sz(c, 2, 0);
|
||||
err = realloc_lpt_leb(c, &lnum);
|
||||
if (err)
|
||||
return err;
|
||||
goto no_space;
|
||||
offs = 0;
|
||||
from = 0;
|
||||
ubifs_assert(lnum >= c->lpt_first &&
|
||||
|
@ -408,12 +432,14 @@ static int write_cnodes(struct ubifs_info *c)
|
|||
done_lsave = 1;
|
||||
ubifs_pack_lsave(c, buf + offs, c->lsave);
|
||||
offs += c->lsave_sz;
|
||||
dbg_chk_lpt_sz(c, 1, c->lsave_sz);
|
||||
continue;
|
||||
}
|
||||
if (!done_ltab) {
|
||||
done_ltab = 1;
|
||||
ubifs_pack_ltab(c, buf + offs, c->ltab_cmt);
|
||||
offs += c->ltab_sz;
|
||||
dbg_chk_lpt_sz(c, 1, c->ltab_sz);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
@ -435,6 +461,7 @@ static int write_cnodes(struct ubifs_info *c)
|
|||
clear_bit(COW_ZNODE, &cnode->flags);
|
||||
smp_mb__after_clear_bit();
|
||||
offs += len;
|
||||
dbg_chk_lpt_sz(c, 1, len);
|
||||
cnode = cnode->cnext;
|
||||
} while (cnode && cnode != c->lpt_cnext);
|
||||
|
||||
|
@ -448,9 +475,10 @@ static int write_cnodes(struct ubifs_info *c)
|
|||
UBI_SHORTTERM);
|
||||
if (err)
|
||||
return err;
|
||||
dbg_chk_lpt_sz(c, 2, alen - wlen);
|
||||
err = realloc_lpt_leb(c, &lnum);
|
||||
if (err)
|
||||
return err;
|
||||
goto no_space;
|
||||
offs = 0;
|
||||
ubifs_assert(lnum >= c->lpt_first &&
|
||||
lnum <= c->lpt_last);
|
||||
|
@ -461,6 +489,7 @@ static int write_cnodes(struct ubifs_info *c)
|
|||
done_lsave = 1;
|
||||
ubifs_pack_lsave(c, buf + offs, c->lsave);
|
||||
offs += c->lsave_sz;
|
||||
dbg_chk_lpt_sz(c, 1, c->lsave_sz);
|
||||
}
|
||||
|
||||
/* Make sure to place LPT's own lprops table */
|
||||
|
@ -473,9 +502,10 @@ static int write_cnodes(struct ubifs_info *c)
|
|||
UBI_SHORTTERM);
|
||||
if (err)
|
||||
return err;
|
||||
dbg_chk_lpt_sz(c, 2, alen - wlen);
|
||||
err = realloc_lpt_leb(c, &lnum);
|
||||
if (err)
|
||||
return err;
|
||||
goto no_space;
|
||||
offs = 0;
|
||||
ubifs_assert(lnum >= c->lpt_first &&
|
||||
lnum <= c->lpt_last);
|
||||
|
@ -486,6 +516,7 @@ static int write_cnodes(struct ubifs_info *c)
|
|||
done_ltab = 1;
|
||||
ubifs_pack_ltab(c, buf + offs, c->ltab_cmt);
|
||||
offs += c->ltab_sz;
|
||||
dbg_chk_lpt_sz(c, 1, c->ltab_sz);
|
||||
}
|
||||
|
||||
/* Write remaining data in buffer */
|
||||
|
@ -495,6 +526,12 @@ static int write_cnodes(struct ubifs_info *c)
|
|||
err = ubifs_leb_write(c, lnum, buf + from, from, alen, UBI_SHORTTERM);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
dbg_chk_lpt_sz(c, 4, alen - wlen);
|
||||
err = dbg_chk_lpt_sz(c, 3, ALIGN(offs, c->min_io_size));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
c->nhead_lnum = lnum;
|
||||
c->nhead_offs = ALIGN(offs, c->min_io_size);
|
||||
|
||||
|
@ -503,7 +540,15 @@ static int write_cnodes(struct ubifs_info *c)
|
|||
dbg_lp("LPT ltab is at %d:%d", c->ltab_lnum, c->ltab_offs);
|
||||
if (c->big_lpt)
|
||||
dbg_lp("LPT lsave is at %d:%d", c->lsave_lnum, c->lsave_offs);
|
||||
|
||||
return 0;
|
||||
|
||||
no_space:
|
||||
ubifs_err("LPT out of space mismatch");
|
||||
dbg_err("LPT out of space mismatch at LEB %d:%d needing %d, done_ltab "
|
||||
"%d, done_lsave %d", lnum, offs, len, done_ltab, done_lsave);
|
||||
dbg_dump_lpt_info(c);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1044,6 +1089,8 @@ static int is_a_node(struct ubifs_info *c, uint8_t *buf, int len)
|
|||
int pos = 0, node_type, node_len;
|
||||
uint16_t crc, calc_crc;
|
||||
|
||||
if (len < UBIFS_LPT_CRC_BYTES + (UBIFS_LPT_TYPE_BITS + 7) / 8)
|
||||
return 0;
|
||||
node_type = ubifs_unpack_bits(&addr, &pos, UBIFS_LPT_TYPE_BITS);
|
||||
if (node_type == UBIFS_LPT_NOT_A_NODE)
|
||||
return 0;
|
||||
|
@ -1156,6 +1203,9 @@ int ubifs_lpt_start_commit(struct ubifs_info *c)
|
|||
dbg_lp("");
|
||||
|
||||
mutex_lock(&c->lp_mutex);
|
||||
err = dbg_chk_lpt_free_spc(c);
|
||||
if (err)
|
||||
goto out;
|
||||
err = dbg_check_ltab(c);
|
||||
if (err)
|
||||
goto out;
|
||||
|
@ -1645,4 +1695,121 @@ int dbg_check_ltab(struct ubifs_info *c)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dbg_chk_lpt_free_spc - check LPT free space is enough to write entire LPT.
|
||||
* @c: the UBIFS file-system description object
|
||||
*
|
||||
* This function returns %0 on success and a negative error code on failure.
|
||||
*/
|
||||
int dbg_chk_lpt_free_spc(struct ubifs_info *c)
|
||||
{
|
||||
long long free = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < c->lpt_lebs; i++) {
|
||||
if (c->ltab[i].tgc || c->ltab[i].cmt)
|
||||
continue;
|
||||
if (i + c->lpt_first == c->nhead_lnum)
|
||||
free += c->leb_size - c->nhead_offs;
|
||||
else if (c->ltab[i].free == c->leb_size)
|
||||
free += c->leb_size;
|
||||
}
|
||||
if (free < c->lpt_sz) {
|
||||
dbg_err("LPT space error: free %lld lpt_sz %lld",
|
||||
free, c->lpt_sz);
|
||||
dbg_dump_lpt_info(c);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dbg_chk_lpt_sz - check LPT does not write more than LPT size.
|
||||
* @c: the UBIFS file-system description object
|
||||
* @action: action
|
||||
* @len: length written
|
||||
*
|
||||
* This function returns %0 on success and a negative error code on failure.
|
||||
*/
|
||||
int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len)
|
||||
{
|
||||
long long chk_lpt_sz, lpt_sz;
|
||||
int err = 0;
|
||||
|
||||
switch (action) {
|
||||
case 0:
|
||||
c->chk_lpt_sz = 0;
|
||||
c->chk_lpt_sz2 = 0;
|
||||
c->chk_lpt_lebs = 0;
|
||||
c->chk_lpt_wastage = 0;
|
||||
if (c->dirty_pn_cnt > c->pnode_cnt) {
|
||||
dbg_err("dirty pnodes %d exceed max %d",
|
||||
c->dirty_pn_cnt, c->pnode_cnt);
|
||||
err = -EINVAL;
|
||||
}
|
||||
if (c->dirty_nn_cnt > c->nnode_cnt) {
|
||||
dbg_err("dirty nnodes %d exceed max %d",
|
||||
c->dirty_nn_cnt, c->nnode_cnt);
|
||||
err = -EINVAL;
|
||||
}
|
||||
return err;
|
||||
case 1:
|
||||
c->chk_lpt_sz += len;
|
||||
return 0;
|
||||
case 2:
|
||||
c->chk_lpt_sz += len;
|
||||
c->chk_lpt_wastage += len;
|
||||
c->chk_lpt_lebs += 1;
|
||||
return 0;
|
||||
case 3:
|
||||
chk_lpt_sz = c->leb_size;
|
||||
chk_lpt_sz *= c->chk_lpt_lebs;
|
||||
chk_lpt_sz += len - c->nhead_offs;
|
||||
if (c->chk_lpt_sz != chk_lpt_sz) {
|
||||
dbg_err("LPT wrote %lld but space used was %lld",
|
||||
c->chk_lpt_sz, chk_lpt_sz);
|
||||
err = -EINVAL;
|
||||
}
|
||||
if (c->chk_lpt_sz > c->lpt_sz) {
|
||||
dbg_err("LPT wrote %lld but lpt_sz is %lld",
|
||||
c->chk_lpt_sz, c->lpt_sz);
|
||||
err = -EINVAL;
|
||||
}
|
||||
if (c->chk_lpt_sz2 && c->chk_lpt_sz != c->chk_lpt_sz2) {
|
||||
dbg_err("LPT layout size %lld but wrote %lld",
|
||||
c->chk_lpt_sz, c->chk_lpt_sz2);
|
||||
err = -EINVAL;
|
||||
}
|
||||
if (c->chk_lpt_sz2 && c->new_nhead_offs != len) {
|
||||
dbg_err("LPT new nhead offs: expected %d was %d",
|
||||
c->new_nhead_offs, len);
|
||||
err = -EINVAL;
|
||||
}
|
||||
lpt_sz = (long long)c->pnode_cnt * c->pnode_sz;
|
||||
lpt_sz += (long long)c->nnode_cnt * c->nnode_sz;
|
||||
lpt_sz += c->ltab_sz;
|
||||
if (c->big_lpt)
|
||||
lpt_sz += c->lsave_sz;
|
||||
if (c->chk_lpt_sz - c->chk_lpt_wastage > lpt_sz) {
|
||||
dbg_err("LPT chk_lpt_sz %lld + waste %lld exceeds %lld",
|
||||
c->chk_lpt_sz, c->chk_lpt_wastage, lpt_sz);
|
||||
err = -EINVAL;
|
||||
}
|
||||
if (err)
|
||||
dbg_dump_lpt_info(c);
|
||||
c->chk_lpt_sz2 = c->chk_lpt_sz;
|
||||
c->chk_lpt_sz = 0;
|
||||
c->chk_lpt_wastage = 0;
|
||||
c->chk_lpt_lebs = 0;
|
||||
c->new_nhead_offs = len;
|
||||
return err;
|
||||
case 4:
|
||||
c->chk_lpt_sz += len;
|
||||
c->chk_lpt_wastage += len;
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_UBIFS_FS_DEBUG */
|
||||
|
|
|
@ -310,4 +310,31 @@ static inline int ubifs_tnc_lookup(struct ubifs_info *c,
|
|||
return ubifs_tnc_locate(c, key, node, NULL, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* ubifs_get_lprops - get reference to LEB properties.
|
||||
* @c: the UBIFS file-system description object
|
||||
*
|
||||
* This function locks lprops. Lprops have to be unlocked by
|
||||
* 'ubifs_release_lprops()'.
|
||||
*/
|
||||
static inline void ubifs_get_lprops(struct ubifs_info *c)
|
||||
{
|
||||
mutex_lock(&c->lp_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* ubifs_release_lprops - release lprops lock.
|
||||
* @c: the UBIFS file-system description object
|
||||
*
|
||||
* This function has to be called after each 'ubifs_get_lprops()' call to
|
||||
* unlock lprops.
|
||||
*/
|
||||
static inline void ubifs_release_lprops(struct ubifs_info *c)
|
||||
{
|
||||
ubifs_assert(mutex_is_locked(&c->lp_mutex));
|
||||
ubifs_assert(c->lst.empty_lebs >= 0 &&
|
||||
c->lst.empty_lebs <= c->main_lebs);
|
||||
mutex_unlock(&c->lp_mutex);
|
||||
}
|
||||
|
||||
#endif /* __UBIFS_MISC_H__ */
|
||||
|
|
|
@ -87,7 +87,7 @@ int ubifs_scan_a_node(const struct ubifs_info *c, void *buf, int len, int lnum,
|
|||
|
||||
dbg_scan("scanning %s", dbg_ntype(ch->node_type));
|
||||
|
||||
if (ubifs_check_node(c, buf, lnum, offs, quiet))
|
||||
if (ubifs_check_node(c, buf, lnum, offs, quiet, 1))
|
||||
return SCANNED_A_CORRUPT_NODE;
|
||||
|
||||
if (ch->node_type == UBIFS_PAD_NODE) {
|
||||
|
|
109
fs/ubifs/super.c
109
fs/ubifs/super.c
|
@ -401,6 +401,16 @@ static int ubifs_show_options(struct seq_file *s, struct vfsmount *mnt)
|
|||
else if (c->mount_opts.unmount_mode == 1)
|
||||
seq_printf(s, ",norm_unmount");
|
||||
|
||||
if (c->mount_opts.bulk_read == 2)
|
||||
seq_printf(s, ",bulk_read");
|
||||
else if (c->mount_opts.bulk_read == 1)
|
||||
seq_printf(s, ",no_bulk_read");
|
||||
|
||||
if (c->mount_opts.chk_data_crc == 2)
|
||||
seq_printf(s, ",chk_data_crc");
|
||||
else if (c->mount_opts.chk_data_crc == 1)
|
||||
seq_printf(s, ",no_chk_data_crc");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -408,13 +418,26 @@ static int ubifs_sync_fs(struct super_block *sb, int wait)
|
|||
{
|
||||
struct ubifs_info *c = sb->s_fs_info;
|
||||
int i, ret = 0, err;
|
||||
long long bud_bytes;
|
||||
|
||||
if (c->jheads)
|
||||
if (c->jheads) {
|
||||
for (i = 0; i < c->jhead_cnt; i++) {
|
||||
err = ubifs_wbuf_sync(&c->jheads[i].wbuf);
|
||||
if (err && !ret)
|
||||
ret = err;
|
||||
}
|
||||
|
||||
/* Commit the journal unless it has too little data */
|
||||
spin_lock(&c->buds_lock);
|
||||
bud_bytes = c->bud_bytes;
|
||||
spin_unlock(&c->buds_lock);
|
||||
if (bud_bytes > c->leb_size) {
|
||||
err = ubifs_run_commit(c);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We ought to call sync for c->ubi but it does not have one. If it had
|
||||
* it would in turn call mtd->sync, however mtd operations are
|
||||
|
@ -538,6 +561,18 @@ static int init_constants_early(struct ubifs_info *c)
|
|||
* calculations when reporting free space.
|
||||
*/
|
||||
c->leb_overhead = c->leb_size % UBIFS_MAX_DATA_NODE_SZ;
|
||||
/* Buffer size for bulk-reads */
|
||||
c->bulk_read_buf_size = UBIFS_MAX_BULK_READ * UBIFS_MAX_DATA_NODE_SZ;
|
||||
if (c->bulk_read_buf_size > c->leb_size)
|
||||
c->bulk_read_buf_size = c->leb_size;
|
||||
if (c->bulk_read_buf_size > 128 * 1024) {
|
||||
/* Check if we can kmalloc more than 128KiB */
|
||||
void *try = kmalloc(c->bulk_read_buf_size, GFP_KERNEL);
|
||||
|
||||
kfree(try);
|
||||
if (!try)
|
||||
c->bulk_read_buf_size = 128 * 1024;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -840,17 +875,29 @@ static int check_volume_empty(struct ubifs_info *c)
|
|||
*
|
||||
* Opt_fast_unmount: do not run a journal commit before un-mounting
|
||||
* Opt_norm_unmount: run a journal commit before un-mounting
|
||||
* Opt_bulk_read: enable bulk-reads
|
||||
* Opt_no_bulk_read: disable bulk-reads
|
||||
* Opt_chk_data_crc: check CRCs when reading data nodes
|
||||
* Opt_no_chk_data_crc: do not check CRCs when reading data nodes
|
||||
* Opt_err: just end of array marker
|
||||
*/
|
||||
enum {
|
||||
Opt_fast_unmount,
|
||||
Opt_norm_unmount,
|
||||
Opt_bulk_read,
|
||||
Opt_no_bulk_read,
|
||||
Opt_chk_data_crc,
|
||||
Opt_no_chk_data_crc,
|
||||
Opt_err,
|
||||
};
|
||||
|
||||
static const match_table_t tokens = {
|
||||
{Opt_fast_unmount, "fast_unmount"},
|
||||
{Opt_norm_unmount, "norm_unmount"},
|
||||
{Opt_bulk_read, "bulk_read"},
|
||||
{Opt_no_bulk_read, "no_bulk_read"},
|
||||
{Opt_chk_data_crc, "chk_data_crc"},
|
||||
{Opt_no_chk_data_crc, "no_chk_data_crc"},
|
||||
{Opt_err, NULL},
|
||||
};
|
||||
|
||||
|
@ -888,6 +935,22 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options,
|
|||
c->mount_opts.unmount_mode = 1;
|
||||
c->fast_unmount = 0;
|
||||
break;
|
||||
case Opt_bulk_read:
|
||||
c->mount_opts.bulk_read = 2;
|
||||
c->bulk_read = 1;
|
||||
break;
|
||||
case Opt_no_bulk_read:
|
||||
c->mount_opts.bulk_read = 1;
|
||||
c->bulk_read = 0;
|
||||
break;
|
||||
case Opt_chk_data_crc:
|
||||
c->mount_opts.chk_data_crc = 2;
|
||||
c->no_chk_data_crc = 0;
|
||||
break;
|
||||
case Opt_no_chk_data_crc:
|
||||
c->mount_opts.chk_data_crc = 1;
|
||||
c->no_chk_data_crc = 1;
|
||||
break;
|
||||
default:
|
||||
ubifs_err("unrecognized mount option \"%s\" "
|
||||
"or missing value", p);
|
||||
|
@ -996,6 +1059,8 @@ static int mount_ubifs(struct ubifs_info *c)
|
|||
goto out_free;
|
||||
}
|
||||
|
||||
c->always_chk_crc = 1;
|
||||
|
||||
err = ubifs_read_superblock(c);
|
||||
if (err)
|
||||
goto out_free;
|
||||
|
@ -1032,8 +1097,6 @@ static int mount_ubifs(struct ubifs_info *c)
|
|||
|
||||
/* Create background thread */
|
||||
c->bgt = kthread_create(ubifs_bg_thread, c, c->bgt_name);
|
||||
if (!c->bgt)
|
||||
c->bgt = ERR_PTR(-EINVAL);
|
||||
if (IS_ERR(c->bgt)) {
|
||||
err = PTR_ERR(c->bgt);
|
||||
c->bgt = NULL;
|
||||
|
@ -1139,24 +1202,28 @@ static int mount_ubifs(struct ubifs_info *c)
|
|||
if (err)
|
||||
goto out_infos;
|
||||
|
||||
c->always_chk_crc = 0;
|
||||
|
||||
ubifs_msg("mounted UBI device %d, volume %d, name \"%s\"",
|
||||
c->vi.ubi_num, c->vi.vol_id, c->vi.name);
|
||||
if (mounted_read_only)
|
||||
ubifs_msg("mounted read-only");
|
||||
x = (long long)c->main_lebs * c->leb_size;
|
||||
ubifs_msg("file system size: %lld bytes (%lld KiB, %lld MiB, %d LEBs)",
|
||||
x, x >> 10, x >> 20, c->main_lebs);
|
||||
ubifs_msg("file system size: %lld bytes (%lld KiB, %lld MiB, %d "
|
||||
"LEBs)", x, x >> 10, x >> 20, c->main_lebs);
|
||||
x = (long long)c->log_lebs * c->leb_size + c->max_bud_bytes;
|
||||
ubifs_msg("journal size: %lld bytes (%lld KiB, %lld MiB, %d LEBs)",
|
||||
x, x >> 10, x >> 20, c->log_lebs + c->max_bud_cnt);
|
||||
ubifs_msg("default compressor: %s", ubifs_compr_name(c->default_compr));
|
||||
ubifs_msg("media format %d, latest format %d",
|
||||
ubifs_msg("journal size: %lld bytes (%lld KiB, %lld MiB, %d "
|
||||
"LEBs)", x, x >> 10, x >> 20, c->log_lebs + c->max_bud_cnt);
|
||||
ubifs_msg("media format: %d (latest is %d)",
|
||||
c->fmt_version, UBIFS_FORMAT_VERSION);
|
||||
ubifs_msg("default compressor: %s", ubifs_compr_name(c->default_compr));
|
||||
ubifs_msg("reserved for root: %llu bytes (%llu KiB)",
|
||||
c->report_rp_size, c->report_rp_size >> 10);
|
||||
|
||||
dbg_msg("compiled on: " __DATE__ " at " __TIME__);
|
||||
dbg_msg("min. I/O unit size: %d bytes", c->min_io_size);
|
||||
dbg_msg("LEB size: %d bytes (%d KiB)",
|
||||
c->leb_size, c->leb_size / 1024);
|
||||
c->leb_size, c->leb_size >> 10);
|
||||
dbg_msg("data journal heads: %d",
|
||||
c->jhead_cnt - NONDATA_JHEADS_CNT);
|
||||
dbg_msg("UUID: %02X%02X%02X%02X-%02X%02X"
|
||||
|
@ -1282,6 +1349,7 @@ static int ubifs_remount_rw(struct ubifs_info *c)
|
|||
|
||||
mutex_lock(&c->umount_mutex);
|
||||
c->remounting_rw = 1;
|
||||
c->always_chk_crc = 1;
|
||||
|
||||
/* Check for enough free space */
|
||||
if (ubifs_calc_available(c, c->min_idx_lebs) <= 0) {
|
||||
|
@ -1345,20 +1413,20 @@ static int ubifs_remount_rw(struct ubifs_info *c)
|
|||
|
||||
/* Create background thread */
|
||||
c->bgt = kthread_create(ubifs_bg_thread, c, c->bgt_name);
|
||||
if (!c->bgt)
|
||||
c->bgt = ERR_PTR(-EINVAL);
|
||||
if (IS_ERR(c->bgt)) {
|
||||
err = PTR_ERR(c->bgt);
|
||||
c->bgt = NULL;
|
||||
ubifs_err("cannot spawn \"%s\", error %d",
|
||||
c->bgt_name, err);
|
||||
return err;
|
||||
goto out;
|
||||
}
|
||||
wake_up_process(c->bgt);
|
||||
|
||||
c->orph_buf = vmalloc(c->leb_size);
|
||||
if (!c->orph_buf)
|
||||
return -ENOMEM;
|
||||
if (!c->orph_buf) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Check for enough log space */
|
||||
lnum = c->lhead_lnum + 1;
|
||||
|
@ -1385,6 +1453,7 @@ static int ubifs_remount_rw(struct ubifs_info *c)
|
|||
dbg_gen("re-mounted read-write");
|
||||
c->vfs_sb->s_flags &= ~MS_RDONLY;
|
||||
c->remounting_rw = 0;
|
||||
c->always_chk_crc = 0;
|
||||
mutex_unlock(&c->umount_mutex);
|
||||
return 0;
|
||||
|
||||
|
@ -1400,6 +1469,7 @@ out:
|
|||
c->ileb_buf = NULL;
|
||||
ubifs_lpt_free(c, 1);
|
||||
c->remounting_rw = 0;
|
||||
c->always_chk_crc = 0;
|
||||
mutex_unlock(&c->umount_mutex);
|
||||
return err;
|
||||
}
|
||||
|
@ -1408,12 +1478,9 @@ out:
|
|||
* commit_on_unmount - commit the journal when un-mounting.
|
||||
* @c: UBIFS file-system description object
|
||||
*
|
||||
* This function is called during un-mounting and it commits the journal unless
|
||||
* the "fast unmount" mode is enabled. It also avoids committing the journal if
|
||||
* it contains too few data.
|
||||
*
|
||||
* Sometimes recovery requires the journal to be committed at least once, and
|
||||
* this function takes care about this.
|
||||
* This function is called during un-mounting and re-mounting, and it commits
|
||||
* the journal unless the "fast unmount" mode is enabled. It also avoids
|
||||
* committing the journal if it contains too few data.
|
||||
*/
|
||||
static void commit_on_unmount(struct ubifs_info *c)
|
||||
{
|
||||
|
|
339
fs/ubifs/tnc.c
339
fs/ubifs/tnc.c
|
@ -284,7 +284,7 @@ static struct ubifs_znode *dirty_cow_znode(struct ubifs_info *c,
|
|||
}
|
||||
|
||||
zn = copy_znode(c, znode);
|
||||
if (unlikely(IS_ERR(zn)))
|
||||
if (IS_ERR(zn))
|
||||
return zn;
|
||||
|
||||
if (zbr->len) {
|
||||
|
@ -470,6 +470,10 @@ static int try_read_node(const struct ubifs_info *c, void *buf, int type,
|
|||
if (node_len != len)
|
||||
return 0;
|
||||
|
||||
if (type == UBIFS_DATA_NODE && !c->always_chk_crc)
|
||||
if (c->no_chk_data_crc)
|
||||
return 0;
|
||||
|
||||
crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8);
|
||||
node_crc = le32_to_cpu(ch->crc);
|
||||
if (crc != node_crc)
|
||||
|
@ -1128,7 +1132,7 @@ static struct ubifs_znode *dirty_cow_bottom_up(struct ubifs_info *c,
|
|||
ubifs_assert(znode == c->zroot.znode);
|
||||
znode = dirty_cow_znode(c, &c->zroot);
|
||||
}
|
||||
if (unlikely(IS_ERR(znode)) || !p)
|
||||
if (IS_ERR(znode) || !p)
|
||||
break;
|
||||
ubifs_assert(path[p - 1] >= 0);
|
||||
ubifs_assert(path[p - 1] < znode->child_cnt);
|
||||
|
@ -1491,6 +1495,289 @@ out:
|
|||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* ubifs_tnc_get_bu_keys - lookup keys for bulk-read.
|
||||
* @c: UBIFS file-system description object
|
||||
* @bu: bulk-read parameters and results
|
||||
*
|
||||
* Lookup consecutive data node keys for the same inode that reside
|
||||
* consecutively in the same LEB.
|
||||
*/
|
||||
int ubifs_tnc_get_bu_keys(struct ubifs_info *c, struct bu_info *bu)
|
||||
{
|
||||
int n, err = 0, lnum = -1, uninitialized_var(offs);
|
||||
int uninitialized_var(len);
|
||||
unsigned int block = key_block(c, &bu->key);
|
||||
struct ubifs_znode *znode;
|
||||
|
||||
bu->cnt = 0;
|
||||
bu->blk_cnt = 0;
|
||||
bu->eof = 0;
|
||||
|
||||
mutex_lock(&c->tnc_mutex);
|
||||
/* Find first key */
|
||||
err = ubifs_lookup_level0(c, &bu->key, &znode, &n);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
if (err) {
|
||||
/* Key found */
|
||||
len = znode->zbranch[n].len;
|
||||
/* The buffer must be big enough for at least 1 node */
|
||||
if (len > bu->buf_len) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
/* Add this key */
|
||||
bu->zbranch[bu->cnt++] = znode->zbranch[n];
|
||||
bu->blk_cnt += 1;
|
||||
lnum = znode->zbranch[n].lnum;
|
||||
offs = ALIGN(znode->zbranch[n].offs + len, 8);
|
||||
}
|
||||
while (1) {
|
||||
struct ubifs_zbranch *zbr;
|
||||
union ubifs_key *key;
|
||||
unsigned int next_block;
|
||||
|
||||
/* Find next key */
|
||||
err = tnc_next(c, &znode, &n);
|
||||
if (err)
|
||||
goto out;
|
||||
zbr = &znode->zbranch[n];
|
||||
key = &zbr->key;
|
||||
/* See if there is another data key for this file */
|
||||
if (key_inum(c, key) != key_inum(c, &bu->key) ||
|
||||
key_type(c, key) != UBIFS_DATA_KEY) {
|
||||
err = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
if (lnum < 0) {
|
||||
/* First key found */
|
||||
lnum = zbr->lnum;
|
||||
offs = ALIGN(zbr->offs + zbr->len, 8);
|
||||
len = zbr->len;
|
||||
if (len > bu->buf_len) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* The data nodes must be in consecutive positions in
|
||||
* the same LEB.
|
||||
*/
|
||||
if (zbr->lnum != lnum || zbr->offs != offs)
|
||||
goto out;
|
||||
offs += ALIGN(zbr->len, 8);
|
||||
len = ALIGN(len, 8) + zbr->len;
|
||||
/* Must not exceed buffer length */
|
||||
if (len > bu->buf_len)
|
||||
goto out;
|
||||
}
|
||||
/* Allow for holes */
|
||||
next_block = key_block(c, key);
|
||||
bu->blk_cnt += (next_block - block - 1);
|
||||
if (bu->blk_cnt >= UBIFS_MAX_BULK_READ)
|
||||
goto out;
|
||||
block = next_block;
|
||||
/* Add this key */
|
||||
bu->zbranch[bu->cnt++] = *zbr;
|
||||
bu->blk_cnt += 1;
|
||||
/* See if we have room for more */
|
||||
if (bu->cnt >= UBIFS_MAX_BULK_READ)
|
||||
goto out;
|
||||
if (bu->blk_cnt >= UBIFS_MAX_BULK_READ)
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
if (err == -ENOENT) {
|
||||
bu->eof = 1;
|
||||
err = 0;
|
||||
}
|
||||
bu->gc_seq = c->gc_seq;
|
||||
mutex_unlock(&c->tnc_mutex);
|
||||
if (err)
|
||||
return err;
|
||||
/*
|
||||
* An enormous hole could cause bulk-read to encompass too many
|
||||
* page cache pages, so limit the number here.
|
||||
*/
|
||||
if (bu->blk_cnt > UBIFS_MAX_BULK_READ)
|
||||
bu->blk_cnt = UBIFS_MAX_BULK_READ;
|
||||
/*
|
||||
* Ensure that bulk-read covers a whole number of page cache
|
||||
* pages.
|
||||
*/
|
||||
if (UBIFS_BLOCKS_PER_PAGE == 1 ||
|
||||
!(bu->blk_cnt & (UBIFS_BLOCKS_PER_PAGE - 1)))
|
||||
return 0;
|
||||
if (bu->eof) {
|
||||
/* At the end of file we can round up */
|
||||
bu->blk_cnt += UBIFS_BLOCKS_PER_PAGE - 1;
|
||||
return 0;
|
||||
}
|
||||
/* Exclude data nodes that do not make up a whole page cache page */
|
||||
block = key_block(c, &bu->key) + bu->blk_cnt;
|
||||
block &= ~(UBIFS_BLOCKS_PER_PAGE - 1);
|
||||
while (bu->cnt) {
|
||||
if (key_block(c, &bu->zbranch[bu->cnt - 1].key) < block)
|
||||
break;
|
||||
bu->cnt -= 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* read_wbuf - bulk-read from a LEB with a wbuf.
|
||||
* @wbuf: wbuf that may overlap the read
|
||||
* @buf: buffer into which to read
|
||||
* @len: read length
|
||||
* @lnum: LEB number from which to read
|
||||
* @offs: offset from which to read
|
||||
*
|
||||
* This functions returns %0 on success or a negative error code on failure.
|
||||
*/
|
||||
static int read_wbuf(struct ubifs_wbuf *wbuf, void *buf, int len, int lnum,
|
||||
int offs)
|
||||
{
|
||||
const struct ubifs_info *c = wbuf->c;
|
||||
int rlen, overlap;
|
||||
|
||||
dbg_io("LEB %d:%d, length %d", lnum, offs, len);
|
||||
ubifs_assert(wbuf && lnum >= 0 && lnum < c->leb_cnt && offs >= 0);
|
||||
ubifs_assert(!(offs & 7) && offs < c->leb_size);
|
||||
ubifs_assert(offs + len <= c->leb_size);
|
||||
|
||||
spin_lock(&wbuf->lock);
|
||||
overlap = (lnum == wbuf->lnum && offs + len > wbuf->offs);
|
||||
if (!overlap) {
|
||||
/* We may safely unlock the write-buffer and read the data */
|
||||
spin_unlock(&wbuf->lock);
|
||||
return ubi_read(c->ubi, lnum, buf, offs, len);
|
||||
}
|
||||
|
||||
/* Don't read under wbuf */
|
||||
rlen = wbuf->offs - offs;
|
||||
if (rlen < 0)
|
||||
rlen = 0;
|
||||
|
||||
/* Copy the rest from the write-buffer */
|
||||
memcpy(buf + rlen, wbuf->buf + offs + rlen - wbuf->offs, len - rlen);
|
||||
spin_unlock(&wbuf->lock);
|
||||
|
||||
if (rlen > 0)
|
||||
/* Read everything that goes before write-buffer */
|
||||
return ubi_read(c->ubi, lnum, buf, offs, rlen);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* validate_data_node - validate data nodes for bulk-read.
|
||||
* @c: UBIFS file-system description object
|
||||
* @buf: buffer containing data node to validate
|
||||
* @zbr: zbranch of data node to validate
|
||||
*
|
||||
* This functions returns %0 on success or a negative error code on failure.
|
||||
*/
|
||||
static int validate_data_node(struct ubifs_info *c, void *buf,
|
||||
struct ubifs_zbranch *zbr)
|
||||
{
|
||||
union ubifs_key key1;
|
||||
struct ubifs_ch *ch = buf;
|
||||
int err, len;
|
||||
|
||||
if (ch->node_type != UBIFS_DATA_NODE) {
|
||||
ubifs_err("bad node type (%d but expected %d)",
|
||||
ch->node_type, UBIFS_DATA_NODE);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
err = ubifs_check_node(c, buf, zbr->lnum, zbr->offs, 0, 0);
|
||||
if (err) {
|
||||
ubifs_err("expected node type %d", UBIFS_DATA_NODE);
|
||||
goto out;
|
||||
}
|
||||
|
||||
len = le32_to_cpu(ch->len);
|
||||
if (len != zbr->len) {
|
||||
ubifs_err("bad node length %d, expected %d", len, zbr->len);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/* Make sure the key of the read node is correct */
|
||||
key_read(c, buf + UBIFS_KEY_OFFSET, &key1);
|
||||
if (!keys_eq(c, &zbr->key, &key1)) {
|
||||
ubifs_err("bad key in node at LEB %d:%d",
|
||||
zbr->lnum, zbr->offs);
|
||||
dbg_tnc("looked for key %s found node's key %s",
|
||||
DBGKEY(&zbr->key), DBGKEY1(&key1));
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
err = -EINVAL;
|
||||
out:
|
||||
ubifs_err("bad node at LEB %d:%d", zbr->lnum, zbr->offs);
|
||||
dbg_dump_node(c, buf);
|
||||
dbg_dump_stack();
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* ubifs_tnc_bulk_read - read a number of data nodes in one go.
|
||||
* @c: UBIFS file-system description object
|
||||
* @bu: bulk-read parameters and results
|
||||
*
|
||||
* This functions reads and validates the data nodes that were identified by the
|
||||
* 'ubifs_tnc_get_bu_keys()' function. This functions returns %0 on success,
|
||||
* -EAGAIN to indicate a race with GC, or another negative error code on
|
||||
* failure.
|
||||
*/
|
||||
int ubifs_tnc_bulk_read(struct ubifs_info *c, struct bu_info *bu)
|
||||
{
|
||||
int lnum = bu->zbranch[0].lnum, offs = bu->zbranch[0].offs, len, err, i;
|
||||
struct ubifs_wbuf *wbuf;
|
||||
void *buf;
|
||||
|
||||
len = bu->zbranch[bu->cnt - 1].offs;
|
||||
len += bu->zbranch[bu->cnt - 1].len - offs;
|
||||
if (len > bu->buf_len) {
|
||||
ubifs_err("buffer too small %d vs %d", bu->buf_len, len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Do the read */
|
||||
wbuf = ubifs_get_wbuf(c, lnum);
|
||||
if (wbuf)
|
||||
err = read_wbuf(wbuf, bu->buf, len, lnum, offs);
|
||||
else
|
||||
err = ubi_read(c->ubi, lnum, bu->buf, offs, len);
|
||||
|
||||
/* Check for a race with GC */
|
||||
if (maybe_leb_gced(c, lnum, bu->gc_seq))
|
||||
return -EAGAIN;
|
||||
|
||||
if (err && err != -EBADMSG) {
|
||||
ubifs_err("failed to read from LEB %d:%d, error %d",
|
||||
lnum, offs, err);
|
||||
dbg_dump_stack();
|
||||
dbg_tnc("key %s", DBGKEY(&bu->key));
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Validate the nodes read */
|
||||
buf = bu->buf;
|
||||
for (i = 0; i < bu->cnt; i++) {
|
||||
err = validate_data_node(c, buf, &bu->zbranch[i]);
|
||||
if (err)
|
||||
return err;
|
||||
buf = buf + ALIGN(bu->zbranch[i].len, 8);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* do_lookup_nm- look up a "hashed" node.
|
||||
* @c: UBIFS file-system description object
|
||||
|
@ -1675,7 +1962,7 @@ static int tnc_insert(struct ubifs_info *c, struct ubifs_znode *znode,
|
|||
{
|
||||
struct ubifs_znode *zn, *zi, *zp;
|
||||
int i, keep, move, appending = 0;
|
||||
union ubifs_key *key = &zbr->key;
|
||||
union ubifs_key *key = &zbr->key, *key1;
|
||||
|
||||
ubifs_assert(n >= 0 && n <= c->fanout);
|
||||
|
||||
|
@ -1716,20 +2003,33 @@ again:
|
|||
zn->level = znode->level;
|
||||
|
||||
/* Decide where to split */
|
||||
if (znode->level == 0 && n == c->fanout &&
|
||||
key_type(c, key) == UBIFS_DATA_KEY) {
|
||||
union ubifs_key *key1;
|
||||
|
||||
/*
|
||||
* If this is an inode which is being appended - do not split
|
||||
* it because no other zbranches can be inserted between
|
||||
* zbranches of consecutive data nodes anyway.
|
||||
*/
|
||||
if (znode->level == 0 && key_type(c, key) == UBIFS_DATA_KEY) {
|
||||
/* Try not to split consecutive data keys */
|
||||
if (n == c->fanout) {
|
||||
key1 = &znode->zbranch[n - 1].key;
|
||||
if (key_inum(c, key1) == key_inum(c, key) &&
|
||||
key_type(c, key1) == UBIFS_DATA_KEY &&
|
||||
key_block(c, key1) == key_block(c, key) - 1)
|
||||
key_type(c, key1) == UBIFS_DATA_KEY)
|
||||
appending = 1;
|
||||
} else
|
||||
goto check_split;
|
||||
} else if (appending && n != c->fanout) {
|
||||
/* Try not to split consecutive data keys */
|
||||
appending = 0;
|
||||
check_split:
|
||||
if (n >= (c->fanout + 1) / 2) {
|
||||
key1 = &znode->zbranch[0].key;
|
||||
if (key_inum(c, key1) == key_inum(c, key) &&
|
||||
key_type(c, key1) == UBIFS_DATA_KEY) {
|
||||
key1 = &znode->zbranch[n].key;
|
||||
if (key_inum(c, key1) != key_inum(c, key) ||
|
||||
key_type(c, key1) != UBIFS_DATA_KEY) {
|
||||
keep = n;
|
||||
move = c->fanout - keep;
|
||||
zi = znode;
|
||||
goto do_split;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (appending) {
|
||||
|
@ -1759,6 +2059,8 @@ again:
|
|||
zbr->znode->parent = zn;
|
||||
}
|
||||
|
||||
do_split:
|
||||
|
||||
__set_bit(DIRTY_ZNODE, &zn->flags);
|
||||
atomic_long_inc(&c->dirty_zn_cnt);
|
||||
|
||||
|
@ -1785,14 +2087,11 @@ again:
|
|||
|
||||
/* Insert new znode (produced by spitting) into the parent */
|
||||
if (zp) {
|
||||
i = n;
|
||||
if (n == 0 && zi == znode && znode->iip == 0)
|
||||
correct_parent_keys(c, znode);
|
||||
|
||||
/* Locate insertion point */
|
||||
n = znode->iip + 1;
|
||||
if (appending && n != c->fanout)
|
||||
appending = 0;
|
||||
|
||||
if (i == 0 && zi == znode && znode->iip == 0)
|
||||
correct_parent_keys(c, znode);
|
||||
|
||||
/* Tail recursion */
|
||||
zbr->key = zn->zbranch[0].key;
|
||||
|
|
|
@ -480,8 +480,8 @@ int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
|
|||
}
|
||||
|
||||
/* Make sure the key of the read node is correct */
|
||||
key_read(c, key, &key1);
|
||||
if (memcmp(node + UBIFS_KEY_OFFSET, &key1, c->key_len)) {
|
||||
key_read(c, node + UBIFS_KEY_OFFSET, &key1);
|
||||
if (!keys_eq(c, key, &key1)) {
|
||||
ubifs_err("bad key in node at LEB %d:%d",
|
||||
zbr->lnum, zbr->offs);
|
||||
dbg_tnc("looked for key %s found node's key %s",
|
||||
|
|
|
@ -75,7 +75,6 @@
|
|||
*/
|
||||
#define UBIFS_BLOCK_SIZE 4096
|
||||
#define UBIFS_BLOCK_SHIFT 12
|
||||
#define UBIFS_BLOCK_MASK 0x00000FFF
|
||||
|
||||
/* UBIFS padding byte pattern (must not be first or last byte of node magic) */
|
||||
#define UBIFS_PADDING_BYTE 0xCE
|
||||
|
|
|
@ -142,6 +142,9 @@
|
|||
/* Maximum expected tree height for use by bottom_up_buf */
|
||||
#define BOTTOM_UP_HEIGHT 64
|
||||
|
||||
/* Maximum number of data nodes to bulk-read */
|
||||
#define UBIFS_MAX_BULK_READ 32
|
||||
|
||||
/*
|
||||
* Lockdep classes for UBIFS inode @ui_mutex.
|
||||
*/
|
||||
|
@ -328,9 +331,10 @@ struct ubifs_gced_idx_leb {
|
|||
* this inode
|
||||
* @dirty: non-zero if the inode is dirty
|
||||
* @xattr: non-zero if this is an extended attribute inode
|
||||
* @bulk_read: non-zero if bulk-read should be used
|
||||
* @ui_mutex: serializes inode write-back with the rest of VFS operations,
|
||||
* serializes "clean <-> dirty" state changes, protects @dirty,
|
||||
* @ui_size, and @xattr_size
|
||||
* serializes "clean <-> dirty" state changes, serializes bulk-read,
|
||||
* protects @dirty, @bulk_read, @ui_size, and @xattr_size
|
||||
* @ui_lock: protects @synced_i_size
|
||||
* @synced_i_size: synchronized size of inode, i.e. the value of inode size
|
||||
* currently stored on the flash; used only for regular file
|
||||
|
@ -338,6 +342,8 @@ struct ubifs_gced_idx_leb {
|
|||
* @ui_size: inode size used by UBIFS when writing to flash
|
||||
* @flags: inode flags (@UBIFS_COMPR_FL, etc)
|
||||
* @compr_type: default compression type used for this inode
|
||||
* @last_page_read: page number of last page read (for bulk read)
|
||||
* @read_in_a_row: number of consecutive pages read in a row (for bulk read)
|
||||
* @data_len: length of the data attached to the inode
|
||||
* @data: inode's data
|
||||
*
|
||||
|
@ -379,12 +385,15 @@ struct ubifs_inode {
|
|||
unsigned int xattr_names;
|
||||
unsigned int dirty:1;
|
||||
unsigned int xattr:1;
|
||||
unsigned int bulk_read:1;
|
||||
struct mutex ui_mutex;
|
||||
spinlock_t ui_lock;
|
||||
loff_t synced_i_size;
|
||||
loff_t ui_size;
|
||||
int flags;
|
||||
int compr_type;
|
||||
pgoff_t last_page_read;
|
||||
pgoff_t read_in_a_row;
|
||||
int data_len;
|
||||
void *data;
|
||||
};
|
||||
|
@ -698,8 +707,8 @@ struct ubifs_jhead {
|
|||
* struct ubifs_zbranch - key/coordinate/length branch stored in znodes.
|
||||
* @key: key
|
||||
* @znode: znode address in memory
|
||||
* @lnum: LEB number of the indexing node
|
||||
* @offs: offset of the indexing node within @lnum
|
||||
* @lnum: LEB number of the target node (indexing node or data node)
|
||||
* @offs: target node offset within @lnum
|
||||
* @len: target node length
|
||||
*/
|
||||
struct ubifs_zbranch {
|
||||
|
@ -743,6 +752,28 @@ struct ubifs_znode {
|
|||
struct ubifs_zbranch zbranch[];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct bu_info - bulk-read information
|
||||
* @key: first data node key
|
||||
* @zbranch: zbranches of data nodes to bulk read
|
||||
* @buf: buffer to read into
|
||||
* @buf_len: buffer length
|
||||
* @gc_seq: GC sequence number to detect races with GC
|
||||
* @cnt: number of data nodes for bulk read
|
||||
* @blk_cnt: number of data blocks including holes
|
||||
* @oef: end of file reached
|
||||
*/
|
||||
struct bu_info {
|
||||
union ubifs_key key;
|
||||
struct ubifs_zbranch zbranch[UBIFS_MAX_BULK_READ];
|
||||
void *buf;
|
||||
int buf_len;
|
||||
int gc_seq;
|
||||
int cnt;
|
||||
int blk_cnt;
|
||||
int eof;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ubifs_node_range - node length range description data structure.
|
||||
* @len: fixed node length
|
||||
|
@ -862,9 +893,13 @@ struct ubifs_orphan {
|
|||
/**
|
||||
* struct ubifs_mount_opts - UBIFS-specific mount options information.
|
||||
* @unmount_mode: selected unmount mode (%0 default, %1 normal, %2 fast)
|
||||
* @bulk_read: enable bulk-reads
|
||||
* @chk_data_crc: check CRCs when reading data nodes
|
||||
*/
|
||||
struct ubifs_mount_opts {
|
||||
unsigned int unmount_mode:2;
|
||||
unsigned int bulk_read:2;
|
||||
unsigned int chk_data_crc:2;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -905,13 +940,12 @@ struct ubifs_mount_opts {
|
|||
* @cmt_state: commit state
|
||||
* @cs_lock: commit state lock
|
||||
* @cmt_wq: wait queue to sleep on if the log is full and a commit is running
|
||||
*
|
||||
* @fast_unmount: do not run journal commit before un-mounting
|
||||
* @big_lpt: flag that LPT is too big to write whole during commit
|
||||
* @check_lpt_free: flag that indicates LPT GC may be needed
|
||||
* @nospace: non-zero if the file-system does not have flash space (used as
|
||||
* optimization)
|
||||
* @nospace_rp: the same as @nospace, but additionally means that even reserved
|
||||
* pool is full
|
||||
* @no_chk_data_crc: do not check CRCs when reading data nodes (except during
|
||||
* recovery)
|
||||
* @bulk_read: enable bulk-reads
|
||||
*
|
||||
* @tnc_mutex: protects the Tree Node Cache (TNC), @zroot, @cnext, @enext, and
|
||||
* @calc_idx_sz
|
||||
|
@ -935,6 +969,7 @@ struct ubifs_mount_opts {
|
|||
* @mst_node: master node
|
||||
* @mst_offs: offset of valid master node
|
||||
* @mst_mutex: protects the master node area, @mst_node, and @mst_offs
|
||||
* @bulk_read_buf_size: buffer size for bulk-reads
|
||||
*
|
||||
* @log_lebs: number of logical eraseblocks in the log
|
||||
* @log_bytes: log size in bytes
|
||||
|
@ -977,12 +1012,17 @@ struct ubifs_mount_opts {
|
|||
* but which still have to be taken into account because
|
||||
* the index has not been committed so far
|
||||
* @space_lock: protects @budg_idx_growth, @budg_data_growth, @budg_dd_growth,
|
||||
* @budg_uncommited_idx, @min_idx_lebs, @old_idx_sz, and @lst;
|
||||
* @budg_uncommited_idx, @min_idx_lebs, @old_idx_sz, @lst,
|
||||
* @nospace, and @nospace_rp;
|
||||
* @min_idx_lebs: minimum number of LEBs required for the index
|
||||
* @old_idx_sz: size of index on flash
|
||||
* @calc_idx_sz: temporary variable which is used to calculate new index size
|
||||
* (contains accurate new index size at end of TNC commit start)
|
||||
* @lst: lprops statistics
|
||||
* @nospace: non-zero if the file-system does not have flash space (used as
|
||||
* optimization)
|
||||
* @nospace_rp: the same as @nospace, but additionally means that even reserved
|
||||
* pool is full
|
||||
*
|
||||
* @page_budget: budget for a page
|
||||
* @inode_budget: budget for an inode
|
||||
|
@ -1061,6 +1101,7 @@ struct ubifs_mount_opts {
|
|||
* @lpt_drty_flgs: dirty flags for LPT special nodes e.g. ltab
|
||||
* @dirty_nn_cnt: number of dirty nnodes
|
||||
* @dirty_pn_cnt: number of dirty pnodes
|
||||
* @check_lpt_free: flag that indicates LPT GC may be needed
|
||||
* @lpt_sz: LPT size
|
||||
* @lpt_nod_buf: buffer for an on-flash nnode or pnode
|
||||
* @lpt_buf: buffer of LEB size used by LPT
|
||||
|
@ -1102,6 +1143,7 @@ struct ubifs_mount_opts {
|
|||
* @rcvrd_mst_node: recovered master node to write when mounting ro to rw
|
||||
* @size_tree: inode size information for recovery
|
||||
* @remounting_rw: set while remounting from ro to rw (sb flags have MS_RDONLY)
|
||||
* @always_chk_crc: always check CRCs (while mounting and remounting rw)
|
||||
* @mount_opts: UBIFS-specific mount options
|
||||
*
|
||||
* @dbg_buf: a buffer of LEB size used for debugging purposes
|
||||
|
@ -1146,11 +1188,11 @@ struct ubifs_info {
|
|||
int cmt_state;
|
||||
spinlock_t cs_lock;
|
||||
wait_queue_head_t cmt_wq;
|
||||
|
||||
unsigned int fast_unmount:1;
|
||||
unsigned int big_lpt:1;
|
||||
unsigned int check_lpt_free:1;
|
||||
unsigned int nospace:1;
|
||||
unsigned int nospace_rp:1;
|
||||
unsigned int no_chk_data_crc:1;
|
||||
unsigned int bulk_read:1;
|
||||
|
||||
struct mutex tnc_mutex;
|
||||
struct ubifs_zbranch zroot;
|
||||
|
@ -1175,6 +1217,7 @@ struct ubifs_info {
|
|||
struct ubifs_mst_node *mst_node;
|
||||
int mst_offs;
|
||||
struct mutex mst_mutex;
|
||||
int bulk_read_buf_size;
|
||||
|
||||
int log_lebs;
|
||||
long long log_bytes;
|
||||
|
@ -1218,6 +1261,8 @@ struct ubifs_info {
|
|||
unsigned long long old_idx_sz;
|
||||
unsigned long long calc_idx_sz;
|
||||
struct ubifs_lp_stats lst;
|
||||
unsigned int nospace:1;
|
||||
unsigned int nospace_rp:1;
|
||||
|
||||
int page_budget;
|
||||
int inode_budget;
|
||||
|
@ -1294,6 +1339,7 @@ struct ubifs_info {
|
|||
int lpt_drty_flgs;
|
||||
int dirty_nn_cnt;
|
||||
int dirty_pn_cnt;
|
||||
int check_lpt_free;
|
||||
long long lpt_sz;
|
||||
void *lpt_nod_buf;
|
||||
void *lpt_buf;
|
||||
|
@ -1335,6 +1381,7 @@ struct ubifs_info {
|
|||
struct ubifs_mst_node *rcvrd_mst_node;
|
||||
struct rb_root size_tree;
|
||||
int remounting_rw;
|
||||
int always_chk_crc;
|
||||
struct ubifs_mount_opts mount_opts;
|
||||
|
||||
#ifdef CONFIG_UBIFS_FS_DEBUG
|
||||
|
@ -1347,6 +1394,12 @@ struct ubifs_info {
|
|||
unsigned long fail_timeout;
|
||||
unsigned int fail_cnt;
|
||||
unsigned int fail_cnt_max;
|
||||
long long chk_lpt_sz;
|
||||
long long chk_lpt_sz2;
|
||||
long long chk_lpt_wastage;
|
||||
int chk_lpt_lebs;
|
||||
int new_nhead_lnum;
|
||||
int new_nhead_offs;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -1377,7 +1430,7 @@ int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len,
|
|||
int ubifs_write_node(struct ubifs_info *c, void *node, int len, int lnum,
|
||||
int offs, int dtype);
|
||||
int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
|
||||
int offs, int quiet);
|
||||
int offs, int quiet, int chk_crc);
|
||||
void ubifs_prepare_node(struct ubifs_info *c, void *buf, int len, int pad);
|
||||
void ubifs_prep_grp_node(struct ubifs_info *c, void *node, int len, int last);
|
||||
int ubifs_io_init(struct ubifs_info *c);
|
||||
|
@ -1490,6 +1543,8 @@ void destroy_old_idx(struct ubifs_info *c);
|
|||
int is_idx_node_in_tnc(struct ubifs_info *c, union ubifs_key *key, int level,
|
||||
int lnum, int offs);
|
||||
int insert_old_idx_znode(struct ubifs_info *c, struct ubifs_znode *znode);
|
||||
int ubifs_tnc_get_bu_keys(struct ubifs_info *c, struct bu_info *bu);
|
||||
int ubifs_tnc_bulk_read(struct ubifs_info *c, struct bu_info *bu);
|
||||
|
||||
/* tnc_misc.c */
|
||||
struct ubifs_znode *ubifs_tnc_levelorder_next(struct ubifs_znode *zr,
|
||||
|
@ -1586,12 +1641,10 @@ int ubifs_lpt_post_commit(struct ubifs_info *c);
|
|||
void ubifs_lpt_free(struct ubifs_info *c, int wr_only);
|
||||
|
||||
/* lprops.c */
|
||||
void ubifs_get_lprops(struct ubifs_info *c);
|
||||
const struct ubifs_lprops *ubifs_change_lp(struct ubifs_info *c,
|
||||
const struct ubifs_lprops *lp,
|
||||
int free, int dirty, int flags,
|
||||
int idx_gc_cnt);
|
||||
void ubifs_release_lprops(struct ubifs_info *c);
|
||||
void ubifs_get_lp_stats(struct ubifs_info *c, struct ubifs_lp_stats *stats);
|
||||
void ubifs_add_to_cat(struct ubifs_info *c, struct ubifs_lprops *lprops,
|
||||
int cat);
|
||||
|
|
|
@ -446,7 +446,7 @@ ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size)
|
|||
int type;
|
||||
|
||||
xent = ubifs_tnc_next_ent(c, &key, &nm);
|
||||
if (unlikely(IS_ERR(xent))) {
|
||||
if (IS_ERR(xent)) {
|
||||
err = PTR_ERR(xent);
|
||||
break;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче