Skip to content

Commit

Permalink
Merge branch 'linux-next' of git://git.infradead.org/ubifs-2.6
Browse files Browse the repository at this point in the history
* 'linux-next' of git://git.infradead.org/ubifs-2.6: (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
  ...
  • Loading branch information
torvalds committed Jan 2, 2009
2 parents 574c3fd + 8e5033a commit 8e3bda0
Show file tree
Hide file tree
Showing 21 changed files with 927 additions and 474 deletions.
3 changes: 3 additions & 0 deletions Documentation/filesystems/ubifs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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 a file can go unnoticed.
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
Expand Down
208 changes: 69 additions & 139 deletions fs/ubifs/budget.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,49 +32,22 @@

#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
* back at when trying to shrink the liability.
*/
#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
Expand Down Expand Up @@ -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:
Expand All @@ -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;

/*
* 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;

spin_lock(&c->space_lock);
liability = c->budg_idx_growth + c->budg_data_growth +
c->budg_dd_growth;
spin_unlock(&c->space_lock);
int err, retries = 0;
long long liab1, liab2;

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);
}
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);

dbg_budg("force write-back (count %d)", ri->shrink_cnt);
shrink_liability(c, NR_TO_WRITE + ri->shrink_cnt);
liab2 = get_liability(c);
if (liab2 < liab1)
return -EAGAIN;

ri->prev_liability = liability;
ri->shrink_cnt += 1;
return -EAGAIN;
}
dbg_budg("new liability %lld (not shrinked)", liab2);

/*
* 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)
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)
if (err != -EAGAIN && err != -ENOSPC)
/* Some real error happened */
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;
}

Expand All @@ -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;

Expand All @@ -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;
}

/**
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -587,12 +522,17 @@ int ubifs_budget_space(struct ubifs_info *c, struct ubifs_budget_req *req)
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)
Expand Down Expand Up @@ -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
Expand All @@ -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;

Expand All @@ -737,16 +677,15 @@ 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;
factor = UBIFS_BLOCK_SIZE;
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);
}

/**
Expand All @@ -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.
Expand All @@ -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);

/*
Expand Down
Loading

0 comments on commit 8e3bda0

Please sign in to comment.