Commit fb89b45cdfdc8bdab93986f1bc1474e313295c31
Committed by
Eric Van Hensbergen
1 parent
f94741fd28
Exists in
master
and in
16 other branches
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
fs/9p/v9fs.c
... | ... | @@ -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 |
fs/9p/v9fs.h
fs/9p/v9fs_vfs.h
... | ... | @@ -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); |
fs/9p/vfs_addr.c
... | ... | @@ -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 | /* |
fs/9p/vfs_file.c
... | ... | @@ -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 | }; |
fs/9p/vfs_inode.c
... | ... | @@ -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: |
fs/9p/vfs_super.c
... | ... | @@ -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); |