passthrough.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * FUSE passthrough to backing file.
  4. *
  5. * Copyright (c) 2023 CTERA Networks.
  6. */
  7. #include "fuse_i.h"
  8. #include <linux/file.h>
  9. #include <linux/backing-file.h>
  10. #include <linux/splice.h>
  11. static void fuse_file_accessed(struct file *file)
  12. {
  13. struct inode *inode = file_inode(file);
  14. fuse_invalidate_atime(inode);
  15. }
  16. static void fuse_passthrough_end_write(struct kiocb *iocb, ssize_t ret)
  17. {
  18. struct inode *inode = file_inode(iocb->ki_filp);
  19. fuse_write_update_attr(inode, iocb->ki_pos, ret);
  20. }
  21. ssize_t fuse_passthrough_read_iter(struct kiocb *iocb, struct iov_iter *iter)
  22. {
  23. struct file *file = iocb->ki_filp;
  24. struct fuse_file *ff = file->private_data;
  25. struct file *backing_file = fuse_file_passthrough(ff);
  26. size_t count = iov_iter_count(iter);
  27. ssize_t ret;
  28. struct backing_file_ctx ctx = {
  29. .cred = ff->cred,
  30. .accessed = fuse_file_accessed,
  31. };
  32. pr_debug("%s: backing_file=0x%p, pos=%lld, len=%zu\n", __func__,
  33. backing_file, iocb->ki_pos, count);
  34. if (!count)
  35. return 0;
  36. ret = backing_file_read_iter(backing_file, iter, iocb, iocb->ki_flags,
  37. &ctx);
  38. return ret;
  39. }
  40. ssize_t fuse_passthrough_write_iter(struct kiocb *iocb,
  41. struct iov_iter *iter)
  42. {
  43. struct file *file = iocb->ki_filp;
  44. struct inode *inode = file_inode(file);
  45. struct fuse_file *ff = file->private_data;
  46. struct file *backing_file = fuse_file_passthrough(ff);
  47. size_t count = iov_iter_count(iter);
  48. ssize_t ret;
  49. struct backing_file_ctx ctx = {
  50. .cred = ff->cred,
  51. .end_write = fuse_passthrough_end_write,
  52. };
  53. pr_debug("%s: backing_file=0x%p, pos=%lld, len=%zu\n", __func__,
  54. backing_file, iocb->ki_pos, count);
  55. if (!count)
  56. return 0;
  57. inode_lock(inode);
  58. ret = backing_file_write_iter(backing_file, iter, iocb, iocb->ki_flags,
  59. &ctx);
  60. inode_unlock(inode);
  61. return ret;
  62. }
  63. ssize_t fuse_passthrough_splice_read(struct file *in, loff_t *ppos,
  64. struct pipe_inode_info *pipe,
  65. size_t len, unsigned int flags)
  66. {
  67. struct fuse_file *ff = in->private_data;
  68. struct file *backing_file = fuse_file_passthrough(ff);
  69. struct backing_file_ctx ctx = {
  70. .cred = ff->cred,
  71. .accessed = fuse_file_accessed,
  72. };
  73. struct kiocb iocb;
  74. ssize_t ret;
  75. pr_debug("%s: backing_file=0x%p, pos=%lld, len=%zu, flags=0x%x\n", __func__,
  76. backing_file, *ppos, len, flags);
  77. init_sync_kiocb(&iocb, in);
  78. iocb.ki_pos = *ppos;
  79. ret = backing_file_splice_read(backing_file, &iocb, pipe, len, flags, &ctx);
  80. *ppos = iocb.ki_pos;
  81. return ret;
  82. }
  83. ssize_t fuse_passthrough_splice_write(struct pipe_inode_info *pipe,
  84. struct file *out, loff_t *ppos,
  85. size_t len, unsigned int flags)
  86. {
  87. struct fuse_file *ff = out->private_data;
  88. struct file *backing_file = fuse_file_passthrough(ff);
  89. struct inode *inode = file_inode(out);
  90. ssize_t ret;
  91. struct backing_file_ctx ctx = {
  92. .cred = ff->cred,
  93. .end_write = fuse_passthrough_end_write,
  94. };
  95. struct kiocb iocb;
  96. pr_debug("%s: backing_file=0x%p, pos=%lld, len=%zu, flags=0x%x\n", __func__,
  97. backing_file, *ppos, len, flags);
  98. inode_lock(inode);
  99. init_sync_kiocb(&iocb, out);
  100. iocb.ki_pos = *ppos;
  101. ret = backing_file_splice_write(pipe, backing_file, &iocb, len, flags, &ctx);
  102. *ppos = iocb.ki_pos;
  103. inode_unlock(inode);
  104. return ret;
  105. }
  106. ssize_t fuse_passthrough_mmap(struct file *file, struct vm_area_struct *vma)
  107. {
  108. struct fuse_file *ff = file->private_data;
  109. struct file *backing_file = fuse_file_passthrough(ff);
  110. struct backing_file_ctx ctx = {
  111. .cred = ff->cred,
  112. .accessed = fuse_file_accessed,
  113. };
  114. pr_debug("%s: backing_file=0x%p, start=%lu, end=%lu\n", __func__,
  115. backing_file, vma->vm_start, vma->vm_end);
  116. return backing_file_mmap(backing_file, vma, &ctx);
  117. }
  118. /*
  119. * Setup passthrough to a backing file.
  120. *
  121. * Returns an fb object with elevated refcount to be stored in fuse inode.
  122. */
  123. struct fuse_backing *fuse_passthrough_open(struct file *file, int backing_id)
  124. {
  125. struct fuse_file *ff = file->private_data;
  126. struct fuse_conn *fc = ff->fm->fc;
  127. struct fuse_backing *fb = NULL;
  128. struct file *backing_file;
  129. int err;
  130. err = -EINVAL;
  131. if (backing_id <= 0)
  132. goto out;
  133. err = -ENOENT;
  134. fb = fuse_backing_lookup(fc, backing_id);
  135. if (!fb)
  136. goto out;
  137. /* Allocate backing file per fuse file to store fuse path */
  138. backing_file = backing_file_open(&file->f_path, file->f_flags,
  139. &fb->file->f_path, fb->cred);
  140. err = PTR_ERR(backing_file);
  141. if (IS_ERR(backing_file)) {
  142. fuse_backing_put(fb);
  143. goto out;
  144. }
  145. err = 0;
  146. ff->passthrough = backing_file;
  147. ff->cred = get_cred(fb->cred);
  148. out:
  149. pr_debug("%s: backing_id=%d, fb=0x%p, backing_file=0x%p, err=%i\n", __func__,
  150. backing_id, fb, ff->passthrough, err);
  151. return err ? ERR_PTR(err) : fb;
  152. }
  153. void fuse_passthrough_release(struct fuse_file *ff, struct fuse_backing *fb)
  154. {
  155. pr_debug("%s: fb=0x%p, backing_file=0x%p\n", __func__,
  156. fb, ff->passthrough);
  157. fput(ff->passthrough);
  158. ff->passthrough = NULL;
  159. put_cred(ff->cred);
  160. ff->cred = NULL;
  161. }