1
0
Fork 0

Merge branch 'linux-next' of git://git.infradead.org/ubifs-2.6

* 'linux-next' of git://git.infradead.org/ubifs-2.6: (33 commits)
  UBIFS: add more useful debugging prints
  UBIFS: print debugging messages properly
  UBIFS: fix numerous spelling mistakes
  UBIFS: allow mounting when short of space
  UBIFS: fix writing uncompressed files
  UBIFS: fix checkpatch.pl warnings
  UBIFS: fix sparse warnings
  UBIFS: simplify make_free_space
  UBIFS: do not lie about used blocks
  UBIFS: restore budg_uncommitted_idx
  UBIFS: always commit on unmount
  UBIFS: use ubi_sync
  UBIFS: always commit in sync_fs
  UBIFS: fix file-system synchronization
  UBIFS: fix constants initialization
  UBIFS: avoid unnecessary calculations
  UBIFS: re-calculate min_idx_size after the commit
  UBIFS: use nicer 64-bit math
  UBIFS: fix available blocks count
  UBIFS: various comment improvements and fixes
  ...
hifive-unleashed-5.1
Linus Torvalds 2009-01-02 15:57:47 -08:00
commit 8e3bda0863
21 changed files with 926 additions and 473 deletions

View File

@ -95,6 +95,9 @@ no_chk_data_crc skip checking of CRCs on data nodes in order to
of this option is that corruption of the contents of this option is that corruption of the contents
of a file can go unnoticed. of a file can go unnoticed.
chk_data_crc (*) do not skip checking CRCs on data nodes chk_data_crc (*) do not skip checking CRCs on data nodes
compr=none override default compressor and set it to "none"
compr=lzo override default compressor and set it to "lzo"
compr=zlib override default compressor and set it to "zlib"
Quick usage instructions Quick usage instructions

View File

@ -32,18 +32,15 @@
#include "ubifs.h" #include "ubifs.h"
#include <linux/writeback.h> #include <linux/writeback.h>
#include <asm/div64.h> #include <linux/math64.h>
/* /*
* When pessimistic budget calculations say that there is no enough space, * When pessimistic budget calculations say that there is no enough space,
* UBIFS starts writing back dirty inodes and pages, doing garbage collection, * UBIFS starts writing back dirty inodes and pages, doing garbage collection,
* or committing. The below constants define maximum number of times UBIFS * or committing. The below constant defines maximum number of times UBIFS
* repeats the operations. * repeats the operations.
*/ */
#define MAX_SHRINK_RETRIES 8 #define MAX_MKSPC_RETRIES 3
#define MAX_GC_RETRIES 4
#define MAX_CMT_RETRIES 2
#define MAX_NOSPC_RETRIES 1
/* /*
* The below constant defines amount of dirty pages which should be written * The below constant defines amount of dirty pages which should be written
@ -51,30 +48,6 @@
*/ */
#define NR_TO_WRITE 16 #define NR_TO_WRITE 16
/**
* struct retries_info - information about re-tries while making free space.
* @prev_liability: previous liability
* @shrink_cnt: how many times the liability was shrinked
* @shrink_retries: count of liability shrink re-tries (increased when
* liability does not shrink)
* @try_gc: GC should be tried first
* @gc_retries: how many times GC was run
* @cmt_retries: how many times commit has been done
* @nospc_retries: how many times GC returned %-ENOSPC
*
* Since we consider budgeting to be the fast-path, and this structure has to
* be allocated on stack and zeroed out, we make it smaller using bit-fields.
*/
struct retries_info {
long long prev_liability;
unsigned int shrink_cnt;
unsigned int shrink_retries:5;
unsigned int try_gc:1;
unsigned int gc_retries:4;
unsigned int cmt_retries:3;
unsigned int nospc_retries:1;
};
/** /**
* shrink_liability - write-back some dirty pages/inodes. * shrink_liability - write-back some dirty pages/inodes.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
@ -146,10 +119,26 @@ static int run_gc(struct ubifs_info *c)
return 0; return 0;
} }
/**
* get_liability - calculate current liability.
* @c: UBIFS file-system description object
*
* This function calculates and returns current UBIFS liability, i.e. the
* amount of bytes UBIFS has "promised" to write to the media.
*/
static long long get_liability(struct ubifs_info *c)
{
long long liab;
spin_lock(&c->space_lock);
liab = c->budg_idx_growth + c->budg_data_growth + c->budg_dd_growth;
spin_unlock(&c->space_lock);
return liab;
}
/** /**
* make_free_space - make more free space on the file-system. * make_free_space - make more free space on the file-system.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
* @ri: information about previous invocations of this function
* *
* This function is called when an operation cannot be budgeted because there * This function is called when an operation cannot be budgeted because there
* is supposedly no free space. But in most cases there is some free space: * is supposedly no free space. But in most cases there is some free space:
@ -165,87 +154,42 @@ static int run_gc(struct ubifs_info *c)
* Returns %-ENOSPC if it couldn't do more free space, and other negative error * Returns %-ENOSPC if it couldn't do more free space, and other negative error
* codes on failures. * codes on failures.
*/ */
static int make_free_space(struct ubifs_info *c, struct retries_info *ri) static int make_free_space(struct ubifs_info *c)
{ {
int err; int err, retries = 0;
long long liab1, liab2;
/* do {
* If we have some dirty pages and inodes (liability), try to write liab1 = get_liability(c);
* them back unless this was tried too many times without effect /*
* already. * We probably have some dirty pages or inodes (liability), try
*/ * to write them back.
if (ri->shrink_retries < MAX_SHRINK_RETRIES && !ri->try_gc) { */
long long liability; dbg_budg("liability %lld, run write-back", liab1);
shrink_liability(c, NR_TO_WRITE);
spin_lock(&c->space_lock); liab2 = get_liability(c);
liability = c->budg_idx_growth + c->budg_data_growth + if (liab2 < liab1)
c->budg_dd_growth; return -EAGAIN;
spin_unlock(&c->space_lock);
if (ri->prev_liability >= liability) { dbg_budg("new liability %lld (not shrinked)", liab2);
/* Liability does not shrink, next time try GC then */
ri->shrink_retries += 1;
if (ri->gc_retries < MAX_GC_RETRIES)
ri->try_gc = 1;
dbg_budg("liability did not shrink: retries %d of %d",
ri->shrink_retries, MAX_SHRINK_RETRIES);
}
dbg_budg("force write-back (count %d)", ri->shrink_cnt); /* Liability did not shrink again, try GC */
shrink_liability(c, NR_TO_WRITE + ri->shrink_cnt); dbg_budg("Run GC");
ri->prev_liability = liability;
ri->shrink_cnt += 1;
return -EAGAIN;
}
/*
* Try to run garbage collector unless it was already tried too many
* times.
*/
if (ri->gc_retries < MAX_GC_RETRIES) {
ri->gc_retries += 1;
dbg_budg("run GC, retries %d of %d",
ri->gc_retries, MAX_GC_RETRIES);
ri->try_gc = 0;
err = run_gc(c); err = run_gc(c);
if (!err) if (!err)
return -EAGAIN; return -EAGAIN;
if (err == -EAGAIN) { if (err != -EAGAIN && err != -ENOSPC)
dbg_budg("GC asked to commit"); /* Some real error happened */
err = ubifs_run_commit(c);
if (err)
return err;
return -EAGAIN;
}
if (err != -ENOSPC)
return err; return err;
/* dbg_budg("Run commit (retries %d)", retries);
* GC could not make any progress. If this is the first time,
* then it makes sense to try to commit, because it might make
* some dirty space.
*/
dbg_budg("GC returned -ENOSPC, retries %d",
ri->nospc_retries);
if (ri->nospc_retries >= MAX_NOSPC_RETRIES)
return err;
ri->nospc_retries += 1;
}
/* Neither GC nor write-back helped, try to commit */
if (ri->cmt_retries < MAX_CMT_RETRIES) {
ri->cmt_retries += 1;
dbg_budg("run commit, retries %d of %d",
ri->cmt_retries, MAX_CMT_RETRIES);
err = ubifs_run_commit(c); err = ubifs_run_commit(c);
if (err) if (err)
return err; return err;
return -EAGAIN; } while (retries++ < MAX_MKSPC_RETRIES);
}
return -ENOSPC; return -ENOSPC;
} }
@ -258,8 +202,8 @@ static int make_free_space(struct ubifs_info *c, struct retries_info *ri)
*/ */
int ubifs_calc_min_idx_lebs(struct ubifs_info *c) int ubifs_calc_min_idx_lebs(struct ubifs_info *c)
{ {
int ret; int idx_lebs, eff_leb_size = c->leb_size - c->max_idx_node_sz;
uint64_t idx_size; long long idx_size;
idx_size = c->old_idx_sz + c->budg_idx_growth + c->budg_uncommitted_idx; idx_size = c->old_idx_sz + c->budg_idx_growth + c->budg_uncommitted_idx;
@ -271,23 +215,16 @@ int ubifs_calc_min_idx_lebs(struct ubifs_info *c)
* pair, nor similarly the two variables for the new index size, so we * pair, nor similarly the two variables for the new index size, so we
* have to do this costly 64-bit division on fast-path. * have to do this costly 64-bit division on fast-path.
*/ */
if (do_div(idx_size, c->leb_size - c->max_idx_node_sz)) idx_size += eff_leb_size - 1;
ret = idx_size + 1; idx_lebs = div_u64(idx_size, eff_leb_size);
else
ret = idx_size;
/* /*
* The index head is not available for the in-the-gaps method, so add an * The index head is not available for the in-the-gaps method, so add an
* extra LEB to compensate. * extra LEB to compensate.
*/ */
ret += 1; idx_lebs += 1;
/* if (idx_lebs < MIN_INDEX_LEBS)
* At present the index needs at least 2 LEBs: one for the index head idx_lebs = MIN_INDEX_LEBS;
* and one for in-the-gaps method (which currently does not cater for return idx_lebs;
* the index head and so excludes it from consideration).
*/
if (ret < 2)
ret = 2;
return ret;
} }
/** /**
@ -530,8 +467,7 @@ static int calc_dd_growth(const struct ubifs_info *c,
int ubifs_budget_space(struct ubifs_info *c, struct ubifs_budget_req *req) int ubifs_budget_space(struct ubifs_info *c, struct ubifs_budget_req *req)
{ {
int uninitialized_var(cmt_retries), uninitialized_var(wb_retries); int uninitialized_var(cmt_retries), uninitialized_var(wb_retries);
int err, idx_growth, data_growth, dd_growth; int err, idx_growth, data_growth, dd_growth, retried = 0;
struct retries_info ri;
ubifs_assert(req->new_page <= 1); ubifs_assert(req->new_page <= 1);
ubifs_assert(req->dirtied_page <= 1); ubifs_assert(req->dirtied_page <= 1);
@ -549,7 +485,6 @@ int ubifs_budget_space(struct ubifs_info *c, struct ubifs_budget_req *req)
if (!data_growth && !dd_growth) if (!data_growth && !dd_growth)
return 0; return 0;
idx_growth = calc_idx_growth(c, req); idx_growth = calc_idx_growth(c, req);
memset(&ri, 0, sizeof(struct retries_info));
again: again:
spin_lock(&c->space_lock); spin_lock(&c->space_lock);
@ -587,12 +522,17 @@ again:
return err; return err;
} }
err = make_free_space(c, &ri); err = make_free_space(c);
cond_resched();
if (err == -EAGAIN) { if (err == -EAGAIN) {
dbg_budg("try again"); dbg_budg("try again");
cond_resched();
goto again; goto again;
} else if (err == -ENOSPC) { } else if (err == -ENOSPC) {
if (!retried) {
retried = 1;
dbg_budg("-ENOSPC, but anyway try once again");
goto again;
}
dbg_budg("FS is full, -ENOSPC"); dbg_budg("FS is full, -ENOSPC");
c->nospace = 1; c->nospace = 1;
if (can_use_rp(c) || c->rp_size == 0) if (can_use_rp(c) || c->rp_size == 0)
@ -712,9 +652,9 @@ void ubifs_release_dirty_inode_budget(struct ubifs_info *c,
* user-space. User-space application tend to expect that if the file-system * user-space. User-space application tend to expect that if the file-system
* (e.g., via the 'statfs()' call) reports that it has N bytes available, they * (e.g., via the 'statfs()' call) reports that it has N bytes available, they
* are able to write a file of size N. UBIFS attaches node headers to each data * are able to write a file of size N. UBIFS attaches node headers to each data
* node and it has to write indexind nodes as well. This introduces additional * node and it has to write indexing nodes as well. This introduces additional
* overhead, and UBIFS it has to report sligtly less free space to meet the * overhead, and UBIFS has to report slightly less free space to meet the above
* above expectetion. * expectations.
* *
* This function assumes free space is made up of uncompressed data nodes and * This function assumes free space is made up of uncompressed data nodes and
* full index nodes (one per data node, tripled because we always allow enough * full index nodes (one per data node, tripled because we always allow enough
@ -723,7 +663,7 @@ void ubifs_release_dirty_inode_budget(struct ubifs_info *c,
* Note, the calculation is pessimistic, which means that most of the time * Note, the calculation is pessimistic, which means that most of the time
* UBIFS reports less space than it actually has. * UBIFS reports less space than it actually has.
*/ */
long long ubifs_reported_space(const struct ubifs_info *c, uint64_t free) long long ubifs_reported_space(const struct ubifs_info *c, long long free)
{ {
int divisor, factor, f; int divisor, factor, f;
@ -737,7 +677,7 @@ long long ubifs_reported_space(const struct ubifs_info *c, uint64_t free)
* of data nodes, f - fanout. Because effective UBIFS fanout is twice * of data nodes, f - fanout. Because effective UBIFS fanout is twice
* as less than maximum fanout, we assume that each data node * as less than maximum fanout, we assume that each data node
* introduces 3 * @c->max_idx_node_sz / (@c->fanout/2 - 1) bytes. * introduces 3 * @c->max_idx_node_sz / (@c->fanout/2 - 1) bytes.
* Note, the multiplier 3 is because UBIFS reseves thrice as more space * Note, the multiplier 3 is because UBIFS reserves thrice as more space
* for the index. * for the index.
*/ */
f = c->fanout > 3 ? c->fanout >> 1 : 2; f = c->fanout > 3 ? c->fanout >> 1 : 2;
@ -745,8 +685,7 @@ long long ubifs_reported_space(const struct ubifs_info *c, uint64_t free)
divisor = UBIFS_MAX_DATA_NODE_SZ; divisor = UBIFS_MAX_DATA_NODE_SZ;
divisor += (c->max_idx_node_sz * 3) / (f - 1); divisor += (c->max_idx_node_sz * 3) / (f - 1);
free *= factor; free *= factor;
do_div(free, divisor); return div_u64(free, divisor);
return free;
} }
/** /**
@ -756,10 +695,10 @@ long long ubifs_reported_space(const struct ubifs_info *c, uint64_t free)
* This function calculates amount of free space to report to user-space. * This function calculates amount of free space to report to user-space.
* *
* Because UBIFS may introduce substantial overhead (the index, node headers, * Because UBIFS may introduce substantial overhead (the index, node headers,
* alighment, wastage at the end of eraseblocks, etc), it cannot report real * alignment, wastage at the end of eraseblocks, etc), it cannot report real
* amount of free flash space it has (well, because not all dirty space is * amount of free flash space it has (well, because not all dirty space is
* reclamable, UBIFS does not actually know the real amount). If UBIFS did so, * reclaimable, UBIFS does not actually know the real amount). If UBIFS did so,
* it would bread user expectetion about what free space is. Users seem to * it would bread user expectations about what free space is. Users seem to
* accustomed to assume that if the file-system reports N bytes of free space, * accustomed to assume that if the file-system reports N bytes of free space,
* they would be able to fit a file of N bytes to the FS. This almost works for * they would be able to fit a file of N bytes to the FS. This almost works for
* traditional file-systems, because they have way less overhead than UBIFS. * traditional file-systems, because they have way less overhead than UBIFS.
@ -771,18 +710,9 @@ long long ubifs_get_free_space(struct ubifs_info *c)
long long available, outstanding, free; long long available, outstanding, free;
spin_lock(&c->space_lock); spin_lock(&c->space_lock);
min_idx_lebs = ubifs_calc_min_idx_lebs(c); min_idx_lebs = c->min_idx_lebs;
ubifs_assert(min_idx_lebs == ubifs_calc_min_idx_lebs(c));
outstanding = c->budg_data_growth + c->budg_dd_growth; outstanding = c->budg_data_growth + c->budg_dd_growth;
/*
* Force the amount available to the total size reported if the used
* space is zero.
*/
if (c->lst.total_used <= UBIFS_INO_NODE_SZ && !outstanding) {
spin_unlock(&c->space_lock);
return (long long)c->block_cnt << UBIFS_BLOCK_SHIFT;
}
available = ubifs_calc_available(c, min_idx_lebs); available = ubifs_calc_available(c, min_idx_lebs);
/* /*

View File

@ -470,12 +470,12 @@ int dbg_old_index_check_init(struct ubifs_info *c, struct ubifs_zbranch *zroot)
{ {
struct ubifs_idx_node *idx; struct ubifs_idx_node *idx;
int lnum, offs, len, err = 0; int lnum, offs, len, err = 0;
struct ubifs_debug_info *d = c->dbg;
c->old_zroot = *zroot; d->old_zroot = *zroot;
lnum = d->old_zroot.lnum;
lnum = c->old_zroot.lnum; offs = d->old_zroot.offs;
offs = c->old_zroot.offs; len = d->old_zroot.len;
len = c->old_zroot.len;
idx = kmalloc(c->max_idx_node_sz, GFP_NOFS); idx = kmalloc(c->max_idx_node_sz, GFP_NOFS);
if (!idx) if (!idx)
@ -485,8 +485,8 @@ int dbg_old_index_check_init(struct ubifs_info *c, struct ubifs_zbranch *zroot)
if (err) if (err)
goto out; goto out;
c->old_zroot_level = le16_to_cpu(idx->level); d->old_zroot_level = le16_to_cpu(idx->level);
c->old_zroot_sqnum = le64_to_cpu(idx->ch.sqnum); d->old_zroot_sqnum = le64_to_cpu(idx->ch.sqnum);
out: out:
kfree(idx); kfree(idx);
return err; return err;
@ -509,6 +509,7 @@ int dbg_check_old_index(struct ubifs_info *c, struct ubifs_zbranch *zroot)
{ {
int lnum, offs, len, err = 0, uninitialized_var(last_level), child_cnt; int lnum, offs, len, err = 0, uninitialized_var(last_level), child_cnt;
int first = 1, iip; int first = 1, iip;
struct ubifs_debug_info *d = c->dbg;
union ubifs_key lower_key, upper_key, l_key, u_key; union ubifs_key lower_key, upper_key, l_key, u_key;
unsigned long long uninitialized_var(last_sqnum); unsigned long long uninitialized_var(last_sqnum);
struct ubifs_idx_node *idx; struct ubifs_idx_node *idx;
@ -525,9 +526,9 @@ int dbg_check_old_index(struct ubifs_info *c, struct ubifs_zbranch *zroot)
UBIFS_IDX_NODE_SZ; UBIFS_IDX_NODE_SZ;
/* Start at the old zroot */ /* Start at the old zroot */
lnum = c->old_zroot.lnum; lnum = d->old_zroot.lnum;
offs = c->old_zroot.offs; offs = d->old_zroot.offs;
len = c->old_zroot.len; len = d->old_zroot.len;
iip = 0; iip = 0;
/* /*
@ -560,11 +561,11 @@ int dbg_check_old_index(struct ubifs_info *c, struct ubifs_zbranch *zroot)
if (first) { if (first) {
first = 0; first = 0;
/* Check root level and sqnum */ /* Check root level and sqnum */
if (le16_to_cpu(idx->level) != c->old_zroot_level) { if (le16_to_cpu(idx->level) != d->old_zroot_level) {
err = 2; err = 2;
goto out_dump; goto out_dump;
} }
if (le64_to_cpu(idx->ch.sqnum) != c->old_zroot_sqnum) { if (le64_to_cpu(idx->ch.sqnum) != d->old_zroot_sqnum) {
err = 3; err = 3;
goto out_dump; goto out_dump;
} }

View File

@ -33,7 +33,7 @@
/* Fake description object for the "none" compressor */ /* Fake description object for the "none" compressor */
static struct ubifs_compressor none_compr = { static struct ubifs_compressor none_compr = {
.compr_type = UBIFS_COMPR_NONE, .compr_type = UBIFS_COMPR_NONE,
.name = "no compression", .name = "none",
.capi_name = "", .capi_name = "",
}; };
@ -43,13 +43,13 @@ static DEFINE_MUTEX(lzo_mutex);
static struct ubifs_compressor lzo_compr = { static struct ubifs_compressor lzo_compr = {
.compr_type = UBIFS_COMPR_LZO, .compr_type = UBIFS_COMPR_LZO,
.comp_mutex = &lzo_mutex, .comp_mutex = &lzo_mutex,
.name = "LZO", .name = "lzo",
.capi_name = "lzo", .capi_name = "lzo",
}; };
#else #else
static struct ubifs_compressor lzo_compr = { static struct ubifs_compressor lzo_compr = {
.compr_type = UBIFS_COMPR_LZO, .compr_type = UBIFS_COMPR_LZO,
.name = "LZO", .name = "lzo",
}; };
#endif #endif
@ -108,7 +108,7 @@ void ubifs_compress(const void *in_buf, int in_len, void *out_buf, int *out_len,
if (compr->comp_mutex) if (compr->comp_mutex)
mutex_lock(compr->comp_mutex); mutex_lock(compr->comp_mutex);
err = crypto_comp_compress(compr->cc, in_buf, in_len, out_buf, err = crypto_comp_compress(compr->cc, in_buf, in_len, out_buf,
out_len); (unsigned int *)out_len);
if (compr->comp_mutex) if (compr->comp_mutex)
mutex_unlock(compr->comp_mutex); mutex_unlock(compr->comp_mutex);
if (unlikely(err)) { if (unlikely(err)) {
@ -119,10 +119,10 @@ void ubifs_compress(const void *in_buf, int in_len, void *out_buf, int *out_len,
} }
/* /*
* Presently, we just require that compression results in less data, * If the data compressed only slightly, it is better to leave it
* rather than any defined minimum compression ratio or amount. * uncompressed to improve read speed.
*/ */
if (ALIGN(*out_len, 8) >= ALIGN(in_len, 8)) if (in_len - *out_len < UBIFS_MIN_COMPRESS_DIFF)
goto no_compr; goto no_compr;
return; return;
@ -172,7 +172,7 @@ int ubifs_decompress(const void *in_buf, int in_len, void *out_buf,
if (compr->decomp_mutex) if (compr->decomp_mutex)
mutex_lock(compr->decomp_mutex); mutex_lock(compr->decomp_mutex);
err = crypto_comp_decompress(compr->cc, in_buf, in_len, out_buf, err = crypto_comp_decompress(compr->cc, in_buf, in_len, out_buf,
out_len); (unsigned int *)out_len);
if (compr->decomp_mutex) if (compr->decomp_mutex)
mutex_unlock(compr->decomp_mutex); mutex_unlock(compr->decomp_mutex);
if (err) if (err)
@ -244,7 +244,7 @@ out_lzo:
/** /**
* ubifs_compressors_exit - de-initialize UBIFS compressors. * ubifs_compressors_exit - de-initialize UBIFS compressors.
*/ */
void __exit ubifs_compressors_exit(void) void ubifs_compressors_exit(void)
{ {
compr_exit(&lzo_compr); compr_exit(&lzo_compr);
compr_exit(&zlib_compr); compr_exit(&zlib_compr);

View File

@ -32,6 +32,8 @@
#include "ubifs.h" #include "ubifs.h"
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/debugfs.h>
#include <linux/math64.h>
#ifdef CONFIG_UBIFS_FS_DEBUG #ifdef CONFIG_UBIFS_FS_DEBUG
@ -596,7 +598,9 @@ void dbg_dump_budg(struct ubifs_info *c)
struct rb_node *rb; struct rb_node *rb;
struct ubifs_bud *bud; struct ubifs_bud *bud;
struct ubifs_gced_idx_leb *idx_gc; struct ubifs_gced_idx_leb *idx_gc;
long long available, outstanding, free;
ubifs_assert(spin_is_locked(&c->space_lock));
spin_lock(&dbg_lock); spin_lock(&dbg_lock);
printk(KERN_DEBUG "(pid %d) Budgeting info: budg_data_growth %lld, " printk(KERN_DEBUG "(pid %d) Budgeting info: budg_data_growth %lld, "
"budg_dd_growth %lld, budg_idx_growth %lld\n", current->pid, "budg_dd_growth %lld, budg_idx_growth %lld\n", current->pid,
@ -629,6 +633,17 @@ void dbg_dump_budg(struct ubifs_info *c)
printk(KERN_DEBUG "\tGC'ed idx LEB %d unmap %d\n", printk(KERN_DEBUG "\tGC'ed idx LEB %d unmap %d\n",
idx_gc->lnum, idx_gc->unmap); idx_gc->lnum, idx_gc->unmap);
printk(KERN_DEBUG "\tcommit state %d\n", c->cmt_state); printk(KERN_DEBUG "\tcommit state %d\n", c->cmt_state);
/* Print budgeting predictions */
available = ubifs_calc_available(c, c->min_idx_lebs);
outstanding = c->budg_data_growth + c->budg_dd_growth;
if (available > outstanding)
free = ubifs_reported_space(c, available - outstanding);
else
free = 0;
printk(KERN_DEBUG "Budgeting predictions:\n");
printk(KERN_DEBUG "\tavailable: %lld, outstanding %lld, free %lld\n",
available, outstanding, free);
spin_unlock(&dbg_lock); spin_unlock(&dbg_lock);
} }
@ -645,7 +660,8 @@ void dbg_dump_lprops(struct ubifs_info *c)
struct ubifs_lprops lp; struct ubifs_lprops lp;
struct ubifs_lp_stats lst; struct ubifs_lp_stats lst;
printk(KERN_DEBUG "(pid %d) Dumping LEB properties\n", current->pid); printk(KERN_DEBUG "(pid %d) start dumping LEB properties\n",
current->pid);
ubifs_get_lp_stats(c, &lst); ubifs_get_lp_stats(c, &lst);
dbg_dump_lstats(&lst); dbg_dump_lstats(&lst);
@ -656,6 +672,8 @@ void dbg_dump_lprops(struct ubifs_info *c)
dbg_dump_lprop(c, &lp); dbg_dump_lprop(c, &lp);
} }
printk(KERN_DEBUG "(pid %d) finish dumping LEB properties\n",
current->pid);
} }
void dbg_dump_lpt_info(struct ubifs_info *c) void dbg_dump_lpt_info(struct ubifs_info *c)
@ -663,6 +681,7 @@ void dbg_dump_lpt_info(struct ubifs_info *c)
int i; int i;
spin_lock(&dbg_lock); spin_lock(&dbg_lock);
printk(KERN_DEBUG "(pid %d) dumping LPT information\n", current->pid);
printk(KERN_DEBUG "\tlpt_sz: %lld\n", c->lpt_sz); printk(KERN_DEBUG "\tlpt_sz: %lld\n", c->lpt_sz);
printk(KERN_DEBUG "\tpnode_sz: %d\n", c->pnode_sz); printk(KERN_DEBUG "\tpnode_sz: %d\n", c->pnode_sz);
printk(KERN_DEBUG "\tnnode_sz: %d\n", c->nnode_sz); printk(KERN_DEBUG "\tnnode_sz: %d\n", c->nnode_sz);
@ -684,7 +703,8 @@ void dbg_dump_lpt_info(struct ubifs_info *c)
printk(KERN_DEBUG "\tLPT root is at %d:%d\n", c->lpt_lnum, c->lpt_offs); 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", printk(KERN_DEBUG "\tLPT head is at %d:%d\n",
c->nhead_lnum, c->nhead_offs); c->nhead_lnum, c->nhead_offs);
printk(KERN_DEBUG "\tLPT ltab is at %d:%d\n", c->ltab_lnum, c->ltab_offs); printk(KERN_DEBUG "\tLPT ltab is at %d:%d\n",
c->ltab_lnum, c->ltab_offs);
if (c->big_lpt) if (c->big_lpt)
printk(KERN_DEBUG "\tLPT lsave is at %d:%d\n", printk(KERN_DEBUG "\tLPT lsave is at %d:%d\n",
c->lsave_lnum, c->lsave_offs); c->lsave_lnum, c->lsave_offs);
@ -703,9 +723,9 @@ void dbg_dump_leb(const struct ubifs_info *c, int lnum)
if (dbg_failure_mode) if (dbg_failure_mode)
return; return;
printk(KERN_DEBUG "(pid %d) Dumping LEB %d\n", current->pid, lnum); printk(KERN_DEBUG "(pid %d) start dumping LEB %d\n",
current->pid, lnum);
sleb = ubifs_scan(c, lnum, 0, c->dbg_buf); sleb = ubifs_scan(c, lnum, 0, c->dbg->buf);
if (IS_ERR(sleb)) { if (IS_ERR(sleb)) {
ubifs_err("scan error %d", (int)PTR_ERR(sleb)); ubifs_err("scan error %d", (int)PTR_ERR(sleb));
return; return;
@ -721,6 +741,8 @@ void dbg_dump_leb(const struct ubifs_info *c, int lnum)
dbg_dump_node(c, snod->node); dbg_dump_node(c, snod->node);
} }
printk(KERN_DEBUG "(pid %d) finish dumping LEB %d\n",
current->pid, lnum);
ubifs_scan_destroy(sleb); ubifs_scan_destroy(sleb);
return; return;
} }
@ -768,7 +790,7 @@ void dbg_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat)
{ {
int i; int i;
printk(KERN_DEBUG "(pid %d) Dumping heap cat %d (%d elements)\n", printk(KERN_DEBUG "(pid %d) start dumping heap cat %d (%d elements)\n",
current->pid, cat, heap->cnt); current->pid, cat, heap->cnt);
for (i = 0; i < heap->cnt; i++) { for (i = 0; i < heap->cnt; i++) {
struct ubifs_lprops *lprops = heap->arr[i]; struct ubifs_lprops *lprops = heap->arr[i];
@ -777,6 +799,7 @@ void dbg_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat)
"flags %d\n", i, lprops->lnum, lprops->hpos, "flags %d\n", i, lprops->lnum, lprops->hpos,
lprops->free, lprops->dirty, lprops->flags); lprops->free, lprops->dirty, lprops->flags);
} }
printk(KERN_DEBUG "(pid %d) finish dumping heap\n", current->pid);
} }
void dbg_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode, void dbg_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
@ -784,7 +807,7 @@ void dbg_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
{ {
int i; int i;
printk(KERN_DEBUG "(pid %d) Dumping pnode:\n", current->pid); printk(KERN_DEBUG "(pid %d) dumping pnode:\n", current->pid);
printk(KERN_DEBUG "\taddress %zx parent %zx cnext %zx\n", printk(KERN_DEBUG "\taddress %zx parent %zx cnext %zx\n",
(size_t)pnode, (size_t)parent, (size_t)pnode->cnext); (size_t)pnode, (size_t)parent, (size_t)pnode->cnext);
printk(KERN_DEBUG "\tflags %lu iip %d level %d num %d\n", printk(KERN_DEBUG "\tflags %lu iip %d level %d num %d\n",
@ -803,7 +826,7 @@ void dbg_dump_tnc(struct ubifs_info *c)
int level; int level;
printk(KERN_DEBUG "\n"); printk(KERN_DEBUG "\n");
printk(KERN_DEBUG "(pid %d) Dumping the TNC tree\n", current->pid); printk(KERN_DEBUG "(pid %d) start dumping TNC tree\n", current->pid);
znode = ubifs_tnc_levelorder_next(c->zroot.znode, NULL); znode = ubifs_tnc_levelorder_next(c->zroot.znode, NULL);
level = znode->level; level = znode->level;
printk(KERN_DEBUG "== Level %d ==\n", level); printk(KERN_DEBUG "== Level %d ==\n", level);
@ -815,8 +838,7 @@ void dbg_dump_tnc(struct ubifs_info *c)
dbg_dump_znode(c, znode); dbg_dump_znode(c, znode);
znode = ubifs_tnc_levelorder_next(c->zroot.znode, znode); znode = ubifs_tnc_levelorder_next(c->zroot.znode, znode);
} }
printk(KERN_DEBUG "(pid %d) finish dumping TNC tree\n", current->pid);
printk(KERN_DEBUG "\n");
} }
static int dump_znode(struct ubifs_info *c, struct ubifs_znode *znode, static int dump_znode(struct ubifs_info *c, struct ubifs_znode *znode,
@ -992,8 +1014,8 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1,
zbr1->offs, DBGKEY(&key)); zbr1->offs, DBGKEY(&key));
dbg_err("but it should have key %s according to tnc", dbg_err("but it should have key %s according to tnc",
DBGKEY(&zbr1->key)); DBGKEY(&zbr1->key));
dbg_dump_node(c, dent1); dbg_dump_node(c, dent1);
goto out_free; goto out_free;
} }
key_read(c, &dent2->key, &key); key_read(c, &dent2->key, &key);
@ -1002,8 +1024,8 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1,
zbr1->offs, DBGKEY(&key)); zbr1->offs, DBGKEY(&key));
dbg_err("but it should have key %s according to tnc", dbg_err("but it should have key %s according to tnc",
DBGKEY(&zbr2->key)); DBGKEY(&zbr2->key));
dbg_dump_node(c, dent2); dbg_dump_node(c, dent2);
goto out_free; goto out_free;
} }
nlen1 = le16_to_cpu(dent1->nlen); nlen1 = le16_to_cpu(dent1->nlen);
@ -1020,9 +1042,9 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1,
dbg_err("bad order of colliding key %s", dbg_err("bad order of colliding key %s",
DBGKEY(&key)); DBGKEY(&key));
dbg_msg("first node at %d:%d\n", zbr1->lnum, zbr1->offs); ubifs_msg("first node at %d:%d\n", zbr1->lnum, zbr1->offs);
dbg_dump_node(c, dent1); dbg_dump_node(c, dent1);
dbg_msg("second node at %d:%d\n", zbr2->lnum, zbr2->offs); ubifs_msg("second node at %d:%d\n", zbr2->lnum, zbr2->offs);
dbg_dump_node(c, dent2); dbg_dump_node(c, dent2);
out_free: out_free:
@ -2097,13 +2119,13 @@ static int simple_rand(void)
return (next >> 16) & 32767; return (next >> 16) & 32767;
} }
void dbg_failure_mode_registration(struct ubifs_info *c) static void failure_mode_init(struct ubifs_info *c)
{ {
struct failure_mode_info *fmi; struct failure_mode_info *fmi;
fmi = kmalloc(sizeof(struct failure_mode_info), GFP_NOFS); fmi = kmalloc(sizeof(struct failure_mode_info), GFP_NOFS);
if (!fmi) { if (!fmi) {
dbg_err("Failed to register failure mode - no memory"); ubifs_err("Failed to register failure mode - no memory");
return; return;
} }
fmi->c = c; fmi->c = c;
@ -2112,7 +2134,7 @@ void dbg_failure_mode_registration(struct ubifs_info *c)
spin_unlock(&fmi_lock); spin_unlock(&fmi_lock);
} }
void dbg_failure_mode_deregistration(struct ubifs_info *c) static void failure_mode_exit(struct ubifs_info *c)
{ {
struct failure_mode_info *fmi, *tmp; struct failure_mode_info *fmi, *tmp;
@ -2146,42 +2168,44 @@ static int in_failure_mode(struct ubi_volume_desc *desc)
struct ubifs_info *c = dbg_find_info(desc); struct ubifs_info *c = dbg_find_info(desc);
if (c && dbg_failure_mode) if (c && dbg_failure_mode)
return c->failure_mode; return c->dbg->failure_mode;
return 0; return 0;
} }
static int do_fail(struct ubi_volume_desc *desc, int lnum, int write) static int do_fail(struct ubi_volume_desc *desc, int lnum, int write)
{ {
struct ubifs_info *c = dbg_find_info(desc); struct ubifs_info *c = dbg_find_info(desc);
struct ubifs_debug_info *d;
if (!c || !dbg_failure_mode) if (!c || !dbg_failure_mode)
return 0; return 0;
if (c->failure_mode) d = c->dbg;
if (d->failure_mode)
return 1; return 1;
if (!c->fail_cnt) { if (!d->fail_cnt) {
/* First call - decide delay to failure */ /* First call - decide delay to failure */
if (chance(1, 2)) { if (chance(1, 2)) {
unsigned int delay = 1 << (simple_rand() >> 11); unsigned int delay = 1 << (simple_rand() >> 11);
if (chance(1, 2)) { if (chance(1, 2)) {
c->fail_delay = 1; d->fail_delay = 1;
c->fail_timeout = jiffies + d->fail_timeout = jiffies +
msecs_to_jiffies(delay); msecs_to_jiffies(delay);
dbg_rcvry("failing after %ums", delay); dbg_rcvry("failing after %ums", delay);
} else { } else {
c->fail_delay = 2; d->fail_delay = 2;
c->fail_cnt_max = delay; d->fail_cnt_max = delay;
dbg_rcvry("failing after %u calls", delay); dbg_rcvry("failing after %u calls", delay);
} }
} }
c->fail_cnt += 1; d->fail_cnt += 1;
} }
/* Determine if failure delay has expired */ /* Determine if failure delay has expired */
if (c->fail_delay == 1) { if (d->fail_delay == 1) {
if (time_before(jiffies, c->fail_timeout)) if (time_before(jiffies, d->fail_timeout))
return 0; return 0;
} else if (c->fail_delay == 2) } else if (d->fail_delay == 2)
if (c->fail_cnt++ < c->fail_cnt_max) if (d->fail_cnt++ < d->fail_cnt_max)
return 0; return 0;
if (lnum == UBIFS_SB_LNUM) { if (lnum == UBIFS_SB_LNUM) {
if (write) { if (write) {
@ -2239,7 +2263,7 @@ static int do_fail(struct ubi_volume_desc *desc, int lnum, int write)
dbg_rcvry("failing in bud LEB %d commit not running", lnum); dbg_rcvry("failing in bud LEB %d commit not running", lnum);
} }
ubifs_err("*** SETTING FAILURE MODE ON (LEB %d) ***", lnum); ubifs_err("*** SETTING FAILURE MODE ON (LEB %d) ***", lnum);
c->failure_mode = 1; d->failure_mode = 1;
dump_stack(); dump_stack();
return 1; return 1;
} }
@ -2344,4 +2368,181 @@ int dbg_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype)
return 0; return 0;
} }
/**
* ubifs_debugging_init - initialize UBIFS debugging.
* @c: UBIFS file-system description object
*
* This function initializes debugging-related data for the file system.
* Returns zero in case of success and a negative error code in case of
* failure.
*/
int ubifs_debugging_init(struct ubifs_info *c)
{
c->dbg = kzalloc(sizeof(struct ubifs_debug_info), GFP_KERNEL);
if (!c->dbg)
return -ENOMEM;
c->dbg->buf = vmalloc(c->leb_size);
if (!c->dbg->buf)
goto out;
failure_mode_init(c);
return 0;
out:
kfree(c->dbg);
return -ENOMEM;
}
/**
* ubifs_debugging_exit - free debugging data.
* @c: UBIFS file-system description object
*/
void ubifs_debugging_exit(struct ubifs_info *c)
{
failure_mode_exit(c);
vfree(c->dbg->buf);
kfree(c->dbg);
}
/*
* Root directory for UBIFS stuff in debugfs. Contains sub-directories which
* contain the stuff specific to particular file-system mounts.
*/
static struct dentry *debugfs_rootdir;
/**
* dbg_debugfs_init - initialize debugfs file-system.
*
* UBIFS uses debugfs file-system to expose various debugging knobs to
* user-space. This function creates "ubifs" directory in the debugfs
* file-system. Returns zero in case of success and a negative error code in
* case of failure.
*/
int dbg_debugfs_init(void)
{
debugfs_rootdir = debugfs_create_dir("ubifs", NULL);
if (IS_ERR(debugfs_rootdir)) {
int err = PTR_ERR(debugfs_rootdir);
ubifs_err("cannot create \"ubifs\" debugfs directory, "
"error %d\n", err);
return err;
}
return 0;
}
/**
* dbg_debugfs_exit - remove the "ubifs" directory from debugfs file-system.
*/
void dbg_debugfs_exit(void)
{
debugfs_remove(debugfs_rootdir);
}
static int open_debugfs_file(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
return 0;
}
static ssize_t write_debugfs_file(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
struct ubifs_info *c = file->private_data;
struct ubifs_debug_info *d = c->dbg;
if (file->f_path.dentry == d->dump_lprops)
dbg_dump_lprops(c);
else if (file->f_path.dentry == d->dump_budg) {
spin_lock(&c->space_lock);
dbg_dump_budg(c);
spin_unlock(&c->space_lock);
} else if (file->f_path.dentry == d->dump_tnc) {
mutex_lock(&c->tnc_mutex);
dbg_dump_tnc(c);
mutex_unlock(&c->tnc_mutex);
} else
return -EINVAL;
*ppos += count;
return count;
}
static const struct file_operations debugfs_fops = {
.open = open_debugfs_file,
.write = write_debugfs_file,
.owner = THIS_MODULE,
};
/**
* dbg_debugfs_init_fs - initialize debugfs for UBIFS instance.
* @c: UBIFS file-system description object
*
* This function creates all debugfs files for this instance of UBIFS. Returns
* zero in case of success and a negative error code in case of failure.
*
* Note, the only reason we have not merged this function with the
* 'ubifs_debugging_init()' function is because it is better to initialize
* debugfs interfaces at the very end of the mount process, and remove them at
* the very beginning of the mount process.
*/
int dbg_debugfs_init_fs(struct ubifs_info *c)
{
int err;
const char *fname;
struct dentry *dent;
struct ubifs_debug_info *d = c->dbg;
sprintf(d->debugfs_dir_name, "ubi%d_%d", c->vi.ubi_num, c->vi.vol_id);
d->debugfs_dir = debugfs_create_dir(d->debugfs_dir_name,
debugfs_rootdir);
if (IS_ERR(d->debugfs_dir)) {
err = PTR_ERR(d->debugfs_dir);
ubifs_err("cannot create \"%s\" debugfs directory, error %d\n",
d->debugfs_dir_name, err);
goto out;
}
fname = "dump_lprops";
dent = debugfs_create_file(fname, S_IWUGO, d->debugfs_dir, c,
&debugfs_fops);
if (IS_ERR(dent))
goto out_remove;
d->dump_lprops = dent;
fname = "dump_budg";
dent = debugfs_create_file(fname, S_IWUGO, d->debugfs_dir, c,
&debugfs_fops);
if (IS_ERR(dent))
goto out_remove;
d->dump_budg = dent;
fname = "dump_tnc";
dent = debugfs_create_file(fname, S_IWUGO, d->debugfs_dir, c,
&debugfs_fops);
if (IS_ERR(dent))
goto out_remove;
d->dump_tnc = dent;
return 0;
out_remove:
err = PTR_ERR(dent);
ubifs_err("cannot create \"%s\" debugfs directory, error %d\n",
fname, err);
debugfs_remove_recursive(d->debugfs_dir);
out:
return err;
}
/**
* dbg_debugfs_exit_fs - remove all debugfs files.
* @c: UBIFS file-system description object
*/
void dbg_debugfs_exit_fs(struct ubifs_info *c)
{
debugfs_remove_recursive(c->dbg->debugfs_dir);
}
#endif /* CONFIG_UBIFS_FS_DEBUG */ #endif /* CONFIG_UBIFS_FS_DEBUG */

View File

@ -25,7 +25,56 @@
#ifdef CONFIG_UBIFS_FS_DEBUG #ifdef CONFIG_UBIFS_FS_DEBUG
#define UBIFS_DBG(op) op /**
* ubifs_debug_info - per-FS debugging information.
* @buf: a buffer of LEB size, used for various purposes
* @old_zroot: old index root - used by 'dbg_check_old_index()'
* @old_zroot_level: old index root level - used by 'dbg_check_old_index()'
* @old_zroot_sqnum: old index root sqnum - used by 'dbg_check_old_index()'
* @failure_mode: failure mode for recovery testing
* @fail_delay: 0=>don't delay, 1=>delay a time, 2=>delay a number of calls
* @fail_timeout: time in jiffies when delay of failure mode expires
* @fail_cnt: current number of calls to failure mode I/O functions
* @fail_cnt_max: number of calls by which to delay failure mode
* @chk_lpt_sz: used by LPT tree size checker
* @chk_lpt_sz2: used by LPT tree size checker
* @chk_lpt_wastage: used by LPT tree size checker
* @chk_lpt_lebs: used by LPT tree size checker
* @new_nhead_offs: used by LPT tree size checker
* @new_ihead_lnum: used by debugging to check ihead_lnum
* @new_ihead_offs: used by debugging to check ihead_offs
*
* debugfs_dir_name: name of debugfs directory containing this file-system's
* files
* debugfs_dir: direntry object of the file-system debugfs directory
* dump_lprops: "dump lprops" debugfs knob
* dump_budg: "dump budgeting information" debugfs knob
* dump_tnc: "dump TNC" debugfs knob
*/
struct ubifs_debug_info {
void *buf;
struct ubifs_zbranch old_zroot;
int old_zroot_level;
unsigned long long old_zroot_sqnum;
int failure_mode;
int fail_delay;
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_offs;
int new_ihead_lnum;
int new_ihead_offs;
char debugfs_dir_name[100];
struct dentry *debugfs_dir;
struct dentry *dump_lprops;
struct dentry *dump_budg;
struct dentry *dump_tnc;
};
#define ubifs_assert(expr) do { \ #define ubifs_assert(expr) do { \
if (unlikely(!(expr))) { \ if (unlikely(!(expr))) { \
@ -211,14 +260,18 @@ extern unsigned int ubifs_msg_flags;
extern unsigned int ubifs_chk_flags; extern unsigned int ubifs_chk_flags;
extern unsigned int ubifs_tst_flags; extern unsigned int ubifs_tst_flags;
/* Dump functions */ int ubifs_debugging_init(struct ubifs_info *c);
void ubifs_debugging_exit(struct ubifs_info *c);
/* Dump functions */
const char *dbg_ntype(int type); const char *dbg_ntype(int type);
const char *dbg_cstate(int cmt_state); const char *dbg_cstate(int cmt_state);
const char *dbg_get_key_dump(const struct ubifs_info *c, const char *dbg_get_key_dump(const struct ubifs_info *c,
const union ubifs_key *key); const union ubifs_key *key);
void dbg_dump_inode(const struct ubifs_info *c, const struct inode *inode); void dbg_dump_inode(const struct ubifs_info *c, const struct inode *inode);
void dbg_dump_node(const struct ubifs_info *c, const void *node); void dbg_dump_node(const struct ubifs_info *c, const void *node);
void dbg_dump_lpt_node(const struct ubifs_info *c, void *node, int lnum,
int offs);
void dbg_dump_budget_req(const struct ubifs_budget_req *req); void dbg_dump_budget_req(const struct ubifs_budget_req *req);
void dbg_dump_lstats(const struct ubifs_lp_stats *lst); void dbg_dump_lstats(const struct ubifs_lp_stats *lst);
void dbg_dump_budg(struct ubifs_info *c); void dbg_dump_budg(struct ubifs_info *c);
@ -233,9 +286,9 @@ void dbg_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
struct ubifs_nnode *parent, int iip); struct ubifs_nnode *parent, int iip);
void dbg_dump_tnc(struct ubifs_info *c); void dbg_dump_tnc(struct ubifs_info *c);
void dbg_dump_index(struct ubifs_info *c); void dbg_dump_index(struct ubifs_info *c);
void dbg_dump_lpt_lebs(const struct ubifs_info *c);
/* Checking helper functions */ /* Checking helper functions */
typedef int (*dbg_leaf_callback)(struct ubifs_info *c, typedef int (*dbg_leaf_callback)(struct ubifs_info *c,
struct ubifs_zbranch *zbr, void *priv); struct ubifs_zbranch *zbr, void *priv);
typedef int (*dbg_znode_callback)(struct ubifs_info *c, typedef int (*dbg_znode_callback)(struct ubifs_info *c,
@ -274,9 +327,6 @@ int dbg_force_in_the_gaps(void);
#define dbg_failure_mode (ubifs_tst_flags & UBIFS_TST_RCVRY) #define dbg_failure_mode (ubifs_tst_flags & UBIFS_TST_RCVRY)
void dbg_failure_mode_registration(struct ubifs_info *c);
void dbg_failure_mode_deregistration(struct ubifs_info *c);
#ifndef UBIFS_DBG_PRESERVE_UBI #ifndef UBIFS_DBG_PRESERVE_UBI
#define ubi_leb_read dbg_leb_read #define ubi_leb_read dbg_leb_read
@ -318,9 +368,13 @@ static inline int dbg_change(struct ubi_volume_desc *desc, int lnum,
return dbg_leb_change(desc, lnum, buf, len, UBI_UNKNOWN); return dbg_leb_change(desc, lnum, buf, len, UBI_UNKNOWN);
} }
#else /* !CONFIG_UBIFS_FS_DEBUG */ /* Debugfs-related stuff */
int dbg_debugfs_init(void);
void dbg_debugfs_exit(void);
int dbg_debugfs_init_fs(struct ubifs_info *c);
void dbg_debugfs_exit_fs(struct ubifs_info *c);
#define UBIFS_DBG(op) #else /* !CONFIG_UBIFS_FS_DEBUG */
/* Use "if (0)" to make compiler check arguments even if debugging is off */ /* Use "if (0)" to make compiler check arguments even if debugging is off */
#define ubifs_assert(expr) do { \ #define ubifs_assert(expr) do { \
@ -360,23 +414,28 @@ static inline int dbg_change(struct ubi_volume_desc *desc, int lnum,
#define DBGKEY(key) ((char *)(key)) #define DBGKEY(key) ((char *)(key))
#define DBGKEY1(key) ((char *)(key)) #define DBGKEY1(key) ((char *)(key))
#define dbg_ntype(type) "" #define ubifs_debugging_init(c) 0
#define dbg_cstate(cmt_state) "" #define ubifs_debugging_exit(c) ({})
#define dbg_get_key_dump(c, key) ({})
#define dbg_dump_inode(c, inode) ({}) #define dbg_ntype(type) ""
#define dbg_dump_node(c, node) ({}) #define dbg_cstate(cmt_state) ""
#define dbg_dump_budget_req(req) ({}) #define dbg_get_key_dump(c, key) ({})
#define dbg_dump_lstats(lst) ({}) #define dbg_dump_inode(c, inode) ({})
#define dbg_dump_budg(c) ({}) #define dbg_dump_node(c, node) ({})
#define dbg_dump_lprop(c, lp) ({}) #define dbg_dump_lpt_node(c, node, lnum, offs) ({})
#define dbg_dump_lprops(c) ({}) #define dbg_dump_budget_req(req) ({})
#define dbg_dump_lpt_info(c) ({}) #define dbg_dump_lstats(lst) ({})
#define dbg_dump_leb(c, lnum) ({}) #define dbg_dump_budg(c) ({})
#define dbg_dump_znode(c, znode) ({}) #define dbg_dump_lprop(c, lp) ({})
#define dbg_dump_heap(c, heap, cat) ({}) #define dbg_dump_lprops(c) ({})
#define dbg_dump_pnode(c, pnode, parent, iip) ({}) #define dbg_dump_lpt_info(c) ({})
#define dbg_dump_tnc(c) ({}) #define dbg_dump_leb(c, lnum) ({})
#define dbg_dump_index(c) ({}) #define dbg_dump_znode(c, znode) ({})
#define dbg_dump_heap(c, heap, cat) ({})
#define dbg_dump_pnode(c, pnode, parent, iip) ({})
#define dbg_dump_tnc(c) ({})
#define dbg_dump_index(c) ({})
#define dbg_dump_lpt_lebs(c) ({})
#define dbg_walk_index(c, leaf_cb, znode_cb, priv) 0 #define dbg_walk_index(c, leaf_cb, znode_cb, priv) 0
#define dbg_old_index_check_init(c, zroot) 0 #define dbg_old_index_check_init(c, zroot) 0
@ -396,9 +455,11 @@ static inline int dbg_change(struct ubi_volume_desc *desc, int lnum,
#define dbg_force_in_the_gaps_enabled 0 #define dbg_force_in_the_gaps_enabled 0
#define dbg_force_in_the_gaps() 0 #define dbg_force_in_the_gaps() 0
#define dbg_failure_mode 0 #define dbg_failure_mode 0
#define dbg_failure_mode_registration(c) ({})
#define dbg_failure_mode_deregistration(c) ({}) #define dbg_debugfs_init() 0
#define dbg_debugfs_exit()
#define dbg_debugfs_init_fs(c) 0
#define dbg_debugfs_exit_fs(c) 0
#endif /* !CONFIG_UBIFS_FS_DEBUG */ #endif /* !CONFIG_UBIFS_FS_DEBUG */
#endif /* !__UBIFS_DEBUG_H__ */ #endif /* !__UBIFS_DEBUG_H__ */

View File

@ -72,8 +72,8 @@ static int read_block(struct inode *inode, void *addr, unsigned int block,
return err; return err;
} }
ubifs_assert(le64_to_cpu(dn->ch.sqnum) > ubifs_inode(inode)->creat_sqnum); ubifs_assert(le64_to_cpu(dn->ch.sqnum) >
ubifs_inode(inode)->creat_sqnum);
len = le32_to_cpu(dn->size); len = le32_to_cpu(dn->size);
if (len <= 0 || len > UBIFS_BLOCK_SIZE) if (len <= 0 || len > UBIFS_BLOCK_SIZE)
goto dump; goto dump;
@ -254,7 +254,7 @@ static int write_begin_slow(struct address_space *mapping,
} }
if (!PageUptodate(page)) { if (!PageUptodate(page)) {
if (!(pos & PAGE_CACHE_MASK) && len == PAGE_CACHE_SIZE) if (!(pos & ~PAGE_CACHE_MASK) && len == PAGE_CACHE_SIZE)
SetPageChecked(page); SetPageChecked(page);
else { else {
err = do_readpage(page); err = do_readpage(page);
@ -444,7 +444,7 @@ static int ubifs_write_begin(struct file *file, struct address_space *mapping,
if (!PageUptodate(page)) { if (!PageUptodate(page)) {
/* The page is not loaded from the flash */ /* The page is not loaded from the flash */
if (!(pos & PAGE_CACHE_MASK) && len == PAGE_CACHE_SIZE) if (!(pos & ~PAGE_CACHE_MASK) && len == PAGE_CACHE_SIZE)
/* /*
* We change whole page so no need to load it. But we * We change whole page so no need to load it. But we
* have to set the @PG_checked flag to make the further * have to set the @PG_checked flag to make the further

View File

@ -154,6 +154,7 @@ long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case FS_IOC_GETFLAGS: case FS_IOC_GETFLAGS:
flags = ubifs2ioctl(ubifs_inode(inode)->flags); flags = ubifs2ioctl(ubifs_inode(inode)->flags);
dbg_gen("get flags: %#x, i_flags %#x", flags, inode->i_flags);
return put_user(flags, (int __user *) arg); return put_user(flags, (int __user *) arg);
case FS_IOC_SETFLAGS: { case FS_IOC_SETFLAGS: {
@ -176,6 +177,7 @@ long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
err = mnt_want_write(file->f_path.mnt); err = mnt_want_write(file->f_path.mnt);
if (err) if (err)
return err; return err;
dbg_gen("set flags: %#x, i_flags %#x", flags, inode->i_flags);
err = setflags(inode, flags); err = setflags(inode, flags);
mnt_drop_write(file->f_path.mnt); mnt_drop_write(file->f_path.mnt);
return err; return err;

View File

@ -704,7 +704,7 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
data->size = cpu_to_le32(len); data->size = cpu_to_le32(len);
zero_data_node_unused(data); zero_data_node_unused(data);
if (!(ui->flags && UBIFS_COMPR_FL)) if (!(ui->flags & UBIFS_COMPR_FL))
/* Compression is disabled for this inode */ /* Compression is disabled for this inode */
compr_type = UBIFS_COMPR_NONE; compr_type = UBIFS_COMPR_NONE;
else else
@ -1220,7 +1220,7 @@ int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode,
data_key_init(c, &key, inum, blk); data_key_init(c, &key, inum, blk);
bit = old_size & (UBIFS_BLOCK_SIZE - 1); bit = old_size & (UBIFS_BLOCK_SIZE - 1);
blk = (old_size >> UBIFS_BLOCK_SHIFT) - (bit ? 0: 1); blk = (old_size >> UBIFS_BLOCK_SHIFT) - (bit ? 0 : 1);
data_key_init(c, &to_key, inum, blk); data_key_init(c, &to_key, inum, blk);
err = ubifs_tnc_remove_range(c, &key, &to_key); err = ubifs_tnc_remove_range(c, &key, &to_key);

View File

@ -37,6 +37,22 @@
#ifndef __UBIFS_KEY_H__ #ifndef __UBIFS_KEY_H__
#define __UBIFS_KEY_H__ #define __UBIFS_KEY_H__
/**
* key_mask_hash - mask a valid hash value.
* @val: value to be masked
*
* We use hash values as offset in directories, so values %0 and %1 are
* reserved for "." and "..". %2 is reserved for "end of readdir" marker. This
* function makes sure the reserved values are not used.
*/
static inline uint32_t key_mask_hash(uint32_t hash)
{
hash &= UBIFS_S_KEY_HASH_MASK;
if (unlikely(hash <= 2))
hash += 3;
return hash;
}
/** /**
* key_r5_hash - R5 hash function (borrowed from reiserfs). * key_r5_hash - R5 hash function (borrowed from reiserfs).
* @s: direntry name * @s: direntry name
@ -54,16 +70,7 @@ static inline uint32_t key_r5_hash(const char *s, int len)
str++; str++;
} }
a &= UBIFS_S_KEY_HASH_MASK; return key_mask_hash(a);
/*
* We use hash values as offset in directories, so values %0 and %1 are
* reserved for "." and "..". %2 is reserved for "end of readdir"
* marker.
*/
if (unlikely(a >= 0 && a <= 2))
a += 3;
return a;
} }
/** /**
@ -77,10 +84,7 @@ static inline uint32_t key_test_hash(const char *str, int len)
len = min_t(uint32_t, len, 4); len = min_t(uint32_t, len, 4);
memcpy(&a, str, len); memcpy(&a, str, len);
a &= UBIFS_S_KEY_HASH_MASK; return key_mask_hash(a);
if (unlikely(a >= 0 && a <= 2))
a += 3;
return a;
} }
/** /**

View File

@ -520,13 +520,13 @@ static int is_lprops_dirty(struct ubifs_info *c, struct ubifs_lprops *lprops)
* @flags: new flags * @flags: new flags
* @idx_gc_cnt: change to the count of idx_gc list * @idx_gc_cnt: change to the count of idx_gc list
* *
* This function changes LEB properties. This function does not change a LEB * This function changes LEB properties (@free, @dirty or @flag). However, the
* property (@free, @dirty or @flag) if the value passed is %LPROPS_NC. * property which has the %LPROPS_NC value is not changed. Returns a pointer to
* the updated LEB properties on success and a negative error code on failure.
* *
* This function returns a pointer to the updated LEB properties on success * Note, the LEB properties may have had to be copied (due to COW) and
* and a negative error code on failure. N.B. the LEB properties may have had to * consequently the pointer returned may not be the same as the pointer
* be copied (due to COW) and consequently the pointer returned may not be the * passed.
* same as the pointer passed.
*/ */
const struct ubifs_lprops *ubifs_change_lp(struct ubifs_info *c, const struct ubifs_lprops *ubifs_change_lp(struct ubifs_info *c,
const struct ubifs_lprops *lp, const struct ubifs_lprops *lp,
@ -1088,7 +1088,7 @@ static int scan_check_cb(struct ubifs_info *c,
} }
} }
sleb = ubifs_scan(c, lnum, 0, c->dbg_buf); sleb = ubifs_scan(c, lnum, 0, c->dbg->buf);
if (IS_ERR(sleb)) { if (IS_ERR(sleb)) {
/* /*
* After an unclean unmount, empty and freeable LEBs * After an unclean unmount, empty and freeable LEBs

View File

@ -36,15 +36,16 @@
* can be written into a single eraseblock. In that case, garbage collection * can be written into a single eraseblock. In that case, garbage collection
* consists of just writing the whole table, which therefore makes all other * consists of just writing the whole table, which therefore makes all other
* eraseblocks reusable. In the case of the big model, dirty eraseblocks are * eraseblocks reusable. In the case of the big model, dirty eraseblocks are
* selected for garbage collection, which consists are marking the nodes in * selected for garbage collection, which consists of marking the clean nodes in
* that LEB as dirty, and then only the dirty nodes are written out. Also, in * that LEB as dirty, and then only the dirty nodes are written out. Also, in
* the case of the big model, a table of LEB numbers is saved so that the entire * the case of the big model, a table of LEB numbers is saved so that the entire
* LPT does not to be scanned looking for empty eraseblocks when UBIFS is first * LPT does not to be scanned looking for empty eraseblocks when UBIFS is first
* mounted. * mounted.
*/ */
#include <linux/crc16.h>
#include "ubifs.h" #include "ubifs.h"
#include <linux/crc16.h>
#include <linux/math64.h>
/** /**
* do_calc_lpt_geom - calculate sizes for the LPT area. * do_calc_lpt_geom - calculate sizes for the LPT area.
@ -135,15 +136,13 @@ static void do_calc_lpt_geom(struct ubifs_info *c)
int ubifs_calc_lpt_geom(struct ubifs_info *c) int ubifs_calc_lpt_geom(struct ubifs_info *c)
{ {
int lebs_needed; int lebs_needed;
uint64_t sz; long long sz;
do_calc_lpt_geom(c); do_calc_lpt_geom(c);
/* Verify that lpt_lebs is big enough */ /* Verify that lpt_lebs is big enough */
sz = c->lpt_sz * 2; /* Must have at least 2 times the size */ sz = c->lpt_sz * 2; /* Must have at least 2 times the size */
sz += c->leb_size - 1; lebs_needed = div_u64(sz + c->leb_size - 1, c->leb_size);
do_div(sz, c->leb_size);
lebs_needed = sz;
if (lebs_needed > c->lpt_lebs) { if (lebs_needed > c->lpt_lebs) {
ubifs_err("too few LPT LEBs"); ubifs_err("too few LPT LEBs");
return -EINVAL; return -EINVAL;
@ -156,7 +155,6 @@ int ubifs_calc_lpt_geom(struct ubifs_info *c)
} }
c->check_lpt_free = c->big_lpt; c->check_lpt_free = c->big_lpt;
return 0; return 0;
} }
@ -176,7 +174,7 @@ static int calc_dflt_lpt_geom(struct ubifs_info *c, int *main_lebs,
int *big_lpt) int *big_lpt)
{ {
int i, lebs_needed; int i, lebs_needed;
uint64_t sz; long long sz;
/* Start by assuming the minimum number of LPT LEBs */ /* Start by assuming the minimum number of LPT LEBs */
c->lpt_lebs = UBIFS_MIN_LPT_LEBS; c->lpt_lebs = UBIFS_MIN_LPT_LEBS;
@ -203,9 +201,7 @@ static int calc_dflt_lpt_geom(struct ubifs_info *c, int *main_lebs,
/* Now check there are enough LPT LEBs */ /* Now check there are enough LPT LEBs */
for (i = 0; i < 64 ; i++) { for (i = 0; i < 64 ; i++) {
sz = c->lpt_sz * 4; /* Allow 4 times the size */ sz = c->lpt_sz * 4; /* Allow 4 times the size */
sz += c->leb_size - 1; lebs_needed = div_u64(sz + c->leb_size - 1, c->leb_size);
do_div(sz, c->leb_size);
lebs_needed = sz;
if (lebs_needed > c->lpt_lebs) { if (lebs_needed > c->lpt_lebs) {
/* Not enough LPT LEBs so try again with more */ /* Not enough LPT LEBs so try again with more */
c->lpt_lebs = lebs_needed; c->lpt_lebs = lebs_needed;
@ -558,7 +554,7 @@ static int calc_nnode_num(int row, int col)
* This function calculates and returns the nnode number based on the parent's * This function calculates and returns the nnode number based on the parent's
* nnode number and the index in parent. * nnode number and the index in parent.
*/ */
static int calc_nnode_num_from_parent(struct ubifs_info *c, static int calc_nnode_num_from_parent(const struct ubifs_info *c,
struct ubifs_nnode *parent, int iip) struct ubifs_nnode *parent, int iip)
{ {
int num, shft; int num, shft;
@ -583,7 +579,7 @@ static int calc_nnode_num_from_parent(struct ubifs_info *c,
* This function calculates and returns the pnode number based on the parent's * This function calculates and returns the pnode number based on the parent's
* nnode number and the index in parent. * nnode number and the index in parent.
*/ */
static int calc_pnode_num_from_parent(struct ubifs_info *c, static int calc_pnode_num_from_parent(const struct ubifs_info *c,
struct ubifs_nnode *parent, int iip) struct ubifs_nnode *parent, int iip)
{ {
int i, n = c->lpt_hght - 1, pnum = parent->num, num = 0; int i, n = c->lpt_hght - 1, pnum = parent->num, num = 0;
@ -966,7 +962,7 @@ static int check_lpt_type(uint8_t **addr, int *pos, int type)
* *
* This function returns %0 on success and a negative error code on failure. * This function returns %0 on success and a negative error code on failure.
*/ */
static int unpack_pnode(struct ubifs_info *c, void *buf, static int unpack_pnode(const struct ubifs_info *c, void *buf,
struct ubifs_pnode *pnode) struct ubifs_pnode *pnode)
{ {
uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES; uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
@ -996,15 +992,15 @@ static int unpack_pnode(struct ubifs_info *c, void *buf,
} }
/** /**
* unpack_nnode - unpack a nnode. * ubifs_unpack_nnode - unpack a nnode.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
* @buf: buffer containing packed nnode to unpack * @buf: buffer containing packed nnode to unpack
* @nnode: nnode structure to fill * @nnode: nnode structure to fill
* *
* This function returns %0 on success and a negative error code on failure. * This function returns %0 on success and a negative error code on failure.
*/ */
static int unpack_nnode(struct ubifs_info *c, void *buf, int ubifs_unpack_nnode(const struct ubifs_info *c, void *buf,
struct ubifs_nnode *nnode) struct ubifs_nnode *nnode)
{ {
uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES; uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
int i, pos = 0, err; int i, pos = 0, err;
@ -1036,7 +1032,7 @@ static int unpack_nnode(struct ubifs_info *c, void *buf,
* *
* This function returns %0 on success and a negative error code on failure. * This function returns %0 on success and a negative error code on failure.
*/ */
static int unpack_ltab(struct ubifs_info *c, void *buf) static int unpack_ltab(const struct ubifs_info *c, void *buf)
{ {
uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES; uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
int i, pos = 0, err; int i, pos = 0, err;
@ -1068,7 +1064,7 @@ static int unpack_ltab(struct ubifs_info *c, void *buf)
* *
* This function returns %0 on success and a negative error code on failure. * This function returns %0 on success and a negative error code on failure.
*/ */
static int unpack_lsave(struct ubifs_info *c, void *buf) static int unpack_lsave(const struct ubifs_info *c, void *buf)
{ {
uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES; uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
int i, pos = 0, err; int i, pos = 0, err;
@ -1096,7 +1092,7 @@ static int unpack_lsave(struct ubifs_info *c, void *buf)
* *
* This function returns %0 on success and a negative error code on failure. * This function returns %0 on success and a negative error code on failure.
*/ */
static int validate_nnode(struct ubifs_info *c, struct ubifs_nnode *nnode, static int validate_nnode(const struct ubifs_info *c, struct ubifs_nnode *nnode,
struct ubifs_nnode *parent, int iip) struct ubifs_nnode *parent, int iip)
{ {
int i, lvl, max_offs; int i, lvl, max_offs;
@ -1140,7 +1136,7 @@ static int validate_nnode(struct ubifs_info *c, struct ubifs_nnode *nnode,
* *
* This function returns %0 on success and a negative error code on failure. * This function returns %0 on success and a negative error code on failure.
*/ */
static int validate_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode, static int validate_pnode(const struct ubifs_info *c, struct ubifs_pnode *pnode,
struct ubifs_nnode *parent, int iip) struct ubifs_nnode *parent, int iip)
{ {
int i; int i;
@ -1174,7 +1170,8 @@ static int validate_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
* This function calculates the LEB numbers for the LEB properties it contains * This function calculates the LEB numbers for the LEB properties it contains
* based on the pnode number. * based on the pnode number.
*/ */
static void set_pnode_lnum(struct ubifs_info *c, struct ubifs_pnode *pnode) static void set_pnode_lnum(const struct ubifs_info *c,
struct ubifs_pnode *pnode)
{ {
int i, lnum; int i, lnum;
@ -1227,7 +1224,7 @@ int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
err = ubi_read(c->ubi, lnum, buf, offs, c->nnode_sz); err = ubi_read(c->ubi, lnum, buf, offs, c->nnode_sz);
if (err) if (err)
goto out; goto out;
err = unpack_nnode(c, buf, nnode); err = ubifs_unpack_nnode(c, buf, nnode);
if (err) if (err)
goto out; goto out;
} }
@ -1816,7 +1813,7 @@ static struct ubifs_nnode *scan_get_nnode(struct ubifs_info *c,
c->nnode_sz); c->nnode_sz);
if (err) if (err)
return ERR_PTR(err); return ERR_PTR(err);
err = unpack_nnode(c, buf, nnode); err = ubifs_unpack_nnode(c, buf, nnode);
if (err) if (err)
return ERR_PTR(err); return ERR_PTR(err);
} }

View File

@ -320,6 +320,8 @@ no_space:
dbg_err("LPT out of space at LEB %d:%d needing %d, done_ltab %d, " 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); "done_lsave %d", lnum, offs, len, done_ltab, done_lsave);
dbg_dump_lpt_info(c); dbg_dump_lpt_info(c);
dbg_dump_lpt_lebs(c);
dump_stack();
return err; return err;
} }
@ -546,8 +548,10 @@ static int write_cnodes(struct ubifs_info *c)
no_space: no_space:
ubifs_err("LPT out of space mismatch"); ubifs_err("LPT out of space mismatch");
dbg_err("LPT out of space mismatch at LEB %d:%d needing %d, done_ltab " 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); "%d, done_lsave %d", lnum, offs, len, done_ltab, done_lsave);
dbg_dump_lpt_info(c); dbg_dump_lpt_info(c);
dbg_dump_lpt_lebs(c);
dump_stack();
return err; return err;
} }
@ -749,7 +753,7 @@ static void lpt_tgc_start(struct ubifs_info *c)
* LPT trivial garbage collection is where a LPT LEB contains only dirty and * LPT trivial garbage collection is where a LPT LEB contains only dirty and
* free space and so may be reused as soon as the next commit is completed. * free space and so may be reused as soon as the next commit is completed.
* This function is called after the commit is completed (master node has been * This function is called after the commit is completed (master node has been
* written) and unmaps LPT LEBs that were marked for trivial GC. * written) and un-maps LPT LEBs that were marked for trivial GC.
*/ */
static int lpt_tgc_end(struct ubifs_info *c) static int lpt_tgc_end(struct ubifs_info *c)
{ {
@ -1025,7 +1029,7 @@ static int make_node_dirty(struct ubifs_info *c, int node_type, int node_num,
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
* @node_type: LPT node type * @node_type: LPT node type
*/ */
static int get_lpt_node_len(struct ubifs_info *c, int node_type) static int get_lpt_node_len(const struct ubifs_info *c, int node_type)
{ {
switch (node_type) { switch (node_type) {
case UBIFS_LPT_NNODE: case UBIFS_LPT_NNODE:
@ -1046,7 +1050,7 @@ static int get_lpt_node_len(struct ubifs_info *c, int node_type)
* @buf: buffer * @buf: buffer
* @len: length of buffer * @len: length of buffer
*/ */
static int get_pad_len(struct ubifs_info *c, uint8_t *buf, int len) static int get_pad_len(const struct ubifs_info *c, uint8_t *buf, int len)
{ {
int offs, pad_len; int offs, pad_len;
@ -1063,7 +1067,8 @@ static int get_pad_len(struct ubifs_info *c, uint8_t *buf, int len)
* @buf: buffer * @buf: buffer
* @node_num: node number is returned here * @node_num: node number is returned here
*/ */
static int get_lpt_node_type(struct ubifs_info *c, uint8_t *buf, int *node_num) static int get_lpt_node_type(const struct ubifs_info *c, uint8_t *buf,
int *node_num)
{ {
uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES; uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
int pos = 0, node_type; int pos = 0, node_type;
@ -1081,7 +1086,7 @@ static int get_lpt_node_type(struct ubifs_info *c, uint8_t *buf, int *node_num)
* *
* This function returns %1 if the buffer contains a node or %0 if it does not. * This function returns %1 if the buffer contains a node or %0 if it does not.
*/ */
static int is_a_node(struct ubifs_info *c, uint8_t *buf, int len) static int is_a_node(const struct ubifs_info *c, uint8_t *buf, int len)
{ {
uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES; uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
int pos = 0, node_type, node_len; int pos = 0, node_type, node_len;
@ -1105,7 +1110,6 @@ static int is_a_node(struct ubifs_info *c, uint8_t *buf, int len)
return 1; return 1;
} }
/** /**
* lpt_gc_lnum - garbage collect a LPT LEB. * lpt_gc_lnum - garbage collect a LPT LEB.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
@ -1463,7 +1467,7 @@ void ubifs_lpt_free(struct ubifs_info *c, int wr_only)
#ifdef CONFIG_UBIFS_FS_DEBUG #ifdef CONFIG_UBIFS_FS_DEBUG
/** /**
* dbg_is_all_ff - determine if a buffer contains only 0xff bytes. * dbg_is_all_ff - determine if a buffer contains only 0xFF bytes.
* @buf: buffer * @buf: buffer
* @len: buffer length * @len: buffer length
*/ */
@ -1488,7 +1492,7 @@ static int dbg_is_nnode_dirty(struct ubifs_info *c, int lnum, int offs)
struct ubifs_nnode *nnode; struct ubifs_nnode *nnode;
int hght; int hght;
/* Entire tree is in memory so first_nnode / next_nnode are ok */ /* Entire tree is in memory so first_nnode / next_nnode are OK */
nnode = first_nnode(c, &hght); nnode = first_nnode(c, &hght);
for (; nnode; nnode = next_nnode(c, nnode, &hght)) { for (; nnode; nnode = next_nnode(c, nnode, &hght)) {
struct ubifs_nbranch *branch; struct ubifs_nbranch *branch;
@ -1602,7 +1606,10 @@ static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum)
{ {
int err, len = c->leb_size, dirty = 0, node_type, node_num, node_len; int err, len = c->leb_size, dirty = 0, node_type, node_num, node_len;
int ret; int ret;
void *buf = c->dbg_buf; void *buf = c->dbg->buf;
if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
return 0;
dbg_lp("LEB %d", lnum); dbg_lp("LEB %d", lnum);
err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size); err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size);
@ -1704,6 +1711,9 @@ int dbg_chk_lpt_free_spc(struct ubifs_info *c)
long long free = 0; long long free = 0;
int i; int i;
if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
return 0;
for (i = 0; i < c->lpt_lebs; i++) { for (i = 0; i < c->lpt_lebs; i++) {
if (c->ltab[i].tgc || c->ltab[i].cmt) if (c->ltab[i].tgc || c->ltab[i].cmt)
continue; continue;
@ -1716,6 +1726,8 @@ int dbg_chk_lpt_free_spc(struct ubifs_info *c)
dbg_err("LPT space error: free %lld lpt_sz %lld", dbg_err("LPT space error: free %lld lpt_sz %lld",
free, c->lpt_sz); free, c->lpt_sz);
dbg_dump_lpt_info(c); dbg_dump_lpt_info(c);
dbg_dump_lpt_lebs(c);
dump_stack();
return -EINVAL; return -EINVAL;
} }
return 0; return 0;
@ -1731,15 +1743,19 @@ 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_chk_lpt_sz(struct ubifs_info *c, int action, int len)
{ {
struct ubifs_debug_info *d = c->dbg;
long long chk_lpt_sz, lpt_sz; long long chk_lpt_sz, lpt_sz;
int err = 0; int err = 0;
if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
return 0;
switch (action) { switch (action) {
case 0: case 0:
c->chk_lpt_sz = 0; d->chk_lpt_sz = 0;
c->chk_lpt_sz2 = 0; d->chk_lpt_sz2 = 0;
c->chk_lpt_lebs = 0; d->chk_lpt_lebs = 0;
c->chk_lpt_wastage = 0; d->chk_lpt_wastage = 0;
if (c->dirty_pn_cnt > c->pnode_cnt) { if (c->dirty_pn_cnt > c->pnode_cnt) {
dbg_err("dirty pnodes %d exceed max %d", dbg_err("dirty pnodes %d exceed max %d",
c->dirty_pn_cnt, c->pnode_cnt); c->dirty_pn_cnt, c->pnode_cnt);
@ -1752,35 +1768,35 @@ int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len)
} }
return err; return err;
case 1: case 1:
c->chk_lpt_sz += len; d->chk_lpt_sz += len;
return 0; return 0;
case 2: case 2:
c->chk_lpt_sz += len; d->chk_lpt_sz += len;
c->chk_lpt_wastage += len; d->chk_lpt_wastage += len;
c->chk_lpt_lebs += 1; d->chk_lpt_lebs += 1;
return 0; return 0;
case 3: case 3:
chk_lpt_sz = c->leb_size; chk_lpt_sz = c->leb_size;
chk_lpt_sz *= c->chk_lpt_lebs; chk_lpt_sz *= d->chk_lpt_lebs;
chk_lpt_sz += len - c->nhead_offs; chk_lpt_sz += len - c->nhead_offs;
if (c->chk_lpt_sz != chk_lpt_sz) { if (d->chk_lpt_sz != chk_lpt_sz) {
dbg_err("LPT wrote %lld but space used was %lld", dbg_err("LPT wrote %lld but space used was %lld",
c->chk_lpt_sz, chk_lpt_sz); d->chk_lpt_sz, chk_lpt_sz);
err = -EINVAL; err = -EINVAL;
} }
if (c->chk_lpt_sz > c->lpt_sz) { if (d->chk_lpt_sz > c->lpt_sz) {
dbg_err("LPT wrote %lld but lpt_sz is %lld", dbg_err("LPT wrote %lld but lpt_sz is %lld",
c->chk_lpt_sz, c->lpt_sz); d->chk_lpt_sz, c->lpt_sz);
err = -EINVAL; err = -EINVAL;
} }
if (c->chk_lpt_sz2 && c->chk_lpt_sz != c->chk_lpt_sz2) { if (d->chk_lpt_sz2 && d->chk_lpt_sz != d->chk_lpt_sz2) {
dbg_err("LPT layout size %lld but wrote %lld", dbg_err("LPT layout size %lld but wrote %lld",
c->chk_lpt_sz, c->chk_lpt_sz2); d->chk_lpt_sz, d->chk_lpt_sz2);
err = -EINVAL; err = -EINVAL;
} }
if (c->chk_lpt_sz2 && c->new_nhead_offs != len) { if (d->chk_lpt_sz2 && d->new_nhead_offs != len) {
dbg_err("LPT new nhead offs: expected %d was %d", dbg_err("LPT new nhead offs: expected %d was %d",
c->new_nhead_offs, len); d->new_nhead_offs, len);
err = -EINVAL; err = -EINVAL;
} }
lpt_sz = (long long)c->pnode_cnt * c->pnode_sz; lpt_sz = (long long)c->pnode_cnt * c->pnode_sz;
@ -1788,26 +1804,146 @@ int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len)
lpt_sz += c->ltab_sz; lpt_sz += c->ltab_sz;
if (c->big_lpt) if (c->big_lpt)
lpt_sz += c->lsave_sz; lpt_sz += c->lsave_sz;
if (c->chk_lpt_sz - c->chk_lpt_wastage > lpt_sz) { if (d->chk_lpt_sz - d->chk_lpt_wastage > lpt_sz) {
dbg_err("LPT chk_lpt_sz %lld + waste %lld exceeds %lld", dbg_err("LPT chk_lpt_sz %lld + waste %lld exceeds %lld",
c->chk_lpt_sz, c->chk_lpt_wastage, lpt_sz); d->chk_lpt_sz, d->chk_lpt_wastage, lpt_sz);
err = -EINVAL; err = -EINVAL;
} }
if (err) if (err) {
dbg_dump_lpt_info(c); dbg_dump_lpt_info(c);
c->chk_lpt_sz2 = c->chk_lpt_sz; dbg_dump_lpt_lebs(c);
c->chk_lpt_sz = 0; dump_stack();
c->chk_lpt_wastage = 0; }
c->chk_lpt_lebs = 0; d->chk_lpt_sz2 = d->chk_lpt_sz;
c->new_nhead_offs = len; d->chk_lpt_sz = 0;
d->chk_lpt_wastage = 0;
d->chk_lpt_lebs = 0;
d->new_nhead_offs = len;
return err; return err;
case 4: case 4:
c->chk_lpt_sz += len; d->chk_lpt_sz += len;
c->chk_lpt_wastage += len; d->chk_lpt_wastage += len;
return 0; return 0;
default: default:
return -EINVAL; return -EINVAL;
} }
} }
/**
* dbg_dump_lpt_leb - dump an LPT LEB.
* @c: UBIFS file-system description object
* @lnum: LEB number to dump
*
* This function dumps an LEB from LPT area. Nodes in this area are very
* different to nodes in the main area (e.g., they do not have common headers,
* they do not have 8-byte alignments, etc), so we have a separate function to
* dump LPT area LEBs. Note, LPT has to be locked by the caller.
*/
static void dump_lpt_leb(const struct ubifs_info *c, int lnum)
{
int err, len = c->leb_size, node_type, node_num, node_len, offs;
void *buf = c->dbg->buf;
printk(KERN_DEBUG "(pid %d) start dumping LEB %d\n",
current->pid, lnum);
err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size);
if (err) {
ubifs_err("cannot read LEB %d, error %d", lnum, err);
return;
}
while (1) {
offs = c->leb_size - len;
if (!is_a_node(c, buf, len)) {
int pad_len;
pad_len = get_pad_len(c, buf, len);
if (pad_len) {
printk(KERN_DEBUG "LEB %d:%d, pad %d bytes\n",
lnum, offs, pad_len);
buf += pad_len;
len -= pad_len;
continue;
}
if (len)
printk(KERN_DEBUG "LEB %d:%d, free %d bytes\n",
lnum, offs, len);
break;
}
node_type = get_lpt_node_type(c, buf, &node_num);
switch (node_type) {
case UBIFS_LPT_PNODE:
{
node_len = c->pnode_sz;
if (c->big_lpt)
printk(KERN_DEBUG "LEB %d:%d, pnode num %d\n",
lnum, offs, node_num);
else
printk(KERN_DEBUG "LEB %d:%d, pnode\n",
lnum, offs);
break;
}
case UBIFS_LPT_NNODE:
{
int i;
struct ubifs_nnode nnode;
node_len = c->nnode_sz;
if (c->big_lpt)
printk(KERN_DEBUG "LEB %d:%d, nnode num %d, ",
lnum, offs, node_num);
else
printk(KERN_DEBUG "LEB %d:%d, nnode, ",
lnum, offs);
err = ubifs_unpack_nnode(c, buf, &nnode);
for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
printk("%d:%d", nnode.nbranch[i].lnum,
nnode.nbranch[i].offs);
if (i != UBIFS_LPT_FANOUT - 1)
printk(", ");
}
printk("\n");
break;
}
case UBIFS_LPT_LTAB:
node_len = c->ltab_sz;
printk(KERN_DEBUG "LEB %d:%d, ltab\n",
lnum, offs);
break;
case UBIFS_LPT_LSAVE:
node_len = c->lsave_sz;
printk(KERN_DEBUG "LEB %d:%d, lsave len\n", lnum, offs);
break;
default:
ubifs_err("LPT node type %d not recognized", node_type);
return;
}
buf += node_len;
len -= node_len;
}
printk(KERN_DEBUG "(pid %d) finish dumping LEB %d\n",
current->pid, lnum);
}
/**
* dbg_dump_lpt_lebs - dump LPT lebs.
* @c: UBIFS file-system description object
*
* This function dumps all LPT LEBs. The caller has to make sure the LPT is
* locked.
*/
void dbg_dump_lpt_lebs(const struct ubifs_info *c)
{
int i;
printk(KERN_DEBUG "(pid %d) start dumping all LPT LEBs\n",
current->pid);
for (i = 0; i < c->lpt_lebs; i++)
dump_lpt_leb(c, i + c->lpt_first);
printk(KERN_DEBUG "(pid %d) finish dumping all LPT LEBs\n",
current->pid);
}
#endif /* CONFIG_UBIFS_FS_DEBUG */ #endif /* CONFIG_UBIFS_FS_DEBUG */

View File

@ -899,7 +899,7 @@ static int dbg_scan_orphans(struct ubifs_info *c, struct check_info *ci)
for (lnum = c->orph_first; lnum <= c->orph_last; lnum++) { for (lnum = c->orph_first; lnum <= c->orph_last; lnum++) {
struct ubifs_scan_leb *sleb; struct ubifs_scan_leb *sleb;
sleb = ubifs_scan(c, lnum, 0, c->dbg_buf); sleb = ubifs_scan(c, lnum, 0, c->dbg->buf);
if (IS_ERR(sleb)) { if (IS_ERR(sleb)) {
err = PTR_ERR(sleb); err = PTR_ERR(sleb);
break; break;

View File

@ -144,7 +144,7 @@ static int set_bud_lprops(struct ubifs_info *c, struct replay_entry *r)
/* /*
* If the replay order was perfect the dirty space would now be * If the replay order was perfect the dirty space would now be
* zero. The order is not perfect because the the journal heads * zero. The order is not perfect because the the journal heads
* race with eachother. This is not a problem but is does mean * race with each other. This is not a problem but is does mean
* that the dirty space may temporarily exceed c->leb_size * that the dirty space may temporarily exceed c->leb_size
* during the replay. * during the replay.
*/ */
@ -656,7 +656,7 @@ out_dump:
* @dirty: amount of dirty space from padding and deletion nodes * @dirty: amount of dirty space from padding and deletion nodes
* *
* This function inserts a reference node to the replay tree and returns zero * This function inserts a reference node to the replay tree and returns zero
* in case of success ort a negative error code in case of failure. * in case of success or a negative error code in case of failure.
*/ */
static int insert_ref_node(struct ubifs_info *c, int lnum, int offs, static int insert_ref_node(struct ubifs_info *c, int lnum, int offs,
unsigned long long sqnum, int free, int dirty) unsigned long long sqnum, int free, int dirty)
@ -883,7 +883,7 @@ static int replay_log_leb(struct ubifs_info *c, int lnum, int offs, void *sbuf)
* This means that we reached end of log and now * This means that we reached end of log and now
* look to the older log data, which was already * look to the older log data, which was already
* committed but the eraseblock was not erased (UBIFS * committed but the eraseblock was not erased (UBIFS
* only unmaps it). So this basically means we have to * only un-maps it). So this basically means we have to
* exit with "end of log" code. * exit with "end of log" code.
*/ */
err = 1; err = 1;
@ -1062,6 +1062,15 @@ int ubifs_replay_journal(struct ubifs_info *c)
if (err) if (err)
goto out; goto out;
/*
* UBIFS budgeting calculations use @c->budg_uncommitted_idx variable
* to roughly estimate index growth. Things like @c->min_idx_lebs
* depend on it. This means we have to initialize it to make sure
* budgeting works properly.
*/
c->budg_uncommitted_idx = atomic_long_read(&c->dirty_zn_cnt);
c->budg_uncommitted_idx *= c->max_idx_node_sz;
ubifs_assert(c->bud_bytes <= c->max_bud_bytes || c->need_recovery); ubifs_assert(c->bud_bytes <= c->max_bud_bytes || c->need_recovery);
dbg_mnt("finished, log head LEB %d:%d, max_sqnum %llu, " dbg_mnt("finished, log head LEB %d:%d, max_sqnum %llu, "
"highest_inum %lu", c->lhead_lnum, c->lhead_offs, c->max_sqnum, "highest_inum %lu", c->lhead_lnum, c->lhead_offs, c->max_sqnum,

View File

@ -28,6 +28,7 @@
#include "ubifs.h" #include "ubifs.h"
#include <linux/random.h> #include <linux/random.h>
#include <linux/math64.h>
/* /*
* Default journal size in logical eraseblocks as a percent of total * Default journal size in logical eraseblocks as a percent of total
@ -80,7 +81,7 @@ static int create_default_filesystem(struct ubifs_info *c)
int err, tmp, jnl_lebs, log_lebs, max_buds, main_lebs, main_first; int err, tmp, jnl_lebs, log_lebs, max_buds, main_lebs, main_first;
int lpt_lebs, lpt_first, orph_lebs, big_lpt, ino_waste, sup_flags = 0; int lpt_lebs, lpt_first, orph_lebs, big_lpt, ino_waste, sup_flags = 0;
int min_leb_cnt = UBIFS_MIN_LEB_CNT; int min_leb_cnt = UBIFS_MIN_LEB_CNT;
uint64_t tmp64, main_bytes; long long tmp64, main_bytes;
__le64 tmp_le64; __le64 tmp_le64;
/* Some functions called from here depend on the @c->key_len filed */ /* Some functions called from here depend on the @c->key_len filed */
@ -160,7 +161,7 @@ static int create_default_filesystem(struct ubifs_info *c)
if (!sup) if (!sup)
return -ENOMEM; return -ENOMEM;
tmp64 = (uint64_t)max_buds * c->leb_size; tmp64 = (long long)max_buds * c->leb_size;
if (big_lpt) if (big_lpt)
sup_flags |= UBIFS_FLG_BIGLPT; sup_flags |= UBIFS_FLG_BIGLPT;
@ -179,14 +180,16 @@ static int create_default_filesystem(struct ubifs_info *c)
sup->fanout = cpu_to_le32(DEFAULT_FANOUT); sup->fanout = cpu_to_le32(DEFAULT_FANOUT);
sup->lsave_cnt = cpu_to_le32(c->lsave_cnt); sup->lsave_cnt = cpu_to_le32(c->lsave_cnt);
sup->fmt_version = cpu_to_le32(UBIFS_FORMAT_VERSION); sup->fmt_version = cpu_to_le32(UBIFS_FORMAT_VERSION);
sup->default_compr = cpu_to_le16(UBIFS_COMPR_LZO);
sup->time_gran = cpu_to_le32(DEFAULT_TIME_GRAN); sup->time_gran = cpu_to_le32(DEFAULT_TIME_GRAN);
if (c->mount_opts.override_compr)
sup->default_compr = cpu_to_le16(c->mount_opts.compr_type);
else
sup->default_compr = cpu_to_le16(UBIFS_COMPR_LZO);
generate_random_uuid(sup->uuid); generate_random_uuid(sup->uuid);
main_bytes = (uint64_t)main_lebs * c->leb_size; main_bytes = (long long)main_lebs * c->leb_size;
tmp64 = main_bytes * DEFAULT_RP_PERCENT; tmp64 = div_u64(main_bytes * DEFAULT_RP_PERCENT, 100);
do_div(tmp64, 100);
if (tmp64 > DEFAULT_MAX_RP_SIZE) if (tmp64 > DEFAULT_MAX_RP_SIZE)
tmp64 = DEFAULT_MAX_RP_SIZE; tmp64 = DEFAULT_MAX_RP_SIZE;
sup->rp_size = cpu_to_le64(tmp64); sup->rp_size = cpu_to_le64(tmp64);
@ -582,16 +585,15 @@ int ubifs_read_superblock(struct ubifs_info *c)
c->jhead_cnt = le32_to_cpu(sup->jhead_cnt) + NONDATA_JHEADS_CNT; c->jhead_cnt = le32_to_cpu(sup->jhead_cnt) + NONDATA_JHEADS_CNT;
c->fanout = le32_to_cpu(sup->fanout); c->fanout = le32_to_cpu(sup->fanout);
c->lsave_cnt = le32_to_cpu(sup->lsave_cnt); c->lsave_cnt = le32_to_cpu(sup->lsave_cnt);
c->default_compr = le16_to_cpu(sup->default_compr);
c->rp_size = le64_to_cpu(sup->rp_size); c->rp_size = le64_to_cpu(sup->rp_size);
c->rp_uid = le32_to_cpu(sup->rp_uid); c->rp_uid = le32_to_cpu(sup->rp_uid);
c->rp_gid = le32_to_cpu(sup->rp_gid); c->rp_gid = le32_to_cpu(sup->rp_gid);
sup_flags = le32_to_cpu(sup->flags); sup_flags = le32_to_cpu(sup->flags);
if (!c->mount_opts.override_compr)
c->default_compr = le16_to_cpu(sup->default_compr);
c->vfs_sb->s_time_gran = le32_to_cpu(sup->time_gran); c->vfs_sb->s_time_gran = le32_to_cpu(sup->time_gran);
memcpy(&c->uuid, &sup->uuid, 16); memcpy(&c->uuid, &sup->uuid, 16);
c->big_lpt = !!(sup_flags & UBIFS_FLG_BIGLPT); c->big_lpt = !!(sup_flags & UBIFS_FLG_BIGLPT);
/* Automatically increase file system size to the maximum size */ /* Automatically increase file system size to the maximum size */

View File

@ -34,6 +34,8 @@
#include <linux/parser.h> #include <linux/parser.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/math64.h>
#include <linux/writeback.h>
#include "ubifs.h" #include "ubifs.h"
/* /*
@ -417,39 +419,54 @@ static int ubifs_show_options(struct seq_file *s, struct vfsmount *mnt)
else if (c->mount_opts.chk_data_crc == 1) else if (c->mount_opts.chk_data_crc == 1)
seq_printf(s, ",no_chk_data_crc"); seq_printf(s, ",no_chk_data_crc");
if (c->mount_opts.override_compr) {
seq_printf(s, ",compr=");
seq_printf(s, ubifs_compr_name(c->mount_opts.compr_type));
}
return 0; return 0;
} }
static int ubifs_sync_fs(struct super_block *sb, int wait) static int ubifs_sync_fs(struct super_block *sb, int wait)
{ {
int i, err;
struct ubifs_info *c = sb->s_fs_info; struct ubifs_info *c = sb->s_fs_info;
int i, ret = 0, err; struct writeback_control wbc = {
long long bud_bytes; .sync_mode = wait ? WB_SYNC_ALL : WB_SYNC_HOLD,
.range_start = 0,
.range_end = LLONG_MAX,
.nr_to_write = LONG_MAX,
};
if (c->jheads) { if (sb->s_flags & MS_RDONLY)
for (i = 0; i < c->jhead_cnt; i++) { return 0;
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); * Synchronize write buffers, because 'ubifs_run_commit()' does not
bud_bytes = c->bud_bytes; * do this if it waits for an already running commit.
spin_unlock(&c->buds_lock); */
if (bud_bytes > c->leb_size) { for (i = 0; i < c->jhead_cnt; i++) {
err = ubifs_run_commit(c); err = ubifs_wbuf_sync(&c->jheads[i].wbuf);
if (err) if (err)
return err; return err;
}
} }
/* /*
* We ought to call sync for c->ubi but it does not have one. If it had * VFS calls '->sync_fs()' before synchronizing all dirty inodes and
* it would in turn call mtd->sync, however mtd operations are * pages, so synchronize them first, then commit the journal. Strictly
* synchronous anyway, so we don't lose any sleep here. * speaking, it is not necessary to commit the journal here,
* synchronizing write-buffers would be enough. But committing makes
* UBIFS free space predictions much more accurate, so we want to let
* the user be able to get more accurate results of 'statfs()' after
* they synchronize the file system.
*/ */
return ret; generic_sync_sb_inodes(sb, &wbc);
err = ubifs_run_commit(c);
if (err)
return err;
return ubi_sync(c->vi.ubi_num);
} }
/** /**
@ -596,7 +613,7 @@ static int bud_wbuf_callback(struct ubifs_info *c, int lnum, int free, int pad)
} }
/* /*
* init_constants_late - initialize UBIFS constants. * init_constants_sb - initialize UBIFS constants.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
* *
* This is a helper function which initializes various UBIFS constants after * This is a helper function which initializes various UBIFS constants after
@ -604,10 +621,10 @@ static int bud_wbuf_callback(struct ubifs_info *c, int lnum, int free, int pad)
* makes sure they are all right. Returns zero in case of success and a * makes sure they are all right. Returns zero in case of success and a
* negative error code in case of failure. * negative error code in case of failure.
*/ */
static int init_constants_late(struct ubifs_info *c) static int init_constants_sb(struct ubifs_info *c)
{ {
int tmp, err; int tmp, err;
uint64_t tmp64; long long tmp64;
c->main_bytes = (long long)c->main_lebs * c->leb_size; c->main_bytes = (long long)c->main_lebs * c->leb_size;
c->max_znode_sz = sizeof(struct ubifs_znode) + c->max_znode_sz = sizeof(struct ubifs_znode) +
@ -634,9 +651,8 @@ static int init_constants_late(struct ubifs_info *c)
* Make sure that the log is large enough to fit reference nodes for * Make sure that the log is large enough to fit reference nodes for
* all buds plus one reserved LEB. * all buds plus one reserved LEB.
*/ */
tmp64 = c->max_bud_bytes; tmp64 = c->max_bud_bytes + c->leb_size - 1;
tmp = do_div(tmp64, c->leb_size); c->max_bud_cnt = div_u64(tmp64, c->leb_size);
c->max_bud_cnt = tmp64 + !!tmp;
tmp = (c->ref_node_alsz * c->max_bud_cnt + c->leb_size - 1); tmp = (c->ref_node_alsz * c->max_bud_cnt + c->leb_size - 1);
tmp /= c->leb_size; tmp /= c->leb_size;
tmp += 1; tmp += 1;
@ -672,7 +688,7 @@ static int init_constants_late(struct ubifs_info *c)
* Consequently, if the journal is too small, UBIFS will treat it as * Consequently, if the journal is too small, UBIFS will treat it as
* always full. * always full.
*/ */
tmp64 = (uint64_t)(c->jhead_cnt + 1) * c->leb_size + 1; tmp64 = (long long)(c->jhead_cnt + 1) * c->leb_size + 1;
if (c->bg_bud_bytes < tmp64) if (c->bg_bud_bytes < tmp64)
c->bg_bud_bytes = tmp64; c->bg_bud_bytes = tmp64;
if (c->max_bud_bytes < tmp64 + c->leb_size) if (c->max_bud_bytes < tmp64 + c->leb_size)
@ -682,6 +698,21 @@ static int init_constants_late(struct ubifs_info *c)
if (err) if (err)
return err; return err;
return 0;
}
/*
* init_constants_master - initialize UBIFS constants.
* @c: UBIFS file-system description object
*
* This is a helper function which initializes various UBIFS constants after
* the master node has been read. It also checks various UBIFS parameters and
* makes sure they are all right.
*/
static void init_constants_master(struct ubifs_info *c)
{
long long tmp64;
c->min_idx_lebs = ubifs_calc_min_idx_lebs(c); c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
/* /*
@ -690,14 +721,13 @@ static int init_constants_late(struct ubifs_info *c)
* necessary to report something for the 'statfs()' call. * necessary to report something for the 'statfs()' call.
* *
* Subtract the LEB reserved for GC, the LEB which is reserved for * Subtract the LEB reserved for GC, the LEB which is reserved for
* deletions, and assume only one journal head is available. * deletions, minimum LEBs for the index, and assume only one journal
* head is available.
*/ */
tmp64 = c->main_lebs - 2 - c->jhead_cnt + 1; tmp64 = c->main_lebs - 1 - 1 - MIN_INDEX_LEBS - c->jhead_cnt + 1;
tmp64 *= (uint64_t)c->leb_size - c->leb_overhead; tmp64 *= (long long)c->leb_size - c->leb_overhead;
tmp64 = ubifs_reported_space(c, tmp64); tmp64 = ubifs_reported_space(c, tmp64);
c->block_cnt = tmp64 >> UBIFS_BLOCK_SHIFT; c->block_cnt = tmp64 >> UBIFS_BLOCK_SHIFT;
return 0;
} }
/** /**
@ -878,6 +908,7 @@ static int check_volume_empty(struct ubifs_info *c)
* Opt_no_bulk_read: disable bulk-reads * Opt_no_bulk_read: disable bulk-reads
* Opt_chk_data_crc: check CRCs when reading data nodes * Opt_chk_data_crc: check CRCs when reading data nodes
* Opt_no_chk_data_crc: do not check CRCs when reading data nodes * Opt_no_chk_data_crc: do not check CRCs when reading data nodes
* Opt_override_compr: override default compressor
* Opt_err: just end of array marker * Opt_err: just end of array marker
*/ */
enum { enum {
@ -887,6 +918,7 @@ enum {
Opt_no_bulk_read, Opt_no_bulk_read,
Opt_chk_data_crc, Opt_chk_data_crc,
Opt_no_chk_data_crc, Opt_no_chk_data_crc,
Opt_override_compr,
Opt_err, Opt_err,
}; };
@ -897,6 +929,7 @@ static const match_table_t tokens = {
{Opt_no_bulk_read, "no_bulk_read"}, {Opt_no_bulk_read, "no_bulk_read"},
{Opt_chk_data_crc, "chk_data_crc"}, {Opt_chk_data_crc, "chk_data_crc"},
{Opt_no_chk_data_crc, "no_chk_data_crc"}, {Opt_no_chk_data_crc, "no_chk_data_crc"},
{Opt_override_compr, "compr=%s"},
{Opt_err, NULL}, {Opt_err, NULL},
}; };
@ -950,6 +983,28 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options,
c->mount_opts.chk_data_crc = 1; c->mount_opts.chk_data_crc = 1;
c->no_chk_data_crc = 1; c->no_chk_data_crc = 1;
break; break;
case Opt_override_compr:
{
char *name = match_strdup(&args[0]);
if (!name)
return -ENOMEM;
if (!strcmp(name, "none"))
c->mount_opts.compr_type = UBIFS_COMPR_NONE;
else if (!strcmp(name, "lzo"))
c->mount_opts.compr_type = UBIFS_COMPR_LZO;
else if (!strcmp(name, "zlib"))
c->mount_opts.compr_type = UBIFS_COMPR_ZLIB;
else {
ubifs_err("unknown compressor \"%s\"", name);
kfree(name);
return -EINVAL;
}
kfree(name);
c->mount_opts.override_compr = 1;
c->default_compr = c->mount_opts.compr_type;
break;
}
default: default:
ubifs_err("unrecognized mount option \"%s\" " ubifs_err("unrecognized mount option \"%s\" "
"or missing value", p); "or missing value", p);
@ -1018,6 +1073,30 @@ again:
} }
} }
/**
* check_free_space - check if there is enough free space to mount.
* @c: UBIFS file-system description object
*
* This function makes sure UBIFS has enough free space to be mounted in
* read/write mode. UBIFS must always have some free space to allow deletions.
*/
static int check_free_space(struct ubifs_info *c)
{
ubifs_assert(c->dark_wm > 0);
if (c->lst.total_free + c->lst.total_dirty < c->dark_wm) {
ubifs_err("insufficient free space to mount in read/write mode");
dbg_dump_budg(c);
dbg_dump_lprops(c);
/*
* We return %-EINVAL instead of %-ENOSPC because it seems to
* be the closest error code mentioned in the mount function
* documentation.
*/
return -EINVAL;
}
return 0;
}
/** /**
* mount_ubifs - mount UBIFS file-system. * mount_ubifs - mount UBIFS file-system.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
@ -1039,11 +1118,9 @@ static int mount_ubifs(struct ubifs_info *c)
if (err) if (err)
return err; return err;
#ifdef CONFIG_UBIFS_FS_DEBUG err = ubifs_debugging_init(c);
c->dbg_buf = vmalloc(c->leb_size); if (err)
if (!c->dbg_buf) return err;
return -ENOMEM;
#endif
err = check_volume_empty(c); err = check_volume_empty(c);
if (err) if (err)
@ -1100,27 +1177,25 @@ static int mount_ubifs(struct ubifs_info *c)
goto out_free; goto out_free;
/* /*
* Make sure the compressor which is set as the default on in the * Make sure the compressor which is set as default in the superblock
* superblock was actually compiled in. * or overridden by mount options is actually compiled in.
*/ */
if (!ubifs_compr_present(c->default_compr)) { if (!ubifs_compr_present(c->default_compr)) {
ubifs_warn("'%s' compressor is set by superblock, but not " ubifs_err("'compressor \"%s\" is not compiled in",
"compiled in", ubifs_compr_name(c->default_compr)); ubifs_compr_name(c->default_compr));
c->default_compr = UBIFS_COMPR_NONE; goto out_free;
} }
dbg_failure_mode_registration(c); err = init_constants_sb(c);
err = init_constants_late(c);
if (err) if (err)
goto out_dereg; goto out_free;
sz = ALIGN(c->max_idx_node_sz, c->min_io_size); sz = ALIGN(c->max_idx_node_sz, c->min_io_size);
sz = ALIGN(sz + c->max_idx_node_sz, c->min_io_size); sz = ALIGN(sz + c->max_idx_node_sz, c->min_io_size);
c->cbuf = kmalloc(sz, GFP_NOFS); c->cbuf = kmalloc(sz, GFP_NOFS);
if (!c->cbuf) { if (!c->cbuf) {
err = -ENOMEM; err = -ENOMEM;
goto out_dereg; goto out_free;
} }
sprintf(c->bgt_name, BGT_NAME_PATTERN, c->vi.ubi_num, c->vi.vol_id); sprintf(c->bgt_name, BGT_NAME_PATTERN, c->vi.ubi_num, c->vi.vol_id);
@ -1145,6 +1220,8 @@ static int mount_ubifs(struct ubifs_info *c)
if (err) if (err)
goto out_master; goto out_master;
init_constants_master(c);
if ((c->mst_node->flags & cpu_to_le32(UBIFS_MST_DIRTY)) != 0) { if ((c->mst_node->flags & cpu_to_le32(UBIFS_MST_DIRTY)) != 0) {
ubifs_msg("recovery needed"); ubifs_msg("recovery needed");
c->need_recovery = 1; c->need_recovery = 1;
@ -1183,12 +1260,9 @@ static int mount_ubifs(struct ubifs_info *c)
if (!mounted_read_only) { if (!mounted_read_only) {
int lnum; int lnum;
/* Check for enough free space */ err = check_free_space(c);
if (ubifs_calc_available(c, c->min_idx_lebs) <= 0) { if (err)
ubifs_err("insufficient available space");
err = -EINVAL;
goto out_orphans; goto out_orphans;
}
/* Check for enough log space */ /* Check for enough log space */
lnum = c->lhead_lnum + 1; lnum = c->lhead_lnum + 1;
@ -1232,6 +1306,10 @@ static int mount_ubifs(struct ubifs_info *c)
} }
} }
err = dbg_debugfs_init_fs(c);
if (err)
goto out_infos;
err = dbg_check_filesystem(c); err = dbg_check_filesystem(c);
if (err) if (err)
goto out_infos; goto out_infos;
@ -1283,8 +1361,20 @@ static int mount_ubifs(struct ubifs_info *c)
dbg_msg("tree fanout: %d", c->fanout); dbg_msg("tree fanout: %d", c->fanout);
dbg_msg("reserved GC LEB: %d", c->gc_lnum); dbg_msg("reserved GC LEB: %d", c->gc_lnum);
dbg_msg("first main LEB: %d", c->main_first); dbg_msg("first main LEB: %d", c->main_first);
dbg_msg("max. znode size %d", c->max_znode_sz);
dbg_msg("max. index node size %d", c->max_idx_node_sz);
dbg_msg("node sizes: data %zu, inode %zu, dentry %zu",
UBIFS_DATA_NODE_SZ, UBIFS_INO_NODE_SZ, UBIFS_DENT_NODE_SZ);
dbg_msg("node sizes: trun %zu, sb %zu, master %zu",
UBIFS_TRUN_NODE_SZ, UBIFS_SB_NODE_SZ, UBIFS_MST_NODE_SZ);
dbg_msg("node sizes: ref %zu, cmt. start %zu, orph %zu",
UBIFS_REF_NODE_SZ, UBIFS_CS_NODE_SZ, UBIFS_ORPH_NODE_SZ);
dbg_msg("max. node sizes: data %zu, inode %zu dentry %zu",
UBIFS_MAX_DATA_NODE_SZ, UBIFS_MAX_INO_NODE_SZ,
UBIFS_MAX_DENT_NODE_SZ);
dbg_msg("dead watermark: %d", c->dead_wm); dbg_msg("dead watermark: %d", c->dead_wm);
dbg_msg("dark watermark: %d", c->dark_wm); dbg_msg("dark watermark: %d", c->dark_wm);
dbg_msg("LEB overhead: %d", c->leb_overhead);
x = (long long)c->main_lebs * c->dark_wm; x = (long long)c->main_lebs * c->dark_wm;
dbg_msg("max. dark space: %lld (%lld KiB, %lld MiB)", dbg_msg("max. dark space: %lld (%lld KiB, %lld MiB)",
x, x >> 10, x >> 20); x, x >> 10, x >> 20);
@ -1320,14 +1410,12 @@ out_wbufs:
free_wbufs(c); free_wbufs(c);
out_cbuf: out_cbuf:
kfree(c->cbuf); kfree(c->cbuf);
out_dereg:
dbg_failure_mode_deregistration(c);
out_free: out_free:
kfree(c->bu.buf); kfree(c->bu.buf);
vfree(c->ileb_buf); vfree(c->ileb_buf);
vfree(c->sbuf); vfree(c->sbuf);
kfree(c->bottom_up_buf); kfree(c->bottom_up_buf);
UBIFS_DBG(vfree(c->dbg_buf)); ubifs_debugging_exit(c);
return err; return err;
} }
@ -1345,6 +1433,7 @@ static void ubifs_umount(struct ubifs_info *c)
dbg_gen("un-mounting UBI device %d, volume %d", c->vi.ubi_num, dbg_gen("un-mounting UBI device %d, volume %d", c->vi.ubi_num,
c->vi.vol_id); c->vi.vol_id);
dbg_debugfs_exit_fs(c);
spin_lock(&ubifs_infos_lock); spin_lock(&ubifs_infos_lock);
list_del(&c->infos_list); list_del(&c->infos_list);
spin_unlock(&ubifs_infos_lock); spin_unlock(&ubifs_infos_lock);
@ -1364,8 +1453,7 @@ static void ubifs_umount(struct ubifs_info *c)
vfree(c->ileb_buf); vfree(c->ileb_buf);
vfree(c->sbuf); vfree(c->sbuf);
kfree(c->bottom_up_buf); kfree(c->bottom_up_buf);
UBIFS_DBG(vfree(c->dbg_buf)); ubifs_debugging_exit(c);
dbg_failure_mode_deregistration(c);
} }
/** /**
@ -1387,12 +1475,9 @@ static int ubifs_remount_rw(struct ubifs_info *c)
c->remounting_rw = 1; c->remounting_rw = 1;
c->always_chk_crc = 1; c->always_chk_crc = 1;
/* Check for enough free space */ err = check_free_space(c);
if (ubifs_calc_available(c, c->min_idx_lebs) <= 0) { if (err)
ubifs_err("insufficient available space");
err = -EINVAL;
goto out; goto out;
}
if (c->old_leb_cnt != c->leb_cnt) { if (c->old_leb_cnt != c->leb_cnt) {
struct ubifs_sb_node *sup; struct ubifs_sb_node *sup;
@ -1515,20 +1600,24 @@ out:
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
* *
* This function is called during un-mounting and re-mounting, and it commits * 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 * the journal unless the "fast unmount" mode is enabled.
* committing the journal if it contains too few data.
*/ */
static void commit_on_unmount(struct ubifs_info *c) static void commit_on_unmount(struct ubifs_info *c)
{ {
if (!c->fast_unmount) { struct super_block *sb = c->vfs_sb;
long long bud_bytes; long long bud_bytes;
spin_lock(&c->buds_lock); /*
bud_bytes = c->bud_bytes; * This function is called before the background thread is stopped, so
spin_unlock(&c->buds_lock); * we may race with ongoing commit, which means we have to take
if (bud_bytes > c->leb_size) * @c->bud_lock to access @c->bud_bytes.
ubifs_run_commit(c); */
} spin_lock(&c->buds_lock);
bud_bytes = c->bud_bytes;
spin_unlock(&c->buds_lock);
if (!c->fast_unmount && !(sb->s_flags & MS_RDONLY) && bud_bytes)
ubifs_run_commit(c);
} }
/** /**
@ -1849,7 +1938,6 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
goto out_iput; goto out_iput;
mutex_unlock(&c->umount_mutex); mutex_unlock(&c->umount_mutex);
return 0; return 0;
out_iput: out_iput:
@ -1955,7 +2043,7 @@ static void ubifs_kill_sb(struct super_block *sb)
* We do 'commit_on_unmount()' here instead of 'ubifs_put_super()' * We do 'commit_on_unmount()' here instead of 'ubifs_put_super()'
* in order to be outside BKL. * in order to be outside BKL.
*/ */
if (sb->s_root && !(sb->s_flags & MS_RDONLY)) if (sb->s_root)
commit_on_unmount(c); commit_on_unmount(c);
/* The un-mount routine is actually done in put_super() */ /* The un-mount routine is actually done in put_super() */
generic_shutdown_super(sb); generic_shutdown_super(sb);
@ -2020,6 +2108,14 @@ static int __init ubifs_init(void)
BUILD_BUG_ON(UBIFS_INO_NODE_SZ != 160); BUILD_BUG_ON(UBIFS_INO_NODE_SZ != 160);
BUILD_BUG_ON(UBIFS_REF_NODE_SZ != 64); BUILD_BUG_ON(UBIFS_REF_NODE_SZ != 64);
/*
* We use 2 bit wide bit-fields to store compression type, which should
* be amended if more compressors are added. The bit-fields are:
* @compr_type in 'struct ubifs_inode', @default_compr in
* 'struct ubifs_info' and @compr_type in 'struct ubifs_mount_opts'.
*/
BUILD_BUG_ON(UBIFS_COMPR_TYPES_CNT > 4);
/* /*
* We require that PAGE_CACHE_SIZE is greater-than-or-equal-to * We require that PAGE_CACHE_SIZE is greater-than-or-equal-to
* UBIFS_BLOCK_SIZE. It is assumed that both are powers of 2. * UBIFS_BLOCK_SIZE. It is assumed that both are powers of 2.
@ -2048,12 +2144,18 @@ static int __init ubifs_init(void)
register_shrinker(&ubifs_shrinker_info); register_shrinker(&ubifs_shrinker_info);
err = ubifs_compressors_init(); err = ubifs_compressors_init();
if (err)
goto out_shrinker;
err = dbg_debugfs_init();
if (err) if (err)
goto out_compr; goto out_compr;
return 0; return 0;
out_compr: out_compr:
ubifs_compressors_exit();
out_shrinker:
unregister_shrinker(&ubifs_shrinker_info); unregister_shrinker(&ubifs_shrinker_info);
kmem_cache_destroy(ubifs_inode_slab); kmem_cache_destroy(ubifs_inode_slab);
out_reg: out_reg:
@ -2068,6 +2170,7 @@ static void __exit ubifs_exit(void)
ubifs_assert(list_empty(&ubifs_infos)); ubifs_assert(list_empty(&ubifs_infos));
ubifs_assert(atomic_long_read(&ubifs_clean_zn_cnt) == 0); ubifs_assert(atomic_long_read(&ubifs_clean_zn_cnt) == 0);
dbg_debugfs_exit();
ubifs_compressors_exit(); ubifs_compressors_exit();
unregister_shrinker(&ubifs_shrinker_info); unregister_shrinker(&ubifs_shrinker_info);
kmem_cache_destroy(ubifs_inode_slab); kmem_cache_destroy(ubifs_inode_slab);

View File

@ -2245,12 +2245,11 @@ int ubifs_tnc_replace(struct ubifs_info *c, const union ubifs_key *key,
if (found) { if (found) {
/* Ensure the znode is dirtied */ /* Ensure the znode is dirtied */
if (znode->cnext || !ubifs_zn_dirty(znode)) { if (znode->cnext || !ubifs_zn_dirty(znode)) {
znode = dirty_cow_bottom_up(c, znode = dirty_cow_bottom_up(c, znode);
znode); if (IS_ERR(znode)) {
if (IS_ERR(znode)) { err = PTR_ERR(znode);
err = PTR_ERR(znode); goto out_unlock;
goto out_unlock; }
}
} }
zbr = &znode->zbranch[n]; zbr = &znode->zbranch[n];
lnc_free(zbr); lnc_free(zbr);
@ -2317,11 +2316,11 @@ int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
/* Ensure the znode is dirtied */ /* Ensure the znode is dirtied */
if (znode->cnext || !ubifs_zn_dirty(znode)) { if (znode->cnext || !ubifs_zn_dirty(znode)) {
znode = dirty_cow_bottom_up(c, znode); znode = dirty_cow_bottom_up(c, znode);
if (IS_ERR(znode)) { if (IS_ERR(znode)) {
err = PTR_ERR(znode); err = PTR_ERR(znode);
goto out_unlock; goto out_unlock;
} }
} }
if (found == 1) { if (found == 1) {
@ -2627,11 +2626,11 @@ int ubifs_tnc_remove_range(struct ubifs_info *c, union ubifs_key *from_key,
/* Ensure the znode is dirtied */ /* Ensure the znode is dirtied */
if (znode->cnext || !ubifs_zn_dirty(znode)) { if (znode->cnext || !ubifs_zn_dirty(znode)) {
znode = dirty_cow_bottom_up(c, znode); znode = dirty_cow_bottom_up(c, znode);
if (IS_ERR(znode)) { if (IS_ERR(znode)) {
err = PTR_ERR(znode); err = PTR_ERR(znode);
goto out_unlock; goto out_unlock;
} }
} }
/* Remove all keys in range except the first */ /* Remove all keys in range except the first */

View File

@ -553,8 +553,8 @@ static int layout_in_empty_space(struct ubifs_info *c)
} }
#ifdef CONFIG_UBIFS_FS_DEBUG #ifdef CONFIG_UBIFS_FS_DEBUG
c->new_ihead_lnum = lnum; c->dbg->new_ihead_lnum = lnum;
c->new_ihead_offs = buf_offs; c->dbg->new_ihead_offs = buf_offs;
#endif #endif
return 0; return 0;
@ -802,8 +802,10 @@ int ubifs_tnc_start_commit(struct ubifs_info *c, struct ubifs_zbranch *zroot)
* budgeting subsystem to assume the index is already committed, * budgeting subsystem to assume the index is already committed,
* even though it is not. * even though it is not.
*/ */
ubifs_assert(c->min_idx_lebs == ubifs_calc_min_idx_lebs(c));
c->old_idx_sz = c->calc_idx_sz; c->old_idx_sz = c->calc_idx_sz;
c->budg_uncommitted_idx = 0; c->budg_uncommitted_idx = 0;
c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
spin_unlock(&c->space_lock); spin_unlock(&c->space_lock);
mutex_unlock(&c->tnc_mutex); mutex_unlock(&c->tnc_mutex);
@ -1002,7 +1004,8 @@ static int write_index(struct ubifs_info *c)
} }
#ifdef CONFIG_UBIFS_FS_DEBUG #ifdef CONFIG_UBIFS_FS_DEBUG
if (lnum != c->new_ihead_lnum || buf_offs != c->new_ihead_offs) { if (lnum != c->dbg->new_ihead_lnum ||
buf_offs != c->dbg->new_ihead_offs) {
ubifs_err("inconsistent ihead"); ubifs_err("inconsistent ihead");
return -EINVAL; return -EINVAL;
} }

View File

@ -51,6 +51,13 @@
*/ */
#define UBIFS_MIN_COMPR_LEN 128 #define UBIFS_MIN_COMPR_LEN 128
/*
* If compressed data length is less than %UBIFS_MIN_COMPRESS_DIFF bytes
* shorter than uncompressed data length, UBIFS preferes to leave this data
* node uncompress, because it'll be read faster.
*/
#define UBIFS_MIN_COMPRESS_DIFF 64
/* Root inode number */ /* Root inode number */
#define UBIFS_ROOT_INO 1 #define UBIFS_ROOT_INO 1

View File

@ -63,6 +63,14 @@
#define SQNUM_WARN_WATERMARK 0xFFFFFFFF00000000ULL #define SQNUM_WARN_WATERMARK 0xFFFFFFFF00000000ULL
#define SQNUM_WATERMARK 0xFFFFFFFFFF000000ULL #define SQNUM_WATERMARK 0xFFFFFFFFFF000000ULL
/*
* Minimum amount of LEBs reserved for the index. At present the index needs at
* least 2 LEBs: one for the index head and one for in-the-gaps method (which
* currently does not cater for the index head and so excludes it from
* consideration).
*/
#define MIN_INDEX_LEBS 2
/* Minimum amount of data UBIFS writes to the flash */ /* Minimum amount of data UBIFS writes to the flash */
#define MIN_WRITE_SZ (UBIFS_DATA_NODE_SZ + 8) #define MIN_WRITE_SZ (UBIFS_DATA_NODE_SZ + 8)
@ -386,12 +394,12 @@ struct ubifs_inode {
unsigned int dirty:1; unsigned int dirty:1;
unsigned int xattr:1; unsigned int xattr:1;
unsigned int bulk_read:1; unsigned int bulk_read:1;
unsigned int compr_type:2;
struct mutex ui_mutex; struct mutex ui_mutex;
spinlock_t ui_lock; spinlock_t ui_lock;
loff_t synced_i_size; loff_t synced_i_size;
loff_t ui_size; loff_t ui_size;
int flags; int flags;
int compr_type;
pgoff_t last_page_read; pgoff_t last_page_read;
pgoff_t read_in_a_row; pgoff_t read_in_a_row;
int data_len; int data_len;
@ -419,7 +427,7 @@ struct ubifs_unclean_leb {
* *
* LPROPS_UNCAT: not categorized * LPROPS_UNCAT: not categorized
* LPROPS_DIRTY: dirty > 0, not index * LPROPS_DIRTY: dirty > 0, not index
* LPROPS_DIRTY_IDX: dirty + free > UBIFS_CH_SZ and index * LPROPS_DIRTY_IDX: dirty + free > @c->min_idx_node_sze and index
* LPROPS_FREE: free > 0, not empty, not index * LPROPS_FREE: free > 0, not empty, not index
* LPROPS_HEAP_CNT: number of heaps used for storing categorized LEBs * LPROPS_HEAP_CNT: number of heaps used for storing categorized LEBs
* LPROPS_EMPTY: LEB is empty, not taken * LPROPS_EMPTY: LEB is empty, not taken
@ -473,8 +481,8 @@ struct ubifs_lprops {
struct ubifs_lpt_lprops { struct ubifs_lpt_lprops {
int free; int free;
int dirty; int dirty;
unsigned tgc : 1; unsigned tgc:1;
unsigned cmt : 1; unsigned cmt:1;
}; };
/** /**
@ -482,24 +490,26 @@ struct ubifs_lpt_lprops {
* @empty_lebs: number of empty LEBs * @empty_lebs: number of empty LEBs
* @taken_empty_lebs: number of taken LEBs * @taken_empty_lebs: number of taken LEBs
* @idx_lebs: number of indexing LEBs * @idx_lebs: number of indexing LEBs
* @total_free: total free space in bytes * @total_free: total free space in bytes (includes all LEBs)
* @total_dirty: total dirty space in bytes * @total_dirty: total dirty space in bytes (includes all LEBs)
* @total_used: total used space in bytes (includes only data LEBs) * @total_used: total used space in bytes (does not include index LEBs)
* @total_dead: total dead space in bytes (includes only data LEBs) * @total_dead: total dead space in bytes (does not include index LEBs)
* @total_dark: total dark space in bytes (includes only data LEBs) * @total_dark: total dark space in bytes (does not include index LEBs)
* *
* N.B. total_dirty and total_used are different to other total_* fields, * The @taken_empty_lebs field counts the LEBs that are in the transient state
* because they account _all_ LEBs, not just data LEBs. * of having been "taken" for use but not yet written to. @taken_empty_lebs is
* needed to account correctly for @gc_lnum, otherwise @empty_lebs could be
* used by itself (in which case 'unused_lebs' would be a better name). In the
* case of @gc_lnum, it is "taken" at mount time or whenever a LEB is retained
* by GC, but unlike other empty LEBs that are "taken", it may not be written
* straight away (i.e. before the next commit start or unmount), so either
* @gc_lnum must be specially accounted for, or the current approach followed
* i.e. count it under @taken_empty_lebs.
* *
* 'taken_empty_lebs' counts the LEBs that are in the transient state of having * @empty_lebs includes @taken_empty_lebs.
* been 'taken' for use but not yet written to. 'taken_empty_lebs' is needed *
* to account correctly for gc_lnum, otherwise 'empty_lebs' could be used * @total_used, @total_dead and @total_dark fields do not account indexing
* by itself (in which case 'unused_lebs' would be a better name). In the case * LEBs.
* of gc_lnum, it is 'taken' at mount time or whenever a LEB is retained by GC,
* but unlike other empty LEBs that are 'taken', it may not be written straight
* away (i.e. before the next commit start or unmount), so either gc_lnum must
* be specially accounted for, or the current approach followed i.e. count it
* under 'taken_empty_lebs'.
*/ */
struct ubifs_lp_stats { struct ubifs_lp_stats {
int empty_lebs; int empty_lebs;
@ -893,15 +903,25 @@ struct ubifs_orphan {
/** /**
* struct ubifs_mount_opts - UBIFS-specific mount options information. * struct ubifs_mount_opts - UBIFS-specific mount options information.
* @unmount_mode: selected unmount mode (%0 default, %1 normal, %2 fast) * @unmount_mode: selected unmount mode (%0 default, %1 normal, %2 fast)
* @bulk_read: enable bulk-reads * @bulk_read: enable/disable bulk-reads (%0 default, %1 disabe, %2 enable)
* @chk_data_crc: check CRCs when reading data nodes * @chk_data_crc: enable/disable CRC data checking when reading data nodes
* (%0 default, %1 disabe, %2 enable)
* @override_compr: override default compressor (%0 - do not override and use
* superblock compressor, %1 - override and use compressor
* specified in @compr_type)
* @compr_type: compressor type to override the superblock compressor with
* (%UBIFS_COMPR_NONE, etc)
*/ */
struct ubifs_mount_opts { struct ubifs_mount_opts {
unsigned int unmount_mode:2; unsigned int unmount_mode:2;
unsigned int bulk_read:2; unsigned int bulk_read:2;
unsigned int chk_data_crc:2; unsigned int chk_data_crc:2;
unsigned int override_compr:1;
unsigned int compr_type:2;
}; };
struct ubifs_debug_info;
/** /**
* struct ubifs_info - UBIFS file-system description data structure * struct ubifs_info - UBIFS file-system description data structure
* (per-superblock). * (per-superblock).
@ -946,6 +966,7 @@ struct ubifs_mount_opts {
* @no_chk_data_crc: do not check CRCs when reading data nodes (except during * @no_chk_data_crc: do not check CRCs when reading data nodes (except during
* recovery) * recovery)
* @bulk_read: enable bulk-reads * @bulk_read: enable bulk-reads
* @default_compr: default compression algorithm (%UBIFS_COMPR_LZO, etc)
* *
* @tnc_mutex: protects the Tree Node Cache (TNC), @zroot, @cnext, @enext, and * @tnc_mutex: protects the Tree Node Cache (TNC), @zroot, @cnext, @enext, and
* @calc_idx_sz * @calc_idx_sz
@ -963,8 +984,6 @@ struct ubifs_mount_opts {
* @ileb_nxt: next pre-allocated index LEBs * @ileb_nxt: next pre-allocated index LEBs
* @old_idx: tree of index nodes obsoleted since the last commit start * @old_idx: tree of index nodes obsoleted since the last commit start
* @bottom_up_buf: a buffer which is used by 'dirty_cow_bottom_up()' in tnc.c * @bottom_up_buf: a buffer which is used by 'dirty_cow_bottom_up()' in tnc.c
* @new_ihead_lnum: used by debugging to check ihead_lnum
* @new_ihead_offs: used by debugging to check ihead_offs
* *
* @mst_node: master node * @mst_node: master node
* @mst_offs: offset of valid master node * @mst_offs: offset of valid master node
@ -986,7 +1005,6 @@ struct ubifs_mount_opts {
* @main_lebs: count of LEBs in the main area * @main_lebs: count of LEBs in the main area
* @main_first: first LEB of the main area * @main_first: first LEB of the main area
* @main_bytes: main area size in bytes * @main_bytes: main area size in bytes
* @default_compr: default compression algorithm (%UBIFS_COMPR_LZO, etc)
* *
* @key_hash_type: type of the key hash * @key_hash_type: type of the key hash
* @key_hash: direntry key hash function * @key_hash: direntry key hash function
@ -1149,15 +1167,7 @@ struct ubifs_mount_opts {
* @always_chk_crc: always check CRCs (while mounting and remounting rw) * @always_chk_crc: always check CRCs (while mounting and remounting rw)
* @mount_opts: UBIFS-specific mount options * @mount_opts: UBIFS-specific mount options
* *
* @dbg_buf: a buffer of LEB size used for debugging purposes * @dbg: debugging-related information
* @old_zroot: old index root - used by 'dbg_check_old_index()'
* @old_zroot_level: old index root level - used by 'dbg_check_old_index()'
* @old_zroot_sqnum: old index root sqnum - used by 'dbg_check_old_index()'
* @failure_mode: failure mode for recovery testing
* @fail_delay: 0=>don't delay, 1=>delay a time, 2=>delay a number of calls
* @fail_timeout: time in jiffies when delay of failure mode expires
* @fail_cnt: current number of calls to failure mode I/O functions
* @fail_cnt_max: number of calls by which to delay failure mode
*/ */
struct ubifs_info { struct ubifs_info {
struct super_block *vfs_sb; struct super_block *vfs_sb;
@ -1196,6 +1206,7 @@ struct ubifs_info {
unsigned int big_lpt:1; unsigned int big_lpt:1;
unsigned int no_chk_data_crc:1; unsigned int no_chk_data_crc:1;
unsigned int bulk_read:1; unsigned int bulk_read:1;
unsigned int default_compr:2;
struct mutex tnc_mutex; struct mutex tnc_mutex;
struct ubifs_zbranch zroot; struct ubifs_zbranch zroot;
@ -1212,10 +1223,6 @@ struct ubifs_info {
int ileb_nxt; int ileb_nxt;
struct rb_root old_idx; struct rb_root old_idx;
int *bottom_up_buf; int *bottom_up_buf;
#ifdef CONFIG_UBIFS_FS_DEBUG
int new_ihead_lnum;
int new_ihead_offs;
#endif
struct ubifs_mst_node *mst_node; struct ubifs_mst_node *mst_node;
int mst_offs; int mst_offs;
@ -1237,7 +1244,6 @@ struct ubifs_info {
int main_lebs; int main_lebs;
int main_first; int main_first;
long long main_bytes; long long main_bytes;
int default_compr;
uint8_t key_hash_type; uint8_t key_hash_type;
uint32_t (*key_hash)(const char *str, int len); uint32_t (*key_hash)(const char *str, int len);
@ -1315,8 +1321,8 @@ struct ubifs_info {
void *sbuf; void *sbuf;
struct list_head idx_gc; struct list_head idx_gc;
int idx_gc_cnt; int idx_gc_cnt;
volatile int gc_seq; int gc_seq;
volatile int gced_lnum; int gced_lnum;
struct list_head infos_list; struct list_head infos_list;
struct mutex umount_mutex; struct mutex umount_mutex;
@ -1391,21 +1397,7 @@ struct ubifs_info {
struct ubifs_mount_opts mount_opts; struct ubifs_mount_opts mount_opts;
#ifdef CONFIG_UBIFS_FS_DEBUG #ifdef CONFIG_UBIFS_FS_DEBUG
void *dbg_buf; struct ubifs_debug_info *dbg;
struct ubifs_zbranch old_zroot;
int old_zroot_level;
unsigned long long old_zroot_sqnum;
int failure_mode;
int fail_delay;
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 #endif
}; };
@ -1505,7 +1497,7 @@ void ubifs_cancel_ino_op(struct ubifs_info *c, struct inode *inode,
long long ubifs_get_free_space(struct ubifs_info *c); long long ubifs_get_free_space(struct ubifs_info *c);
int ubifs_calc_min_idx_lebs(struct ubifs_info *c); int ubifs_calc_min_idx_lebs(struct ubifs_info *c);
void ubifs_convert_page_budget(struct ubifs_info *c); void ubifs_convert_page_budget(struct ubifs_info *c);
long long ubifs_reported_space(const struct ubifs_info *c, uint64_t free); long long ubifs_reported_space(const struct ubifs_info *c, long long free);
long long ubifs_calc_available(const struct ubifs_info *c, int min_idx_lebs); long long ubifs_calc_available(const struct ubifs_info *c, int min_idx_lebs);
/* find.c */ /* find.c */
@ -1639,6 +1631,9 @@ void ubifs_add_lpt_dirt(struct ubifs_info *c, int lnum, int dirty);
void ubifs_add_nnode_dirt(struct ubifs_info *c, struct ubifs_nnode *nnode); void ubifs_add_nnode_dirt(struct ubifs_info *c, struct ubifs_nnode *nnode);
uint32_t ubifs_unpack_bits(uint8_t **addr, int *pos, int nrbits); uint32_t ubifs_unpack_bits(uint8_t **addr, int *pos, int nrbits);
struct ubifs_nnode *ubifs_first_nnode(struct ubifs_info *c, int *hght); struct ubifs_nnode *ubifs_first_nnode(struct ubifs_info *c, int *hght);
/* Needed only in debugging code in lpt_commit.c */
int ubifs_unpack_nnode(const struct ubifs_info *c, void *buf,
struct ubifs_nnode *nnode);
/* lpt_commit.c */ /* lpt_commit.c */
int ubifs_lpt_start_commit(struct ubifs_info *c); int ubifs_lpt_start_commit(struct ubifs_info *c);
@ -1714,7 +1709,7 @@ long ubifs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
/* compressor.c */ /* compressor.c */
int __init ubifs_compressors_init(void); int __init ubifs_compressors_init(void);
void __exit ubifs_compressors_exit(void); void ubifs_compressors_exit(void);
void ubifs_compress(const void *in_buf, int in_len, void *out_buf, int *out_len, void ubifs_compress(const void *in_buf, int in_len, void *out_buf, int *out_len,
int *compr_type); int *compr_type);
int ubifs_decompress(const void *buf, int len, void *out, int *out_len, int ubifs_decompress(const void *buf, int len, void *out, int *out_len,