[PATCH 2/2] fs: wire up .truncate_range and .fallocate
From: Cong Wang <hidden>
Date: 2011-11-23 08:53:31
Also in:
linux-fsdevel, lkml
Subsystem:
filesystems (vfs and infrastructure), memory management, memory management - core, memory mapping - madvise (memory advice), page cache, the rest, tmpfs (shmem filesystem) · Maintainers:
Alexander Viro, Christian Brauner, Andrew Morton, David Hildenbrand, Liam R. Howlett, Lorenzo Stoakes, Matthew Wilcox, Linus Torvalds, Hugh Dickins
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@google.com> Cc: Al Viro <viro@zeniv.linux.org.uk> Cc: Christoph Hellwig <hch@lst.de> Signed-off-by: WANG Cong <redacted> --- 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, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>