summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-08-15 10:33:07 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2008-08-15 10:33:07 -0700
commit21d3bdb1606311a2900eabccfcb5a887952e2c44 (patch)
treee4aebcff13178d18dc86e5ac760ac5f209243322 /fs
parent3141eb6c50f1dafa99874e702d8b444034e2bb10 (diff)
parentc78c7e35a4709b55d3126624662c8f6d7e3d1a5e (diff)
Merge branch 'linux-next' of git://git.infradead.org/~dedekind/ubifs-2.6
* 'linux-next' of git://git.infradead.org/~dedekind/ubifs-2.6: (29 commits) UBIFS: xattr bugfixes UBIFS: remove unneeded check UBIFS: few commentary fixes UBIFS: fix budgeting request alignment in xattr code UBIFS: improve arguments checking in debugging messages UBIFS: always set i_generation to 0 UBIFS: correct spelling of "thrice". UBIFS: support splice_write UBIFS: minor tweaks in commit UBIFS: reserve more space for index UBIFS: print pid in dump function UBIFS: align inode data to eight UBIFS: improve budgeting checks UBIFS: correct orphan deletion order UBIFS: fix typos in comments UBIFS: do not union creat_sqnum and del_cmtno UBIFS: optimize deletions UBIFS: increment commit number earlier UBIFS: remove another unneeded function parameter UBIFS: remove unneeded function parameter ...
Diffstat (limited to 'fs')
-rw-r--r--fs/ubifs/budget.c33
-rw-r--r--fs/ubifs/commit.c3
-rw-r--r--fs/ubifs/debug.c27
-rw-r--r--fs/ubifs/debug.h143
-rw-r--r--fs/ubifs/dir.c24
-rw-r--r--fs/ubifs/file.c8
-rw-r--r--fs/ubifs/find.c9
-rw-r--r--fs/ubifs/io.c14
-rw-r--r--fs/ubifs/journal.c110
-rw-r--r--fs/ubifs/log.c4
-rw-r--r--fs/ubifs/misc.h16
-rw-r--r--fs/ubifs/orphan.c4
-rw-r--r--fs/ubifs/super.c48
-rw-r--r--fs/ubifs/tnc_commit.c37
-rw-r--r--fs/ubifs/ubifs-media.h4
-rw-r--r--fs/ubifs/ubifs.h33
-rw-r--r--fs/ubifs/xattr.c54
17 files changed, 328 insertions, 243 deletions
diff --git a/fs/ubifs/budget.c b/fs/ubifs/budget.c
index d81fb9ed2b8e..154098157473 100644
--- a/fs/ubifs/budget.c
+++ b/fs/ubifs/budget.c
@@ -263,8 +263,8 @@ int ubifs_calc_min_idx_lebs(struct ubifs_info *c)
idx_size = c->old_idx_sz + c->budg_idx_growth + c->budg_uncommitted_idx;
- /* And make sure we have twice the index size of space reserved */
- idx_size <<= 1;
+ /* And make sure we have thrice the index size of space reserved */
+ idx_size = idx_size + (idx_size << 1);
/*
* We do not maintain 'old_idx_size' as 'old_idx_lebs'/'old_idx_bytes'
@@ -388,11 +388,11 @@ static int can_use_rp(struct ubifs_info *c)
* This function makes sure UBIFS has enough free eraseblocks for index growth
* and data.
*
- * When budgeting index space, UBIFS reserves twice as more LEBs as the index
+ * When budgeting index space, UBIFS reserves thrice as many LEBs as the index
* would take if it was consolidated and written to the flash. This guarantees
* that the "in-the-gaps" commit method always succeeds and UBIFS will always
* be able to commit dirty index. So this function basically adds amount of
- * budgeted index space to the size of the current index, multiplies this by 2,
+ * budgeted index space to the size of the current index, multiplies this by 3,
* and makes sure this does not exceed the amount of free eraseblocks.
*
* Notes about @c->min_idx_lebs and @c->lst.idx_lebs variables:
@@ -543,8 +543,16 @@ int ubifs_budget_space(struct ubifs_info *c, struct ubifs_budget_req *req)
int err, idx_growth, data_growth, dd_growth;
struct retries_info ri;
+ ubifs_assert(req->new_page <= 1);
+ ubifs_assert(req->dirtied_page <= 1);
+ ubifs_assert(req->new_dent <= 1);
+ ubifs_assert(req->mod_dent <= 1);
+ ubifs_assert(req->new_ino <= 1);
+ ubifs_assert(req->new_ino_d <= UBIFS_MAX_INO_DATA);
ubifs_assert(req->dirtied_ino <= 4);
ubifs_assert(req->dirtied_ino_d <= UBIFS_MAX_INO_DATA * 4);
+ ubifs_assert(!(req->new_ino_d & 7));
+ ubifs_assert(!(req->dirtied_ino_d & 7));
data_growth = calc_data_growth(c, req);
dd_growth = calc_dd_growth(c, req);
@@ -618,8 +626,16 @@ again:
*/
void ubifs_release_budget(struct ubifs_info *c, struct ubifs_budget_req *req)
{
+ ubifs_assert(req->new_page <= 1);
+ ubifs_assert(req->dirtied_page <= 1);
+ ubifs_assert(req->new_dent <= 1);
+ ubifs_assert(req->mod_dent <= 1);
+ ubifs_assert(req->new_ino <= 1);
+ ubifs_assert(req->new_ino_d <= UBIFS_MAX_INO_DATA);
ubifs_assert(req->dirtied_ino <= 4);
ubifs_assert(req->dirtied_ino_d <= UBIFS_MAX_INO_DATA * 4);
+ ubifs_assert(!(req->new_ino_d & 7));
+ ubifs_assert(!(req->dirtied_ino_d & 7));
if (!req->recalculate) {
ubifs_assert(req->idx_growth >= 0);
ubifs_assert(req->data_growth >= 0);
@@ -647,7 +663,11 @@ void ubifs_release_budget(struct ubifs_info *c, struct ubifs_budget_req *req)
ubifs_assert(c->budg_idx_growth >= 0);
ubifs_assert(c->budg_data_growth >= 0);
+ ubifs_assert(c->budg_dd_growth >= 0);
ubifs_assert(c->min_idx_lebs < c->main_lebs);
+ ubifs_assert(!(c->budg_idx_growth & 7));
+ ubifs_assert(!(c->budg_data_growth & 7));
+ ubifs_assert(!(c->budg_dd_growth & 7));
spin_unlock(&c->space_lock);
}
@@ -686,9 +706,10 @@ void ubifs_convert_page_budget(struct ubifs_info *c)
void ubifs_release_dirty_inode_budget(struct ubifs_info *c,
struct ubifs_inode *ui)
{
- struct ubifs_budget_req req = {.dd_growth = c->inode_budget,
- .dirtied_ino_d = ui->data_len};
+ struct ubifs_budget_req req;
+ memset(&req, 0, sizeof(struct ubifs_budget_req));
+ req.dd_growth = c->inode_budget + ALIGN(ui->data_len, 8);
ubifs_release_budget(c, &req);
}
diff --git a/fs/ubifs/commit.c b/fs/ubifs/commit.c
index 3b516316c9b3..0a6aa2cc78f0 100644
--- a/fs/ubifs/commit.c
+++ b/fs/ubifs/commit.c
@@ -74,6 +74,7 @@ static int do_commit(struct ubifs_info *c)
goto out_up;
}
+ c->cmt_no += 1;
err = ubifs_gc_start_commit(c);
if (err)
goto out_up;
@@ -115,7 +116,7 @@ static int do_commit(struct ubifs_info *c)
goto out;
mutex_lock(&c->mst_mutex);
- c->mst_node->cmt_no = cpu_to_le64(++c->cmt_no);
+ c->mst_node->cmt_no = cpu_to_le64(c->cmt_no);
c->mst_node->log_lnum = cpu_to_le32(new_ltail_lnum);
c->mst_node->root_lnum = cpu_to_le32(zroot.lnum);
c->mst_node->root_offs = cpu_to_le32(zroot.offs);
diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c
index 4e3aaeba4eca..b9cb77473758 100644
--- a/fs/ubifs/debug.c
+++ b/fs/ubifs/debug.c
@@ -568,8 +568,8 @@ void dbg_dump_budget_req(const struct ubifs_budget_req *req)
void dbg_dump_lstats(const struct ubifs_lp_stats *lst)
{
spin_lock(&dbg_lock);
- printk(KERN_DEBUG "Lprops statistics: empty_lebs %d, idx_lebs %d\n",
- lst->empty_lebs, lst->idx_lebs);
+ printk(KERN_DEBUG "(pid %d) Lprops statistics: empty_lebs %d, "
+ "idx_lebs %d\n", current->pid, lst->empty_lebs, lst->idx_lebs);
printk(KERN_DEBUG "\ttaken_empty_lebs %d, total_free %lld, "
"total_dirty %lld\n", lst->taken_empty_lebs, lst->total_free,
lst->total_dirty);
@@ -587,8 +587,8 @@ void dbg_dump_budg(struct ubifs_info *c)
struct ubifs_gced_idx_leb *idx_gc;
spin_lock(&dbg_lock);
- printk(KERN_DEBUG "Budgeting info: budg_data_growth %lld, "
- "budg_dd_growth %lld, budg_idx_growth %lld\n",
+ printk(KERN_DEBUG "(pid %d) Budgeting info: budg_data_growth %lld, "
+ "budg_dd_growth %lld, budg_idx_growth %lld\n", current->pid,
c->budg_data_growth, c->budg_dd_growth, c->budg_idx_growth);
printk(KERN_DEBUG "\tdata budget sum %lld, total budget sum %lld, "
"freeable_cnt %d\n", c->budg_data_growth + c->budg_dd_growth,
@@ -634,7 +634,7 @@ void dbg_dump_lprops(struct ubifs_info *c)
struct ubifs_lprops lp;
struct ubifs_lp_stats lst;
- printk(KERN_DEBUG "Dumping LEB properties\n");
+ printk(KERN_DEBUG "(pid %d) Dumping LEB properties\n", current->pid);
ubifs_get_lp_stats(c, &lst);
dbg_dump_lstats(&lst);
@@ -655,7 +655,7 @@ void dbg_dump_leb(const struct ubifs_info *c, int lnum)
if (dbg_failure_mode)
return;
- printk(KERN_DEBUG "Dumping LEB %d\n", lnum);
+ printk(KERN_DEBUG "(pid %d) Dumping LEB %d\n", current->pid, lnum);
sleb = ubifs_scan(c, lnum, 0, c->dbg_buf);
if (IS_ERR(sleb)) {
@@ -720,8 +720,8 @@ void dbg_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat)
{
int i;
- printk(KERN_DEBUG "Dumping heap cat %d (%d elements)\n",
- cat, heap->cnt);
+ printk(KERN_DEBUG "(pid %d) Dumping heap cat %d (%d elements)\n",
+ current->pid, cat, heap->cnt);
for (i = 0; i < heap->cnt; i++) {
struct ubifs_lprops *lprops = heap->arr[i];
@@ -736,7 +736,7 @@ void dbg_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
{
int i;
- printk(KERN_DEBUG "Dumping pnode:\n");
+ printk(KERN_DEBUG "(pid %d) Dumping pnode:\n", current->pid);
printk(KERN_DEBUG "\taddress %zx parent %zx cnext %zx\n",
(size_t)pnode, (size_t)parent, (size_t)pnode->cnext);
printk(KERN_DEBUG "\tflags %lu iip %d level %d num %d\n",
@@ -755,7 +755,7 @@ void dbg_dump_tnc(struct ubifs_info *c)
int level;
printk(KERN_DEBUG "\n");
- printk(KERN_DEBUG "Dumping the TNC tree\n");
+ printk(KERN_DEBUG "(pid %d) Dumping the TNC tree\n", current->pid);
znode = ubifs_tnc_levelorder_next(c->zroot.znode, NULL);
level = znode->level;
printk(KERN_DEBUG "== Level %d ==\n", level);
@@ -2208,16 +2208,17 @@ int dbg_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
int dbg_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
int offset, int len, int dtype)
{
- int err;
+ int err, failing;
if (in_failure_mode(desc))
return -EIO;
- if (do_fail(desc, lnum, 1))
+ failing = do_fail(desc, lnum, 1);
+ if (failing)
cut_data(buf, len);
err = ubi_leb_write(desc, lnum, buf, offset, len, dtype);
if (err)
return err;
- if (in_failure_mode(desc))
+ if (failing)
return -EIO;
return 0;
}
diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h
index 3c4f1e93c9e0..50315fc57185 100644
--- a/fs/ubifs/debug.h
+++ b/fs/ubifs/debug.h
@@ -27,7 +27,7 @@
#define UBIFS_DBG(op) op
-#define ubifs_assert(expr) do { \
+#define ubifs_assert(expr) do { \
if (unlikely(!(expr))) { \
printk(KERN_CRIT "UBIFS assert failed in %s at %u (pid %d)\n", \
__func__, __LINE__, current->pid); \
@@ -73,50 +73,50 @@ const char *dbg_key_str1(const struct ubifs_info *c,
const union ubifs_key *key);
/*
- * DBGKEY macros require dbg_lock to be held, which it is in the dbg message
+ * DBGKEY macros require @dbg_lock to be held, which it is in the dbg message
* macros.
*/
#define DBGKEY(key) dbg_key_str0(c, (key))
#define DBGKEY1(key) dbg_key_str1(c, (key))
/* General messages */
-#define dbg_gen(fmt, ...) dbg_do_msg(UBIFS_MSG_GEN, fmt, ##__VA_ARGS__)
+#define dbg_gen(fmt, ...) dbg_do_msg(UBIFS_MSG_GEN, fmt, ##__VA_ARGS__)
/* Additional journal messages */
-#define dbg_jnl(fmt, ...) dbg_do_msg(UBIFS_MSG_JNL, fmt, ##__VA_ARGS__)
+#define dbg_jnl(fmt, ...) dbg_do_msg(UBIFS_MSG_JNL, fmt, ##__VA_ARGS__)
/* Additional TNC messages */
-#define dbg_tnc(fmt, ...) dbg_do_msg(UBIFS_MSG_TNC, fmt, ##__VA_ARGS__)
+#define dbg_tnc(fmt, ...) dbg_do_msg(UBIFS_MSG_TNC, fmt, ##__VA_ARGS__)
/* Additional lprops messages */
-#define dbg_lp(fmt, ...) dbg_do_msg(UBIFS_MSG_LP, fmt, ##__VA_ARGS__)
+#define dbg_lp(fmt, ...) dbg_do_msg(UBIFS_MSG_LP, fmt, ##__VA_ARGS__)
/* Additional LEB find messages */
-#define dbg_find(fmt, ...) dbg_do_msg(UBIFS_MSG_FIND, fmt, ##__VA_ARGS__)
+#define dbg_find(fmt, ...) dbg_do_msg(UBIFS_MSG_FIND, fmt, ##__VA_ARGS__)
/* Additional mount messages */
-#define dbg_mnt(fmt, ...) dbg_do_msg(UBIFS_MSG_MNT, fmt, ##__VA_ARGS__)
+#define dbg_mnt(fmt, ...) dbg_do_msg(UBIFS_MSG_MNT, fmt, ##__VA_ARGS__)
/* Additional I/O messages */
-#define dbg_io(fmt, ...) dbg_do_msg(UBIFS_MSG_IO, fmt, ##__VA_ARGS__)
+#define dbg_io(fmt, ...) dbg_do_msg(UBIFS_MSG_IO, fmt, ##__VA_ARGS__)
/* Additional commit messages */
-#define dbg_cmt(fmt, ...) dbg_do_msg(UBIFS_MSG_CMT, fmt, ##__VA_ARGS__)
+#define dbg_cmt(fmt, ...) dbg_do_msg(UBIFS_MSG_CMT, fmt, ##__VA_ARGS__)
/* Additional budgeting messages */
-#define dbg_budg(fmt, ...) dbg_do_msg(UBIFS_MSG_BUDG, fmt, ##__VA_ARGS__)
+#define dbg_budg(fmt, ...) dbg_do_msg(UBIFS_MSG_BUDG, fmt, ##__VA_ARGS__)
/* Additional log messages */
-#define dbg_log(fmt, ...) dbg_do_msg(UBIFS_MSG_LOG, fmt, ##__VA_ARGS__)
+#define dbg_log(fmt, ...) dbg_do_msg(UBIFS_MSG_LOG, fmt, ##__VA_ARGS__)
/* Additional gc messages */
-#define dbg_gc(fmt, ...) dbg_do_msg(UBIFS_MSG_GC, fmt, ##__VA_ARGS__)
+#define dbg_gc(fmt, ...) dbg_do_msg(UBIFS_MSG_GC, fmt, ##__VA_ARGS__)
/* Additional scan messages */
-#define dbg_scan(fmt, ...) dbg_do_msg(UBIFS_MSG_SCAN, fmt, ##__VA_ARGS__)
+#define dbg_scan(fmt, ...) dbg_do_msg(UBIFS_MSG_SCAN, fmt, ##__VA_ARGS__)
/* Additional recovery messages */
-#define dbg_rcvry(fmt, ...) dbg_do_msg(UBIFS_MSG_RCVRY, fmt, ##__VA_ARGS__)
+#define dbg_rcvry(fmt, ...) dbg_do_msg(UBIFS_MSG_RCVRY, fmt, ##__VA_ARGS__)
/*
* Debugging message type flags (must match msg_type_names in debug.c).
@@ -239,34 +239,23 @@ typedef int (*dbg_leaf_callback)(struct ubifs_info *c,
struct ubifs_zbranch *zbr, void *priv);
typedef int (*dbg_znode_callback)(struct ubifs_info *c,
struct ubifs_znode *znode, void *priv);
-
int dbg_walk_index(struct ubifs_info *c, dbg_leaf_callback leaf_cb,
dbg_znode_callback znode_cb, void *priv);
/* Checking functions */
int dbg_check_lprops(struct ubifs_info *c);
-
int dbg_old_index_check_init(struct ubifs_info *c, struct ubifs_zbranch *zroot);
int dbg_check_old_index(struct ubifs_info *c, struct ubifs_zbranch *zroot);
-
int dbg_check_cats(struct ubifs_info *c);
-
int dbg_check_ltab(struct ubifs_info *c);
-
int dbg_check_synced_i_size(struct inode *inode);
-
int dbg_check_dir_size(struct ubifs_info *c, const struct inode *dir);
-
int dbg_check_tnc(struct ubifs_info *c, int extra);
-
int dbg_check_idx_size(struct ubifs_info *c, long long idx_size);
-
int dbg_check_filesystem(struct ubifs_info *c);
-
void dbg_check_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat,
int add_pos);
-
int dbg_check_lprops(struct ubifs_info *c);
int dbg_check_lpt_nodes(struct ubifs_info *c, struct ubifs_cnode *cnode,
int row, int col);
@@ -329,71 +318,77 @@ static inline int dbg_change(struct ubi_volume_desc *desc, int lnum,
#else /* !CONFIG_UBIFS_FS_DEBUG */
#define UBIFS_DBG(op)
-#define ubifs_assert(expr) ({})
-#define ubifs_assert_cmt_locked(c)
+
+/* Use "if (0)" to make compiler check arguments even if debugging is off */
+#define ubifs_assert(expr) do { \
+ if (0 && (expr)) \
+ printk(KERN_CRIT "UBIFS assert failed in %s at %u (pid %d)\n", \
+ __func__, __LINE__, current->pid); \
+} while (0)
+
+#define dbg_err(fmt, ...) do { \
+ if (0) \
+ ubifs_err(fmt, ##__VA_ARGS__); \
+} while (0)
+
+#define dbg_msg(fmt, ...) do { \
+ if (0) \
+ printk(KERN_DEBUG "UBIFS DBG (pid %d): %s: " fmt "\n", \
+ current->pid, __func__, ##__VA_ARGS__); \
+} while (0)
+
#define dbg_dump_stack()
-#define dbg_err(fmt, ...) ({})
-#define dbg_msg(fmt, ...) ({})
-#define dbg_key(c, key, fmt, ...) ({})
-
-#define dbg_gen(fmt, ...) ({})
-#define dbg_jnl(fmt, ...) ({})
-#define dbg_tnc(fmt, ...) ({})
-#define dbg_lp(fmt, ...) ({})
-#define dbg_find(fmt, ...) ({})
-#define dbg_mnt(fmt, ...) ({})
-#define dbg_io(fmt, ...) ({})
-#define dbg_cmt(fmt, ...) ({})
-#define dbg_budg(fmt, ...) ({})
-#define dbg_log(fmt, ...) ({})
-#define dbg_gc(fmt, ...) ({})
-#define dbg_scan(fmt, ...) ({})
-#define dbg_rcvry(fmt, ...) ({})
-
-#define dbg_ntype(type) ""
-#define dbg_cstate(cmt_state) ""
-#define dbg_get_key_dump(c, key) ({})
-#define dbg_dump_inode(c, inode) ({})
-#define dbg_dump_node(c, node) ({})
-#define dbg_dump_budget_req(req) ({})
-#define dbg_dump_lstats(lst) ({})
-#define dbg_dump_budg(c) ({})
-#define dbg_dump_lprop(c, lp) ({})
-#define dbg_dump_lprops(c) ({})
-#define dbg_dump_leb(c, lnum) ({})
-#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 ubifs_assert_cmt_locked(c)
-#define dbg_walk_index(c, leaf_cb, znode_cb, priv) 0
+#define dbg_gen(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_jnl(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_tnc(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_lp(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_find(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_mnt(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_io(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_cmt(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_budg(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_log(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_gc(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_scan(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_rcvry(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+
+#define DBGKEY(key) ((char *)(key))
+#define DBGKEY1(key) ((char *)(key))
+
+#define dbg_ntype(type) ""
+#define dbg_cstate(cmt_state) ""
+#define dbg_get_key_dump(c, key) ({})
+#define dbg_dump_inode(c, inode) ({})
+#define dbg_dump_node(c, node) ({})
+#define dbg_dump_budget_req(req) ({})
+#define dbg_dump_lstats(lst) ({})
+#define dbg_dump_budg(c) ({})
+#define dbg_dump_lprop(c, lp) ({})
+#define dbg_dump_lprops(c) ({})
+#define dbg_dump_leb(c, lnum) ({})
+#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_walk_index(c, leaf_cb, znode_cb, priv) 0
#define dbg_old_index_check_init(c, zroot) 0
#define dbg_check_old_index(c, zroot) 0
-
#define dbg_check_cats(c) 0
-
#define dbg_check_ltab(c) 0
-
#define dbg_check_synced_i_size(inode) 0
-
#define dbg_check_dir_size(c, dir) 0
-
#define dbg_check_tnc(c, x) 0
-
#define dbg_check_idx_size(c, idx_size) 0
-
#define dbg_check_filesystem(c) 0
-
#define dbg_check_heap(c, heap, cat, add_pos) ({})
-
#define dbg_check_lprops(c) 0
#define dbg_check_lpt_nodes(c, cnode, row, col) 0
-
#define dbg_force_in_the_gaps_enabled 0
#define dbg_force_in_the_gaps() 0
-
#define dbg_failure_mode 0
#define dbg_failure_mode_registration(c) ({})
#define dbg_failure_mode_deregistration(c) ({})
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index e90374be7d3b..5c96f1fb7016 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -165,7 +165,6 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
}
inode->i_ino = ++c->highest_inum;
- inode->i_generation = ++c->vfs_gen;
/*
* The creation sequence number remains with this inode for its
* lifetime. All nodes for this inode have a greater sequence number,
@@ -220,15 +219,7 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
err = ubifs_tnc_lookup_nm(c, &key, dent, &dentry->d_name);
if (err) {
- /*
- * Do not hash the direntry if parent 'i_nlink' is zero, because
- * this has side-effects - '->delete_inode()' call will not be
- * called for the parent orphan inode, because 'd_count' of its
- * direntry will stay 1 (it'll be negative direntry I guess)
- * and prevent 'iput_final()' until the dentry is destroyed due
- * to unmount or memory pressure.
- */
- if (err == -ENOENT && dir->i_nlink != 0) {
+ if (err == -ENOENT) {
dbg_gen("not found");
goto done;
}
@@ -525,7 +516,7 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir,
struct ubifs_inode *dir_ui = ubifs_inode(dir);
int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len);
struct ubifs_budget_req req = { .new_dent = 1, .dirtied_ino = 2,
- .dirtied_ino_d = ui->data_len };
+ .dirtied_ino_d = ALIGN(ui->data_len, 8) };
/*
* Budget request settings: new direntry, changing the target inode,
@@ -727,8 +718,7 @@ static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
struct ubifs_inode *dir_ui = ubifs_inode(dir);
struct ubifs_info *c = dir->i_sb->s_fs_info;
int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len);
- struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
- .dirtied_ino_d = 1 };
+ struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1 };
/*
* Budget request settings: new inode, new direntry and changing parent
@@ -789,7 +779,8 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry,
int sz_change = CALC_DENT_SIZE(dentry->d_name.len);
int err, devlen = 0;
struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
- .new_ino_d = devlen, .dirtied_ino = 1 };
+ .new_ino_d = ALIGN(devlen, 8),
+ .dirtied_ino = 1 };
/*
* Budget request settings: new inode, new direntry and changing parent
@@ -863,7 +854,8 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry,
int err, len = strlen(symname);
int sz_change = CALC_DENT_SIZE(dentry->d_name.len);
struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
- .new_ino_d = len, .dirtied_ino = 1 };
+ .new_ino_d = ALIGN(len, 8),
+ .dirtied_ino = 1 };
/*
* Budget request settings: new inode, new direntry and changing parent
@@ -1012,7 +1004,7 @@ static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct ubifs_budget_req req = { .new_dent = 1, .mod_dent = 1,
.dirtied_ino = 3 };
struct ubifs_budget_req ino_req = { .dirtied_ino = 1,
- .dirtied_ino_d = old_inode_ui->data_len };
+ .dirtied_ino_d = ALIGN(old_inode_ui->data_len, 8) };
struct timespec time;
/*
diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
index 8565e586e533..4071d1cae29f 100644
--- a/fs/ubifs/file.c
+++ b/fs/ubifs/file.c
@@ -890,7 +890,7 @@ static int do_setattr(struct ubifs_info *c, struct inode *inode,
loff_t new_size = attr->ia_size;
struct ubifs_inode *ui = ubifs_inode(inode);
struct ubifs_budget_req req = { .dirtied_ino = 1,
- .dirtied_ino_d = ui->data_len };
+ .dirtied_ino_d = ALIGN(ui->data_len, 8) };
err = ubifs_budget_space(c, &req);
if (err)
@@ -941,7 +941,8 @@ int ubifs_setattr(struct dentry *dentry, struct iattr *attr)
struct inode *inode = dentry->d_inode;
struct ubifs_info *c = inode->i_sb->s_fs_info;
- dbg_gen("ino %lu, ia_valid %#x", inode->i_ino, attr->ia_valid);
+ dbg_gen("ino %lu, mode %#x, ia_valid %#x",
+ inode->i_ino, inode->i_mode, attr->ia_valid);
err = inode_change_ok(inode, attr);
if (err)
return err;
@@ -1051,7 +1052,7 @@ static int update_mctime(struct ubifs_info *c, struct inode *inode)
if (mctime_update_needed(inode, &now)) {
int err, release;
struct ubifs_budget_req req = { .dirtied_ino = 1,
- .dirtied_ino_d = ui->data_len };
+ .dirtied_ino_d = ALIGN(ui->data_len, 8) };
err = ubifs_budget_space(c, &req);
if (err)
@@ -1270,6 +1271,7 @@ struct file_operations ubifs_file_operations = {
.fsync = ubifs_fsync,
.unlocked_ioctl = ubifs_ioctl,
.splice_read = generic_file_splice_read,
+ .splice_write = generic_file_splice_write,
#ifdef CONFIG_COMPAT
.compat_ioctl = ubifs_compat_ioctl,
#endif
diff --git a/fs/ubifs/find.c b/fs/ubifs/find.c
index 10394c548367..adee7b5ddeab 100644
--- a/fs/ubifs/find.c
+++ b/fs/ubifs/find.c
@@ -290,9 +290,14 @@ int ubifs_find_dirty_leb(struct ubifs_info *c, struct ubifs_lprops *ret_lp,
idx_lp = idx_heap->arr[0];
sum = idx_lp->free + idx_lp->dirty;
/*
- * Since we reserve twice as more space for the index than it
+ * Since we reserve thrice as much space for the index than it
* actually takes, it does not make sense to pick indexing LEBs
- * with less than half LEB of dirty space.
+ * with less than, say, half LEB of dirty space. May be half is
+ * not the optimal boundary - this should be tested and
+ * checked. This boundary should determine how much we use
+ * in-the-gaps to consolidate the index comparing to how much
+ * we use garbage collector to consolidate it. The "half"
+ * criteria just feels to be fine.
*/
if (sum < min_space || sum < c->half_leb_size)
idx_lp = NULL;
diff --git a/fs/ubifs/io.c b/fs/ubifs/io.c
index 3374f91b6709..054363f2b207 100644
--- a/fs/ubifs/io.c
+++ b/fs/ubifs/io.c
@@ -54,6 +54,20 @@
#include "ubifs.h"
/**
+ * ubifs_ro_mode - switch UBIFS to read read-only mode.
+ * @c: UBIFS file-system description object
+ * @err: error code which is the reason of switching to R/O mode
+ */
+void ubifs_ro_mode(struct ubifs_info *c, int err)
+{
+ if (!c->ro_media) {
+ c->ro_media = 1;
+ ubifs_warn("switched to read-only mode, error %d", err);
+ dbg_dump_stack();
+ }
+}
+
+/**
* ubifs_check_node - check node.
* @c: UBIFS file-system description object
* @buf: node to check
diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c
index 283155abe5f5..22993f867d19 100644
--- a/fs/ubifs/journal.c
+++ b/fs/ubifs/journal.c
@@ -447,13 +447,11 @@ static int get_dent_type(int mode)
* @ino: buffer in which to pack inode node
* @inode: inode to pack
* @last: indicates the last node of the group
- * @last_reference: non-zero if this is a deletion inode
*/
static void pack_inode(struct ubifs_info *c, struct ubifs_ino_node *ino,
- const struct inode *inode, int last,
- int last_reference)
+ const struct inode *inode, int last)
{
- int data_len = 0;
+ int data_len = 0, last_reference = !inode->i_nlink;
struct ubifs_inode *ui = ubifs_inode(inode);
ino->ch.node_type = UBIFS_INO_NODE;
@@ -596,9 +594,9 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
ubifs_prep_grp_node(c, dent, dlen, 0);
ino = (void *)dent + aligned_dlen;
- pack_inode(c, ino, inode, 0, last_reference);
+ pack_inode(c, ino, inode, 0);
ino = (void *)ino + aligned_ilen;
- pack_inode(c, ino, dir, 1, 0);
+ pack_inode(c, ino, dir, 1);
if (last_reference) {
err = ubifs_add_orphan(c, inode->i_ino);
@@ -606,6 +604,7 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
release_head(c, BASEHD);
goto out_finish;
}
+ ui->del_cmtno = c->cmt_no;
}
err = write_head(c, BASEHD, dent, len, &lnum, &dent_offs, sync);
@@ -750,30 +749,25 @@ out_free:
* ubifs_jnl_write_inode - flush inode to the journal.
* @c: UBIFS file-system description object
* @inode: inode to flush
- * @deletion: inode has been deleted
*
* This function writes inode @inode to the journal. If the inode is
* synchronous, it also synchronizes the write-buffer. Returns zero in case of
* success and a negative error code in case of failure.
*/
-int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode,
- int deletion)
+int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode)
{
- int err, len, lnum, offs, sync = 0;
+ int err, lnum, offs;
struct ubifs_ino_node *ino;
struct ubifs_inode *ui = ubifs_inode(inode);
+ int sync = 0, len = UBIFS_INO_NODE_SZ, last_reference = !inode->i_nlink;
- dbg_jnl("ino %lu%s", inode->i_ino,
- deletion ? " (last reference)" : "");
- if (deletion)
- ubifs_assert(inode->i_nlink == 0);
+ dbg_jnl("ino %lu, nlink %u", inode->i_ino, inode->i_nlink);
- len = UBIFS_INO_NODE_SZ;
/*
* If the inode is being deleted, do not write the attached data. No
* need to synchronize the write-buffer either.
*/
- if (!deletion) {
+ if (!last_reference) {
len += ui->data_len;
sync = IS_SYNC(inode);
}
@@ -786,7 +780,7 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode,
if (err)
goto out_free;
- pack_inode(c, ino, inode, 1, deletion);
+ pack_inode(c, ino, inode, 1);
err = write_head(c, BASEHD, ino, len, &lnum, &offs, sync);
if (err)
goto out_release;
@@ -795,7 +789,7 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode,
inode->i_ino);
release_head(c, BASEHD);
- if (deletion) {
+ if (last_reference) {
err = ubifs_tnc_remove_ino(c, inode->i_ino);
if (err)
goto out_ro;
@@ -828,6 +822,65 @@ out_free:
}
/**
+ * ubifs_jnl_delete_inode - delete an inode.
+ * @c: UBIFS file-system description object
+ * @inode: inode to delete
+ *
+ * This function deletes inode @inode which includes removing it from orphans,
+ * deleting it from TNC and, in some cases, writing a deletion inode to the
+ * journal.
+ *
+ * When regular file inodes are unlinked or a directory inode is removed, the
+ * 'ubifs_jnl_update()' function writes a corresponding deletion inode and
+ * direntry to the media, and adds the inode to orphans. After this, when the
+ * last reference to this inode has been dropped, this function is called. In
+ * general, it has to write one more deletion inode to the media, because if
+ * a commit happened between 'ubifs_jnl_update()' and
+ * 'ubifs_jnl_delete_inode()', the deletion inode is not in the journal
+ * anymore, and in fact it might not be on the flash anymore, because it might
+ * have been garbage-collected already. And for optimization reasons UBIFS does
+ * not read the orphan area if it has been unmounted cleanly, so it would have
+ * no indication in the journal that there is a deleted inode which has to be
+ * removed from TNC.
+ *
+ * However, if there was no commit between 'ubifs_jnl_update()' and
+ * 'ubifs_jnl_delete_inode()', then there is no need to write the deletion
+ * inode to the media for the second time. And this is quite a typical case.
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+int ubifs_jnl_delete_inode(struct ubifs_info *c, const struct inode *inode)
+{
+ int err;
+ struct ubifs_inode *ui = ubifs_inode(inode);
+
+ ubifs_assert(inode->i_nlink == 0);
+
+ if (ui->del_cmtno != c->cmt_no)
+ /* A commit happened for sure */
+ return ubifs_jnl_write_inode(c, inode);
+
+ down_read(&c->commit_sem);
+ /*
+ * Check commit number again, because the first test has been done
+ * without @c->commit_sem, so a commit might have happened.
+ */
+ if (ui->del_cmtno != c->cmt_no) {
+ up_read(&c->commit_sem);
+ return ubifs_jnl_write_inode(c, inode);
+ }
+
+ err = ubifs_tnc_remove_ino(c, inode->i_ino);
+ if (err)
+ ubifs_ro_mode(c, err);
+ else
+ ubifs_delete_orphan(c, inode->i_ino);
+ up_read(&c->commit_sem);
+ return err;
+}
+
+/**
* ubifs_jnl_rename - rename a directory entry.
* @c: UBIFS file-system description object
* @old_dir: parent inode of directory entry to rename
@@ -917,16 +970,16 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
p = (void *)dent2 + aligned_dlen2;
if (new_inode) {
- pack_inode(c, p, new_inode, 0, last_reference);
+ pack_inode(c, p, new_inode, 0);
p += ALIGN(ilen, 8);
}
if (!move)
- pack_inode(c, p, old_dir, 1, 0);
+ pack_inode(c, p, old_dir, 1);
else {
- pack_inode(c, p, old_dir, 0, 0);
+ pack_inode(c, p, old_dir, 0);
p += ALIGN(plen, 8);
- pack_inode(c, p, new_dir, 1, 0);
+ pack_inode(c, p, new_dir, 1);
}
if (last_reference) {
@@ -935,6 +988,7 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
release_head(c, BASEHD);
goto out_finish;
}
+ new_ui->del_cmtno = c->cmt_no;
}
err = write_head(c, BASEHD, dent, len, &lnum, &offs, sync);
@@ -1131,7 +1185,7 @@ int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode,
if (err)
goto out_free;
- pack_inode(c, ino, inode, 0, 0);
+ pack_inode(c, ino, inode, 0);
ubifs_prep_grp_node(c, trun, UBIFS_TRUN_NODE_SZ, dlen ? 0 : 1);
if (dlen)
ubifs_prep_grp_node(c, dn, dlen, 1);
@@ -1251,9 +1305,9 @@ int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
ubifs_prep_grp_node(c, xent, xlen, 0);
ino = (void *)xent + aligned_xlen;
- pack_inode(c, ino, inode, 0, 1);
+ pack_inode(c, ino, inode, 0);
ino = (void *)ino + UBIFS_INO_NODE_SZ;
- pack_inode(c, ino, host, 1, 0);
+ pack_inode(c, ino, host, 1);
err = write_head(c, BASEHD, xent, len, &lnum, &xent_offs, sync);
if (!sync && !err)
@@ -1320,7 +1374,7 @@ int ubifs_jnl_change_xattr(struct ubifs_info *c, const struct inode *inode,
const struct inode *host)
{
int err, len1, len2, aligned_len, aligned_len1, lnum, offs;