/** * make_free_space - make more free space on the file-system. * @c: UBIFS file-system description object * * 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: * o budgeting is pessimistic, so it always budgets more than it is actually * needed, so shrinking the liability is one way to make free space - the * cached data will take less space then it was budgeted for; * o GC may turn some dark space into free space (budgeting treats dark space * as not available); * o commit may free some LEB, i.e., turn freeable LEBs into free LEBs. * * So this function tries to do the above. Returns %-EAGAIN if some free space * was presumably made and the caller has to re-try budgeting the operation. * 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) { int err, retries = 0; long long liab1, liab2; 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); liab2 = get_liability(c); if (liab2 < liab1) return -EAGAIN; dbg_budg("new liability %lld (not shrunk)", liab2); /* Liability did not shrink again, try GC */ dbg_budg("Run GC"); err = run_gc(c); if (!err) return -EAGAIN; if (err != -EAGAIN && err != -ENOSPC) /* Some real error happened */ return err; dbg_budg("Run commit (retries %d)", retries); err = ubifs_run_commit(c); if (err) return err; } while (retries++ < MAX_MKSPC_RETRIES); return -ENOSPC; }
/** * 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: * o budgeting is pessimistic, so it always budgets more then it is actually * needed, so shrinking the liability is one way to make free space - the * cached data will take less space then it was budgeted for; * o GC may turn some dark space into free space (budgeting treats dark space * as not available); * o commit may free some LEB, i.e., turn freeable LEBs into free LEBs. * * So this function tries to do the above. Returns %-EAGAIN if some free space * was presumably made and the caller has to re-try budgeting the operation. * 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) { 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); 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("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; 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) 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); if (err) return err; return -EAGAIN; } return -ENOSPC; }