Skip to content

Commit

Permalink
mm: fault feedback #1
Browse files Browse the repository at this point in the history
Change ->fault prototype.  We now return an int, which contains
VM_FAULT_xxx code in the low byte, and FAULT_RET_xxx code in the next byte.
 FAULT_RET_ code tells the VM whether a page was found, whether it has been
locked, and potentially other things.  This is not quite the way he wanted
it yet, but that's changed in the next patch (which requires changes to
arch code).

This means we no longer set VM_CAN_INVALIDATE in the vma in order to say
that a page is locked which requires filemap_nopage to go away (because we
can no longer remain backward compatible without that flag), but we were
going to do that anyway.

struct fault_data is renamed to struct vm_fault as Linus asked. address
is now a void __user * that we should firmly encourage drivers not to use
without really good reason.

The page is now returned via a page pointer in the vm_fault struct.

Signed-off-by: Nick Piggin <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
Nick Piggin authored and Linus Torvalds committed Jul 19, 2007
1 parent ed2f2f9 commit d0217ac
Show file tree
Hide file tree
Showing 16 changed files with 238 additions and 524 deletions.
20 changes: 1 addition & 19 deletions Documentation/feature-removal-schedule.txt
Original file line number Diff line number Diff line change
Expand Up @@ -135,26 +135,8 @@ Who: Greg Kroah-Hartman <[email protected]>

---------------------------

What: filemap_nopage, filemap_populate
When: April 2007
Why: These legacy interfaces no longer have any callers in the kernel and
any functionality provided can be provided with filemap_fault. The
removal schedule is short because they are a big maintainence burden
and have some bugs.
Who: Nick Piggin <[email protected]>

---------------------------

What: vm_ops.populate, install_page
When: April 2007
Why: These legacy interfaces no longer have any callers in the kernel and
any functionality provided can be provided with vm_ops.fault.
Who: Nick Piggin <[email protected]>

---------------------------

What: vm_ops.nopage
When: February 2008, provided in-kernel callers have been converted
When: Soon, provided in-kernel callers have been converted
Why: This interface is replaced by vm_ops.fault, but it has been around
forever, is used by a lot of drivers, and doesn't cost much to
maintain.
Expand Down
2 changes: 1 addition & 1 deletion Documentation/filesystems/Locking
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,7 @@ More details about quota locking can be found in fs/dquot.c.
prototypes:
void (*open)(struct vm_area_struct*);
void (*close)(struct vm_area_struct*);
struct page *(*fault)(struct vm_area_struct*, struct fault_data *);
int (*fault)(struct vm_area_struct*, struct vm_fault *);
struct page *(*nopage)(struct vm_area_struct*, unsigned long, int *);
int (*page_mkwrite)(struct vm_area_struct *, struct page *);

Expand Down
2 changes: 0 additions & 2 deletions fs/gfs2/ops_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -364,8 +364,6 @@ static int gfs2_mmap(struct file *file, struct vm_area_struct *vma)
else
vma->vm_ops = &gfs2_vm_ops_private;

vma->vm_flags |= VM_CAN_INVALIDATE|VM_CAN_NONLINEAR;

gfs2_glock_dq_uninit(&i_gh);

return error;
Expand Down
47 changes: 23 additions & 24 deletions fs/gfs2/ops_vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,12 @@
#include "trans.h"
#include "util.h"

static struct page *gfs2_private_fault(struct vm_area_struct *vma,
struct fault_data *fdata)
static int gfs2_private_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct gfs2_inode *ip = GFS2_I(vma->vm_file->f_mapping->host);

set_bit(GIF_PAGED, &ip->i_flags);
return filemap_fault(vma, fdata);
return filemap_fault(vma, vmf);
}

static int alloc_page_backing(struct gfs2_inode *ip, struct page *page)
Expand Down Expand Up @@ -104,55 +103,55 @@ static int alloc_page_backing(struct gfs2_inode *ip, struct page *page)
return error;
}

static struct page *gfs2_sharewrite_fault(struct vm_area_struct *vma,
struct fault_data *fdata)
static int gfs2_sharewrite_fault(struct vm_area_struct *vma,
struct vm_fault *vmf)
{
struct file *file = vma->vm_file;
struct gfs2_file *gf = file->private_data;
struct gfs2_inode *ip = GFS2_I(file->f_mapping->host);
struct gfs2_holder i_gh;
struct page *result = NULL;
int alloc_required;
int error;
int ret = VM_FAULT_MINOR;

error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh);
if (error)
return NULL;
goto out;

set_bit(GIF_PAGED, &ip->i_flags);
set_bit(GIF_SW_PAGED, &ip->i_flags);

error = gfs2_write_alloc_required(ip,
(u64)fdata->pgoff << PAGE_CACHE_SHIFT,
(u64)vmf->pgoff << PAGE_CACHE_SHIFT,
PAGE_CACHE_SIZE, &alloc_required);
if (error) {
fdata->type = VM_FAULT_OOM; /* XXX: are these right? */
goto out;
ret = VM_FAULT_OOM; /* XXX: are these right? */
goto out_unlock;
}

set_bit(GFF_EXLOCK, &gf->f_flags);
result = filemap_fault(vma, fdata);
ret = filemap_fault(vma, vmf);
clear_bit(GFF_EXLOCK, &gf->f_flags);
if (!result)
goto out;
if (ret & (VM_FAULT_ERROR | FAULT_RET_NOPAGE))
goto out_unlock;

if (alloc_required) {
error = alloc_page_backing(ip, result);
/* XXX: do we need to drop page lock around alloc_page_backing?*/
error = alloc_page_backing(ip, vmf->page);
if (error) {
if (vma->vm_flags & VM_CAN_INVALIDATE)
unlock_page(result);
page_cache_release(result);
fdata->type = VM_FAULT_OOM;
result = NULL;
goto out;
if (ret & FAULT_RET_LOCKED)
unlock_page(vmf->page);
page_cache_release(vmf->page);
ret = VM_FAULT_OOM;
goto out_unlock;
}
set_page_dirty(result);
set_page_dirty(vmf->page);
}

out:
out_unlock:
gfs2_glock_dq_uninit(&i_gh);

return result;
out:
return ret;
}

struct vm_operations_struct gfs2_vm_ops_private = {
Expand Down
38 changes: 19 additions & 19 deletions fs/ncpfs/mmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,33 +24,35 @@

/*
* Fill in the supplied page for mmap
* XXX: how are we excluding truncate/invalidate here? Maybe need to lock
* page?
*/
static struct page* ncp_file_mmap_fault(struct vm_area_struct *area,
struct fault_data *fdata)
static int ncp_file_mmap_fault(struct vm_area_struct *area,
struct vm_fault *vmf)
{
struct file *file = area->vm_file;
struct dentry *dentry = file->f_path.dentry;
struct inode *inode = dentry->d_inode;
struct page* page;
char *pg_addr;
unsigned int already_read;
unsigned int count;
int bufsize;
int pos;
int pos; /* XXX: loff_t ? */

page = alloc_page(GFP_HIGHUSER); /* ncpfs has nothing against high pages
as long as recvmsg and memset works on it */
if (!page) {
fdata->type = VM_FAULT_OOM;
return NULL;
}
pg_addr = kmap(page);
pos = fdata->pgoff << PAGE_SHIFT;
/*
* ncpfs has nothing against high pages as long
* as recvmsg and memset works on it
*/
vmf->page = alloc_page(GFP_HIGHUSER);
if (!vmf->page)
return VM_FAULT_OOM;
pg_addr = kmap(vmf->page);
pos = vmf->pgoff << PAGE_SHIFT;

count = PAGE_SIZE;
if (fdata->address + PAGE_SIZE > area->vm_end) {
if ((unsigned long)vmf->virtual_address + PAGE_SIZE > area->vm_end) {
WARN_ON(1); /* shouldn't happen? */
count = area->vm_end - fdata->address;
count = area->vm_end - (unsigned long)vmf->virtual_address;
}
/* what we can read in one go */
bufsize = NCP_SERVER(inode)->buffer_size;
Expand Down Expand Up @@ -85,17 +87,16 @@ static struct page* ncp_file_mmap_fault(struct vm_area_struct *area,

if (already_read < PAGE_SIZE)
memset(pg_addr + already_read, 0, PAGE_SIZE - already_read);
flush_dcache_page(page);
kunmap(page);
flush_dcache_page(vmf->page);
kunmap(vmf->page);

/*
* If I understand ncp_read_kernel() properly, the above always
* fetches from the network, here the analogue of disk.
* -- wli
*/
fdata->type = VM_FAULT_MAJOR;
count_vm_event(PGMAJFAULT);
return page;
return VM_FAULT_MAJOR;
}

static struct vm_operations_struct ncp_file_mmap =
Expand Down Expand Up @@ -124,7 +125,6 @@ int ncp_mmap(struct file *file, struct vm_area_struct *vma)
return -EFBIG;

vma->vm_ops = &ncp_file_mmap;
vma->vm_flags |= VM_CAN_INVALIDATE;
file_accessed(file);
return 0;
}
30 changes: 14 additions & 16 deletions fs/ocfs2/mmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,30 +60,28 @@ static inline int ocfs2_vm_op_unblock_sigs(sigset_t *oldset)
return sigprocmask(SIG_SETMASK, oldset, NULL);
}

static struct page *ocfs2_fault(struct vm_area_struct *area,
struct fault_data *fdata)
static int ocfs2_fault(struct vm_area_struct *area, struct vm_fault *vmf)
{
struct page *page = NULL;
sigset_t blocked, oldset;
int ret;
int error, ret;

mlog_entry("(area=%p, page offset=%lu)\n", area, fdata->pgoff);
mlog_entry("(area=%p, page offset=%lu)\n", area, vmf->pgoff);

ret = ocfs2_vm_op_block_sigs(&blocked, &oldset);
if (ret < 0) {
fdata->type = VM_FAULT_SIGBUS;
mlog_errno(ret);
error = ocfs2_vm_op_block_sigs(&blocked, &oldset);
if (error < 0) {
mlog_errno(error);
ret = VM_FAULT_SIGBUS;
goto out;
}

page = filemap_fault(area, fdata);
ret = filemap_fault(area, vmf);

ret = ocfs2_vm_op_unblock_sigs(&oldset);
if (ret < 0)
mlog_errno(ret);
error = ocfs2_vm_op_unblock_sigs(&oldset);
if (error < 0)
mlog_errno(error);
out:
mlog_exit_ptr(page);
return page;
mlog_exit_ptr(vmf->page);
return ret;
}

static int __ocfs2_page_mkwrite(struct inode *inode, struct buffer_head *di_bh,
Expand Down Expand Up @@ -225,7 +223,7 @@ int ocfs2_mmap(struct file *file, struct vm_area_struct *vma)
ocfs2_meta_unlock(file->f_dentry->d_inode, lock_level);
out:
vma->vm_ops = &ocfs2_file_vm_ops;
vma->vm_flags |= VM_CAN_INVALIDATE | VM_CAN_NONLINEAR;
vma->vm_flags |= VM_CAN_NONLINEAR;
return 0;
}

14 changes: 6 additions & 8 deletions fs/xfs/linux-2.6/xfs_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -212,20 +212,18 @@ xfs_file_fsync(
}

#ifdef CONFIG_XFS_DMAPI
STATIC struct page *
STATIC int
xfs_vm_fault(
struct vm_area_struct *vma,
struct fault_data *fdata)
struct vm_fault *vmf)
{
struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
bhv_vnode_t *vp = vn_from_inode(inode);

ASSERT_ALWAYS(vp->v_vfsp->vfs_flag & VFS_DMI);
if (XFS_SEND_MMAP(XFS_VFSTOM(vp->v_vfsp), vma, 0)) {
fdata->type = VM_FAULT_SIGBUS;
return NULL;
}
return filemap_fault(vma, fdata);
if (XFS_SEND_MMAP(XFS_VFSTOM(vp->v_vfsp), vma, 0))
return VM_FAULT_SIGBUS;
return filemap_fault(vma, vmf);
}
#endif /* CONFIG_XFS_DMAPI */

Expand Down Expand Up @@ -311,7 +309,7 @@ xfs_file_mmap(
struct vm_area_struct *vma)
{
vma->vm_ops = &xfs_file_vm_ops;
vma->vm_flags |= VM_CAN_INVALIDATE | VM_CAN_NONLINEAR;
vma->vm_flags |= VM_CAN_NONLINEAR;

#ifdef CONFIG_XFS_DMAPI
if (vn_from_inode(filp->f_path.dentry->d_inode)->v_vfsp->vfs_flag & VFS_DMI)
Expand Down
Loading

0 comments on commit d0217ac

Please sign in to comment.