aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2017-06-15 03:57:46 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2017-06-15 03:57:46 -0400
commita8fad984833832d5ca11a9ed64ddc55646da30e3 (patch)
treefa151e8eb08d478103849e36a65bc350cfe0def1
parent289dec5b895a7ecefb2f49da109e6aed9b0f1754 (diff)
ufs_truncate_blocks(): fix the case when size is in the last direct block
The logics when deciding whether we need to do anything with direct blocks is broken when new size is within the last direct block. It's better to find the path to the last byte _not_ to be removed and use that instead of the path to the beginning of the first block to be freed... Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--fs/ufs/inode.c21
1 files changed, 12 insertions, 9 deletions
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
index 1dda6c4875f9..9f4590261134 100644
--- a/fs/ufs/inode.c
+++ b/fs/ufs/inode.c
@@ -886,7 +886,6 @@ static inline void free_data(struct to_free *ctx, u64 from, unsigned count)
886 ctx->to = from + count; 886 ctx->to = from + count;
887} 887}
888 888
889#define DIRECT_BLOCK ((inode->i_size + uspi->s_bsize - 1) >> uspi->s_bshift)
890#define DIRECT_FRAGMENT ((inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift) 889#define DIRECT_FRAGMENT ((inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift)
891 890
892static void ufs_trunc_direct(struct inode *inode) 891static void ufs_trunc_direct(struct inode *inode)
@@ -1124,19 +1123,24 @@ static void ufs_truncate_blocks(struct inode *inode)
1124 struct super_block *sb = inode->i_sb; 1123 struct super_block *sb = inode->i_sb;
1125 struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; 1124 struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
1126 unsigned offsets[4]; 1125 unsigned offsets[4];
1127 int depth = ufs_block_to_path(inode, DIRECT_BLOCK, offsets); 1126 int depth;
1128 int depth2; 1127 int depth2;
1129 unsigned i; 1128 unsigned i;
1130 struct ufs_buffer_head *ubh[3]; 1129 struct ufs_buffer_head *ubh[3];
1131 void *p; 1130 void *p;
1132 u64 block; 1131 u64 block;
1133 1132
1134 if (!depth) 1133 if (inode->i_size) {
1135 return; 1134 sector_t last = (inode->i_size - 1) >> uspi->s_bshift;
1135 depth = ufs_block_to_path(inode, last, offsets);
1136 if (!depth)
1137 return;
1138 } else {
1139 depth = 1;
1140 }
1136 1141
1137 /* find the last non-zero in offsets[] */
1138 for (depth2 = depth - 1; depth2; depth2--) 1142 for (depth2 = depth - 1; depth2; depth2--)
1139 if (offsets[depth2]) 1143 if (offsets[depth2] != uspi->s_apb - 1)
1140 break; 1144 break;
1141 1145
1142 mutex_lock(&ufsi->truncate_mutex); 1146 mutex_lock(&ufsi->truncate_mutex);
@@ -1145,9 +1149,8 @@ static void ufs_truncate_blocks(struct inode *inode)
1145 offsets[0] = UFS_IND_BLOCK; 1149 offsets[0] = UFS_IND_BLOCK;
1146 } else { 1150 } else {
1147 /* get the blocks that should be partially emptied */ 1151 /* get the blocks that should be partially emptied */
1148 p = ufs_get_direct_data_ptr(uspi, ufsi, offsets[0]); 1152 p = ufs_get_direct_data_ptr(uspi, ufsi, offsets[0]++);
1149 for (i = 0; i < depth2; i++) { 1153 for (i = 0; i < depth2; i++) {
1150 offsets[i]++; /* next branch is fully freed */
1151 block = ufs_data_ptr_to_cpu(sb, p); 1154 block = ufs_data_ptr_to_cpu(sb, p);
1152 if (!block) 1155 if (!block)
1153 break; 1156 break;
@@ -1158,7 +1161,7 @@ static void ufs_truncate_blocks(struct inode *inode)
1158 write_sequnlock(&ufsi->meta_lock); 1161 write_sequnlock(&ufsi->meta_lock);
1159 break; 1162 break;
1160 } 1163 }
1161 p = ubh_get_data_ptr(uspi, ubh[i], offsets[i + 1]); 1164 p = ubh_get_data_ptr(uspi, ubh[i], offsets[i + 1]++);
1162 } 1165 }
1163 while (i--) 1166 while (i--)
1164 free_branch_tail(inode, offsets[i + 1], ubh[i], depth - i - 1); 1167 free_branch_tail(inode, offsets[i + 1], ubh[i], depth - i - 1);