aboutsummaryrefslogtreecommitdiffstats
path: root/fs/9p/vfs_file.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/9p/vfs_file.c')
-rw-r--r--fs/9p/vfs_file.c316
1 files changed, 253 insertions, 63 deletions
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index 240c30674396..78bcb97c3425 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -44,8 +44,7 @@
44#include "fid.h" 44#include "fid.h"
45#include "cache.h" 45#include "cache.h"
46 46
47static const struct file_operations v9fs_cached_file_operations; 47static const struct vm_operations_struct v9fs_file_vm_ops;
48static const struct file_operations v9fs_cached_file_operations_dotl;
49 48
50/** 49/**
51 * v9fs_file_open - open a file (or directory) 50 * v9fs_file_open - open a file (or directory)
@@ -57,11 +56,13 @@ static const struct file_operations v9fs_cached_file_operations_dotl;
57int v9fs_file_open(struct inode *inode, struct file *file) 56int v9fs_file_open(struct inode *inode, struct file *file)
58{ 57{
59 int err; 58 int err;
59 struct v9fs_inode *v9inode;
60 struct v9fs_session_info *v9ses; 60 struct v9fs_session_info *v9ses;
61 struct p9_fid *fid; 61 struct p9_fid *fid;
62 int omode; 62 int omode;
63 63
64 P9_DPRINTK(P9_DEBUG_VFS, "inode: %p file: %p\n", inode, file); 64 P9_DPRINTK(P9_DEBUG_VFS, "inode: %p file: %p\n", inode, file);
65 v9inode = V9FS_I(inode);
65 v9ses = v9fs_inode2v9ses(inode); 66 v9ses = v9fs_inode2v9ses(inode);
66 if (v9fs_proto_dotl(v9ses)) 67 if (v9fs_proto_dotl(v9ses))
67 omode = file->f_flags; 68 omode = file->f_flags;
@@ -89,20 +90,30 @@ int v9fs_file_open(struct inode *inode, struct file *file)
89 } 90 }
90 91
91 file->private_data = fid; 92 file->private_data = fid;
92 if ((fid->qid.version) && (v9ses->cache)) { 93 if (v9ses->cache && !v9inode->writeback_fid) {
93 P9_DPRINTK(P9_DEBUG_VFS, "cached"); 94 /*
94 /* enable cached file options */ 95 * clone a fid and add it to writeback_fid
95 if(file->f_op == &v9fs_file_operations) 96 * we do it during open time instead of
96 file->f_op = &v9fs_cached_file_operations; 97 * page dirty time via write_begin/page_mkwrite
97 else if (file->f_op == &v9fs_file_operations_dotl) 98 * because we want write after unlink usecase
98 file->f_op = &v9fs_cached_file_operations_dotl; 99 * to work.
99 100 */
101 fid = v9fs_writeback_fid(file->f_path.dentry);
102 if (IS_ERR(fid)) {
103 err = PTR_ERR(fid);
104 goto out_error;
105 }
106 v9inode->writeback_fid = (void *) fid;
107 }
100#ifdef CONFIG_9P_FSCACHE 108#ifdef CONFIG_9P_FSCACHE
109 if (v9ses->cache)
101 v9fs_cache_inode_set_cookie(inode, file); 110 v9fs_cache_inode_set_cookie(inode, file);
102#endif 111#endif
103 }
104
105 return 0; 112 return 0;
113out_error:
114 p9_client_clunk(file->private_data);
115 file->private_data = NULL;
116 return err;
106} 117}
107 118
108/** 119/**
@@ -335,25 +346,22 @@ out_err:
335} 346}
336 347
337/** 348/**
338 * v9fs_file_readn - read from a file 349 * v9fs_fid_readn - read from a fid
339 * @filp: file pointer to read 350 * @fid: fid to read
340 * @data: data buffer to read data into 351 * @data: data buffer to read data into
341 * @udata: user data buffer to read data into 352 * @udata: user data buffer to read data into
342 * @count: size of buffer 353 * @count: size of buffer
343 * @offset: offset at which to read data 354 * @offset: offset at which to read data
344 * 355 *
345 */ 356 */
346
347ssize_t 357ssize_t
348v9fs_file_readn(struct file *filp, char *data, char __user *udata, u32 count, 358v9fs_fid_readn(struct p9_fid *fid, char *data, char __user *udata, u32 count,
349 u64 offset) 359 u64 offset)
350{ 360{
351 int n, total, size; 361 int n, total, size;
352 struct p9_fid *fid = filp->private_data;
353 362
354 P9_DPRINTK(P9_DEBUG_VFS, "fid %d offset %llu count %d\n", fid->fid, 363 P9_DPRINTK(P9_DEBUG_VFS, "fid %d offset %llu count %d\n", fid->fid,
355 (long long unsigned) offset, count); 364 (long long unsigned) offset, count);
356
357 n = 0; 365 n = 0;
358 total = 0; 366 total = 0;
359 size = fid->iounit ? fid->iounit : fid->clnt->msize - P9_IOHDRSZ; 367 size = fid->iounit ? fid->iounit : fid->clnt->msize - P9_IOHDRSZ;
@@ -379,6 +387,22 @@ v9fs_file_readn(struct file *filp, char *data, char __user *udata, u32 count,
379} 387}
380 388
381/** 389/**
390 * v9fs_file_readn - read from a file
391 * @filp: file pointer to read
392 * @data: data buffer to read data into
393 * @udata: user data buffer to read data into
394 * @count: size of buffer
395 * @offset: offset at which to read data
396 *
397 */
398ssize_t
399v9fs_file_readn(struct file *filp, char *data, char __user *udata, u32 count,
400 u64 offset)
401{
402 return v9fs_fid_readn(filp->private_data, data, udata, count, offset);
403}
404
405/**
382 * v9fs_file_read - read from a file 406 * v9fs_file_read - read from a file
383 * @filp: file pointer to read 407 * @filp: file pointer to read
384 * @udata: user data buffer to read data into 408 * @udata: user data buffer to read data into
@@ -410,45 +434,22 @@ v9fs_file_read(struct file *filp, char __user *udata, size_t count,
410 return ret; 434 return ret;
411} 435}
412 436
413/** 437ssize_t
414 * v9fs_file_write - write to a file 438v9fs_file_write_internal(struct inode *inode, struct p9_fid *fid,
415 * @filp: file pointer to write 439 const char __user *data, size_t count,
416 * @data: data buffer to write data from 440 loff_t *offset, int invalidate)
417 * @count: size of buffer
418 * @offset: offset at which to write data
419 *
420 */
421
422static ssize_t
423v9fs_file_write(struct file *filp, const char __user * data,
424 size_t count, loff_t * offset)
425{ 441{
426 ssize_t retval;
427 size_t total = 0;
428 int n; 442 int n;
429 struct p9_fid *fid; 443 loff_t i_size;
444 size_t total = 0;
430 struct p9_client *clnt; 445 struct p9_client *clnt;
431 struct inode *inode = filp->f_path.dentry->d_inode;
432 loff_t origin = *offset; 446 loff_t origin = *offset;
433 unsigned long pg_start, pg_end; 447 unsigned long pg_start, pg_end;
434 448
435 P9_DPRINTK(P9_DEBUG_VFS, "data %p count %d offset %x\n", data, 449 P9_DPRINTK(P9_DEBUG_VFS, "data %p count %d offset %x\n", data,
436 (int)count, (int)*offset); 450 (int)count, (int)*offset);
437 451
438 fid = filp->private_data;
439 clnt = fid->clnt; 452 clnt = fid->clnt;
440
441 retval = generic_write_checks(filp, &origin, &count, 0);
442 if (retval)
443 goto out;
444
445 retval = -EINVAL;
446 if ((ssize_t) count < 0)
447 goto out;
448 retval = 0;
449 if (!count)
450 goto out;
451
452 do { 453 do {
453 n = p9_client_write(fid, NULL, data+total, origin+total, count); 454 n = p9_client_write(fid, NULL, data+total, origin+total, count);
454 if (n <= 0) 455 if (n <= 0)
@@ -457,25 +458,60 @@ v9fs_file_write(struct file *filp, const char __user * data,
457 total += n; 458 total += n;
458 } while (count > 0); 459 } while (count > 0);
459 460
460 if (total > 0) { 461 if (invalidate && (total > 0)) {
461 pg_start = origin >> PAGE_CACHE_SHIFT; 462 pg_start = origin >> PAGE_CACHE_SHIFT;
462 pg_end = (origin + total - 1) >> PAGE_CACHE_SHIFT; 463 pg_end = (origin + total - 1) >> PAGE_CACHE_SHIFT;
463 if (inode->i_mapping && inode->i_mapping->nrpages) 464 if (inode->i_mapping && inode->i_mapping->nrpages)
464 invalidate_inode_pages2_range(inode->i_mapping, 465 invalidate_inode_pages2_range(inode->i_mapping,
465 pg_start, pg_end); 466 pg_start, pg_end);
466 *offset += total; 467 *offset += total;
467 i_size_write(inode, i_size_read(inode) + total); 468 i_size = i_size_read(inode);
468 inode->i_blocks = (i_size_read(inode) + 512 - 1) >> 9; 469 if (*offset > i_size) {
470 inode_add_bytes(inode, *offset - i_size);
471 i_size_write(inode, *offset);
472 }
469 } 473 }
470
471 if (n < 0) 474 if (n < 0)
472 retval = n; 475 return n;
473 else 476
474 retval = total; 477 return total;
478}
479
480/**
481 * v9fs_file_write - write to a file
482 * @filp: file pointer to write
483 * @data: data buffer to write data from
484 * @count: size of buffer
485 * @offset: offset at which to write data
486 *
487 */
488static ssize_t
489v9fs_file_write(struct file *filp, const char __user * data,
490 size_t count, loff_t *offset)
491{
492 ssize_t retval = 0;
493 loff_t origin = *offset;
494
495
496 retval = generic_write_checks(filp, &origin, &count, 0);
497 if (retval)
498 goto out;
499
500 retval = -EINVAL;
501 if ((ssize_t) count < 0)
502 goto out;
503 retval = 0;
504 if (!count)
505 goto out;
506
507 return v9fs_file_write_internal(filp->f_path.dentry->d_inode,
508 filp->private_data,
509 data, count, offset, 1);
475out: 510out:
476 return retval; 511 return retval;
477} 512}
478 513
514
479static int v9fs_file_fsync(struct file *filp, int datasync) 515static int v9fs_file_fsync(struct file *filp, int datasync)
480{ 516{
481 struct p9_fid *fid; 517 struct p9_fid *fid;
@@ -505,28 +541,182 @@ int v9fs_file_fsync_dotl(struct file *filp, int datasync)
505 return retval; 541 return retval;
506} 542}
507 543
508static const struct file_operations v9fs_cached_file_operations = { 544static int
545v9fs_file_mmap(struct file *file, struct vm_area_struct *vma)
546{
547 int retval;
548
549 retval = generic_file_mmap(file, vma);
550 if (!retval)
551 vma->vm_ops = &v9fs_file_vm_ops;
552
553 return retval;
554}
555
556static int
557v9fs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
558{
559 struct v9fs_inode *v9inode;
560 struct page *page = vmf->page;
561 struct file *filp = vma->vm_file;
562 struct inode *inode = filp->f_path.dentry->d_inode;
563
564
565 P9_DPRINTK(P9_DEBUG_VFS, "page %p fid %lx\n",
566 page, (unsigned long)filp->private_data);
567
568 v9inode = V9FS_I(inode);
569 /* make sure the cache has finished storing the page */
570 v9fs_fscache_wait_on_page_write(inode, page);
571 BUG_ON(!v9inode->writeback_fid);
572 lock_page(page);
573 if (page->mapping != inode->i_mapping)
574 goto out_unlock;
575
576 return VM_FAULT_LOCKED;
577out_unlock:
578 unlock_page(page);
579 return VM_FAULT_NOPAGE;
580}
581
582static ssize_t
583v9fs_direct_read(struct file *filp, char __user *udata, size_t count,
584 loff_t *offsetp)
585{
586 loff_t size, offset;
587 struct inode *inode;
588 struct address_space *mapping;
589
590 offset = *offsetp;
591 mapping = filp->f_mapping;
592 inode = mapping->host;
593 if (!count)
594 return 0;
595 size = i_size_read(inode);
596 if (offset < size)
597 filemap_write_and_wait_range(mapping, offset,
598 offset + count - 1);
599
600 return v9fs_file_read(filp, udata, count, offsetp);
601}
602
603/**
604 * v9fs_cached_file_read - read from a file
605 * @filp: file pointer to read
606 * @udata: user data buffer to read data into
607 * @count: size of buffer
608 * @offset: offset at which to read data
609 *
610 */
611static ssize_t
612v9fs_cached_file_read(struct file *filp, char __user *data, size_t count,
613 loff_t *offset)
614{
615 if (filp->f_flags & O_DIRECT)
616 return v9fs_direct_read(filp, data, count, offset);
617 return do_sync_read(filp, data, count, offset);
618}
619
620static ssize_t
621v9fs_direct_write(struct file *filp, const char __user * data,
622 size_t count, loff_t *offsetp)
623{
624 loff_t offset;
625 ssize_t retval;
626 struct inode *inode;
627 struct address_space *mapping;
628
629 offset = *offsetp;
630 mapping = filp->f_mapping;
631 inode = mapping->host;
632 if (!count)
633 return 0;
634
635 mutex_lock(&inode->i_mutex);
636 retval = filemap_write_and_wait_range(mapping, offset,
637 offset + count - 1);
638 if (retval)
639 goto err_out;
640 /*
641 * After a write we want buffered reads to be sure to go to disk to get
642 * the new data. We invalidate clean cached page from the region we're
643 * about to write. We do this *before* the write so that if we fail
644 * here we fall back to buffered write
645 */
646 if (mapping->nrpages) {
647 pgoff_t pg_start = offset >> PAGE_CACHE_SHIFT;
648 pgoff_t pg_end = (offset + count - 1) >> PAGE_CACHE_SHIFT;
649
650 retval = invalidate_inode_pages2_range(mapping,
651 pg_start, pg_end);
652 /*
653 * If a page can not be invalidated, fall back
654 * to buffered write.
655 */
656 if (retval) {
657 if (retval == -EBUSY)
658 goto buff_write;
659 goto err_out;
660 }
661 }
662 retval = v9fs_file_write(filp, data, count, offsetp);
663err_out:
664 mutex_unlock(&inode->i_mutex);
665 return retval;
666
667buff_write:
668 mutex_unlock(&inode->i_mutex);
669 return do_sync_write(filp, data, count, offsetp);
670}
671
672/**
673 * v9fs_cached_file_write - write to a file
674 * @filp: file pointer to write
675 * @data: data buffer to write data from
676 * @count: size of buffer
677 * @offset: offset at which to write data
678 *
679 */
680static ssize_t
681v9fs_cached_file_write(struct file *filp, const char __user * data,
682 size_t count, loff_t *offset)
683{
684
685 if (filp->f_flags & O_DIRECT)
686 return v9fs_direct_write(filp, data, count, offset);
687 return do_sync_write(filp, data, count, offset);
688}
689
690static const struct vm_operations_struct v9fs_file_vm_ops = {
691 .fault = filemap_fault,
692 .page_mkwrite = v9fs_vm_page_mkwrite,
693};
694
695
696const struct file_operations v9fs_cached_file_operations = {
509 .llseek = generic_file_llseek, 697 .llseek = generic_file_llseek,
510 .read = do_sync_read, 698 .read = v9fs_cached_file_read,
699 .write = v9fs_cached_file_write,
511 .aio_read = generic_file_aio_read, 700 .aio_read = generic_file_aio_read,
512 .write = v9fs_file_write, 701 .aio_write = generic_file_aio_write,
513 .open = v9fs_file_open, 702 .open = v9fs_file_open,
514 .release = v9fs_dir_release, 703 .release = v9fs_dir_release,
515 .lock = v9fs_file_lock, 704 .lock = v9fs_file_lock,
516 .mmap = generic_file_readonly_mmap, 705 .mmap = v9fs_file_mmap,
517 .fsync = v9fs_file_fsync, 706 .fsync = v9fs_file_fsync,
518}; 707};
519 708
520static const struct file_operations v9fs_cached_file_operations_dotl = { 709const struct file_operations v9fs_cached_file_operations_dotl = {
521 .llseek = generic_file_llseek, 710 .llseek = generic_file_llseek,
522 .read = do_sync_read, 711 .read = v9fs_cached_file_read,
712 .write = v9fs_cached_file_write,
523 .aio_read = generic_file_aio_read, 713 .aio_read = generic_file_aio_read,
524 .write = v9fs_file_write, 714 .aio_write = generic_file_aio_write,
525 .open = v9fs_file_open, 715 .open = v9fs_file_open,
526 .release = v9fs_dir_release, 716 .release = v9fs_dir_release,
527 .lock = v9fs_file_lock_dotl, 717 .lock = v9fs_file_lock_dotl,
528 .flock = v9fs_file_flock_dotl, 718 .flock = v9fs_file_flock_dotl,
529 .mmap = generic_file_readonly_mmap, 719 .mmap = v9fs_file_mmap,
530 .fsync = v9fs_file_fsync_dotl, 720 .fsync = v9fs_file_fsync_dotl,
531}; 721};
532 722