Commit fb89b45cdfdc8bdab93986f1bc1474e313295c31

Authored by Dominique Martinet
Committed by Eric Van Hensbergen
1 parent f94741fd28

9P: introduction of a new cache=mmap model.

- Add cache=mmap option
 - Make mmap read-write while keeping it as synchronous as possible
 - Build writeback fid on mmap creation if it is writable

Signed-off-by: Dominique Martinet <dominique.martinet@cea.fr>
Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com>

Showing 8 changed files with 179 additions and 19 deletions Side-by-side Diff

... ... @@ -56,7 +56,7 @@
56 56 /* Options that take no arguments */
57 57 Opt_nodevmap,
58 58 /* Cache options */
59   - Opt_cache_loose, Opt_fscache,
  59 + Opt_cache_loose, Opt_fscache, Opt_mmap,
60 60 /* Access options */
61 61 Opt_access, Opt_posixacl,
62 62 /* Error token */
... ... @@ -74,6 +74,7 @@
74 74 {Opt_cache, "cache=%s"},
75 75 {Opt_cache_loose, "loose"},
76 76 {Opt_fscache, "fscache"},
  77 + {Opt_mmap, "mmap"},
77 78 {Opt_cachetag, "cachetag=%s"},
78 79 {Opt_access, "access=%s"},
79 80 {Opt_posixacl, "posixacl"},
... ... @@ -91,6 +92,9 @@
91 92 } else if (!strcmp(s, "fscache")) {
92 93 version = CACHE_FSCACHE;
93 94 p9_debug(P9_DEBUG_9P, "Cache mode: fscache\n");
  95 + } else if (!strcmp(s, "mmap")) {
  96 + version = CACHE_MMAP;
  97 + p9_debug(P9_DEBUG_9P, "Cache mode: mmap\n");
94 98 } else if (!strcmp(s, "none")) {
95 99 version = CACHE_NONE;
96 100 p9_debug(P9_DEBUG_9P, "Cache mode: none\n");
... ... @@ -219,6 +223,9 @@
219 223 break;
220 224 case Opt_fscache:
221 225 v9ses->cache = CACHE_FSCACHE;
  226 + break;
  227 + case Opt_mmap:
  228 + v9ses->cache = CACHE_MMAP;
222 229 break;
223 230 case Opt_cachetag:
224 231 #ifdef CONFIG_9P_FSCACHE
... ... @@ -64,6 +64,7 @@
64 64  
65 65 enum p9_cache_modes {
66 66 CACHE_NONE,
  67 + CACHE_MMAP,
67 68 CACHE_LOOSE,
68 69 CACHE_FSCACHE,
69 70 };
... ... @@ -50,6 +50,8 @@
50 50 extern const struct dentry_operations v9fs_cached_dentry_operations;
51 51 extern const struct file_operations v9fs_cached_file_operations;
52 52 extern const struct file_operations v9fs_cached_file_operations_dotl;
  53 +extern const struct file_operations v9fs_mmap_file_operations;
  54 +extern const struct file_operations v9fs_mmap_file_operations_dotl;
53 55 extern struct kmem_cache *v9fs_inode_cache;
54 56  
55 57 struct inode *v9fs_alloc_inode(struct super_block *sb);
... ... @@ -202,6 +202,8 @@
202 202 {
203 203 int retval;
204 204  
  205 + p9_debug(P9_DEBUG_VFS, "page %p\n", page);
  206 +
205 207 retval = v9fs_vfs_writepage_locked(page);
206 208 if (retval < 0) {
207 209 if (retval == -EAGAIN) {
... ... @@ -282,6 +284,9 @@
282 284 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
283 285 struct inode *inode = mapping->host;
284 286  
  287 +
  288 + p9_debug(P9_DEBUG_VFS, "filp %p, mapping %p\n", filp, mapping);
  289 +
285 290 v9inode = V9FS_I(inode);
286 291 start:
287 292 page = grab_cache_page_write_begin(mapping, index, flags);
... ... @@ -311,6 +316,8 @@
311 316 {
312 317 loff_t last_pos = pos + copied;
313 318 struct inode *inode = page->mapping->host;
  319 +
  320 + p9_debug(P9_DEBUG_VFS, "filp %p, mapping %p\n", filp, mapping);
314 321  
315 322 if (unlikely(copied < len)) {
316 323 /*
... ... @@ -45,6 +45,7 @@
45 45 #include "cache.h"
46 46  
47 47 static const struct vm_operations_struct v9fs_file_vm_ops;
  48 +static const struct vm_operations_struct v9fs_mmap_file_vm_ops;
48 49  
49 50 /**
50 51 * v9fs_file_open - open a file (or directory)
... ... @@ -87,7 +88,8 @@
87 88  
88 89 file->private_data = fid;
89 90 mutex_lock(&v9inode->v_mutex);
90   - if (v9ses->cache && !v9inode->writeback_fid &&
  91 + if ((v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) &&
  92 + !v9inode->writeback_fid &&
91 93 ((file->f_flags & O_ACCMODE) != O_RDONLY)) {
92 94 /*
93 95 * clone a fid and add it to writeback_fid
... ... @@ -105,7 +107,7 @@
105 107 v9inode->writeback_fid = (void *) fid;
106 108 }
107 109 mutex_unlock(&v9inode->v_mutex);
108   - if (v9ses->cache)
  110 + if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
109 111 v9fs_cache_inode_set_cookie(inode, file);
110 112 return 0;
111 113 out_error:
112 114  
... ... @@ -579,11 +581,12 @@
579 581 }
580 582  
581 583 static int
582   -v9fs_file_mmap(struct file *file, struct vm_area_struct *vma)
  584 +v9fs_file_mmap(struct file *filp, struct vm_area_struct *vma)
583 585 {
584 586 int retval;
585 587  
586   - retval = generic_file_mmap(file, vma);
  588 +
  589 + retval = generic_file_mmap(filp, vma);
587 590 if (!retval)
588 591 vma->vm_ops = &v9fs_file_vm_ops;
589 592  
... ... @@ -591,6 +594,43 @@
591 594 }
592 595  
593 596 static int
  597 +v9fs_mmap_file_mmap(struct file *filp, struct vm_area_struct *vma)
  598 +{
  599 + int retval;
  600 + struct inode *inode;
  601 + struct v9fs_inode *v9inode;
  602 + struct p9_fid *fid;
  603 +
  604 + inode = file_inode(filp);
  605 + v9inode = V9FS_I(inode);
  606 + mutex_lock(&v9inode->v_mutex);
  607 + if (!v9inode->writeback_fid &&
  608 + (vma->vm_flags & VM_WRITE)) {
  609 + /*
  610 + * clone a fid and add it to writeback_fid
  611 + * we do it during mmap instead of
  612 + * page dirty time via write_begin/page_mkwrite
  613 + * because we want write after unlink usecase
  614 + * to work.
  615 + */
  616 + fid = v9fs_writeback_fid(filp->f_path.dentry);
  617 + if (IS_ERR(fid)) {
  618 + retval = PTR_ERR(fid);
  619 + mutex_unlock(&v9inode->v_mutex);
  620 + return retval;
  621 + }
  622 + v9inode->writeback_fid = (void *) fid;
  623 + }
  624 + mutex_unlock(&v9inode->v_mutex);
  625 +
  626 + retval = generic_file_mmap(filp, vma);
  627 + if (!retval)
  628 + vma->vm_ops = &v9fs_mmap_file_vm_ops;
  629 +
  630 + return retval;
  631 +}
  632 +
  633 +static int
594 634 v9fs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
595 635 {
596 636 struct v9fs_inode *v9inode;
597 637  
... ... @@ -658,7 +698,23 @@
658 698 return do_sync_read(filp, data, count, offset);
659 699 }
660 700  
  701 +/**
  702 + * v9fs_mmap_file_read - read from a file
  703 + * @filp: file pointer to read
  704 + * @udata: user data buffer to read data into
  705 + * @count: size of buffer
  706 + * @offset: offset at which to read data
  707 + *
  708 + */
661 709 static ssize_t
  710 +v9fs_mmap_file_read(struct file *filp, char __user *data, size_t count,
  711 + loff_t *offset)
  712 +{
  713 + /* TODO: Check if there are dirty pages */
  714 + return v9fs_file_read(filp, data, count, offset);
  715 +}
  716 +
  717 +static ssize_t
662 718 v9fs_direct_write(struct file *filp, const char __user * data,
663 719 size_t count, loff_t *offsetp)
664 720 {
665 721  
666 722  
... ... @@ -728,13 +784,66 @@
728 784 return do_sync_write(filp, data, count, offset);
729 785 }
730 786  
  787 +
  788 +/**
  789 + * v9fs_mmap_file_write - write to a file
  790 + * @filp: file pointer to write
  791 + * @data: data buffer to write data from
  792 + * @count: size of buffer
  793 + * @offset: offset at which to write data
  794 + *
  795 + */
  796 +static ssize_t
  797 +v9fs_mmap_file_write(struct file *filp, const char __user *data,
  798 + size_t count, loff_t *offset)
  799 +{
  800 + /*
  801 + * TODO: invalidate mmaps on filp's inode between
  802 + * offset and offset+count
  803 + */
  804 + return v9fs_file_write(filp, data, count, offset);
  805 +}
  806 +
  807 +static void v9fs_mmap_vm_close(struct vm_area_struct *vma)
  808 +{
  809 + struct inode *inode;
  810 +
  811 + struct writeback_control wbc = {
  812 + .nr_to_write = LONG_MAX,
  813 + .sync_mode = WB_SYNC_ALL,
  814 + .range_start = vma->vm_pgoff * PAGE_SIZE,
  815 + /* absolute end, byte at end included */
  816 + .range_end = vma->vm_pgoff * PAGE_SIZE +
  817 + (vma->vm_end - vma->vm_start - 1),
  818 + };
  819 +
  820 +
  821 + p9_debug(P9_DEBUG_VFS, "9p VMA close, %p, flushing", vma);
  822 +
  823 + inode = file_inode(vma->vm_file);
  824 +
  825 + if (!mapping_cap_writeback_dirty(inode->i_mapping))
  826 + wbc.nr_to_write = 0;
  827 +
  828 + might_sleep();
  829 + sync_inode(inode, &wbc);
  830 +}
  831 +
  832 +
731 833 static const struct vm_operations_struct v9fs_file_vm_ops = {
732 834 .fault = filemap_fault,
733 835 .page_mkwrite = v9fs_vm_page_mkwrite,
734 836 .remap_pages = generic_file_remap_pages,
735 837 };
736 838  
  839 +static const struct vm_operations_struct v9fs_mmap_file_vm_ops = {
  840 + .close = v9fs_mmap_vm_close,
  841 + .fault = filemap_fault,
  842 + .page_mkwrite = v9fs_vm_page_mkwrite,
  843 + .remap_pages = generic_file_remap_pages,
  844 +};
737 845  
  846 +
738 847 const struct file_operations v9fs_cached_file_operations = {
739 848 .llseek = generic_file_llseek,
740 849 .read = v9fs_cached_file_read,
... ... @@ -782,6 +891,29 @@
782 891 .lock = v9fs_file_lock_dotl,
783 892 .flock = v9fs_file_flock_dotl,
784 893 .mmap = generic_file_readonly_mmap,
  894 + .fsync = v9fs_file_fsync_dotl,
  895 +};
  896 +
  897 +const struct file_operations v9fs_mmap_file_operations = {
  898 + .llseek = generic_file_llseek,
  899 + .read = v9fs_mmap_file_read,
  900 + .write = v9fs_mmap_file_write,
  901 + .open = v9fs_file_open,
  902 + .release = v9fs_dir_release,
  903 + .lock = v9fs_file_lock,
  904 + .mmap = v9fs_mmap_file_mmap,
  905 + .fsync = v9fs_file_fsync,
  906 +};
  907 +
  908 +const struct file_operations v9fs_mmap_file_operations_dotl = {
  909 + .llseek = generic_file_llseek,
  910 + .read = v9fs_mmap_file_read,
  911 + .write = v9fs_mmap_file_write,
  912 + .open = v9fs_file_open,
  913 + .release = v9fs_dir_release,
  914 + .lock = v9fs_file_lock_dotl,
  915 + .flock = v9fs_file_flock_dotl,
  916 + .mmap = v9fs_mmap_file_mmap,
785 917 .fsync = v9fs_file_fsync_dotl,
786 918 };
... ... @@ -299,15 +299,22 @@
299 299 case S_IFREG:
300 300 if (v9fs_proto_dotl(v9ses)) {
301 301 inode->i_op = &v9fs_file_inode_operations_dotl;
302   - if (v9ses->cache)
  302 + if (v9ses->cache == CACHE_LOOSE ||
  303 + v9ses->cache == CACHE_FSCACHE)
303 304 inode->i_fop =
304 305 &v9fs_cached_file_operations_dotl;
  306 + else if (v9ses->cache == CACHE_MMAP)
  307 + inode->i_fop = &v9fs_mmap_file_operations_dotl;
305 308 else
306 309 inode->i_fop = &v9fs_file_operations_dotl;
307 310 } else {
308 311 inode->i_op = &v9fs_file_inode_operations;
309   - if (v9ses->cache)
310   - inode->i_fop = &v9fs_cached_file_operations;
  312 + if (v9ses->cache == CACHE_LOOSE ||
  313 + v9ses->cache == CACHE_FSCACHE)
  314 + inode->i_fop =
  315 + &v9fs_cached_file_operations;
  316 + else if (v9ses->cache == CACHE_MMAP)
  317 + inode->i_fop = &v9fs_mmap_file_operations;
311 318 else
312 319 inode->i_fop = &v9fs_file_operations;
313 320 }
... ... @@ -810,7 +817,7 @@
810 817 * unlink. For cached mode create calls request for new
811 818 * inode. But with cache disabled, lookup should do this.
812 819 */
813   - if (v9ses->cache)
  820 + if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
814 821 inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb);
815 822 else
816 823 inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
... ... @@ -876,7 +883,8 @@
876 883 v9fs_invalidate_inode_attr(dir);
877 884 v9inode = V9FS_I(dentry->d_inode);
878 885 mutex_lock(&v9inode->v_mutex);
879   - if (v9ses->cache && !v9inode->writeback_fid &&
  886 + if ((v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) &&
  887 + !v9inode->writeback_fid &&
880 888 ((flags & O_ACCMODE) != O_RDONLY)) {
881 889 /*
882 890 * clone a fid and add it to writeback_fid
... ... @@ -899,7 +907,7 @@
899 907 goto error;
900 908  
901 909 file->private_data = fid;
902   - if (v9ses->cache)
  910 + if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
903 911 v9fs_cache_inode_set_cookie(dentry->d_inode, file);
904 912  
905 913 *opened |= FILE_CREATED;
... ... @@ -1477,7 +1485,7 @@
1477 1485 */
1478 1486 i_size = inode->i_size;
1479 1487 v9fs_stat2inode(st, inode, inode->i_sb);
1480   - if (v9ses->cache)
  1488 + if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
1481 1489 inode->i_size = i_size;
1482 1490 spin_unlock(&inode->i_lock);
1483 1491 out:
fs/9p/vfs_inode_dotl.c
... ... @@ -330,7 +330,8 @@
330 330  
331 331 v9inode = V9FS_I(inode);
332 332 mutex_lock(&v9inode->v_mutex);
333   - if (v9ses->cache && !v9inode->writeback_fid &&
  333 + if ((v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) &&
  334 + !v9inode->writeback_fid &&
334 335 ((flags & O_ACCMODE) != O_RDONLY)) {
335 336 /*
336 337 * clone a fid and add it to writeback_fid
... ... @@ -353,7 +354,7 @@
353 354 if (err)
354 355 goto err_clunk_old_fid;
355 356 file->private_data = ofid;
356   - if (v9ses->cache)
  357 + if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
357 358 v9fs_cache_inode_set_cookie(inode, file);
358 359 *opened |= FILE_CREATED;
359 360 out:
... ... @@ -710,7 +711,7 @@
710 711 }
711 712  
712 713 v9fs_invalidate_inode_attr(dir);
713   - if (v9ses->cache) {
  714 + if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
714 715 /* Now walk from the parent so we can get an unopened fid. */
715 716 fid = p9_client_walk(dfid, 1, &name, 1);
716 717 if (IS_ERR(fid)) {
... ... @@ -965,7 +966,7 @@
965 966 */
966 967 i_size = inode->i_size;
967 968 v9fs_stat2inode_dotl(st, inode);
968   - if (v9ses->cache)
  969 + if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
969 970 inode->i_size = i_size;
970 971 spin_unlock(&inode->i_lock);
971 972 out:
... ... @@ -144,7 +144,7 @@
144 144 }
145 145 v9fs_fill_super(sb, v9ses, flags, data);
146 146  
147   - if (v9ses->cache)
  147 + if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
148 148 sb->s_d_op = &v9fs_cached_dentry_operations;
149 149 else
150 150 sb->s_d_op = &v9fs_dentry_operations;
... ... @@ -282,7 +282,7 @@
282 282 {
283 283 struct v9fs_session_info *v9ses;
284 284 v9ses = v9fs_inode2v9ses(inode);
285   - if (v9ses->cache)
  285 + if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
286 286 return generic_drop_inode(inode);
287 287 /*
288 288 * in case of non cached mode always drop the
289 289  
290 290  
... ... @@ -325,10 +325,12 @@
325 325 * send an fsync request to server irrespective of
326 326 * wbc->sync_mode.
327 327 */
328   - p9_debug(P9_DEBUG_VFS, "%s: inode %p\n", __func__, inode);
329 328 v9inode = V9FS_I(inode);
  329 + p9_debug(P9_DEBUG_VFS, "%s: inode %p, writeback_fid %p\n",
  330 + __func__, inode, v9inode->writeback_fid);
330 331 if (!v9inode->writeback_fid)
331 332 return 0;
  333 +
332 334 ret = p9_client_fsync(v9inode->writeback_fid, 0);
333 335 if (ret < 0) {
334 336 __mark_inode_dirty(inode, I_DIRTY_DATASYNC);