[PATCH 2/3] PMFS: Fix two bugs with last block calculation
Ross Zwisler
ross.zwisler at linux.intel.com
Wed Jun 19 19:56:35 EDT 2013
From: Sanjay Kumar <sanjay.k.kumar at intel.com>
This commit fixes two bugs in the calculation of last block number while
deleting/truncating files.
1) While deleting a file, we were not looking at the PMFS_EOFBLOCKS_FL
flag and checking the size for 0 to determine last_blocknr which caused
last_blocknr to be set to invalid value which in-turn caused crash.
2) When determining the last_blocknr based on file size, we were not
truncating last_blocknr according to the inode's tree height. Sparse
files may have large file sizes (and hence large last_blocknr) but their
tree height may be too small to accomodate such a large file size.
Signed-off-by: Sanjay Kumar <sanjay.k.kumar at intel.com>
Signed-off-by: Ross Zwisler <ross.zwisler at linux.intel.com>
---
fs/pmfs/bbuild.c | 9 ++++++---
fs/pmfs/inode.c | 36 ++++++++++++++++++++++++++++++------
fs/pmfs/pmfs.h | 2 +-
3 files changed, 37 insertions(+), 10 deletions(-)
diff --git a/fs/pmfs/bbuild.c b/fs/pmfs/bbuild.c
index 9405882..71fee7f 100644
--- a/fs/pmfs/bbuild.c
+++ b/fs/pmfs/bbuild.c
@@ -82,8 +82,9 @@ static bool pmfs_can_skip_full_scan(struct super_block *sb)
struct pmfs_inode *pi = pmfs_get_inode(sb, PMFS_BLOCKNODE_IN0);
struct pmfs_super_block *super = pmfs_get_super(sb);
struct pmfs_sb_info *sbi = PMFS_SB(sb);
- u64 root, isize;
+ u64 root;
unsigned int height, btype;
+ unsigned long last_blocknr;
if (!pi->root)
{
@@ -103,12 +104,14 @@ static bool pmfs_can_skip_full_scan(struct super_block *sb)
root = pi->root;
height = pi->height;
btype = pi->i_blk_type;
- isize = le64_to_cpu(pi->i_size);
+ /* pi->i_size can not be zero */
+ last_blocknr = (le64_to_cpu(pi->i_size) - 1) >>
+ pmfs_inode_blk_shift(pi);
/* Clearing the datablock inode */
pmfs_clear_datablock_inode(sb);
- pmfs_free_inode_subtree(sb, root, height, btype, isize);
+ pmfs_free_inode_subtree(sb, root, height, btype, last_blocknr);
return true;
}
diff --git a/fs/pmfs/inode.c b/fs/pmfs/inode.c
index b13560d..4de4238 100644
--- a/fs/pmfs/inode.c
+++ b/fs/pmfs/inode.c
@@ -315,11 +315,10 @@ static int recursive_truncate_blocks(struct super_block *sb, u64 block,
}
unsigned int pmfs_free_inode_subtree(struct super_block *sb,
- u64 root, u32 height, u32 btype, loff_t end)
+ u64 root, u32 height, u32 btype, unsigned long last_blocknr)
{
- unsigned long first_blocknr, last_blocknr;
+ unsigned long first_blocknr;
unsigned int freed;
- unsigned int data_bits = blk_type_to_shift[btype];
bool mpty;
if (!root)
@@ -332,7 +331,6 @@ unsigned int pmfs_free_inode_subtree(struct super_block *sb,
freed = 1;
} else {
first_blocknr = 0;
- last_blocknr = (end - 1) >> data_bits;
freed = recursive_truncate_blocks(sb, root, height, btype,
first_blocknr, last_blocknr, &mpty);
@@ -420,6 +418,18 @@ static inline unsigned long pmfs_inode_count_iblocks (struct super_block *sb,
return (iblocks << (pmfs_inode_blk_shift(pi) - sb->s_blocksize_bits));
}
+/* Support for sparse files: even though pi->i_size may indicate a certain
+ * last_blocknr, it may not be true for sparse files. Specifically, last_blocknr
+ * can not be more than the maximum allowed by the inode's tree height.
+ */
+static inline unsigned long pmfs_sparse_last_blocknr(unsigned int height,
+ unsigned long last_blocknr)
+{
+ if (last_blocknr >= (1UL << (height * META_BLK_SHIFT)))
+ last_blocknr = (1UL << (height * META_BLK_SHIFT)) - 1;
+ return last_blocknr;
+}
+
/*
* Free data blocks from inode in the range start <=> end
*/
@@ -451,6 +461,8 @@ static void __pmfs_truncate_blocks(struct inode *inode, loff_t start,
if (end == 0)
goto end_truncate_blocks;
last_blocknr = (end - 1) >> data_bits;
+ last_blocknr = pmfs_sparse_last_blocknr(pi->height,
+ last_blocknr);
}
if (first_blocknr > last_blocknr)
@@ -996,6 +1008,7 @@ void pmfs_evict_inode(struct inode *inode)
struct super_block *sb = inode->i_sb;
struct pmfs_inode *pi = pmfs_get_inode(sb, inode->i_ino);
u64 root;
+ unsigned long last_blocknr;
unsigned int height, btype;
int err = 0;
@@ -1015,8 +1028,19 @@ void pmfs_evict_inode(struct inode *inode)
if (err)
goto out;
/* then free the blocks from the inode's b-tree */
- pmfs_free_inode_subtree(sb, root, height, btype,
- inode->i_size);
+ if (pi->i_flags & cpu_to_le32(PMFS_EOFBLOCKS_FL)) {
+ last_blocknr = (1UL << (pi->height * META_BLK_SHIFT))
+ - 1;
+ } else {
+ if (likely(inode->i_size))
+ last_blocknr = (inode->i_size - 1) >>
+ pmfs_inode_blk_shift(pi);
+ else
+ last_blocknr = 0;
+ last_blocknr = pmfs_sparse_last_blocknr(pi->height,
+ last_blocknr);
+ }
+ pmfs_free_inode_subtree(sb, root, height, btype, last_blocknr);
inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
inode->i_size = 0;
}
diff --git a/fs/pmfs/pmfs.h b/fs/pmfs/pmfs.h
index 5dbb74c..dbff31d 100644
--- a/fs/pmfs/pmfs.h
+++ b/fs/pmfs/pmfs.h
@@ -133,7 +133,7 @@ extern struct dentry *pmfs_get_parent(struct dentry *child);
/* inode.c */
extern unsigned int pmfs_free_inode_subtree(struct super_block *sb,
- u64 root, u32 height, u32 btype, loff_t end);
+ u64 root, u32 height, u32 btype, unsigned long last_blocknr);
extern int __pmfs_alloc_blocks(pmfs_transaction_t *trans,
struct super_block *sb, struct pmfs_inode *pi,
unsigned long file_blocknr, unsigned int num, bool zero);
--
1.8.2.GIT
More information about the Linux-pmfs
mailing list