[V2 PATCH 2/2] fs: wire up .truncate_range and .fallocate
From: Cong Wang <hidden>
Date: 2011-11-29 05:33:13
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
V1->V2: Move tmpfs stuff into shmem_fallocate(), suggested by Christoph. 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: Christoph Hellwig <hch@lst.de> Cc: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: WANG Cong <redacted> --- include/linux/fs.h | 1 - include/linux/mm.h | 2 +- mm/madvise.c | 6 +++--- mm/shmem.c | 12 +++++++++++- mm/truncate.c | 22 +++++----------------- 5 files changed, 20 insertions(+), 23 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..0582ce8 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h@@ -951,7 +951,7 @@ 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, 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..3a281b7 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c@@ -194,7 +194,7 @@ 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; loff_t offset, endoff; int error;
@@ -211,7 +211,7 @@ 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; offset = (loff_t)(start - vma->vm_start) + ((loff_t)vma->vm_pgoff << PAGE_SHIFT);
@@ -220,7 +220,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, offset, endoff); down_read(¤t->mm->mmap_sem); return error; }
diff --git a/mm/shmem.c b/mm/shmem.c
index 90c835b..b435da8 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c@@ -1465,6 +1465,7 @@ static long shmem_fallocate(struct file *file, int mode, loff_t offset, loff_t len) { struct inode *inode = file->f_path.dentry->d_inode; + struct address_space *mapping = file->f_mapping; pgoff_t start = offset >> PAGE_CACHE_SHIFT; pgoff_t end = DIV_ROUND_UP((offset + len), PAGE_CACHE_SIZE); pgoff_t index = start;
@@ -1476,6 +1477,12 @@ static long shmem_fallocate(struct file *file, int mode, return -ETXTBSY; mutex_lock(&inode->i_mutex); + + if (mapping) { + inode_dio_wait(mapping->host); + unmap_mapping_range(mapping, offset, len, 1); + } + i_size = inode->i_size; if (mode & FALLOC_FL_PUNCH_HOLE) { if (!(offset > i_size || (end << PAGE_CACHE_SHIFT) > i_size))
@@ -1507,6 +1514,10 @@ static long shmem_fallocate(struct file *file, int mode, if (!(mode & FALLOC_FL_KEEP_SIZE) && (index << PAGE_CACHE_SHIFT) > i_size) i_size_write(inode, index << PAGE_CACHE_SHIFT); + /* unmap again to remove racily COWed private pages */ + if (mapping) + unmap_mapping_range(mapping, offset, len, 1); + goto unlock; undo:
@@ -2381,7 +2392,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..5a7ddda 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,27 +603,14 @@ 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, 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; - /* - * 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); - /* unmap again to remove racily COWed private pages */ - unmap_mapping_range(mapping, holebegin, holelen, 1); - mutex_unlock(&inode->i_mutex); - - return 0; + return do_fallocate(file, FALLOC_FL_KEEP_SIZE|FALLOC_FL_PUNCH_HOLE, + holebegin, holelen); } --
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>