diff options
author | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2008-07-22 06:06:20 -0400 |
---|---|---|
committer | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2008-08-13 04:28:44 -0400 |
commit | de94eb558b542873d3f6f9ede1b8575fb5662248 (patch) | |
tree | 3ba858a1c87870e22886ac3d4774287bbf367131 /fs | |
parent | 014eb04b03202dc75c1c749df4246d98045f5e69 (diff) |
UBIFS: optimize deletions
Every time anything is deleted, UBIFS writes the deletion inode
node twice - once in 'ubifs_jnl_update()' and the second time in
'ubifs_jnl_write_inode()'. However, the second write is not needed
if no commit happened after 'ubifs_jnl_update()'. This patch
checks that condition and avoids writing the deletion inode for
the second time.
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ubifs/journal.c | 60 | ||||
-rw-r--r-- | fs/ubifs/super.c | 6 | ||||
-rw-r--r-- | fs/ubifs/ubifs.h | 12 |
3 files changed, 73 insertions, 5 deletions
diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c index 3bc3fc947099..0bcee7d221e8 100644 --- a/fs/ubifs/journal.c +++ b/fs/ubifs/journal.c | |||
@@ -604,6 +604,7 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir, | |||
604 | release_head(c, BASEHD); | 604 | release_head(c, BASEHD); |
605 | goto out_finish; | 605 | goto out_finish; |
606 | } | 606 | } |
607 | ui->del_cmtno = c->cmt_no; | ||
607 | } | 608 | } |
608 | 609 | ||
609 | err = write_head(c, BASEHD, dent, len, &lnum, &dent_offs, sync); | 610 | err = write_head(c, BASEHD, dent, len, &lnum, &dent_offs, sync); |
@@ -821,6 +822,64 @@ out_free: | |||
821 | } | 822 | } |
822 | 823 | ||
823 | /** | 824 | /** |
825 | * ubifs_jnl_write_inode - delete an inode. | ||
826 | * @c: UBIFS file-system description object | ||
827 | * @inode: inode to delete | ||
828 | * | ||
829 | * This function deletes inode @inode which includes removing it from orphans, | ||
830 | * deleting it from TNC and, in some cases, writing a deletion inode to the | ||
831 | * journal. | ||
832 | * | ||
833 | * When regular file inodes are unlinked or a directory inode is removed, the | ||
834 | * 'ubifs_jnl_update()' function write corresponding deletion inode and | ||
835 | * direntry to the media, and adds the inode to orphans. After this, when the | ||
836 | * last reference to this inode has been dropped, this function is called. In | ||
837 | * general, it has to write one more deletion inode to the media, because if | ||
838 | * a commit happened between 'ubifs_jnl_update()' and | ||
839 | * 'ubifs_jnl_delete_inode()', the deletion inode is not in the journal | ||
840 | * anymore, and in fact it might be not on the flash anymore, becouse it might | ||
841 | * have been garbage-collected already. And for optimization reasond UBIFS does | ||
842 | * not read the orphan area if it has been unmounted cleanly, so it would have | ||
843 | * no indication in the journal that there is a deleted inode which has to be | ||
844 | * removed from TNC. | ||
845 | * | ||
846 | * However, if there was no commit between 'ubifs_jnl_update()' and | ||
847 | * 'ubifs_jnl_delete_inode()', then there is no need to write the deletion | ||
848 | * inode to the media for the second time. And this is quite typical case. | ||
849 | * | ||
850 | * This function returns zero in case of success and a negative error code in | ||
851 | * case of failure. | ||
852 | */ | ||
853 | int ubifs_jnl_delete_inode(struct ubifs_info *c, const struct inode *inode) | ||
854 | { | ||
855 | int err; | ||
856 | struct ubifs_inode *ui = ubifs_inode(inode); | ||
857 | |||
858 | ubifs_assert(inode->i_nlink == 0); | ||
859 | |||
860 | if (ui->del_cmtno != c->cmt_no) | ||
861 | /* A commit happened for sure */ | ||
862 | return ubifs_jnl_write_inode(c, inode); | ||
863 | |||
864 | down_read(&c->commit_sem); | ||
865 | /* | ||
866 | * Check commit number again, because the first test has been done | ||
867 | * without @c->commit_sem, so a commit might have happened. | ||
868 | */ | ||
869 | if (ui->del_cmtno != c->cmt_no) { | ||
870 | up_read(&c->commit_sem); | ||
871 | return ubifs_jnl_write_inode(c, inode); | ||
872 | } | ||
873 | |||
874 | ubifs_delete_orphan(c, inode->i_ino); | ||
875 | err = ubifs_tnc_remove_ino(c, inode->i_ino); | ||
876 | if (err) | ||
877 | ubifs_ro_mode(c, err); | ||
878 | up_read(&c->commit_sem); | ||
879 | return err; | ||
880 | } | ||
881 | |||
882 | /** | ||
824 | * ubifs_jnl_rename - rename a directory entry. | 883 | * ubifs_jnl_rename - rename a directory entry. |
825 | * @c: UBIFS file-system description object | 884 | * @c: UBIFS file-system description object |
826 | * @old_dir: parent inode of directory entry to rename | 885 | * @old_dir: parent inode of directory entry to rename |
@@ -928,6 +987,7 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir, | |||
928 | release_head(c, BASEHD); | 987 | release_head(c, BASEHD); |
929 | goto out_finish; | 988 | goto out_finish; |
930 | } | 989 | } |
990 | new_ui->del_cmtno = c->cmt_no; | ||
931 | } | 991 | } |
932 | 992 | ||
933 | err = write_head(c, BASEHD, dent, len, &lnum, &offs, sync); | 993 | err = write_head(c, BASEHD, dent, len, &lnum, &offs, sync); |
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index cf1fb6cffa09..6cc4175f23c1 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c | |||
@@ -341,13 +341,15 @@ static void ubifs_delete_inode(struct inode *inode) | |||
341 | goto out; | 341 | goto out; |
342 | 342 | ||
343 | ui->ui_size = inode->i_size = 0; | 343 | ui->ui_size = inode->i_size = 0; |
344 | err = ubifs_jnl_write_inode(c, inode); | 344 | err = ubifs_jnl_delete_inode(c, inode); |
345 | if (err) | 345 | if (err) |
346 | /* | 346 | /* |
347 | * Worst case we have a lost orphan inode wasting space, so a | 347 | * Worst case we have a lost orphan inode wasting space, so a |
348 | * simple error message is ok here. | 348 | * simple error message is ok here. |
349 | */ | 349 | */ |
350 | ubifs_err("can't write inode %lu, error %d", inode->i_ino, err); | 350 | ubifs_err("can't delete inode %lu, error %d", |
351 | inode->i_ino, err); | ||
352 | |||
351 | out: | 353 | out: |
352 | if (ui->dirty) | 354 | if (ui->dirty) |
353 | ubifs_release_dirty_inode_budget(c, ui); | 355 | ubifs_release_dirty_inode_budget(c, ui); |
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h index 21502b6040f0..dfb4b93614ff 100644 --- a/fs/ubifs/ubifs.h +++ b/fs/ubifs/ubifs.h | |||
@@ -322,6 +322,8 @@ struct ubifs_gced_idx_leb { | |||
322 | * struct ubifs_inode - UBIFS in-memory inode description. | 322 | * struct ubifs_inode - UBIFS in-memory inode description. |
323 | * @vfs_inode: VFS inode description object | 323 | * @vfs_inode: VFS inode description object |
324 | * @creat_sqnum: sequence number at time of creation | 324 | * @creat_sqnum: sequence number at time of creation |
325 | * @del_cmtno: commit number corresponding to the time the inode was deleted, | ||
326 | * protected by @c->commit_sem; | ||
325 | * @xattr_size: summarized size of all extended attributes in bytes | 327 | * @xattr_size: summarized size of all extended attributes in bytes |
326 | * @xattr_cnt: count of extended attributes this inode has | 328 | * @xattr_cnt: count of extended attributes this inode has |
327 | * @xattr_names: sum of lengths of all extended attribute names belonging to | 329 | * @xattr_names: sum of lengths of all extended attribute names belonging to |
@@ -372,7 +374,10 @@ struct ubifs_gced_idx_leb { | |||
372 | */ | 374 | */ |
373 | struct ubifs_inode { | 375 | struct ubifs_inode { |
374 | struct inode vfs_inode; | 376 | struct inode vfs_inode; |
375 | unsigned long long creat_sqnum; | 377 | union { |
378 | unsigned long long creat_sqnum; | ||
379 | unsigned long long del_cmtno; | ||
380 | }; | ||
376 | unsigned int xattr_size; | 381 | unsigned int xattr_size; |
377 | unsigned int xattr_cnt; | 382 | unsigned int xattr_cnt; |
378 | unsigned int xattr_names; | 383 | unsigned int xattr_names; |
@@ -779,7 +784,7 @@ struct ubifs_compressor { | |||
779 | /** | 784 | /** |
780 | * struct ubifs_budget_req - budget requirements of an operation. | 785 | * struct ubifs_budget_req - budget requirements of an operation. |
781 | * | 786 | * |
782 | * @fast: non-zero if the budgeting should try to aquire budget quickly and | 787 | * @fast: non-zero if the budgeting should try to acquire budget quickly and |
783 | * should not try to call write-back | 788 | * should not try to call write-back |
784 | * @recalculate: non-zero if @idx_growth, @data_growth, and @dd_growth fields | 789 | * @recalculate: non-zero if @idx_growth, @data_growth, and @dd_growth fields |
785 | * have to be re-calculated | 790 | * have to be re-calculated |
@@ -860,7 +865,7 @@ struct ubifs_mount_opts { | |||
860 | * struct ubifs_info - UBIFS file-system description data structure | 865 | * struct ubifs_info - UBIFS file-system description data structure |
861 | * (per-superblock). | 866 | * (per-superblock). |
862 | * @vfs_sb: VFS @struct super_block object | 867 | * @vfs_sb: VFS @struct super_block object |
863 | * @bdi: backing device info object to make VFS happy and disable readahead | 868 | * @bdi: backing device info object to make VFS happy and disable read-ahead |
864 | * | 869 | * |
865 | * @highest_inum: highest used inode number | 870 | * @highest_inum: highest used inode number |
866 | * @vfs_gen: VFS inode generation counter | 871 | * @vfs_gen: VFS inode generation counter |
@@ -1402,6 +1407,7 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir, | |||
1402 | int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode, | 1407 | int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode, |
1403 | const union ubifs_key *key, const void *buf, int len); | 1408 | const union ubifs_key *key, const void *buf, int len); |
1404 | int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode); | 1409 | int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode); |
1410 | int ubifs_jnl_delete_inode(struct ubifs_info *c, const struct inode *inode); | ||
1405 | int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir, | 1411 | int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir, |
1406 | const struct dentry *old_dentry, | 1412 | const struct dentry *old_dentry, |
1407 | const struct inode *new_dir, | 1413 | const struct inode *new_dir, |