18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci FUSE: Filesystem in Userspace 38c2ecf20Sopenharmony_ci Copyright (C) 2001-2008 Miklos Szeredi <miklos@szeredi.hu> 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci This program can be distributed under the terms of the GNU GPL. 68c2ecf20Sopenharmony_ci See the file COPYING. 78c2ecf20Sopenharmony_ci*/ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "fuse_i.h" 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/pagemap.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/sched.h> 158c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 168c2ecf20Sopenharmony_ci#include <linux/module.h> 178c2ecf20Sopenharmony_ci#include <linux/compat.h> 188c2ecf20Sopenharmony_ci#include <linux/swap.h> 198c2ecf20Sopenharmony_ci#include <linux/falloc.h> 208c2ecf20Sopenharmony_ci#include <linux/uio.h> 218c2ecf20Sopenharmony_ci#include <linux/fs.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic struct page **fuse_pages_alloc(unsigned int npages, gfp_t flags, 248c2ecf20Sopenharmony_ci struct fuse_page_desc **desc) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci struct page **pages; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci pages = kzalloc(npages * (sizeof(struct page *) + 298c2ecf20Sopenharmony_ci sizeof(struct fuse_page_desc)), flags); 308c2ecf20Sopenharmony_ci *desc = (void *) (pages + npages); 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci return pages; 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic int fuse_send_open(struct fuse_mount *fm, u64 nodeid, struct file *file, 368c2ecf20Sopenharmony_ci int opcode, struct fuse_open_out *outargp) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci struct fuse_open_in inarg; 398c2ecf20Sopenharmony_ci FUSE_ARGS(args); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci memset(&inarg, 0, sizeof(inarg)); 428c2ecf20Sopenharmony_ci inarg.flags = file->f_flags & ~(O_CREAT | O_EXCL | O_NOCTTY); 438c2ecf20Sopenharmony_ci if (!fm->fc->atomic_o_trunc) 448c2ecf20Sopenharmony_ci inarg.flags &= ~O_TRUNC; 458c2ecf20Sopenharmony_ci args.opcode = opcode; 468c2ecf20Sopenharmony_ci args.nodeid = nodeid; 478c2ecf20Sopenharmony_ci args.in_numargs = 1; 488c2ecf20Sopenharmony_ci args.in_args[0].size = sizeof(inarg); 498c2ecf20Sopenharmony_ci args.in_args[0].value = &inarg; 508c2ecf20Sopenharmony_ci args.out_numargs = 1; 518c2ecf20Sopenharmony_ci args.out_args[0].size = sizeof(*outargp); 528c2ecf20Sopenharmony_ci args.out_args[0].value = outargp; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci return fuse_simple_request(fm, &args); 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistruct fuse_release_args { 588c2ecf20Sopenharmony_ci struct fuse_args args; 598c2ecf20Sopenharmony_ci struct fuse_release_in inarg; 608c2ecf20Sopenharmony_ci struct inode *inode; 618c2ecf20Sopenharmony_ci}; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistruct fuse_file *fuse_file_alloc(struct fuse_mount *fm) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci struct fuse_file *ff; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci ff = kzalloc(sizeof(struct fuse_file), GFP_KERNEL_ACCOUNT); 688c2ecf20Sopenharmony_ci if (unlikely(!ff)) 698c2ecf20Sopenharmony_ci return NULL; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci ff->fm = fm; 728c2ecf20Sopenharmony_ci ff->release_args = kzalloc(sizeof(*ff->release_args), 738c2ecf20Sopenharmony_ci GFP_KERNEL_ACCOUNT); 748c2ecf20Sopenharmony_ci if (!ff->release_args) { 758c2ecf20Sopenharmony_ci kfree(ff); 768c2ecf20Sopenharmony_ci return NULL; 778c2ecf20Sopenharmony_ci } 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ff->write_entry); 808c2ecf20Sopenharmony_ci mutex_init(&ff->readdir.lock); 818c2ecf20Sopenharmony_ci refcount_set(&ff->count, 1); 828c2ecf20Sopenharmony_ci RB_CLEAR_NODE(&ff->polled_node); 838c2ecf20Sopenharmony_ci init_waitqueue_head(&ff->poll_wait); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci ff->kh = atomic64_inc_return(&fm->fc->khctr); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci return ff; 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_civoid fuse_file_free(struct fuse_file *ff) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci kfree(ff->release_args); 938c2ecf20Sopenharmony_ci mutex_destroy(&ff->readdir.lock); 948c2ecf20Sopenharmony_ci kfree(ff); 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic struct fuse_file *fuse_file_get(struct fuse_file *ff) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci refcount_inc(&ff->count); 1008c2ecf20Sopenharmony_ci return ff; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic void fuse_release_end(struct fuse_mount *fm, struct fuse_args *args, 1048c2ecf20Sopenharmony_ci int error) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci struct fuse_release_args *ra = container_of(args, typeof(*ra), args); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci iput(ra->inode); 1098c2ecf20Sopenharmony_ci kfree(ra); 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic void fuse_file_put(struct fuse_file *ff, bool sync, bool isdir) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci if (refcount_dec_and_test(&ff->count)) { 1158c2ecf20Sopenharmony_ci struct fuse_args *args = &ff->release_args->args; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci if (isdir ? ff->fm->fc->no_opendir : ff->fm->fc->no_open) { 1188c2ecf20Sopenharmony_ci /* Do nothing when client does not implement 'open' */ 1198c2ecf20Sopenharmony_ci fuse_release_end(ff->fm, args, 0); 1208c2ecf20Sopenharmony_ci } else if (sync) { 1218c2ecf20Sopenharmony_ci fuse_simple_request(ff->fm, args); 1228c2ecf20Sopenharmony_ci fuse_release_end(ff->fm, args, 0); 1238c2ecf20Sopenharmony_ci } else { 1248c2ecf20Sopenharmony_ci args->end = fuse_release_end; 1258c2ecf20Sopenharmony_ci if (fuse_simple_background(ff->fm, args, 1268c2ecf20Sopenharmony_ci GFP_KERNEL | __GFP_NOFAIL)) 1278c2ecf20Sopenharmony_ci fuse_release_end(ff->fm, args, -ENOTCONN); 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci kfree(ff); 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ciint fuse_do_open(struct fuse_mount *fm, u64 nodeid, struct file *file, 1348c2ecf20Sopenharmony_ci bool isdir) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci struct fuse_conn *fc = fm->fc; 1378c2ecf20Sopenharmony_ci struct fuse_file *ff; 1388c2ecf20Sopenharmony_ci int opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci ff = fuse_file_alloc(fm); 1418c2ecf20Sopenharmony_ci if (!ff) 1428c2ecf20Sopenharmony_ci return -ENOMEM; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci ff->fh = 0; 1458c2ecf20Sopenharmony_ci /* Default for no-open */ 1468c2ecf20Sopenharmony_ci ff->open_flags = FOPEN_KEEP_CACHE | (isdir ? FOPEN_CACHE_DIR : 0); 1478c2ecf20Sopenharmony_ci if (isdir ? !fc->no_opendir : !fc->no_open) { 1488c2ecf20Sopenharmony_ci struct fuse_open_out outarg; 1498c2ecf20Sopenharmony_ci int err; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci err = fuse_send_open(fm, nodeid, file, opcode, &outarg); 1528c2ecf20Sopenharmony_ci if (!err) { 1538c2ecf20Sopenharmony_ci ff->fh = outarg.fh; 1548c2ecf20Sopenharmony_ci ff->open_flags = outarg.open_flags; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci } else if (err != -ENOSYS) { 1578c2ecf20Sopenharmony_ci fuse_file_free(ff); 1588c2ecf20Sopenharmony_ci return err; 1598c2ecf20Sopenharmony_ci } else { 1608c2ecf20Sopenharmony_ci if (isdir) 1618c2ecf20Sopenharmony_ci fc->no_opendir = 1; 1628c2ecf20Sopenharmony_ci else 1638c2ecf20Sopenharmony_ci fc->no_open = 1; 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci if (isdir) 1688c2ecf20Sopenharmony_ci ff->open_flags &= ~FOPEN_DIRECT_IO; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci ff->nodeid = nodeid; 1718c2ecf20Sopenharmony_ci file->private_data = ff; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci return 0; 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(fuse_do_open); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistatic void fuse_link_write_file(struct file *file) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 1808c2ecf20Sopenharmony_ci struct fuse_inode *fi = get_fuse_inode(inode); 1818c2ecf20Sopenharmony_ci struct fuse_file *ff = file->private_data; 1828c2ecf20Sopenharmony_ci /* 1838c2ecf20Sopenharmony_ci * file may be written through mmap, so chain it onto the 1848c2ecf20Sopenharmony_ci * inodes's write_file list 1858c2ecf20Sopenharmony_ci */ 1868c2ecf20Sopenharmony_ci spin_lock(&fi->lock); 1878c2ecf20Sopenharmony_ci if (list_empty(&ff->write_entry)) 1888c2ecf20Sopenharmony_ci list_add(&ff->write_entry, &fi->write_files); 1898c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_civoid fuse_finish_open(struct inode *inode, struct file *file) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci struct fuse_file *ff = file->private_data; 1958c2ecf20Sopenharmony_ci struct fuse_conn *fc = get_fuse_conn(inode); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci if (ff->open_flags & FOPEN_STREAM) 1988c2ecf20Sopenharmony_ci stream_open(inode, file); 1998c2ecf20Sopenharmony_ci else if (ff->open_flags & FOPEN_NONSEEKABLE) 2008c2ecf20Sopenharmony_ci nonseekable_open(inode, file); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci if (fc->atomic_o_trunc && (file->f_flags & O_TRUNC)) { 2038c2ecf20Sopenharmony_ci struct fuse_inode *fi = get_fuse_inode(inode); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci spin_lock(&fi->lock); 2068c2ecf20Sopenharmony_ci fi->attr_version = atomic64_inc_return(&fc->attr_version); 2078c2ecf20Sopenharmony_ci i_size_write(inode, 0); 2088c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 2098c2ecf20Sopenharmony_ci fuse_invalidate_attr(inode); 2108c2ecf20Sopenharmony_ci if (fc->writeback_cache) 2118c2ecf20Sopenharmony_ci file_update_time(file); 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci if ((file->f_mode & FMODE_WRITE) && fc->writeback_cache) 2148c2ecf20Sopenharmony_ci fuse_link_write_file(file); 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ciint fuse_open_common(struct inode *inode, struct file *file, bool isdir) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci struct fuse_mount *fm = get_fuse_mount(inode); 2208c2ecf20Sopenharmony_ci struct fuse_conn *fc = fm->fc; 2218c2ecf20Sopenharmony_ci int err; 2228c2ecf20Sopenharmony_ci bool is_wb_truncate = (file->f_flags & O_TRUNC) && 2238c2ecf20Sopenharmony_ci fc->atomic_o_trunc && 2248c2ecf20Sopenharmony_ci fc->writeback_cache; 2258c2ecf20Sopenharmony_ci bool dax_truncate = (file->f_flags & O_TRUNC) && 2268c2ecf20Sopenharmony_ci fc->atomic_o_trunc && FUSE_IS_DAX(inode); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci if (fuse_is_bad(inode)) 2298c2ecf20Sopenharmony_ci return -EIO; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci err = generic_file_open(inode, file); 2328c2ecf20Sopenharmony_ci if (err) 2338c2ecf20Sopenharmony_ci return err; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci if (is_wb_truncate || dax_truncate) 2368c2ecf20Sopenharmony_ci inode_lock(inode); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci if (dax_truncate) { 2398c2ecf20Sopenharmony_ci down_write(&get_fuse_inode(inode)->i_mmap_sem); 2408c2ecf20Sopenharmony_ci err = fuse_dax_break_layouts(inode, 0, 0); 2418c2ecf20Sopenharmony_ci if (err) 2428c2ecf20Sopenharmony_ci goto out_inode_unlock; 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci if (is_wb_truncate || dax_truncate) 2468c2ecf20Sopenharmony_ci fuse_set_nowrite(inode); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci err = fuse_do_open(fm, get_node_id(inode), file, isdir); 2498c2ecf20Sopenharmony_ci if (!err) 2508c2ecf20Sopenharmony_ci fuse_finish_open(inode, file); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci if (is_wb_truncate || dax_truncate) 2538c2ecf20Sopenharmony_ci fuse_release_nowrite(inode); 2548c2ecf20Sopenharmony_ci if (!err) { 2558c2ecf20Sopenharmony_ci struct fuse_file *ff = file->private_data; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci if (fc->atomic_o_trunc && (file->f_flags & O_TRUNC)) 2588c2ecf20Sopenharmony_ci truncate_pagecache(inode, 0); 2598c2ecf20Sopenharmony_ci else if (!(ff->open_flags & FOPEN_KEEP_CACHE)) 2608c2ecf20Sopenharmony_ci invalidate_inode_pages2(inode->i_mapping); 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci if (dax_truncate) 2638c2ecf20Sopenharmony_ci up_write(&get_fuse_inode(inode)->i_mmap_sem); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ciout_inode_unlock: 2668c2ecf20Sopenharmony_ci if (is_wb_truncate || dax_truncate) 2678c2ecf20Sopenharmony_ci inode_unlock(inode); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci return err; 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cistatic void fuse_prepare_release(struct fuse_inode *fi, struct fuse_file *ff, 2738c2ecf20Sopenharmony_ci int flags, int opcode) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci struct fuse_conn *fc = ff->fm->fc; 2768c2ecf20Sopenharmony_ci struct fuse_release_args *ra = ff->release_args; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci /* Inode is NULL on error path of fuse_create_open() */ 2798c2ecf20Sopenharmony_ci if (likely(fi)) { 2808c2ecf20Sopenharmony_ci spin_lock(&fi->lock); 2818c2ecf20Sopenharmony_ci list_del(&ff->write_entry); 2828c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci spin_lock(&fc->lock); 2858c2ecf20Sopenharmony_ci if (!RB_EMPTY_NODE(&ff->polled_node)) 2868c2ecf20Sopenharmony_ci rb_erase(&ff->polled_node, &fc->polled_files); 2878c2ecf20Sopenharmony_ci spin_unlock(&fc->lock); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci wake_up_interruptible_all(&ff->poll_wait); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci ra->inarg.fh = ff->fh; 2928c2ecf20Sopenharmony_ci ra->inarg.flags = flags; 2938c2ecf20Sopenharmony_ci ra->args.in_numargs = 1; 2948c2ecf20Sopenharmony_ci ra->args.in_args[0].size = sizeof(struct fuse_release_in); 2958c2ecf20Sopenharmony_ci ra->args.in_args[0].value = &ra->inarg; 2968c2ecf20Sopenharmony_ci ra->args.opcode = opcode; 2978c2ecf20Sopenharmony_ci ra->args.nodeid = ff->nodeid; 2988c2ecf20Sopenharmony_ci ra->args.force = true; 2998c2ecf20Sopenharmony_ci ra->args.nocreds = true; 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_civoid fuse_release_common(struct file *file, bool isdir) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci struct fuse_inode *fi = get_fuse_inode(file_inode(file)); 3058c2ecf20Sopenharmony_ci struct fuse_file *ff = file->private_data; 3068c2ecf20Sopenharmony_ci struct fuse_release_args *ra = ff->release_args; 3078c2ecf20Sopenharmony_ci int opcode = isdir ? FUSE_RELEASEDIR : FUSE_RELEASE; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci fuse_prepare_release(fi, ff, file->f_flags, opcode); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (ff->flock) { 3128c2ecf20Sopenharmony_ci ra->inarg.release_flags |= FUSE_RELEASE_FLOCK_UNLOCK; 3138c2ecf20Sopenharmony_ci ra->inarg.lock_owner = fuse_lock_owner_id(ff->fm->fc, 3148c2ecf20Sopenharmony_ci (fl_owner_t) file); 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci /* Hold inode until release is finished */ 3178c2ecf20Sopenharmony_ci ra->inode = igrab(file_inode(file)); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci /* 3208c2ecf20Sopenharmony_ci * Normally this will send the RELEASE request, however if 3218c2ecf20Sopenharmony_ci * some asynchronous READ or WRITE requests are outstanding, 3228c2ecf20Sopenharmony_ci * the sending will be delayed. 3238c2ecf20Sopenharmony_ci * 3248c2ecf20Sopenharmony_ci * Make the release synchronous if this is a fuseblk mount, 3258c2ecf20Sopenharmony_ci * synchronous RELEASE is allowed (and desirable) in this case 3268c2ecf20Sopenharmony_ci * because the server can be trusted not to screw up. 3278c2ecf20Sopenharmony_ci */ 3288c2ecf20Sopenharmony_ci fuse_file_put(ff, ff->fm->fc->destroy, isdir); 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_cistatic int fuse_open(struct inode *inode, struct file *file) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci return fuse_open_common(inode, file, false); 3348c2ecf20Sopenharmony_ci} 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_cistatic int fuse_release(struct inode *inode, struct file *file) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci struct fuse_conn *fc = get_fuse_conn(inode); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci /* see fuse_vma_close() for !writeback_cache case */ 3418c2ecf20Sopenharmony_ci if (fc->writeback_cache) 3428c2ecf20Sopenharmony_ci write_inode_now(inode, 1); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci fuse_release_common(file, false); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci /* return value is ignored by VFS */ 3478c2ecf20Sopenharmony_ci return 0; 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_civoid fuse_sync_release(struct fuse_inode *fi, struct fuse_file *ff, int flags) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci WARN_ON(refcount_read(&ff->count) > 1); 3538c2ecf20Sopenharmony_ci fuse_prepare_release(fi, ff, flags, FUSE_RELEASE); 3548c2ecf20Sopenharmony_ci /* 3558c2ecf20Sopenharmony_ci * iput(NULL) is a no-op and since the refcount is 1 and everything's 3568c2ecf20Sopenharmony_ci * synchronous, we are fine with not doing igrab() here" 3578c2ecf20Sopenharmony_ci */ 3588c2ecf20Sopenharmony_ci fuse_file_put(ff, true, false); 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(fuse_sync_release); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci/* 3638c2ecf20Sopenharmony_ci * Scramble the ID space with XTEA, so that the value of the files_struct 3648c2ecf20Sopenharmony_ci * pointer is not exposed to userspace. 3658c2ecf20Sopenharmony_ci */ 3668c2ecf20Sopenharmony_ciu64 fuse_lock_owner_id(struct fuse_conn *fc, fl_owner_t id) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci u32 *k = fc->scramble_key; 3698c2ecf20Sopenharmony_ci u64 v = (unsigned long) id; 3708c2ecf20Sopenharmony_ci u32 v0 = v; 3718c2ecf20Sopenharmony_ci u32 v1 = v >> 32; 3728c2ecf20Sopenharmony_ci u32 sum = 0; 3738c2ecf20Sopenharmony_ci int i; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci for (i = 0; i < 32; i++) { 3768c2ecf20Sopenharmony_ci v0 += ((v1 << 4 ^ v1 >> 5) + v1) ^ (sum + k[sum & 3]); 3778c2ecf20Sopenharmony_ci sum += 0x9E3779B9; 3788c2ecf20Sopenharmony_ci v1 += ((v0 << 4 ^ v0 >> 5) + v0) ^ (sum + k[sum>>11 & 3]); 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci return (u64) v0 + ((u64) v1 << 32); 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_cistruct fuse_writepage_args { 3858c2ecf20Sopenharmony_ci struct fuse_io_args ia; 3868c2ecf20Sopenharmony_ci struct rb_node writepages_entry; 3878c2ecf20Sopenharmony_ci struct list_head queue_entry; 3888c2ecf20Sopenharmony_ci struct fuse_writepage_args *next; 3898c2ecf20Sopenharmony_ci struct inode *inode; 3908c2ecf20Sopenharmony_ci}; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_cistatic struct fuse_writepage_args *fuse_find_writeback(struct fuse_inode *fi, 3938c2ecf20Sopenharmony_ci pgoff_t idx_from, pgoff_t idx_to) 3948c2ecf20Sopenharmony_ci{ 3958c2ecf20Sopenharmony_ci struct rb_node *n; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci n = fi->writepages.rb_node; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci while (n) { 4008c2ecf20Sopenharmony_ci struct fuse_writepage_args *wpa; 4018c2ecf20Sopenharmony_ci pgoff_t curr_index; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci wpa = rb_entry(n, struct fuse_writepage_args, writepages_entry); 4048c2ecf20Sopenharmony_ci WARN_ON(get_fuse_inode(wpa->inode) != fi); 4058c2ecf20Sopenharmony_ci curr_index = wpa->ia.write.in.offset >> PAGE_SHIFT; 4068c2ecf20Sopenharmony_ci if (idx_from >= curr_index + wpa->ia.ap.num_pages) 4078c2ecf20Sopenharmony_ci n = n->rb_right; 4088c2ecf20Sopenharmony_ci else if (idx_to < curr_index) 4098c2ecf20Sopenharmony_ci n = n->rb_left; 4108c2ecf20Sopenharmony_ci else 4118c2ecf20Sopenharmony_ci return wpa; 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci return NULL; 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci/* 4178c2ecf20Sopenharmony_ci * Check if any page in a range is under writeback 4188c2ecf20Sopenharmony_ci * 4198c2ecf20Sopenharmony_ci * This is currently done by walking the list of writepage requests 4208c2ecf20Sopenharmony_ci * for the inode, which can be pretty inefficient. 4218c2ecf20Sopenharmony_ci */ 4228c2ecf20Sopenharmony_cistatic bool fuse_range_is_writeback(struct inode *inode, pgoff_t idx_from, 4238c2ecf20Sopenharmony_ci pgoff_t idx_to) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci struct fuse_inode *fi = get_fuse_inode(inode); 4268c2ecf20Sopenharmony_ci bool found; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci spin_lock(&fi->lock); 4298c2ecf20Sopenharmony_ci found = fuse_find_writeback(fi, idx_from, idx_to); 4308c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci return found; 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cistatic inline bool fuse_page_is_writeback(struct inode *inode, pgoff_t index) 4368c2ecf20Sopenharmony_ci{ 4378c2ecf20Sopenharmony_ci return fuse_range_is_writeback(inode, index, index); 4388c2ecf20Sopenharmony_ci} 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci/* 4418c2ecf20Sopenharmony_ci * Wait for page writeback to be completed. 4428c2ecf20Sopenharmony_ci * 4438c2ecf20Sopenharmony_ci * Since fuse doesn't rely on the VM writeback tracking, this has to 4448c2ecf20Sopenharmony_ci * use some other means. 4458c2ecf20Sopenharmony_ci */ 4468c2ecf20Sopenharmony_cistatic void fuse_wait_on_page_writeback(struct inode *inode, pgoff_t index) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci struct fuse_inode *fi = get_fuse_inode(inode); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci wait_event(fi->page_waitq, !fuse_page_is_writeback(inode, index)); 4518c2ecf20Sopenharmony_ci} 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci/* 4548c2ecf20Sopenharmony_ci * Wait for all pending writepages on the inode to finish. 4558c2ecf20Sopenharmony_ci * 4568c2ecf20Sopenharmony_ci * This is currently done by blocking further writes with FUSE_NOWRITE 4578c2ecf20Sopenharmony_ci * and waiting for all sent writes to complete. 4588c2ecf20Sopenharmony_ci * 4598c2ecf20Sopenharmony_ci * This must be called under i_mutex, otherwise the FUSE_NOWRITE usage 4608c2ecf20Sopenharmony_ci * could conflict with truncation. 4618c2ecf20Sopenharmony_ci */ 4628c2ecf20Sopenharmony_cistatic void fuse_sync_writes(struct inode *inode) 4638c2ecf20Sopenharmony_ci{ 4648c2ecf20Sopenharmony_ci fuse_set_nowrite(inode); 4658c2ecf20Sopenharmony_ci fuse_release_nowrite(inode); 4668c2ecf20Sopenharmony_ci} 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_cistatic int fuse_flush(struct file *file, fl_owner_t id) 4698c2ecf20Sopenharmony_ci{ 4708c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 4718c2ecf20Sopenharmony_ci struct fuse_mount *fm = get_fuse_mount(inode); 4728c2ecf20Sopenharmony_ci struct fuse_file *ff = file->private_data; 4738c2ecf20Sopenharmony_ci struct fuse_flush_in inarg; 4748c2ecf20Sopenharmony_ci FUSE_ARGS(args); 4758c2ecf20Sopenharmony_ci int err; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci if (fuse_is_bad(inode)) 4788c2ecf20Sopenharmony_ci return -EIO; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci err = write_inode_now(inode, 1); 4818c2ecf20Sopenharmony_ci if (err) 4828c2ecf20Sopenharmony_ci return err; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci inode_lock(inode); 4858c2ecf20Sopenharmony_ci fuse_sync_writes(inode); 4868c2ecf20Sopenharmony_ci inode_unlock(inode); 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci err = filemap_check_errors(file->f_mapping); 4898c2ecf20Sopenharmony_ci if (err) 4908c2ecf20Sopenharmony_ci return err; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci err = 0; 4938c2ecf20Sopenharmony_ci if (fm->fc->no_flush) 4948c2ecf20Sopenharmony_ci goto inval_attr_out; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci memset(&inarg, 0, sizeof(inarg)); 4978c2ecf20Sopenharmony_ci inarg.fh = ff->fh; 4988c2ecf20Sopenharmony_ci inarg.lock_owner = fuse_lock_owner_id(fm->fc, id); 4998c2ecf20Sopenharmony_ci args.opcode = FUSE_FLUSH; 5008c2ecf20Sopenharmony_ci args.nodeid = get_node_id(inode); 5018c2ecf20Sopenharmony_ci args.in_numargs = 1; 5028c2ecf20Sopenharmony_ci args.in_args[0].size = sizeof(inarg); 5038c2ecf20Sopenharmony_ci args.in_args[0].value = &inarg; 5048c2ecf20Sopenharmony_ci args.force = true; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci err = fuse_simple_request(fm, &args); 5078c2ecf20Sopenharmony_ci if (err == -ENOSYS) { 5088c2ecf20Sopenharmony_ci fm->fc->no_flush = 1; 5098c2ecf20Sopenharmony_ci err = 0; 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ciinval_attr_out: 5138c2ecf20Sopenharmony_ci /* 5148c2ecf20Sopenharmony_ci * In memory i_blocks is not maintained by fuse, if writeback cache is 5158c2ecf20Sopenharmony_ci * enabled, i_blocks from cached attr may not be accurate. 5168c2ecf20Sopenharmony_ci */ 5178c2ecf20Sopenharmony_ci if (!err && fm->fc->writeback_cache) 5188c2ecf20Sopenharmony_ci fuse_invalidate_attr(inode); 5198c2ecf20Sopenharmony_ci return err; 5208c2ecf20Sopenharmony_ci} 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ciint fuse_fsync_common(struct file *file, loff_t start, loff_t end, 5238c2ecf20Sopenharmony_ci int datasync, int opcode) 5248c2ecf20Sopenharmony_ci{ 5258c2ecf20Sopenharmony_ci struct inode *inode = file->f_mapping->host; 5268c2ecf20Sopenharmony_ci struct fuse_mount *fm = get_fuse_mount(inode); 5278c2ecf20Sopenharmony_ci struct fuse_file *ff = file->private_data; 5288c2ecf20Sopenharmony_ci FUSE_ARGS(args); 5298c2ecf20Sopenharmony_ci struct fuse_fsync_in inarg; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci memset(&inarg, 0, sizeof(inarg)); 5328c2ecf20Sopenharmony_ci inarg.fh = ff->fh; 5338c2ecf20Sopenharmony_ci inarg.fsync_flags = datasync ? FUSE_FSYNC_FDATASYNC : 0; 5348c2ecf20Sopenharmony_ci args.opcode = opcode; 5358c2ecf20Sopenharmony_ci args.nodeid = get_node_id(inode); 5368c2ecf20Sopenharmony_ci args.in_numargs = 1; 5378c2ecf20Sopenharmony_ci args.in_args[0].size = sizeof(inarg); 5388c2ecf20Sopenharmony_ci args.in_args[0].value = &inarg; 5398c2ecf20Sopenharmony_ci return fuse_simple_request(fm, &args); 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_cistatic int fuse_fsync(struct file *file, loff_t start, loff_t end, 5438c2ecf20Sopenharmony_ci int datasync) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci struct inode *inode = file->f_mapping->host; 5468c2ecf20Sopenharmony_ci struct fuse_conn *fc = get_fuse_conn(inode); 5478c2ecf20Sopenharmony_ci int err; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci if (fuse_is_bad(inode)) 5508c2ecf20Sopenharmony_ci return -EIO; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci inode_lock(inode); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci /* 5558c2ecf20Sopenharmony_ci * Start writeback against all dirty pages of the inode, then 5568c2ecf20Sopenharmony_ci * wait for all outstanding writes, before sending the FSYNC 5578c2ecf20Sopenharmony_ci * request. 5588c2ecf20Sopenharmony_ci */ 5598c2ecf20Sopenharmony_ci err = file_write_and_wait_range(file, start, end); 5608c2ecf20Sopenharmony_ci if (err) 5618c2ecf20Sopenharmony_ci goto out; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci fuse_sync_writes(inode); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci /* 5668c2ecf20Sopenharmony_ci * Due to implementation of fuse writeback 5678c2ecf20Sopenharmony_ci * file_write_and_wait_range() does not catch errors. 5688c2ecf20Sopenharmony_ci * We have to do this directly after fuse_sync_writes() 5698c2ecf20Sopenharmony_ci */ 5708c2ecf20Sopenharmony_ci err = file_check_and_advance_wb_err(file); 5718c2ecf20Sopenharmony_ci if (err) 5728c2ecf20Sopenharmony_ci goto out; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci err = sync_inode_metadata(inode, 1); 5758c2ecf20Sopenharmony_ci if (err) 5768c2ecf20Sopenharmony_ci goto out; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci if (fc->no_fsync) 5798c2ecf20Sopenharmony_ci goto out; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci err = fuse_fsync_common(file, start, end, datasync, FUSE_FSYNC); 5828c2ecf20Sopenharmony_ci if (err == -ENOSYS) { 5838c2ecf20Sopenharmony_ci fc->no_fsync = 1; 5848c2ecf20Sopenharmony_ci err = 0; 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ciout: 5878c2ecf20Sopenharmony_ci inode_unlock(inode); 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci return err; 5908c2ecf20Sopenharmony_ci} 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_civoid fuse_read_args_fill(struct fuse_io_args *ia, struct file *file, loff_t pos, 5938c2ecf20Sopenharmony_ci size_t count, int opcode) 5948c2ecf20Sopenharmony_ci{ 5958c2ecf20Sopenharmony_ci struct fuse_file *ff = file->private_data; 5968c2ecf20Sopenharmony_ci struct fuse_args *args = &ia->ap.args; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci ia->read.in.fh = ff->fh; 5998c2ecf20Sopenharmony_ci ia->read.in.offset = pos; 6008c2ecf20Sopenharmony_ci ia->read.in.size = count; 6018c2ecf20Sopenharmony_ci ia->read.in.flags = file->f_flags; 6028c2ecf20Sopenharmony_ci args->opcode = opcode; 6038c2ecf20Sopenharmony_ci args->nodeid = ff->nodeid; 6048c2ecf20Sopenharmony_ci args->in_numargs = 1; 6058c2ecf20Sopenharmony_ci args->in_args[0].size = sizeof(ia->read.in); 6068c2ecf20Sopenharmony_ci args->in_args[0].value = &ia->read.in; 6078c2ecf20Sopenharmony_ci args->out_argvar = true; 6088c2ecf20Sopenharmony_ci args->out_numargs = 1; 6098c2ecf20Sopenharmony_ci args->out_args[0].size = count; 6108c2ecf20Sopenharmony_ci} 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_cistatic void fuse_release_user_pages(struct fuse_args_pages *ap, 6138c2ecf20Sopenharmony_ci bool should_dirty) 6148c2ecf20Sopenharmony_ci{ 6158c2ecf20Sopenharmony_ci unsigned int i; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci for (i = 0; i < ap->num_pages; i++) { 6188c2ecf20Sopenharmony_ci if (should_dirty) 6198c2ecf20Sopenharmony_ci set_page_dirty_lock(ap->pages[i]); 6208c2ecf20Sopenharmony_ci put_page(ap->pages[i]); 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci} 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_cistatic void fuse_io_release(struct kref *kref) 6258c2ecf20Sopenharmony_ci{ 6268c2ecf20Sopenharmony_ci kfree(container_of(kref, struct fuse_io_priv, refcnt)); 6278c2ecf20Sopenharmony_ci} 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_cistatic ssize_t fuse_get_res_by_io(struct fuse_io_priv *io) 6308c2ecf20Sopenharmony_ci{ 6318c2ecf20Sopenharmony_ci if (io->err) 6328c2ecf20Sopenharmony_ci return io->err; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci if (io->bytes >= 0 && io->write) 6358c2ecf20Sopenharmony_ci return -EIO; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci return io->bytes < 0 ? io->size : io->bytes; 6388c2ecf20Sopenharmony_ci} 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci/** 6418c2ecf20Sopenharmony_ci * In case of short read, the caller sets 'pos' to the position of 6428c2ecf20Sopenharmony_ci * actual end of fuse request in IO request. Otherwise, if bytes_requested 6438c2ecf20Sopenharmony_ci * == bytes_transferred or rw == WRITE, the caller sets 'pos' to -1. 6448c2ecf20Sopenharmony_ci * 6458c2ecf20Sopenharmony_ci * An example: 6468c2ecf20Sopenharmony_ci * User requested DIO read of 64K. It was splitted into two 32K fuse requests, 6478c2ecf20Sopenharmony_ci * both submitted asynchronously. The first of them was ACKed by userspace as 6488c2ecf20Sopenharmony_ci * fully completed (req->out.args[0].size == 32K) resulting in pos == -1. The 6498c2ecf20Sopenharmony_ci * second request was ACKed as short, e.g. only 1K was read, resulting in 6508c2ecf20Sopenharmony_ci * pos == 33K. 6518c2ecf20Sopenharmony_ci * 6528c2ecf20Sopenharmony_ci * Thus, when all fuse requests are completed, the minimal non-negative 'pos' 6538c2ecf20Sopenharmony_ci * will be equal to the length of the longest contiguous fragment of 6548c2ecf20Sopenharmony_ci * transferred data starting from the beginning of IO request. 6558c2ecf20Sopenharmony_ci */ 6568c2ecf20Sopenharmony_cistatic void fuse_aio_complete(struct fuse_io_priv *io, int err, ssize_t pos) 6578c2ecf20Sopenharmony_ci{ 6588c2ecf20Sopenharmony_ci int left; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci spin_lock(&io->lock); 6618c2ecf20Sopenharmony_ci if (err) 6628c2ecf20Sopenharmony_ci io->err = io->err ? : err; 6638c2ecf20Sopenharmony_ci else if (pos >= 0 && (io->bytes < 0 || pos < io->bytes)) 6648c2ecf20Sopenharmony_ci io->bytes = pos; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci left = --io->reqs; 6678c2ecf20Sopenharmony_ci if (!left && io->blocking) 6688c2ecf20Sopenharmony_ci complete(io->done); 6698c2ecf20Sopenharmony_ci spin_unlock(&io->lock); 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci if (!left && !io->blocking) { 6728c2ecf20Sopenharmony_ci ssize_t res = fuse_get_res_by_io(io); 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci if (res >= 0) { 6758c2ecf20Sopenharmony_ci struct inode *inode = file_inode(io->iocb->ki_filp); 6768c2ecf20Sopenharmony_ci struct fuse_conn *fc = get_fuse_conn(inode); 6778c2ecf20Sopenharmony_ci struct fuse_inode *fi = get_fuse_inode(inode); 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci spin_lock(&fi->lock); 6808c2ecf20Sopenharmony_ci fi->attr_version = atomic64_inc_return(&fc->attr_version); 6818c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci io->iocb->ki_complete(io->iocb, res, 0); 6858c2ecf20Sopenharmony_ci } 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci kref_put(&io->refcnt, fuse_io_release); 6888c2ecf20Sopenharmony_ci} 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_cistatic struct fuse_io_args *fuse_io_alloc(struct fuse_io_priv *io, 6918c2ecf20Sopenharmony_ci unsigned int npages) 6928c2ecf20Sopenharmony_ci{ 6938c2ecf20Sopenharmony_ci struct fuse_io_args *ia; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci ia = kzalloc(sizeof(*ia), GFP_KERNEL); 6968c2ecf20Sopenharmony_ci if (ia) { 6978c2ecf20Sopenharmony_ci ia->io = io; 6988c2ecf20Sopenharmony_ci ia->ap.pages = fuse_pages_alloc(npages, GFP_KERNEL, 6998c2ecf20Sopenharmony_ci &ia->ap.descs); 7008c2ecf20Sopenharmony_ci if (!ia->ap.pages) { 7018c2ecf20Sopenharmony_ci kfree(ia); 7028c2ecf20Sopenharmony_ci ia = NULL; 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci } 7058c2ecf20Sopenharmony_ci return ia; 7068c2ecf20Sopenharmony_ci} 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_cistatic void fuse_io_free(struct fuse_io_args *ia) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci kfree(ia->ap.pages); 7118c2ecf20Sopenharmony_ci kfree(ia); 7128c2ecf20Sopenharmony_ci} 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_cistatic void fuse_aio_complete_req(struct fuse_mount *fm, struct fuse_args *args, 7158c2ecf20Sopenharmony_ci int err) 7168c2ecf20Sopenharmony_ci{ 7178c2ecf20Sopenharmony_ci struct fuse_io_args *ia = container_of(args, typeof(*ia), ap.args); 7188c2ecf20Sopenharmony_ci struct fuse_io_priv *io = ia->io; 7198c2ecf20Sopenharmony_ci ssize_t pos = -1; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci fuse_release_user_pages(&ia->ap, io->should_dirty); 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci if (err) { 7248c2ecf20Sopenharmony_ci /* Nothing */ 7258c2ecf20Sopenharmony_ci } else if (io->write) { 7268c2ecf20Sopenharmony_ci if (ia->write.out.size > ia->write.in.size) { 7278c2ecf20Sopenharmony_ci err = -EIO; 7288c2ecf20Sopenharmony_ci } else if (ia->write.in.size != ia->write.out.size) { 7298c2ecf20Sopenharmony_ci pos = ia->write.in.offset - io->offset + 7308c2ecf20Sopenharmony_ci ia->write.out.size; 7318c2ecf20Sopenharmony_ci } 7328c2ecf20Sopenharmony_ci } else { 7338c2ecf20Sopenharmony_ci u32 outsize = args->out_args[0].size; 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci if (ia->read.in.size != outsize) 7368c2ecf20Sopenharmony_ci pos = ia->read.in.offset - io->offset + outsize; 7378c2ecf20Sopenharmony_ci } 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci fuse_aio_complete(io, err, pos); 7408c2ecf20Sopenharmony_ci fuse_io_free(ia); 7418c2ecf20Sopenharmony_ci} 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_cistatic ssize_t fuse_async_req_send(struct fuse_mount *fm, 7448c2ecf20Sopenharmony_ci struct fuse_io_args *ia, size_t num_bytes) 7458c2ecf20Sopenharmony_ci{ 7468c2ecf20Sopenharmony_ci ssize_t err; 7478c2ecf20Sopenharmony_ci struct fuse_io_priv *io = ia->io; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci spin_lock(&io->lock); 7508c2ecf20Sopenharmony_ci kref_get(&io->refcnt); 7518c2ecf20Sopenharmony_ci io->size += num_bytes; 7528c2ecf20Sopenharmony_ci io->reqs++; 7538c2ecf20Sopenharmony_ci spin_unlock(&io->lock); 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci ia->ap.args.end = fuse_aio_complete_req; 7568c2ecf20Sopenharmony_ci ia->ap.args.may_block = io->should_dirty; 7578c2ecf20Sopenharmony_ci err = fuse_simple_background(fm, &ia->ap.args, GFP_KERNEL); 7588c2ecf20Sopenharmony_ci if (err) 7598c2ecf20Sopenharmony_ci fuse_aio_complete_req(fm, &ia->ap.args, err); 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci return num_bytes; 7628c2ecf20Sopenharmony_ci} 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_cistatic ssize_t fuse_send_read(struct fuse_io_args *ia, loff_t pos, size_t count, 7658c2ecf20Sopenharmony_ci fl_owner_t owner) 7668c2ecf20Sopenharmony_ci{ 7678c2ecf20Sopenharmony_ci struct file *file = ia->io->iocb->ki_filp; 7688c2ecf20Sopenharmony_ci struct fuse_file *ff = file->private_data; 7698c2ecf20Sopenharmony_ci struct fuse_mount *fm = ff->fm; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci fuse_read_args_fill(ia, file, pos, count, FUSE_READ); 7728c2ecf20Sopenharmony_ci if (owner != NULL) { 7738c2ecf20Sopenharmony_ci ia->read.in.read_flags |= FUSE_READ_LOCKOWNER; 7748c2ecf20Sopenharmony_ci ia->read.in.lock_owner = fuse_lock_owner_id(fm->fc, owner); 7758c2ecf20Sopenharmony_ci } 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci if (ia->io->async) 7788c2ecf20Sopenharmony_ci return fuse_async_req_send(fm, ia, count); 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci return fuse_simple_request(fm, &ia->ap.args); 7818c2ecf20Sopenharmony_ci} 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_cistatic void fuse_read_update_size(struct inode *inode, loff_t size, 7848c2ecf20Sopenharmony_ci u64 attr_ver) 7858c2ecf20Sopenharmony_ci{ 7868c2ecf20Sopenharmony_ci struct fuse_conn *fc = get_fuse_conn(inode); 7878c2ecf20Sopenharmony_ci struct fuse_inode *fi = get_fuse_inode(inode); 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci spin_lock(&fi->lock); 7908c2ecf20Sopenharmony_ci if (attr_ver >= fi->attr_version && size < inode->i_size && 7918c2ecf20Sopenharmony_ci !test_bit(FUSE_I_SIZE_UNSTABLE, &fi->state)) { 7928c2ecf20Sopenharmony_ci fi->attr_version = atomic64_inc_return(&fc->attr_version); 7938c2ecf20Sopenharmony_ci i_size_write(inode, size); 7948c2ecf20Sopenharmony_ci } 7958c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 7968c2ecf20Sopenharmony_ci} 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_cistatic void fuse_short_read(struct inode *inode, u64 attr_ver, size_t num_read, 7998c2ecf20Sopenharmony_ci struct fuse_args_pages *ap) 8008c2ecf20Sopenharmony_ci{ 8018c2ecf20Sopenharmony_ci struct fuse_conn *fc = get_fuse_conn(inode); 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci if (fc->writeback_cache) { 8048c2ecf20Sopenharmony_ci /* 8058c2ecf20Sopenharmony_ci * A hole in a file. Some data after the hole are in page cache, 8068c2ecf20Sopenharmony_ci * but have not reached the client fs yet. So, the hole is not 8078c2ecf20Sopenharmony_ci * present there. 8088c2ecf20Sopenharmony_ci */ 8098c2ecf20Sopenharmony_ci int i; 8108c2ecf20Sopenharmony_ci int start_idx = num_read >> PAGE_SHIFT; 8118c2ecf20Sopenharmony_ci size_t off = num_read & (PAGE_SIZE - 1); 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci for (i = start_idx; i < ap->num_pages; i++) { 8148c2ecf20Sopenharmony_ci zero_user_segment(ap->pages[i], off, PAGE_SIZE); 8158c2ecf20Sopenharmony_ci off = 0; 8168c2ecf20Sopenharmony_ci } 8178c2ecf20Sopenharmony_ci } else { 8188c2ecf20Sopenharmony_ci loff_t pos = page_offset(ap->pages[0]) + num_read; 8198c2ecf20Sopenharmony_ci fuse_read_update_size(inode, pos, attr_ver); 8208c2ecf20Sopenharmony_ci } 8218c2ecf20Sopenharmony_ci} 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_cistatic int fuse_do_readpage(struct file *file, struct page *page) 8248c2ecf20Sopenharmony_ci{ 8258c2ecf20Sopenharmony_ci struct inode *inode = page->mapping->host; 8268c2ecf20Sopenharmony_ci struct fuse_mount *fm = get_fuse_mount(inode); 8278c2ecf20Sopenharmony_ci loff_t pos = page_offset(page); 8288c2ecf20Sopenharmony_ci struct fuse_page_desc desc = { .length = PAGE_SIZE }; 8298c2ecf20Sopenharmony_ci struct fuse_io_args ia = { 8308c2ecf20Sopenharmony_ci .ap.args.page_zeroing = true, 8318c2ecf20Sopenharmony_ci .ap.args.out_pages = true, 8328c2ecf20Sopenharmony_ci .ap.num_pages = 1, 8338c2ecf20Sopenharmony_ci .ap.pages = &page, 8348c2ecf20Sopenharmony_ci .ap.descs = &desc, 8358c2ecf20Sopenharmony_ci }; 8368c2ecf20Sopenharmony_ci ssize_t res; 8378c2ecf20Sopenharmony_ci u64 attr_ver; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci /* 8408c2ecf20Sopenharmony_ci * Page writeback can extend beyond the lifetime of the 8418c2ecf20Sopenharmony_ci * page-cache page, so make sure we read a properly synced 8428c2ecf20Sopenharmony_ci * page. 8438c2ecf20Sopenharmony_ci */ 8448c2ecf20Sopenharmony_ci fuse_wait_on_page_writeback(inode, page->index); 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci attr_ver = fuse_get_attr_version(fm->fc); 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci /* Don't overflow end offset */ 8498c2ecf20Sopenharmony_ci if (pos + (desc.length - 1) == LLONG_MAX) 8508c2ecf20Sopenharmony_ci desc.length--; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci fuse_read_args_fill(&ia, file, pos, desc.length, FUSE_READ); 8538c2ecf20Sopenharmony_ci res = fuse_simple_request(fm, &ia.ap.args); 8548c2ecf20Sopenharmony_ci if (res < 0) 8558c2ecf20Sopenharmony_ci return res; 8568c2ecf20Sopenharmony_ci /* 8578c2ecf20Sopenharmony_ci * Short read means EOF. If file size is larger, truncate it 8588c2ecf20Sopenharmony_ci */ 8598c2ecf20Sopenharmony_ci if (res < desc.length) 8608c2ecf20Sopenharmony_ci fuse_short_read(inode, attr_ver, res, &ia.ap); 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci SetPageUptodate(page); 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci return 0; 8658c2ecf20Sopenharmony_ci} 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_cistatic int fuse_readpage(struct file *file, struct page *page) 8688c2ecf20Sopenharmony_ci{ 8698c2ecf20Sopenharmony_ci struct inode *inode = page->mapping->host; 8708c2ecf20Sopenharmony_ci int err; 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci err = -EIO; 8738c2ecf20Sopenharmony_ci if (fuse_is_bad(inode)) 8748c2ecf20Sopenharmony_ci goto out; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci err = fuse_do_readpage(file, page); 8778c2ecf20Sopenharmony_ci fuse_invalidate_atime(inode); 8788c2ecf20Sopenharmony_ci out: 8798c2ecf20Sopenharmony_ci unlock_page(page); 8808c2ecf20Sopenharmony_ci return err; 8818c2ecf20Sopenharmony_ci} 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_cistatic void fuse_readpages_end(struct fuse_mount *fm, struct fuse_args *args, 8848c2ecf20Sopenharmony_ci int err) 8858c2ecf20Sopenharmony_ci{ 8868c2ecf20Sopenharmony_ci int i; 8878c2ecf20Sopenharmony_ci struct fuse_io_args *ia = container_of(args, typeof(*ia), ap.args); 8888c2ecf20Sopenharmony_ci struct fuse_args_pages *ap = &ia->ap; 8898c2ecf20Sopenharmony_ci size_t count = ia->read.in.size; 8908c2ecf20Sopenharmony_ci size_t num_read = args->out_args[0].size; 8918c2ecf20Sopenharmony_ci struct address_space *mapping = NULL; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci for (i = 0; mapping == NULL && i < ap->num_pages; i++) 8948c2ecf20Sopenharmony_ci mapping = ap->pages[i]->mapping; 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci if (mapping) { 8978c2ecf20Sopenharmony_ci struct inode *inode = mapping->host; 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci /* 9008c2ecf20Sopenharmony_ci * Short read means EOF. If file size is larger, truncate it 9018c2ecf20Sopenharmony_ci */ 9028c2ecf20Sopenharmony_ci if (!err && num_read < count) 9038c2ecf20Sopenharmony_ci fuse_short_read(inode, ia->read.attr_ver, num_read, ap); 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci fuse_invalidate_atime(inode); 9068c2ecf20Sopenharmony_ci } 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci for (i = 0; i < ap->num_pages; i++) { 9098c2ecf20Sopenharmony_ci struct page *page = ap->pages[i]; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci if (!err) 9128c2ecf20Sopenharmony_ci SetPageUptodate(page); 9138c2ecf20Sopenharmony_ci else 9148c2ecf20Sopenharmony_ci SetPageError(page); 9158c2ecf20Sopenharmony_ci unlock_page(page); 9168c2ecf20Sopenharmony_ci put_page(page); 9178c2ecf20Sopenharmony_ci } 9188c2ecf20Sopenharmony_ci if (ia->ff) 9198c2ecf20Sopenharmony_ci fuse_file_put(ia->ff, false, false); 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci fuse_io_free(ia); 9228c2ecf20Sopenharmony_ci} 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_cistatic void fuse_send_readpages(struct fuse_io_args *ia, struct file *file) 9258c2ecf20Sopenharmony_ci{ 9268c2ecf20Sopenharmony_ci struct fuse_file *ff = file->private_data; 9278c2ecf20Sopenharmony_ci struct fuse_mount *fm = ff->fm; 9288c2ecf20Sopenharmony_ci struct fuse_args_pages *ap = &ia->ap; 9298c2ecf20Sopenharmony_ci loff_t pos = page_offset(ap->pages[0]); 9308c2ecf20Sopenharmony_ci size_t count = ap->num_pages << PAGE_SHIFT; 9318c2ecf20Sopenharmony_ci ssize_t res; 9328c2ecf20Sopenharmony_ci int err; 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci ap->args.out_pages = true; 9358c2ecf20Sopenharmony_ci ap->args.page_zeroing = true; 9368c2ecf20Sopenharmony_ci ap->args.page_replace = true; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci /* Don't overflow end offset */ 9398c2ecf20Sopenharmony_ci if (pos + (count - 1) == LLONG_MAX) { 9408c2ecf20Sopenharmony_ci count--; 9418c2ecf20Sopenharmony_ci ap->descs[ap->num_pages - 1].length--; 9428c2ecf20Sopenharmony_ci } 9438c2ecf20Sopenharmony_ci WARN_ON((loff_t) (pos + count) < 0); 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci fuse_read_args_fill(ia, file, pos, count, FUSE_READ); 9468c2ecf20Sopenharmony_ci ia->read.attr_ver = fuse_get_attr_version(fm->fc); 9478c2ecf20Sopenharmony_ci if (fm->fc->async_read) { 9488c2ecf20Sopenharmony_ci ia->ff = fuse_file_get(ff); 9498c2ecf20Sopenharmony_ci ap->args.end = fuse_readpages_end; 9508c2ecf20Sopenharmony_ci err = fuse_simple_background(fm, &ap->args, GFP_KERNEL); 9518c2ecf20Sopenharmony_ci if (!err) 9528c2ecf20Sopenharmony_ci return; 9538c2ecf20Sopenharmony_ci } else { 9548c2ecf20Sopenharmony_ci res = fuse_simple_request(fm, &ap->args); 9558c2ecf20Sopenharmony_ci err = res < 0 ? res : 0; 9568c2ecf20Sopenharmony_ci } 9578c2ecf20Sopenharmony_ci fuse_readpages_end(fm, &ap->args, err); 9588c2ecf20Sopenharmony_ci} 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_cistatic void fuse_readahead(struct readahead_control *rac) 9618c2ecf20Sopenharmony_ci{ 9628c2ecf20Sopenharmony_ci struct inode *inode = rac->mapping->host; 9638c2ecf20Sopenharmony_ci struct fuse_conn *fc = get_fuse_conn(inode); 9648c2ecf20Sopenharmony_ci unsigned int i, max_pages, nr_pages = 0; 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci if (fuse_is_bad(inode)) 9678c2ecf20Sopenharmony_ci return; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci max_pages = min_t(unsigned int, fc->max_pages, 9708c2ecf20Sopenharmony_ci fc->max_read / PAGE_SIZE); 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci for (;;) { 9738c2ecf20Sopenharmony_ci struct fuse_io_args *ia; 9748c2ecf20Sopenharmony_ci struct fuse_args_pages *ap; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci nr_pages = readahead_count(rac) - nr_pages; 9778c2ecf20Sopenharmony_ci if (nr_pages > max_pages) 9788c2ecf20Sopenharmony_ci nr_pages = max_pages; 9798c2ecf20Sopenharmony_ci if (nr_pages == 0) 9808c2ecf20Sopenharmony_ci break; 9818c2ecf20Sopenharmony_ci ia = fuse_io_alloc(NULL, nr_pages); 9828c2ecf20Sopenharmony_ci if (!ia) 9838c2ecf20Sopenharmony_ci return; 9848c2ecf20Sopenharmony_ci ap = &ia->ap; 9858c2ecf20Sopenharmony_ci nr_pages = __readahead_batch(rac, ap->pages, nr_pages); 9868c2ecf20Sopenharmony_ci for (i = 0; i < nr_pages; i++) { 9878c2ecf20Sopenharmony_ci fuse_wait_on_page_writeback(inode, 9888c2ecf20Sopenharmony_ci readahead_index(rac) + i); 9898c2ecf20Sopenharmony_ci ap->descs[i].length = PAGE_SIZE; 9908c2ecf20Sopenharmony_ci } 9918c2ecf20Sopenharmony_ci ap->num_pages = nr_pages; 9928c2ecf20Sopenharmony_ci fuse_send_readpages(ia, rac->file); 9938c2ecf20Sopenharmony_ci } 9948c2ecf20Sopenharmony_ci} 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_cistatic ssize_t fuse_cache_read_iter(struct kiocb *iocb, struct iov_iter *to) 9978c2ecf20Sopenharmony_ci{ 9988c2ecf20Sopenharmony_ci struct inode *inode = iocb->ki_filp->f_mapping->host; 9998c2ecf20Sopenharmony_ci struct fuse_conn *fc = get_fuse_conn(inode); 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci /* 10028c2ecf20Sopenharmony_ci * In auto invalidate mode, always update attributes on read. 10038c2ecf20Sopenharmony_ci * Otherwise, only update if we attempt to read past EOF (to ensure 10048c2ecf20Sopenharmony_ci * i_size is up to date). 10058c2ecf20Sopenharmony_ci */ 10068c2ecf20Sopenharmony_ci if (fc->auto_inval_data || 10078c2ecf20Sopenharmony_ci (iocb->ki_pos + iov_iter_count(to) > i_size_read(inode))) { 10088c2ecf20Sopenharmony_ci int err; 10098c2ecf20Sopenharmony_ci err = fuse_update_attributes(inode, iocb->ki_filp); 10108c2ecf20Sopenharmony_ci if (err) 10118c2ecf20Sopenharmony_ci return err; 10128c2ecf20Sopenharmony_ci } 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci return generic_file_read_iter(iocb, to); 10158c2ecf20Sopenharmony_ci} 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_cistatic void fuse_write_args_fill(struct fuse_io_args *ia, struct fuse_file *ff, 10188c2ecf20Sopenharmony_ci loff_t pos, size_t count) 10198c2ecf20Sopenharmony_ci{ 10208c2ecf20Sopenharmony_ci struct fuse_args *args = &ia->ap.args; 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci ia->write.in.fh = ff->fh; 10238c2ecf20Sopenharmony_ci ia->write.in.offset = pos; 10248c2ecf20Sopenharmony_ci ia->write.in.size = count; 10258c2ecf20Sopenharmony_ci args->opcode = FUSE_WRITE; 10268c2ecf20Sopenharmony_ci args->nodeid = ff->nodeid; 10278c2ecf20Sopenharmony_ci args->in_numargs = 2; 10288c2ecf20Sopenharmony_ci if (ff->fm->fc->minor < 9) 10298c2ecf20Sopenharmony_ci args->in_args[0].size = FUSE_COMPAT_WRITE_IN_SIZE; 10308c2ecf20Sopenharmony_ci else 10318c2ecf20Sopenharmony_ci args->in_args[0].size = sizeof(ia->write.in); 10328c2ecf20Sopenharmony_ci args->in_args[0].value = &ia->write.in; 10338c2ecf20Sopenharmony_ci args->in_args[1].size = count; 10348c2ecf20Sopenharmony_ci args->out_numargs = 1; 10358c2ecf20Sopenharmony_ci args->out_args[0].size = sizeof(ia->write.out); 10368c2ecf20Sopenharmony_ci args->out_args[0].value = &ia->write.out; 10378c2ecf20Sopenharmony_ci} 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_cistatic unsigned int fuse_write_flags(struct kiocb *iocb) 10408c2ecf20Sopenharmony_ci{ 10418c2ecf20Sopenharmony_ci unsigned int flags = iocb->ki_filp->f_flags; 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci if (iocb->ki_flags & IOCB_DSYNC) 10448c2ecf20Sopenharmony_ci flags |= O_DSYNC; 10458c2ecf20Sopenharmony_ci if (iocb->ki_flags & IOCB_SYNC) 10468c2ecf20Sopenharmony_ci flags |= O_SYNC; 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci return flags; 10498c2ecf20Sopenharmony_ci} 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_cistatic ssize_t fuse_send_write(struct fuse_io_args *ia, loff_t pos, 10528c2ecf20Sopenharmony_ci size_t count, fl_owner_t owner) 10538c2ecf20Sopenharmony_ci{ 10548c2ecf20Sopenharmony_ci struct kiocb *iocb = ia->io->iocb; 10558c2ecf20Sopenharmony_ci struct file *file = iocb->ki_filp; 10568c2ecf20Sopenharmony_ci struct fuse_file *ff = file->private_data; 10578c2ecf20Sopenharmony_ci struct fuse_mount *fm = ff->fm; 10588c2ecf20Sopenharmony_ci struct fuse_write_in *inarg = &ia->write.in; 10598c2ecf20Sopenharmony_ci ssize_t err; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci fuse_write_args_fill(ia, ff, pos, count); 10628c2ecf20Sopenharmony_ci inarg->flags = fuse_write_flags(iocb); 10638c2ecf20Sopenharmony_ci if (owner != NULL) { 10648c2ecf20Sopenharmony_ci inarg->write_flags |= FUSE_WRITE_LOCKOWNER; 10658c2ecf20Sopenharmony_ci inarg->lock_owner = fuse_lock_owner_id(fm->fc, owner); 10668c2ecf20Sopenharmony_ci } 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci if (ia->io->async) 10698c2ecf20Sopenharmony_ci return fuse_async_req_send(fm, ia, count); 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci err = fuse_simple_request(fm, &ia->ap.args); 10728c2ecf20Sopenharmony_ci if (!err && ia->write.out.size > count) 10738c2ecf20Sopenharmony_ci err = -EIO; 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci return err ?: ia->write.out.size; 10768c2ecf20Sopenharmony_ci} 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_cibool fuse_write_update_size(struct inode *inode, loff_t pos) 10798c2ecf20Sopenharmony_ci{ 10808c2ecf20Sopenharmony_ci struct fuse_conn *fc = get_fuse_conn(inode); 10818c2ecf20Sopenharmony_ci struct fuse_inode *fi = get_fuse_inode(inode); 10828c2ecf20Sopenharmony_ci bool ret = false; 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci spin_lock(&fi->lock); 10858c2ecf20Sopenharmony_ci fi->attr_version = atomic64_inc_return(&fc->attr_version); 10868c2ecf20Sopenharmony_ci if (pos > inode->i_size) { 10878c2ecf20Sopenharmony_ci i_size_write(inode, pos); 10888c2ecf20Sopenharmony_ci ret = true; 10898c2ecf20Sopenharmony_ci } 10908c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci return ret; 10938c2ecf20Sopenharmony_ci} 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_cistatic ssize_t fuse_send_write_pages(struct fuse_io_args *ia, 10968c2ecf20Sopenharmony_ci struct kiocb *iocb, struct inode *inode, 10978c2ecf20Sopenharmony_ci loff_t pos, size_t count) 10988c2ecf20Sopenharmony_ci{ 10998c2ecf20Sopenharmony_ci struct fuse_args_pages *ap = &ia->ap; 11008c2ecf20Sopenharmony_ci struct file *file = iocb->ki_filp; 11018c2ecf20Sopenharmony_ci struct fuse_file *ff = file->private_data; 11028c2ecf20Sopenharmony_ci struct fuse_mount *fm = ff->fm; 11038c2ecf20Sopenharmony_ci unsigned int offset, i; 11048c2ecf20Sopenharmony_ci bool short_write; 11058c2ecf20Sopenharmony_ci int err; 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci for (i = 0; i < ap->num_pages; i++) 11088c2ecf20Sopenharmony_ci fuse_wait_on_page_writeback(inode, ap->pages[i]->index); 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci fuse_write_args_fill(ia, ff, pos, count); 11118c2ecf20Sopenharmony_ci ia->write.in.flags = fuse_write_flags(iocb); 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci err = fuse_simple_request(fm, &ap->args); 11148c2ecf20Sopenharmony_ci if (!err && ia->write.out.size > count) 11158c2ecf20Sopenharmony_ci err = -EIO; 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci short_write = ia->write.out.size < count; 11188c2ecf20Sopenharmony_ci offset = ap->descs[0].offset; 11198c2ecf20Sopenharmony_ci count = ia->write.out.size; 11208c2ecf20Sopenharmony_ci for (i = 0; i < ap->num_pages; i++) { 11218c2ecf20Sopenharmony_ci struct page *page = ap->pages[i]; 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci if (err) { 11248c2ecf20Sopenharmony_ci ClearPageUptodate(page); 11258c2ecf20Sopenharmony_ci } else { 11268c2ecf20Sopenharmony_ci if (count >= PAGE_SIZE - offset) 11278c2ecf20Sopenharmony_ci count -= PAGE_SIZE - offset; 11288c2ecf20Sopenharmony_ci else { 11298c2ecf20Sopenharmony_ci if (short_write) 11308c2ecf20Sopenharmony_ci ClearPageUptodate(page); 11318c2ecf20Sopenharmony_ci count = 0; 11328c2ecf20Sopenharmony_ci } 11338c2ecf20Sopenharmony_ci offset = 0; 11348c2ecf20Sopenharmony_ci } 11358c2ecf20Sopenharmony_ci if (ia->write.page_locked && (i == ap->num_pages - 1)) 11368c2ecf20Sopenharmony_ci unlock_page(page); 11378c2ecf20Sopenharmony_ci put_page(page); 11388c2ecf20Sopenharmony_ci } 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci return err; 11418c2ecf20Sopenharmony_ci} 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_cistatic ssize_t fuse_fill_write_pages(struct fuse_io_args *ia, 11448c2ecf20Sopenharmony_ci struct address_space *mapping, 11458c2ecf20Sopenharmony_ci struct iov_iter *ii, loff_t pos, 11468c2ecf20Sopenharmony_ci unsigned int max_pages) 11478c2ecf20Sopenharmony_ci{ 11488c2ecf20Sopenharmony_ci struct fuse_args_pages *ap = &ia->ap; 11498c2ecf20Sopenharmony_ci struct fuse_conn *fc = get_fuse_conn(mapping->host); 11508c2ecf20Sopenharmony_ci unsigned offset = pos & (PAGE_SIZE - 1); 11518c2ecf20Sopenharmony_ci size_t count = 0; 11528c2ecf20Sopenharmony_ci int err; 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci ap->args.in_pages = true; 11558c2ecf20Sopenharmony_ci ap->descs[0].offset = offset; 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci do { 11588c2ecf20Sopenharmony_ci size_t tmp; 11598c2ecf20Sopenharmony_ci struct page *page; 11608c2ecf20Sopenharmony_ci pgoff_t index = pos >> PAGE_SHIFT; 11618c2ecf20Sopenharmony_ci size_t bytes = min_t(size_t, PAGE_SIZE - offset, 11628c2ecf20Sopenharmony_ci iov_iter_count(ii)); 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci bytes = min_t(size_t, bytes, fc->max_write - count); 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci again: 11678c2ecf20Sopenharmony_ci err = -EFAULT; 11688c2ecf20Sopenharmony_ci if (iov_iter_fault_in_readable(ii, bytes)) 11698c2ecf20Sopenharmony_ci break; 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci err = -ENOMEM; 11728c2ecf20Sopenharmony_ci page = grab_cache_page_write_begin(mapping, index, 0); 11738c2ecf20Sopenharmony_ci if (!page) 11748c2ecf20Sopenharmony_ci break; 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci if (mapping_writably_mapped(mapping)) 11778c2ecf20Sopenharmony_ci flush_dcache_page(page); 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci tmp = iov_iter_copy_from_user_atomic(page, ii, offset, bytes); 11808c2ecf20Sopenharmony_ci flush_dcache_page(page); 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci iov_iter_advance(ii, tmp); 11838c2ecf20Sopenharmony_ci if (!tmp) { 11848c2ecf20Sopenharmony_ci unlock_page(page); 11858c2ecf20Sopenharmony_ci put_page(page); 11868c2ecf20Sopenharmony_ci bytes = min(bytes, iov_iter_single_seg_count(ii)); 11878c2ecf20Sopenharmony_ci goto again; 11888c2ecf20Sopenharmony_ci } 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci err = 0; 11918c2ecf20Sopenharmony_ci ap->pages[ap->num_pages] = page; 11928c2ecf20Sopenharmony_ci ap->descs[ap->num_pages].length = tmp; 11938c2ecf20Sopenharmony_ci ap->num_pages++; 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci count += tmp; 11968c2ecf20Sopenharmony_ci pos += tmp; 11978c2ecf20Sopenharmony_ci offset += tmp; 11988c2ecf20Sopenharmony_ci if (offset == PAGE_SIZE) 11998c2ecf20Sopenharmony_ci offset = 0; 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci /* If we copied full page, mark it uptodate */ 12028c2ecf20Sopenharmony_ci if (tmp == PAGE_SIZE) 12038c2ecf20Sopenharmony_ci SetPageUptodate(page); 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci if (PageUptodate(page)) { 12068c2ecf20Sopenharmony_ci unlock_page(page); 12078c2ecf20Sopenharmony_ci } else { 12088c2ecf20Sopenharmony_ci ia->write.page_locked = true; 12098c2ecf20Sopenharmony_ci break; 12108c2ecf20Sopenharmony_ci } 12118c2ecf20Sopenharmony_ci if (!fc->big_writes) 12128c2ecf20Sopenharmony_ci break; 12138c2ecf20Sopenharmony_ci } while (iov_iter_count(ii) && count < fc->max_write && 12148c2ecf20Sopenharmony_ci ap->num_pages < max_pages && offset == 0); 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci return count > 0 ? count : err; 12178c2ecf20Sopenharmony_ci} 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_cistatic inline unsigned int fuse_wr_pages(loff_t pos, size_t len, 12208c2ecf20Sopenharmony_ci unsigned int max_pages) 12218c2ecf20Sopenharmony_ci{ 12228c2ecf20Sopenharmony_ci return min_t(unsigned int, 12238c2ecf20Sopenharmony_ci ((pos + len - 1) >> PAGE_SHIFT) - 12248c2ecf20Sopenharmony_ci (pos >> PAGE_SHIFT) + 1, 12258c2ecf20Sopenharmony_ci max_pages); 12268c2ecf20Sopenharmony_ci} 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_cistatic ssize_t fuse_perform_write(struct kiocb *iocb, 12298c2ecf20Sopenharmony_ci struct address_space *mapping, 12308c2ecf20Sopenharmony_ci struct iov_iter *ii, loff_t pos) 12318c2ecf20Sopenharmony_ci{ 12328c2ecf20Sopenharmony_ci struct inode *inode = mapping->host; 12338c2ecf20Sopenharmony_ci struct fuse_conn *fc = get_fuse_conn(inode); 12348c2ecf20Sopenharmony_ci struct fuse_inode *fi = get_fuse_inode(inode); 12358c2ecf20Sopenharmony_ci int err = 0; 12368c2ecf20Sopenharmony_ci ssize_t res = 0; 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci if (inode->i_size < pos + iov_iter_count(ii)) 12398c2ecf20Sopenharmony_ci set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state); 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci do { 12428c2ecf20Sopenharmony_ci ssize_t count; 12438c2ecf20Sopenharmony_ci struct fuse_io_args ia = {}; 12448c2ecf20Sopenharmony_ci struct fuse_args_pages *ap = &ia.ap; 12458c2ecf20Sopenharmony_ci unsigned int nr_pages = fuse_wr_pages(pos, iov_iter_count(ii), 12468c2ecf20Sopenharmony_ci fc->max_pages); 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci ap->pages = fuse_pages_alloc(nr_pages, GFP_KERNEL, &ap->descs); 12498c2ecf20Sopenharmony_ci if (!ap->pages) { 12508c2ecf20Sopenharmony_ci err = -ENOMEM; 12518c2ecf20Sopenharmony_ci break; 12528c2ecf20Sopenharmony_ci } 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci count = fuse_fill_write_pages(&ia, mapping, ii, pos, nr_pages); 12558c2ecf20Sopenharmony_ci if (count <= 0) { 12568c2ecf20Sopenharmony_ci err = count; 12578c2ecf20Sopenharmony_ci } else { 12588c2ecf20Sopenharmony_ci err = fuse_send_write_pages(&ia, iocb, inode, 12598c2ecf20Sopenharmony_ci pos, count); 12608c2ecf20Sopenharmony_ci if (!err) { 12618c2ecf20Sopenharmony_ci size_t num_written = ia.write.out.size; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci res += num_written; 12648c2ecf20Sopenharmony_ci pos += num_written; 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci /* break out of the loop on short write */ 12678c2ecf20Sopenharmony_ci if (num_written != count) 12688c2ecf20Sopenharmony_ci err = -EIO; 12698c2ecf20Sopenharmony_ci } 12708c2ecf20Sopenharmony_ci } 12718c2ecf20Sopenharmony_ci kfree(ap->pages); 12728c2ecf20Sopenharmony_ci } while (!err && iov_iter_count(ii)); 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci if (res > 0) 12758c2ecf20Sopenharmony_ci fuse_write_update_size(inode, pos); 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state); 12788c2ecf20Sopenharmony_ci fuse_invalidate_attr(inode); 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci return res > 0 ? res : err; 12818c2ecf20Sopenharmony_ci} 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_cistatic ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from) 12848c2ecf20Sopenharmony_ci{ 12858c2ecf20Sopenharmony_ci struct file *file = iocb->ki_filp; 12868c2ecf20Sopenharmony_ci struct address_space *mapping = file->f_mapping; 12878c2ecf20Sopenharmony_ci ssize_t written = 0; 12888c2ecf20Sopenharmony_ci ssize_t written_buffered = 0; 12898c2ecf20Sopenharmony_ci struct inode *inode = mapping->host; 12908c2ecf20Sopenharmony_ci ssize_t err; 12918c2ecf20Sopenharmony_ci loff_t endbyte = 0; 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci if (get_fuse_conn(inode)->writeback_cache) { 12948c2ecf20Sopenharmony_ci /* Update size (EOF optimization) and mode (SUID clearing) */ 12958c2ecf20Sopenharmony_ci err = fuse_update_attributes(mapping->host, file); 12968c2ecf20Sopenharmony_ci if (err) 12978c2ecf20Sopenharmony_ci return err; 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci return generic_file_write_iter(iocb, from); 13008c2ecf20Sopenharmony_ci } 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci inode_lock(inode); 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci /* We can write back this queue in page reclaim */ 13058c2ecf20Sopenharmony_ci current->backing_dev_info = inode_to_bdi(inode); 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci err = generic_write_checks(iocb, from); 13088c2ecf20Sopenharmony_ci if (err <= 0) 13098c2ecf20Sopenharmony_ci goto out; 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci err = file_remove_privs(file); 13128c2ecf20Sopenharmony_ci if (err) 13138c2ecf20Sopenharmony_ci goto out; 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci err = file_update_time(file); 13168c2ecf20Sopenharmony_ci if (err) 13178c2ecf20Sopenharmony_ci goto out; 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci if (iocb->ki_flags & IOCB_DIRECT) { 13208c2ecf20Sopenharmony_ci loff_t pos = iocb->ki_pos; 13218c2ecf20Sopenharmony_ci written = generic_file_direct_write(iocb, from); 13228c2ecf20Sopenharmony_ci if (written < 0 || !iov_iter_count(from)) 13238c2ecf20Sopenharmony_ci goto out; 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci pos += written; 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci written_buffered = fuse_perform_write(iocb, mapping, from, pos); 13288c2ecf20Sopenharmony_ci if (written_buffered < 0) { 13298c2ecf20Sopenharmony_ci err = written_buffered; 13308c2ecf20Sopenharmony_ci goto out; 13318c2ecf20Sopenharmony_ci } 13328c2ecf20Sopenharmony_ci endbyte = pos + written_buffered - 1; 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci err = filemap_write_and_wait_range(file->f_mapping, pos, 13358c2ecf20Sopenharmony_ci endbyte); 13368c2ecf20Sopenharmony_ci if (err) 13378c2ecf20Sopenharmony_ci goto out; 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci invalidate_mapping_pages(file->f_mapping, 13408c2ecf20Sopenharmony_ci pos >> PAGE_SHIFT, 13418c2ecf20Sopenharmony_ci endbyte >> PAGE_SHIFT); 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci written += written_buffered; 13448c2ecf20Sopenharmony_ci iocb->ki_pos = pos + written_buffered; 13458c2ecf20Sopenharmony_ci } else { 13468c2ecf20Sopenharmony_ci written = fuse_perform_write(iocb, mapping, from, iocb->ki_pos); 13478c2ecf20Sopenharmony_ci if (written >= 0) 13488c2ecf20Sopenharmony_ci iocb->ki_pos += written; 13498c2ecf20Sopenharmony_ci } 13508c2ecf20Sopenharmony_ciout: 13518c2ecf20Sopenharmony_ci current->backing_dev_info = NULL; 13528c2ecf20Sopenharmony_ci inode_unlock(inode); 13538c2ecf20Sopenharmony_ci if (written > 0) 13548c2ecf20Sopenharmony_ci written = generic_write_sync(iocb, written); 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci return written ? written : err; 13578c2ecf20Sopenharmony_ci} 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_cistatic inline void fuse_page_descs_length_init(struct fuse_page_desc *descs, 13608c2ecf20Sopenharmony_ci unsigned int index, 13618c2ecf20Sopenharmony_ci unsigned int nr_pages) 13628c2ecf20Sopenharmony_ci{ 13638c2ecf20Sopenharmony_ci int i; 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci for (i = index; i < index + nr_pages; i++) 13668c2ecf20Sopenharmony_ci descs[i].length = PAGE_SIZE - descs[i].offset; 13678c2ecf20Sopenharmony_ci} 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_cistatic inline unsigned long fuse_get_user_addr(const struct iov_iter *ii) 13708c2ecf20Sopenharmony_ci{ 13718c2ecf20Sopenharmony_ci return (unsigned long)ii->iov->iov_base + ii->iov_offset; 13728c2ecf20Sopenharmony_ci} 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_cistatic inline size_t fuse_get_frag_size(const struct iov_iter *ii, 13758c2ecf20Sopenharmony_ci size_t max_size) 13768c2ecf20Sopenharmony_ci{ 13778c2ecf20Sopenharmony_ci return min(iov_iter_single_seg_count(ii), max_size); 13788c2ecf20Sopenharmony_ci} 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_cistatic int fuse_get_user_pages(struct fuse_args_pages *ap, struct iov_iter *ii, 13818c2ecf20Sopenharmony_ci size_t *nbytesp, int write, 13828c2ecf20Sopenharmony_ci unsigned int max_pages) 13838c2ecf20Sopenharmony_ci{ 13848c2ecf20Sopenharmony_ci size_t nbytes = 0; /* # bytes already packed in req */ 13858c2ecf20Sopenharmony_ci ssize_t ret = 0; 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci /* Special case for kernel I/O: can copy directly into the buffer */ 13888c2ecf20Sopenharmony_ci if (iov_iter_is_kvec(ii)) { 13898c2ecf20Sopenharmony_ci unsigned long user_addr = fuse_get_user_addr(ii); 13908c2ecf20Sopenharmony_ci size_t frag_size = fuse_get_frag_size(ii, *nbytesp); 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci if (write) 13938c2ecf20Sopenharmony_ci ap->args.in_args[1].value = (void *) user_addr; 13948c2ecf20Sopenharmony_ci else 13958c2ecf20Sopenharmony_ci ap->args.out_args[0].value = (void *) user_addr; 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci iov_iter_advance(ii, frag_size); 13988c2ecf20Sopenharmony_ci *nbytesp = frag_size; 13998c2ecf20Sopenharmony_ci return 0; 14008c2ecf20Sopenharmony_ci } 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci while (nbytes < *nbytesp && ap->num_pages < max_pages) { 14038c2ecf20Sopenharmony_ci unsigned npages; 14048c2ecf20Sopenharmony_ci size_t start; 14058c2ecf20Sopenharmony_ci ret = iov_iter_get_pages(ii, &ap->pages[ap->num_pages], 14068c2ecf20Sopenharmony_ci *nbytesp - nbytes, 14078c2ecf20Sopenharmony_ci max_pages - ap->num_pages, 14088c2ecf20Sopenharmony_ci &start); 14098c2ecf20Sopenharmony_ci if (ret < 0) 14108c2ecf20Sopenharmony_ci break; 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci iov_iter_advance(ii, ret); 14138c2ecf20Sopenharmony_ci nbytes += ret; 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci ret += start; 14168c2ecf20Sopenharmony_ci npages = (ret + PAGE_SIZE - 1) / PAGE_SIZE; 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci ap->descs[ap->num_pages].offset = start; 14198c2ecf20Sopenharmony_ci fuse_page_descs_length_init(ap->descs, ap->num_pages, npages); 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci ap->num_pages += npages; 14228c2ecf20Sopenharmony_ci ap->descs[ap->num_pages - 1].length -= 14238c2ecf20Sopenharmony_ci (PAGE_SIZE - ret) & (PAGE_SIZE - 1); 14248c2ecf20Sopenharmony_ci } 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci ap->args.user_pages = true; 14278c2ecf20Sopenharmony_ci if (write) 14288c2ecf20Sopenharmony_ci ap->args.in_pages = true; 14298c2ecf20Sopenharmony_ci else 14308c2ecf20Sopenharmony_ci ap->args.out_pages = true; 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci *nbytesp = nbytes; 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci return ret < 0 ? ret : 0; 14358c2ecf20Sopenharmony_ci} 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_cissize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter, 14388c2ecf20Sopenharmony_ci loff_t *ppos, int flags) 14398c2ecf20Sopenharmony_ci{ 14408c2ecf20Sopenharmony_ci int write = flags & FUSE_DIO_WRITE; 14418c2ecf20Sopenharmony_ci int cuse = flags & FUSE_DIO_CUSE; 14428c2ecf20Sopenharmony_ci struct file *file = io->iocb->ki_filp; 14438c2ecf20Sopenharmony_ci struct inode *inode = file->f_mapping->host; 14448c2ecf20Sopenharmony_ci struct fuse_file *ff = file->private_data; 14458c2ecf20Sopenharmony_ci struct fuse_conn *fc = ff->fm->fc; 14468c2ecf20Sopenharmony_ci size_t nmax = write ? fc->max_write : fc->max_read; 14478c2ecf20Sopenharmony_ci loff_t pos = *ppos; 14488c2ecf20Sopenharmony_ci size_t count = iov_iter_count(iter); 14498c2ecf20Sopenharmony_ci pgoff_t idx_from = pos >> PAGE_SHIFT; 14508c2ecf20Sopenharmony_ci pgoff_t idx_to = (pos + count - 1) >> PAGE_SHIFT; 14518c2ecf20Sopenharmony_ci ssize_t res = 0; 14528c2ecf20Sopenharmony_ci int err = 0; 14538c2ecf20Sopenharmony_ci struct fuse_io_args *ia; 14548c2ecf20Sopenharmony_ci unsigned int max_pages; 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci max_pages = iov_iter_npages(iter, fc->max_pages); 14578c2ecf20Sopenharmony_ci ia = fuse_io_alloc(io, max_pages); 14588c2ecf20Sopenharmony_ci if (!ia) 14598c2ecf20Sopenharmony_ci return -ENOMEM; 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci ia->io = io; 14628c2ecf20Sopenharmony_ci if (!cuse && fuse_range_is_writeback(inode, idx_from, idx_to)) { 14638c2ecf20Sopenharmony_ci if (!write) 14648c2ecf20Sopenharmony_ci inode_lock(inode); 14658c2ecf20Sopenharmony_ci fuse_sync_writes(inode); 14668c2ecf20Sopenharmony_ci if (!write) 14678c2ecf20Sopenharmony_ci inode_unlock(inode); 14688c2ecf20Sopenharmony_ci } 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci io->should_dirty = !write && iter_is_iovec(iter); 14718c2ecf20Sopenharmony_ci while (count) { 14728c2ecf20Sopenharmony_ci ssize_t nres; 14738c2ecf20Sopenharmony_ci fl_owner_t owner = current->files; 14748c2ecf20Sopenharmony_ci size_t nbytes = min(count, nmax); 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci err = fuse_get_user_pages(&ia->ap, iter, &nbytes, write, 14778c2ecf20Sopenharmony_ci max_pages); 14788c2ecf20Sopenharmony_ci if (err && !nbytes) 14798c2ecf20Sopenharmony_ci break; 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci if (write) { 14828c2ecf20Sopenharmony_ci if (!capable(CAP_FSETID)) 14838c2ecf20Sopenharmony_ci ia->write.in.write_flags |= FUSE_WRITE_KILL_PRIV; 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci nres = fuse_send_write(ia, pos, nbytes, owner); 14868c2ecf20Sopenharmony_ci } else { 14878c2ecf20Sopenharmony_ci nres = fuse_send_read(ia, pos, nbytes, owner); 14888c2ecf20Sopenharmony_ci } 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci if (!io->async || nres < 0) { 14918c2ecf20Sopenharmony_ci fuse_release_user_pages(&ia->ap, io->should_dirty); 14928c2ecf20Sopenharmony_ci fuse_io_free(ia); 14938c2ecf20Sopenharmony_ci } 14948c2ecf20Sopenharmony_ci ia = NULL; 14958c2ecf20Sopenharmony_ci if (nres < 0) { 14968c2ecf20Sopenharmony_ci iov_iter_revert(iter, nbytes); 14978c2ecf20Sopenharmony_ci err = nres; 14988c2ecf20Sopenharmony_ci break; 14998c2ecf20Sopenharmony_ci } 15008c2ecf20Sopenharmony_ci WARN_ON(nres > nbytes); 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci count -= nres; 15038c2ecf20Sopenharmony_ci res += nres; 15048c2ecf20Sopenharmony_ci pos += nres; 15058c2ecf20Sopenharmony_ci if (nres != nbytes) { 15068c2ecf20Sopenharmony_ci iov_iter_revert(iter, nbytes - nres); 15078c2ecf20Sopenharmony_ci break; 15088c2ecf20Sopenharmony_ci } 15098c2ecf20Sopenharmony_ci if (count) { 15108c2ecf20Sopenharmony_ci max_pages = iov_iter_npages(iter, fc->max_pages); 15118c2ecf20Sopenharmony_ci ia = fuse_io_alloc(io, max_pages); 15128c2ecf20Sopenharmony_ci if (!ia) 15138c2ecf20Sopenharmony_ci break; 15148c2ecf20Sopenharmony_ci } 15158c2ecf20Sopenharmony_ci } 15168c2ecf20Sopenharmony_ci if (ia) 15178c2ecf20Sopenharmony_ci fuse_io_free(ia); 15188c2ecf20Sopenharmony_ci if (res > 0) 15198c2ecf20Sopenharmony_ci *ppos = pos; 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci return res > 0 ? res : err; 15228c2ecf20Sopenharmony_ci} 15238c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(fuse_direct_io); 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_cistatic ssize_t __fuse_direct_read(struct fuse_io_priv *io, 15268c2ecf20Sopenharmony_ci struct iov_iter *iter, 15278c2ecf20Sopenharmony_ci loff_t *ppos) 15288c2ecf20Sopenharmony_ci{ 15298c2ecf20Sopenharmony_ci ssize_t res; 15308c2ecf20Sopenharmony_ci struct inode *inode = file_inode(io->iocb->ki_filp); 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci res = fuse_direct_io(io, iter, ppos, 0); 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci fuse_invalidate_atime(inode); 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci return res; 15378c2ecf20Sopenharmony_ci} 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_cistatic ssize_t fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter); 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_cistatic ssize_t fuse_direct_read_iter(struct kiocb *iocb, struct iov_iter *to) 15428c2ecf20Sopenharmony_ci{ 15438c2ecf20Sopenharmony_ci ssize_t res; 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci if (!is_sync_kiocb(iocb) && iocb->ki_flags & IOCB_DIRECT) { 15468c2ecf20Sopenharmony_ci res = fuse_direct_IO(iocb, to); 15478c2ecf20Sopenharmony_ci } else { 15488c2ecf20Sopenharmony_ci struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(iocb); 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci res = __fuse_direct_read(&io, to, &iocb->ki_pos); 15518c2ecf20Sopenharmony_ci } 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ci return res; 15548c2ecf20Sopenharmony_ci} 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_cistatic ssize_t fuse_direct_write_iter(struct kiocb *iocb, struct iov_iter *from) 15578c2ecf20Sopenharmony_ci{ 15588c2ecf20Sopenharmony_ci struct inode *inode = file_inode(iocb->ki_filp); 15598c2ecf20Sopenharmony_ci struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(iocb); 15608c2ecf20Sopenharmony_ci ssize_t res; 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci /* Don't allow parallel writes to the same file */ 15638c2ecf20Sopenharmony_ci inode_lock(inode); 15648c2ecf20Sopenharmony_ci res = generic_write_checks(iocb, from); 15658c2ecf20Sopenharmony_ci if (res > 0) { 15668c2ecf20Sopenharmony_ci if (!is_sync_kiocb(iocb) && iocb->ki_flags & IOCB_DIRECT) { 15678c2ecf20Sopenharmony_ci res = fuse_direct_IO(iocb, from); 15688c2ecf20Sopenharmony_ci } else { 15698c2ecf20Sopenharmony_ci res = fuse_direct_io(&io, from, &iocb->ki_pos, 15708c2ecf20Sopenharmony_ci FUSE_DIO_WRITE); 15718c2ecf20Sopenharmony_ci } 15728c2ecf20Sopenharmony_ci } 15738c2ecf20Sopenharmony_ci fuse_invalidate_attr(inode); 15748c2ecf20Sopenharmony_ci if (res > 0) 15758c2ecf20Sopenharmony_ci fuse_write_update_size(inode, iocb->ki_pos); 15768c2ecf20Sopenharmony_ci inode_unlock(inode); 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci return res; 15798c2ecf20Sopenharmony_ci} 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_cistatic ssize_t fuse_file_read_iter(struct kiocb *iocb, struct iov_iter *to) 15828c2ecf20Sopenharmony_ci{ 15838c2ecf20Sopenharmony_ci struct file *file = iocb->ki_filp; 15848c2ecf20Sopenharmony_ci struct fuse_file *ff = file->private_data; 15858c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci if (fuse_is_bad(inode)) 15888c2ecf20Sopenharmony_ci return -EIO; 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci if (FUSE_IS_DAX(inode)) 15918c2ecf20Sopenharmony_ci return fuse_dax_read_iter(iocb, to); 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci if (!(ff->open_flags & FOPEN_DIRECT_IO)) 15948c2ecf20Sopenharmony_ci return fuse_cache_read_iter(iocb, to); 15958c2ecf20Sopenharmony_ci else 15968c2ecf20Sopenharmony_ci return fuse_direct_read_iter(iocb, to); 15978c2ecf20Sopenharmony_ci} 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_cistatic ssize_t fuse_file_write_iter(struct kiocb *iocb, struct iov_iter *from) 16008c2ecf20Sopenharmony_ci{ 16018c2ecf20Sopenharmony_ci struct file *file = iocb->ki_filp; 16028c2ecf20Sopenharmony_ci struct fuse_file *ff = file->private_data; 16038c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci if (fuse_is_bad(inode)) 16068c2ecf20Sopenharmony_ci return -EIO; 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci if (FUSE_IS_DAX(inode)) 16098c2ecf20Sopenharmony_ci return fuse_dax_write_iter(iocb, from); 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci if (!(ff->open_flags & FOPEN_DIRECT_IO)) 16128c2ecf20Sopenharmony_ci return fuse_cache_write_iter(iocb, from); 16138c2ecf20Sopenharmony_ci else 16148c2ecf20Sopenharmony_ci return fuse_direct_write_iter(iocb, from); 16158c2ecf20Sopenharmony_ci} 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_cistatic void fuse_writepage_free(struct fuse_writepage_args *wpa) 16188c2ecf20Sopenharmony_ci{ 16198c2ecf20Sopenharmony_ci struct fuse_args_pages *ap = &wpa->ia.ap; 16208c2ecf20Sopenharmony_ci int i; 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_ci for (i = 0; i < ap->num_pages; i++) 16238c2ecf20Sopenharmony_ci __free_page(ap->pages[i]); 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_ci if (wpa->ia.ff) 16268c2ecf20Sopenharmony_ci fuse_file_put(wpa->ia.ff, false, false); 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci kfree(ap->pages); 16298c2ecf20Sopenharmony_ci kfree(wpa); 16308c2ecf20Sopenharmony_ci} 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_cistatic void fuse_writepage_finish(struct fuse_mount *fm, 16338c2ecf20Sopenharmony_ci struct fuse_writepage_args *wpa) 16348c2ecf20Sopenharmony_ci{ 16358c2ecf20Sopenharmony_ci struct fuse_args_pages *ap = &wpa->ia.ap; 16368c2ecf20Sopenharmony_ci struct inode *inode = wpa->inode; 16378c2ecf20Sopenharmony_ci struct fuse_inode *fi = get_fuse_inode(inode); 16388c2ecf20Sopenharmony_ci struct backing_dev_info *bdi = inode_to_bdi(inode); 16398c2ecf20Sopenharmony_ci int i; 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci for (i = 0; i < ap->num_pages; i++) { 16428c2ecf20Sopenharmony_ci dec_wb_stat(&bdi->wb, WB_WRITEBACK); 16438c2ecf20Sopenharmony_ci dec_node_page_state(ap->pages[i], NR_WRITEBACK_TEMP); 16448c2ecf20Sopenharmony_ci wb_writeout_inc(&bdi->wb); 16458c2ecf20Sopenharmony_ci } 16468c2ecf20Sopenharmony_ci wake_up(&fi->page_waitq); 16478c2ecf20Sopenharmony_ci} 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci/* Called under fi->lock, may release and reacquire it */ 16508c2ecf20Sopenharmony_cistatic void fuse_send_writepage(struct fuse_mount *fm, 16518c2ecf20Sopenharmony_ci struct fuse_writepage_args *wpa, loff_t size) 16528c2ecf20Sopenharmony_ci__releases(fi->lock) 16538c2ecf20Sopenharmony_ci__acquires(fi->lock) 16548c2ecf20Sopenharmony_ci{ 16558c2ecf20Sopenharmony_ci struct fuse_writepage_args *aux, *next; 16568c2ecf20Sopenharmony_ci struct fuse_inode *fi = get_fuse_inode(wpa->inode); 16578c2ecf20Sopenharmony_ci struct fuse_write_in *inarg = &wpa->ia.write.in; 16588c2ecf20Sopenharmony_ci struct fuse_args *args = &wpa->ia.ap.args; 16598c2ecf20Sopenharmony_ci __u64 data_size = wpa->ia.ap.num_pages * PAGE_SIZE; 16608c2ecf20Sopenharmony_ci int err; 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci fi->writectr++; 16638c2ecf20Sopenharmony_ci if (inarg->offset + data_size <= size) { 16648c2ecf20Sopenharmony_ci inarg->size = data_size; 16658c2ecf20Sopenharmony_ci } else if (inarg->offset < size) { 16668c2ecf20Sopenharmony_ci inarg->size = size - inarg->offset; 16678c2ecf20Sopenharmony_ci } else { 16688c2ecf20Sopenharmony_ci /* Got truncated off completely */ 16698c2ecf20Sopenharmony_ci goto out_free; 16708c2ecf20Sopenharmony_ci } 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci args->in_args[1].size = inarg->size; 16738c2ecf20Sopenharmony_ci args->force = true; 16748c2ecf20Sopenharmony_ci args->nocreds = true; 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci err = fuse_simple_background(fm, args, GFP_ATOMIC); 16778c2ecf20Sopenharmony_ci if (err == -ENOMEM) { 16788c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 16798c2ecf20Sopenharmony_ci err = fuse_simple_background(fm, args, GFP_NOFS | __GFP_NOFAIL); 16808c2ecf20Sopenharmony_ci spin_lock(&fi->lock); 16818c2ecf20Sopenharmony_ci } 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci /* Fails on broken connection only */ 16848c2ecf20Sopenharmony_ci if (unlikely(err)) 16858c2ecf20Sopenharmony_ci goto out_free; 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci return; 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_ci out_free: 16908c2ecf20Sopenharmony_ci fi->writectr--; 16918c2ecf20Sopenharmony_ci rb_erase(&wpa->writepages_entry, &fi->writepages); 16928c2ecf20Sopenharmony_ci fuse_writepage_finish(fm, wpa); 16938c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci /* After fuse_writepage_finish() aux request list is private */ 16968c2ecf20Sopenharmony_ci for (aux = wpa->next; aux; aux = next) { 16978c2ecf20Sopenharmony_ci next = aux->next; 16988c2ecf20Sopenharmony_ci aux->next = NULL; 16998c2ecf20Sopenharmony_ci fuse_writepage_free(aux); 17008c2ecf20Sopenharmony_ci } 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci fuse_writepage_free(wpa); 17038c2ecf20Sopenharmony_ci spin_lock(&fi->lock); 17048c2ecf20Sopenharmony_ci} 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_ci/* 17078c2ecf20Sopenharmony_ci * If fi->writectr is positive (no truncate or fsync going on) send 17088c2ecf20Sopenharmony_ci * all queued writepage requests. 17098c2ecf20Sopenharmony_ci * 17108c2ecf20Sopenharmony_ci * Called with fi->lock 17118c2ecf20Sopenharmony_ci */ 17128c2ecf20Sopenharmony_civoid fuse_flush_writepages(struct inode *inode) 17138c2ecf20Sopenharmony_ci__releases(fi->lock) 17148c2ecf20Sopenharmony_ci__acquires(fi->lock) 17158c2ecf20Sopenharmony_ci{ 17168c2ecf20Sopenharmony_ci struct fuse_mount *fm = get_fuse_mount(inode); 17178c2ecf20Sopenharmony_ci struct fuse_inode *fi = get_fuse_inode(inode); 17188c2ecf20Sopenharmony_ci loff_t crop = i_size_read(inode); 17198c2ecf20Sopenharmony_ci struct fuse_writepage_args *wpa; 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci while (fi->writectr >= 0 && !list_empty(&fi->queued_writes)) { 17228c2ecf20Sopenharmony_ci wpa = list_entry(fi->queued_writes.next, 17238c2ecf20Sopenharmony_ci struct fuse_writepage_args, queue_entry); 17248c2ecf20Sopenharmony_ci list_del_init(&wpa->queue_entry); 17258c2ecf20Sopenharmony_ci fuse_send_writepage(fm, wpa, crop); 17268c2ecf20Sopenharmony_ci } 17278c2ecf20Sopenharmony_ci} 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_cistatic struct fuse_writepage_args *fuse_insert_writeback(struct rb_root *root, 17308c2ecf20Sopenharmony_ci struct fuse_writepage_args *wpa) 17318c2ecf20Sopenharmony_ci{ 17328c2ecf20Sopenharmony_ci pgoff_t idx_from = wpa->ia.write.in.offset >> PAGE_SHIFT; 17338c2ecf20Sopenharmony_ci pgoff_t idx_to = idx_from + wpa->ia.ap.num_pages - 1; 17348c2ecf20Sopenharmony_ci struct rb_node **p = &root->rb_node; 17358c2ecf20Sopenharmony_ci struct rb_node *parent = NULL; 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci WARN_ON(!wpa->ia.ap.num_pages); 17388c2ecf20Sopenharmony_ci while (*p) { 17398c2ecf20Sopenharmony_ci struct fuse_writepage_args *curr; 17408c2ecf20Sopenharmony_ci pgoff_t curr_index; 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_ci parent = *p; 17438c2ecf20Sopenharmony_ci curr = rb_entry(parent, struct fuse_writepage_args, 17448c2ecf20Sopenharmony_ci writepages_entry); 17458c2ecf20Sopenharmony_ci WARN_ON(curr->inode != wpa->inode); 17468c2ecf20Sopenharmony_ci curr_index = curr->ia.write.in.offset >> PAGE_SHIFT; 17478c2ecf20Sopenharmony_ci 17488c2ecf20Sopenharmony_ci if (idx_from >= curr_index + curr->ia.ap.num_pages) 17498c2ecf20Sopenharmony_ci p = &(*p)->rb_right; 17508c2ecf20Sopenharmony_ci else if (idx_to < curr_index) 17518c2ecf20Sopenharmony_ci p = &(*p)->rb_left; 17528c2ecf20Sopenharmony_ci else 17538c2ecf20Sopenharmony_ci return curr; 17548c2ecf20Sopenharmony_ci } 17558c2ecf20Sopenharmony_ci 17568c2ecf20Sopenharmony_ci rb_link_node(&wpa->writepages_entry, parent, p); 17578c2ecf20Sopenharmony_ci rb_insert_color(&wpa->writepages_entry, root); 17588c2ecf20Sopenharmony_ci return NULL; 17598c2ecf20Sopenharmony_ci} 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_cistatic void tree_insert(struct rb_root *root, struct fuse_writepage_args *wpa) 17628c2ecf20Sopenharmony_ci{ 17638c2ecf20Sopenharmony_ci WARN_ON(fuse_insert_writeback(root, wpa)); 17648c2ecf20Sopenharmony_ci} 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_cistatic void fuse_writepage_end(struct fuse_mount *fm, struct fuse_args *args, 17678c2ecf20Sopenharmony_ci int error) 17688c2ecf20Sopenharmony_ci{ 17698c2ecf20Sopenharmony_ci struct fuse_writepage_args *wpa = 17708c2ecf20Sopenharmony_ci container_of(args, typeof(*wpa), ia.ap.args); 17718c2ecf20Sopenharmony_ci struct inode *inode = wpa->inode; 17728c2ecf20Sopenharmony_ci struct fuse_inode *fi = get_fuse_inode(inode); 17738c2ecf20Sopenharmony_ci struct fuse_conn *fc = get_fuse_conn(inode); 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci mapping_set_error(inode->i_mapping, error); 17768c2ecf20Sopenharmony_ci /* 17778c2ecf20Sopenharmony_ci * A writeback finished and this might have updated mtime/ctime on 17788c2ecf20Sopenharmony_ci * server making local mtime/ctime stale. Hence invalidate attrs. 17798c2ecf20Sopenharmony_ci * Do this only if writeback_cache is not enabled. If writeback_cache 17808c2ecf20Sopenharmony_ci * is enabled, we trust local ctime/mtime. 17818c2ecf20Sopenharmony_ci */ 17828c2ecf20Sopenharmony_ci if (!fc->writeback_cache) 17838c2ecf20Sopenharmony_ci fuse_invalidate_attr(inode); 17848c2ecf20Sopenharmony_ci spin_lock(&fi->lock); 17858c2ecf20Sopenharmony_ci rb_erase(&wpa->writepages_entry, &fi->writepages); 17868c2ecf20Sopenharmony_ci while (wpa->next) { 17878c2ecf20Sopenharmony_ci struct fuse_mount *fm = get_fuse_mount(inode); 17888c2ecf20Sopenharmony_ci struct fuse_write_in *inarg = &wpa->ia.write.in; 17898c2ecf20Sopenharmony_ci struct fuse_writepage_args *next = wpa->next; 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci wpa->next = next->next; 17928c2ecf20Sopenharmony_ci next->next = NULL; 17938c2ecf20Sopenharmony_ci next->ia.ff = fuse_file_get(wpa->ia.ff); 17948c2ecf20Sopenharmony_ci tree_insert(&fi->writepages, next); 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci /* 17978c2ecf20Sopenharmony_ci * Skip fuse_flush_writepages() to make it easy to crop requests 17988c2ecf20Sopenharmony_ci * based on primary request size. 17998c2ecf20Sopenharmony_ci * 18008c2ecf20Sopenharmony_ci * 1st case (trivial): there are no concurrent activities using 18018c2ecf20Sopenharmony_ci * fuse_set/release_nowrite. Then we're on safe side because 18028c2ecf20Sopenharmony_ci * fuse_flush_writepages() would call fuse_send_writepage() 18038c2ecf20Sopenharmony_ci * anyway. 18048c2ecf20Sopenharmony_ci * 18058c2ecf20Sopenharmony_ci * 2nd case: someone called fuse_set_nowrite and it is waiting 18068c2ecf20Sopenharmony_ci * now for completion of all in-flight requests. This happens 18078c2ecf20Sopenharmony_ci * rarely and no more than once per page, so this should be 18088c2ecf20Sopenharmony_ci * okay. 18098c2ecf20Sopenharmony_ci * 18108c2ecf20Sopenharmony_ci * 3rd case: someone (e.g. fuse_do_setattr()) is in the middle 18118c2ecf20Sopenharmony_ci * of fuse_set_nowrite..fuse_release_nowrite section. The fact 18128c2ecf20Sopenharmony_ci * that fuse_set_nowrite returned implies that all in-flight 18138c2ecf20Sopenharmony_ci * requests were completed along with all of their secondary 18148c2ecf20Sopenharmony_ci * requests. Further primary requests are blocked by negative 18158c2ecf20Sopenharmony_ci * writectr. Hence there cannot be any in-flight requests and 18168c2ecf20Sopenharmony_ci * no invocations of fuse_writepage_end() while we're in 18178c2ecf20Sopenharmony_ci * fuse_set_nowrite..fuse_release_nowrite section. 18188c2ecf20Sopenharmony_ci */ 18198c2ecf20Sopenharmony_ci fuse_send_writepage(fm, next, inarg->offset + inarg->size); 18208c2ecf20Sopenharmony_ci } 18218c2ecf20Sopenharmony_ci fi->writectr--; 18228c2ecf20Sopenharmony_ci fuse_writepage_finish(fm, wpa); 18238c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 18248c2ecf20Sopenharmony_ci fuse_writepage_free(wpa); 18258c2ecf20Sopenharmony_ci} 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_cistatic struct fuse_file *__fuse_write_file_get(struct fuse_conn *fc, 18288c2ecf20Sopenharmony_ci struct fuse_inode *fi) 18298c2ecf20Sopenharmony_ci{ 18308c2ecf20Sopenharmony_ci struct fuse_file *ff = NULL; 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ci spin_lock(&fi->lock); 18338c2ecf20Sopenharmony_ci if (!list_empty(&fi->write_files)) { 18348c2ecf20Sopenharmony_ci ff = list_entry(fi->write_files.next, struct fuse_file, 18358c2ecf20Sopenharmony_ci write_entry); 18368c2ecf20Sopenharmony_ci fuse_file_get(ff); 18378c2ecf20Sopenharmony_ci } 18388c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ci return ff; 18418c2ecf20Sopenharmony_ci} 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_cistatic struct fuse_file *fuse_write_file_get(struct fuse_conn *fc, 18448c2ecf20Sopenharmony_ci struct fuse_inode *fi) 18458c2ecf20Sopenharmony_ci{ 18468c2ecf20Sopenharmony_ci struct fuse_file *ff = __fuse_write_file_get(fc, fi); 18478c2ecf20Sopenharmony_ci WARN_ON(!ff); 18488c2ecf20Sopenharmony_ci return ff; 18498c2ecf20Sopenharmony_ci} 18508c2ecf20Sopenharmony_ci 18518c2ecf20Sopenharmony_ciint fuse_write_inode(struct inode *inode, struct writeback_control *wbc) 18528c2ecf20Sopenharmony_ci{ 18538c2ecf20Sopenharmony_ci struct fuse_conn *fc = get_fuse_conn(inode); 18548c2ecf20Sopenharmony_ci struct fuse_inode *fi = get_fuse_inode(inode); 18558c2ecf20Sopenharmony_ci struct fuse_file *ff; 18568c2ecf20Sopenharmony_ci int err; 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ci /* 18598c2ecf20Sopenharmony_ci * Inode is always written before the last reference is dropped and 18608c2ecf20Sopenharmony_ci * hence this should not be reached from reclaim. 18618c2ecf20Sopenharmony_ci * 18628c2ecf20Sopenharmony_ci * Writing back the inode from reclaim can deadlock if the request 18638c2ecf20Sopenharmony_ci * processing itself needs an allocation. Allocations triggering 18648c2ecf20Sopenharmony_ci * reclaim while serving a request can't be prevented, because it can 18658c2ecf20Sopenharmony_ci * involve any number of unrelated userspace processes. 18668c2ecf20Sopenharmony_ci */ 18678c2ecf20Sopenharmony_ci WARN_ON(wbc->for_reclaim); 18688c2ecf20Sopenharmony_ci 18698c2ecf20Sopenharmony_ci ff = __fuse_write_file_get(fc, fi); 18708c2ecf20Sopenharmony_ci err = fuse_flush_times(inode, ff); 18718c2ecf20Sopenharmony_ci if (ff) 18728c2ecf20Sopenharmony_ci fuse_file_put(ff, false, false); 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci return err; 18758c2ecf20Sopenharmony_ci} 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_cistatic struct fuse_writepage_args *fuse_writepage_args_alloc(void) 18788c2ecf20Sopenharmony_ci{ 18798c2ecf20Sopenharmony_ci struct fuse_writepage_args *wpa; 18808c2ecf20Sopenharmony_ci struct fuse_args_pages *ap; 18818c2ecf20Sopenharmony_ci 18828c2ecf20Sopenharmony_ci wpa = kzalloc(sizeof(*wpa), GFP_NOFS); 18838c2ecf20Sopenharmony_ci if (wpa) { 18848c2ecf20Sopenharmony_ci ap = &wpa->ia.ap; 18858c2ecf20Sopenharmony_ci ap->num_pages = 0; 18868c2ecf20Sopenharmony_ci ap->pages = fuse_pages_alloc(1, GFP_NOFS, &ap->descs); 18878c2ecf20Sopenharmony_ci if (!ap->pages) { 18888c2ecf20Sopenharmony_ci kfree(wpa); 18898c2ecf20Sopenharmony_ci wpa = NULL; 18908c2ecf20Sopenharmony_ci } 18918c2ecf20Sopenharmony_ci } 18928c2ecf20Sopenharmony_ci return wpa; 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_ci} 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_cistatic int fuse_writepage_locked(struct page *page) 18978c2ecf20Sopenharmony_ci{ 18988c2ecf20Sopenharmony_ci struct address_space *mapping = page->mapping; 18998c2ecf20Sopenharmony_ci struct inode *inode = mapping->host; 19008c2ecf20Sopenharmony_ci struct fuse_conn *fc = get_fuse_conn(inode); 19018c2ecf20Sopenharmony_ci struct fuse_inode *fi = get_fuse_inode(inode); 19028c2ecf20Sopenharmony_ci struct fuse_writepage_args *wpa; 19038c2ecf20Sopenharmony_ci struct fuse_args_pages *ap; 19048c2ecf20Sopenharmony_ci struct page *tmp_page; 19058c2ecf20Sopenharmony_ci int error = -ENOMEM; 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_ci set_page_writeback(page); 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_ci wpa = fuse_writepage_args_alloc(); 19108c2ecf20Sopenharmony_ci if (!wpa) 19118c2ecf20Sopenharmony_ci goto err; 19128c2ecf20Sopenharmony_ci ap = &wpa->ia.ap; 19138c2ecf20Sopenharmony_ci 19148c2ecf20Sopenharmony_ci tmp_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM); 19158c2ecf20Sopenharmony_ci if (!tmp_page) 19168c2ecf20Sopenharmony_ci goto err_free; 19178c2ecf20Sopenharmony_ci 19188c2ecf20Sopenharmony_ci error = -EIO; 19198c2ecf20Sopenharmony_ci wpa->ia.ff = fuse_write_file_get(fc, fi); 19208c2ecf20Sopenharmony_ci if (!wpa->ia.ff) 19218c2ecf20Sopenharmony_ci goto err_nofile; 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_ci fuse_write_args_fill(&wpa->ia, wpa->ia.ff, page_offset(page), 0); 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_ci copy_highpage(tmp_page, page); 19268c2ecf20Sopenharmony_ci wpa->ia.write.in.write_flags |= FUSE_WRITE_CACHE; 19278c2ecf20Sopenharmony_ci wpa->next = NULL; 19288c2ecf20Sopenharmony_ci ap->args.in_pages = true; 19298c2ecf20Sopenharmony_ci ap->num_pages = 1; 19308c2ecf20Sopenharmony_ci ap->pages[0] = tmp_page; 19318c2ecf20Sopenharmony_ci ap->descs[0].offset = 0; 19328c2ecf20Sopenharmony_ci ap->descs[0].length = PAGE_SIZE; 19338c2ecf20Sopenharmony_ci ap->args.end = fuse_writepage_end; 19348c2ecf20Sopenharmony_ci wpa->inode = inode; 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_ci inc_wb_stat(&inode_to_bdi(inode)->wb, WB_WRITEBACK); 19378c2ecf20Sopenharmony_ci inc_node_page_state(tmp_page, NR_WRITEBACK_TEMP); 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_ci spin_lock(&fi->lock); 19408c2ecf20Sopenharmony_ci tree_insert(&fi->writepages, wpa); 19418c2ecf20Sopenharmony_ci list_add_tail(&wpa->queue_entry, &fi->queued_writes); 19428c2ecf20Sopenharmony_ci fuse_flush_writepages(inode); 19438c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci end_page_writeback(page); 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_ci return 0; 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_cierr_nofile: 19508c2ecf20Sopenharmony_ci __free_page(tmp_page); 19518c2ecf20Sopenharmony_cierr_free: 19528c2ecf20Sopenharmony_ci kfree(wpa); 19538c2ecf20Sopenharmony_cierr: 19548c2ecf20Sopenharmony_ci mapping_set_error(page->mapping, error); 19558c2ecf20Sopenharmony_ci end_page_writeback(page); 19568c2ecf20Sopenharmony_ci return error; 19578c2ecf20Sopenharmony_ci} 19588c2ecf20Sopenharmony_ci 19598c2ecf20Sopenharmony_cistatic int fuse_writepage(struct page *page, struct writeback_control *wbc) 19608c2ecf20Sopenharmony_ci{ 19618c2ecf20Sopenharmony_ci int err; 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci if (fuse_page_is_writeback(page->mapping->host, page->index)) { 19648c2ecf20Sopenharmony_ci /* 19658c2ecf20Sopenharmony_ci * ->writepages() should be called for sync() and friends. We 19668c2ecf20Sopenharmony_ci * should only get here on direct reclaim and then we are 19678c2ecf20Sopenharmony_ci * allowed to skip a page which is already in flight 19688c2ecf20Sopenharmony_ci */ 19698c2ecf20Sopenharmony_ci WARN_ON(wbc->sync_mode == WB_SYNC_ALL); 19708c2ecf20Sopenharmony_ci 19718c2ecf20Sopenharmony_ci redirty_page_for_writepage(wbc, page); 19728c2ecf20Sopenharmony_ci unlock_page(page); 19738c2ecf20Sopenharmony_ci return 0; 19748c2ecf20Sopenharmony_ci } 19758c2ecf20Sopenharmony_ci 19768c2ecf20Sopenharmony_ci err = fuse_writepage_locked(page); 19778c2ecf20Sopenharmony_ci unlock_page(page); 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_ci return err; 19808c2ecf20Sopenharmony_ci} 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_cistruct fuse_fill_wb_data { 19838c2ecf20Sopenharmony_ci struct fuse_writepage_args *wpa; 19848c2ecf20Sopenharmony_ci struct fuse_file *ff; 19858c2ecf20Sopenharmony_ci struct inode *inode; 19868c2ecf20Sopenharmony_ci struct page **orig_pages; 19878c2ecf20Sopenharmony_ci unsigned int max_pages; 19888c2ecf20Sopenharmony_ci}; 19898c2ecf20Sopenharmony_ci 19908c2ecf20Sopenharmony_cistatic bool fuse_pages_realloc(struct fuse_fill_wb_data *data) 19918c2ecf20Sopenharmony_ci{ 19928c2ecf20Sopenharmony_ci struct fuse_args_pages *ap = &data->wpa->ia.ap; 19938c2ecf20Sopenharmony_ci struct fuse_conn *fc = get_fuse_conn(data->inode); 19948c2ecf20Sopenharmony_ci struct page **pages; 19958c2ecf20Sopenharmony_ci struct fuse_page_desc *descs; 19968c2ecf20Sopenharmony_ci unsigned int npages = min_t(unsigned int, 19978c2ecf20Sopenharmony_ci max_t(unsigned int, data->max_pages * 2, 19988c2ecf20Sopenharmony_ci FUSE_DEFAULT_MAX_PAGES_PER_REQ), 19998c2ecf20Sopenharmony_ci fc->max_pages); 20008c2ecf20Sopenharmony_ci WARN_ON(npages <= data->max_pages); 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_ci pages = fuse_pages_alloc(npages, GFP_NOFS, &descs); 20038c2ecf20Sopenharmony_ci if (!pages) 20048c2ecf20Sopenharmony_ci return false; 20058c2ecf20Sopenharmony_ci 20068c2ecf20Sopenharmony_ci memcpy(pages, ap->pages, sizeof(struct page *) * ap->num_pages); 20078c2ecf20Sopenharmony_ci memcpy(descs, ap->descs, sizeof(struct fuse_page_desc) * ap->num_pages); 20088c2ecf20Sopenharmony_ci kfree(ap->pages); 20098c2ecf20Sopenharmony_ci ap->pages = pages; 20108c2ecf20Sopenharmony_ci ap->descs = descs; 20118c2ecf20Sopenharmony_ci data->max_pages = npages; 20128c2ecf20Sopenharmony_ci 20138c2ecf20Sopenharmony_ci return true; 20148c2ecf20Sopenharmony_ci} 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_cistatic void fuse_writepages_send(struct fuse_fill_wb_data *data) 20178c2ecf20Sopenharmony_ci{ 20188c2ecf20Sopenharmony_ci struct fuse_writepage_args *wpa = data->wpa; 20198c2ecf20Sopenharmony_ci struct inode *inode = data->inode; 20208c2ecf20Sopenharmony_ci struct fuse_inode *fi = get_fuse_inode(inode); 20218c2ecf20Sopenharmony_ci int num_pages = wpa->ia.ap.num_pages; 20228c2ecf20Sopenharmony_ci int i; 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_ci wpa->ia.ff = fuse_file_get(data->ff); 20258c2ecf20Sopenharmony_ci spin_lock(&fi->lock); 20268c2ecf20Sopenharmony_ci list_add_tail(&wpa->queue_entry, &fi->queued_writes); 20278c2ecf20Sopenharmony_ci fuse_flush_writepages(inode); 20288c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_ci for (i = 0; i < num_pages; i++) 20318c2ecf20Sopenharmony_ci end_page_writeback(data->orig_pages[i]); 20328c2ecf20Sopenharmony_ci} 20338c2ecf20Sopenharmony_ci 20348c2ecf20Sopenharmony_ci/* 20358c2ecf20Sopenharmony_ci * Check under fi->lock if the page is under writeback, and insert it onto the 20368c2ecf20Sopenharmony_ci * rb_tree if not. Otherwise iterate auxiliary write requests, to see if there's 20378c2ecf20Sopenharmony_ci * one already added for a page at this offset. If there's none, then insert 20388c2ecf20Sopenharmony_ci * this new request onto the auxiliary list, otherwise reuse the existing one by 20398c2ecf20Sopenharmony_ci * swapping the new temp page with the old one. 20408c2ecf20Sopenharmony_ci */ 20418c2ecf20Sopenharmony_cistatic bool fuse_writepage_add(struct fuse_writepage_args *new_wpa, 20428c2ecf20Sopenharmony_ci struct page *page) 20438c2ecf20Sopenharmony_ci{ 20448c2ecf20Sopenharmony_ci struct fuse_inode *fi = get_fuse_inode(new_wpa->inode); 20458c2ecf20Sopenharmony_ci struct fuse_writepage_args *tmp; 20468c2ecf20Sopenharmony_ci struct fuse_writepage_args *old_wpa; 20478c2ecf20Sopenharmony_ci struct fuse_args_pages *new_ap = &new_wpa->ia.ap; 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_ci WARN_ON(new_ap->num_pages != 0); 20508c2ecf20Sopenharmony_ci new_ap->num_pages = 1; 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci spin_lock(&fi->lock); 20538c2ecf20Sopenharmony_ci old_wpa = fuse_insert_writeback(&fi->writepages, new_wpa); 20548c2ecf20Sopenharmony_ci if (!old_wpa) { 20558c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 20568c2ecf20Sopenharmony_ci return true; 20578c2ecf20Sopenharmony_ci } 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_ci for (tmp = old_wpa->next; tmp; tmp = tmp->next) { 20608c2ecf20Sopenharmony_ci pgoff_t curr_index; 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_ci WARN_ON(tmp->inode != new_wpa->inode); 20638c2ecf20Sopenharmony_ci curr_index = tmp->ia.write.in.offset >> PAGE_SHIFT; 20648c2ecf20Sopenharmony_ci if (curr_index == page->index) { 20658c2ecf20Sopenharmony_ci WARN_ON(tmp->ia.ap.num_pages != 1); 20668c2ecf20Sopenharmony_ci swap(tmp->ia.ap.pages[0], new_ap->pages[0]); 20678c2ecf20Sopenharmony_ci break; 20688c2ecf20Sopenharmony_ci } 20698c2ecf20Sopenharmony_ci } 20708c2ecf20Sopenharmony_ci 20718c2ecf20Sopenharmony_ci if (!tmp) { 20728c2ecf20Sopenharmony_ci new_wpa->next = old_wpa->next; 20738c2ecf20Sopenharmony_ci old_wpa->next = new_wpa; 20748c2ecf20Sopenharmony_ci } 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 20778c2ecf20Sopenharmony_ci 20788c2ecf20Sopenharmony_ci if (tmp) { 20798c2ecf20Sopenharmony_ci struct backing_dev_info *bdi = inode_to_bdi(new_wpa->inode); 20808c2ecf20Sopenharmony_ci 20818c2ecf20Sopenharmony_ci dec_wb_stat(&bdi->wb, WB_WRITEBACK); 20828c2ecf20Sopenharmony_ci dec_node_page_state(new_ap->pages[0], NR_WRITEBACK_TEMP); 20838c2ecf20Sopenharmony_ci wb_writeout_inc(&bdi->wb); 20848c2ecf20Sopenharmony_ci fuse_writepage_free(new_wpa); 20858c2ecf20Sopenharmony_ci } 20868c2ecf20Sopenharmony_ci 20878c2ecf20Sopenharmony_ci return false; 20888c2ecf20Sopenharmony_ci} 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_cistatic bool fuse_writepage_need_send(struct fuse_conn *fc, struct page *page, 20918c2ecf20Sopenharmony_ci struct fuse_args_pages *ap, 20928c2ecf20Sopenharmony_ci struct fuse_fill_wb_data *data) 20938c2ecf20Sopenharmony_ci{ 20948c2ecf20Sopenharmony_ci WARN_ON(!ap->num_pages); 20958c2ecf20Sopenharmony_ci 20968c2ecf20Sopenharmony_ci /* 20978c2ecf20Sopenharmony_ci * Being under writeback is unlikely but possible. For example direct 20988c2ecf20Sopenharmony_ci * read to an mmaped fuse file will set the page dirty twice; once when 20998c2ecf20Sopenharmony_ci * the pages are faulted with get_user_pages(), and then after the read 21008c2ecf20Sopenharmony_ci * completed. 21018c2ecf20Sopenharmony_ci */ 21028c2ecf20Sopenharmony_ci if (fuse_page_is_writeback(data->inode, page->index)) 21038c2ecf20Sopenharmony_ci return true; 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_ci /* Reached max pages */ 21068c2ecf20Sopenharmony_ci if (ap->num_pages == fc->max_pages) 21078c2ecf20Sopenharmony_ci return true; 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_ci /* Reached max write bytes */ 21108c2ecf20Sopenharmony_ci if ((ap->num_pages + 1) * PAGE_SIZE > fc->max_write) 21118c2ecf20Sopenharmony_ci return true; 21128c2ecf20Sopenharmony_ci 21138c2ecf20Sopenharmony_ci /* Discontinuity */ 21148c2ecf20Sopenharmony_ci if (data->orig_pages[ap->num_pages - 1]->index + 1 != page->index) 21158c2ecf20Sopenharmony_ci return true; 21168c2ecf20Sopenharmony_ci 21178c2ecf20Sopenharmony_ci /* Need to grow the pages array? If so, did the expansion fail? */ 21188c2ecf20Sopenharmony_ci if (ap->num_pages == data->max_pages && !fuse_pages_realloc(data)) 21198c2ecf20Sopenharmony_ci return true; 21208c2ecf20Sopenharmony_ci 21218c2ecf20Sopenharmony_ci return false; 21228c2ecf20Sopenharmony_ci} 21238c2ecf20Sopenharmony_ci 21248c2ecf20Sopenharmony_cistatic int fuse_writepages_fill(struct page *page, 21258c2ecf20Sopenharmony_ci struct writeback_control *wbc, void *_data) 21268c2ecf20Sopenharmony_ci{ 21278c2ecf20Sopenharmony_ci struct fuse_fill_wb_data *data = _data; 21288c2ecf20Sopenharmony_ci struct fuse_writepage_args *wpa = data->wpa; 21298c2ecf20Sopenharmony_ci struct fuse_args_pages *ap = &wpa->ia.ap; 21308c2ecf20Sopenharmony_ci struct inode *inode = data->inode; 21318c2ecf20Sopenharmony_ci struct fuse_inode *fi = get_fuse_inode(inode); 21328c2ecf20Sopenharmony_ci struct fuse_conn *fc = get_fuse_conn(inode); 21338c2ecf20Sopenharmony_ci struct page *tmp_page; 21348c2ecf20Sopenharmony_ci int err; 21358c2ecf20Sopenharmony_ci 21368c2ecf20Sopenharmony_ci if (!data->ff) { 21378c2ecf20Sopenharmony_ci err = -EIO; 21388c2ecf20Sopenharmony_ci data->ff = fuse_write_file_get(fc, fi); 21398c2ecf20Sopenharmony_ci if (!data->ff) 21408c2ecf20Sopenharmony_ci goto out_unlock; 21418c2ecf20Sopenharmony_ci } 21428c2ecf20Sopenharmony_ci 21438c2ecf20Sopenharmony_ci if (wpa && fuse_writepage_need_send(fc, page, ap, data)) { 21448c2ecf20Sopenharmony_ci fuse_writepages_send(data); 21458c2ecf20Sopenharmony_ci data->wpa = NULL; 21468c2ecf20Sopenharmony_ci } 21478c2ecf20Sopenharmony_ci 21488c2ecf20Sopenharmony_ci err = -ENOMEM; 21498c2ecf20Sopenharmony_ci tmp_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM); 21508c2ecf20Sopenharmony_ci if (!tmp_page) 21518c2ecf20Sopenharmony_ci goto out_unlock; 21528c2ecf20Sopenharmony_ci 21538c2ecf20Sopenharmony_ci /* 21548c2ecf20Sopenharmony_ci * The page must not be redirtied until the writeout is completed 21558c2ecf20Sopenharmony_ci * (i.e. userspace has sent a reply to the write request). Otherwise 21568c2ecf20Sopenharmony_ci * there could be more than one temporary page instance for each real 21578c2ecf20Sopenharmony_ci * page. 21588c2ecf20Sopenharmony_ci * 21598c2ecf20Sopenharmony_ci * This is ensured by holding the page lock in page_mkwrite() while 21608c2ecf20Sopenharmony_ci * checking fuse_page_is_writeback(). We already hold the page lock 21618c2ecf20Sopenharmony_ci * since clear_page_dirty_for_io() and keep it held until we add the 21628c2ecf20Sopenharmony_ci * request to the fi->writepages list and increment ap->num_pages. 21638c2ecf20Sopenharmony_ci * After this fuse_page_is_writeback() will indicate that the page is 21648c2ecf20Sopenharmony_ci * under writeback, so we can release the page lock. 21658c2ecf20Sopenharmony_ci */ 21668c2ecf20Sopenharmony_ci if (data->wpa == NULL) { 21678c2ecf20Sopenharmony_ci err = -ENOMEM; 21688c2ecf20Sopenharmony_ci wpa = fuse_writepage_args_alloc(); 21698c2ecf20Sopenharmony_ci if (!wpa) { 21708c2ecf20Sopenharmony_ci __free_page(tmp_page); 21718c2ecf20Sopenharmony_ci goto out_unlock; 21728c2ecf20Sopenharmony_ci } 21738c2ecf20Sopenharmony_ci data->max_pages = 1; 21748c2ecf20Sopenharmony_ci 21758c2ecf20Sopenharmony_ci ap = &wpa->ia.ap; 21768c2ecf20Sopenharmony_ci fuse_write_args_fill(&wpa->ia, data->ff, page_offset(page), 0); 21778c2ecf20Sopenharmony_ci wpa->ia.write.in.write_flags |= FUSE_WRITE_CACHE; 21788c2ecf20Sopenharmony_ci wpa->next = NULL; 21798c2ecf20Sopenharmony_ci ap->args.in_pages = true; 21808c2ecf20Sopenharmony_ci ap->args.end = fuse_writepage_end; 21818c2ecf20Sopenharmony_ci ap->num_pages = 0; 21828c2ecf20Sopenharmony_ci wpa->inode = inode; 21838c2ecf20Sopenharmony_ci } 21848c2ecf20Sopenharmony_ci set_page_writeback(page); 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_ci copy_highpage(tmp_page, page); 21878c2ecf20Sopenharmony_ci ap->pages[ap->num_pages] = tmp_page; 21888c2ecf20Sopenharmony_ci ap->descs[ap->num_pages].offset = 0; 21898c2ecf20Sopenharmony_ci ap->descs[ap->num_pages].length = PAGE_SIZE; 21908c2ecf20Sopenharmony_ci data->orig_pages[ap->num_pages] = page; 21918c2ecf20Sopenharmony_ci 21928c2ecf20Sopenharmony_ci inc_wb_stat(&inode_to_bdi(inode)->wb, WB_WRITEBACK); 21938c2ecf20Sopenharmony_ci inc_node_page_state(tmp_page, NR_WRITEBACK_TEMP); 21948c2ecf20Sopenharmony_ci 21958c2ecf20Sopenharmony_ci err = 0; 21968c2ecf20Sopenharmony_ci if (data->wpa) { 21978c2ecf20Sopenharmony_ci /* 21988c2ecf20Sopenharmony_ci * Protected by fi->lock against concurrent access by 21998c2ecf20Sopenharmony_ci * fuse_page_is_writeback(). 22008c2ecf20Sopenharmony_ci */ 22018c2ecf20Sopenharmony_ci spin_lock(&fi->lock); 22028c2ecf20Sopenharmony_ci ap->num_pages++; 22038c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 22048c2ecf20Sopenharmony_ci } else if (fuse_writepage_add(wpa, page)) { 22058c2ecf20Sopenharmony_ci data->wpa = wpa; 22068c2ecf20Sopenharmony_ci } else { 22078c2ecf20Sopenharmony_ci end_page_writeback(page); 22088c2ecf20Sopenharmony_ci } 22098c2ecf20Sopenharmony_ciout_unlock: 22108c2ecf20Sopenharmony_ci unlock_page(page); 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_ci return err; 22138c2ecf20Sopenharmony_ci} 22148c2ecf20Sopenharmony_ci 22158c2ecf20Sopenharmony_cistatic int fuse_writepages(struct address_space *mapping, 22168c2ecf20Sopenharmony_ci struct writeback_control *wbc) 22178c2ecf20Sopenharmony_ci{ 22188c2ecf20Sopenharmony_ci struct inode *inode = mapping->host; 22198c2ecf20Sopenharmony_ci struct fuse_conn *fc = get_fuse_conn(inode); 22208c2ecf20Sopenharmony_ci struct fuse_fill_wb_data data; 22218c2ecf20Sopenharmony_ci int err; 22228c2ecf20Sopenharmony_ci 22238c2ecf20Sopenharmony_ci err = -EIO; 22248c2ecf20Sopenharmony_ci if (fuse_is_bad(inode)) 22258c2ecf20Sopenharmony_ci goto out; 22268c2ecf20Sopenharmony_ci 22278c2ecf20Sopenharmony_ci data.inode = inode; 22288c2ecf20Sopenharmony_ci data.wpa = NULL; 22298c2ecf20Sopenharmony_ci data.ff = NULL; 22308c2ecf20Sopenharmony_ci 22318c2ecf20Sopenharmony_ci err = -ENOMEM; 22328c2ecf20Sopenharmony_ci data.orig_pages = kcalloc(fc->max_pages, 22338c2ecf20Sopenharmony_ci sizeof(struct page *), 22348c2ecf20Sopenharmony_ci GFP_NOFS); 22358c2ecf20Sopenharmony_ci if (!data.orig_pages) 22368c2ecf20Sopenharmony_ci goto out; 22378c2ecf20Sopenharmony_ci 22388c2ecf20Sopenharmony_ci err = write_cache_pages(mapping, wbc, fuse_writepages_fill, &data); 22398c2ecf20Sopenharmony_ci if (data.wpa) { 22408c2ecf20Sopenharmony_ci WARN_ON(!data.wpa->ia.ap.num_pages); 22418c2ecf20Sopenharmony_ci fuse_writepages_send(&data); 22428c2ecf20Sopenharmony_ci } 22438c2ecf20Sopenharmony_ci if (data.ff) 22448c2ecf20Sopenharmony_ci fuse_file_put(data.ff, false, false); 22458c2ecf20Sopenharmony_ci 22468c2ecf20Sopenharmony_ci kfree(data.orig_pages); 22478c2ecf20Sopenharmony_ciout: 22488c2ecf20Sopenharmony_ci return err; 22498c2ecf20Sopenharmony_ci} 22508c2ecf20Sopenharmony_ci 22518c2ecf20Sopenharmony_ci/* 22528c2ecf20Sopenharmony_ci * It's worthy to make sure that space is reserved on disk for the write, 22538c2ecf20Sopenharmony_ci * but how to implement it without killing performance need more thinking. 22548c2ecf20Sopenharmony_ci */ 22558c2ecf20Sopenharmony_cistatic int fuse_write_begin(struct file *file, struct address_space *mapping, 22568c2ecf20Sopenharmony_ci loff_t pos, unsigned len, unsigned flags, 22578c2ecf20Sopenharmony_ci struct page **pagep, void **fsdata) 22588c2ecf20Sopenharmony_ci{ 22598c2ecf20Sopenharmony_ci pgoff_t index = pos >> PAGE_SHIFT; 22608c2ecf20Sopenharmony_ci struct fuse_conn *fc = get_fuse_conn(file_inode(file)); 22618c2ecf20Sopenharmony_ci struct page *page; 22628c2ecf20Sopenharmony_ci loff_t fsize; 22638c2ecf20Sopenharmony_ci int err = -ENOMEM; 22648c2ecf20Sopenharmony_ci 22658c2ecf20Sopenharmony_ci WARN_ON(!fc->writeback_cache); 22668c2ecf20Sopenharmony_ci 22678c2ecf20Sopenharmony_ci page = grab_cache_page_write_begin(mapping, index, flags); 22688c2ecf20Sopenharmony_ci if (!page) 22698c2ecf20Sopenharmony_ci goto error; 22708c2ecf20Sopenharmony_ci 22718c2ecf20Sopenharmony_ci fuse_wait_on_page_writeback(mapping->host, page->index); 22728c2ecf20Sopenharmony_ci 22738c2ecf20Sopenharmony_ci if (PageUptodate(page) || len == PAGE_SIZE) 22748c2ecf20Sopenharmony_ci goto success; 22758c2ecf20Sopenharmony_ci /* 22768c2ecf20Sopenharmony_ci * Check if the start this page comes after the end of file, in which 22778c2ecf20Sopenharmony_ci * case the readpage can be optimized away. 22788c2ecf20Sopenharmony_ci */ 22798c2ecf20Sopenharmony_ci fsize = i_size_read(mapping->host); 22808c2ecf20Sopenharmony_ci if (fsize <= (pos & PAGE_MASK)) { 22818c2ecf20Sopenharmony_ci size_t off = pos & ~PAGE_MASK; 22828c2ecf20Sopenharmony_ci if (off) 22838c2ecf20Sopenharmony_ci zero_user_segment(page, 0, off); 22848c2ecf20Sopenharmony_ci goto success; 22858c2ecf20Sopenharmony_ci } 22868c2ecf20Sopenharmony_ci err = fuse_do_readpage(file, page); 22878c2ecf20Sopenharmony_ci if (err) 22888c2ecf20Sopenharmony_ci goto cleanup; 22898c2ecf20Sopenharmony_cisuccess: 22908c2ecf20Sopenharmony_ci *pagep = page; 22918c2ecf20Sopenharmony_ci return 0; 22928c2ecf20Sopenharmony_ci 22938c2ecf20Sopenharmony_cicleanup: 22948c2ecf20Sopenharmony_ci unlock_page(page); 22958c2ecf20Sopenharmony_ci put_page(page); 22968c2ecf20Sopenharmony_cierror: 22978c2ecf20Sopenharmony_ci return err; 22988c2ecf20Sopenharmony_ci} 22998c2ecf20Sopenharmony_ci 23008c2ecf20Sopenharmony_cistatic int fuse_write_end(struct file *file, struct address_space *mapping, 23018c2ecf20Sopenharmony_ci loff_t pos, unsigned len, unsigned copied, 23028c2ecf20Sopenharmony_ci struct page *page, void *fsdata) 23038c2ecf20Sopenharmony_ci{ 23048c2ecf20Sopenharmony_ci struct inode *inode = page->mapping->host; 23058c2ecf20Sopenharmony_ci 23068c2ecf20Sopenharmony_ci /* Haven't copied anything? Skip zeroing, size extending, dirtying. */ 23078c2ecf20Sopenharmony_ci if (!copied) 23088c2ecf20Sopenharmony_ci goto unlock; 23098c2ecf20Sopenharmony_ci 23108c2ecf20Sopenharmony_ci if (!PageUptodate(page)) { 23118c2ecf20Sopenharmony_ci /* Zero any unwritten bytes at the end of the page */ 23128c2ecf20Sopenharmony_ci size_t endoff = (pos + copied) & ~PAGE_MASK; 23138c2ecf20Sopenharmony_ci if (endoff) 23148c2ecf20Sopenharmony_ci zero_user_segment(page, endoff, PAGE_SIZE); 23158c2ecf20Sopenharmony_ci SetPageUptodate(page); 23168c2ecf20Sopenharmony_ci } 23178c2ecf20Sopenharmony_ci 23188c2ecf20Sopenharmony_ci fuse_write_update_size(inode, pos + copied); 23198c2ecf20Sopenharmony_ci set_page_dirty(page); 23208c2ecf20Sopenharmony_ci 23218c2ecf20Sopenharmony_ciunlock: 23228c2ecf20Sopenharmony_ci unlock_page(page); 23238c2ecf20Sopenharmony_ci put_page(page); 23248c2ecf20Sopenharmony_ci 23258c2ecf20Sopenharmony_ci return copied; 23268c2ecf20Sopenharmony_ci} 23278c2ecf20Sopenharmony_ci 23288c2ecf20Sopenharmony_cistatic int fuse_launder_page(struct page *page) 23298c2ecf20Sopenharmony_ci{ 23308c2ecf20Sopenharmony_ci int err = 0; 23318c2ecf20Sopenharmony_ci if (clear_page_dirty_for_io(page)) { 23328c2ecf20Sopenharmony_ci struct inode *inode = page->mapping->host; 23338c2ecf20Sopenharmony_ci err = fuse_writepage_locked(page); 23348c2ecf20Sopenharmony_ci if (!err) 23358c2ecf20Sopenharmony_ci fuse_wait_on_page_writeback(inode, page->index); 23368c2ecf20Sopenharmony_ci } 23378c2ecf20Sopenharmony_ci return err; 23388c2ecf20Sopenharmony_ci} 23398c2ecf20Sopenharmony_ci 23408c2ecf20Sopenharmony_ci/* 23418c2ecf20Sopenharmony_ci * Write back dirty pages now, because there may not be any suitable 23428c2ecf20Sopenharmony_ci * open files later 23438c2ecf20Sopenharmony_ci */ 23448c2ecf20Sopenharmony_cistatic void fuse_vma_close(struct vm_area_struct *vma) 23458c2ecf20Sopenharmony_ci{ 23468c2ecf20Sopenharmony_ci filemap_write_and_wait(vma->vm_file->f_mapping); 23478c2ecf20Sopenharmony_ci} 23488c2ecf20Sopenharmony_ci 23498c2ecf20Sopenharmony_ci/* 23508c2ecf20Sopenharmony_ci * Wait for writeback against this page to complete before allowing it 23518c2ecf20Sopenharmony_ci * to be marked dirty again, and hence written back again, possibly 23528c2ecf20Sopenharmony_ci * before the previous writepage completed. 23538c2ecf20Sopenharmony_ci * 23548c2ecf20Sopenharmony_ci * Block here, instead of in ->writepage(), so that the userspace fs 23558c2ecf20Sopenharmony_ci * can only block processes actually operating on the filesystem. 23568c2ecf20Sopenharmony_ci * 23578c2ecf20Sopenharmony_ci * Otherwise unprivileged userspace fs would be able to block 23588c2ecf20Sopenharmony_ci * unrelated: 23598c2ecf20Sopenharmony_ci * 23608c2ecf20Sopenharmony_ci * - page migration 23618c2ecf20Sopenharmony_ci * - sync(2) 23628c2ecf20Sopenharmony_ci * - try_to_free_pages() with order > PAGE_ALLOC_COSTLY_ORDER 23638c2ecf20Sopenharmony_ci */ 23648c2ecf20Sopenharmony_cistatic vm_fault_t fuse_page_mkwrite(struct vm_fault *vmf) 23658c2ecf20Sopenharmony_ci{ 23668c2ecf20Sopenharmony_ci struct page *page = vmf->page; 23678c2ecf20Sopenharmony_ci struct inode *inode = file_inode(vmf->vma->vm_file); 23688c2ecf20Sopenharmony_ci 23698c2ecf20Sopenharmony_ci file_update_time(vmf->vma->vm_file); 23708c2ecf20Sopenharmony_ci lock_page(page); 23718c2ecf20Sopenharmony_ci if (page->mapping != inode->i_mapping) { 23728c2ecf20Sopenharmony_ci unlock_page(page); 23738c2ecf20Sopenharmony_ci return VM_FAULT_NOPAGE; 23748c2ecf20Sopenharmony_ci } 23758c2ecf20Sopenharmony_ci 23768c2ecf20Sopenharmony_ci fuse_wait_on_page_writeback(inode, page->index); 23778c2ecf20Sopenharmony_ci return VM_FAULT_LOCKED; 23788c2ecf20Sopenharmony_ci} 23798c2ecf20Sopenharmony_ci 23808c2ecf20Sopenharmony_cistatic const struct vm_operations_struct fuse_file_vm_ops = { 23818c2ecf20Sopenharmony_ci .close = fuse_vma_close, 23828c2ecf20Sopenharmony_ci .fault = filemap_fault, 23838c2ecf20Sopenharmony_ci .map_pages = filemap_map_pages, 23848c2ecf20Sopenharmony_ci .page_mkwrite = fuse_page_mkwrite, 23858c2ecf20Sopenharmony_ci}; 23868c2ecf20Sopenharmony_ci 23878c2ecf20Sopenharmony_cistatic int fuse_file_mmap(struct file *file, struct vm_area_struct *vma) 23888c2ecf20Sopenharmony_ci{ 23898c2ecf20Sopenharmony_ci struct fuse_file *ff = file->private_data; 23908c2ecf20Sopenharmony_ci 23918c2ecf20Sopenharmony_ci /* DAX mmap is superior to direct_io mmap */ 23928c2ecf20Sopenharmony_ci if (FUSE_IS_DAX(file_inode(file))) 23938c2ecf20Sopenharmony_ci return fuse_dax_mmap(file, vma); 23948c2ecf20Sopenharmony_ci 23958c2ecf20Sopenharmony_ci if (ff->open_flags & FOPEN_DIRECT_IO) { 23968c2ecf20Sopenharmony_ci /* Can't provide the coherency needed for MAP_SHARED */ 23978c2ecf20Sopenharmony_ci if (vma->vm_flags & VM_MAYSHARE) 23988c2ecf20Sopenharmony_ci return -ENODEV; 23998c2ecf20Sopenharmony_ci 24008c2ecf20Sopenharmony_ci invalidate_inode_pages2(file->f_mapping); 24018c2ecf20Sopenharmony_ci 24028c2ecf20Sopenharmony_ci return generic_file_mmap(file, vma); 24038c2ecf20Sopenharmony_ci } 24048c2ecf20Sopenharmony_ci 24058c2ecf20Sopenharmony_ci if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE)) 24068c2ecf20Sopenharmony_ci fuse_link_write_file(file); 24078c2ecf20Sopenharmony_ci 24088c2ecf20Sopenharmony_ci file_accessed(file); 24098c2ecf20Sopenharmony_ci vma->vm_ops = &fuse_file_vm_ops; 24108c2ecf20Sopenharmony_ci return 0; 24118c2ecf20Sopenharmony_ci} 24128c2ecf20Sopenharmony_ci 24138c2ecf20Sopenharmony_cistatic int convert_fuse_file_lock(struct fuse_conn *fc, 24148c2ecf20Sopenharmony_ci const struct fuse_file_lock *ffl, 24158c2ecf20Sopenharmony_ci struct file_lock *fl) 24168c2ecf20Sopenharmony_ci{ 24178c2ecf20Sopenharmony_ci switch (ffl->type) { 24188c2ecf20Sopenharmony_ci case F_UNLCK: 24198c2ecf20Sopenharmony_ci break; 24208c2ecf20Sopenharmony_ci 24218c2ecf20Sopenharmony_ci case F_RDLCK: 24228c2ecf20Sopenharmony_ci case F_WRLCK: 24238c2ecf20Sopenharmony_ci if (ffl->start > OFFSET_MAX || ffl->end > OFFSET_MAX || 24248c2ecf20Sopenharmony_ci ffl->end < ffl->start) 24258c2ecf20Sopenharmony_ci return -EIO; 24268c2ecf20Sopenharmony_ci 24278c2ecf20Sopenharmony_ci fl->fl_start = ffl->start; 24288c2ecf20Sopenharmony_ci fl->fl_end = ffl->end; 24298c2ecf20Sopenharmony_ci 24308c2ecf20Sopenharmony_ci /* 24318c2ecf20Sopenharmony_ci * Convert pid into init's pid namespace. The locks API will 24328c2ecf20Sopenharmony_ci * translate it into the caller's pid namespace. 24338c2ecf20Sopenharmony_ci */ 24348c2ecf20Sopenharmony_ci rcu_read_lock(); 24358c2ecf20Sopenharmony_ci fl->fl_pid = pid_nr_ns(find_pid_ns(ffl->pid, fc->pid_ns), &init_pid_ns); 24368c2ecf20Sopenharmony_ci rcu_read_unlock(); 24378c2ecf20Sopenharmony_ci break; 24388c2ecf20Sopenharmony_ci 24398c2ecf20Sopenharmony_ci default: 24408c2ecf20Sopenharmony_ci return -EIO; 24418c2ecf20Sopenharmony_ci } 24428c2ecf20Sopenharmony_ci fl->fl_type = ffl->type; 24438c2ecf20Sopenharmony_ci return 0; 24448c2ecf20Sopenharmony_ci} 24458c2ecf20Sopenharmony_ci 24468c2ecf20Sopenharmony_cistatic void fuse_lk_fill(struct fuse_args *args, struct file *file, 24478c2ecf20Sopenharmony_ci const struct file_lock *fl, int opcode, pid_t pid, 24488c2ecf20Sopenharmony_ci int flock, struct fuse_lk_in *inarg) 24498c2ecf20Sopenharmony_ci{ 24508c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 24518c2ecf20Sopenharmony_ci struct fuse_conn *fc = get_fuse_conn(inode); 24528c2ecf20Sopenharmony_ci struct fuse_file *ff = file->private_data; 24538c2ecf20Sopenharmony_ci 24548c2ecf20Sopenharmony_ci memset(inarg, 0, sizeof(*inarg)); 24558c2ecf20Sopenharmony_ci inarg->fh = ff->fh; 24568c2ecf20Sopenharmony_ci inarg->owner = fuse_lock_owner_id(fc, fl->fl_owner); 24578c2ecf20Sopenharmony_ci inarg->lk.start = fl->fl_start; 24588c2ecf20Sopenharmony_ci inarg->lk.end = fl->fl_end; 24598c2ecf20Sopenharmony_ci inarg->lk.type = fl->fl_type; 24608c2ecf20Sopenharmony_ci inarg->lk.pid = pid; 24618c2ecf20Sopenharmony_ci if (flock) 24628c2ecf20Sopenharmony_ci inarg->lk_flags |= FUSE_LK_FLOCK; 24638c2ecf20Sopenharmony_ci args->opcode = opcode; 24648c2ecf20Sopenharmony_ci args->nodeid = get_node_id(inode); 24658c2ecf20Sopenharmony_ci args->in_numargs = 1; 24668c2ecf20Sopenharmony_ci args->in_args[0].size = sizeof(*inarg); 24678c2ecf20Sopenharmony_ci args->in_args[0].value = inarg; 24688c2ecf20Sopenharmony_ci} 24698c2ecf20Sopenharmony_ci 24708c2ecf20Sopenharmony_cistatic int fuse_getlk(struct file *file, struct file_lock *fl) 24718c2ecf20Sopenharmony_ci{ 24728c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 24738c2ecf20Sopenharmony_ci struct fuse_mount *fm = get_fuse_mount(inode); 24748c2ecf20Sopenharmony_ci FUSE_ARGS(args); 24758c2ecf20Sopenharmony_ci struct fuse_lk_in inarg; 24768c2ecf20Sopenharmony_ci struct fuse_lk_out outarg; 24778c2ecf20Sopenharmony_ci int err; 24788c2ecf20Sopenharmony_ci 24798c2ecf20Sopenharmony_ci fuse_lk_fill(&args, file, fl, FUSE_GETLK, 0, 0, &inarg); 24808c2ecf20Sopenharmony_ci args.out_numargs = 1; 24818c2ecf20Sopenharmony_ci args.out_args[0].size = sizeof(outarg); 24828c2ecf20Sopenharmony_ci args.out_args[0].value = &outarg; 24838c2ecf20Sopenharmony_ci err = fuse_simple_request(fm, &args); 24848c2ecf20Sopenharmony_ci if (!err) 24858c2ecf20Sopenharmony_ci err = convert_fuse_file_lock(fm->fc, &outarg.lk, fl); 24868c2ecf20Sopenharmony_ci 24878c2ecf20Sopenharmony_ci return err; 24888c2ecf20Sopenharmony_ci} 24898c2ecf20Sopenharmony_ci 24908c2ecf20Sopenharmony_cistatic int fuse_setlk(struct file *file, struct file_lock *fl, int flock) 24918c2ecf20Sopenharmony_ci{ 24928c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 24938c2ecf20Sopenharmony_ci struct fuse_mount *fm = get_fuse_mount(inode); 24948c2ecf20Sopenharmony_ci FUSE_ARGS(args); 24958c2ecf20Sopenharmony_ci struct fuse_lk_in inarg; 24968c2ecf20Sopenharmony_ci int opcode = (fl->fl_flags & FL_SLEEP) ? FUSE_SETLKW : FUSE_SETLK; 24978c2ecf20Sopenharmony_ci struct pid *pid = fl->fl_type != F_UNLCK ? task_tgid(current) : NULL; 24988c2ecf20Sopenharmony_ci pid_t pid_nr = pid_nr_ns(pid, fm->fc->pid_ns); 24998c2ecf20Sopenharmony_ci int err; 25008c2ecf20Sopenharmony_ci 25018c2ecf20Sopenharmony_ci if (fl->fl_lmops && fl->fl_lmops->lm_grant) { 25028c2ecf20Sopenharmony_ci /* NLM needs asynchronous locks, which we don't support yet */ 25038c2ecf20Sopenharmony_ci return -ENOLCK; 25048c2ecf20Sopenharmony_ci } 25058c2ecf20Sopenharmony_ci 25068c2ecf20Sopenharmony_ci /* Unlock on close is handled by the flush method */ 25078c2ecf20Sopenharmony_ci if ((fl->fl_flags & FL_CLOSE_POSIX) == FL_CLOSE_POSIX) 25088c2ecf20Sopenharmony_ci return 0; 25098c2ecf20Sopenharmony_ci 25108c2ecf20Sopenharmony_ci fuse_lk_fill(&args, file, fl, opcode, pid_nr, flock, &inarg); 25118c2ecf20Sopenharmony_ci err = fuse_simple_request(fm, &args); 25128c2ecf20Sopenharmony_ci 25138c2ecf20Sopenharmony_ci /* locking is restartable */ 25148c2ecf20Sopenharmony_ci if (err == -EINTR) 25158c2ecf20Sopenharmony_ci err = -ERESTARTSYS; 25168c2ecf20Sopenharmony_ci 25178c2ecf20Sopenharmony_ci return err; 25188c2ecf20Sopenharmony_ci} 25198c2ecf20Sopenharmony_ci 25208c2ecf20Sopenharmony_cistatic int fuse_file_lock(struct file *file, int cmd, struct file_lock *fl) 25218c2ecf20Sopenharmony_ci{ 25228c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 25238c2ecf20Sopenharmony_ci struct fuse_conn *fc = get_fuse_conn(inode); 25248c2ecf20Sopenharmony_ci int err; 25258c2ecf20Sopenharmony_ci 25268c2ecf20Sopenharmony_ci if (cmd == F_CANCELLK) { 25278c2ecf20Sopenharmony_ci err = 0; 25288c2ecf20Sopenharmony_ci } else if (cmd == F_GETLK) { 25298c2ecf20Sopenharmony_ci if (fc->no_lock) { 25308c2ecf20Sopenharmony_ci posix_test_lock(file, fl); 25318c2ecf20Sopenharmony_ci err = 0; 25328c2ecf20Sopenharmony_ci } else 25338c2ecf20Sopenharmony_ci err = fuse_getlk(file, fl); 25348c2ecf20Sopenharmony_ci } else { 25358c2ecf20Sopenharmony_ci if (fc->no_lock) 25368c2ecf20Sopenharmony_ci err = posix_lock_file(file, fl, NULL); 25378c2ecf20Sopenharmony_ci else 25388c2ecf20Sopenharmony_ci err = fuse_setlk(file, fl, 0); 25398c2ecf20Sopenharmony_ci } 25408c2ecf20Sopenharmony_ci return err; 25418c2ecf20Sopenharmony_ci} 25428c2ecf20Sopenharmony_ci 25438c2ecf20Sopenharmony_cistatic int fuse_file_flock(struct file *file, int cmd, struct file_lock *fl) 25448c2ecf20Sopenharmony_ci{ 25458c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 25468c2ecf20Sopenharmony_ci struct fuse_conn *fc = get_fuse_conn(inode); 25478c2ecf20Sopenharmony_ci int err; 25488c2ecf20Sopenharmony_ci 25498c2ecf20Sopenharmony_ci if (fc->no_flock) { 25508c2ecf20Sopenharmony_ci err = locks_lock_file_wait(file, fl); 25518c2ecf20Sopenharmony_ci } else { 25528c2ecf20Sopenharmony_ci struct fuse_file *ff = file->private_data; 25538c2ecf20Sopenharmony_ci 25548c2ecf20Sopenharmony_ci /* emulate flock with POSIX locks */ 25558c2ecf20Sopenharmony_ci ff->flock = true; 25568c2ecf20Sopenharmony_ci err = fuse_setlk(file, fl, 1); 25578c2ecf20Sopenharmony_ci } 25588c2ecf20Sopenharmony_ci 25598c2ecf20Sopenharmony_ci return err; 25608c2ecf20Sopenharmony_ci} 25618c2ecf20Sopenharmony_ci 25628c2ecf20Sopenharmony_cistatic sector_t fuse_bmap(struct address_space *mapping, sector_t block) 25638c2ecf20Sopenharmony_ci{ 25648c2ecf20Sopenharmony_ci struct inode *inode = mapping->host; 25658c2ecf20Sopenharmony_ci struct fuse_mount *fm = get_fuse_mount(inode); 25668c2ecf20Sopenharmony_ci FUSE_ARGS(args); 25678c2ecf20Sopenharmony_ci struct fuse_bmap_in inarg; 25688c2ecf20Sopenharmony_ci struct fuse_bmap_out outarg; 25698c2ecf20Sopenharmony_ci int err; 25708c2ecf20Sopenharmony_ci 25718c2ecf20Sopenharmony_ci if (!inode->i_sb->s_bdev || fm->fc->no_bmap) 25728c2ecf20Sopenharmony_ci return 0; 25738c2ecf20Sopenharmony_ci 25748c2ecf20Sopenharmony_ci memset(&inarg, 0, sizeof(inarg)); 25758c2ecf20Sopenharmony_ci inarg.block = block; 25768c2ecf20Sopenharmony_ci inarg.blocksize = inode->i_sb->s_blocksize; 25778c2ecf20Sopenharmony_ci args.opcode = FUSE_BMAP; 25788c2ecf20Sopenharmony_ci args.nodeid = get_node_id(inode); 25798c2ecf20Sopenharmony_ci args.in_numargs = 1; 25808c2ecf20Sopenharmony_ci args.in_args[0].size = sizeof(inarg); 25818c2ecf20Sopenharmony_ci args.in_args[0].value = &inarg; 25828c2ecf20Sopenharmony_ci args.out_numargs = 1; 25838c2ecf20Sopenharmony_ci args.out_args[0].size = sizeof(outarg); 25848c2ecf20Sopenharmony_ci args.out_args[0].value = &outarg; 25858c2ecf20Sopenharmony_ci err = fuse_simple_request(fm, &args); 25868c2ecf20Sopenharmony_ci if (err == -ENOSYS) 25878c2ecf20Sopenharmony_ci fm->fc->no_bmap = 1; 25888c2ecf20Sopenharmony_ci 25898c2ecf20Sopenharmony_ci return err ? 0 : outarg.block; 25908c2ecf20Sopenharmony_ci} 25918c2ecf20Sopenharmony_ci 25928c2ecf20Sopenharmony_cistatic loff_t fuse_lseek(struct file *file, loff_t offset, int whence) 25938c2ecf20Sopenharmony_ci{ 25948c2ecf20Sopenharmony_ci struct inode *inode = file->f_mapping->host; 25958c2ecf20Sopenharmony_ci struct fuse_mount *fm = get_fuse_mount(inode); 25968c2ecf20Sopenharmony_ci struct fuse_file *ff = file->private_data; 25978c2ecf20Sopenharmony_ci FUSE_ARGS(args); 25988c2ecf20Sopenharmony_ci struct fuse_lseek_in inarg = { 25998c2ecf20Sopenharmony_ci .fh = ff->fh, 26008c2ecf20Sopenharmony_ci .offset = offset, 26018c2ecf20Sopenharmony_ci .whence = whence 26028c2ecf20Sopenharmony_ci }; 26038c2ecf20Sopenharmony_ci struct fuse_lseek_out outarg; 26048c2ecf20Sopenharmony_ci int err; 26058c2ecf20Sopenharmony_ci 26068c2ecf20Sopenharmony_ci if (fm->fc->no_lseek) 26078c2ecf20Sopenharmony_ci goto fallback; 26088c2ecf20Sopenharmony_ci 26098c2ecf20Sopenharmony_ci args.opcode = FUSE_LSEEK; 26108c2ecf20Sopenharmony_ci args.nodeid = ff->nodeid; 26118c2ecf20Sopenharmony_ci args.in_numargs = 1; 26128c2ecf20Sopenharmony_ci args.in_args[0].size = sizeof(inarg); 26138c2ecf20Sopenharmony_ci args.in_args[0].value = &inarg; 26148c2ecf20Sopenharmony_ci args.out_numargs = 1; 26158c2ecf20Sopenharmony_ci args.out_args[0].size = sizeof(outarg); 26168c2ecf20Sopenharmony_ci args.out_args[0].value = &outarg; 26178c2ecf20Sopenharmony_ci err = fuse_simple_request(fm, &args); 26188c2ecf20Sopenharmony_ci if (err) { 26198c2ecf20Sopenharmony_ci if (err == -ENOSYS) { 26208c2ecf20Sopenharmony_ci fm->fc->no_lseek = 1; 26218c2ecf20Sopenharmony_ci goto fallback; 26228c2ecf20Sopenharmony_ci } 26238c2ecf20Sopenharmony_ci return err; 26248c2ecf20Sopenharmony_ci } 26258c2ecf20Sopenharmony_ci 26268c2ecf20Sopenharmony_ci return vfs_setpos(file, outarg.offset, inode->i_sb->s_maxbytes); 26278c2ecf20Sopenharmony_ci 26288c2ecf20Sopenharmony_cifallback: 26298c2ecf20Sopenharmony_ci err = fuse_update_attributes(inode, file); 26308c2ecf20Sopenharmony_ci if (!err) 26318c2ecf20Sopenharmony_ci return generic_file_llseek(file, offset, whence); 26328c2ecf20Sopenharmony_ci else 26338c2ecf20Sopenharmony_ci return err; 26348c2ecf20Sopenharmony_ci} 26358c2ecf20Sopenharmony_ci 26368c2ecf20Sopenharmony_cistatic loff_t fuse_file_llseek(struct file *file, loff_t offset, int whence) 26378c2ecf20Sopenharmony_ci{ 26388c2ecf20Sopenharmony_ci loff_t retval; 26398c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 26408c2ecf20Sopenharmony_ci 26418c2ecf20Sopenharmony_ci switch (whence) { 26428c2ecf20Sopenharmony_ci case SEEK_SET: 26438c2ecf20Sopenharmony_ci case SEEK_CUR: 26448c2ecf20Sopenharmony_ci /* No i_mutex protection necessary for SEEK_CUR and SEEK_SET */ 26458c2ecf20Sopenharmony_ci retval = generic_file_llseek(file, offset, whence); 26468c2ecf20Sopenharmony_ci break; 26478c2ecf20Sopenharmony_ci case SEEK_END: 26488c2ecf20Sopenharmony_ci inode_lock(inode); 26498c2ecf20Sopenharmony_ci retval = fuse_update_attributes(inode, file); 26508c2ecf20Sopenharmony_ci if (!retval) 26518c2ecf20Sopenharmony_ci retval = generic_file_llseek(file, offset, whence); 26528c2ecf20Sopenharmony_ci inode_unlock(inode); 26538c2ecf20Sopenharmony_ci break; 26548c2ecf20Sopenharmony_ci case SEEK_HOLE: 26558c2ecf20Sopenharmony_ci case SEEK_DATA: 26568c2ecf20Sopenharmony_ci inode_lock(inode); 26578c2ecf20Sopenharmony_ci retval = fuse_lseek(file, offset, whence); 26588c2ecf20Sopenharmony_ci inode_unlock(inode); 26598c2ecf20Sopenharmony_ci break; 26608c2ecf20Sopenharmony_ci default: 26618c2ecf20Sopenharmony_ci retval = -EINVAL; 26628c2ecf20Sopenharmony_ci } 26638c2ecf20Sopenharmony_ci 26648c2ecf20Sopenharmony_ci return retval; 26658c2ecf20Sopenharmony_ci} 26668c2ecf20Sopenharmony_ci 26678c2ecf20Sopenharmony_ci/* 26688c2ecf20Sopenharmony_ci * CUSE servers compiled on 32bit broke on 64bit kernels because the 26698c2ecf20Sopenharmony_ci * ABI was defined to be 'struct iovec' which is different on 32bit 26708c2ecf20Sopenharmony_ci * and 64bit. Fortunately we can determine which structure the server 26718c2ecf20Sopenharmony_ci * used from the size of the reply. 26728c2ecf20Sopenharmony_ci */ 26738c2ecf20Sopenharmony_cistatic int fuse_copy_ioctl_iovec_old(struct iovec *dst, void *src, 26748c2ecf20Sopenharmony_ci size_t transferred, unsigned count, 26758c2ecf20Sopenharmony_ci bool is_compat) 26768c2ecf20Sopenharmony_ci{ 26778c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 26788c2ecf20Sopenharmony_ci if (count * sizeof(struct compat_iovec) == transferred) { 26798c2ecf20Sopenharmony_ci struct compat_iovec *ciov = src; 26808c2ecf20Sopenharmony_ci unsigned i; 26818c2ecf20Sopenharmony_ci 26828c2ecf20Sopenharmony_ci /* 26838c2ecf20Sopenharmony_ci * With this interface a 32bit server cannot support 26848c2ecf20Sopenharmony_ci * non-compat (i.e. ones coming from 64bit apps) ioctl 26858c2ecf20Sopenharmony_ci * requests 26868c2ecf20Sopenharmony_ci */ 26878c2ecf20Sopenharmony_ci if (!is_compat) 26888c2ecf20Sopenharmony_ci return -EINVAL; 26898c2ecf20Sopenharmony_ci 26908c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 26918c2ecf20Sopenharmony_ci dst[i].iov_base = compat_ptr(ciov[i].iov_base); 26928c2ecf20Sopenharmony_ci dst[i].iov_len = ciov[i].iov_len; 26938c2ecf20Sopenharmony_ci } 26948c2ecf20Sopenharmony_ci return 0; 26958c2ecf20Sopenharmony_ci } 26968c2ecf20Sopenharmony_ci#endif 26978c2ecf20Sopenharmony_ci 26988c2ecf20Sopenharmony_ci if (count * sizeof(struct iovec) != transferred) 26998c2ecf20Sopenharmony_ci return -EIO; 27008c2ecf20Sopenharmony_ci 27018c2ecf20Sopenharmony_ci memcpy(dst, src, transferred); 27028c2ecf20Sopenharmony_ci return 0; 27038c2ecf20Sopenharmony_ci} 27048c2ecf20Sopenharmony_ci 27058c2ecf20Sopenharmony_ci/* Make sure iov_length() won't overflow */ 27068c2ecf20Sopenharmony_cistatic int fuse_verify_ioctl_iov(struct fuse_conn *fc, struct iovec *iov, 27078c2ecf20Sopenharmony_ci size_t count) 27088c2ecf20Sopenharmony_ci{ 27098c2ecf20Sopenharmony_ci size_t n; 27108c2ecf20Sopenharmony_ci u32 max = fc->max_pages << PAGE_SHIFT; 27118c2ecf20Sopenharmony_ci 27128c2ecf20Sopenharmony_ci for (n = 0; n < count; n++, iov++) { 27138c2ecf20Sopenharmony_ci if (iov->iov_len > (size_t) max) 27148c2ecf20Sopenharmony_ci return -ENOMEM; 27158c2ecf20Sopenharmony_ci max -= iov->iov_len; 27168c2ecf20Sopenharmony_ci } 27178c2ecf20Sopenharmony_ci return 0; 27188c2ecf20Sopenharmony_ci} 27198c2ecf20Sopenharmony_ci 27208c2ecf20Sopenharmony_cistatic int fuse_copy_ioctl_iovec(struct fuse_conn *fc, struct iovec *dst, 27218c2ecf20Sopenharmony_ci void *src, size_t transferred, unsigned count, 27228c2ecf20Sopenharmony_ci bool is_compat) 27238c2ecf20Sopenharmony_ci{ 27248c2ecf20Sopenharmony_ci unsigned i; 27258c2ecf20Sopenharmony_ci struct fuse_ioctl_iovec *fiov = src; 27268c2ecf20Sopenharmony_ci 27278c2ecf20Sopenharmony_ci if (fc->minor < 16) { 27288c2ecf20Sopenharmony_ci return fuse_copy_ioctl_iovec_old(dst, src, transferred, 27298c2ecf20Sopenharmony_ci count, is_compat); 27308c2ecf20Sopenharmony_ci } 27318c2ecf20Sopenharmony_ci 27328c2ecf20Sopenharmony_ci if (count * sizeof(struct fuse_ioctl_iovec) != transferred) 27338c2ecf20Sopenharmony_ci return -EIO; 27348c2ecf20Sopenharmony_ci 27358c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 27368c2ecf20Sopenharmony_ci /* Did the server supply an inappropriate value? */ 27378c2ecf20Sopenharmony_ci if (fiov[i].base != (unsigned long) fiov[i].base || 27388c2ecf20Sopenharmony_ci fiov[i].len != (unsigned long) fiov[i].len) 27398c2ecf20Sopenharmony_ci return -EIO; 27408c2ecf20Sopenharmony_ci 27418c2ecf20Sopenharmony_ci dst[i].iov_base = (void __user *) (unsigned long) fiov[i].base; 27428c2ecf20Sopenharmony_ci dst[i].iov_len = (size_t) fiov[i].len; 27438c2ecf20Sopenharmony_ci 27448c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 27458c2ecf20Sopenharmony_ci if (is_compat && 27468c2ecf20Sopenharmony_ci (ptr_to_compat(dst[i].iov_base) != fiov[i].base || 27478c2ecf20Sopenharmony_ci (compat_size_t) dst[i].iov_len != fiov[i].len)) 27488c2ecf20Sopenharmony_ci return -EIO; 27498c2ecf20Sopenharmony_ci#endif 27508c2ecf20Sopenharmony_ci } 27518c2ecf20Sopenharmony_ci 27528c2ecf20Sopenharmony_ci return 0; 27538c2ecf20Sopenharmony_ci} 27548c2ecf20Sopenharmony_ci 27558c2ecf20Sopenharmony_ci 27568c2ecf20Sopenharmony_ci/* 27578c2ecf20Sopenharmony_ci * For ioctls, there is no generic way to determine how much memory 27588c2ecf20Sopenharmony_ci * needs to be read and/or written. Furthermore, ioctls are allowed 27598c2ecf20Sopenharmony_ci * to dereference the passed pointer, so the parameter requires deep 27608c2ecf20Sopenharmony_ci * copying but FUSE has no idea whatsoever about what to copy in or 27618c2ecf20Sopenharmony_ci * out. 27628c2ecf20Sopenharmony_ci * 27638c2ecf20Sopenharmony_ci * This is solved by allowing FUSE server to retry ioctl with 27648c2ecf20Sopenharmony_ci * necessary in/out iovecs. Let's assume the ioctl implementation 27658c2ecf20Sopenharmony_ci * needs to read in the following structure. 27668c2ecf20Sopenharmony_ci * 27678c2ecf20Sopenharmony_ci * struct a { 27688c2ecf20Sopenharmony_ci * char *buf; 27698c2ecf20Sopenharmony_ci * size_t buflen; 27708c2ecf20Sopenharmony_ci * } 27718c2ecf20Sopenharmony_ci * 27728c2ecf20Sopenharmony_ci * On the first callout to FUSE server, inarg->in_size and 27738c2ecf20Sopenharmony_ci * inarg->out_size will be NULL; then, the server completes the ioctl 27748c2ecf20Sopenharmony_ci * with FUSE_IOCTL_RETRY set in out->flags, out->in_iovs set to 1 and 27758c2ecf20Sopenharmony_ci * the actual iov array to 27768c2ecf20Sopenharmony_ci * 27778c2ecf20Sopenharmony_ci * { { .iov_base = inarg.arg, .iov_len = sizeof(struct a) } } 27788c2ecf20Sopenharmony_ci * 27798c2ecf20Sopenharmony_ci * which tells FUSE to copy in the requested area and retry the ioctl. 27808c2ecf20Sopenharmony_ci * On the second round, the server has access to the structure and 27818c2ecf20Sopenharmony_ci * from that it can tell what to look for next, so on the invocation, 27828c2ecf20Sopenharmony_ci * it sets FUSE_IOCTL_RETRY, out->in_iovs to 2 and iov array to 27838c2ecf20Sopenharmony_ci * 27848c2ecf20Sopenharmony_ci * { { .iov_base = inarg.arg, .iov_len = sizeof(struct a) }, 27858c2ecf20Sopenharmony_ci * { .iov_base = a.buf, .iov_len = a.buflen } } 27868c2ecf20Sopenharmony_ci * 27878c2ecf20Sopenharmony_ci * FUSE will copy both struct a and the pointed buffer from the 27888c2ecf20Sopenharmony_ci * process doing the ioctl and retry ioctl with both struct a and the 27898c2ecf20Sopenharmony_ci * buffer. 27908c2ecf20Sopenharmony_ci * 27918c2ecf20Sopenharmony_ci * This time, FUSE server has everything it needs and completes ioctl 27928c2ecf20Sopenharmony_ci * without FUSE_IOCTL_RETRY which finishes the ioctl call. 27938c2ecf20Sopenharmony_ci * 27948c2ecf20Sopenharmony_ci * Copying data out works the same way. 27958c2ecf20Sopenharmony_ci * 27968c2ecf20Sopenharmony_ci * Note that if FUSE_IOCTL_UNRESTRICTED is clear, the kernel 27978c2ecf20Sopenharmony_ci * automatically initializes in and out iovs by decoding @cmd with 27988c2ecf20Sopenharmony_ci * _IOC_* macros and the server is not allowed to request RETRY. This 27998c2ecf20Sopenharmony_ci * limits ioctl data transfers to well-formed ioctls and is the forced 28008c2ecf20Sopenharmony_ci * behavior for all FUSE servers. 28018c2ecf20Sopenharmony_ci */ 28028c2ecf20Sopenharmony_cilong fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg, 28038c2ecf20Sopenharmony_ci unsigned int flags) 28048c2ecf20Sopenharmony_ci{ 28058c2ecf20Sopenharmony_ci struct fuse_file *ff = file->private_data; 28068c2ecf20Sopenharmony_ci struct fuse_mount *fm = ff->fm; 28078c2ecf20Sopenharmony_ci struct fuse_ioctl_in inarg = { 28088c2ecf20Sopenharmony_ci .fh = ff->fh, 28098c2ecf20Sopenharmony_ci .cmd = cmd, 28108c2ecf20Sopenharmony_ci .arg = arg, 28118c2ecf20Sopenharmony_ci .flags = flags 28128c2ecf20Sopenharmony_ci }; 28138c2ecf20Sopenharmony_ci struct fuse_ioctl_out outarg; 28148c2ecf20Sopenharmony_ci struct iovec *iov_page = NULL; 28158c2ecf20Sopenharmony_ci struct iovec *in_iov = NULL, *out_iov = NULL; 28168c2ecf20Sopenharmony_ci unsigned int in_iovs = 0, out_iovs = 0, max_pages; 28178c2ecf20Sopenharmony_ci size_t in_size, out_size, c; 28188c2ecf20Sopenharmony_ci ssize_t transferred; 28198c2ecf20Sopenharmony_ci int err, i; 28208c2ecf20Sopenharmony_ci struct iov_iter ii; 28218c2ecf20Sopenharmony_ci struct fuse_args_pages ap = {}; 28228c2ecf20Sopenharmony_ci 28238c2ecf20Sopenharmony_ci#if BITS_PER_LONG == 32 28248c2ecf20Sopenharmony_ci inarg.flags |= FUSE_IOCTL_32BIT; 28258c2ecf20Sopenharmony_ci#else 28268c2ecf20Sopenharmony_ci if (flags & FUSE_IOCTL_COMPAT) { 28278c2ecf20Sopenharmony_ci inarg.flags |= FUSE_IOCTL_32BIT; 28288c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_X32 28298c2ecf20Sopenharmony_ci if (in_x32_syscall()) 28308c2ecf20Sopenharmony_ci inarg.flags |= FUSE_IOCTL_COMPAT_X32; 28318c2ecf20Sopenharmony_ci#endif 28328c2ecf20Sopenharmony_ci } 28338c2ecf20Sopenharmony_ci#endif 28348c2ecf20Sopenharmony_ci 28358c2ecf20Sopenharmony_ci /* assume all the iovs returned by client always fits in a page */ 28368c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct fuse_ioctl_iovec) * FUSE_IOCTL_MAX_IOV > PAGE_SIZE); 28378c2ecf20Sopenharmony_ci 28388c2ecf20Sopenharmony_ci err = -ENOMEM; 28398c2ecf20Sopenharmony_ci ap.pages = fuse_pages_alloc(fm->fc->max_pages, GFP_KERNEL, &ap.descs); 28408c2ecf20Sopenharmony_ci iov_page = (struct iovec *) __get_free_page(GFP_KERNEL); 28418c2ecf20Sopenharmony_ci if (!ap.pages || !iov_page) 28428c2ecf20Sopenharmony_ci goto out; 28438c2ecf20Sopenharmony_ci 28448c2ecf20Sopenharmony_ci fuse_page_descs_length_init(ap.descs, 0, fm->fc->max_pages); 28458c2ecf20Sopenharmony_ci 28468c2ecf20Sopenharmony_ci /* 28478c2ecf20Sopenharmony_ci * If restricted, initialize IO parameters as encoded in @cmd. 28488c2ecf20Sopenharmony_ci * RETRY from server is not allowed. 28498c2ecf20Sopenharmony_ci */ 28508c2ecf20Sopenharmony_ci if (!(flags & FUSE_IOCTL_UNRESTRICTED)) { 28518c2ecf20Sopenharmony_ci struct iovec *iov = iov_page; 28528c2ecf20Sopenharmony_ci 28538c2ecf20Sopenharmony_ci iov->iov_base = (void __user *)arg; 28548c2ecf20Sopenharmony_ci 28558c2ecf20Sopenharmony_ci switch (cmd) { 28568c2ecf20Sopenharmony_ci case FS_IOC_GETFLAGS: 28578c2ecf20Sopenharmony_ci case FS_IOC_SETFLAGS: 28588c2ecf20Sopenharmony_ci iov->iov_len = sizeof(int); 28598c2ecf20Sopenharmony_ci break; 28608c2ecf20Sopenharmony_ci default: 28618c2ecf20Sopenharmony_ci iov->iov_len = _IOC_SIZE(cmd); 28628c2ecf20Sopenharmony_ci break; 28638c2ecf20Sopenharmony_ci } 28648c2ecf20Sopenharmony_ci 28658c2ecf20Sopenharmony_ci if (_IOC_DIR(cmd) & _IOC_WRITE) { 28668c2ecf20Sopenharmony_ci in_iov = iov; 28678c2ecf20Sopenharmony_ci in_iovs = 1; 28688c2ecf20Sopenharmony_ci } 28698c2ecf20Sopenharmony_ci 28708c2ecf20Sopenharmony_ci if (_IOC_DIR(cmd) & _IOC_READ) { 28718c2ecf20Sopenharmony_ci out_iov = iov; 28728c2ecf20Sopenharmony_ci out_iovs = 1; 28738c2ecf20Sopenharmony_ci } 28748c2ecf20Sopenharmony_ci } 28758c2ecf20Sopenharmony_ci 28768c2ecf20Sopenharmony_ci retry: 28778c2ecf20Sopenharmony_ci inarg.in_size = in_size = iov_length(in_iov, in_iovs); 28788c2ecf20Sopenharmony_ci inarg.out_size = out_size = iov_length(out_iov, out_iovs); 28798c2ecf20Sopenharmony_ci 28808c2ecf20Sopenharmony_ci /* 28818c2ecf20Sopenharmony_ci * Out data can be used either for actual out data or iovs, 28828c2ecf20Sopenharmony_ci * make sure there always is at least one page. 28838c2ecf20Sopenharmony_ci */ 28848c2ecf20Sopenharmony_ci out_size = max_t(size_t, out_size, PAGE_SIZE); 28858c2ecf20Sopenharmony_ci max_pages = DIV_ROUND_UP(max(in_size, out_size), PAGE_SIZE); 28868c2ecf20Sopenharmony_ci 28878c2ecf20Sopenharmony_ci /* make sure there are enough buffer pages and init request with them */ 28888c2ecf20Sopenharmony_ci err = -ENOMEM; 28898c2ecf20Sopenharmony_ci if (max_pages > fm->fc->max_pages) 28908c2ecf20Sopenharmony_ci goto out; 28918c2ecf20Sopenharmony_ci while (ap.num_pages < max_pages) { 28928c2ecf20Sopenharmony_ci ap.pages[ap.num_pages] = alloc_page(GFP_KERNEL | __GFP_HIGHMEM); 28938c2ecf20Sopenharmony_ci if (!ap.pages[ap.num_pages]) 28948c2ecf20Sopenharmony_ci goto out; 28958c2ecf20Sopenharmony_ci ap.num_pages++; 28968c2ecf20Sopenharmony_ci } 28978c2ecf20Sopenharmony_ci 28988c2ecf20Sopenharmony_ci 28998c2ecf20Sopenharmony_ci /* okay, let's send it to the client */ 29008c2ecf20Sopenharmony_ci ap.args.opcode = FUSE_IOCTL; 29018c2ecf20Sopenharmony_ci ap.args.nodeid = ff->nodeid; 29028c2ecf20Sopenharmony_ci ap.args.in_numargs = 1; 29038c2ecf20Sopenharmony_ci ap.args.in_args[0].size = sizeof(inarg); 29048c2ecf20Sopenharmony_ci ap.args.in_args[0].value = &inarg; 29058c2ecf20Sopenharmony_ci if (in_size) { 29068c2ecf20Sopenharmony_ci ap.args.in_numargs++; 29078c2ecf20Sopenharmony_ci ap.args.in_args[1].size = in_size; 29088c2ecf20Sopenharmony_ci ap.args.in_pages = true; 29098c2ecf20Sopenharmony_ci 29108c2ecf20Sopenharmony_ci err = -EFAULT; 29118c2ecf20Sopenharmony_ci iov_iter_init(&ii, WRITE, in_iov, in_iovs, in_size); 29128c2ecf20Sopenharmony_ci for (i = 0; iov_iter_count(&ii) && !WARN_ON(i >= ap.num_pages); i++) { 29138c2ecf20Sopenharmony_ci c = copy_page_from_iter(ap.pages[i], 0, PAGE_SIZE, &ii); 29148c2ecf20Sopenharmony_ci if (c != PAGE_SIZE && iov_iter_count(&ii)) 29158c2ecf20Sopenharmony_ci goto out; 29168c2ecf20Sopenharmony_ci } 29178c2ecf20Sopenharmony_ci } 29188c2ecf20Sopenharmony_ci 29198c2ecf20Sopenharmony_ci ap.args.out_numargs = 2; 29208c2ecf20Sopenharmony_ci ap.args.out_args[0].size = sizeof(outarg); 29218c2ecf20Sopenharmony_ci ap.args.out_args[0].value = &outarg; 29228c2ecf20Sopenharmony_ci ap.args.out_args[1].size = out_size; 29238c2ecf20Sopenharmony_ci ap.args.out_pages = true; 29248c2ecf20Sopenharmony_ci ap.args.out_argvar = true; 29258c2ecf20Sopenharmony_ci 29268c2ecf20Sopenharmony_ci transferred = fuse_simple_request(fm, &ap.args); 29278c2ecf20Sopenharmony_ci err = transferred; 29288c2ecf20Sopenharmony_ci if (transferred < 0) 29298c2ecf20Sopenharmony_ci goto out; 29308c2ecf20Sopenharmony_ci 29318c2ecf20Sopenharmony_ci /* did it ask for retry? */ 29328c2ecf20Sopenharmony_ci if (outarg.flags & FUSE_IOCTL_RETRY) { 29338c2ecf20Sopenharmony_ci void *vaddr; 29348c2ecf20Sopenharmony_ci 29358c2ecf20Sopenharmony_ci /* no retry if in restricted mode */ 29368c2ecf20Sopenharmony_ci err = -EIO; 29378c2ecf20Sopenharmony_ci if (!(flags & FUSE_IOCTL_UNRESTRICTED)) 29388c2ecf20Sopenharmony_ci goto out; 29398c2ecf20Sopenharmony_ci 29408c2ecf20Sopenharmony_ci in_iovs = outarg.in_iovs; 29418c2ecf20Sopenharmony_ci out_iovs = outarg.out_iovs; 29428c2ecf20Sopenharmony_ci 29438c2ecf20Sopenharmony_ci /* 29448c2ecf20Sopenharmony_ci * Make sure things are in boundary, separate checks 29458c2ecf20Sopenharmony_ci * are to protect against overflow. 29468c2ecf20Sopenharmony_ci */ 29478c2ecf20Sopenharmony_ci err = -ENOMEM; 29488c2ecf20Sopenharmony_ci if (in_iovs > FUSE_IOCTL_MAX_IOV || 29498c2ecf20Sopenharmony_ci out_iovs > FUSE_IOCTL_MAX_IOV || 29508c2ecf20Sopenharmony_ci in_iovs + out_iovs > FUSE_IOCTL_MAX_IOV) 29518c2ecf20Sopenharmony_ci goto out; 29528c2ecf20Sopenharmony_ci 29538c2ecf20Sopenharmony_ci vaddr = kmap_atomic(ap.pages[0]); 29548c2ecf20Sopenharmony_ci err = fuse_copy_ioctl_iovec(fm->fc, iov_page, vaddr, 29558c2ecf20Sopenharmony_ci transferred, in_iovs + out_iovs, 29568c2ecf20Sopenharmony_ci (flags & FUSE_IOCTL_COMPAT) != 0); 29578c2ecf20Sopenharmony_ci kunmap_atomic(vaddr); 29588c2ecf20Sopenharmony_ci if (err) 29598c2ecf20Sopenharmony_ci goto out; 29608c2ecf20Sopenharmony_ci 29618c2ecf20Sopenharmony_ci in_iov = iov_page; 29628c2ecf20Sopenharmony_ci out_iov = in_iov + in_iovs; 29638c2ecf20Sopenharmony_ci 29648c2ecf20Sopenharmony_ci err = fuse_verify_ioctl_iov(fm->fc, in_iov, in_iovs); 29658c2ecf20Sopenharmony_ci if (err) 29668c2ecf20Sopenharmony_ci goto out; 29678c2ecf20Sopenharmony_ci 29688c2ecf20Sopenharmony_ci err = fuse_verify_ioctl_iov(fm->fc, out_iov, out_iovs); 29698c2ecf20Sopenharmony_ci if (err) 29708c2ecf20Sopenharmony_ci goto out; 29718c2ecf20Sopenharmony_ci 29728c2ecf20Sopenharmony_ci goto retry; 29738c2ecf20Sopenharmony_ci } 29748c2ecf20Sopenharmony_ci 29758c2ecf20Sopenharmony_ci err = -EIO; 29768c2ecf20Sopenharmony_ci if (transferred > inarg.out_size) 29778c2ecf20Sopenharmony_ci goto out; 29788c2ecf20Sopenharmony_ci 29798c2ecf20Sopenharmony_ci err = -EFAULT; 29808c2ecf20Sopenharmony_ci iov_iter_init(&ii, READ, out_iov, out_iovs, transferred); 29818c2ecf20Sopenharmony_ci for (i = 0; iov_iter_count(&ii) && !WARN_ON(i >= ap.num_pages); i++) { 29828c2ecf20Sopenharmony_ci c = copy_page_to_iter(ap.pages[i], 0, PAGE_SIZE, &ii); 29838c2ecf20Sopenharmony_ci if (c != PAGE_SIZE && iov_iter_count(&ii)) 29848c2ecf20Sopenharmony_ci goto out; 29858c2ecf20Sopenharmony_ci } 29868c2ecf20Sopenharmony_ci err = 0; 29878c2ecf20Sopenharmony_ci out: 29888c2ecf20Sopenharmony_ci free_page((unsigned long) iov_page); 29898c2ecf20Sopenharmony_ci while (ap.num_pages) 29908c2ecf20Sopenharmony_ci __free_page(ap.pages[--ap.num_pages]); 29918c2ecf20Sopenharmony_ci kfree(ap.pages); 29928c2ecf20Sopenharmony_ci 29938c2ecf20Sopenharmony_ci return err ? err : outarg.result; 29948c2ecf20Sopenharmony_ci} 29958c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(fuse_do_ioctl); 29968c2ecf20Sopenharmony_ci 29978c2ecf20Sopenharmony_cilong fuse_ioctl_common(struct file *file, unsigned int cmd, 29988c2ecf20Sopenharmony_ci unsigned long arg, unsigned int flags) 29998c2ecf20Sopenharmony_ci{ 30008c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 30018c2ecf20Sopenharmony_ci struct fuse_conn *fc = get_fuse_conn(inode); 30028c2ecf20Sopenharmony_ci 30038c2ecf20Sopenharmony_ci if (!fuse_allow_current_process(fc)) 30048c2ecf20Sopenharmony_ci return -EACCES; 30058c2ecf20Sopenharmony_ci 30068c2ecf20Sopenharmony_ci if (fuse_is_bad(inode)) 30078c2ecf20Sopenharmony_ci return -EIO; 30088c2ecf20Sopenharmony_ci 30098c2ecf20Sopenharmony_ci return fuse_do_ioctl(file, cmd, arg, flags); 30108c2ecf20Sopenharmony_ci} 30118c2ecf20Sopenharmony_ci 30128c2ecf20Sopenharmony_cistatic long fuse_file_ioctl(struct file *file, unsigned int cmd, 30138c2ecf20Sopenharmony_ci unsigned long arg) 30148c2ecf20Sopenharmony_ci{ 30158c2ecf20Sopenharmony_ci return fuse_ioctl_common(file, cmd, arg, 0); 30168c2ecf20Sopenharmony_ci} 30178c2ecf20Sopenharmony_ci 30188c2ecf20Sopenharmony_cistatic long fuse_file_compat_ioctl(struct file *file, unsigned int cmd, 30198c2ecf20Sopenharmony_ci unsigned long arg) 30208c2ecf20Sopenharmony_ci{ 30218c2ecf20Sopenharmony_ci return fuse_ioctl_common(file, cmd, arg, FUSE_IOCTL_COMPAT); 30228c2ecf20Sopenharmony_ci} 30238c2ecf20Sopenharmony_ci 30248c2ecf20Sopenharmony_ci/* 30258c2ecf20Sopenharmony_ci * All files which have been polled are linked to RB tree 30268c2ecf20Sopenharmony_ci * fuse_conn->polled_files which is indexed by kh. Walk the tree and 30278c2ecf20Sopenharmony_ci * find the matching one. 30288c2ecf20Sopenharmony_ci */ 30298c2ecf20Sopenharmony_cistatic struct rb_node **fuse_find_polled_node(struct fuse_conn *fc, u64 kh, 30308c2ecf20Sopenharmony_ci struct rb_node **parent_out) 30318c2ecf20Sopenharmony_ci{ 30328c2ecf20Sopenharmony_ci struct rb_node **link = &fc->polled_files.rb_node; 30338c2ecf20Sopenharmony_ci struct rb_node *last = NULL; 30348c2ecf20Sopenharmony_ci 30358c2ecf20Sopenharmony_ci while (*link) { 30368c2ecf20Sopenharmony_ci struct fuse_file *ff; 30378c2ecf20Sopenharmony_ci 30388c2ecf20Sopenharmony_ci last = *link; 30398c2ecf20Sopenharmony_ci ff = rb_entry(last, struct fuse_file, polled_node); 30408c2ecf20Sopenharmony_ci 30418c2ecf20Sopenharmony_ci if (kh < ff->kh) 30428c2ecf20Sopenharmony_ci link = &last->rb_left; 30438c2ecf20Sopenharmony_ci else if (kh > ff->kh) 30448c2ecf20Sopenharmony_ci link = &last->rb_right; 30458c2ecf20Sopenharmony_ci else 30468c2ecf20Sopenharmony_ci return link; 30478c2ecf20Sopenharmony_ci } 30488c2ecf20Sopenharmony_ci 30498c2ecf20Sopenharmony_ci if (parent_out) 30508c2ecf20Sopenharmony_ci *parent_out = last; 30518c2ecf20Sopenharmony_ci return link; 30528c2ecf20Sopenharmony_ci} 30538c2ecf20Sopenharmony_ci 30548c2ecf20Sopenharmony_ci/* 30558c2ecf20Sopenharmony_ci * The file is about to be polled. Make sure it's on the polled_files 30568c2ecf20Sopenharmony_ci * RB tree. Note that files once added to the polled_files tree are 30578c2ecf20Sopenharmony_ci * not removed before the file is released. This is because a file 30588c2ecf20Sopenharmony_ci * polled once is likely to be polled again. 30598c2ecf20Sopenharmony_ci */ 30608c2ecf20Sopenharmony_cistatic void fuse_register_polled_file(struct fuse_conn *fc, 30618c2ecf20Sopenharmony_ci struct fuse_file *ff) 30628c2ecf20Sopenharmony_ci{ 30638c2ecf20Sopenharmony_ci spin_lock(&fc->lock); 30648c2ecf20Sopenharmony_ci if (RB_EMPTY_NODE(&ff->polled_node)) { 30658c2ecf20Sopenharmony_ci struct rb_node **link, *parent; 30668c2ecf20Sopenharmony_ci 30678c2ecf20Sopenharmony_ci link = fuse_find_polled_node(fc, ff->kh, &parent); 30688c2ecf20Sopenharmony_ci BUG_ON(*link); 30698c2ecf20Sopenharmony_ci rb_link_node(&ff->polled_node, parent, link); 30708c2ecf20Sopenharmony_ci rb_insert_color(&ff->polled_node, &fc->polled_files); 30718c2ecf20Sopenharmony_ci } 30728c2ecf20Sopenharmony_ci spin_unlock(&fc->lock); 30738c2ecf20Sopenharmony_ci} 30748c2ecf20Sopenharmony_ci 30758c2ecf20Sopenharmony_ci__poll_t fuse_file_poll(struct file *file, poll_table *wait) 30768c2ecf20Sopenharmony_ci{ 30778c2ecf20Sopenharmony_ci struct fuse_file *ff = file->private_data; 30788c2ecf20Sopenharmony_ci struct fuse_mount *fm = ff->fm; 30798c2ecf20Sopenharmony_ci struct fuse_poll_in inarg = { .fh = ff->fh, .kh = ff->kh }; 30808c2ecf20Sopenharmony_ci struct fuse_poll_out outarg; 30818c2ecf20Sopenharmony_ci FUSE_ARGS(args); 30828c2ecf20Sopenharmony_ci int err; 30838c2ecf20Sopenharmony_ci 30848c2ecf20Sopenharmony_ci if (fm->fc->no_poll) 30858c2ecf20Sopenharmony_ci return DEFAULT_POLLMASK; 30868c2ecf20Sopenharmony_ci 30878c2ecf20Sopenharmony_ci poll_wait(file, &ff->poll_wait, wait); 30888c2ecf20Sopenharmony_ci inarg.events = mangle_poll(poll_requested_events(wait)); 30898c2ecf20Sopenharmony_ci 30908c2ecf20Sopenharmony_ci /* 30918c2ecf20Sopenharmony_ci * Ask for notification iff there's someone waiting for it. 30928c2ecf20Sopenharmony_ci * The client may ignore the flag and always notify. 30938c2ecf20Sopenharmony_ci */ 30948c2ecf20Sopenharmony_ci if (waitqueue_active(&ff->poll_wait)) { 30958c2ecf20Sopenharmony_ci inarg.flags |= FUSE_POLL_SCHEDULE_NOTIFY; 30968c2ecf20Sopenharmony_ci fuse_register_polled_file(fm->fc, ff); 30978c2ecf20Sopenharmony_ci } 30988c2ecf20Sopenharmony_ci 30998c2ecf20Sopenharmony_ci args.opcode = FUSE_POLL; 31008c2ecf20Sopenharmony_ci args.nodeid = ff->nodeid; 31018c2ecf20Sopenharmony_ci args.in_numargs = 1; 31028c2ecf20Sopenharmony_ci args.in_args[0].size = sizeof(inarg); 31038c2ecf20Sopenharmony_ci args.in_args[0].value = &inarg; 31048c2ecf20Sopenharmony_ci args.out_numargs = 1; 31058c2ecf20Sopenharmony_ci args.out_args[0].size = sizeof(outarg); 31068c2ecf20Sopenharmony_ci args.out_args[0].value = &outarg; 31078c2ecf20Sopenharmony_ci err = fuse_simple_request(fm, &args); 31088c2ecf20Sopenharmony_ci 31098c2ecf20Sopenharmony_ci if (!err) 31108c2ecf20Sopenharmony_ci return demangle_poll(outarg.revents); 31118c2ecf20Sopenharmony_ci if (err == -ENOSYS) { 31128c2ecf20Sopenharmony_ci fm->fc->no_poll = 1; 31138c2ecf20Sopenharmony_ci return DEFAULT_POLLMASK; 31148c2ecf20Sopenharmony_ci } 31158c2ecf20Sopenharmony_ci return EPOLLERR; 31168c2ecf20Sopenharmony_ci} 31178c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(fuse_file_poll); 31188c2ecf20Sopenharmony_ci 31198c2ecf20Sopenharmony_ci/* 31208c2ecf20Sopenharmony_ci * This is called from fuse_handle_notify() on FUSE_NOTIFY_POLL and 31218c2ecf20Sopenharmony_ci * wakes up the poll waiters. 31228c2ecf20Sopenharmony_ci */ 31238c2ecf20Sopenharmony_ciint fuse_notify_poll_wakeup(struct fuse_conn *fc, 31248c2ecf20Sopenharmony_ci struct fuse_notify_poll_wakeup_out *outarg) 31258c2ecf20Sopenharmony_ci{ 31268c2ecf20Sopenharmony_ci u64 kh = outarg->kh; 31278c2ecf20Sopenharmony_ci struct rb_node **link; 31288c2ecf20Sopenharmony_ci 31298c2ecf20Sopenharmony_ci spin_lock(&fc->lock); 31308c2ecf20Sopenharmony_ci 31318c2ecf20Sopenharmony_ci link = fuse_find_polled_node(fc, kh, NULL); 31328c2ecf20Sopenharmony_ci if (*link) { 31338c2ecf20Sopenharmony_ci struct fuse_file *ff; 31348c2ecf20Sopenharmony_ci 31358c2ecf20Sopenharmony_ci ff = rb_entry(*link, struct fuse_file, polled_node); 31368c2ecf20Sopenharmony_ci wake_up_interruptible_sync(&ff->poll_wait); 31378c2ecf20Sopenharmony_ci } 31388c2ecf20Sopenharmony_ci 31398c2ecf20Sopenharmony_ci spin_unlock(&fc->lock); 31408c2ecf20Sopenharmony_ci return 0; 31418c2ecf20Sopenharmony_ci} 31428c2ecf20Sopenharmony_ci 31438c2ecf20Sopenharmony_cistatic void fuse_do_truncate(struct file *file) 31448c2ecf20Sopenharmony_ci{ 31458c2ecf20Sopenharmony_ci struct inode *inode = file->f_mapping->host; 31468c2ecf20Sopenharmony_ci struct iattr attr; 31478c2ecf20Sopenharmony_ci 31488c2ecf20Sopenharmony_ci attr.ia_valid = ATTR_SIZE; 31498c2ecf20Sopenharmony_ci attr.ia_size = i_size_read(inode); 31508c2ecf20Sopenharmony_ci 31518c2ecf20Sopenharmony_ci attr.ia_file = file; 31528c2ecf20Sopenharmony_ci attr.ia_valid |= ATTR_FILE; 31538c2ecf20Sopenharmony_ci 31548c2ecf20Sopenharmony_ci fuse_do_setattr(file_dentry(file), &attr, file); 31558c2ecf20Sopenharmony_ci} 31568c2ecf20Sopenharmony_ci 31578c2ecf20Sopenharmony_cistatic inline loff_t fuse_round_up(struct fuse_conn *fc, loff_t off) 31588c2ecf20Sopenharmony_ci{ 31598c2ecf20Sopenharmony_ci return round_up(off, fc->max_pages << PAGE_SHIFT); 31608c2ecf20Sopenharmony_ci} 31618c2ecf20Sopenharmony_ci 31628c2ecf20Sopenharmony_cistatic ssize_t 31638c2ecf20Sopenharmony_cifuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter) 31648c2ecf20Sopenharmony_ci{ 31658c2ecf20Sopenharmony_ci DECLARE_COMPLETION_ONSTACK(wait); 31668c2ecf20Sopenharmony_ci ssize_t ret = 0; 31678c2ecf20Sopenharmony_ci struct file *file = iocb->ki_filp; 31688c2ecf20Sopenharmony_ci struct fuse_file *ff = file->private_data; 31698c2ecf20Sopenharmony_ci loff_t pos = 0; 31708c2ecf20Sopenharmony_ci struct inode *inode; 31718c2ecf20Sopenharmony_ci loff_t i_size; 31728c2ecf20Sopenharmony_ci size_t count = iov_iter_count(iter), shortened = 0; 31738c2ecf20Sopenharmony_ci loff_t offset = iocb->ki_pos; 31748c2ecf20Sopenharmony_ci struct fuse_io_priv *io; 31758c2ecf20Sopenharmony_ci 31768c2ecf20Sopenharmony_ci pos = offset; 31778c2ecf20Sopenharmony_ci inode = file->f_mapping->host; 31788c2ecf20Sopenharmony_ci i_size = i_size_read(inode); 31798c2ecf20Sopenharmony_ci 31808c2ecf20Sopenharmony_ci if ((iov_iter_rw(iter) == READ) && (offset >= i_size)) 31818c2ecf20Sopenharmony_ci return 0; 31828c2ecf20Sopenharmony_ci 31838c2ecf20Sopenharmony_ci io = kmalloc(sizeof(struct fuse_io_priv), GFP_KERNEL); 31848c2ecf20Sopenharmony_ci if (!io) 31858c2ecf20Sopenharmony_ci return -ENOMEM; 31868c2ecf20Sopenharmony_ci spin_lock_init(&io->lock); 31878c2ecf20Sopenharmony_ci kref_init(&io->refcnt); 31888c2ecf20Sopenharmony_ci io->reqs = 1; 31898c2ecf20Sopenharmony_ci io->bytes = -1; 31908c2ecf20Sopenharmony_ci io->size = 0; 31918c2ecf20Sopenharmony_ci io->offset = offset; 31928c2ecf20Sopenharmony_ci io->write = (iov_iter_rw(iter) == WRITE); 31938c2ecf20Sopenharmony_ci io->err = 0; 31948c2ecf20Sopenharmony_ci /* 31958c2ecf20Sopenharmony_ci * By default, we want to optimize all I/Os with async request 31968c2ecf20Sopenharmony_ci * submission to the client filesystem if supported. 31978c2ecf20Sopenharmony_ci */ 31988c2ecf20Sopenharmony_ci io->async = ff->fm->fc->async_dio; 31998c2ecf20Sopenharmony_ci io->iocb = iocb; 32008c2ecf20Sopenharmony_ci io->blocking = is_sync_kiocb(iocb); 32018c2ecf20Sopenharmony_ci 32028c2ecf20Sopenharmony_ci /* optimization for short read */ 32038c2ecf20Sopenharmony_ci if (io->async && !io->write && offset + count > i_size) { 32048c2ecf20Sopenharmony_ci iov_iter_truncate(iter, fuse_round_up(ff->fm->fc, i_size - offset)); 32058c2ecf20Sopenharmony_ci shortened = count - iov_iter_count(iter); 32068c2ecf20Sopenharmony_ci count -= shortened; 32078c2ecf20Sopenharmony_ci } 32088c2ecf20Sopenharmony_ci 32098c2ecf20Sopenharmony_ci /* 32108c2ecf20Sopenharmony_ci * We cannot asynchronously extend the size of a file. 32118c2ecf20Sopenharmony_ci * In such case the aio will behave exactly like sync io. 32128c2ecf20Sopenharmony_ci */ 32138c2ecf20Sopenharmony_ci if ((offset + count > i_size) && io->write) 32148c2ecf20Sopenharmony_ci io->blocking = true; 32158c2ecf20Sopenharmony_ci 32168c2ecf20Sopenharmony_ci if (io->async && io->blocking) { 32178c2ecf20Sopenharmony_ci /* 32188c2ecf20Sopenharmony_ci * Additional reference to keep io around after 32198c2ecf20Sopenharmony_ci * calling fuse_aio_complete() 32208c2ecf20Sopenharmony_ci */ 32218c2ecf20Sopenharmony_ci kref_get(&io->refcnt); 32228c2ecf20Sopenharmony_ci io->done = &wait; 32238c2ecf20Sopenharmony_ci } 32248c2ecf20Sopenharmony_ci 32258c2ecf20Sopenharmony_ci if (iov_iter_rw(iter) == WRITE) { 32268c2ecf20Sopenharmony_ci ret = fuse_direct_io(io, iter, &pos, FUSE_DIO_WRITE); 32278c2ecf20Sopenharmony_ci fuse_invalidate_attr(inode); 32288c2ecf20Sopenharmony_ci } else { 32298c2ecf20Sopenharmony_ci ret = __fuse_direct_read(io, iter, &pos); 32308c2ecf20Sopenharmony_ci } 32318c2ecf20Sopenharmony_ci iov_iter_reexpand(iter, iov_iter_count(iter) + shortened); 32328c2ecf20Sopenharmony_ci 32338c2ecf20Sopenharmony_ci if (io->async) { 32348c2ecf20Sopenharmony_ci bool blocking = io->blocking; 32358c2ecf20Sopenharmony_ci 32368c2ecf20Sopenharmony_ci fuse_aio_complete(io, ret < 0 ? ret : 0, -1); 32378c2ecf20Sopenharmony_ci 32388c2ecf20Sopenharmony_ci /* we have a non-extending, async request, so return */ 32398c2ecf20Sopenharmony_ci if (!blocking) 32408c2ecf20Sopenharmony_ci return -EIOCBQUEUED; 32418c2ecf20Sopenharmony_ci 32428c2ecf20Sopenharmony_ci wait_for_completion(&wait); 32438c2ecf20Sopenharmony_ci ret = fuse_get_res_by_io(io); 32448c2ecf20Sopenharmony_ci } 32458c2ecf20Sopenharmony_ci 32468c2ecf20Sopenharmony_ci kref_put(&io->refcnt, fuse_io_release); 32478c2ecf20Sopenharmony_ci 32488c2ecf20Sopenharmony_ci if (iov_iter_rw(iter) == WRITE) { 32498c2ecf20Sopenharmony_ci if (ret > 0) 32508c2ecf20Sopenharmony_ci fuse_write_update_size(inode, pos); 32518c2ecf20Sopenharmony_ci else if (ret < 0 && offset + count > i_size) 32528c2ecf20Sopenharmony_ci fuse_do_truncate(file); 32538c2ecf20Sopenharmony_ci } 32548c2ecf20Sopenharmony_ci 32558c2ecf20Sopenharmony_ci return ret; 32568c2ecf20Sopenharmony_ci} 32578c2ecf20Sopenharmony_ci 32588c2ecf20Sopenharmony_cistatic int fuse_writeback_range(struct inode *inode, loff_t start, loff_t end) 32598c2ecf20Sopenharmony_ci{ 32608c2ecf20Sopenharmony_ci int err = filemap_write_and_wait_range(inode->i_mapping, start, LLONG_MAX); 32618c2ecf20Sopenharmony_ci 32628c2ecf20Sopenharmony_ci if (!err) 32638c2ecf20Sopenharmony_ci fuse_sync_writes(inode); 32648c2ecf20Sopenharmony_ci 32658c2ecf20Sopenharmony_ci return err; 32668c2ecf20Sopenharmony_ci} 32678c2ecf20Sopenharmony_ci 32688c2ecf20Sopenharmony_cistatic long fuse_file_fallocate(struct file *file, int mode, loff_t offset, 32698c2ecf20Sopenharmony_ci loff_t length) 32708c2ecf20Sopenharmony_ci{ 32718c2ecf20Sopenharmony_ci struct fuse_file *ff = file->private_data; 32728c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 32738c2ecf20Sopenharmony_ci struct fuse_inode *fi = get_fuse_inode(inode); 32748c2ecf20Sopenharmony_ci struct fuse_mount *fm = ff->fm; 32758c2ecf20Sopenharmony_ci FUSE_ARGS(args); 32768c2ecf20Sopenharmony_ci struct fuse_fallocate_in inarg = { 32778c2ecf20Sopenharmony_ci .fh = ff->fh, 32788c2ecf20Sopenharmony_ci .offset = offset, 32798c2ecf20Sopenharmony_ci .length = length, 32808c2ecf20Sopenharmony_ci .mode = mode 32818c2ecf20Sopenharmony_ci }; 32828c2ecf20Sopenharmony_ci int err; 32838c2ecf20Sopenharmony_ci bool block_faults = FUSE_IS_DAX(inode) && 32848c2ecf20Sopenharmony_ci (!(mode & FALLOC_FL_KEEP_SIZE) || 32858c2ecf20Sopenharmony_ci (mode & FALLOC_FL_PUNCH_HOLE)); 32868c2ecf20Sopenharmony_ci 32878c2ecf20Sopenharmony_ci if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE)) 32888c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 32898c2ecf20Sopenharmony_ci 32908c2ecf20Sopenharmony_ci if (fm->fc->no_fallocate) 32918c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 32928c2ecf20Sopenharmony_ci 32938c2ecf20Sopenharmony_ci inode_lock(inode); 32948c2ecf20Sopenharmony_ci if (block_faults) { 32958c2ecf20Sopenharmony_ci down_write(&fi->i_mmap_sem); 32968c2ecf20Sopenharmony_ci err = fuse_dax_break_layouts(inode, 0, 0); 32978c2ecf20Sopenharmony_ci if (err) 32988c2ecf20Sopenharmony_ci goto out; 32998c2ecf20Sopenharmony_ci } 33008c2ecf20Sopenharmony_ci 33018c2ecf20Sopenharmony_ci if (mode & FALLOC_FL_PUNCH_HOLE) { 33028c2ecf20Sopenharmony_ci loff_t endbyte = offset + length - 1; 33038c2ecf20Sopenharmony_ci 33048c2ecf20Sopenharmony_ci err = fuse_writeback_range(inode, offset, endbyte); 33058c2ecf20Sopenharmony_ci if (err) 33068c2ecf20Sopenharmony_ci goto out; 33078c2ecf20Sopenharmony_ci } 33088c2ecf20Sopenharmony_ci 33098c2ecf20Sopenharmony_ci if (!(mode & FALLOC_FL_KEEP_SIZE) && 33108c2ecf20Sopenharmony_ci offset + length > i_size_read(inode)) { 33118c2ecf20Sopenharmony_ci err = inode_newsize_ok(inode, offset + length); 33128c2ecf20Sopenharmony_ci if (err) 33138c2ecf20Sopenharmony_ci goto out; 33148c2ecf20Sopenharmony_ci } 33158c2ecf20Sopenharmony_ci 33168c2ecf20Sopenharmony_ci err = file_modified(file); 33178c2ecf20Sopenharmony_ci if (err) 33188c2ecf20Sopenharmony_ci goto out; 33198c2ecf20Sopenharmony_ci 33208c2ecf20Sopenharmony_ci if (!(mode & FALLOC_FL_KEEP_SIZE)) 33218c2ecf20Sopenharmony_ci set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state); 33228c2ecf20Sopenharmony_ci 33238c2ecf20Sopenharmony_ci args.opcode = FUSE_FALLOCATE; 33248c2ecf20Sopenharmony_ci args.nodeid = ff->nodeid; 33258c2ecf20Sopenharmony_ci args.in_numargs = 1; 33268c2ecf20Sopenharmony_ci args.in_args[0].size = sizeof(inarg); 33278c2ecf20Sopenharmony_ci args.in_args[0].value = &inarg; 33288c2ecf20Sopenharmony_ci err = fuse_simple_request(fm, &args); 33298c2ecf20Sopenharmony_ci if (err == -ENOSYS) { 33308c2ecf20Sopenharmony_ci fm->fc->no_fallocate = 1; 33318c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 33328c2ecf20Sopenharmony_ci } 33338c2ecf20Sopenharmony_ci if (err) 33348c2ecf20Sopenharmony_ci goto out; 33358c2ecf20Sopenharmony_ci 33368c2ecf20Sopenharmony_ci /* we could have extended the file */ 33378c2ecf20Sopenharmony_ci if (!(mode & FALLOC_FL_KEEP_SIZE)) { 33388c2ecf20Sopenharmony_ci bool changed = fuse_write_update_size(inode, offset + length); 33398c2ecf20Sopenharmony_ci 33408c2ecf20Sopenharmony_ci if (changed && fm->fc->writeback_cache) 33418c2ecf20Sopenharmony_ci file_update_time(file); 33428c2ecf20Sopenharmony_ci } 33438c2ecf20Sopenharmony_ci 33448c2ecf20Sopenharmony_ci if (mode & FALLOC_FL_PUNCH_HOLE) 33458c2ecf20Sopenharmony_ci truncate_pagecache_range(inode, offset, offset + length - 1); 33468c2ecf20Sopenharmony_ci 33478c2ecf20Sopenharmony_ci fuse_invalidate_attr(inode); 33488c2ecf20Sopenharmony_ci 33498c2ecf20Sopenharmony_ciout: 33508c2ecf20Sopenharmony_ci if (!(mode & FALLOC_FL_KEEP_SIZE)) 33518c2ecf20Sopenharmony_ci clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state); 33528c2ecf20Sopenharmony_ci 33538c2ecf20Sopenharmony_ci if (block_faults) 33548c2ecf20Sopenharmony_ci up_write(&fi->i_mmap_sem); 33558c2ecf20Sopenharmony_ci 33568c2ecf20Sopenharmony_ci inode_unlock(inode); 33578c2ecf20Sopenharmony_ci 33588c2ecf20Sopenharmony_ci fuse_flush_time_update(inode); 33598c2ecf20Sopenharmony_ci 33608c2ecf20Sopenharmony_ci return err; 33618c2ecf20Sopenharmony_ci} 33628c2ecf20Sopenharmony_ci 33638c2ecf20Sopenharmony_cistatic ssize_t __fuse_copy_file_range(struct file *file_in, loff_t pos_in, 33648c2ecf20Sopenharmony_ci struct file *file_out, loff_t pos_out, 33658c2ecf20Sopenharmony_ci size_t len, unsigned int flags) 33668c2ecf20Sopenharmony_ci{ 33678c2ecf20Sopenharmony_ci struct fuse_file *ff_in = file_in->private_data; 33688c2ecf20Sopenharmony_ci struct fuse_file *ff_out = file_out->private_data; 33698c2ecf20Sopenharmony_ci struct inode *inode_in = file_inode(file_in); 33708c2ecf20Sopenharmony_ci struct inode *inode_out = file_inode(file_out); 33718c2ecf20Sopenharmony_ci struct fuse_inode *fi_out = get_fuse_inode(inode_out); 33728c2ecf20Sopenharmony_ci struct fuse_mount *fm = ff_in->fm; 33738c2ecf20Sopenharmony_ci struct fuse_conn *fc = fm->fc; 33748c2ecf20Sopenharmony_ci FUSE_ARGS(args); 33758c2ecf20Sopenharmony_ci struct fuse_copy_file_range_in inarg = { 33768c2ecf20Sopenharmony_ci .fh_in = ff_in->fh, 33778c2ecf20Sopenharmony_ci .off_in = pos_in, 33788c2ecf20Sopenharmony_ci .nodeid_out = ff_out->nodeid, 33798c2ecf20Sopenharmony_ci .fh_out = ff_out->fh, 33808c2ecf20Sopenharmony_ci .off_out = pos_out, 33818c2ecf20Sopenharmony_ci .len = len, 33828c2ecf20Sopenharmony_ci .flags = flags 33838c2ecf20Sopenharmony_ci }; 33848c2ecf20Sopenharmony_ci struct fuse_write_out outarg; 33858c2ecf20Sopenharmony_ci ssize_t err; 33868c2ecf20Sopenharmony_ci /* mark unstable when write-back is not used, and file_out gets 33878c2ecf20Sopenharmony_ci * extended */ 33888c2ecf20Sopenharmony_ci bool is_unstable = (!fc->writeback_cache) && 33898c2ecf20Sopenharmony_ci ((pos_out + len) > inode_out->i_size); 33908c2ecf20Sopenharmony_ci 33918c2ecf20Sopenharmony_ci if (fc->no_copy_file_range) 33928c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 33938c2ecf20Sopenharmony_ci 33948c2ecf20Sopenharmony_ci if (file_inode(file_in)->i_sb != file_inode(file_out)->i_sb) 33958c2ecf20Sopenharmony_ci return -EXDEV; 33968c2ecf20Sopenharmony_ci 33978c2ecf20Sopenharmony_ci inode_lock(inode_in); 33988c2ecf20Sopenharmony_ci err = fuse_writeback_range(inode_in, pos_in, pos_in + len - 1); 33998c2ecf20Sopenharmony_ci inode_unlock(inode_in); 34008c2ecf20Sopenharmony_ci if (err) 34018c2ecf20Sopenharmony_ci return err; 34028c2ecf20Sopenharmony_ci 34038c2ecf20Sopenharmony_ci inode_lock(inode_out); 34048c2ecf20Sopenharmony_ci 34058c2ecf20Sopenharmony_ci err = file_modified(file_out); 34068c2ecf20Sopenharmony_ci if (err) 34078c2ecf20Sopenharmony_ci goto out; 34088c2ecf20Sopenharmony_ci 34098c2ecf20Sopenharmony_ci /* 34108c2ecf20Sopenharmony_ci * Write out dirty pages in the destination file before sending the COPY 34118c2ecf20Sopenharmony_ci * request to userspace. After the request is completed, truncate off 34128c2ecf20Sopenharmony_ci * pages (including partial ones) from the cache that have been copied, 34138c2ecf20Sopenharmony_ci * since these contain stale data at that point. 34148c2ecf20Sopenharmony_ci * 34158c2ecf20Sopenharmony_ci * This should be mostly correct, but if the COPY writes to partial 34168c2ecf20Sopenharmony_ci * pages (at the start or end) and the parts not covered by the COPY are 34178c2ecf20Sopenharmony_ci * written through a memory map after calling fuse_writeback_range(), 34188c2ecf20Sopenharmony_ci * then these partial page modifications will be lost on truncation. 34198c2ecf20Sopenharmony_ci * 34208c2ecf20Sopenharmony_ci * It is unlikely that someone would rely on such mixed style 34218c2ecf20Sopenharmony_ci * modifications. Yet this does give less guarantees than if the 34228c2ecf20Sopenharmony_ci * copying was performed with write(2). 34238c2ecf20Sopenharmony_ci * 34248c2ecf20Sopenharmony_ci * To fix this a i_mmap_sem style lock could be used to prevent new 34258c2ecf20Sopenharmony_ci * faults while the copy is ongoing. 34268c2ecf20Sopenharmony_ci */ 34278c2ecf20Sopenharmony_ci err = fuse_writeback_range(inode_out, pos_out, pos_out + len - 1); 34288c2ecf20Sopenharmony_ci if (err) 34298c2ecf20Sopenharmony_ci goto out; 34308c2ecf20Sopenharmony_ci 34318c2ecf20Sopenharmony_ci if (is_unstable) 34328c2ecf20Sopenharmony_ci set_bit(FUSE_I_SIZE_UNSTABLE, &fi_out->state); 34338c2ecf20Sopenharmony_ci 34348c2ecf20Sopenharmony_ci args.opcode = FUSE_COPY_FILE_RANGE; 34358c2ecf20Sopenharmony_ci args.nodeid = ff_in->nodeid; 34368c2ecf20Sopenharmony_ci args.in_numargs = 1; 34378c2ecf20Sopenharmony_ci args.in_args[0].size = sizeof(inarg); 34388c2ecf20Sopenharmony_ci args.in_args[0].value = &inarg; 34398c2ecf20Sopenharmony_ci args.out_numargs = 1; 34408c2ecf20Sopenharmony_ci args.out_args[0].size = sizeof(outarg); 34418c2ecf20Sopenharmony_ci args.out_args[0].value = &outarg; 34428c2ecf20Sopenharmony_ci err = fuse_simple_request(fm, &args); 34438c2ecf20Sopenharmony_ci if (err == -ENOSYS) { 34448c2ecf20Sopenharmony_ci fc->no_copy_file_range = 1; 34458c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 34468c2ecf20Sopenharmony_ci } 34478c2ecf20Sopenharmony_ci if (err) 34488c2ecf20Sopenharmony_ci goto out; 34498c2ecf20Sopenharmony_ci 34508c2ecf20Sopenharmony_ci truncate_inode_pages_range(inode_out->i_mapping, 34518c2ecf20Sopenharmony_ci ALIGN_DOWN(pos_out, PAGE_SIZE), 34528c2ecf20Sopenharmony_ci ALIGN(pos_out + outarg.size, PAGE_SIZE) - 1); 34538c2ecf20Sopenharmony_ci 34548c2ecf20Sopenharmony_ci if (fc->writeback_cache) { 34558c2ecf20Sopenharmony_ci fuse_write_update_size(inode_out, pos_out + outarg.size); 34568c2ecf20Sopenharmony_ci file_update_time(file_out); 34578c2ecf20Sopenharmony_ci } 34588c2ecf20Sopenharmony_ci 34598c2ecf20Sopenharmony_ci fuse_invalidate_attr(inode_out); 34608c2ecf20Sopenharmony_ci 34618c2ecf20Sopenharmony_ci err = outarg.size; 34628c2ecf20Sopenharmony_ciout: 34638c2ecf20Sopenharmony_ci if (is_unstable) 34648c2ecf20Sopenharmony_ci clear_bit(FUSE_I_SIZE_UNSTABLE, &fi_out->state); 34658c2ecf20Sopenharmony_ci 34668c2ecf20Sopenharmony_ci inode_unlock(inode_out); 34678c2ecf20Sopenharmony_ci file_accessed(file_in); 34688c2ecf20Sopenharmony_ci 34698c2ecf20Sopenharmony_ci fuse_flush_time_update(inode_out); 34708c2ecf20Sopenharmony_ci 34718c2ecf20Sopenharmony_ci return err; 34728c2ecf20Sopenharmony_ci} 34738c2ecf20Sopenharmony_ci 34748c2ecf20Sopenharmony_cistatic ssize_t fuse_copy_file_range(struct file *src_file, loff_t src_off, 34758c2ecf20Sopenharmony_ci struct file *dst_file, loff_t dst_off, 34768c2ecf20Sopenharmony_ci size_t len, unsigned int flags) 34778c2ecf20Sopenharmony_ci{ 34788c2ecf20Sopenharmony_ci ssize_t ret; 34798c2ecf20Sopenharmony_ci 34808c2ecf20Sopenharmony_ci ret = __fuse_copy_file_range(src_file, src_off, dst_file, dst_off, 34818c2ecf20Sopenharmony_ci len, flags); 34828c2ecf20Sopenharmony_ci 34838c2ecf20Sopenharmony_ci if (ret == -EOPNOTSUPP || ret == -EXDEV) 34848c2ecf20Sopenharmony_ci ret = generic_copy_file_range(src_file, src_off, dst_file, 34858c2ecf20Sopenharmony_ci dst_off, len, flags); 34868c2ecf20Sopenharmony_ci return ret; 34878c2ecf20Sopenharmony_ci} 34888c2ecf20Sopenharmony_ci 34898c2ecf20Sopenharmony_cistatic const struct file_operations fuse_file_operations = { 34908c2ecf20Sopenharmony_ci .llseek = fuse_file_llseek, 34918c2ecf20Sopenharmony_ci .read_iter = fuse_file_read_iter, 34928c2ecf20Sopenharmony_ci .write_iter = fuse_file_write_iter, 34938c2ecf20Sopenharmony_ci .mmap = fuse_file_mmap, 34948c2ecf20Sopenharmony_ci .open = fuse_open, 34958c2ecf20Sopenharmony_ci .flush = fuse_flush, 34968c2ecf20Sopenharmony_ci .release = fuse_release, 34978c2ecf20Sopenharmony_ci .fsync = fuse_fsync, 34988c2ecf20Sopenharmony_ci .lock = fuse_file_lock, 34998c2ecf20Sopenharmony_ci .get_unmapped_area = thp_get_unmapped_area, 35008c2ecf20Sopenharmony_ci .flock = fuse_file_flock, 35018c2ecf20Sopenharmony_ci .splice_read = generic_file_splice_read, 35028c2ecf20Sopenharmony_ci .splice_write = iter_file_splice_write, 35038c2ecf20Sopenharmony_ci .unlocked_ioctl = fuse_file_ioctl, 35048c2ecf20Sopenharmony_ci .compat_ioctl = fuse_file_compat_ioctl, 35058c2ecf20Sopenharmony_ci .poll = fuse_file_poll, 35068c2ecf20Sopenharmony_ci .fallocate = fuse_file_fallocate, 35078c2ecf20Sopenharmony_ci .copy_file_range = fuse_copy_file_range, 35088c2ecf20Sopenharmony_ci}; 35098c2ecf20Sopenharmony_ci 35108c2ecf20Sopenharmony_cistatic const struct address_space_operations fuse_file_aops = { 35118c2ecf20Sopenharmony_ci .readpage = fuse_readpage, 35128c2ecf20Sopenharmony_ci .readahead = fuse_readahead, 35138c2ecf20Sopenharmony_ci .writepage = fuse_writepage, 35148c2ecf20Sopenharmony_ci .writepages = fuse_writepages, 35158c2ecf20Sopenharmony_ci .launder_page = fuse_launder_page, 35168c2ecf20Sopenharmony_ci .set_page_dirty = __set_page_dirty_nobuffers, 35178c2ecf20Sopenharmony_ci .bmap = fuse_bmap, 35188c2ecf20Sopenharmony_ci .direct_IO = fuse_direct_IO, 35198c2ecf20Sopenharmony_ci .write_begin = fuse_write_begin, 35208c2ecf20Sopenharmony_ci .write_end = fuse_write_end, 35218c2ecf20Sopenharmony_ci}; 35228c2ecf20Sopenharmony_ci 35238c2ecf20Sopenharmony_civoid fuse_init_file_inode(struct inode *inode) 35248c2ecf20Sopenharmony_ci{ 35258c2ecf20Sopenharmony_ci struct fuse_inode *fi = get_fuse_inode(inode); 35268c2ecf20Sopenharmony_ci 35278c2ecf20Sopenharmony_ci inode->i_fop = &fuse_file_operations; 35288c2ecf20Sopenharmony_ci inode->i_data.a_ops = &fuse_file_aops; 35298c2ecf20Sopenharmony_ci 35308c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&fi->write_files); 35318c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&fi->queued_writes); 35328c2ecf20Sopenharmony_ci fi->writectr = 0; 35338c2ecf20Sopenharmony_ci init_waitqueue_head(&fi->page_waitq); 35348c2ecf20Sopenharmony_ci fi->writepages = RB_ROOT; 35358c2ecf20Sopenharmony_ci 35368c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_FUSE_DAX)) 35378c2ecf20Sopenharmony_ci fuse_dax_inode_init(inode); 35388c2ecf20Sopenharmony_ci} 3539