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 ...
This commit is contained in:
@@ -32,18 +32,15 @@
|
||||
|
||||
#include "ubifs.h"
|
||||
#include <linux/writeback.h>
|
||||
#include <asm/div64.h>
|
||||
#include <linux/math64.h>
|
||||
|
||||
/*
|
||||
* When pessimistic budget calculations say that there is no enough space,
|
||||
* 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.
|
||||
*/
|
||||
#define MAX_SHRINK_RETRIES 8
|
||||
#define MAX_GC_RETRIES 4
|
||||
#define MAX_CMT_RETRIES 2
|
||||
#define MAX_NOSPC_RETRIES 1
|
||||
#define MAX_MKSPC_RETRIES 3
|
||||
|
||||
/*
|
||||
* The below constant defines amount of dirty pages which should be written
|
||||
@@ -51,30 +48,6 @@
|
||||
*/
|
||||
#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.
|
||||
* @c: UBIFS file-system description object
|
||||
@@ -146,10 +119,26 @@ static int run_gc(struct ubifs_info *c)
|
||||
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.
|
||||
* @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
|
||||
* 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
|
||||
* 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;
|
||||
|
||||
/*
|
||||
* If we have some dirty pages and inodes (liability), try to write
|
||||
* them back unless this was tried too many times without effect
|
||||
* already.
|
||||
*/
|
||||
if (ri->shrink_retries < MAX_SHRINK_RETRIES && !ri->try_gc) {
|
||||
long long liability;
|
||||
do {
|
||||
liab1 = get_liability(c);
|
||||
/*
|
||||
* We probably have some dirty pages or inodes (liability), try
|
||||
* to write them back.
|
||||
*/
|
||||
dbg_budg("liability %lld, run write-back", liab1);
|
||||
shrink_liability(c, NR_TO_WRITE);
|
||||
|
||||
spin_lock(&c->space_lock);
|
||||
liability = c->budg_idx_growth + c->budg_data_growth +
|
||||
c->budg_dd_growth;
|
||||
spin_unlock(&c->space_lock);
|
||||
liab2 = get_liability(c);
|
||||
if (liab2 < liab1)
|
||||
return -EAGAIN;
|
||||
|
||||
if (ri->prev_liability >= liability) {
|
||||
/* 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("new liability %lld (not shrinked)", liab2);
|
||||
|
||||
dbg_budg("force write-back (count %d)", ri->shrink_cnt);
|
||||
shrink_liability(c, NR_TO_WRITE + ri->shrink_cnt);
|
||||
|
||||
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;
|
||||
/* Liability did not shrink again, try GC */
|
||||
dbg_budg("Run GC");
|
||||
err = run_gc(c);
|
||||
if (!err)
|
||||
return -EAGAIN;
|
||||
|
||||
if (err == -EAGAIN) {
|
||||
dbg_budg("GC asked to commit");
|
||||
err = ubifs_run_commit(c);
|
||||
if (err)
|
||||
return err;
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
if (err != -ENOSPC)
|
||||
if (err != -EAGAIN && err != -ENOSPC)
|
||||
/* Some real error happened */
|
||||
return err;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
dbg_budg("Run commit (retries %d)", retries);
|
||||
err = ubifs_run_commit(c);
|
||||
if (err)
|
||||
return err;
|
||||
return -EAGAIN;
|
||||
}
|
||||
} while (retries++ < MAX_MKSPC_RETRIES);
|
||||
|
||||
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 ret;
|
||||
uint64_t idx_size;
|
||||
int idx_lebs, eff_leb_size = c->leb_size - c->max_idx_node_sz;
|
||||
long long idx_size;
|
||||
|
||||
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
|
||||
* have to do this costly 64-bit division on fast-path.
|
||||
*/
|
||||
if (do_div(idx_size, c->leb_size - c->max_idx_node_sz))
|
||||
ret = idx_size + 1;
|
||||
else
|
||||
ret = idx_size;
|
||||
idx_size += eff_leb_size - 1;
|
||||
idx_lebs = div_u64(idx_size, eff_leb_size);
|
||||
/*
|
||||
* The index head is not available for the in-the-gaps method, so add an
|
||||
* extra LEB to compensate.
|
||||
*/
|
||||
ret += 1;
|
||||
/*
|
||||
* 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).
|
||||
*/
|
||||
if (ret < 2)
|
||||
ret = 2;
|
||||
return ret;
|
||||
idx_lebs += 1;
|
||||
if (idx_lebs < MIN_INDEX_LEBS)
|
||||
idx_lebs = MIN_INDEX_LEBS;
|
||||
return idx_lebs;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -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 uninitialized_var(cmt_retries), uninitialized_var(wb_retries);
|
||||
int err, idx_growth, data_growth, dd_growth;
|
||||
struct retries_info ri;
|
||||
int err, idx_growth, data_growth, dd_growth, retried = 0;
|
||||
|
||||
ubifs_assert(req->new_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)
|
||||
return 0;
|
||||
idx_growth = calc_idx_growth(c, req);
|
||||
memset(&ri, 0, sizeof(struct retries_info));
|
||||
|
||||
again:
|
||||
spin_lock(&c->space_lock);
|
||||
@@ -587,12 +522,17 @@ again:
|
||||
return err;
|
||||
}
|
||||
|
||||
err = make_free_space(c, &ri);
|
||||
err = make_free_space(c);
|
||||
cond_resched();
|
||||
if (err == -EAGAIN) {
|
||||
dbg_budg("try again");
|
||||
cond_resched();
|
||||
goto again;
|
||||
} else if (err == -ENOSPC) {
|
||||
if (!retried) {
|
||||
retried = 1;
|
||||
dbg_budg("-ENOSPC, but anyway try once again");
|
||||
goto again;
|
||||
}
|
||||
dbg_budg("FS is full, -ENOSPC");
|
||||
c->nospace = 1;
|
||||
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
|
||||
* (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
|
||||
* node and it has to write indexind nodes as well. This introduces additional
|
||||
* overhead, and UBIFS it has to report sligtly less free space to meet the
|
||||
* above expectetion.
|
||||
* node and it has to write indexing nodes as well. This introduces additional
|
||||
* overhead, and UBIFS has to report slightly less free space to meet the above
|
||||
* expectations.
|
||||
*
|
||||
* 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
|
||||
@@ -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
|
||||
* 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;
|
||||
|
||||
@@ -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
|
||||
* as less than maximum fanout, we assume that each data node
|
||||
* 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.
|
||||
*/
|
||||
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 += (c->max_idx_node_sz * 3) / (f - 1);
|
||||
free *= factor;
|
||||
do_div(free, divisor);
|
||||
return free;
|
||||
return div_u64(free, divisor);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -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.
|
||||
*
|
||||
* 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
|
||||
* reclamable, 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
|
||||
* reclaimable, UBIFS does not actually know the real amount). If UBIFS did so,
|
||||
* 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,
|
||||
* 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.
|
||||
@@ -771,18 +710,9 @@ long long ubifs_get_free_space(struct ubifs_info *c)
|
||||
long long available, outstanding, free;
|
||||
|
||||
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;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user