lkml.org 
[lkml]   [2007]   [Sep]   [26]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 22/24] AFS: Implement shared-writable mmap
    Date
    Implement shared-writable mmap for AFS.

    The key with which to access the file is obtained from the VMA at the point
    where the PTE is made writable by the page_mkwrite() VMA op and cached in the
    affected page.

    If there's an outstanding write on the page made with a different key, then
    page_mkwrite() will flush it before attaching a record of the new key.

    Signed-off-by: David Howells <dhowells@redhat.com>
    ---

    fs/afs/file.c | 20 +++++++++++++++++++-
    fs/afs/internal.h | 1 +
    fs/afs/write.c | 35 +++++++++++++++++++++++++++++++++++
    3 files changed, 55 insertions(+), 1 deletions(-)

    diff --git a/fs/afs/file.c b/fs/afs/file.c
    index 525f7c5..1323df4 100644
    --- a/fs/afs/file.c
    +++ b/fs/afs/file.c
    @@ -22,6 +22,7 @@ static int afs_readpage(struct file *file, struct page *page);
    static void afs_invalidatepage(struct page *page, unsigned long offset);
    static int afs_releasepage(struct page *page, gfp_t gfp_flags);
    static int afs_launder_page(struct page *page);
    +static int afs_mmap(struct file *file, struct vm_area_struct *vma);

    const struct file_operations afs_file_operations = {
    .open = afs_open,
    @@ -31,7 +32,7 @@ const struct file_operations afs_file_operations = {
    .write = do_sync_write,
    .aio_read = generic_file_aio_read,
    .aio_write = afs_file_write,
    - .mmap = generic_file_readonly_mmap,
    + .mmap = afs_mmap,
    .splice_read = generic_file_splice_read,
    .fsync = afs_fsync,
    .lock = afs_lock,
    @@ -56,6 +57,11 @@ const struct address_space_operations afs_fs_aops = {
    .writepages = afs_writepages,
    };

    +static struct vm_operations_struct afs_file_vm_ops = {
    + .fault = filemap_fault,
    + .page_mkwrite = afs_page_mkwrite,
    +};
    +
    /*
    * open an AFS file or directory and attach a key to it
    */
    @@ -295,3 +301,15 @@ static int afs_releasepage(struct page *page, gfp_t gfp_flags)
    _leave(" = 0");
    return 0;
    }
    +
    +/*
    + * memory map part of an AFS file
    + */
    +static int afs_mmap(struct file *file, struct vm_area_struct *vma)
    +{
    + _enter("");
    +
    + file_accessed(file);
    + vma->vm_ops = &afs_file_vm_ops;
    + return 0;
    +}
    diff --git a/fs/afs/internal.h b/fs/afs/internal.h
    index e1bcce0..12afccc 100644
    --- a/fs/afs/internal.h
    +++ b/fs/afs/internal.h
    @@ -743,6 +743,7 @@ extern ssize_t afs_file_write(struct kiocb *, const struct iovec *,
    unsigned long, loff_t);
    extern int afs_writeback_all(struct afs_vnode *);
    extern int afs_fsync(struct file *, struct dentry *, int);
    +extern int afs_page_mkwrite(struct vm_area_struct *, struct page *);


    /*****************************************************************************/
    diff --git a/fs/afs/write.c b/fs/afs/write.c
    index ac621e8..dd471f0 100644
    --- a/fs/afs/write.c
    +++ b/fs/afs/write.c
    @@ -155,6 +155,8 @@ static int afs_prepare_page(struct afs_vnode *vnode, struct page *page,
    * prepare to perform part of a write to a page
    * - the caller holds the page locked, preventing it from being written out or
    * modified by anyone else
    + * - may be called from afs_page_mkwrite() to set up a page for modification
    + * through shared-writable mmap
    */
    int afs_prepare_write(struct file *file, struct page *page,
    unsigned offset, unsigned to)
    @@ -833,3 +835,36 @@ int afs_fsync(struct file *file, struct dentry *dentry, int datasync)
    _leave(" = %d", ret);
    return ret;
    }
    +
    +/*
    + * notification that a previously read-only page is about to become writable
    + * - if it returns an error, the caller will deliver a bus error signal
    + *
    + * we use this to make a record of the key with which the writeback should be
    + * performed and to flush any outstanding writes made with a different key
    + *
    + * the key to be used is attached to the struct file pinned by the VMA
    + */
    +int afs_page_mkwrite(struct vm_area_struct *vma, struct page *page)
    +{
    + struct afs_vnode *vnode = AFS_FS_I(vma->vm_file->f_mapping->host);
    + struct key *key = vma->vm_file->private_data;
    + int ret;
    +
    + _enter("{{%x:%u},%x},{%lx}",
    + vnode->fid.vid, vnode->fid.vnode, key_serial(key), page->index);
    +
    + do {
    + lock_page(page);
    + if (page->mapping == vma->vm_file->f_mapping)
    + ret = afs_prepare_write(vma->vm_file, page, 0,
    + PAGE_SIZE);
    + else
    + ret = 0; /* seems there was interference - let the
    + * caller deal with it */
    + unlock_page(page);
    + } while (ret == AOP_TRUNCATED_PAGE);
    +
    + _leave(" = %d", ret);
    + return ret;
    +}
    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2007-09-26 16:37    [W:0.029 / U:0.176 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site