diff mbox

[V9fs-developer,RFC,V2] RFC version of a new cache=mmap model.

Message ID 1379418681-27221-1-git-send-email-dominique.martinet@cea.fr (mailing list archive)
State New, archived
Headers show

Commit Message

Dominique Martinet Sept. 17, 2013, 11:51 a.m. UTC
- Add cache=mmap option
 - Try to keep most operations synchronous

Signed-off-by: Dominique Martinet <dominique.martinet@cea.fr>
---

Changes from V1 to V2:
 - Changed write_inode_now to sync_inode with the specific region
relating the mmap'd area (I'm honestly not sure about bounds, but it
covers at least the area pointed by the vma_struct. There doesn't seem
to be many functions using sync_inode, should I use do_writeback
directly instead? does it still make sense to check
mapping_cap_writeback_dirty on inode mapping when I'm using sync on a
sub-range?)
 - Fixed one v9ses->cache check that kept inodes around in cache

Missing for offering a real patch:
 - I didn't get any reply on what v9fs_fscache_wait_on_page_write
is called for, so mkwrite might still be wrong given it technically
doesn't wait for anything.
 - I originally wanted to open writeback fids at the same places as
the other cache modems, but it does seem like a waste and will move it
to the mmap creation call; a shame to duplicate code but there really
were many unused fids open because of this
 - More complains/comments :)




Original comment:
I brought up the issue of mmap being read-only with cache=none a bit
ago, and worked on it since.

Here's what this patch does:
 - Add an option cache=mmap (or just mmap, like other caches), nothing
changes for default or other caches.
The following assumes cache=mmap.
 - fills in writeback_fid on open (this could be done in
v9fs_file_mmap since we don't enable buffered write either, but I
wanted to keep the code shared with other caches, so we just have
useless writeback fids most of the time)
 - flush mmap data synchronously on munmap (vma->vm_op->close), this
is because we don't want to use the cache for read, so we need the
modifications to take place immediately. I'm not quite sure why I had
to force it, but it's lost otherwise (with buffered reads, you'd read
from the mmap pages anyway and it wouldn't matter if it's flushed
later - this doesn't really work for this case)


What works:
 - msync(addr, length, MS_SYNC) (MS_SYNC might just be the default
behaviour) does sync correctly;
 - munmap does a sync as well, obviously;
 - no msync/msync with MS_ASYNC will eventually flush when the kernel
decides to.

What doesn't:
 - If you want to read a file after writting in a mmap'd section with
no msync (or msync with MS_ASYNC) and no munmap, you will read what
the servers  knows about -- so the old data. With buffered read,
you'd expect the read to find about the map and use it, we don't.
There is, however, what the documentation says so I don't see this as
a bug. What could probably be done would be to check on read if we
have dirty mapped pages and flush them before reading? I'm not too
sure I like this idea.
 - Likewise, if you write with a map open, the map won't be updated
unless something else invalidates it. I guess we should do that like
the direct write function does.


All in all, while I'm unhappy that I had to use write_inode_now() in
vm_ops->close, I would guess it works for what it is (i.e. an unsafe
feature on a networking filesystem); at least it seems better than
returning ENOTSUPP for my own usage, given read mmap isn't much safer
anyway, and that's why it's an option.


There are a few questions/TODO marks and p9_debug lines that could go
away, but figured it probably makes more sense to leave it there for
an RFC patch.
(Also a few lines over 80 characters I'll fix for the real deal)


Comments more than welcome, thanks!


 fs/9p/v9fs.c           |   9 +++-
 fs/9p/v9fs.h           |   1 +
 fs/9p/v9fs_vfs.h       |   2 +
 fs/9p/vfs_addr.c       |   7 +++
 fs/9p/vfs_file.c       | 113 +++++++++++++++++++++++++++++++++++++++++++++++--
 fs/9p/vfs_inode.c      |  17 +++++---
 fs/9p/vfs_inode_dotl.c |   6 +--
 fs/9p/vfs_super.c      |   7 +--
 8 files changed, 146 insertions(+), 16 deletions(-)

Comments

Eric Van Hensbergen Oct. 20, 2013, 9:33 p.m. UTC | #1
I was going to take a look at bringing this in for testing, but my scripts
barfed on style guidelines.  Please run scripts/checkpatch.pl before
submitting to the list.  I realize this was still a work in progress, but
it makes things easier since all my scripts have a workflow to check
against the submissions guidelines.  Thanks...

    -eric



On Tue, Sep 17, 2013 at 6:51 AM, Dominique Martinet <
dominique.martinet@cea.fr> wrote:

>  - Add cache=mmap option
>  - Try to keep most operations synchronous
>
> Signed-off-by: Dominique Martinet <dominique.martinet@cea.fr>
> ---
>
> Changes from V1 to V2:
>  - Changed write_inode_now to sync_inode with the specific region
> relating the mmap'd area (I'm honestly not sure about bounds, but it
> covers at least the area pointed by the vma_struct. There doesn't seem
> to be many functions using sync_inode, should I use do_writeback
> directly instead? does it still make sense to check
> mapping_cap_writeback_dirty on inode mapping when I'm using sync on a
> sub-range?)
>  - Fixed one v9ses->cache check that kept inodes around in cache
>
> Missing for offering a real patch:
>  - I didn't get any reply on what v9fs_fscache_wait_on_page_write
> is called for, so mkwrite might still be wrong given it technically
> doesn't wait for anything.
>  - I originally wanted to open writeback fids at the same places as
> the other cache modems, but it does seem like a waste and will move it
> to the mmap creation call; a shame to duplicate code but there really
> were many unused fids open because of this
>  - More complains/comments :)
>
>
>
>
> Original comment:
> I brought up the issue of mmap being read-only with cache=none a bit
> ago, and worked on it since.
>
> Here's what this patch does:
>  - Add an option cache=mmap (or just mmap, like other caches), nothing
> changes for default or other caches.
> The following assumes cache=mmap.
>  - fills in writeback_fid on open (this could be done in
> v9fs_file_mmap since we don't enable buffered write either, but I
> wanted to keep the code shared with other caches, so we just have
> useless writeback fids most of the time)
>  - flush mmap data synchronously on munmap (vma->vm_op->close), this
> is because we don't want to use the cache for read, so we need the
> modifications to take place immediately. I'm not quite sure why I had
> to force it, but it's lost otherwise (with buffered reads, you'd read
> from the mmap pages anyway and it wouldn't matter if it's flushed
> later - this doesn't really work for this case)
>
>
> What works:
>  - msync(addr, length, MS_SYNC) (MS_SYNC might just be the default
> behaviour) does sync correctly;
>  - munmap does a sync as well, obviously;
>  - no msync/msync with MS_ASYNC will eventually flush when the kernel
> decides to.
>
> What doesn't:
>  - If you want to read a file after writting in a mmap'd section with
> no msync (or msync with MS_ASYNC) and no munmap, you will read what
> the servers  knows about -- so the old data. With buffered read,
> you'd expect the read to find about the map and use it, we don't.
> There is, however, what the documentation says so I don't see this as
> a bug. What could probably be done would be to check on read if we
> have dirty mapped pages and flush them before reading? I'm not too
> sure I like this idea.
>  - Likewise, if you write with a map open, the map won't be updated
> unless something else invalidates it. I guess we should do that like
> the direct write function does.
>
>
> All in all, while I'm unhappy that I had to use write_inode_now() in
> vm_ops->close, I would guess it works for what it is (i.e. an unsafe
> feature on a networking filesystem); at least it seems better than
> returning ENOTSUPP for my own usage, given read mmap isn't much safer
> anyway, and that's why it's an option.
>
>
> There are a few questions/TODO marks and p9_debug lines that could go
> away, but figured it probably makes more sense to leave it there for
> an RFC patch.
> (Also a few lines over 80 characters I'll fix for the real deal)
>
>
> Comments more than welcome, thanks!
>
>
>  fs/9p/v9fs.c           |   9 +++-
>  fs/9p/v9fs.h           |   1 +
>  fs/9p/v9fs_vfs.h       |   2 +
>  fs/9p/vfs_addr.c       |   7 +++
>  fs/9p/vfs_file.c       | 113
> +++++++++++++++++++++++++++++++++++++++++++++++--
>  fs/9p/vfs_inode.c      |  17 +++++---
>  fs/9p/vfs_inode_dotl.c |   6 +--
>  fs/9p/vfs_super.c      |   7 +--
>  8 files changed, 146 insertions(+), 16 deletions(-)
>
> diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
> index 58e6cbc..1a2b0c8 100644
> --- a/fs/9p/v9fs.c
> +++ b/fs/9p/v9fs.c
> @@ -56,7 +56,7 @@ enum {
>         /* Options that take no arguments */
>         Opt_nodevmap,
>         /* Cache options */
> -       Opt_cache_loose, Opt_fscache,
> +       Opt_cache_loose, Opt_fscache, Opt_mmap,
>         /* Access options */
>         Opt_access, Opt_posixacl,
>         /* Error token */
> @@ -74,6 +74,7 @@ static const match_table_t tokens = {
>         {Opt_cache, "cache=%s"},
>         {Opt_cache_loose, "loose"},
>         {Opt_fscache, "fscache"},
> +       {Opt_mmap, "mmap"},
>         {Opt_cachetag, "cachetag=%s"},
>         {Opt_access, "access=%s"},
>         {Opt_posixacl, "posixacl"},
> @@ -91,6 +92,9 @@ static int get_cache_mode(char *s)
>         } else if (!strcmp(s, "fscache")) {
>                 version = CACHE_FSCACHE;
>                 p9_debug(P9_DEBUG_9P, "Cache mode: fscache\n");
> +       } else if (!strcmp(s, "mmap")) {
> +               version = CACHE_MMAP;
> +               p9_debug(P9_DEBUG_9P, "Cache mode: mmap\n");
>         } else if (!strcmp(s, "none")) {
>                 version = CACHE_NONE;
>                 p9_debug(P9_DEBUG_9P, "Cache mode: none\n");
> @@ -220,6 +224,9 @@ static int v9fs_parse_options(struct v9fs_session_info
> *v9ses, char *opts)
>                 case Opt_fscache:
>                         v9ses->cache = CACHE_FSCACHE;
>                         break;
> +               case Opt_mmap:
> +                       v9ses->cache = CACHE_MMAP;
> +                       break;
>                 case Opt_cachetag:
>  #ifdef CONFIG_9P_FSCACHE
>                         v9ses->cachetag = match_strdup(&args[0]);
> diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h
> index a8e127c..099c771 100644
> --- a/fs/9p/v9fs.h
> +++ b/fs/9p/v9fs.h
> @@ -64,6 +64,7 @@ enum p9_session_flags {
>
>  enum p9_cache_modes {
>         CACHE_NONE,
> +       CACHE_MMAP,
>         CACHE_LOOSE,
>         CACHE_FSCACHE,
>  };
> diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h
> index dc95a25..b83ebfb 100644
> --- a/fs/9p/v9fs_vfs.h
> +++ b/fs/9p/v9fs_vfs.h
> @@ -50,6 +50,8 @@ extern const struct dentry_operations
> v9fs_dentry_operations;
>  extern const struct dentry_operations v9fs_cached_dentry_operations;
>  extern const struct file_operations v9fs_cached_file_operations;
>  extern const struct file_operations v9fs_cached_file_operations_dotl;
> +extern const struct file_operations v9fs_mmap_file_operations;
> +extern const struct file_operations v9fs_mmap_file_operations_dotl;
>  extern struct kmem_cache *v9fs_inode_cache;
>
>  struct inode *v9fs_alloc_inode(struct super_block *sb);
> diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c
> index 9ff073f..c71e886 100644
> --- a/fs/9p/vfs_addr.c
> +++ b/fs/9p/vfs_addr.c
> @@ -202,6 +202,8 @@ static int v9fs_vfs_writepage(struct page *page,
> struct writeback_control *wbc)
>  {
>         int retval;
>
> +       p9_debug(P9_DEBUG_VFS, "page %p\n", page);
> +
>         retval = v9fs_vfs_writepage_locked(page);
>         if (retval < 0) {
>                 if (retval == -EAGAIN) {
> @@ -282,6 +284,9 @@ static int v9fs_write_begin(struct file *filp, struct
> address_space *mapping,
>         pgoff_t index = pos >> PAGE_CACHE_SHIFT;
>         struct inode *inode = mapping->host;
>
> +
> +       p9_debug(P9_DEBUG_VFS, "filp %p, mapping %p\n", filp, mapping);
> +
>         v9inode = V9FS_I(inode);
>  start:
>         page = grab_cache_page_write_begin(mapping, index, flags);
> @@ -312,6 +317,8 @@ static int v9fs_write_end(struct file *filp, struct
> address_space *mapping,
>         loff_t last_pos = pos + copied;
>         struct inode *inode = page->mapping->host;
>
> +       p9_debug(P9_DEBUG_VFS, "filp %p, mapping %p\n", filp, mapping);
> +
>         if (unlikely(copied < len)) {
>                 /*
>                  * zero out the rest of the area
> diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
> index d384a8b..ec904ed 100644
> --- a/fs/9p/vfs_file.c
> +++ b/fs/9p/vfs_file.c
> @@ -45,6 +45,7 @@
>  #include "cache.h"
>
>  static const struct vm_operations_struct v9fs_file_vm_ops;
> +static const struct vm_operations_struct v9fs_mmap_file_vm_ops;
>
>  /**
>   * v9fs_file_open - open a file (or directory)
> @@ -106,7 +107,9 @@ int v9fs_file_open(struct inode *inode, struct file
> *file)
>         }
>         mutex_unlock(&v9inode->v_mutex);
>  #ifdef CONFIG_9P_FSCACHE
> -       if (v9ses->cache)
> +       /* previous check would also set cookie with CACHE_LOOSE?
> +        * set_cookie does a check if v9inode->fscache anyway... */
> +       if (v9ses->cache == CACHE_FSCACHE)
>                 v9fs_cache_inode_set_cookie(inode, file);
>  #endif
>         return 0;
> @@ -583,17 +586,33 @@ int v9fs_file_fsync_dotl(struct file *filp, loff_t
> start, loff_t end,
>  }
>
>  static int
> -v9fs_file_mmap(struct file *file, struct vm_area_struct *vma)
> +v9fs_file_mmap(struct file *filp, struct vm_area_struct *vma)
>  {
>         int retval;
>
> -       retval = generic_file_mmap(file, vma);
> +
> +       retval = generic_file_mmap(filp, vma);
>         if (!retval)
>                 vma->vm_ops = &v9fs_file_vm_ops;
>
>         return retval;
>  }
>
> +/* TODO: merge this with the previous function
> + * and set the right vm_ops depending on v9ses->cache */
> +static int
> +v9fs_mmap_file_mmap(struct file *filp, struct vm_area_struct *vma)
> +{
> +       int retval;
> +
> +
> +       retval = generic_file_mmap(filp, vma);
> +       if (!retval)
> +               vma->vm_ops = &v9fs_mmap_file_vm_ops;
> +
> +       return retval;
> +}
> +
>  static int
>  v9fs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
>  {
> @@ -662,6 +681,22 @@ v9fs_cached_file_read(struct file *filp, char __user
> *data, size_t count,
>         return do_sync_read(filp, data, count, offset);
>  }
>
> +/**
> + * v9fs_mmap_file_read - read from a file
> + * @filp: file pointer to read
> + * @udata: user data buffer to read data into
> + * @count: size of buffer
> + * @offset: offset at which to read data
> + *
> + */
> +static ssize_t
> +v9fs_mmap_file_read(struct file *filp, char __user *data, size_t count,
> +                     loff_t *offset)
> +{
> +       /* TODO: Check if there are dirty pages */
> +       return v9fs_file_read(filp, data, count, offset);
> +}
> +
>  static ssize_t
>  v9fs_direct_write(struct file *filp, const char __user * data,
>                   size_t count, loff_t *offsetp)
> @@ -732,12 +767,61 @@ v9fs_cached_file_write(struct file *filp, const char
> __user * data,
>         return do_sync_write(filp, data, count, offset);
>  }
>
> +
> +/**
> + * v9fs_mmap_file_write - write to a file
> + * @filp: file pointer to write
> + * @data: data buffer to write data from
> + * @count: size of buffer
> + * @offset: offset at which to write data
> + *
> + */
> +static ssize_t
> +v9fs_mmap_file_write(struct file *filp, const char __user *data,
> +                      size_t count, loff_t *offset)
> +{
> +       /* TODO: invalidate mmaps on filp's inode between offset and
> offset+count */
> +       return v9fs_file_write(filp, data, count, offset);
> +}
> +
> +static void v9fs_mmap_vm_close(struct vm_area_struct *vma)
> +{
> +        struct inode *inode;
> +
> +       p9_debug(P9_DEBUG_VFS, "9p VMA close, %p, flushing", vma);
> +
> +       struct writeback_control wbc = {
> +               .nr_to_write = LONG_MAX,
> +               .sync_mode = WB_SYNC_ALL,
> +               .range_start = vma->vm_pgoff * PAGE_SIZE,
> +                /* absolute end, byte at end included */
> +               .range_end = vma->vm_pgoff * PAGE_SIZE +
> +                       (vma->vm_end - vma->vm_start - 1),
> +       };
> +
> +       inode = file_inode(vma->vm_file);
> +
> +       if (!mapping_cap_writeback_dirty(inode->i_mapping))
> +               wbc.nr_to_write = 0;
> +
> +       might_sleep();
> +       sync_inode(inode, &wbc);
> +}
> +
> +
>  static const struct vm_operations_struct v9fs_file_vm_ops = {
>         .fault = filemap_fault,
>         .page_mkwrite = v9fs_vm_page_mkwrite,
>         .remap_pages = generic_file_remap_pages,
>  };
>
> +static const struct vm_operations_struct v9fs_mmap_file_vm_ops = {
> +       .close = v9fs_mmap_vm_close,
> +       .fault = filemap_fault,
> +       .page_mkwrite = v9fs_vm_page_mkwrite,
> +       .remap_pages = generic_file_remap_pages,
> +};
> +
>
>  const struct file_operations v9fs_cached_file_operations = {
>         .llseek = generic_file_llseek,
> @@ -788,3 +872,26 @@ const struct file_operations
> v9fs_file_operations_dotl = {
>         .mmap = generic_file_readonly_mmap,
>         .fsync = v9fs_file_fsync_dotl,
>  };
> +
> +const struct file_operations v9fs_mmap_file_operations = {
> +       .llseek = generic_file_llseek,
> +       .read = v9fs_mmap_file_read,
> +       .write = v9fs_mmap_file_write,
> +       .open = v9fs_file_open,
> +       .release = v9fs_dir_release,
> +       .lock = v9fs_file_lock,
> +       .mmap = v9fs_mmap_file_mmap,
> +       .fsync = v9fs_file_fsync,
> +};
> +
> +const struct file_operations v9fs_mmap_file_operations_dotl = {
> +       .llseek = generic_file_llseek,
> +       .read = v9fs_mmap_file_read,
> +       .write = v9fs_mmap_file_write,
> +       .open = v9fs_file_open,
> +       .release = v9fs_dir_release,
> +       .lock = v9fs_file_lock_dotl,
> +       .flock = v9fs_file_flock_dotl,
> +       .mmap = v9fs_mmap_file_mmap,
> +       .fsync = v9fs_file_fsync_dotl,
> +};
> diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
> index 25b018e..d52179c 100644
> --- a/fs/9p/vfs_inode.c
> +++ b/fs/9p/vfs_inode.c
> @@ -299,15 +299,20 @@ int v9fs_init_inode(struct v9fs_session_info *v9ses,
>         case S_IFREG:
>                 if (v9fs_proto_dotl(v9ses)) {
>                         inode->i_op = &v9fs_file_inode_operations_dotl;
> -                       if (v9ses->cache)
> +                       if (v9ses->cache == CACHE_LOOSE || v9ses->cache ==
> CACHE_FSCACHE)
>                                 inode->i_fop =
>                                         &v9fs_cached_file_operations_dotl;
> +                       else if (v9ses->cache == CACHE_MMAP)
> +                               inode->i_fop =
> &v9fs_mmap_file_operations_dotl;
>                         else
>                                 inode->i_fop = &v9fs_file_operations_dotl;
>                 } else {
>                         inode->i_op = &v9fs_file_inode_operations;
> -                       if (v9ses->cache)
> -                               inode->i_fop =
> &v9fs_cached_file_operations;
> +                       if (v9ses->cache == CACHE_LOOSE || v9ses->cache ==
> CACHE_FSCACHE)
> +                               inode->i_fop =
> +                                       &v9fs_cached_file_operations;
> +                       else if (v9ses->cache == CACHE_MMAP)
> +                               inode->i_fop = &v9fs_mmap_file_operations;
>                         else
>                                 inode->i_fop = &v9fs_file_operations;
>                 }
> @@ -816,7 +821,7 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir,
> struct dentry *dentry,
>          * unlink. For cached mode create calls request for new
>          * inode. But with cache disabled, lookup should do this.
>          */
> -       if (v9ses->cache)
> +       if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
>                 inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb);
>         else
>                 inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
> @@ -906,7 +911,7 @@ v9fs_vfs_atomic_open(struct inode *dir, struct dentry
> *dentry,
>
>         file->private_data = fid;
>  #ifdef CONFIG_9P_FSCACHE
> -       if (v9ses->cache)
> +       if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
>                 v9fs_cache_inode_set_cookie(dentry->d_inode, file);
>  #endif
>
> @@ -1485,7 +1490,7 @@ int v9fs_refresh_inode(struct p9_fid *fid, struct
> inode *inode)
>          */
>         i_size = inode->i_size;
>         v9fs_stat2inode(st, inode, inode->i_sb);
> -       if (v9ses->cache)
> +       if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
>                 inode->i_size = i_size;
>         spin_unlock(&inode->i_lock);
>  out:
> diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c
> index 53687bb..710d5c6 100644
> --- a/fs/9p/vfs_inode_dotl.c
> +++ b/fs/9p/vfs_inode_dotl.c
> @@ -362,7 +362,7 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct
> dentry *dentry,
>                 goto err_clunk_old_fid;
>         file->private_data = ofid;
>  #ifdef CONFIG_9P_FSCACHE
> -       if (v9ses->cache)
> +       if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
>                 v9fs_cache_inode_set_cookie(inode, file);
>  #endif
>         *opened |= FILE_CREATED;
> @@ -725,7 +725,7 @@ v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry
> *dentry,
>         }
>
>         v9fs_invalidate_inode_attr(dir);
> -       if (v9ses->cache) {
> +       if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
>                 /* Now walk from the parent so we can get an unopened fid.
> */
>                 fid = p9_client_walk(dfid, 1, &name, 1);
>                 if (IS_ERR(fid)) {
> @@ -983,7 +983,7 @@ int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct
> inode *inode)
>          */
>         i_size = inode->i_size;
>         v9fs_stat2inode_dotl(st, inode);
> -       if (v9ses->cache)
> +       if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
>                 inode->i_size = i_size;
>         spin_unlock(&inode->i_lock);
>  out:
> diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
> index 2756dcd..a4dd162 100644
> --- a/fs/9p/vfs_super.c
> +++ b/fs/9p/vfs_super.c
> @@ -144,7 +144,7 @@ static struct dentry *v9fs_mount(struct
> file_system_type *fs_type, int flags,
>         }
>         v9fs_fill_super(sb, v9ses, flags, data);
>
> -       if (v9ses->cache)
> +       if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
>                 sb->s_d_op = &v9fs_cached_dentry_operations;
>         else
>                 sb->s_d_op = &v9fs_dentry_operations;
> @@ -282,7 +282,7 @@ static int v9fs_drop_inode(struct inode *inode)
>  {
>         struct v9fs_session_info *v9ses;
>         v9ses = v9fs_inode2v9ses(inode);
> -       if (v9ses->cache)
> +       if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
>                 return generic_drop_inode(inode);
>         /*
>          * in case of non cached mode always drop the
> @@ -325,10 +325,11 @@ static int v9fs_write_inode_dotl(struct inode *inode,
>          * send an fsync request to server irrespective of
>          * wbc->sync_mode.
>          */
> -       p9_debug(P9_DEBUG_VFS, "%s: inode %p\n", __func__, inode);
>         v9inode = V9FS_I(inode);
> +       p9_debug(P9_DEBUG_VFS, "%s: inode %p, writeback_fid %p\n",
> __func__, inode, v9inode->writeback_fid);
>         if (!v9inode->writeback_fid)
>                 return 0;
> +
>         ret = p9_client_fsync(v9inode->writeback_fid, 0);
>         if (ret < 0) {
>                 __mark_inode_dirty(inode, I_DIRTY_DATASYNC);
> --
> 1.8.1.4
>
>
------------------------------------------------------------------------------
October Webinars: Code for Performance
Free Intel webinars can help you accelerate application performance.
Explore tips for MPI, OpenMP, advanced profiling, and more. Get the most from 
the latest Intel processors and coprocessors. See abstracts and register >
http://pubads.g.doubleclick.net/gampad/clk?id=60135031&iu=/4140/ostg.clktrk
diff mbox

Patch

diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
index 58e6cbc..1a2b0c8 100644
--- a/fs/9p/v9fs.c
+++ b/fs/9p/v9fs.c
@@ -56,7 +56,7 @@  enum {
 	/* Options that take no arguments */
 	Opt_nodevmap,
 	/* Cache options */
-	Opt_cache_loose, Opt_fscache,
+	Opt_cache_loose, Opt_fscache, Opt_mmap,
 	/* Access options */
 	Opt_access, Opt_posixacl,
 	/* Error token */
@@ -74,6 +74,7 @@  static const match_table_t tokens = {
 	{Opt_cache, "cache=%s"},
 	{Opt_cache_loose, "loose"},
 	{Opt_fscache, "fscache"},
+	{Opt_mmap, "mmap"},
 	{Opt_cachetag, "cachetag=%s"},
 	{Opt_access, "access=%s"},
 	{Opt_posixacl, "posixacl"},
@@ -91,6 +92,9 @@  static int get_cache_mode(char *s)
 	} else if (!strcmp(s, "fscache")) {
 		version = CACHE_FSCACHE;
 		p9_debug(P9_DEBUG_9P, "Cache mode: fscache\n");
+	} else if (!strcmp(s, "mmap")) {
+		version = CACHE_MMAP;
+		p9_debug(P9_DEBUG_9P, "Cache mode: mmap\n");
 	} else if (!strcmp(s, "none")) {
 		version = CACHE_NONE;
 		p9_debug(P9_DEBUG_9P, "Cache mode: none\n");
@@ -220,6 +224,9 @@  static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
 		case Opt_fscache:
 			v9ses->cache = CACHE_FSCACHE;
 			break;
+		case Opt_mmap:
+			v9ses->cache = CACHE_MMAP;
+			break;
 		case Opt_cachetag:
 #ifdef CONFIG_9P_FSCACHE
 			v9ses->cachetag = match_strdup(&args[0]);
diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h
index a8e127c..099c771 100644
--- a/fs/9p/v9fs.h
+++ b/fs/9p/v9fs.h
@@ -64,6 +64,7 @@  enum p9_session_flags {
 
 enum p9_cache_modes {
 	CACHE_NONE,
+	CACHE_MMAP,
 	CACHE_LOOSE,
 	CACHE_FSCACHE,
 };
diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h
index dc95a25..b83ebfb 100644
--- a/fs/9p/v9fs_vfs.h
+++ b/fs/9p/v9fs_vfs.h
@@ -50,6 +50,8 @@  extern const struct dentry_operations v9fs_dentry_operations;
 extern const struct dentry_operations v9fs_cached_dentry_operations;
 extern const struct file_operations v9fs_cached_file_operations;
 extern const struct file_operations v9fs_cached_file_operations_dotl;
+extern const struct file_operations v9fs_mmap_file_operations;
+extern const struct file_operations v9fs_mmap_file_operations_dotl;
 extern struct kmem_cache *v9fs_inode_cache;
 
 struct inode *v9fs_alloc_inode(struct super_block *sb);
diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c
index 9ff073f..c71e886 100644
--- a/fs/9p/vfs_addr.c
+++ b/fs/9p/vfs_addr.c
@@ -202,6 +202,8 @@  static int v9fs_vfs_writepage(struct page *page, struct writeback_control *wbc)
 {
 	int retval;
 
+	p9_debug(P9_DEBUG_VFS, "page %p\n", page);
+
 	retval = v9fs_vfs_writepage_locked(page);
 	if (retval < 0) {
 		if (retval == -EAGAIN) {
@@ -282,6 +284,9 @@  static int v9fs_write_begin(struct file *filp, struct address_space *mapping,
 	pgoff_t index = pos >> PAGE_CACHE_SHIFT;
 	struct inode *inode = mapping->host;
 
+
+	p9_debug(P9_DEBUG_VFS, "filp %p, mapping %p\n", filp, mapping);
+
 	v9inode = V9FS_I(inode);
 start:
 	page = grab_cache_page_write_begin(mapping, index, flags);
@@ -312,6 +317,8 @@  static int v9fs_write_end(struct file *filp, struct address_space *mapping,
 	loff_t last_pos = pos + copied;
 	struct inode *inode = page->mapping->host;
 
+	p9_debug(P9_DEBUG_VFS, "filp %p, mapping %p\n", filp, mapping);
+
 	if (unlikely(copied < len)) {
 		/*
 		 * zero out the rest of the area
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index d384a8b..ec904ed 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -45,6 +45,7 @@ 
 #include "cache.h"
 
 static const struct vm_operations_struct v9fs_file_vm_ops;
+static const struct vm_operations_struct v9fs_mmap_file_vm_ops;
 
 /**
  * v9fs_file_open - open a file (or directory)
@@ -106,7 +107,9 @@  int v9fs_file_open(struct inode *inode, struct file *file)
 	}
 	mutex_unlock(&v9inode->v_mutex);
 #ifdef CONFIG_9P_FSCACHE
-	if (v9ses->cache)
+	/* previous check would also set cookie with CACHE_LOOSE?
+	 * set_cookie does a check if v9inode->fscache anyway... */
+	if (v9ses->cache == CACHE_FSCACHE)
 		v9fs_cache_inode_set_cookie(inode, file);
 #endif
 	return 0;
@@ -583,17 +586,33 @@  int v9fs_file_fsync_dotl(struct file *filp, loff_t start, loff_t end,
 }
 
 static int
-v9fs_file_mmap(struct file *file, struct vm_area_struct *vma)
+v9fs_file_mmap(struct file *filp, struct vm_area_struct *vma)
 {
 	int retval;
 
-	retval = generic_file_mmap(file, vma);
+
+	retval = generic_file_mmap(filp, vma);
 	if (!retval)
 		vma->vm_ops = &v9fs_file_vm_ops;
 
 	return retval;
 }
 
+/* TODO: merge this with the previous function
+ * and set the right vm_ops depending on v9ses->cache */
+static int
+v9fs_mmap_file_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	int retval;
+
+
+	retval = generic_file_mmap(filp, vma);
+	if (!retval)
+		vma->vm_ops = &v9fs_mmap_file_vm_ops;
+
+	return retval;
+}
+
 static int
 v9fs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
@@ -662,6 +681,22 @@  v9fs_cached_file_read(struct file *filp, char __user *data, size_t count,
 	return do_sync_read(filp, data, count, offset);
 }
 
+/**
+ * v9fs_mmap_file_read - read from a file
+ * @filp: file pointer to read
+ * @udata: user data buffer to read data into
+ * @count: size of buffer
+ * @offset: offset at which to read data
+ *
+ */
+static ssize_t
+v9fs_mmap_file_read(struct file *filp, char __user *data, size_t count,
+		      loff_t *offset)
+{
+	/* TODO: Check if there are dirty pages */
+	return v9fs_file_read(filp, data, count, offset);
+}
+
 static ssize_t
 v9fs_direct_write(struct file *filp, const char __user * data,
 		  size_t count, loff_t *offsetp)
@@ -732,12 +767,61 @@  v9fs_cached_file_write(struct file *filp, const char __user * data,
 	return do_sync_write(filp, data, count, offset);
 }
 
+
+/**
+ * v9fs_mmap_file_write - write to a file
+ * @filp: file pointer to write
+ * @data: data buffer to write data from
+ * @count: size of buffer
+ * @offset: offset at which to write data
+ *
+ */
+static ssize_t
+v9fs_mmap_file_write(struct file *filp, const char __user *data,
+		       size_t count, loff_t *offset)
+{
+	/* TODO: invalidate mmaps on filp's inode between offset and offset+count */
+	return v9fs_file_write(filp, data, count, offset);
+}
+
+static void v9fs_mmap_vm_close(struct vm_area_struct *vma)
+{
+        struct inode *inode;
+
+	p9_debug(P9_DEBUG_VFS, "9p VMA close, %p, flushing", vma);
+
+	struct writeback_control wbc = {
+		.nr_to_write = LONG_MAX,
+		.sync_mode = WB_SYNC_ALL,
+		.range_start = vma->vm_pgoff * PAGE_SIZE,
+		 /* absolute end, byte at end included */
+		.range_end = vma->vm_pgoff * PAGE_SIZE +
+			(vma->vm_end - vma->vm_start - 1),
+	};
+
+	inode = file_inode(vma->vm_file);
+
+	if (!mapping_cap_writeback_dirty(inode->i_mapping))
+		wbc.nr_to_write = 0;
+
+	might_sleep();
+	sync_inode(inode, &wbc);
+}
+
+
 static const struct vm_operations_struct v9fs_file_vm_ops = {
 	.fault = filemap_fault,
 	.page_mkwrite = v9fs_vm_page_mkwrite,
 	.remap_pages = generic_file_remap_pages,
 };
 
+static const struct vm_operations_struct v9fs_mmap_file_vm_ops = {
+	.close = v9fs_mmap_vm_close,
+	.fault = filemap_fault,
+	.page_mkwrite = v9fs_vm_page_mkwrite,
+	.remap_pages = generic_file_remap_pages,
+};
+
 
 const struct file_operations v9fs_cached_file_operations = {
 	.llseek = generic_file_llseek,
@@ -788,3 +872,26 @@  const struct file_operations v9fs_file_operations_dotl = {
 	.mmap = generic_file_readonly_mmap,
 	.fsync = v9fs_file_fsync_dotl,
 };
+
+const struct file_operations v9fs_mmap_file_operations = {
+	.llseek = generic_file_llseek,
+	.read = v9fs_mmap_file_read,
+	.write = v9fs_mmap_file_write,
+	.open = v9fs_file_open,
+	.release = v9fs_dir_release,
+	.lock = v9fs_file_lock,
+	.mmap = v9fs_mmap_file_mmap,
+	.fsync = v9fs_file_fsync,
+};
+
+const struct file_operations v9fs_mmap_file_operations_dotl = {
+	.llseek = generic_file_llseek,
+	.read = v9fs_mmap_file_read,
+	.write = v9fs_mmap_file_write,
+	.open = v9fs_file_open,
+	.release = v9fs_dir_release,
+	.lock = v9fs_file_lock_dotl,
+	.flock = v9fs_file_flock_dotl,
+	.mmap = v9fs_mmap_file_mmap,
+	.fsync = v9fs_file_fsync_dotl,
+};
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 25b018e..d52179c 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -299,15 +299,20 @@  int v9fs_init_inode(struct v9fs_session_info *v9ses,
 	case S_IFREG:
 		if (v9fs_proto_dotl(v9ses)) {
 			inode->i_op = &v9fs_file_inode_operations_dotl;
-			if (v9ses->cache)
+			if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
 				inode->i_fop =
 					&v9fs_cached_file_operations_dotl;
+			else if (v9ses->cache == CACHE_MMAP)
+				inode->i_fop = &v9fs_mmap_file_operations_dotl;
 			else
 				inode->i_fop = &v9fs_file_operations_dotl;
 		} else {
 			inode->i_op = &v9fs_file_inode_operations;
-			if (v9ses->cache)
-				inode->i_fop = &v9fs_cached_file_operations;
+			if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
+				inode->i_fop =
+					&v9fs_cached_file_operations;
+			else if (v9ses->cache == CACHE_MMAP)
+				inode->i_fop = &v9fs_mmap_file_operations;
 			else
 				inode->i_fop = &v9fs_file_operations;
 		}
@@ -816,7 +821,7 @@  struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
 	 * unlink. For cached mode create calls request for new
 	 * inode. But with cache disabled, lookup should do this.
 	 */
-	if (v9ses->cache)
+	if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
 		inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb);
 	else
 		inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
@@ -906,7 +911,7 @@  v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry,
 
 	file->private_data = fid;
 #ifdef CONFIG_9P_FSCACHE
-	if (v9ses->cache)
+	if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
 		v9fs_cache_inode_set_cookie(dentry->d_inode, file);
 #endif
 
@@ -1485,7 +1490,7 @@  int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode)
 	 */
 	i_size = inode->i_size;
 	v9fs_stat2inode(st, inode, inode->i_sb);
-	if (v9ses->cache)
+	if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
 		inode->i_size = i_size;
 	spin_unlock(&inode->i_lock);
 out:
diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c
index 53687bb..710d5c6 100644
--- a/fs/9p/vfs_inode_dotl.c
+++ b/fs/9p/vfs_inode_dotl.c
@@ -362,7 +362,7 @@  v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry,
 		goto err_clunk_old_fid;
 	file->private_data = ofid;
 #ifdef CONFIG_9P_FSCACHE
-	if (v9ses->cache)
+	if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
 		v9fs_cache_inode_set_cookie(inode, file);
 #endif
 	*opened |= FILE_CREATED;
@@ -725,7 +725,7 @@  v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry,
 	}
 
 	v9fs_invalidate_inode_attr(dir);
-	if (v9ses->cache) {
+	if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
 		/* Now walk from the parent so we can get an unopened fid. */
 		fid = p9_client_walk(dfid, 1, &name, 1);
 		if (IS_ERR(fid)) {
@@ -983,7 +983,7 @@  int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode)
 	 */
 	i_size = inode->i_size;
 	v9fs_stat2inode_dotl(st, inode);
-	if (v9ses->cache)
+	if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
 		inode->i_size = i_size;
 	spin_unlock(&inode->i_lock);
 out:
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index 2756dcd..a4dd162 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -144,7 +144,7 @@  static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags,
 	}
 	v9fs_fill_super(sb, v9ses, flags, data);
 
-	if (v9ses->cache)
+	if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
 		sb->s_d_op = &v9fs_cached_dentry_operations;
 	else
 		sb->s_d_op = &v9fs_dentry_operations;
@@ -282,7 +282,7 @@  static int v9fs_drop_inode(struct inode *inode)
 {
 	struct v9fs_session_info *v9ses;
 	v9ses = v9fs_inode2v9ses(inode);
-	if (v9ses->cache)
+	if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
 		return generic_drop_inode(inode);
 	/*
 	 * in case of non cached mode always drop the
@@ -325,10 +325,11 @@  static int v9fs_write_inode_dotl(struct inode *inode,
 	 * send an fsync request to server irrespective of
 	 * wbc->sync_mode.
 	 */
-	p9_debug(P9_DEBUG_VFS, "%s: inode %p\n", __func__, inode);
 	v9inode = V9FS_I(inode);
+	p9_debug(P9_DEBUG_VFS, "%s: inode %p, writeback_fid %p\n", __func__, inode, v9inode->writeback_fid);
 	if (!v9inode->writeback_fid)
 		return 0;
+
 	ret = p9_client_fsync(v9inode->writeback_fid, 0);
 	if (ret < 0) {
 		__mark_inode_dirty(inode, I_DIRTY_DATASYNC);