As Hugh suggested, with FALLOC_FL_PUNCH_HOLE, we can use do_fallocate() to implement madvise_remove and finally remove .truncate_range call back. Cc: Hugh Dickins <hughd@xxxxxxxxxx> Cc: Al Viro <viro@xxxxxxxxxxxxxxxxxx> Cc: Christoph Hellwig <hch@xxxxxx> Signed-off-by: WANG Cong <amwang@xxxxxxxxxx> --- include/linux/fs.h | 1 - include/linux/mm.h | 3 ++- mm/madvise.c | 8 +++++--- mm/shmem.c | 1 - mm/truncate.c | 21 +++++++++++++-------- 5 files changed, 20 insertions(+), 14 deletions(-) diff --git a/include/linux/fs.h b/include/linux/fs.h index e313022..266df73 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1635,7 +1635,6 @@ struct inode_operations { ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t); ssize_t (*listxattr) (struct dentry *, char *, size_t); int (*removexattr) (struct dentry *, const char *); - void (*truncate_range)(struct inode *, loff_t, loff_t); int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, u64 len); } ____cacheline_aligned; diff --git a/include/linux/mm.h b/include/linux/mm.h index 3dc3a8c..a47f744 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -951,7 +951,8 @@ static inline void unmap_shared_mapping_range(struct address_space *mapping, extern void truncate_pagecache(struct inode *inode, loff_t old, loff_t new); extern void truncate_setsize(struct inode *inode, loff_t newsize); extern int vmtruncate(struct inode *inode, loff_t offset); -extern int vmtruncate_range(struct inode *inode, loff_t offset, loff_t end); +extern int vmtruncate_file_range(struct file *file, struct inode *inode, + loff_t offset, loff_t end); int truncate_inode_page(struct address_space *mapping, struct page *page); int generic_error_remove_page(struct address_space *mapping, struct page *page); diff --git a/mm/madvise.c b/mm/madvise.c index 74bf193..05610d3 100644 --- a/mm/madvise.c +++ b/mm/madvise.c @@ -194,7 +194,8 @@ static long madvise_remove(struct vm_area_struct *vma, struct vm_area_struct **prev, unsigned long start, unsigned long end) { - struct address_space *mapping; + struct file *file; + struct inode *inode; loff_t offset, endoff; int error; @@ -211,7 +212,8 @@ static long madvise_remove(struct vm_area_struct *vma, if ((vma->vm_flags & (VM_SHARED|VM_WRITE)) != (VM_SHARED|VM_WRITE)) return -EACCES; - mapping = vma->vm_file->f_mapping; + file = vma->vm_file; + inode = file->f_mapping->host; offset = (loff_t)(start - vma->vm_start) + ((loff_t)vma->vm_pgoff << PAGE_SHIFT); @@ -220,7 +222,7 @@ static long madvise_remove(struct vm_area_struct *vma, /* vmtruncate_range needs to take i_mutex */ up_read(¤t->mm->mmap_sem); - error = vmtruncate_range(mapping->host, offset, endoff); + error = vmtruncate_file_range(file, inode, offset, endoff); down_read(¤t->mm->mmap_sem); return error; } diff --git a/mm/shmem.c b/mm/shmem.c index 65f7a27..fce5667 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -2356,7 +2356,6 @@ static const struct file_operations shmem_file_operations = { static const struct inode_operations shmem_inode_operations = { .setattr = shmem_setattr, - .truncate_range = shmem_truncate_range, #ifdef CONFIG_TMPFS_XATTR .setxattr = shmem_setxattr, .getxattr = shmem_getxattr, diff --git a/mm/truncate.c b/mm/truncate.c index 632b15e..7c46539 100644 --- a/mm/truncate.c +++ b/mm/truncate.c @@ -20,6 +20,7 @@ #include <linux/buffer_head.h> /* grr. try_to_release_page, do_invalidatepage */ #include <linux/cleancache.h> +#include <linux/falloc.h> #include "internal.h" @@ -602,24 +603,28 @@ int vmtruncate(struct inode *inode, loff_t newsize) } EXPORT_SYMBOL(vmtruncate); -int vmtruncate_range(struct inode *inode, loff_t lstart, loff_t lend) +int vmtruncate_file_range(struct file *file, struct inode *inode, + loff_t lstart, loff_t lend) { struct address_space *mapping = inode->i_mapping; loff_t holebegin = round_up(lstart, PAGE_SIZE); loff_t holelen = 1 + lend - holebegin; + int err; - /* - * If the underlying filesystem is not going to provide - * a way to truncate a range of blocks (punch a hole) - - * we should return failure right now. - */ - if (!inode->i_op->truncate_range) + if (!file->f_op->fallocate) return -ENOSYS; mutex_lock(&inode->i_mutex); inode_dio_wait(inode); unmap_mapping_range(mapping, holebegin, holelen, 1); - inode->i_op->truncate_range(inode, lstart, lend); + mutex_unlock(&inode->i_mutex); + + err = do_fallocate(file, FALLOC_FL_KEEP_SIZE|FALLOC_FL_PUNCH_HOLE, + holebegin, holelen); + if (err) + return err; + + mutex_lock(&inode->i_mutex); /* unmap again to remove racily COWed private pages */ unmap_mapping_range(mapping, holebegin, holelen, 1); mutex_unlock(&inode->i_mutex); -- 1.7.4.4 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html