From: Andiry Xu <jix...@cs.ucsd.edu> After new log entries are appended to the log, old log entries can be marked invalid to faciliate garbage collection.
Signed-off-by: Andiry Xu <jix...@cs.ucsd.edu> --- fs/nova/log.c | 160 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/nova/log.h | 4 ++ fs/nova/nova.h | 12 +++++ 3 files changed, 176 insertions(+) diff --git a/fs/nova/log.c b/fs/nova/log.c index c8b7d2e..d150f2e 100644 --- a/fs/nova/log.c +++ b/fs/nova/log.c @@ -20,6 +20,88 @@ #include "inode.h" #include "log.h" +static int nova_execute_invalidate_reassign_logentry(struct super_block *sb, + void *entry, enum nova_entry_type type, int reassign, + unsigned int num_free) +{ + struct nova_file_write_entry *fw_entry; + int invalid = 0; + + switch (type) { + case FILE_WRITE: + fw_entry = (struct nova_file_write_entry *)entry; + if (reassign) + fw_entry->reassigned = 1; + if (num_free) + fw_entry->invalid_pages += num_free; + if (fw_entry->invalid_pages == fw_entry->num_pages) + invalid = 1; + break; + case DIR_LOG: + if (reassign) { + ((struct nova_dentry *)entry)->reassigned = 1; + } else { + ((struct nova_dentry *)entry)->invalid = 1; + invalid = 1; + } + break; + case SET_ATTR: + ((struct nova_setattr_logentry *)entry)->invalid = 1; + invalid = 1; + break; + case LINK_CHANGE: + ((struct nova_link_change_entry *)entry)->invalid = 1; + invalid = 1; + break; + default: + break; + } + + if (invalid) { + u64 addr = nova_get_addr_off(NOVA_SB(sb), entry); + + nova_inc_page_invalid_entries(sb, addr); + } + + nova_persist_entry(entry); + return 0; +} + +static int nova_invalidate_reassign_logentry(struct super_block *sb, + void *entry, enum nova_entry_type type, int reassign, + unsigned int num_free) +{ + nova_execute_invalidate_reassign_logentry(sb, entry, type, + reassign, num_free); + return 0; +} + +static int nova_invalidate_logentry(struct super_block *sb, void *entry, + enum nova_entry_type type, unsigned int num_free) +{ + return nova_invalidate_reassign_logentry(sb, entry, type, 0, num_free); +} + +static int nova_reassign_logentry(struct super_block *sb, void *entry, + enum nova_entry_type type) +{ + return nova_invalidate_reassign_logentry(sb, entry, type, 1, 0); +} + +static inline int nova_invalidate_write_entry(struct super_block *sb, + struct nova_file_write_entry *entry, int reassign, + unsigned int num_free) +{ + if (!entry) + return 0; + + if (num_free == 0 && entry->reassigned == 1) + return 0; + + return nova_invalidate_reassign_logentry(sb, entry, FILE_WRITE, + reassign, num_free); +} + static void nova_update_setattr_entry(struct inode *inode, struct nova_setattr_logentry *entry, struct nova_log_entry_info *entry_info) @@ -279,6 +361,27 @@ static int nova_append_setattr_entry(struct super_block *sb, return ret; } +/* Invalidate old setattr entry */ +static int nova_invalidate_setattr_entry(struct super_block *sb, + u64 last_setattr) +{ + struct nova_setattr_logentry *old_entry; + void *addr; + int ret; + + addr = (void *)nova_get_block(sb, last_setattr); + old_entry = (struct nova_setattr_logentry *)addr; + + /* Do not invalidate setsize entries */ + if (!old_entry_freeable(sb, old_entry->epoch_id) || + (old_entry->attr & ATTR_SIZE)) + return 0; + + ret = nova_invalidate_logentry(sb, old_entry, SET_ATTR, 0); + + return ret; +} + static int nova_can_inplace_update_setattr(struct super_block *sb, struct nova_inode_info_header *sih, u64 epoch_id) { @@ -358,9 +461,35 @@ int nova_handle_setattr_operation(struct super_block *sb, struct inode *inode, nova_update_inode(sb, inode, pi, &update); } + /* Invalidate old setattr entry */ + if (last_setattr) + nova_invalidate_setattr_entry(sb, last_setattr); + return 0; } +/* Invalidate old link change entry */ +int nova_invalidate_link_change_entry(struct super_block *sb, + u64 old_link_change) +{ + struct nova_link_change_entry *old_entry; + void *addr; + int ret; + + if (old_link_change == 0) + return 0; + + addr = (void *)nova_get_block(sb, old_link_change); + old_entry = (struct nova_link_change_entry *)addr; + + if (!old_entry_freeable(sb, old_entry->epoch_id)) + return 0; + + ret = nova_invalidate_logentry(sb, old_entry, LINK_CHANGE, 0); + + return ret; +} + static int nova_can_inplace_update_lcentry(struct super_block *sb, struct nova_inode_info_header *sih, u64 epoch_id) { @@ -481,6 +610,37 @@ int nova_append_file_write_entry(struct super_block *sb, struct nova_inode *pi, return ret; } +/* Create dentry and delete dentry must be invalidated together */ +int nova_invalidate_dentries(struct super_block *sb, + struct nova_inode_update *update) +{ + struct nova_sb_info *sbi = NOVA_SB(sb); + struct nova_dentry *create_dentry; + struct nova_dentry *delete_dentry; + u64 create_curr, delete_curr; + int ret; + + create_dentry = update->create_dentry; + delete_dentry = update->delete_dentry; + + if (!create_dentry) + return 0; + + nova_reassign_logentry(sb, create_dentry, DIR_LOG); + + if (!old_entry_freeable(sb, create_dentry->epoch_id)) + return 0; + + create_curr = nova_get_addr_off(sbi, create_dentry); + delete_curr = nova_get_addr_off(sbi, delete_dentry); + + nova_invalidate_logentry(sb, create_dentry, DIR_LOG, 0); + + ret = nova_invalidate_logentry(sb, delete_dentry, DIR_LOG, 0); + + return ret; +} + int nova_inplace_update_dentry(struct super_block *sb, struct inode *dir, struct nova_dentry *dentry, int link_change, u64 epoch_id) diff --git a/fs/nova/log.h b/fs/nova/log.h index 74891b3..2548083 100644 --- a/fs/nova/log.h +++ b/fs/nova/log.h @@ -367,6 +367,8 @@ static inline int is_dir_init_entry(struct super_block *sb, int nova_handle_setattr_operation(struct super_block *sb, struct inode *inode, struct nova_inode *pi, unsigned int ia_valid, struct iattr *attr, u64 epoch_id); +int nova_invalidate_link_change_entry(struct super_block *sb, + u64 old_link_change); int nova_append_link_change_entry(struct super_block *sb, struct nova_inode *pi, struct inode *inode, struct nova_inode_update *update, u64 *old_linkc, u64 epoch_id); @@ -376,6 +378,8 @@ int nova_inplace_update_write_entry(struct super_block *sb, int nova_append_file_write_entry(struct super_block *sb, struct nova_inode *pi, struct inode *inode, struct nova_file_write_item *item, struct nova_inode_update *update); +int nova_invalidate_dentries(struct super_block *sb, + struct nova_inode_update *update); int nova_inplace_update_dentry(struct super_block *sb, struct inode *dir, struct nova_dentry *dentry, int link_change, u64 epoch_id); diff --git a/fs/nova/nova.h b/fs/nova/nova.h index 03c4991..6cf3c33 100644 --- a/fs/nova/nova.h +++ b/fs/nova/nova.h @@ -328,6 +328,18 @@ struct inode_map { int freed; }; + +/* Old entry is freeable if it is appended after the latest snapshot */ +static inline int old_entry_freeable(struct super_block *sb, u64 epoch_id) +{ + struct nova_sb_info *sbi = NOVA_SB(sb); + + if (epoch_id == sbi->s_epoch_id) + return 1; + + return 0; +} + #include "balloc.h" static inline unsigned long -- 2.7.4