Commit 21d3bdb1 authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents 3141eb6c c78c7e35
...@@ -57,7 +57,7 @@ Similarly to JFFS2, UBIFS supports on-the-flight compression which makes ...@@ -57,7 +57,7 @@ Similarly to JFFS2, UBIFS supports on-the-flight compression which makes
it possible to fit quite a lot of data to the flash. it possible to fit quite a lot of data to the flash.
Similarly to JFFS2, UBIFS is tolerant of unclean reboots and power-cuts. Similarly to JFFS2, UBIFS is tolerant of unclean reboots and power-cuts.
It does not need stuff like ckfs.ext2. UBIFS automatically replays its It does not need stuff like fsck.ext2. UBIFS automatically replays its
journal and recovers from crashes, ensuring that the on-flash data journal and recovers from crashes, ensuring that the on-flash data
structures are consistent. structures are consistent.
......
...@@ -263,8 +263,8 @@ int ubifs_calc_min_idx_lebs(struct ubifs_info *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; 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 */ /* And make sure we have thrice the index size of space reserved */
idx_size <<= 1; idx_size = idx_size + (idx_size << 1);
/* /*
* We do not maintain 'old_idx_size' as 'old_idx_lebs'/'old_idx_bytes' * 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) ...@@ -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 * This function makes sure UBIFS has enough free eraseblocks for index growth
* and data. * 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 * 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 * 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 * 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. * and makes sure this does not exceed the amount of free eraseblocks.
* *
* Notes about @c->min_idx_lebs and @c->lst.idx_lebs variables: * 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) ...@@ -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; int err, idx_growth, data_growth, dd_growth;
struct retries_info ri; 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 <= 4);
ubifs_assert(req->dirtied_ino_d <= UBIFS_MAX_INO_DATA * 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); data_growth = calc_data_growth(c, req);
dd_growth = calc_dd_growth(c, req); dd_growth = calc_dd_growth(c, req);
...@@ -618,8 +626,16 @@ int ubifs_budget_space(struct ubifs_info *c, struct ubifs_budget_req *req) ...@@ -618,8 +626,16 @@ int ubifs_budget_space(struct ubifs_info *c, struct ubifs_budget_req *req)
*/ */
void ubifs_release_budget(struct ubifs_info *c, struct ubifs_budget_req *req) 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 <= 4);
ubifs_assert(req->dirtied_ino_d <= UBIFS_MAX_INO_DATA * 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) { if (!req->recalculate) {
ubifs_assert(req->idx_growth >= 0); ubifs_assert(req->idx_growth >= 0);
ubifs_assert(req->data_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) ...@@ -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_idx_growth >= 0);
ubifs_assert(c->budg_data_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->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); spin_unlock(&c->space_lock);
} }
...@@ -686,9 +706,10 @@ void ubifs_convert_page_budget(struct ubifs_info *c) ...@@ -686,9 +706,10 @@ void ubifs_convert_page_budget(struct ubifs_info *c)
void ubifs_release_dirty_inode_budget(struct ubifs_info *c, void ubifs_release_dirty_inode_budget(struct ubifs_info *c,
struct ubifs_inode *ui) struct ubifs_inode *ui)
{ {
struct ubifs_budget_req req = {.dd_growth = c->inode_budget, struct ubifs_budget_req req;
.dirtied_ino_d = ui->data_len};
memset(&req, 0, sizeof(struct ubifs_budget_req));
req.dd_growth = c->inode_budget + ALIGN(ui->data_len, 8);
ubifs_release_budget(c, &req); ubifs_release_budget(c, &req);
} }
......
...@@ -74,6 +74,7 @@ static int do_commit(struct ubifs_info *c) ...@@ -74,6 +74,7 @@ static int do_commit(struct ubifs_info *c)
goto out_up; goto out_up;
} }
c->cmt_no += 1;
err = ubifs_gc_start_commit(c); err = ubifs_gc_start_commit(c);
if (err) if (err)
goto out_up; goto out_up;
...@@ -115,7 +116,7 @@ static int do_commit(struct ubifs_info *c) ...@@ -115,7 +116,7 @@ static int do_commit(struct ubifs_info *c)
goto out; goto out;
mutex_lock(&c->mst_mutex); 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->log_lnum = cpu_to_le32(new_ltail_lnum);
c->mst_node->root_lnum = cpu_to_le32(zroot.lnum); c->mst_node->root_lnum = cpu_to_le32(zroot.lnum);
c->mst_node->root_offs = cpu_to_le32(zroot.offs); c->mst_node->root_offs = cpu_to_le32(zroot.offs);
......
...@@ -568,8 +568,8 @@ void dbg_dump_budget_req(const struct ubifs_budget_req *req) ...@@ -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) void dbg_dump_lstats(const struct ubifs_lp_stats *lst)
{ {
spin_lock(&dbg_lock); spin_lock(&dbg_lock);
printk(KERN_DEBUG "Lprops statistics: empty_lebs %d, idx_lebs %d\n", printk(KERN_DEBUG "(pid %d) Lprops statistics: empty_lebs %d, "
lst->empty_lebs, lst->idx_lebs); "idx_lebs %d\n", current->pid, lst->empty_lebs, lst->idx_lebs);
printk(KERN_DEBUG "\ttaken_empty_lebs %d, total_free %lld, " printk(KERN_DEBUG "\ttaken_empty_lebs %d, total_free %lld, "
"total_dirty %lld\n", lst->taken_empty_lebs, lst->total_free, "total_dirty %lld\n", lst->taken_empty_lebs, lst->total_free,
lst->total_dirty); lst->total_dirty);
...@@ -587,8 +587,8 @@ void dbg_dump_budg(struct ubifs_info *c) ...@@ -587,8 +587,8 @@ void dbg_dump_budg(struct ubifs_info *c)
struct ubifs_gced_idx_leb *idx_gc; struct ubifs_gced_idx_leb *idx_gc;
spin_lock(&dbg_lock); spin_lock(&dbg_lock);
printk(KERN_DEBUG "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", "budg_dd_growth %lld, budg_idx_growth %lld\n", current->pid,
c->budg_data_growth, c->budg_dd_growth, c->budg_idx_growth); c->budg_data_growth, c->budg_dd_growth, c->budg_idx_growth);
printk(KERN_DEBUG "\tdata budget sum %lld, total budget sum %lld, " printk(KERN_DEBUG "\tdata budget sum %lld, total budget sum %lld, "
"freeable_cnt %d\n", c->budg_data_growth + c->budg_dd_growth, "freeable_cnt %d\n", c->budg_data_growth + c->budg_dd_growth,
...@@ -634,7 +634,7 @@ void dbg_dump_lprops(struct ubifs_info *c) ...@@ -634,7 +634,7 @@ 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 "Dumping LEB properties\n"); printk(KERN_DEBUG "(pid %d) 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);
...@@ -655,7 +655,7 @@ void dbg_dump_leb(const struct ubifs_info *c, int lnum) ...@@ -655,7 +655,7 @@ void dbg_dump_leb(const struct ubifs_info *c, int lnum)
if (dbg_failure_mode) if (dbg_failure_mode)
return; 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); sleb = ubifs_scan(c, lnum, 0, c->dbg_buf);
if (IS_ERR(sleb)) { if (IS_ERR(sleb)) {
...@@ -720,8 +720,8 @@ void dbg_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat) ...@@ -720,8 +720,8 @@ void dbg_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat)
{ {
int i; int i;
printk(KERN_DEBUG "Dumping heap cat %d (%d elements)\n", printk(KERN_DEBUG "(pid %d) Dumping heap cat %d (%d elements)\n",
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];
...@@ -736,7 +736,7 @@ void dbg_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode, ...@@ -736,7 +736,7 @@ void dbg_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
{ {
int i; 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", 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",
...@@ -755,7 +755,7 @@ void dbg_dump_tnc(struct ubifs_info *c) ...@@ -755,7 +755,7 @@ void dbg_dump_tnc(struct ubifs_info *c)
int level; int level;
printk(KERN_DEBUG "\n"); 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); 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);
...@@ -2208,16 +2208,17 @@ int dbg_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset, ...@@ -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 dbg_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
int offset, int len, int dtype) int offset, int len, int dtype)
{ {
int err; int err, failing;
if (in_failure_mode(desc)) if (in_failure_mode(desc))
return -EIO; return -EIO;
if (do_fail(desc, lnum, 1)) failing = do_fail(desc, lnum, 1);
if (failing)
cut_data(buf, len); cut_data(buf, len);
err = ubi_leb_write(desc, lnum, buf, offset, len, dtype); err = ubi_leb_write(desc, lnum, buf, offset, len, dtype);
if (err) if (err)
return err; return err;
if (in_failure_mode(desc)) if (failing)
return -EIO; return -EIO;
return 0; return 0;
} }
......
This diff is collapsed.
...@@ -165,7 +165,6 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir, ...@@ -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_ino = ++c->highest_inum;
inode->i_generation = ++c->vfs_gen;
/* /*
* The creation sequence number remains with this inode for its * The creation sequence number remains with this inode for its
* lifetime. All nodes for this inode have a greater sequence number, * 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, ...@@ -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); err = ubifs_tnc_lookup_nm(c, &key, dent, &dentry->d_name);
if (err) { if (err) {
/* if (err == -ENOENT) {
* 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) {
dbg_gen("not found"); dbg_gen("not found");
goto done; goto done;
} }
...@@ -525,7 +516,7 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir, ...@@ -525,7 +516,7 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir,
struct ubifs_inode *dir_ui = ubifs_inode(dir); struct ubifs_inode *dir_ui = ubifs_inode(dir);
int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len); int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len);
struct ubifs_budget_req req = { .new_dent = 1, .dirtied_ino = 2, 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, * 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) ...@@ -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_inode *dir_ui = ubifs_inode(dir);
struct ubifs_info *c = dir->i_sb->s_fs_info; struct ubifs_info *c = dir->i_sb->s_fs_info;
int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len); int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len);
struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1 };
.dirtied_ino_d = 1 };
/* /*
* Budget request settings: new inode, new direntry and changing parent * Budget request settings: new inode, new direntry and changing parent
...@@ -789,7 +779,8 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry, ...@@ -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 sz_change = CALC_DENT_SIZE(dentry->d_name.len);
int err, devlen = 0; int err, devlen = 0;
struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, 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 * Budget request settings: new inode, new direntry and changing parent
...@@ -863,7 +854,8 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry, ...@@ -863,7 +854,8 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry,
int err, len = strlen(symname); int err, len = strlen(symname);
int sz_change = CALC_DENT_SIZE(dentry->d_name.len); int sz_change = CALC_DENT_SIZE(dentry->d_name.len);
struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, 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 * 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, ...@@ -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, struct ubifs_budget_req req = { .new_dent = 1, .mod_dent = 1,
.dirtied_ino = 3 }; .dirtied_ino = 3 };
struct ubifs_budget_req ino_req = { .dirtied_ino = 1, 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; struct timespec time;
/* /*
......
...@@ -890,7 +890,7 @@ static int do_setattr(struct ubifs_info *c, struct inode *inode, ...@@ -890,7 +890,7 @@ static int do_setattr(struct ubifs_info *c, struct inode *inode,
loff_t new_size = attr->ia_size; loff_t new_size = attr->ia_size;
struct ubifs_inode *ui = ubifs_inode(inode); struct ubifs_inode *ui = ubifs_inode(inode);
struct ubifs_budget_req req = { .dirtied_ino = 1, 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); err = ubifs_budget_space(c, &req);
if (err) if (err)
...@@ -941,7 +941,8 @@ int ubifs_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -941,7 +941,8 @@ int ubifs_setattr(struct dentry *dentry, struct iattr *attr)
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
struct ubifs_info *c = inode->i_sb->s_fs_info; 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); err = inode_change_ok(inode, attr);
if (err) if (err)
return err; return err;
...@@ -1051,7 +1052,7 @@ static int update_mctime(struct ubifs_info *c, struct inode *inode) ...@@ -1051,7 +1052,7 @@ static int update_mctime(struct ubifs_info *c, struct inode *inode)
if (mctime_update_needed(inode, &now)) { if (mctime_update_needed(inode, &now)) {
int err, release; int err, release;
struct ubifs_budget_req req = { .dirtied_ino = 1, 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); err = ubifs_budget_space(c, &req);
if (err) if (err)
...@@ -1270,6 +1271,7 @@ struct file_operations ubifs_file_operations = { ...@@ -1270,6 +1271,7 @@ struct file_operations ubifs_file_operations = {
.fsync = ubifs_fsync, .fsync = ubifs_fsync,
.unlocked_ioctl = ubifs_ioctl, .unlocked_ioctl = ubifs_ioctl,
.splice_read = generic_file_splice_read, .splice_read = generic_file_splice_read,
.splice_write = generic_file_splice_write,
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
.compat_ioctl = ubifs_compat_ioctl, .compat_ioctl = ubifs_compat_ioctl,
#endif #endif
......
...@@ -290,9 +290,14 @@ int ubifs_find_dirty_leb(struct ubifs_info *c, struct ubifs_lprops *ret_lp, ...@@ -290,9 +290,14 @@ int ubifs_find_dirty_leb(struct ubifs_info *c, struct ubifs_lprops *ret_lp,
idx_lp = idx_heap->arr[0]; idx_lp = idx_heap->arr[0];
sum = idx_lp->free + idx_lp->dirty; 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 * 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) if (sum < min_space || sum < c->half_leb_size)
idx_lp = NULL; idx_lp = NULL;
......
...@@ -53,6 +53,20 @@ ...@@ -53,6 +53,20 @@
#include <linux/crc32.h> #include <linux/crc32.h>
#include "ubifs.h" #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. * ubifs_check_node - check node.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
......
...@@ -447,13 +447,11 @@ static int get_dent_type(int mode) ...@@ -447,13 +447,11 @@ static int get_dent_type(int mode)
* @ino: buffer in which to pack inode node * @ino: buffer in which to pack inode node
* @inode: inode to pack * @inode: inode to pack
* @last: indicates the last node of the group * @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, static void pack_inode(struct ubifs_info *c, struct ubifs_ino_node *ino,
const struct inode *inode, int last, const struct inode *inode, int last)
int last_reference)
{ {
int data_len = 0; int data_len = 0, last_reference = !inode->i_nlink;
struct ubifs_inode *ui = ubifs_inode(inode); struct ubifs_inode *ui = ubifs_inode(inode);
ino->ch.node_type = UBIFS_INO_NODE; ino->ch.node_type = UBIFS_INO_NODE;
...@@ -596,9 +594,9 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir, ...@@ -596,9 +594,9 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
ubifs_prep_grp_node(c, dent, dlen, 0); ubifs_prep_grp_node(c, dent, dlen, 0);
ino = (void *)dent + aligned_dlen; ino = (void *)dent + aligned_dlen;
pack_inode(c, ino, inode, 0, last_reference); pack_inode(c, ino, inode, 0);
ino = (void *)ino + aligned_ilen; ino = (void *)ino + aligned_ilen;
pack_inode(c, ino, dir, 1, 0); pack_inode(c, ino, dir, 1);
if (last_reference) { if (last_reference) {
err = ubifs_add_orphan(c, inode->i_ino); err = ubifs_add_orphan(c, inode->i_ino);
...@@ -606,6 +604,7 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir, ...@@ -606,6 +604,7 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
release_head(c, BASEHD); release_head(c, BASEHD);
goto out_finish; goto out_finish;
} }
ui->del_cmtno = c->cmt_no;
} }
err = write_head(c, BASEHD, dent, len, &lnum, &dent_offs, sync); err = write_head(c, BASEHD, dent, len, &lnum, &dent_offs, sync);
...@@ -750,30 +749,25 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode, ...@@ -750,30 +749,25 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
* ubifs_jnl_write_inode - flush inode to the journal. * ubifs_jnl_write_inode - flush inode to the journal.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
* @inode: inode to flush * @inode: inode to flush
* @deletion: inode has been deleted
* *
* This function writes inode @inode to the journal. If the inode is * This function writes inode @inode to the journal. If the inode is
* synchronous, it also synchronizes the write-buffer. Returns zero in case of * synchronous, it also synchronizes the write-buffer. Returns zero in case of
* success and a negative error code in case of failure. * success and a negative error code in case of failure.
*/ */
int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode, int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode)
int deletion)
{ {
int err, len, lnum, offs, sync = 0; int err, lnum, offs;
struct ubifs_ino_node *ino; struct ubifs_ino_node *ino;
struct ubifs_inode *ui = ubifs_inode(inode); 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, dbg_jnl("ino %lu, nlink %u", inode->i_ino, inode->i_nlink);
deletion ? " (last reference)" : "");
if (deletion)
ubifs_assert(inode->i_nlink == 0);
len = UBIFS_INO_NODE_SZ;
/* /*
* If the inode is being deleted, do not write the attached data. No * If the inode is being deleted, do not write the attached data. No
* need to synchronize the write-buffer either. * need to synchronize the write-buffer either.
*/ */
if (!deletion) { if (!last_reference) {
len += ui->data_len; len += ui->data_len;
sync = IS_SYNC(inode); sync = IS_SYNC(inode);
} }
...@@ -786,7 +780,7 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode, ...@@ -786,7 +780,7 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode,
if (err) if (err)
goto out_free; 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); err = write_head(c, BASEHD, ino, len, &lnum, &offs, sync);
if (err) if (err)
goto out_release; goto out_release;
...@@ -795,7 +789,7 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode, ...@@ -795,7 +789,7 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode,
inode->i_ino); inode->i_ino);
release_head(c, BASEHD); release_head(c, BASEHD);
if (deletion) { if (last_reference) {
err = ubifs_tnc_remove_ino(c, inode->i_ino); err = ubifs_tnc_remove_ino(c, inode->i_ino);
if (err) if (err)
goto out_ro; goto out_ro;
...@@ -827,6 +821,65 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode, ...@@ -827,6 +821,65 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode,
return err; return err;
} }
/**
* 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. * ubifs_jnl_rename - rename a directory entry.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
...@@ -917,16 +970,16 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir, ...@@ -917,16 +970,16 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
p = (void *)dent2 + aligned_dlen2; p = (void *)dent2 + aligned_dlen2;
if (new_inode) { if (new_inode) {
pack_inode(c, p, new_inode, 0, last_reference); pack_inode(c, p, new_inode, 0);
p += ALIGN(ilen, 8); p += ALIGN(ilen, 8);
} }
if (!move) if (!move)
pack_inode(c, p, old_dir, 1, 0); pack_inode(c, p, old_dir, 1);
else { else {
pack_inode(c, p, old_dir, 0, 0); pack_inode(c, p, old_dir, 0);
p += ALIGN(plen, 8); p += ALIGN(plen, 8);
pack_inode(c, p, new_dir, 1, 0); pack_inode(c, p, new_dir, 1);
} }
if (last_reference) { if (last_reference) {
...@@ -935,6 +988,7 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir, ...@@ -935,6 +988,7 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
release_head(c, BASEHD); release_head(c, BASEHD);
goto out_finish; goto out_finish;
} }
new_ui->del_cmtno = c->cmt_no;
} }
err = write_head(c, BASEHD, dent, len, &lnum, &offs, sync); 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, ...@@ -1131,7 +1185,7 @@ int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode,
if (err) if (err)
goto out_free; 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); ubifs_prep_grp_node(c, trun, UBIFS_TRUN_NODE_SZ, dlen ? 0 : 1);
if (dlen) if (dlen)
ubifs_prep_grp_node(c, dn, dlen, 1); 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, ...@@ -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); ubifs_prep_grp_node(c, xent, xlen, 0);
ino = (void *)xent + aligned_xlen; 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; 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); err = write_head(c, BASEHD, xent, len, &lnum, &xent_offs, sync);
if (!sync && !err) if (!sync && !err)
...@@ -1320,7 +1374,7 @@ int ubifs_jnl_change_xattr(struct ubifs_info *c, const struct inode *inode, ...@@ -1320,7 +1374,7 @@ int ubifs_jnl_change_xattr(struct ubifs_info *c, const struct inode *inode,
const struct inode *host) const struct inode *host)
{ {
int err, len1, len2, aligned_len, aligned_len1, lnum, offs; int err, len1, len2, aligned_len, aligned_len1, lnum, offs;
struct ubifs_inode *host_ui = ubifs_inode(inode); struct ubifs_inode *host_ui = ubifs_inode(host);
struct ubifs_ino_node *ino; struct ubifs_ino_node *ino;
union ubifs_key key; union ubifs_key key;
int sync = IS_DIRSYNC(host); int sync = IS_DIRSYNC(host);
...@@ -1344,8 +1398,8 @@ int ubifs_jnl_change_xattr(struct ubifs_info *c, const struct inode *inode, ...@@ -1344,8 +1398,8 @@ int ubifs_jnl_change_xattr(struct ubifs_info *c, const struct inode *inode,
if (err) if (err)
goto out_free; goto out_free;
pack_inode(c, ino, host, 0, 0); pack_inode(c, ino, host, 0);
pack_inode(c, (void *)ino + aligned_len1, inode, 1, 0); pack_inode(c, (void *)ino + aligned_len1, inode, 1);
err = write_head(c, BASEHD, ino, aligned_len, &lnum, &offs, 0); err = write_head(c, BASEHD, ino, aligned_len, &lnum, &offs, 0);
if (!sync && !err) { if (!sync && !err) {
......
...@@ -317,6 +317,8 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs) ...@@ -317,6 +317,8 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs)
return 0; return 0;
out_unlock: out_unlock:
if (err != -EAGAIN)
ubifs_ro_mode(c, err);
mutex_unlock(&c->log_mutex); mutex_unlock(&c->log_mutex);
kfree(ref); kfree(ref);
kfree(bud); kfree(bud);
...@@ -410,7 +412,7 @@ int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum) ...@@ -410,7 +412,7 @@ int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum)
return -ENOMEM; return -ENOMEM;
cs->ch.node_type = UBIFS_CS_NODE; cs->ch.node_type = UBIFS_CS_NODE;
cs->cmt_no = cpu_to_le64(c->cmt_no + 1); cs->cmt_no = cpu_to_le64(c->cmt_no);
ubifs_prepare_node(c, cs, UBIFS_CS_NODE_SZ, 0); ubifs_prepare_node(c, cs, UBIFS_CS_NODE_SZ, 0);
/* /*
......
...@@ -79,20 +79,6 @@ static inline struct ubifs_inode *ubifs_inode(const struct inode *inode) ...@@ -79,20 +79,6 @@ static inline struct ubifs_inode *ubifs_inode(const struct inode *inode)
return container_of(inode, struct ubifs_inode, vfs_inode); return container_of(inode, struct ubifs_inode, vfs_inode);
} }
/**
* 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
*/
static inline 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_compr_present - check if compressor was compiled in. * ubifs_compr_present - check if compressor was compiled in.
* @compr_type: compressor type to check * @compr_type: compressor type to check
...@@ -322,7 +308,7 @@ static inline long long ubifs_reported_space(const struct ubifs_info *c, ...@@ -322,7 +308,7 @@ static inline long long ubifs_reported_space(const struct ubifs_info *c,
{ {
int divisor, factor; int divisor, factor;
divisor = UBIFS_MAX_DATA_NODE_SZ + (c->max_idx_node_sz << 1); divisor = UBIFS_MAX_DATA_NODE_SZ + (c->max_idx_node_sz * 3);
factor = UBIFS_MAX_DATA_NODE_SZ - UBIFS_DATA_NODE_SZ; factor = UBIFS_MAX_DATA_NODE_SZ - UBIFS_DATA_NODE_SZ;
do_div(free, divisor); do_div(free, divisor);
......
...@@ -310,10 +310,10 @@ static int write_orph_node(struct ubifs_info *c, int atomic) ...@@ -310,10 +310,10 @@ static int write_orph_node(struct ubifs_info *c, int atomic)
c->cmt_orphans -= cnt; c->cmt_orphans -= cnt;
spin_unlock(&c->orphan_lock); spin_unlock(&c->orphan_lock);
if (c->cmt_orphans) if (c->cmt_orphans)
orph->cmt_no = cpu_to_le64(c->cmt_no + 1); orph->cmt_no = cpu_to_le64(c->cmt_no);
else else
/* Mark the last node of the commit */ /* Mark the last node of the commit */
orph->cmt_no = cpu_to_le64((c->cmt_no + 1) | (1ULL << 63)); orph->cmt_no = cpu_to_le64((c->cmt_no) | (1ULL << 63));
ubifs_assert(c->ohead_offs + len <= c->leb_size); ubifs_assert(c->ohead_offs + len <= c->leb_size);
ubifs_assert(c->ohead_lnum >= c->orph_first); ubifs_assert(c->ohead_lnum >= c->orph_first);
ubifs_assert(c->ohead_lnum <= c->orph_last); ubifs_assert(c->ohead_lnum <= c->orph_last);
......
...@@ -30,7 +30,6 @@ ...@@ -30,7 +30,6 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/random.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/parser.h> #include <linux/parser.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
...@@ -149,7 +148,7 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum) ...@@ -149,7 +148,7 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum)
if (err) if (err)
goto out_invalid; goto out_invalid;
/* Disable readahead */ /* Disable read-ahead */
inode->i_mapping->backing_dev_info = &c->bdi; inode->i_mapping->backing_dev_info = &c->bdi;
switch (inode->i_mode & S_IFMT) { switch (inode->i_mode & S_IFMT) {
...@@ -278,7 +277,7 @@ static void ubifs_destroy_inode(struct inode *inode) ...@@ -278,7 +277,7 @@ static void ubifs_destroy_inode(struct inode *inode)
*/ */
static int ubifs_write_inode(struct inode *inode, int wait) static int ubifs_write_inode(struct inode *inode, int wait)
{ {
int err; int err = 0;
struct ubifs_info *c = inode->i_sb->s_fs_info; struct ubifs_info *c = inode->i_sb->s_fs_info;
struct ubifs_inode *ui = ubifs_inode(inode); struct ubifs_inode *ui = ubifs_inode(inode);
...@@ -299,10 +298,18 @@ static int ubifs_write_inode(struct inode *inode, int wait) ...@@ -299,10 +298,18 @@ static int ubifs_write_inode(struct inode *inode, int wait)
return 0; return 0;
} }
dbg_gen("inode %lu", inode->i_ino); /*
err = ubifs_jnl_write_inode(c, inode, 0); * As an optimization, do not write orphan inodes to the media just
if (err) * because this is not needed.
ubifs_err("can't write inode %lu, error %d", inode->i_ino, err); */
dbg_gen("inode %lu, mode %#x, nlink %u",
inode->i_ino, (int)inode->i_mode, inode->i_nlink);
if (inode->i_nlink) {
err = ubifs_jnl_write_inode(c, inode);
if (err)
ubifs_err("can't write inode %lu, error %d",
inode->i_ino, err);
}
ui->dirty = 0; ui->dirty = 0;
mutex_unlock(&ui->ui_mutex); mutex_unlock(&ui->ui_mutex);
...@@ -314,8 +321,9 @@ static void ubifs_delete_inode(struct inode *inode) ...@@ -314,8 +321,9 @@ static void ubifs_delete_inode(struct inode *inode)
{ {
int err; int err;
struct ubifs_info *c = inode->i_sb->s_fs_info; struct ubifs_info *c = inode->i_sb->s_fs_info;
struct ubifs_inode *ui = ubifs_inode(inode);
if (ubifs_inode(inode)->xattr) if (ui->xattr)
/* /*
* Extended attribute inode deletions are fully handled in * Extended attribute inode deletions are fully handled in
* 'ubifs_removexattr()'. These inodes are special and have * 'ubifs_removexattr()'. These inodes are special and have
...@@ -323,7 +331,7 @@ static void ubifs_delete_inode(struct inode *inode) ...@@ -323,7 +331,7 @@ static void ubifs_delete_inode(struct inode *inode)
*/ */
goto out; goto out;
dbg_gen("inode %lu", inode->i_ino); dbg_gen("inode %lu, mode %#x", inode->i_ino, (int)inode->i_mode);
ubifs_assert(!atomic_read(&inode->i_count)); ubifs_assert(!atomic_read(&inode->i_count));
ubifs_assert(inode->i_nlink == 0); ubifs_assert(inode->i_nlink == 0);
...@@ -331,15 +339,19 @@ static void ubifs_delete_inode(struct inode *inode) ...@@ -331,15 +339,19 @@ static void ubifs_delete_inode(struct inode *inode)
if (is_bad_inode(inode)) if (is_bad_inode(inode))
goto out; goto out;
ubifs_inode(inode)->ui_size = inode->i_size = 0; ui->ui_size = inode->i_size = 0;
err = ubifs_jnl_write_inode(c, inode, 1); err = ubifs_jnl_delete_inode(c, inode);
if (err) if (err)
/* /*
* Worst case we have a lost orphan inode wasting space, so a * Worst case we have a lost orphan inode wasting space, so a
* simple error message is ok here. * simple error message is OK here.
*/ */
ubifs_err("can't write inode %lu, error %d", inode->i_ino, err); ubifs_err("can't delete inode %lu, error %d",
inode->i_ino, err);
out: out:
if (ui->dirty)
ubifs_release_dirty_inode_budget(c, ui);
clear_inode(inode); clear_inode(inode);
} }
...@@ -1122,8 +1134,8 @@ static int mount_ubifs(struct ubifs_info *c) ...@@ -1122,8 +1134,8 @@ static int mount_ubifs(struct ubifs_info *c)
if (err) if (err)
goto out_infos; goto out_infos;
ubifs_msg("mounted UBI device %d, volume %d", c->vi.ubi_num, ubifs_msg("mounted UBI device %d, volume %d, name \"%s\"",
c->vi.vol_id); c->vi.ubi_num, c->vi.vol_id, c->vi.name);
if (mounted_read_only) if (mounted_read_only)
ubifs_msg("mounted read-only"); ubifs_msg("mounted read-only");
x = (long long)c->main_lebs * c->leb_size; x = (long long)c->main_lebs * c->leb_size;
...@@ -1469,6 +1481,7 @@ static void ubifs_put_super(struct super_block *sb) ...@@ -1469,6 +1481,7 @@ static void ubifs_put_super(struct super_block *sb)
*/ */
ubifs_assert(atomic_long_read(&c->dirty_pg_cnt) == 0); ubifs_assert(atomic_long_read(&c->dirty_pg_cnt) == 0);
ubifs_assert(c->budg_idx_growth == 0); ubifs_assert(c->budg_idx_growth == 0);
ubifs_assert(c->budg_dd_growth == 0);
ubifs_assert(c->budg_data_growth == 0); ubifs_assert(c->budg_data_growth == 0);
/* /*
...@@ -1657,7 +1670,6 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent) ...@@ -1657,7 +1670,6 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
INIT_LIST_HEAD(&c->orph_new); INIT_LIST_HEAD(&c->orph_new);
c->highest_inum = UBIFS_FIRST_INO; c->highest_inum = UBIFS_FIRST_INO;
get_random_bytes(&c->vfs_gen, sizeof(int));
c->lhead_lnum = c->ltail_lnum = UBIFS_LOG_LNUM; c->lhead_lnum = c->ltail_lnum = UBIFS_LOG_LNUM;
ubi_get_volume_info(ubi, &c->vi); ubi_get_volume_info(ubi, &c->vi);
...@@ -1671,10 +1683,10 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent) ...@@ -1671,10 +1683,10 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
} }
/* /*
* UBIFS provids 'backing_dev_info' in order to disable readahead. For * UBIFS provides 'backing_dev_info' in order to disable read-ahead. For
* UBIFS, I/O is not deferred, it is done immediately in readpage, * UBIFS, I/O is not deferred, it is done immediately in readpage,
* which means the user would have to wait not just for their own I/O * which means the user would have to wait not just for their own I/O
* but the readahead I/O as well i.e. completely pointless. * but the read-ahead I/O as well i.e. completely pointless.
* *
* Read-ahead will be disabled because @c->bdi.ra_pages is 0. * Read-ahead will be disabled because @c->bdi.ra_pages is 0.
*/ */
......
...@@ -372,26 +372,25 @@ static int layout_in_gaps(struct ubifs_info *c, int cnt) ...@@ -372,26 +372,25 @@ static int layout_in_gaps(struct ubifs_info *c, int cnt)
written = layout_leb_in_gaps(c, p); written = layout_leb_in_gaps(c, p);
if (written < 0) { if (written < 0) {
err = written; err = written;
if (err == -ENOSPC) { if (err != -ENOSPC) {
if (!dbg_force_in_the_gaps_enabled) { kfree(c->gap_lebs);
/* c->gap_lebs = NULL;
* Do not print scary warnings if the return err;
* debugging option which forces
* in-the-gaps is enabled.
*/
ubifs_err("out of space");
spin_lock(&c->space_lock);
dbg_dump_budg(c);
spin_unlock(&c->space_lock);
dbg_dump_lprops(c);
}
/* Try to commit anyway */
err = 0;
break;
} }
kfree(c->gap_lebs); if (!dbg_force_in_the_gaps_enabled) {
c->gap_lebs = NULL; /*
return err; * Do not print scary warnings if the debugging
* option which forces in-the-gaps is enabled.
*/
ubifs_err("out of space");
spin_lock(&c->space_lock);
dbg_dump_budg(c);
spin_unlock(&c->space_lock);
dbg_dump_lprops(c);
}
/* Try to commit anyway */
err = 0;
break;
} }
p++; p++;
cnt -= written; cnt -= written;
......
...@@ -228,10 +228,10 @@ enum { ...@@ -228,10 +228,10 @@ enum {
/* Minimum number of orphan area logical eraseblocks */ /* Minimum number of orphan area logical eraseblocks */
#define UBIFS_MIN_ORPH_LEBS 1 #define UBIFS_MIN_ORPH_LEBS 1
/* /*
* Minimum number of main area logical eraseblocks (buds, 2 for the index, 1 * Minimum number of main area logical eraseblocks (buds, 3 for the index, 1
* for GC, 1 for deletions, and at least 1 for committed data). * for GC, 1 for deletions, and at least 1 for committed data).
*/ */
#define UBIFS_MIN_MAIN_LEBS (UBIFS_MIN_BUD_LEBS + 5) #define UBIFS_MIN_MAIN_LEBS (UBIFS_MIN_BUD_LEBS + 6)
/* Minimum number of logical eraseblocks */ /* Minimum number of logical eraseblocks */
#define UBIFS_MIN_LEB_CNT (UBIFS_SB_LEBS + UBIFS_MST_LEBS + \ #define UBIFS_MIN_LEB_CNT (UBIFS_SB_LEBS + UBIFS_MST_LEBS + \
......
...@@ -20,8 +20,6 @@ ...@@ -20,8 +20,6 @@
* Adrian Hunter * Adrian Hunter
*/ */
/* Implementation version 0.7 */
#ifndef __UBIFS_H__ #ifndef __UBIFS_H__
#define __UBIFS_H__ #define __UBIFS_H__
...@@ -322,6 +320,8 @@ struct ubifs_gced_idx_leb { ...@@ -322,6 +320,8 @@ struct ubifs_gced_idx_leb {
* struct ubifs_inode - UBIFS in-memory inode description. * struct ubifs_inode - UBIFS in-memory inode description.
* @vfs_inode: VFS inode description object * @vfs_inode: VFS inode description object
* @creat_sqnum: sequence number at time of creation * @creat_sqnum: sequence number at time of creation
* @del_cmtno: commit number corresponding to the time the inode was deleted,
* protected by @c->commit_sem;
* @xattr_size: summarized size of all extended attributes in bytes * @xattr_size: summarized size of all extended attributes in bytes
* @xattr_cnt: count of extended attributes this inode has * @xattr_cnt: count of extended attributes this inode has
* @xattr_names: sum of lengths of all extended attribute names belonging to * @xattr_names: sum of lengths of all extended attribute names belonging to
...@@ -373,6 +373,7 @@ struct ubifs_gced_idx_leb { ...@@ -373,6 +373,7 @@ struct ubifs_gced_idx_leb {
struct ubifs_inode { struct ubifs_inode {
struct inode vfs_inode; struct inode vfs_inode;
unsigned long long creat_sqnum; unsigned long long creat_sqnum;
unsigned long long del_cmtno;
unsigned int xattr_size; unsigned int xattr_size;
unsigned int xattr_cnt; unsigned int xattr_cnt;
unsigned int xattr_names; unsigned int xattr_names;
...@@ -779,7 +780,7 @@ struct ubifs_compressor { ...@@ -779,7 +780,7 @@ struct ubifs_compressor {
/** /**
* struct ubifs_budget_req - budget requirements of an operation. * struct ubifs_budget_req - budget requirements of an operation.
* *
* @fast: non-zero if the budgeting should try to aquire budget quickly and * @fast: non-zero if the budgeting should try to acquire budget quickly and
* should not try to call write-back * should not try to call write-back
* @recalculate: non-zero if @idx_growth, @data_growth, and @dd_growth fields * @recalculate: non-zero if @idx_growth, @data_growth, and @dd_growth fields
* have to be re-calculated * have to be re-calculated
...@@ -805,21 +806,31 @@ struct ubifs_compressor { ...@@ -805,21 +806,31 @@ struct ubifs_compressor {
* An inode may contain 4KiB of data at max., thus the widths of @new_ino_d * An inode may contain 4KiB of data at max., thus the widths of @new_ino_d
* is 13 bits, and @dirtied_ino_d - 15, because up to 4 inodes may be made * is 13 bits, and @dirtied_ino_d - 15, because up to 4 inodes may be made
* dirty by the re-name operation. * dirty by the re-name operation.
*
* Note, UBIFS aligns node lengths to 8-bytes boundary, so the requester has to
* make sure the amount of inode data which contribute to @new_ino_d and
* @dirtied_ino_d fields are aligned.
*/ */
struct ubifs_budget_req { struct ubifs_budget_req {
unsigned int fast:1; unsigned int fast:1;
unsigned int recalculate:1; unsigned int recalculate:1;
#ifndef UBIFS_DEBUG
unsigned int new_page:1; unsigned int new_page:1;
unsigned int dirtied_page:1; unsigned int dirtied_page:1;
unsigned int new_dent:1; unsigned int new_dent:1;
unsigned int mod_dent:1; unsigned int mod_dent:1;
unsigned int new_ino:1; unsigned int new_ino:1;
unsigned int new_ino_d:13; unsigned int new_ino_d:13;
#ifndef UBIFS_DEBUG
unsigned int dirtied_ino:4; unsigned int dirtied_ino:4;
unsigned int dirtied_ino_d:15; unsigned int dirtied_ino_d:15;
#else #else
/* Not bit-fields to check for overflows */ /* Not bit-fields to check for overflows */
unsigned int new_page;
unsigned int dirtied_page;
unsigned int new_dent;
unsigned int mod_dent;
unsigned int new_ino;
unsigned int new_ino_d;
unsigned int dirtied_ino; unsigned int dirtied_ino;
unsigned int dirtied_ino_d; unsigned int dirtied_ino_d;
#endif #endif
...@@ -860,13 +871,13 @@ struct ubifs_mount_opts { ...@@ -860,13 +871,13 @@ struct ubifs_mount_opts {
* struct ubifs_info - UBIFS file-system description data structure * struct ubifs_info - UBIFS file-system description data structure
* (per-superblock). * (per-superblock).
* @vfs_sb: VFS @struct super_block object * @vfs_sb: VFS @struct super_block object
* @bdi: backing device info object to make VFS happy and disable readahead * @bdi: backing device info object to make VFS happy and disable read-ahead
* *
* @highest_inum: highest used inode number * @highest_inum: highest used inode number
* @vfs_gen: VFS inode generation counter
* @max_sqnum: current global sequence number * @max_sqnum: current global sequence number
* @cmt_no: commit number (last successfully completed commit) * @cmt_no: commit number of the last successfully completed commit, protected
* @cnt_lock: protects @highest_inum, @vfs_gen, and @max_sqnum counters * by @commit_sem
* @cnt_lock: protects @highest_inum and @max_sqnum counters
* @fmt_version: UBIFS on-flash format version * @fmt_version: UBIFS on-flash format version
* @uuid: UUID from super block * @uuid: UUID from super block
* *
...@@ -1103,7 +1114,6 @@ struct ubifs_info { ...@@ -1103,7 +1114,6 @@ struct ubifs_info {
struct backing_dev_info bdi; struct backing_dev_info bdi;
ino_t highest_inum; ino_t highest_inum;
unsigned int vfs_gen;
unsigned long long max_sqnum; unsigned long long max_sqnum;
unsigned long long cmt_no; unsigned long long cmt_no;
spinlock_t cnt_lock; spinlock_t cnt_lock;
...@@ -1346,6 +1356,7 @@ extern struct backing_dev_info ubifs_backing_dev_info; ...@@ -1346,6 +1356,7 @@ extern struct backing_dev_info ubifs_backing_dev_info;
extern struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT]; extern struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];
/* io.c */ /* io.c */
void ubifs_ro_mode(struct ubifs_info *c, int err);
int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len); int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len);
int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs, int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs,
int dtype); int dtype);
...@@ -1399,8 +1410,8 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir, ...@@ -1399,8 +1410,8 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
int deletion, int xent); int deletion, int xent);
int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode, int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
const union ubifs_key *key, const void *buf, int len); const union ubifs_key *key, const void *buf, int len);
int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode, int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode);
int last_reference); int ubifs_jnl_delete_inode(struct ubifs_info *c, const struct inode *inode);
int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir, int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
const struct dentry *old_dentry, const struct dentry *old_dentry,
const struct inode *new_dir, const struct inode *new_dir,
......
...@@ -61,7 +61,7 @@ ...@@ -61,7 +61,7 @@
/* /*
* Limit the number of extended attributes per inode so that the total size * Limit the number of extended attributes per inode so that the total size
* (xattr_size) is guaranteeded to fit in an 'unsigned int'. * (@xattr_size) is guaranteeded to fit in an 'unsigned int'.
*/ */
#define MAX_XATTRS_PER_INODE 65535 #define MAX_XATTRS_PER_INODE 65535
...@@ -103,14 +103,14 @@ static int create_xattr(struct ubifs_info *c, struct inode *host, ...@@ -103,14 +103,14 @@ static int create_xattr(struct ubifs_info *c, struct inode *host,
struct inode *inode; struct inode *inode;
struct ubifs_inode *ui, *host_ui = ubifs_inode(host); struct ubifs_inode *ui, *host_ui = ubifs_inode(host);
struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
.new_ino_d = size, .dirtied_ino = 1, .new_ino_d = ALIGN(size, 8), .dirtied_ino = 1,
.dirtied_ino_d = host_ui->data_len}; .dirtied_ino_d = ALIGN(host_ui->data_len, 8) };
if (host_ui->xattr_cnt >= MAX_XATTRS_PER_INODE) if (host_ui->xattr_cnt >= MAX_XATTRS_PER_INODE)
return -ENOSPC; return -ENOSPC;
/* /*
* Linux limits the maximum size of the extended attribute names list * Linux limits the maximum size of the extended attribute names list
* to %XATTR_LIST_MAX. This means we should not allow creating more* * to %XATTR_LIST_MAX. This means we should not allow creating more
* extended attributes if the name list becomes larger. This limitation * extended attributes if the name list becomes larger. This limitation
* is artificial for UBIFS, though. * is artificial for UBIFS, though.
*/ */
...@@ -128,7 +128,6 @@ static int create_xattr(struct ubifs_info *c, struct inode *host, ...@@ -128,7 +128,6 @@ static int create_xattr(struct ubifs_info *c, struct inode *host,
goto out_budg; goto out_budg;
} }
mutex_lock(&host_ui->ui_mutex);
/* Re-define all operations to be "nothing" */ /* Re-define all operations to be "nothing" */
inode->i_mapping->a_ops = &none_address_operations; inode->i_mapping->a_ops = &none_address_operations;
inode->i_op = &none_inode_operations; inode->i_op = &none_inode_operations;
...@@ -141,23 +140,19 @@ static int create_xattr(struct ubifs_info *c, struct inode *host, ...@@ -141,23 +140,19 @@ static int create_xattr(struct ubifs_info *c, struct inode *host,
ui->data = kmalloc(size, GFP_NOFS); ui->data = kmalloc(size, GFP_NOFS);
if (!ui->data) { if (!ui->data) {
err = -ENOMEM; err = -ENOMEM;
goto out_unlock; goto out_free;
} }
memcpy(ui->data, value, size); memcpy(ui->data, value, size);
inode->i_size = ui->ui_size = size;
ui->data_len = size;
mutex_lock(&host_ui->ui_mutex);
host->i_ctime = ubifs_current_time(host); host->i_ctime = ubifs_current_time(host);
host_ui->xattr_cnt += 1; host_ui->xattr_cnt += 1;
host_ui->xattr_size += CALC_DENT_SIZE(nm->len); host_ui->xattr_size += CALC_DENT_SIZE(nm->len);
host_ui->xattr_size += CALC_XATTR_BYTES(size); host_ui->xattr_size += CALC_XATTR_BYTES(size);
host_ui->xattr_names += nm->len; host_ui->xattr_names += nm->len;
/*
* We do not use i_size_write() because nobody can race with us as we
* are holding host @host->i_mutex - every xattr operation for this
* inode is serialized by it.
*/
inode->i_size = ui->ui_size = size;
ui->data_len = size;
err = ubifs_jnl_update(c, host, nm, inode, 0, 1); err = ubifs_jnl_update(c, host, nm, inode, 0, 1);
if (err) if (err)
goto out_cancel; goto out_cancel;
...@@ -172,8 +167,8 @@ static int create_xattr(struct ubifs_info *c, struct inode *host, ...@@ -172,8 +167,8 @@ static int create_xattr(struct ubifs_info *c, struct inode *host,
host_ui->xattr_cnt -= 1; host_ui->xattr_cnt -= 1;
host_ui->xattr_size -= CALC_DENT_SIZE(nm->len); host_ui->xattr_size -= CALC_DENT_SIZE(nm->len);
host_ui->xattr_size -= CALC_XATTR_BYTES(size); host_ui->xattr_size -= CALC_XATTR_BYTES(size);
out_unlock:
mutex_unlock(&host_ui->ui_mutex); mutex_unlock(&host_ui->ui_mutex);
out_free:
make_bad_inode(inode); make_bad_inode(inode);
iput(inode); iput(inode);
out_budg: out_budg:
...@@ -200,29 +195,28 @@ static int change_xattr(struct ubifs_info *c, struct inode *host, ...@@ -200,29 +195,28 @@ static int change_xattr(struct ubifs_info *c, struct inode *host,
struct ubifs_inode *host_ui = ubifs_inode(host); struct ubifs_inode *host_ui = ubifs_inode(host);
struct ubifs_inode *ui = ubifs_inode(inode); struct ubifs_inode *ui = ubifs_inode(inode);
struct ubifs_budget_req req = { .dirtied_ino = 2, struct ubifs_budget_req req = { .dirtied_ino = 2,
.dirtied_ino_d = size + host_ui->data_len }; .dirtied_ino_d = ALIGN(size, 8) + ALIGN(host_ui->data_len, 8) };
ubifs_assert(ui->data_len == inode->i_size); ubifs_assert(ui->data_len == inode->i_size);
err = ubifs_budget_space(c, &req); err = ubifs_budget_space(c, &req);
if (err) if (err)
return err; return err;
mutex_lock(&host_ui->ui_mutex);
host->i_ctime = ubifs_current_time(host);
host_ui->xattr_size -= CALC_XATTR_BYTES(ui->data_len);
host_ui->xattr_size += CALC_XATTR_BYTES(size);
kfree(ui->data); kfree(ui->data);
ui->data = kmalloc(size, GFP_NOFS); ui->data = kmalloc(size, GFP_NOFS);
if (!ui->data) { if (!ui->data) {
err = -ENOMEM; err = -ENOMEM;
goto out_unlock; goto out_free;
} }
memcpy(ui->data, value, size); memcpy(ui->data, value, size);
inode->i_size = ui->ui_size = size; inode->i_size = ui->ui_size = size;
ui->data_len = size; ui->data_len = size;
mutex_lock(&host_ui->ui_mutex);
host->i_ctime = ubifs_current_time(host);
host_ui->xattr_size -= CALC_XATTR_BYTES(ui->data_len);
host_ui->xattr_size += CALC_XATTR_BYTES(size);
/* /*
* It is important to write the host inode after the xattr inode * It is important to write the host inode after the xattr inode
* because if the host inode gets synchronized (via 'fsync()'), then * because if the host inode gets synchronized (via 'fsync()'), then
...@@ -240,9 +234,9 @@ static int change_xattr(struct ubifs_info *c, struct inode *host, ...@@ -240,9 +234,9 @@ static int change_xattr(struct ubifs_info *c, struct inode *host,
out_cancel: out_cancel:
host_ui->xattr_size -= CALC_XATTR_BYTES(size); host_ui->xattr_size -= CALC_XATTR_BYTES(size);
host_ui->xattr_size += CALC_XATTR_BYTES(ui->data_len); host_ui->xattr_size += CALC_XATTR_BYTES(ui->data_len);
make_bad_inode(inode);
out_unlock:
mutex_unlock(&host_ui->ui_mutex); mutex_unlock(&host_ui->ui_mutex);
make_bad_inode(inode);
out_free:
ubifs_release_budget(c, &req); ubifs_release_budget(c, &req);
return err; return err;
} }
...@@ -312,6 +306,7 @@ int ubifs_setxattr(struct dentry *dentry, const char *name, ...@@ -312,6 +306,7 @@ int ubifs_setxattr(struct dentry *dentry, const char *name,
dbg_gen("xattr '%s', host ino %lu ('%.*s'), size %zd", name, dbg_gen("xattr '%s', host ino %lu ('%.*s'), size %zd", name,
host->i_ino, dentry->d_name.len, dentry->d_name.name, size); host->i_ino, dentry->d_name.len, dentry->d_name.name, size);
ubifs_assert(mutex_is_locked(&host->i_mutex));
if (size > UBIFS_MAX_INO_DATA) if (size > UBIFS_MAX_INO_DATA)
return -ERANGE; return -ERANGE;
...@@ -384,7 +379,6 @@ ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf, ...@@ -384,7 +379,6 @@ ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf,
if (!xent) if (!xent)
return -ENOMEM; return -ENOMEM;
mutex_lock(&host->i_mutex);
xent_key_init(c, &key, host->i_ino, &nm); xent_key_init(c, &key, host->i_ino, &nm);
err = ubifs_tnc_lookup_nm(c, &key, xent, &nm); err = ubifs_tnc_lookup_nm(c, &key, xent, &nm);
if (err) { if (err) {
...@@ -419,7 +413,6 @@ ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf, ...@@ -419,7 +413,6 @@ ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf,
out_iput: out_iput:
iput(inode); iput(inode);
out_unlock: out_unlock:
mutex_unlock(&host->i_mutex);
kfree(xent); kfree(xent);
return err; return err;
} }
...@@ -449,8 +442,6 @@ ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size) ...@@ -449,8 +442,6 @@ ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size)
return -ERANGE; return -ERANGE;
lowest_xent_key(c, &key, host->i_ino); lowest_xent_key(c, &key, host->i_ino);
mutex_lock(&host->i_mutex);
while (1) { while (1) {
int type; int type;
...@@ -479,7 +470,6 @@ ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size) ...@@ -479,7 +470,6 @@ ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size)
pxent = xent; pxent = xent;
key_read(c, &xent->key, &key); key_read(c, &xent->key, &key);
} }
mutex_unlock(&host->i_mutex);
kfree(pxent); kfree(pxent);
if (err != -ENOENT) { if (err != -ENOENT) {
...@@ -497,8 +487,8 @@ static int remove_xattr(struct ubifs_info *c, struct inode *host, ...@@ -497,8 +487,8 @@ static int remove_xattr(struct ubifs_info *c, struct inode *host,
int err; int err;
struct ubifs_inode *host_ui = ubifs_inode(host); struct ubifs_inode *host_ui = ubifs_inode(host);
struct ubifs_inode *ui = ubifs_inode(inode); struct ubifs_inode *ui = ubifs_inode(inode);
struct ubifs_budget_req req = { .dirtied_ino = 1, .mod_dent = 1, struct ubifs_budget_req req = { .dirtied_ino = 2, .mod_dent = 1,
.dirtied_ino_d = host_ui->data_len }; .dirtied_ino_d = ALIGN(host_ui->data_len, 8) };
ubifs_assert(ui->data_len == inode->i_size); ubifs_assert(ui->data_len == inode->i_size);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment