diff --git a/kmod/src/counters.h b/kmod/src/counters.h index adae0a23..bd22c0ab 100644 --- a/kmod/src/counters.h +++ b/kmod/src/counters.h @@ -30,6 +30,7 @@ EXPAND_COUNTER(corrupt_dirent_backref_name_len) \ EXPAND_COUNTER(corrupt_dirent_name_len) \ EXPAND_COUNTER(corrupt_dirent_readdir_name_len) \ + EXPAND_COUNTER(corrupt_inode_block_counts) \ EXPAND_COUNTER(corrupt_symlink_inode_size) \ EXPAND_COUNTER(corrupt_symlink_missing_item) \ EXPAND_COUNTER(corrupt_symlink_not_null_term) \ diff --git a/kmod/src/format.h b/kmod/src/format.h index 3cefe482..012a6b70 100644 --- a/kmod/src/format.h +++ b/kmod/src/format.h @@ -658,6 +658,7 @@ enum { SC_SYMLINK_NOT_NULL_TERM, SC_BTREE_BLOCK_LEVEL, SC_BTREE_NO_CHILD_REF, + SC_INODE_BLOCK_COUNTS, SC_NR_SOURCES, }; diff --git a/kmod/src/inode.c b/kmod/src/inode.c index 2812ae25..726f4483 100644 --- a/kmod/src/inode.c +++ b/kmod/src/inode.c @@ -500,32 +500,32 @@ void scoutfs_inode_inc_data_version(struct inode *inode) preempt_enable(); } -static void add_seq_value(struct scoutfs_inode_info *si, u64 *si_u64, u64 val) -{ - preempt_disable(); - write_seqcount_begin(&si->seqcount); - *si_u64 += val; - write_seqcount_end(&si->seqcount); - preempt_enable(); -} - -void scoutfs_inode_add_online_blocks(struct inode *inode, u64 val) +void scoutfs_inode_add_onoff(struct inode *inode, s64 on, s64 off) { struct scoutfs_inode_info *si; - if (inode) { + if (inode && (on || off)) { si = SCOUTFS_I(inode); - add_seq_value(si, &SCOUTFS_I(inode)->online_blocks, val); - } -} + preempt_disable(); + write_seqcount_begin(&si->seqcount); -void scoutfs_inode_add_offline_blocks(struct inode *inode, u64 val) -{ - struct scoutfs_inode_info *si; + /* inode and extents out of sync, bad callers */ + if (((s64)si->online_blocks + on < 0) || + ((s64)si->offline_blocks + off < 0)) { + scoutfs_corruption(inode->i_sb, SC_INODE_BLOCK_COUNTS, + corrupt_inode_block_counts, + "ino %llu size %llu online %llu + %lld offline %llu + %lld", + scoutfs_ino(inode), i_size_read(inode), + si->online_blocks, on, si->offline_blocks, off); + } - if (inode) { - si = SCOUTFS_I(inode); - add_seq_value(si, &SCOUTFS_I(inode)->offline_blocks, val); + si->online_blocks += on; + si->offline_blocks += off; + /* XXX not sure if this is right */ + inode->i_blocks += (on + off) * SCOUTFS_BLOCK_SECTORS; + + write_seqcount_end(&si->seqcount); + preempt_enable(); } } @@ -577,6 +577,19 @@ u64 scoutfs_inode_offline_blocks(struct inode *inode) return read_seqcount_u64(inode, &si->offline_blocks); } + +void scoutfs_inode_get_onoff(struct inode *inode, s64 *on, s64 *off) +{ + struct scoutfs_inode_info *si = SCOUTFS_I(inode); + unsigned int seq; + + do { + seq = read_seqcount_begin(&si->seqcount); + *on = SCOUTFS_I(inode)->online_blocks; + *off = SCOUTFS_I(inode)->offline_blocks; + } while (read_seqcount_retry(&si->seqcount, seq)); +} + static int scoutfs_iget_test(struct inode *inode, void *arg) { struct scoutfs_inode_info *ci = SCOUTFS_I(inode); @@ -644,6 +657,10 @@ out: static void store_inode(struct scoutfs_inode *cinode, struct inode *inode) { struct scoutfs_inode_info *ci = SCOUTFS_I(inode); + u64 online_blocks; + u64 offline_blocks; + + scoutfs_inode_get_onoff(inode, &online_blocks, &offline_blocks); cinode->size = cpu_to_le64(i_size_read(inode)); cinode->nlink = cpu_to_le32(inode->i_nlink); @@ -661,9 +678,8 @@ static void store_inode(struct scoutfs_inode *cinode, struct inode *inode) cinode->meta_seq = cpu_to_le64(scoutfs_inode_meta_seq(inode)); cinode->data_seq = cpu_to_le64(scoutfs_inode_data_seq(inode)); cinode->data_version = cpu_to_le64(scoutfs_inode_data_version(inode)); - cinode->online_blocks = cpu_to_le64(scoutfs_inode_online_blocks(inode)); - cinode->offline_blocks = - cpu_to_le64(scoutfs_inode_offline_blocks(inode)); + cinode->online_blocks = cpu_to_le64(online_blocks); + cinode->offline_blocks = cpu_to_le64(offline_blocks); cinode->next_readdir_pos = cpu_to_le64(ci->next_readdir_pos); cinode->next_xattr_id = cpu_to_le64(ci->next_xattr_id); cinode->flags = cpu_to_le32(ci->flags); diff --git a/kmod/src/inode.h b/kmod/src/inode.h index d46f24d1..4dd5f641 100644 --- a/kmod/src/inode.h +++ b/kmod/src/inode.h @@ -102,11 +102,13 @@ void scoutfs_inode_set_data_seq(struct inode *inode); void scoutfs_inode_inc_data_version(struct inode *inode); void scoutfs_inode_add_online_blocks(struct inode *inode, u64 val); void scoutfs_inode_add_offline_blocks(struct inode *inode, u64 val); +void scoutfs_inode_add_onoff(struct inode *inode, s64 on, s64 off); u64 scoutfs_inode_meta_seq(struct inode *inode); u64 scoutfs_inode_data_seq(struct inode *inode); u64 scoutfs_inode_data_version(struct inode *inode); u64 scoutfs_inode_online_blocks(struct inode *inode); u64 scoutfs_inode_offline_blocks(struct inode *inode); +void scoutfs_inode_get_onoff(struct inode *inode, s64 *on, s64 *off); int scoutfs_complete_truncate(struct inode *inode, struct scoutfs_lock *lock); int scoutfs_inode_refresh(struct inode *inode, struct scoutfs_lock *lock, diff --git a/kmod/src/ioctl.c b/kmod/src/ioctl.c index bd135650..206a054d 100644 --- a/kmod/src/ioctl.c +++ b/kmod/src/ioctl.c @@ -464,8 +464,7 @@ static long scoutfs_ioc_stat_more(struct file *file, unsigned long arg) stm.meta_seq = scoutfs_inode_meta_seq(inode); stm.data_seq = scoutfs_inode_data_seq(inode); stm.data_version = scoutfs_inode_data_version(inode); - stm.online_blocks = scoutfs_inode_online_blocks(inode); - stm.offline_blocks = scoutfs_inode_offline_blocks(inode); + scoutfs_inode_get_onoff(inode, &stm.online_blocks, &stm.offline_blocks); if (copy_to_user((void __user *)arg, &stm, stm.valid_bytes)) return -EFAULT;