From 2e9d7e4b984a61823c41ba65e1b58b98ca9912bb Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 19 Mar 2024 11:13:26 +0000 Subject: mm: Remove the PG_fscache alias for PG_private_2 Remove the PG_fscache alias for PG_private_2 and use the latter directly. Use of this flag for marking pages undergoing writing to the cache should be considered deprecated and the folios should be marked dirty instead and the write done in ->writepages(). Note that PG_private_2 itself should be considered deprecated and up for future removal by the MM folks too. Signed-off-by: David Howells Reviewed-by: Jeff Layton cc: Matthew Wilcox (Oracle) cc: Ilya Dryomov cc: Xiubo Li cc: Steve French cc: Paulo Alcantara cc: Ronnie Sahlberg cc: Shyam Prasad N cc: Tom Talpey cc: Bharath SM cc: Trond Myklebust cc: Anna Schumaker cc: netfs@lists.linux.dev cc: ceph-devel@vger.kernel.org cc: linux-cifs@vger.kernel.org cc: linux-nfs@vger.kernel.org cc: linux-fsdevel@vger.kernel.org cc: linux-mm@kvack.org --- fs/smb/client/file.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'fs/smb') diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c index 9be37d0fe724..b39caae652f6 100644 --- a/fs/smb/client/file.c +++ b/fs/smb/client/file.c @@ -3032,12 +3032,12 @@ lock_again: } if (folio_test_writeback(folio) || - folio_test_fscache(folio)) { + folio_test_private_2(folio)) { /* [DEPRECATED] */ folio_unlock(folio); if (wbc->sync_mode != WB_SYNC_NONE) { folio_wait_writeback(folio); #ifdef CONFIG_CIFS_FSCACHE - folio_wait_fscache(folio); + folio_wait_private_2(folio); #endif goto lock_again; } @@ -4510,8 +4510,8 @@ static vm_fault_t cifs_page_mkwrite(struct vm_fault *vmf) * be modified. We then assume the entire folio will need writing back. */ #ifdef CONFIG_CIFS_FSCACHE - if (folio_test_fscache(folio) && - folio_wait_fscache_killable(folio) < 0) + if (folio_test_private_2(folio) && /* [DEPRECATED] */ + folio_wait_private_2_killable(folio) < 0) return VM_FAULT_RETRY; #endif @@ -4977,10 +4977,10 @@ static bool cifs_release_folio(struct folio *folio, gfp_t gfp) { if (folio_test_private(folio)) return 0; - if (folio_test_fscache(folio)) { + if (folio_test_private_2(folio)) { /* [DEPRECATED] */ if (current_is_kswapd() || !(gfp & __GFP_FS)) return false; - folio_wait_fscache(folio); + folio_wait_private_2(folio); } fscache_note_page_release(cifs_inode_cookie(folio->mapping->host)); return true; @@ -4989,7 +4989,7 @@ static bool cifs_release_folio(struct folio *folio, gfp_t gfp) static void cifs_invalidate_folio(struct folio *folio, size_t offset, size_t length) { - folio_wait_fscache(folio); + folio_wait_private_2(folio); /* [DEPRECATED] */ } static int cifs_launder_folio(struct folio *folio) @@ -5009,7 +5009,7 @@ static int cifs_launder_folio(struct folio *folio) if (folio_clear_dirty_for_io(folio)) rc = cifs_writepage_locked(&folio->page, &wbc); - folio_wait_fscache(folio); + folio_wait_private_2(folio); /* [DEPRECATED] */ return rc; } -- cgit From 0f7c0f3f51501a472a08d16315903d17012325ca Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 27 Mar 2024 08:51:38 +0000 Subject: cifs: Use alternative invalidation to using launder_folio Use writepages-based flushing invalidation instead of invalidate_inode_pages2() and ->launder_folio(). This will allow ->launder_folio() to be removed eventually. Signed-off-by: David Howells cc: Steve French cc: Shyam Prasad N cc: Rohith Surabattula cc: Jeff Layton cc: linux-cifs@vger.kernel.org cc: netfs@lists.linux.dev cc: linux-fsdevel@vger.kernel.org --- fs/smb/client/cifsfs.h | 1 - fs/smb/client/file.c | 122 ------------------------------------------------- fs/smb/client/inode.c | 25 ++-------- 3 files changed, 5 insertions(+), 143 deletions(-) (limited to 'fs/smb') diff --git a/fs/smb/client/cifsfs.h b/fs/smb/client/cifsfs.h index ca55d01117c8..1ab7e5998c58 100644 --- a/fs/smb/client/cifsfs.h +++ b/fs/smb/client/cifsfs.h @@ -69,7 +69,6 @@ extern int cifs_revalidate_file_attr(struct file *filp); extern int cifs_revalidate_dentry_attr(struct dentry *); extern int cifs_revalidate_file(struct file *filp); extern int cifs_revalidate_dentry(struct dentry *); -extern int cifs_invalidate_mapping(struct inode *inode); extern int cifs_revalidate_mapping(struct inode *inode); extern int cifs_zap_mapping(struct inode *inode); extern int cifs_getattr(struct mnt_idmap *, const struct path *, diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c index b39caae652f6..2d5488a67965 100644 --- a/fs/smb/client/file.c +++ b/fs/smb/client/file.c @@ -2655,64 +2655,6 @@ struct cifs_writedata *cifs_writedata_alloc(work_func_t complete) return wdata; } -static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) -{ - struct address_space *mapping = page->mapping; - loff_t offset = (loff_t)page->index << PAGE_SHIFT; - char *write_data; - int rc = -EFAULT; - int bytes_written = 0; - struct inode *inode; - struct cifsFileInfo *open_file; - - if (!mapping || !mapping->host) - return -EFAULT; - - inode = page->mapping->host; - - offset += (loff_t)from; - write_data = kmap(page); - write_data += from; - - if ((to > PAGE_SIZE) || (from > to)) { - kunmap(page); - return -EIO; - } - - /* racing with truncate? */ - if (offset > mapping->host->i_size) { - kunmap(page); - return 0; /* don't care */ - } - - /* check to make sure that we are not extending the file */ - if (mapping->host->i_size - offset < (loff_t)to) - to = (unsigned)(mapping->host->i_size - offset); - - rc = cifs_get_writable_file(CIFS_I(mapping->host), FIND_WR_ANY, - &open_file); - if (!rc) { - bytes_written = cifs_write(open_file, open_file->pid, - write_data, to - from, &offset); - cifsFileInfo_put(open_file); - /* Does mm or vfs already set times? */ - simple_inode_init_ts(inode); - if ((bytes_written > 0) && (offset)) - rc = 0; - else if (bytes_written < 0) - rc = bytes_written; - else - rc = -EFAULT; - } else { - cifs_dbg(FYI, "No writable handle for write page rc=%d\n", rc); - if (!is_retryable_error(rc)) - rc = -EIO; - } - - kunmap(page); - return rc; -} - /* * Extend the region to be written back to include subsequent contiguously * dirty pages if possible, but don't sleep while doing so. @@ -3126,47 +3068,6 @@ out: return ret; } -static int -cifs_writepage_locked(struct page *page, struct writeback_control *wbc) -{ - int rc; - unsigned int xid; - - xid = get_xid(); -/* BB add check for wbc flags */ - get_page(page); - if (!PageUptodate(page)) - cifs_dbg(FYI, "ppw - page not up to date\n"); - - /* - * Set the "writeback" flag, and clear "dirty" in the radix tree. - * - * A writepage() implementation always needs to do either this, - * or re-dirty the page with "redirty_page_for_writepage()" in - * the case of a failure. - * - * Just unlocking the page will cause the radix tree tag-bits - * to fail to update with the state of the page correctly. - */ - set_page_writeback(page); -retry_write: - rc = cifs_partialpagewrite(page, 0, PAGE_SIZE); - if (is_retryable_error(rc)) { - if (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN) - goto retry_write; - redirty_page_for_writepage(wbc, page); - } else if (rc != 0) { - SetPageError(page); - mapping_set_error(page->mapping, rc); - } else { - SetPageUptodate(page); - } - end_page_writeback(page); - put_page(page); - free_xid(xid); - return rc; -} - static int cifs_write_end(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned copied, struct page *page, void *fsdata) @@ -4992,27 +4893,6 @@ static void cifs_invalidate_folio(struct folio *folio, size_t offset, folio_wait_private_2(folio); /* [DEPRECATED] */ } -static int cifs_launder_folio(struct folio *folio) -{ - int rc = 0; - loff_t range_start = folio_pos(folio); - loff_t range_end = range_start + folio_size(folio); - struct writeback_control wbc = { - .sync_mode = WB_SYNC_ALL, - .nr_to_write = 0, - .range_start = range_start, - .range_end = range_end, - }; - - cifs_dbg(FYI, "Launder page: %lu\n", folio->index); - - if (folio_clear_dirty_for_io(folio)) - rc = cifs_writepage_locked(&folio->page, &wbc); - - folio_wait_private_2(folio); /* [DEPRECATED] */ - return rc; -} - void cifs_oplock_break(struct work_struct *work) { struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, @@ -5191,7 +5071,6 @@ const struct address_space_operations cifs_addr_ops = { .release_folio = cifs_release_folio, .direct_IO = cifs_direct_io, .invalidate_folio = cifs_invalidate_folio, - .launder_folio = cifs_launder_folio, .migrate_folio = filemap_migrate_folio, /* * TODO: investigate and if useful we could add an is_dirty_writeback @@ -5214,6 +5093,5 @@ const struct address_space_operations cifs_addr_ops_smallbuf = { .dirty_folio = netfs_dirty_folio, .release_folio = cifs_release_folio, .invalidate_folio = cifs_invalidate_folio, - .launder_folio = cifs_launder_folio, .migrate_folio = filemap_migrate_folio, }; diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c index 60afab5c83d4..033948d34c5a 100644 --- a/fs/smb/client/inode.c +++ b/fs/smb/client/inode.c @@ -2431,24 +2431,6 @@ cifs_dentry_needs_reval(struct dentry *dentry) return false; } -/* - * Zap the cache. Called when invalid_mapping flag is set. - */ -int -cifs_invalidate_mapping(struct inode *inode) -{ - int rc = 0; - - if (inode->i_mapping && inode->i_mapping->nrpages != 0) { - rc = invalidate_inode_pages2(inode->i_mapping); - if (rc) - cifs_dbg(VFS, "%s: invalidate inode %p failed with rc %d\n", - __func__, inode, rc); - } - - return rc; -} - /** * cifs_wait_bit_killable - helper for functions that are sleeping on bit locks * @@ -2485,9 +2467,12 @@ cifs_revalidate_mapping(struct inode *inode) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RW_CACHE) goto skip_invalidate; - rc = cifs_invalidate_mapping(inode); - if (rc) + rc = filemap_invalidate_inode(inode, true, 0, LLONG_MAX); + if (rc) { + cifs_dbg(VFS, "%s: invalidate inode %p failed with rc %d\n", + __func__, inode, rc); set_bit(CIFS_INO_INVALID_MAPPING, flags); + } } skip_invalidate: -- cgit From 753b67eb630db34e36ec4ae1e86c75e243ea4fc9 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 9 Mar 2022 11:01:12 +0000 Subject: cifs: Replace cifs_readdata with a wrapper around netfs_io_subrequest Netfslib has a facility whereby the allocation for netfs_io_subrequest can be increased to so that filesystem-specific data can be tagged on the end. Prepare to use this by making a struct, cifs_io_subrequest, that wraps netfs_io_subrequest, and absorb struct cifs_readdata into it. Signed-off-by: David Howells cc: Steve French cc: Shyam Prasad N cc: Rohith Surabattula cc: Jeff Layton cc: linux-cifs@vger.kernel.org cc: netfs@lists.linux.dev cc: linux-fsdevel@vger.kernel.org cc: linux-mm@kvack.org --- fs/smb/client/cifsglob.h | 22 ++++++++++++---------- fs/smb/client/cifsproto.h | 13 +++++++++++-- fs/smb/client/cifssmb.c | 11 ++++------- fs/smb/client/file.c | 44 ++++++++++++++++++++------------------------ fs/smb/client/smb2ops.c | 2 +- fs/smb/client/smb2pdu.c | 12 +++++++----- fs/smb/client/smb2proto.h | 2 +- fs/smb/client/transport.c | 4 ++-- 8 files changed, 58 insertions(+), 52 deletions(-) (limited to 'fs/smb') diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 6ff35570db81..405110052e17 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -268,7 +268,7 @@ struct dfs_info3_param; struct cifs_fattr; struct smb3_fs_context; struct cifs_fid; -struct cifs_readdata; +struct cifs_io_subrequest; struct cifs_writedata; struct cifs_io_parms; struct cifs_search_info; @@ -450,7 +450,7 @@ struct smb_version_operations { /* send a flush request to the server */ int (*flush)(const unsigned int, struct cifs_tcon *, struct cifs_fid *); /* async read from the server */ - int (*async_readv)(struct cifs_readdata *); + int (*async_readv)(struct cifs_io_subrequest *); /* async write to the server */ int (*async_writev)(struct cifs_writedata *, void (*release)(struct kref *)); @@ -1493,26 +1493,28 @@ struct cifs_aio_ctx { }; /* asynchronous read support */ -struct cifs_readdata { - struct kref refcount; - struct list_head list; - struct completion done; +struct cifs_io_subrequest { + struct netfs_io_subrequest subreq; struct cifsFileInfo *cfile; struct address_space *mapping; struct cifs_aio_ctx *ctx; - __u64 offset; ssize_t got_bytes; - unsigned int bytes; pid_t pid; int result; - struct work_struct work; - struct iov_iter iter; struct kvec iov[2]; struct TCP_Server_Info *server; #ifdef CONFIG_CIFS_SMB_DIRECT struct smbd_mr *mr; #endif struct cifs_credits credits; + + // TODO: Remove following elements + struct list_head list; + struct completion done; + struct work_struct work; + struct iov_iter iter; + __u64 offset; + unsigned int bytes; }; /* asynchronous write support */ diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h index fbc358c09da3..5712f789eaa0 100644 --- a/fs/smb/client/cifsproto.h +++ b/fs/smb/client/cifsproto.h @@ -599,8 +599,17 @@ void __cifs_put_smb_ses(struct cifs_ses *ses); extern struct cifs_ses * cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx); -void cifs_readdata_release(struct kref *refcount); -int cifs_async_readv(struct cifs_readdata *rdata); +void cifs_readdata_release(struct cifs_io_subrequest *rdata); +static inline void cifs_get_readdata(struct cifs_io_subrequest *rdata) +{ + refcount_inc(&rdata->subreq.ref); +} +static inline void cifs_put_readdata(struct cifs_io_subrequest *rdata) +{ + if (refcount_dec_and_test(&rdata->subreq.ref)) + cifs_readdata_release(rdata); +} +int cifs_async_readv(struct cifs_io_subrequest *rdata); int cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid); int cifs_async_writev(struct cifs_writedata *wdata, diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index 23b5709ddc31..2aaeae6c5766 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include "cifspdu.h" #include "cifsfs.h" #include "cifsglob.h" @@ -1262,12 +1264,11 @@ openRetry: static void cifs_readv_callback(struct mid_q_entry *mid) { - struct cifs_readdata *rdata = mid->callback_data; + struct cifs_io_subrequest *rdata = mid->callback_data; struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink); struct TCP_Server_Info *server = tcon->ses->server; struct smb_rqst rqst = { .rq_iov = rdata->iov, .rq_nvec = 2, - .rq_iter_size = iov_iter_count(&rdata->iter), .rq_iter = rdata->iter }; struct cifs_credits credits = { .value = 1, .instance = 0 }; @@ -1312,7 +1313,7 @@ cifs_readv_callback(struct mid_q_entry *mid) /* cifs_async_readv - send an async write, and set up mid to handle result */ int -cifs_async_readv(struct cifs_readdata *rdata) +cifs_async_readv(struct cifs_io_subrequest *rdata) { int rc; READ_REQ *smb = NULL; @@ -1364,15 +1365,11 @@ cifs_async_readv(struct cifs_readdata *rdata) rdata->iov[1].iov_base = (char *)smb + 4; rdata->iov[1].iov_len = get_rfc1002_length(smb); - kref_get(&rdata->refcount); rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive, cifs_readv_callback, NULL, rdata, 0, NULL); if (rc == 0) cifs_stats_inc(&tcon->stats.cifs_stats.num_reads); - else - kref_put(&rdata->refcount, cifs_readdata_release); - cifs_small_buf_release(smb); return rc; } diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c index 2d5488a67965..0bea058099d4 100644 --- a/fs/smb/client/file.c +++ b/fs/smb/client/file.c @@ -3822,13 +3822,13 @@ out: return written; } -static struct cifs_readdata *cifs_readdata_alloc(work_func_t complete) +static struct cifs_io_subrequest *cifs_readdata_alloc(work_func_t complete) { - struct cifs_readdata *rdata; + struct cifs_io_subrequest *rdata; rdata = kzalloc(sizeof(*rdata), GFP_KERNEL); if (rdata) { - kref_init(&rdata->refcount); + refcount_set(&rdata->subreq.ref, 1); INIT_LIST_HEAD(&rdata->list); init_completion(&rdata->done); INIT_WORK(&rdata->work, complete); @@ -3838,11 +3838,8 @@ static struct cifs_readdata *cifs_readdata_alloc(work_func_t complete) } void -cifs_readdata_release(struct kref *refcount) +cifs_readdata_release(struct cifs_io_subrequest *rdata) { - struct cifs_readdata *rdata = container_of(refcount, - struct cifs_readdata, refcount); - if (rdata->ctx) kref_put(&rdata->ctx->refcount, cifs_aio_ctx_release); #ifdef CONFIG_CIFS_SMB_DIRECT @@ -3862,16 +3859,16 @@ static void collect_uncached_read_data(struct cifs_aio_ctx *ctx); static void cifs_uncached_readv_complete(struct work_struct *work) { - struct cifs_readdata *rdata = container_of(work, - struct cifs_readdata, work); + struct cifs_io_subrequest *rdata = + container_of(work, struct cifs_io_subrequest, work); complete(&rdata->done); collect_uncached_read_data(rdata->ctx); /* the below call can possibly free the last ref to aio ctx */ - kref_put(&rdata->refcount, cifs_readdata_release); + cifs_put_readdata(rdata); } -static int cifs_resend_rdata(struct cifs_readdata *rdata, +static int cifs_resend_rdata(struct cifs_io_subrequest *rdata, struct list_head *rdata_list, struct cifs_aio_ctx *ctx) { @@ -3939,7 +3936,7 @@ static int cifs_resend_rdata(struct cifs_readdata *rdata, } while (rc == -EAGAIN); fail: - kref_put(&rdata->refcount, cifs_readdata_release); + cifs_put_readdata(rdata); return rc; } @@ -3948,7 +3945,7 @@ cifs_send_async_read(loff_t fpos, size_t len, struct cifsFileInfo *open_file, struct cifs_sb_info *cifs_sb, struct list_head *rdata_list, struct cifs_aio_ctx *ctx) { - struct cifs_readdata *rdata; + struct cifs_io_subrequest *rdata; unsigned int rsize, nsegs, max_segs = INT_MAX; struct cifs_credits credits_on_stack; struct cifs_credits *credits = &credits_on_stack; @@ -4030,7 +4027,7 @@ cifs_send_async_read(loff_t fpos, size_t len, struct cifsFileInfo *open_file, if (rc) { add_credits_and_wake_if(server, &rdata->credits, 0); - kref_put(&rdata->refcount, cifs_readdata_release); + cifs_put_readdata(rdata); if (rc == -EAGAIN) continue; break; @@ -4048,7 +4045,7 @@ cifs_send_async_read(loff_t fpos, size_t len, struct cifsFileInfo *open_file, static void collect_uncached_read_data(struct cifs_aio_ctx *ctx) { - struct cifs_readdata *rdata, *tmp; + struct cifs_io_subrequest *rdata, *tmp; struct cifs_sb_info *cifs_sb; int rc; @@ -4094,8 +4091,7 @@ again: rdata->cfile, cifs_sb, &tmp_list, ctx); - kref_put(&rdata->refcount, - cifs_readdata_release); + cifs_put_readdata(rdata); } list_splice(&tmp_list, &ctx->list); @@ -4111,7 +4107,7 @@ again: ctx->total_len += rdata->got_bytes; } list_del_init(&rdata->list); - kref_put(&rdata->refcount, cifs_readdata_release); + cifs_put_readdata(rdata); } /* mask nodata case */ @@ -4483,8 +4479,8 @@ static void cifs_unlock_folios(struct address_space *mapping, pgoff_t first, pgo static void cifs_readahead_complete(struct work_struct *work) { - struct cifs_readdata *rdata = container_of(work, - struct cifs_readdata, work); + struct cifs_io_subrequest *rdata = container_of(work, + struct cifs_io_subrequest, work); struct folio *folio; pgoff_t last; bool good = rdata->result == 0 || (rdata->result == -EAGAIN && rdata->got_bytes); @@ -4510,7 +4506,7 @@ static void cifs_readahead_complete(struct work_struct *work) } rcu_read_unlock(); - kref_put(&rdata->refcount, cifs_readdata_release); + cifs_put_readdata(rdata); } static void cifs_readahead(struct readahead_control *ractl) @@ -4550,7 +4546,7 @@ static void cifs_readahead(struct readahead_control *ractl) */ while ((nr_pages = ra_pages)) { unsigned int i, rsize; - struct cifs_readdata *rdata; + struct cifs_io_subrequest *rdata; struct cifs_credits credits_on_stack; struct cifs_credits *credits = &credits_on_stack; struct folio *folio; @@ -4669,11 +4665,11 @@ static void cifs_readahead(struct readahead_control *ractl) rdata->offset / PAGE_SIZE, (rdata->offset + rdata->bytes - 1) / PAGE_SIZE); /* Fallback to the readpage in error/reconnect cases */ - kref_put(&rdata->refcount, cifs_readdata_release); + cifs_put_readdata(rdata); break; } - kref_put(&rdata->refcount, cifs_readdata_release); + cifs_put_readdata(rdata); } free_xid(xid); diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index 28f0b7d19d53..56026f4cbc13 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -4490,7 +4490,7 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid, unsigned int cur_off; unsigned int cur_page_idx; unsigned int pad_len; - struct cifs_readdata *rdata = mid->callback_data; + struct cifs_io_subrequest *rdata = mid->callback_data; struct smb2_hdr *shdr = (struct smb2_hdr *)buf; int length; bool use_rdma_mr = false; diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index a5efce03cb58..0957dd4c07e7 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include "cifsglob.h" #include "cifsacl.h" #include "cifsproto.h" @@ -4391,7 +4393,7 @@ static inline bool smb3_use_rdma_offload(struct cifs_io_parms *io_parms) */ static int smb2_new_read_req(void **buf, unsigned int *total_len, - struct cifs_io_parms *io_parms, struct cifs_readdata *rdata, + struct cifs_io_parms *io_parms, struct cifs_io_subrequest *rdata, unsigned int remaining_bytes, int request_type) { int rc = -EACCES; @@ -4483,7 +4485,7 @@ smb2_new_read_req(void **buf, unsigned int *total_len, static void smb2_readv_callback(struct mid_q_entry *mid) { - struct cifs_readdata *rdata = mid->callback_data; + struct cifs_io_subrequest *rdata = mid->callback_data; struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink); struct TCP_Server_Info *server = rdata->server; struct smb2_hdr *shdr = @@ -4570,7 +4572,7 @@ smb2_readv_callback(struct mid_q_entry *mid) /* smb2_async_readv - send an async read, and set up mid to handle result */ int -smb2_async_readv(struct cifs_readdata *rdata) +smb2_async_readv(struct cifs_io_subrequest *rdata) { int rc, flags = 0; char *buf; @@ -4628,13 +4630,13 @@ smb2_async_readv(struct cifs_readdata *rdata) flags |= CIFS_HAS_CREDITS; } - kref_get(&rdata->refcount); + cifs_get_readdata(rdata); rc = cifs_call_async(server, &rqst, cifs_readv_receive, smb2_readv_callback, smb3_handle_read_data, rdata, flags, &rdata->credits); if (rc) { - kref_put(&rdata->refcount, cifs_readdata_release); + cifs_put_readdata(rdata); cifs_stats_fail_inc(io_parms.tcon, SMB2_READ_HE); trace_smb3_read_err(0 /* xid */, io_parms.persistent_fid, io_parms.tcon->tid, diff --git a/fs/smb/client/smb2proto.h b/fs/smb/client/smb2proto.h index 732169d8a67a..740053c0118e 100644 --- a/fs/smb/client/smb2proto.h +++ b/fs/smb/client/smb2proto.h @@ -210,7 +210,7 @@ extern int SMB2_query_acl(const unsigned int xid, struct cifs_tcon *tcon, extern int SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid, __le64 *uniqueid); -extern int smb2_async_readv(struct cifs_readdata *rdata); +extern int smb2_async_readv(struct cifs_io_subrequest *rdata); extern int SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms, unsigned int *nbytes, char **buf, int *buf_type); extern int smb2_async_writev(struct cifs_writedata *wdata, diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c index ddf1a3aafee5..dcc10a105b56 100644 --- a/fs/smb/client/transport.c +++ b/fs/smb/client/transport.c @@ -1692,7 +1692,7 @@ __cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid, static int cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid) { - struct cifs_readdata *rdata = mid->callback_data; + struct cifs_io_subrequest *rdata = mid->callback_data; return __cifs_readv_discard(server, mid, rdata->result); } @@ -1702,7 +1702,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) { int length, len; unsigned int data_offset, data_len; - struct cifs_readdata *rdata = mid->callback_data; + struct cifs_io_subrequest *rdata = mid->callback_data; char *buf = server->smallbuf; unsigned int buflen = server->pdu_size + HEADER_PREAMBLE_SIZE(server); bool use_rdma_mr = false; -- cgit From a975a2f22cdce7ec0c678ce8d73d2f6616cb281c Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 6 Oct 2023 16:27:41 +0100 Subject: cifs: Replace cifs_writedata with a wrapper around netfs_io_subrequest Replace the cifs_writedata struct with the same wrapper around netfs_io_subrequest that was used to replace cifs_readdata. Signed-off-by: David Howells cc: Steve French cc: Shyam Prasad N cc: Rohith Surabattula cc: Jeff Layton cc: linux-cifs@vger.kernel.org cc: netfs@lists.linux.dev cc: linux-fsdevel@vger.kernel.org cc: linux-mm@kvack.org --- fs/smb/client/cifsglob.h | 32 ++++--------------- fs/smb/client/cifsproto.h | 16 +++++++--- fs/smb/client/cifssmb.c | 9 +++--- fs/smb/client/file.c | 79 +++++++++++++++++++---------------------------- fs/smb/client/smb2pdu.c | 9 +++--- fs/smb/client/smb2proto.h | 3 +- 6 files changed, 59 insertions(+), 89 deletions(-) (limited to 'fs/smb') diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 405110052e17..7c07cf8cc29d 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -269,7 +269,6 @@ struct cifs_fattr; struct smb3_fs_context; struct cifs_fid; struct cifs_io_subrequest; -struct cifs_writedata; struct cifs_io_parms; struct cifs_search_info; struct cifsInodeInfo; @@ -452,8 +451,7 @@ struct smb_version_operations { /* async read from the server */ int (*async_readv)(struct cifs_io_subrequest *); /* async write to the server */ - int (*async_writev)(struct cifs_writedata *, - void (*release)(struct kref *)); + int (*async_writev)(struct cifs_io_subrequest *); /* sync read from the server */ int (*sync_read)(const unsigned int, struct cifs_fid *, struct cifs_io_parms *, unsigned int *, char **, @@ -1508,36 +1506,18 @@ struct cifs_io_subrequest { #endif struct cifs_credits credits; - // TODO: Remove following elements - struct list_head list; - struct completion done; - struct work_struct work; - struct iov_iter iter; - __u64 offset; - unsigned int bytes; -}; + enum writeback_sync_modes sync_mode; + bool uncached; + bool replay; + struct bio_vec *bv; -/* asynchronous write support */ -struct cifs_writedata { - struct kref refcount; + // TODO: Remove following elements struct list_head list; struct completion done; - enum writeback_sync_modes sync_mode; struct work_struct work; - struct cifsFileInfo *cfile; - struct cifs_aio_ctx *ctx; struct iov_iter iter; - struct bio_vec *bv; __u64 offset; - pid_t pid; unsigned int bytes; - int result; - struct TCP_Server_Info *server; -#ifdef CONFIG_CIFS_SMB_DIRECT - struct smbd_mr *mr; -#endif - struct cifs_credits credits; - bool replay; }; /* diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h index 5712f789eaa0..cb5cc5711a84 100644 --- a/fs/smb/client/cifsproto.h +++ b/fs/smb/client/cifsproto.h @@ -612,11 +612,19 @@ static inline void cifs_put_readdata(struct cifs_io_subrequest *rdata) int cifs_async_readv(struct cifs_io_subrequest *rdata); int cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid); -int cifs_async_writev(struct cifs_writedata *wdata, - void (*release)(struct kref *kref)); +int cifs_async_writev(struct cifs_io_subrequest *wdata); void cifs_writev_complete(struct work_struct *work); -struct cifs_writedata *cifs_writedata_alloc(work_func_t complete); -void cifs_writedata_release(struct kref *refcount); +struct cifs_io_subrequest *cifs_writedata_alloc(work_func_t complete); +void cifs_writedata_release(struct cifs_io_subrequest *rdata); +static inline void cifs_get_writedata(struct cifs_io_subrequest *wdata) +{ + refcount_inc(&wdata->subreq.ref); +} +static inline void cifs_put_writedata(struct cifs_io_subrequest *wdata) +{ + if (refcount_dec_and_test(&wdata->subreq.ref)) + cifs_writedata_release(wdata); +} int cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, struct cifs_sb_info *cifs_sb, const unsigned char *path, char *pbuf, diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index 2aaeae6c5766..30d24b4fbdf6 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -1612,7 +1612,7 @@ CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms, static void cifs_writev_callback(struct mid_q_entry *mid) { - struct cifs_writedata *wdata = mid->callback_data; + struct cifs_io_subrequest *wdata = mid->callback_data; struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink); unsigned int written; WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf; @@ -1657,8 +1657,7 @@ cifs_writev_callback(struct mid_q_entry *mid) /* cifs_async_writev - send an async write, and set up mid to handle result */ int -cifs_async_writev(struct cifs_writedata *wdata, - void (*release)(struct kref *kref)) +cifs_async_writev(struct cifs_io_subrequest *wdata) { int rc = -EACCES; WRITE_REQ *smb = NULL; @@ -1725,14 +1724,14 @@ cifs_async_writev(struct cifs_writedata *wdata, iov[1].iov_len += 4; /* pad bigger by four bytes */ } - kref_get(&wdata->refcount); + cifs_get_writedata(wdata); rc = cifs_call_async(tcon->ses->server, &rqst, NULL, cifs_writev_callback, NULL, wdata, 0, NULL); if (rc == 0) cifs_stats_inc(&tcon->stats.cifs_stats.num_writes); else - kref_put(&wdata->refcount, release); + cifs_put_writedata(wdata); async_writev_out: cifs_small_buf_release(smb); diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c index 0bea058099d4..2a0982b2d577 100644 --- a/fs/smb/client/file.c +++ b/fs/smb/client/file.c @@ -2510,10 +2510,10 @@ cifs_get_readable_path(struct cifs_tcon *tcon, const char *name, } void -cifs_writedata_release(struct kref *refcount) +cifs_writedata_release(struct cifs_io_subrequest *wdata) { - struct cifs_writedata *wdata = container_of(refcount, - struct cifs_writedata, refcount); + if (wdata->uncached) + kref_put(&wdata->ctx->refcount, cifs_aio_ctx_release); #ifdef CONFIG_CIFS_SMB_DIRECT if (wdata->mr) { smbd_deregister_mr(wdata->mr); @@ -2532,7 +2532,7 @@ cifs_writedata_release(struct kref *refcount) * possible that the page was redirtied so re-clean the page. */ static void -cifs_writev_requeue(struct cifs_writedata *wdata) +cifs_writev_requeue(struct cifs_io_subrequest *wdata) { int rc = 0; struct inode *inode = d_inode(wdata->cfile->dentry); @@ -2542,7 +2542,7 @@ cifs_writev_requeue(struct cifs_writedata *wdata) server = tlink_tcon(wdata->cfile->tlink)->ses->server; do { - struct cifs_writedata *wdata2; + struct cifs_io_subrequest *wdata2; unsigned int wsize, cur_len; wsize = server->ops->wp_retry_size(inode); @@ -2565,7 +2565,7 @@ cifs_writev_requeue(struct cifs_writedata *wdata) wdata2->sync_mode = wdata->sync_mode; wdata2->offset = fpos; wdata2->bytes = cur_len; - wdata2->iter = wdata->iter; + wdata2->iter = wdata->iter; iov_iter_advance(&wdata2->iter, fpos - wdata->offset); iov_iter_truncate(&wdata2->iter, wdata2->bytes); @@ -2587,11 +2587,10 @@ cifs_writev_requeue(struct cifs_writedata *wdata) rc = -EBADF; } else { wdata2->pid = wdata2->cfile->pid; - rc = server->ops->async_writev(wdata2, - cifs_writedata_release); + rc = server->ops->async_writev(wdata2); } - kref_put(&wdata2->refcount, cifs_writedata_release); + cifs_put_writedata(wdata2); if (rc) { if (is_retryable_error(rc)) continue; @@ -2610,14 +2609,14 @@ cifs_writev_requeue(struct cifs_writedata *wdata) if (rc != 0 && !is_retryable_error(rc)) mapping_set_error(inode->i_mapping, rc); - kref_put(&wdata->refcount, cifs_writedata_release); + cifs_put_writedata(wdata); } void cifs_writev_complete(struct work_struct *work) { - struct cifs_writedata *wdata = container_of(work, - struct cifs_writedata, work); + struct cifs_io_subrequest *wdata = container_of(work, + struct cifs_io_subrequest, work); struct inode *inode = d_inode(wdata->cfile->dentry); if (wdata->result == 0) { @@ -2638,16 +2637,16 @@ cifs_writev_complete(struct work_struct *work) if (wdata->result != -EAGAIN) mapping_set_error(inode->i_mapping, wdata->result); - kref_put(&wdata->refcount, cifs_writedata_release); + cifs_put_writedata(wdata); } -struct cifs_writedata *cifs_writedata_alloc(work_func_t complete) +struct cifs_io_subrequest *cifs_writedata_alloc(work_func_t complete) { - struct cifs_writedata *wdata; + struct cifs_io_subrequest *wdata; wdata = kzalloc(sizeof(*wdata), GFP_NOFS); if (wdata != NULL) { - kref_init(&wdata->refcount); + refcount_set(&wdata->subreq.ref, 1); INIT_LIST_HEAD(&wdata->list); init_completion(&wdata->done); INIT_WORK(&wdata->work, complete); @@ -2778,7 +2777,7 @@ static ssize_t cifs_write_back_from_locked_folio(struct address_space *mapping, { struct inode *inode = mapping->host; struct TCP_Server_Info *server; - struct cifs_writedata *wdata; + struct cifs_io_subrequest *wdata; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifs_credits credits_on_stack; struct cifs_credits *credits = &credits_on_stack; @@ -2871,10 +2870,9 @@ static ssize_t cifs_write_back_from_locked_folio(struct address_space *mapping, if (wdata->cfile->invalidHandle) rc = -EAGAIN; else - rc = wdata->server->ops->async_writev(wdata, - cifs_writedata_release); + rc = wdata->server->ops->async_writev(wdata); if (rc >= 0) { - kref_put(&wdata->refcount, cifs_writedata_release); + cifs_put_writedata(wdata); goto err_close; } } else { @@ -2884,7 +2882,7 @@ static ssize_t cifs_write_back_from_locked_folio(struct address_space *mapping, } err_wdata: - kref_put(&wdata->refcount, cifs_writedata_release); + cifs_put_writedata(wdata); err_uncredit: add_credits_and_wake_if(server, credits, 0); err_close: @@ -3261,23 +3259,13 @@ int cifs_flush(struct file *file, fl_owner_t id) return rc; } -static void -cifs_uncached_writedata_release(struct kref *refcount) -{ - struct cifs_writedata *wdata = container_of(refcount, - struct cifs_writedata, refcount); - - kref_put(&wdata->ctx->refcount, cifs_aio_ctx_release); - cifs_writedata_release(refcount); -} - static void collect_uncached_write_data(struct cifs_aio_ctx *ctx); static void cifs_uncached_writev_complete(struct work_struct *work) { - struct cifs_writedata *wdata = container_of(work, - struct cifs_writedata, work); + struct cifs_io_subrequest *wdata = container_of(work, + struct cifs_io_subrequest, work); struct inode *inode = d_inode(wdata->cfile->dentry); struct cifsInodeInfo *cifsi = CIFS_I(inode); @@ -3290,11 +3278,11 @@ cifs_uncached_writev_complete(struct work_struct *work) complete(&wdata->done); collect_uncached_write_data(wdata->ctx); /* the below call can possibly free the last ref to aio ctx */ - kref_put(&wdata->refcount, cifs_uncached_writedata_release); + cifs_put_writedata(wdata); } static int -cifs_resend_wdata(struct cifs_writedata *wdata, struct list_head *wdata_list, +cifs_resend_wdata(struct cifs_io_subrequest *wdata, struct list_head *wdata_list, struct cifs_aio_ctx *ctx) { unsigned int wsize; @@ -3344,8 +3332,7 @@ cifs_resend_wdata(struct cifs_writedata *wdata, struct list_head *wdata_list, wdata->mr = NULL; } #endif - rc = server->ops->async_writev(wdata, - cifs_uncached_writedata_release); + rc = server->ops->async_writev(wdata); } } @@ -3360,7 +3347,7 @@ cifs_resend_wdata(struct cifs_writedata *wdata, struct list_head *wdata_list, } while (rc == -EAGAIN); fail: - kref_put(&wdata->refcount, cifs_uncached_writedata_release); + cifs_put_writedata(wdata); return rc; } @@ -3412,7 +3399,7 @@ cifs_write_from_iter(loff_t fpos, size_t len, struct iov_iter *from, { int rc = 0; size_t cur_len, max_len; - struct cifs_writedata *wdata; + struct cifs_io_subrequest *wdata; pid_t pid; struct TCP_Server_Info *server; unsigned int xid, max_segs = INT_MAX; @@ -3476,6 +3463,7 @@ cifs_write_from_iter(loff_t fpos, size_t len, struct iov_iter *from, break; } + wdata->uncached = true; wdata->sync_mode = WB_SYNC_ALL; wdata->offset = (__u64)fpos; wdata->cfile = cifsFileInfo_get(open_file); @@ -3495,14 +3483,12 @@ cifs_write_from_iter(loff_t fpos, size_t len, struct iov_iter *from, if (wdata->cfile->invalidHandle) rc = -EAGAIN; else - rc = server->ops->async_writev(wdata, - cifs_uncached_writedata_release); + rc = server->ops->async_writev(wdata); } if (rc) { add_credits_and_wake_if(server, &wdata->credits, 0); - kref_put(&wdata->refcount, - cifs_uncached_writedata_release); + cifs_put_writedata(wdata); if (rc == -EAGAIN) continue; break; @@ -3520,7 +3506,7 @@ cifs_write_from_iter(loff_t fpos, size_t len, struct iov_iter *from, static void collect_uncached_write_data(struct cifs_aio_ctx *ctx) { - struct cifs_writedata *wdata, *tmp; + struct cifs_io_subrequest *wdata, *tmp; struct cifs_tcon *tcon; struct cifs_sb_info *cifs_sb; struct dentry *dentry = ctx->cfile->dentry; @@ -3575,8 +3561,7 @@ restart_loop: ctx->cfile, cifs_sb, &tmp_list, ctx); - kref_put(&wdata->refcount, - cifs_uncached_writedata_release); + cifs_put_writedata(wdata); } list_splice(&tmp_list, &ctx->list); @@ -3584,7 +3569,7 @@ restart_loop: } } list_del_init(&wdata->list); - kref_put(&wdata->refcount, cifs_uncached_writedata_release); + cifs_put_writedata(wdata); } cifs_stats_bytes_written(tcon, ctx->total_len); diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index 0957dd4c07e7..8143611ba336 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -4737,7 +4737,7 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms, static void smb2_writev_callback(struct mid_q_entry *mid) { - struct cifs_writedata *wdata = mid->callback_data; + struct cifs_io_subrequest *wdata = mid->callback_data; struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink); struct TCP_Server_Info *server = wdata->server; unsigned int written; @@ -4818,8 +4818,7 @@ smb2_writev_callback(struct mid_q_entry *mid) /* smb2_async_writev - send an async write, and set up mid to handle result */ int -smb2_async_writev(struct cifs_writedata *wdata, - void (*release)(struct kref *kref)) +smb2_async_writev(struct cifs_io_subrequest *wdata) { int rc = -EACCES, flags = 0; struct smb2_write_req *req = NULL; @@ -4953,7 +4952,7 @@ smb2_async_writev(struct cifs_writedata *wdata, flags |= CIFS_HAS_CREDITS; } - kref_get(&wdata->refcount); + cifs_get_writedata(wdata); rc = cifs_call_async(server, &rqst, NULL, smb2_writev_callback, NULL, wdata, flags, &wdata->credits); @@ -4965,7 +4964,7 @@ smb2_async_writev(struct cifs_writedata *wdata, io_parms->offset, io_parms->length, rc); - kref_put(&wdata->refcount, release); + cifs_put_writedata(wdata); cifs_stats_fail_inc(tcon, SMB2_WRITE_HE); } diff --git a/fs/smb/client/smb2proto.h b/fs/smb/client/smb2proto.h index 740053c0118e..c781eaa0cba8 100644 --- a/fs/smb/client/smb2proto.h +++ b/fs/smb/client/smb2proto.h @@ -213,8 +213,7 @@ extern int SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon, extern int smb2_async_readv(struct cifs_io_subrequest *rdata); extern int SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms, unsigned int *nbytes, char **buf, int *buf_type); -extern int smb2_async_writev(struct cifs_writedata *wdata, - void (*release)(struct kref *kref)); +extern int smb2_async_writev(struct cifs_io_subrequest *wdata); extern int SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms, unsigned int *nbytes, struct kvec *iov, int n_vec); extern int SMB2_echo(struct TCP_Server_Info *server); -- cgit From ab58fbdeebc7f9fe8b9bc202660eae3a10e5e678 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 6 Oct 2023 16:55:20 +0100 Subject: cifs: Use more fields from netfs_io_subrequest Use more fields from netfs_io_subrequest instead of those incorporated into cifs_io_subrequest from cifs_readdata and cifs_writedata. Signed-off-by: David Howells cc: Steve French cc: Shyam Prasad N cc: Rohith Surabattula cc: Jeff Layton cc: linux-cifs@vger.kernel.org cc: netfs@lists.linux.dev cc: linux-fsdevel@vger.kernel.org cc: linux-mm@kvack.org --- fs/smb/client/cifsglob.h | 3 -- fs/smb/client/cifssmb.c | 52 ++++++++++----------- fs/smb/client/file.c | 112 +++++++++++++++++++++++----------------------- fs/smb/client/smb2ops.c | 4 +- fs/smb/client/smb2pdu.c | 52 ++++++++++----------- fs/smb/client/transport.c | 6 +-- 6 files changed, 113 insertions(+), 116 deletions(-) (limited to 'fs/smb') diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 7c07cf8cc29d..5100aa047ed6 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -1515,9 +1515,6 @@ struct cifs_io_subrequest { struct list_head list; struct completion done; struct work_struct work; - struct iov_iter iter; - __u64 offset; - unsigned int bytes; }; /* diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index 30d24b4fbdf6..99b75102ba6b 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -1269,12 +1269,12 @@ cifs_readv_callback(struct mid_q_entry *mid) struct TCP_Server_Info *server = tcon->ses->server; struct smb_rqst rqst = { .rq_iov = rdata->iov, .rq_nvec = 2, - .rq_iter = rdata->iter }; + .rq_iter = rdata->subreq.io_iter }; struct cifs_credits credits = { .value = 1, .instance = 0 }; - cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n", + cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%zu\n", __func__, mid->mid, mid->mid_state, rdata->result, - rdata->bytes); + rdata->subreq.len); switch (mid->mid_state) { case MID_RESPONSE_RECEIVED: @@ -1322,14 +1322,14 @@ cifs_async_readv(struct cifs_io_subrequest *rdata) struct smb_rqst rqst = { .rq_iov = rdata->iov, .rq_nvec = 2 }; - cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n", - __func__, rdata->offset, rdata->bytes); + cifs_dbg(FYI, "%s: offset=%llu bytes=%zu\n", + __func__, rdata->subreq.start, rdata->subreq.len); if (tcon->ses->capabilities & CAP_LARGE_FILES) wct = 12; else { wct = 10; /* old style read */ - if ((rdata->offset >> 32) > 0) { + if ((rdata->subreq.start >> 32) > 0) { /* can not handle this big offset for old */ return -EIO; } @@ -1344,12 +1344,12 @@ cifs_async_readv(struct cifs_io_subrequest *rdata) smb->AndXCommand = 0xFF; /* none */ smb->Fid = rdata->cfile->fid.netfid; - smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF); + smb->OffsetLow = cpu_to_le32(rdata->subreq.start & 0xFFFFFFFF); if (wct == 12) - smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32); + smb->OffsetHigh = cpu_to_le32(rdata->subreq.start >> 32); smb->Remaining = 0; - smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF); - smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16); + smb->MaxCount = cpu_to_le16(rdata->subreq.len & 0xFFFF); + smb->MaxCountHigh = cpu_to_le32(rdata->subreq.len >> 16); if (wct == 12) smb->ByteCount = 0; else { @@ -1633,13 +1633,13 @@ cifs_writev_callback(struct mid_q_entry *mid) * client. OS/2 servers are known to set incorrect * CountHigh values. */ - if (written > wdata->bytes) + if (written > wdata->subreq.len) written &= 0xFFFF; - if (written < wdata->bytes) + if (written < wdata->subreq.len) wdata->result = -ENOSPC; else - wdata->bytes = written; + wdata->subreq.len = written; break; case MID_REQUEST_SUBMITTED: case MID_RETRY_NEEDED: @@ -1670,7 +1670,7 @@ cifs_async_writev(struct cifs_io_subrequest *wdata) wct = 14; } else { wct = 12; - if (wdata->offset >> 32 > 0) { + if (wdata->subreq.start >> 32 > 0) { /* can not handle big offset for old srv */ return -EIO; } @@ -1685,9 +1685,9 @@ cifs_async_writev(struct cifs_io_subrequest *wdata) smb->AndXCommand = 0xFF; /* none */ smb->Fid = wdata->cfile->fid.netfid; - smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF); + smb->OffsetLow = cpu_to_le32(wdata->subreq.start & 0xFFFFFFFF); if (wct == 14) - smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32); + smb->OffsetHigh = cpu_to_le32(wdata->subreq.start >> 32); smb->Reserved = 0xFFFFFFFF; smb->WriteMode = 0; smb->Remaining = 0; @@ -1703,24 +1703,24 @@ cifs_async_writev(struct cifs_io_subrequest *wdata) rqst.rq_iov = iov; rqst.rq_nvec = 2; - rqst.rq_iter = wdata->iter; - rqst.rq_iter_size = iov_iter_count(&wdata->iter); + rqst.rq_iter = wdata->subreq.io_iter; + rqst.rq_iter_size = iov_iter_count(&wdata->subreq.io_iter); - cifs_dbg(FYI, "async write at %llu %u bytes\n", - wdata->offset, wdata->bytes); + cifs_dbg(FYI, "async write at %llu %zu bytes\n", + wdata->subreq.start, wdata->subreq.len); - smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF); - smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16); + smb->DataLengthLow = cpu_to_le16(wdata->subreq.len & 0xFFFF); + smb->DataLengthHigh = cpu_to_le16(wdata->subreq.len >> 16); if (wct == 14) { - inc_rfc1001_len(&smb->hdr, wdata->bytes + 1); - put_bcc(wdata->bytes + 1, &smb->hdr); + inc_rfc1001_len(&smb->hdr, wdata->subreq.len + 1); + put_bcc(wdata->subreq.len + 1, &smb->hdr); } else { /* wct == 12 */ struct smb_com_writex_req *smbw = (struct smb_com_writex_req *)smb; - inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5); - put_bcc(wdata->bytes + 5, &smbw->hdr); + inc_rfc1001_len(&smbw->hdr, wdata->subreq.len + 5); + put_bcc(wdata->subreq.len + 5, &smbw->hdr); iov[1].iov_len += 4; /* pad bigger by four bytes */ } diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c index 2a0982b2d577..7528f6436ec4 100644 --- a/fs/smb/client/file.c +++ b/fs/smb/client/file.c @@ -2537,8 +2537,8 @@ cifs_writev_requeue(struct cifs_io_subrequest *wdata) int rc = 0; struct inode *inode = d_inode(wdata->cfile->dentry); struct TCP_Server_Info *server; - unsigned int rest_len = wdata->bytes; - loff_t fpos = wdata->offset; + unsigned int rest_len = wdata->subreq.len; + loff_t fpos = wdata->subreq.start; server = tlink_tcon(wdata->cfile->tlink)->ses->server; do { @@ -2563,14 +2563,14 @@ cifs_writev_requeue(struct cifs_io_subrequest *wdata) } wdata2->sync_mode = wdata->sync_mode; - wdata2->offset = fpos; - wdata2->bytes = cur_len; - wdata2->iter = wdata->iter; + wdata2->subreq.start = fpos; + wdata2->subreq.len = cur_len; + wdata2->subreq.io_iter = wdata->subreq.io_iter; - iov_iter_advance(&wdata2->iter, fpos - wdata->offset); - iov_iter_truncate(&wdata2->iter, wdata2->bytes); + iov_iter_advance(&wdata2->subreq.io_iter, fpos - wdata->subreq.start); + iov_iter_truncate(&wdata2->subreq.io_iter, wdata2->subreq.len); - if (iov_iter_is_xarray(&wdata2->iter)) + if (iov_iter_is_xarray(&wdata2->subreq.io_iter)) /* Check for pages having been redirtied and clean * them. We can do this by walking the xarray. If * it's not an xarray, then it's a DIO and we shouldn't @@ -2604,7 +2604,7 @@ cifs_writev_requeue(struct cifs_io_subrequest *wdata) } while (rest_len > 0); /* Clean up remaining pages from the original wdata */ - if (iov_iter_is_xarray(&wdata->iter)) + if (iov_iter_is_xarray(&wdata->subreq.io_iter)) cifs_pages_write_failed(inode, fpos, rest_len); if (rc != 0 && !is_retryable_error(rc)) @@ -2621,19 +2621,19 @@ cifs_writev_complete(struct work_struct *work) if (wdata->result == 0) { spin_lock(&inode->i_lock); - cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes); + cifs_update_eof(CIFS_I(inode), wdata->subreq.start, wdata->subreq.len); spin_unlock(&inode->i_lock); cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink), - wdata->bytes); + wdata->subreq.len); } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN) return cifs_writev_requeue(wdata); if (wdata->result == -EAGAIN) - cifs_pages_write_redirty(inode, wdata->offset, wdata->bytes); + cifs_pages_write_redirty(inode, wdata->subreq.start, wdata->subreq.len); else if (wdata->result < 0) - cifs_pages_write_failed(inode, wdata->offset, wdata->bytes); + cifs_pages_write_failed(inode, wdata->subreq.start, wdata->subreq.len); else - cifs_pages_written_back(inode, wdata->offset, wdata->bytes); + cifs_pages_written_back(inode, wdata->subreq.start, wdata->subreq.len); if (wdata->result != -EAGAIN) mapping_set_error(inode->i_mapping, wdata->result); @@ -2816,7 +2816,7 @@ static ssize_t cifs_write_back_from_locked_folio(struct address_space *mapping, } wdata->sync_mode = wbc->sync_mode; - wdata->offset = folio_pos(folio); + wdata->subreq.start = folio_pos(folio); wdata->pid = cfile->pid; wdata->credits = credits_on_stack; wdata->cfile = cfile; @@ -2857,13 +2857,13 @@ static ssize_t cifs_write_back_from_locked_folio(struct address_space *mapping, * have been unlocked. */ folio_unlock(folio); - wdata->bytes = len; + wdata->subreq.len = len; if (start < i_size) { - iov_iter_xarray(&wdata->iter, ITER_SOURCE, &mapping->i_pages, + iov_iter_xarray(&wdata->subreq.io_iter, ITER_SOURCE, &mapping->i_pages, start, len); - rc = adjust_credits(wdata->server, &wdata->credits, wdata->bytes); + rc = adjust_credits(wdata->server, &wdata->credits, wdata->subreq.len); if (rc) goto err_wdata; @@ -3270,7 +3270,7 @@ cifs_uncached_writev_complete(struct work_struct *work) struct cifsInodeInfo *cifsi = CIFS_I(inode); spin_lock(&inode->i_lock); - cifs_update_eof(cifsi, wdata->offset, wdata->bytes); + cifs_update_eof(cifsi, wdata->subreq.start, wdata->subreq.len); if (cifsi->netfs.remote_i_size > inode->i_size) i_size_write(inode, cifsi->netfs.remote_i_size); spin_unlock(&inode->i_lock); @@ -3306,19 +3306,19 @@ cifs_resend_wdata(struct cifs_io_subrequest *wdata, struct list_head *wdata_list * segments */ do { - rc = server->ops->wait_mtu_credits(server, wdata->bytes, + rc = server->ops->wait_mtu_credits(server, wdata->subreq.len, &wsize, &credits); if (rc) goto fail; - if (wsize < wdata->bytes) { + if (wsize < wdata->subreq.len) { add_credits_and_wake_if(server, &credits, 0); msleep(1000); } - } while (wsize < wdata->bytes); + } while (wsize < wdata->subreq.len); wdata->credits = credits; - rc = adjust_credits(server, &wdata->credits, wdata->bytes); + rc = adjust_credits(server, &wdata->credits, wdata->subreq.len); if (!rc) { if (wdata->cfile->invalidHandle) @@ -3465,19 +3465,19 @@ cifs_write_from_iter(loff_t fpos, size_t len, struct iov_iter *from, wdata->uncached = true; wdata->sync_mode = WB_SYNC_ALL; - wdata->offset = (__u64)fpos; + wdata->subreq.start = (__u64)fpos; wdata->cfile = cifsFileInfo_get(open_file); wdata->server = server; wdata->pid = pid; - wdata->bytes = cur_len; + wdata->subreq.len = cur_len; wdata->credits = credits_on_stack; - wdata->iter = *from; + wdata->subreq.io_iter = *from; wdata->ctx = ctx; kref_get(&ctx->refcount); - iov_iter_truncate(&wdata->iter, cur_len); + iov_iter_truncate(&wdata->subreq.io_iter, cur_len); - rc = adjust_credits(server, &wdata->credits, wdata->bytes); + rc = adjust_credits(server, &wdata->credits, wdata->subreq.len); if (!rc) { if (wdata->cfile->invalidHandle) @@ -3539,7 +3539,7 @@ restart_loop: if (wdata->result) rc = wdata->result; else - ctx->total_len += wdata->bytes; + ctx->total_len += wdata->subreq.len; /* resend call if it's a retryable error */ if (rc == -EAGAIN) { @@ -3554,10 +3554,10 @@ restart_loop: wdata, &tmp_list, ctx); else { iov_iter_advance(&tmp_from, - wdata->offset - ctx->pos); + wdata->subreq.start - ctx->pos); - rc = cifs_write_from_iter(wdata->offset, - wdata->bytes, &tmp_from, + rc = cifs_write_from_iter(wdata->subreq.start, + wdata->subreq.len, &tmp_from, ctx->cfile, cifs_sb, &tmp_list, ctx); @@ -3880,20 +3880,20 @@ static int cifs_resend_rdata(struct cifs_io_subrequest *rdata, * segments */ do { - rc = server->ops->wait_mtu_credits(server, rdata->bytes, + rc = server->ops->wait_mtu_credits(server, rdata->subreq.len, &rsize, &credits); if (rc) goto fail; - if (rsize < rdata->bytes) { + if (rsize < rdata->subreq.len) { add_credits_and_wake_if(server, &credits, 0); msleep(1000); } - } while (rsize < rdata->bytes); + } while (rsize < rdata->subreq.len); rdata->credits = credits; - rc = adjust_credits(server, &rdata->credits, rdata->bytes); + rc = adjust_credits(server, &rdata->credits, rdata->subreq.len); if (!rc) { if (rdata->cfile->invalidHandle) rc = -EAGAIN; @@ -3991,17 +3991,17 @@ cifs_send_async_read(loff_t fpos, size_t len, struct cifsFileInfo *open_file, rdata->server = server; rdata->cfile = cifsFileInfo_get(open_file); - rdata->offset = fpos; - rdata->bytes = cur_len; + rdata->subreq.start = fpos; + rdata->subreq.len = cur_len; rdata->pid = pid; rdata->credits = credits_on_stack; rdata->ctx = ctx; kref_get(&ctx->refcount); - rdata->iter = ctx->iter; - iov_iter_truncate(&rdata->iter, cur_len); + rdata->subreq.io_iter = ctx->iter; + iov_iter_truncate(&rdata->subreq.io_iter, cur_len); - rc = adjust_credits(server, &rdata->credits, rdata->bytes); + rc = adjust_credits(server, &rdata->credits, rdata->subreq.len); if (!rc) { if (rdata->cfile->invalidHandle) @@ -4071,8 +4071,8 @@ again: &tmp_list, ctx); } else { rc = cifs_send_async_read( - rdata->offset + got_bytes, - rdata->bytes - got_bytes, + rdata->subreq.start + got_bytes, + rdata->subreq.len - got_bytes, rdata->cfile, cifs_sb, &tmp_list, ctx); @@ -4086,7 +4086,7 @@ again: rc = rdata->result; /* if there was a short read -- discard anything left */ - if (rdata->got_bytes && rdata->got_bytes < rdata->bytes) + if (rdata->got_bytes && rdata->got_bytes < rdata->subreq.len) rc = -ENODATA; ctx->total_len += rdata->got_bytes; @@ -4470,16 +4470,16 @@ static void cifs_readahead_complete(struct work_struct *work) pgoff_t last; bool good = rdata->result == 0 || (rdata->result == -EAGAIN && rdata->got_bytes); - XA_STATE(xas, &rdata->mapping->i_pages, rdata->offset / PAGE_SIZE); + XA_STATE(xas, &rdata->mapping->i_pages, rdata->subreq.start / PAGE_SIZE); if (good) cifs_readahead_to_fscache(rdata->mapping->host, - rdata->offset, rdata->bytes); + rdata->subreq.start, rdata->subreq.len); - if (iov_iter_count(&rdata->iter) > 0) - iov_iter_zero(iov_iter_count(&rdata->iter), &rdata->iter); + if (iov_iter_count(&rdata->subreq.io_iter) > 0) + iov_iter_zero(iov_iter_count(&rdata->subreq.io_iter), &rdata->subreq.io_iter); - last = (rdata->offset + rdata->bytes - 1) / PAGE_SIZE; + last = (rdata->subreq.start + rdata->subreq.len - 1) / PAGE_SIZE; rcu_read_lock(); xas_for_each(&xas, folio, last) { @@ -4618,8 +4618,8 @@ static void cifs_readahead(struct readahead_control *ractl) break; } - rdata->offset = ra_index * PAGE_SIZE; - rdata->bytes = nr_pages * PAGE_SIZE; + rdata->subreq.start = ra_index * PAGE_SIZE; + rdata->subreq.len = nr_pages * PAGE_SIZE; rdata->cfile = cifsFileInfo_get(open_file); rdata->server = server; rdata->mapping = ractl->mapping; @@ -4633,10 +4633,10 @@ static void cifs_readahead(struct readahead_control *ractl) ra_pages -= nr_pages; ra_index += nr_pages; - iov_iter_xarray(&rdata->iter, ITER_DEST, &rdata->mapping->i_pages, - rdata->offset, rdata->bytes); + iov_iter_xarray(&rdata->subreq.io_iter, ITER_DEST, &rdata->mapping->i_pages, + rdata->subreq.start, rdata->subreq.len); - rc = adjust_credits(server, &rdata->credits, rdata->bytes); + rc = adjust_credits(server, &rdata->credits, rdata->subreq.len); if (!rc) { if (rdata->cfile->invalidHandle) rc = -EAGAIN; @@ -4647,8 +4647,8 @@ static void cifs_readahead(struct readahead_control *ractl) if (rc) { add_credits_and_wake_if(server, &rdata->credits, 0); cifs_unlock_folios(rdata->mapping, - rdata->offset / PAGE_SIZE, - (rdata->offset + rdata->bytes - 1) / PAGE_SIZE); + rdata->subreq.start / PAGE_SIZE, + (rdata->subreq.start + rdata->subreq.len - 1) / PAGE_SIZE); /* Fallback to the readpage in error/reconnect cases */ cifs_put_readdata(rdata); break; diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index 56026f4cbc13..c13705c0e47f 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -4592,7 +4592,7 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid, /* Copy the data to the output I/O iterator. */ rdata->result = cifs_copy_pages_to_iter(pages, pages_len, - cur_off, &rdata->iter); + cur_off, &rdata->subreq.io_iter); if (rdata->result != 0) { if (is_offloaded) mid->mid_state = MID_RESPONSE_MALFORMED; @@ -4606,7 +4606,7 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid, /* read response payload is in buf */ WARN_ONCE(pages && !xa_empty(pages), "read data can be either in buf or in pages"); - length = copy_to_iter(buf + data_offset, data_len, &rdata->iter); + length = copy_to_iter(buf + data_offset, data_len, &rdata->subreq.io_iter); if (length < 0) return length; rdata->got_bytes = data_len; diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index 8143611ba336..ca8ba6878f9f 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -4434,7 +4434,7 @@ smb2_new_read_req(void **buf, unsigned int *total_len, struct smbd_buffer_descriptor_v1 *v1; bool need_invalidate = server->dialect == SMB30_PROT_ID; - rdata->mr = smbd_register_mr(server->smbd_conn, &rdata->iter, + rdata->mr = smbd_register_mr(server->smbd_conn, &rdata->subreq.io_iter, true, need_invalidate); if (!rdata->mr) return -EAGAIN; @@ -4494,17 +4494,17 @@ smb2_readv_callback(struct mid_q_entry *mid) struct smb_rqst rqst = { .rq_iov = &rdata->iov[1], .rq_nvec = 1 }; if (rdata->got_bytes) { - rqst.rq_iter = rdata->iter; - rqst.rq_iter_size = iov_iter_count(&rdata->iter); + rqst.rq_iter = rdata->subreq.io_iter; + rqst.rq_iter_size = iov_iter_count(&rdata->subreq.io_iter); } WARN_ONCE(rdata->server != mid->server, "rdata server %p != mid server %p", rdata->server, mid->server); - cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n", + cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%zu\n", __func__, mid->mid, mid->mid_state, rdata->result, - rdata->bytes); + rdata->subreq.len); switch (mid->mid_state) { case MID_RESPONSE_RECEIVED: @@ -4557,13 +4557,13 @@ smb2_readv_callback(struct mid_q_entry *mid) cifs_stats_fail_inc(tcon, SMB2_READ_HE); trace_smb3_read_err(0 /* xid */, rdata->cfile->fid.persistent_fid, - tcon->tid, tcon->ses->Suid, rdata->offset, - rdata->bytes, rdata->result); + tcon->tid, tcon->ses->Suid, rdata->subreq.start, + rdata->subreq.len, rdata->result); } else trace_smb3_read_done(0 /* xid */, rdata->cfile->fid.persistent_fid, tcon->tid, tcon->ses->Suid, - rdata->offset, rdata->got_bytes); + rdata->subreq.start, rdata->got_bytes); queue_work(cifsiod_wq, &rdata->work); release_mid(mid); @@ -4585,16 +4585,16 @@ smb2_async_readv(struct cifs_io_subrequest *rdata) unsigned int total_len; int credit_request; - cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n", - __func__, rdata->offset, rdata->bytes); + cifs_dbg(FYI, "%s: offset=%llu bytes=%zu\n", + __func__, rdata->subreq.start, rdata->subreq.len); if (!rdata->server) rdata->server = cifs_pick_channel(tcon->ses); io_parms.tcon = tlink_tcon(rdata->cfile->tlink); io_parms.server = server = rdata->server; - io_parms.offset = rdata->offset; - io_parms.length = rdata->bytes; + io_parms.offset = rdata->subreq.start; + io_parms.length = rdata->subreq.len; io_parms.persistent_fid = rdata->cfile->fid.persistent_fid; io_parms.volatile_fid = rdata->cfile->fid.volatile_fid; io_parms.pid = rdata->pid; @@ -4613,7 +4613,7 @@ smb2_async_readv(struct cifs_io_subrequest *rdata) shdr = (struct smb2_hdr *)buf; if (rdata->credits.value > 0) { - shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(rdata->bytes, + shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(rdata->subreq.len, SMB2_MAX_BUFFER_SIZE)); credit_request = le16_to_cpu(shdr->CreditCharge) + 8; if (server->credits >= server->max_credits) @@ -4623,7 +4623,7 @@ smb2_async_readv(struct cifs_io_subrequest *rdata) min_t(int, server->max_credits - server->credits, credit_request)); - rc = adjust_credits(server, &rdata->credits, rdata->bytes); + rc = adjust_credits(server, &rdata->credits, rdata->subreq.len); if (rc) goto async_readv_out; @@ -4763,13 +4763,13 @@ smb2_writev_callback(struct mid_q_entry *mid) * client. OS/2 servers are known to set incorrect * CountHigh values. */ - if (written > wdata->bytes) + if (written > wdata->subreq.len) written &= 0xFFFF; - if (written < wdata->bytes) + if (written < wdata->subreq.len) wdata->result = -ENOSPC; else - wdata->bytes = written; + wdata->subreq.len = written; break; case MID_REQUEST_SUBMITTED: case MID_RETRY_NEEDED: @@ -4800,8 +4800,8 @@ smb2_writev_callback(struct mid_q_entry *mid) cifs_stats_fail_inc(tcon, SMB2_WRITE_HE); trace_smb3_write_err(0 /* no xid */, wdata->cfile->fid.persistent_fid, - tcon->tid, tcon->ses->Suid, wdata->offset, - wdata->bytes, wdata->result); + tcon->tid, tcon->ses->Suid, wdata->subreq.start, + wdata->subreq.len, wdata->result); if (wdata->result == -ENOSPC) pr_warn_once("Out of space writing to %s\n", tcon->tree_name); @@ -4809,7 +4809,7 @@ smb2_writev_callback(struct mid_q_entry *mid) trace_smb3_write_done(0 /* no xid */, wdata->cfile->fid.persistent_fid, tcon->tid, tcon->ses->Suid, - wdata->offset, wdata->bytes); + wdata->subreq.start, wdata->subreq.len); queue_work(cifsiod_wq, &wdata->work); release_mid(mid); @@ -4842,8 +4842,8 @@ smb2_async_writev(struct cifs_io_subrequest *wdata) _io_parms = (struct cifs_io_parms) { .tcon = tcon, .server = server, - .offset = wdata->offset, - .length = wdata->bytes, + .offset = wdata->subreq.start, + .length = wdata->subreq.len, .persistent_fid = wdata->cfile->fid.persistent_fid, .volatile_fid = wdata->cfile->fid.volatile_fid, .pid = wdata->pid, @@ -4885,10 +4885,10 @@ smb2_async_writev(struct cifs_io_subrequest *wdata) */ if (smb3_use_rdma_offload(io_parms)) { struct smbd_buffer_descriptor_v1 *v1; - size_t data_size = iov_iter_count(&wdata->iter); + size_t data_size = iov_iter_count(&wdata->subreq.io_iter); bool need_invalidate = server->dialect == SMB30_PROT_ID; - wdata->mr = smbd_register_mr(server->smbd_conn, &wdata->iter, + wdata->mr = smbd_register_mr(server->smbd_conn, &wdata->subreq.io_iter, false, need_invalidate); if (!wdata->mr) { rc = -EAGAIN; @@ -4915,7 +4915,7 @@ smb2_async_writev(struct cifs_io_subrequest *wdata) rqst.rq_iov = iov; rqst.rq_nvec = 1; - rqst.rq_iter = wdata->iter; + rqst.rq_iter = wdata->subreq.io_iter; rqst.rq_iter_size = iov_iter_count(&rqst.rq_iter); if (wdata->replay) smb2_set_replay(server, &rqst); @@ -4935,7 +4935,7 @@ smb2_async_writev(struct cifs_io_subrequest *wdata) #endif if (wdata->credits.value > 0) { - shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(wdata->bytes, + shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(wdata->subreq.len, SMB2_MAX_BUFFER_SIZE)); credit_request = le16_to_cpu(shdr->CreditCharge) + 8; if (server->credits >= server->max_credits) diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c index dcc10a105b56..cccc1248c48a 100644 --- a/fs/smb/client/transport.c +++ b/fs/smb/client/transport.c @@ -1707,8 +1707,8 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) unsigned int buflen = server->pdu_size + HEADER_PREAMBLE_SIZE(server); bool use_rdma_mr = false; - cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n", - __func__, mid->mid, rdata->offset, rdata->bytes); + cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%zu\n", + __func__, mid->mid, rdata->subreq.start, rdata->subreq.len); /* * read the rest of READ_RSP header (sans Data array), or whatever we @@ -1813,7 +1813,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) length = data_len; /* An RDMA read is already done. */ else #endif - length = cifs_read_iter_from_socket(server, &rdata->iter, + length = cifs_read_iter_from_socket(server, &rdata->subreq.io_iter, data_len); if (length > 0) rdata->got_bytes += length; -- cgit From 56257334e8e0075515aedc44044a5585dcf7f465 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 6 Oct 2023 18:20:39 +0100 Subject: cifs: Make wait_mtu_credits take size_t args Make the wait_mtu_credits functions use size_t for the size and num arguments rather than unsigned int as netfslib uses size_t/ssize_t for arguments and return values to allow for extra capacity. Signed-off-by: David Howells cc: Steve French cc: Shyam Prasad N cc: Rohith Surabattula cc: Jeff Layton cc: linux-cifs@vger.kernel.org cc: linux-cachefs@redhat.com cc: netfs@lists.linux.dev cc: linux-mm@kvack.org --- fs/smb/client/cifsglob.h | 4 ++-- fs/smb/client/cifsproto.h | 2 +- fs/smb/client/file.c | 17 ++++++++++------- fs/smb/client/smb2ops.c | 4 ++-- fs/smb/client/transport.c | 4 ++-- 5 files changed, 17 insertions(+), 14 deletions(-) (limited to 'fs/smb') diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 5100aa047ed6..13161e0b5cc0 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -546,8 +546,8 @@ struct smb_version_operations { /* writepages retry size */ unsigned int (*wp_retry_size)(struct inode *); /* get mtu credits */ - int (*wait_mtu_credits)(struct TCP_Server_Info *, unsigned int, - unsigned int *, struct cifs_credits *); + int (*wait_mtu_credits)(struct TCP_Server_Info *, size_t, + size_t *, struct cifs_credits *); /* adjust previously taken mtu credits to request size */ int (*adjust_credits)(struct TCP_Server_Info *server, struct cifs_credits *credits, diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h index cb5cc5711a84..103f264b42d7 100644 --- a/fs/smb/client/cifsproto.h +++ b/fs/smb/client/cifsproto.h @@ -121,7 +121,7 @@ extern struct mid_q_entry *cifs_setup_async_request(struct TCP_Server_Info *, extern int cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server, bool log_error); extern int cifs_wait_mtu_credits(struct TCP_Server_Info *server, - unsigned int size, unsigned int *num, + size_t size, size_t *num, struct cifs_credits *credits); extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *, struct kvec *, int /* nvec to send */, diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c index 7528f6436ec4..4d8cd0d82104 100644 --- a/fs/smb/client/file.c +++ b/fs/smb/client/file.c @@ -2783,7 +2783,8 @@ static ssize_t cifs_write_back_from_locked_folio(struct address_space *mapping, struct cifs_credits *credits = &credits_on_stack; struct cifsFileInfo *cfile = NULL; unsigned long long i_size = i_size_read(inode), max_len; - unsigned int xid, wsize; + unsigned int xid; + size_t wsize; size_t len = folio_size(folio); long count = wbc->nr_to_write; int rc; @@ -3285,7 +3286,7 @@ static int cifs_resend_wdata(struct cifs_io_subrequest *wdata, struct list_head *wdata_list, struct cifs_aio_ctx *ctx) { - unsigned int wsize; + size_t wsize; struct cifs_credits credits; int rc; struct TCP_Server_Info *server = wdata->server; @@ -3420,7 +3421,8 @@ cifs_write_from_iter(loff_t fpos, size_t len, struct iov_iter *from, do { struct cifs_credits credits_on_stack; struct cifs_credits *credits = &credits_on_stack; - unsigned int wsize, nsegs = 0; + unsigned int nsegs = 0; + size_t wsize; if (signal_pending(current)) { rc = -EINTR; @@ -3857,7 +3859,7 @@ static int cifs_resend_rdata(struct cifs_io_subrequest *rdata, struct list_head *rdata_list, struct cifs_aio_ctx *ctx) { - unsigned int rsize; + size_t rsize; struct cifs_credits credits; int rc; struct TCP_Server_Info *server; @@ -3931,10 +3933,10 @@ cifs_send_async_read(loff_t fpos, size_t len, struct cifsFileInfo *open_file, struct cifs_aio_ctx *ctx) { struct cifs_io_subrequest *rdata; - unsigned int rsize, nsegs, max_segs = INT_MAX; + unsigned int nsegs, max_segs = INT_MAX; struct cifs_credits credits_on_stack; struct cifs_credits *credits = &credits_on_stack; - size_t cur_len, max_len; + size_t cur_len, max_len, rsize; int rc; pid_t pid; struct TCP_Server_Info *server; @@ -4530,12 +4532,13 @@ static void cifs_readahead(struct readahead_control *ractl) * Chop the readahead request up into rsize-sized read requests. */ while ((nr_pages = ra_pages)) { - unsigned int i, rsize; + unsigned int i; struct cifs_io_subrequest *rdata; struct cifs_credits credits_on_stack; struct cifs_credits *credits = &credits_on_stack; struct folio *folio; pgoff_t fsize; + size_t rsize; /* * Find out if we have anything cached in the range of diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index c13705c0e47f..ef18cd30f66c 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -217,8 +217,8 @@ smb2_get_credits(struct mid_q_entry *mid) } static int -smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size, - unsigned int *num, struct cifs_credits *credits) +smb2_wait_mtu_credits(struct TCP_Server_Info *server, size_t size, + size_t *num, struct cifs_credits *credits) { int rc = 0; unsigned int scredits, in_flight; diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c index cccc1248c48a..4c8af995c60b 100644 --- a/fs/smb/client/transport.c +++ b/fs/smb/client/transport.c @@ -691,8 +691,8 @@ wait_for_compound_request(struct TCP_Server_Info *server, int num, } int -cifs_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size, - unsigned int *num, struct cifs_credits *credits) +cifs_wait_mtu_credits(struct TCP_Server_Info *server, size_t size, + size_t *num, struct cifs_credits *credits) { *num = size; credits->value = 0; -- cgit From dc5939de82f149633d6ec1c403003538442ec9ef Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 5 Feb 2024 09:08:57 +0000 Subject: cifs: Replace the writedata replay bool with a netfs sreq flag Replace the 'replay' bool in cifs_writedata (now cifs_io_subrequest) with a flag in the netfs_io_subrequest flags. Signed-off-by: David Howells cc: Steve French cc: Shyam Prasad N cc: Rohith Surabattula cc: Jeff Layton cc: linux-cifs@vger.kernel.org cc: netfs@lists.linux.dev cc: linux-fsdevel@vger.kernel.org cc: linux-mm@kvack.org --- fs/smb/client/file.c | 2 +- fs/smb/client/smb2pdu.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'fs/smb') diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c index 4d8cd0d82104..7f2ce68d2a2a 100644 --- a/fs/smb/client/file.c +++ b/fs/smb/client/file.c @@ -3325,7 +3325,7 @@ cifs_resend_wdata(struct cifs_io_subrequest *wdata, struct list_head *wdata_list if (wdata->cfile->invalidHandle) rc = -EAGAIN; else { - wdata->replay = true; + set_bit(NETFS_SREQ_RETRYING, &wdata->subreq.flags); #ifdef CONFIG_CIFS_SMB_DIRECT if (wdata->mr) { wdata->mr->need_invalidate = true; diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index ca8ba6878f9f..b063f5e95f5d 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -4832,7 +4832,7 @@ smb2_async_writev(struct cifs_io_subrequest *wdata) struct cifs_io_parms *io_parms = NULL; int credit_request; - if (!wdata->server || wdata->replay) + if (!wdata->server || test_bit(NETFS_SREQ_RETRYING, &wdata->subreq.flags)) server = wdata->server = cifs_pick_channel(tcon->ses); /* @@ -4917,7 +4917,7 @@ smb2_async_writev(struct cifs_io_subrequest *wdata) rqst.rq_nvec = 1; rqst.rq_iter = wdata->subreq.io_iter; rqst.rq_iter_size = iov_iter_count(&rqst.rq_iter); - if (wdata->replay) + if (test_bit(NETFS_SREQ_RETRYING, &wdata->subreq.flags)) smb2_set_replay(server, &rqst); #ifdef CONFIG_CIFS_SMB_DIRECT if (wdata->mr) -- cgit From 1a5b4edd97cee40922ca8bfb91008338d3a1de60 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 12 Oct 2023 08:36:44 +0100 Subject: cifs: Move cifs_loose_read_iter() and cifs_file_write_iter() to file.c Move cifs_loose_read_iter() and cifs_file_write_iter() to file.c so that they are colocated with similar functions rather than being split with cifsfs.c. Signed-off-by: David Howells cc: Steve French cc: Shyam Prasad N cc: Rohith Surabattula cc: Jeff Layton cc: linux-cifs@vger.kernel.org cc: netfs@lists.linux.dev cc: linux-fsdevel@vger.kernel.org cc: linux-mm@kvack.org --- fs/smb/client/cifsfs.c | 55 -------------------------------------------------- fs/smb/client/cifsfs.h | 2 ++ fs/smb/client/file.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 55 deletions(-) (limited to 'fs/smb') diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c index 39277c37185c..847df5152835 100644 --- a/fs/smb/client/cifsfs.c +++ b/fs/smb/client/cifsfs.c @@ -986,61 +986,6 @@ out: return root; } - -static ssize_t -cifs_loose_read_iter(struct kiocb *iocb, struct iov_iter *iter) -{ - ssize_t rc; - struct inode *inode = file_inode(iocb->ki_filp); - - if (iocb->ki_flags & IOCB_DIRECT) - return cifs_user_readv(iocb, iter); - - rc = cifs_revalidate_mapping(inode); - if (rc) - return rc; - - return generic_file_read_iter(iocb, iter); -} - -static ssize_t cifs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) -{ - struct inode *inode = file_inode(iocb->ki_filp); - struct cifsInodeInfo *cinode = CIFS_I(inode); - ssize_t written; - int rc; - - if (iocb->ki_filp->f_flags & O_DIRECT) { - written = cifs_user_writev(iocb, from); - if (written > 0 && CIFS_CACHE_READ(cinode)) { - cifs_zap_mapping(inode); - cifs_dbg(FYI, - "Set no oplock for inode=%p after a write operation\n", - inode); - cinode->oplock = 0; - } - return written; - } - - written = cifs_get_writer(cinode); - if (written) - return written; - - written = generic_file_write_iter(iocb, from); - - if (CIFS_CACHE_WRITE(CIFS_I(inode))) - goto out; - - rc = filemap_fdatawrite(inode->i_mapping); - if (rc) - cifs_dbg(FYI, "cifs_file_write_iter: %d rc on %p inode\n", - rc, inode); - -out: - cifs_put_writer(cinode); - return written; -} - static loff_t cifs_llseek(struct file *file, loff_t offset, int whence) { struct cifsFileInfo *cfile = file->private_data; diff --git a/fs/smb/client/cifsfs.h b/fs/smb/client/cifsfs.h index 1ab7e5998c58..1acf6bfc06de 100644 --- a/fs/smb/client/cifsfs.h +++ b/fs/smb/client/cifsfs.h @@ -99,6 +99,8 @@ extern ssize_t cifs_strict_readv(struct kiocb *iocb, struct iov_iter *to); extern ssize_t cifs_user_writev(struct kiocb *iocb, struct iov_iter *from); extern ssize_t cifs_direct_writev(struct kiocb *iocb, struct iov_iter *from); extern ssize_t cifs_strict_writev(struct kiocb *iocb, struct iov_iter *from); +ssize_t cifs_file_write_iter(struct kiocb *iocb, struct iov_iter *from); +ssize_t cifs_loose_read_iter(struct kiocb *iocb, struct iov_iter *iter); extern int cifs_flock(struct file *pfile, int cmd, struct file_lock *plock); extern int cifs_lock(struct file *, int, struct file_lock *); extern int cifs_fsync(struct file *, loff_t, loff_t, int); diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c index 7f2ce68d2a2a..331446fc3d22 100644 --- a/fs/smb/client/file.c +++ b/fs/smb/client/file.c @@ -4250,6 +4250,59 @@ ssize_t cifs_user_readv(struct kiocb *iocb, struct iov_iter *to) return __cifs_readv(iocb, to, false); } +ssize_t cifs_loose_read_iter(struct kiocb *iocb, struct iov_iter *iter) +{ + ssize_t rc; + struct inode *inode = file_inode(iocb->ki_filp); + + if (iocb->ki_flags & IOCB_DIRECT) + return cifs_user_readv(iocb, iter); + + rc = cifs_revalidate_mapping(inode); + if (rc) + return rc; + + return generic_file_read_iter(iocb, iter); +} + +ssize_t cifs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) +{ + struct inode *inode = file_inode(iocb->ki_filp); + struct cifsInodeInfo *cinode = CIFS_I(inode); + ssize_t written; + int rc; + + if (iocb->ki_filp->f_flags & O_DIRECT) { + written = cifs_user_writev(iocb, from); + if (written > 0 && CIFS_CACHE_READ(cinode)) { + cifs_zap_mapping(inode); + cifs_dbg(FYI, + "Set no oplock for inode=%p after a write operation\n", + inode); + cinode->oplock = 0; + } + return written; + } + + written = cifs_get_writer(cinode); + if (written) + return written; + + written = generic_file_write_iter(iocb, from); + + if (CIFS_CACHE_WRITE(CIFS_I(inode))) + goto out; + + rc = filemap_fdatawrite(inode->i_mapping); + if (rc) + cifs_dbg(FYI, "cifs_file_write_iter: %d rc on %p inode\n", + rc, inode); + +out: + cifs_put_writer(cinode); + return written; +} + ssize_t cifs_strict_readv(struct kiocb *iocb, struct iov_iter *to) { -- cgit From 3758c485f6c9124d8ad76b88382004cbc28a0892 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 28 Nov 2023 16:26:44 +0000 Subject: cifs: Set zero_point in the copy_file_range() and remap_file_range() Set zero_point in the copy_file_range() and remap_file_range() implementations so that we don't skip reading data modified on a server-side copy. Signed-off-by: David Howells cc: Steve French cc: Shyam Prasad N cc: Rohith Surabattula cc: Jeff Layton cc: linux-cifs@vger.kernel.org cc: netfs@lists.linux.dev cc: linux-fsdevel@vger.kernel.org cc: linux-mm@kvack.org --- fs/smb/client/cifsfs.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'fs/smb') diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c index 847df5152835..9d656a08f617 100644 --- a/fs/smb/client/cifsfs.c +++ b/fs/smb/client/cifsfs.c @@ -1287,6 +1287,8 @@ static loff_t cifs_remap_file_range(struct file *src_file, loff_t off, rc = cifs_flush_folio(target_inode, destend, &fstart, &fend, false); if (rc) goto unlock; + if (fend > target_cifsi->netfs.zero_point) + target_cifsi->netfs.zero_point = fend + 1; /* Discard all the folios that overlap the destination region. */ cifs_dbg(FYI, "about to discard pages %llx-%llx\n", fstart, fend); @@ -1305,6 +1307,8 @@ static loff_t cifs_remap_file_range(struct file *src_file, loff_t off, fscache_resize_cookie(cifs_inode_cookie(target_inode), new_size); } + if (rc == 0 && new_size > target_cifsi->netfs.zero_point) + target_cifsi->netfs.zero_point = new_size; } /* force revalidate of size and timestamps of target file now @@ -1396,6 +1400,8 @@ ssize_t cifs_file_copychunk_range(unsigned int xid, rc = cifs_flush_folio(target_inode, destend, &fstart, &fend, false); if (rc) goto unlock; + if (fend > target_cifsi->netfs.zero_point) + target_cifsi->netfs.zero_point = fend + 1; /* Discard all the folios that overlap the destination region. */ truncate_inode_pages_range(&target_inode->i_data, fstart, fend); -- cgit From edea94a69730b74a8867bbafe742c3fc4e580722 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 15 Mar 2024 18:03:30 +0000 Subject: cifs: Add mempools for cifs_io_request and cifs_io_subrequest structs Add mempools for the allocation of cifs_io_request and cifs_io_subrequest structs for netfslib to use so that it can guarantee eventual allocation in writeback. Signed-off-by: David Howells cc: Steve French cc: Shyam Prasad N cc: Rohith Surabattula cc: Jeff Layton cc: linux-cifs@vger.kernel.org cc: netfs@lists.linux.dev cc: linux-fsdevel@vger.kernel.org cc: linux-mm@kvack.org --- fs/smb/client/cifsfs.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++- fs/smb/client/cifsglob.h | 2 ++ 2 files changed, 56 insertions(+), 1 deletion(-) (limited to 'fs/smb') diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c index 9d656a08f617..763d17870e0b 100644 --- a/fs/smb/client/cifsfs.c +++ b/fs/smb/client/cifsfs.c @@ -371,9 +371,13 @@ static struct kmem_cache *cifs_inode_cachep; static struct kmem_cache *cifs_req_cachep; static struct kmem_cache *cifs_mid_cachep; static struct kmem_cache *cifs_sm_req_cachep; +static struct kmem_cache *cifs_io_request_cachep; +static struct kmem_cache *cifs_io_subrequest_cachep; mempool_t *cifs_sm_req_poolp; mempool_t *cifs_req_poolp; mempool_t *cifs_mid_poolp; +mempool_t cifs_io_request_pool; +mempool_t cifs_io_subrequest_pool; static struct inode * cifs_alloc_inode(struct super_block *sb) @@ -1750,6 +1754,48 @@ static void destroy_mids(void) kmem_cache_destroy(cifs_mid_cachep); } +static int cifs_init_netfs(void) +{ + cifs_io_request_cachep = + kmem_cache_create("cifs_io_request", + sizeof(struct netfs_io_request), 0, + SLAB_HWCACHE_ALIGN, NULL); + if (!cifs_io_request_cachep) + goto nomem_req; + + if (mempool_init_slab_pool(&cifs_io_request_pool, 100, cifs_io_request_cachep) < 0) + goto nomem_reqpool; + + cifs_io_subrequest_cachep = + kmem_cache_create("cifs_io_subrequest", + sizeof(struct cifs_io_subrequest), 0, + SLAB_HWCACHE_ALIGN, NULL); + if (!cifs_io_subrequest_cachep) + goto nomem_subreq; + + if (mempool_init_slab_pool(&cifs_io_subrequest_pool, 100, cifs_io_subrequest_cachep) < 0) + goto nomem_subreqpool; + + return 0; + +nomem_subreqpool: + kmem_cache_destroy(cifs_io_subrequest_cachep); +nomem_subreq: + mempool_destroy(&cifs_io_request_pool); +nomem_reqpool: + kmem_cache_destroy(cifs_io_request_cachep); +nomem_req: + return -ENOMEM; +} + +static void cifs_destroy_netfs(void) +{ + mempool_destroy(&cifs_io_subrequest_pool); + kmem_cache_destroy(cifs_io_subrequest_cachep); + mempool_destroy(&cifs_io_request_pool); + kmem_cache_destroy(cifs_io_request_cachep); +} + static int __init init_cifs(void) { @@ -1854,10 +1900,14 @@ init_cifs(void) if (rc) goto out_destroy_deferredclose_wq; - rc = init_mids(); + rc = cifs_init_netfs(); if (rc) goto out_destroy_inodecache; + rc = init_mids(); + if (rc) + goto out_destroy_netfs; + rc = cifs_init_request_bufs(); if (rc) goto out_destroy_mids; @@ -1912,6 +1962,8 @@ out_destroy_request_bufs: cifs_destroy_request_bufs(); out_destroy_mids: destroy_mids(); +out_destroy_netfs: + cifs_destroy_netfs(); out_destroy_inodecache: cifs_destroy_inodecache(); out_destroy_deferredclose_wq: @@ -1950,6 +2002,7 @@ exit_cifs(void) #endif cifs_destroy_request_bufs(); destroy_mids(); + cifs_destroy_netfs(); cifs_destroy_inodecache(); destroy_workqueue(deferredclose_wq); destroy_workqueue(cifsoplockd_wq); diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 13161e0b5cc0..29c9ee2dd304 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -2094,6 +2094,8 @@ extern __u32 cifs_lock_secret; extern mempool_t *cifs_sm_req_poolp; extern mempool_t *cifs_req_poolp; extern mempool_t *cifs_mid_poolp; +extern mempool_t cifs_io_request_pool; +extern mempool_t cifs_io_subrequest_pool; /* Operations for different SMB versions */ #define SMB1_VERSION_STRING "1.0" -- cgit From c20c0d7325abd9a8bf985a934591d75d514a3d4d Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 28 Mar 2024 07:59:18 +0000 Subject: cifs: Make add_credits_and_wake_if() clear deducted credits Make add_credits_and_wake_if() clear the amount of credits in the cifs_credits struct after it has returned them to the overall counter. This allows add_credits_and_wake_if() to be called multiple times during the error handling and cleanup without accidentally returning the credits again and again. Note that the wake_up() in add_credits_and_wake_if() may also be superfluous as ->add_credits() also does a wake on the request_q. Signed-off-by: David Howells cc: Steve French cc: Shyam Prasad N cc: Rohith Surabattula cc: Jeff Layton cc: linux-cifs@vger.kernel.org cc: netfs@lists.linux.dev cc: linux-fsdevel@vger.kernel.org --- fs/smb/client/cifsglob.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'fs/smb') diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 29c9ee2dd304..611f59c6d2c0 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -881,11 +881,12 @@ add_credits(struct TCP_Server_Info *server, const struct cifs_credits *credits, static inline void add_credits_and_wake_if(struct TCP_Server_Info *server, - const struct cifs_credits *credits, const int optype) + struct cifs_credits *credits, const int optype) { if (credits->value) { server->ops->add_credits(server, credits, optype); wake_up(&server->request_q); + credits->value = 0; } } -- cgit From 69c3c023af25edb5433a2db824d3e7cc328f0183 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 6 Oct 2023 18:16:15 +0100 Subject: cifs: Implement netfslib hooks Provide implementation of the netfslib hooks that will be used by netfslib to ask cifs to set up and perform operations. Of particular note are (*) cifs_clamp_length() - This is used to negotiate the size of the next subrequest in a read request, taking into account the credit available and the rsize. The credits are attached to the subrequest. (*) cifs_req_issue_read() - This is used to issue a subrequest that has been set up and clamped. (*) cifs_prepare_write() - This prepares to fill a subrequest by picking a channel, reopening the file and requesting credits so that we can set the maximum size of the subrequest and also sets the maximum number of segments if we're doing RDMA. (*) cifs_issue_write() - This releases any unneeded credits and issues an asynchronous data write for the contiguous slice of file covered by the subrequest. This should possibly be folded in to all ->async_writev() ops and that called directly. (*) cifs_begin_writeback() - This gets the cached writable handle through which we do writeback (this does not affect writethrough, unbuffered or direct writes). At this point, cifs is not wired up to actually *use* netfslib; that will be done in a subsequent patch. Signed-off-by: David Howells cc: Steve French cc: Shyam Prasad N cc: Rohith Surabattula cc: Jeff Layton cc: linux-cifs@vger.kernel.org cc: netfs@lists.linux.dev cc: linux-fsdevel@vger.kernel.org cc: linux-mm@kvack.org --- fs/smb/client/Kconfig | 1 + fs/smb/client/cifsfs.c | 2 +- fs/smb/client/cifsfs.h | 1 + fs/smb/client/cifsglob.h | 28 +++-- fs/smb/client/file.c | 315 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 337 insertions(+), 10 deletions(-) (limited to 'fs/smb') diff --git a/fs/smb/client/Kconfig b/fs/smb/client/Kconfig index 2927bd174a88..2517dc242386 100644 --- a/fs/smb/client/Kconfig +++ b/fs/smb/client/Kconfig @@ -2,6 +2,7 @@ config CIFS tristate "SMB3 and CIFS support (advanced network filesystem)" depends on INET + select NETFS_SUPPORT select NLS select NLS_UCS2_UTILS select CRYPTO diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c index 763d17870e0b..8f7165567be7 100644 --- a/fs/smb/client/cifsfs.c +++ b/fs/smb/client/cifsfs.c @@ -1758,7 +1758,7 @@ static int cifs_init_netfs(void) { cifs_io_request_cachep = kmem_cache_create("cifs_io_request", - sizeof(struct netfs_io_request), 0, + sizeof(struct cifs_io_request), 0, SLAB_HWCACHE_ALIGN, NULL); if (!cifs_io_request_cachep) goto nomem_req; diff --git a/fs/smb/client/cifsfs.h b/fs/smb/client/cifsfs.h index 1acf6bfc06de..922c10d7cfdd 100644 --- a/fs/smb/client/cifsfs.h +++ b/fs/smb/client/cifsfs.h @@ -84,6 +84,7 @@ extern const struct inode_operations cifs_namespace_inode_operations; /* Functions related to files and directories */ +extern const struct netfs_request_ops cifs_req_ops; extern const struct file_operations cifs_file_ops; extern const struct file_operations cifs_file_direct_ops; /* if directio mnt */ extern const struct file_operations cifs_file_strict_ops; /* if strictio mnt */ diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 611f59c6d2c0..4e9033b2f191 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -1491,15 +1491,24 @@ struct cifs_aio_ctx { bool direct_io; }; +struct cifs_io_request { + struct netfs_io_request rreq; + struct cifsFileInfo *cfile; +}; + /* asynchronous read support */ struct cifs_io_subrequest { - struct netfs_io_subrequest subreq; - struct cifsFileInfo *cfile; - struct address_space *mapping; - struct cifs_aio_ctx *ctx; + union { + struct netfs_io_subrequest subreq; + struct netfs_io_request *rreq; + struct cifs_io_request *req; + }; ssize_t got_bytes; pid_t pid; + unsigned int xid; int result; + bool have_xid; + bool replay; struct kvec iov[2]; struct TCP_Server_Info *server; #ifdef CONFIG_CIFS_SMB_DIRECT @@ -1507,15 +1516,16 @@ struct cifs_io_subrequest { #endif struct cifs_credits credits; - enum writeback_sync_modes sync_mode; - bool uncached; - bool replay; - struct bio_vec *bv; - // TODO: Remove following elements struct list_head list; struct completion done; struct work_struct work; + struct cifsFileInfo *cfile; + struct address_space *mapping; + struct cifs_aio_ctx *ctx; + enum writeback_sync_modes sync_mode; + bool uncached; + struct bio_vec *bv; }; /* diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c index 331446fc3d22..c9c33b3a54f3 100644 --- a/fs/smb/client/file.c +++ b/fs/smb/client/file.c @@ -36,6 +36,321 @@ #include "fs_context.h" #include "cifs_ioctl.h" #include "cached_dir.h" +#include + +static int cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush); + +/* + * Prepare a subrequest to upload to the server. We need to allocate credits + * so that we know the maximum amount of data that we can include in it. + */ +static void cifs_prepare_write(struct netfs_io_subrequest *subreq) +{ + struct cifs_io_subrequest *wdata = + container_of(subreq, struct cifs_io_subrequest, subreq); + struct cifs_io_request *req = wdata->req; + struct TCP_Server_Info *server; + struct cifsFileInfo *open_file = req->cfile; + size_t wsize = req->rreq.wsize; + int rc; + + if (!wdata->have_xid) { + wdata->xid = get_xid(); + wdata->have_xid = true; + } + + server = cifs_pick_channel(tlink_tcon(open_file->tlink)->ses); + wdata->server = server; + +retry: + if (open_file->invalidHandle) { + rc = cifs_reopen_file(open_file, false); + if (rc < 0) { + if (rc == -EAGAIN) + goto retry; + subreq->error = rc; + return netfs_prepare_write_failed(subreq); + } + } + + rc = server->ops->wait_mtu_credits(server, wsize, &wdata->subreq.max_len, + &wdata->credits); + if (rc < 0) { + subreq->error = rc; + return netfs_prepare_write_failed(subreq); + } + +#ifdef CONFIG_CIFS_SMB_DIRECT + if (server->smbd_conn) + subreq->max_nr_segs = server->smbd_conn->max_frmr_depth; +#endif +} + +/* + * Issue a subrequest to upload to the server. + */ +static void cifs_issue_write(struct netfs_io_subrequest *subreq) +{ + struct cifs_io_subrequest *wdata = + container_of(subreq, struct cifs_io_subrequest, subreq); + struct cifs_sb_info *sbi = CIFS_SB(subreq->rreq->inode->i_sb); + int rc; + + if (cifs_forced_shutdown(sbi)) { + rc = -EIO; + goto fail; + } + + rc = adjust_credits(wdata->server, &wdata->credits, wdata->subreq.len); + if (rc) + goto fail; + + rc = -EAGAIN; + if (wdata->req->cfile->invalidHandle) + goto fail; + + wdata->server->ops->async_writev(wdata); +out: + return; + +fail: + if (rc == -EAGAIN) + trace_netfs_sreq(subreq, netfs_sreq_trace_retry); + else + trace_netfs_sreq(subreq, netfs_sreq_trace_fail); + add_credits_and_wake_if(wdata->server, &wdata->credits, 0); + netfs_write_subrequest_terminated(wdata, rc, false); + goto out; +} + +/* + * Split the read up according to how many credits we can get for each piece. + * It's okay to sleep here if we need to wait for more credit to become + * available. + * + * We also choose the server and allocate an operation ID to be cleaned up + * later. + */ +static bool cifs_clamp_length(struct netfs_io_subrequest *subreq) +{ + struct netfs_io_request *rreq = subreq->rreq; + struct TCP_Server_Info *server; + struct cifs_io_subrequest *rdata = container_of(subreq, struct cifs_io_subrequest, subreq); + struct cifs_io_request *req = container_of(subreq->rreq, struct cifs_io_request, rreq); + struct cifs_sb_info *cifs_sb = CIFS_SB(rreq->inode->i_sb); + size_t rsize = 0; + int rc; + + rdata->xid = get_xid(); + rdata->have_xid = true; + + server = cifs_pick_channel(tlink_tcon(req->cfile->tlink)->ses); + rdata->server = server; + + if (cifs_sb->ctx->rsize == 0) + cifs_sb->ctx->rsize = + server->ops->negotiate_rsize(tlink_tcon(req->cfile->tlink), + cifs_sb->ctx); + + + rc = server->ops->wait_mtu_credits(server, cifs_sb->ctx->rsize, &rsize, + &rdata->credits); + if (rc) { + subreq->error = rc; + return false; + } + + subreq->len = min_t(size_t, subreq->len, rsize); +#ifdef CONFIG_CIFS_SMB_DIRECT + if (server->smbd_conn) + subreq->max_nr_segs = server->smbd_conn->max_frmr_depth; +#endif + return true; +} + +/* + * Issue a read operation on behalf of the netfs helper functions. We're asked + * to make a read of a certain size at a point in the file. We are permitted + * to only read a portion of that, but as long as we read something, the netfs + * helper will call us again so that we can issue another read. + */ +static void cifs_req_issue_read(struct netfs_io_subrequest *subreq) +{ + struct netfs_io_request *rreq = subreq->rreq; + struct cifs_io_subrequest *rdata = container_of(subreq, struct cifs_io_subrequest, subreq); + struct cifs_io_request *req = container_of(subreq->rreq, struct cifs_io_request, rreq); + struct cifs_sb_info *cifs_sb = CIFS_SB(rreq->inode->i_sb); + pid_t pid; + int rc = 0; + + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD) + pid = req->cfile->pid; + else + pid = current->tgid; // Ummm... This may be a workqueue + + cifs_dbg(FYI, "%s: op=%08x[%x] mapping=%p len=%zu/%zu\n", + __func__, rreq->debug_id, subreq->debug_index, rreq->mapping, + subreq->transferred, subreq->len); + + if (req->cfile->invalidHandle) { + do { + rc = cifs_reopen_file(req->cfile, true); + } while (rc == -EAGAIN); + if (rc) + goto out; + } + + __set_bit(NETFS_SREQ_CLEAR_TAIL, &subreq->flags); + rdata->pid = pid; + + rc = adjust_credits(rdata->server, &rdata->credits, rdata->subreq.len); + if (!rc) { + if (rdata->req->cfile->invalidHandle) + rc = -EAGAIN; + else + rc = rdata->server->ops->async_readv(rdata); + } + +out: + if (rc) + netfs_subreq_terminated(subreq, rc, false); +} + +/* + * Writeback calls this when it finds a folio that needs uploading. This isn't + * called if writeback only has copy-to-cache to deal with. + */ +static void cifs_begin_writeback(struct netfs_io_request *wreq) +{ + struct cifs_io_request *req = container_of(wreq, struct cifs_io_request, rreq); + int ret; + + ret = cifs_get_writable_file(CIFS_I(wreq->inode), FIND_WR_ANY, &req->cfile); + if (ret) { + cifs_dbg(VFS, "No writable handle in writepages ret=%d\n", ret); + return; + } + + wreq->io_streams[0].avail = true; +} + +/* + * Initialise a request. + */ +static int cifs_init_request(struct netfs_io_request *rreq, struct file *file) +{ + struct cifs_io_request *req = container_of(rreq, struct cifs_io_request, rreq); + struct cifs_sb_info *cifs_sb = CIFS_SB(rreq->inode->i_sb); + struct cifsFileInfo *open_file = NULL; + + rreq->rsize = cifs_sb->ctx->rsize; + rreq->wsize = cifs_sb->ctx->wsize; + + if (file) { + open_file = file->private_data; + rreq->netfs_priv = file->private_data; + req->cfile = cifsFileInfo_get(open_file); + } else if (rreq->origin != NETFS_WRITEBACK) { + WARN_ON_ONCE(1); + return -EIO; + } + + return 0; +} + +/* + * Expand the size of a readahead to the size of the rsize, if at least as + * large as a page, allowing for the possibility that rsize is not pow-2 + * aligned. + */ +static void cifs_expand_readahead(struct netfs_io_request *rreq) +{ + unsigned int rsize = rreq->rsize; + loff_t misalignment, i_size = i_size_read(rreq->inode); + + if (rsize < PAGE_SIZE) + return; + + if (rsize < INT_MAX) + rsize = roundup_pow_of_two(rsize); + else + rsize = ((unsigned int)INT_MAX + 1) / 2; + + misalignment = rreq->start & (rsize - 1); + if (misalignment) { + rreq->start -= misalignment; + rreq->len += misalignment; + } + + rreq->len = round_up(rreq->len, rsize); + if (rreq->start < i_size && rreq->len > i_size - rreq->start) + rreq->len = i_size - rreq->start; +} + +/* + * Completion of a request operation. + */ +static void cifs_rreq_done(struct netfs_io_request *rreq) +{ + struct timespec64 atime, mtime; + struct inode *inode = rreq->inode; + + /* we do not want atime to be less than mtime, it broke some apps */ + atime = inode_set_atime_to_ts(inode, current_time(inode)); + mtime = inode_get_mtime(inode); + if (timespec64_compare(&atime, &mtime)) + inode_set_atime_to_ts(inode, inode_get_mtime(inode)); +} + +static void cifs_post_modify(struct inode *inode) +{ + /* Indication to update ctime and mtime as close is deferred */ + set_bit(CIFS_INO_MODIFIED_ATTR, &CIFS_I(inode)->flags); +} + +static void cifs_free_request(struct netfs_io_request *rreq) +{ + struct cifs_io_request *req = container_of(rreq, struct cifs_io_request, rreq); + + if (req->cfile) + cifsFileInfo_put(req->cfile); +} + +static void cifs_free_subrequest(struct netfs_io_subrequest *subreq) +{ + struct cifs_io_subrequest *rdata = + container_of(subreq, struct cifs_io_subrequest, subreq); + int rc = subreq->error; + + if (rdata->subreq.source == NETFS_DOWNLOAD_FROM_SERVER) { +#ifdef CONFIG_CIFS_SMB_DIRECT + if (rdata->mr) { + smbd_deregister_mr(rdata->mr); + rdata->mr = NULL; + } +#endif + } + + add_credits_and_wake_if(rdata->server, &rdata->credits, 0); + if (rdata->have_xid) + free_xid(rdata->xid); +} + +const struct netfs_request_ops cifs_req_ops = { + .request_pool = &cifs_io_request_pool, + .subrequest_pool = &cifs_io_subrequest_pool, + .init_request = cifs_init_request, + .free_request = cifs_free_request, + .free_subrequest = cifs_free_subrequest, + .expand_readahead = cifs_expand_readahead, + .clamp_length = cifs_clamp_length, + .issue_read = cifs_req_issue_read, + .done = cifs_rreq_done, + .post_modify = cifs_post_modify, + .begin_writeback = cifs_begin_writeback, + .prepare_write = cifs_prepare_write, + .issue_write = cifs_issue_write, +}; /* * Remove the dirty flags from a span of pages. -- cgit From 3ee1a1fc39819906f04d6c62c180e760cd3a689d Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 6 Oct 2023 18:29:59 +0100 Subject: cifs: Cut over to using netfslib Make the cifs filesystem use netfslib to handle reading and writing on behalf of cifs. The changes include: (1) Various read_iter/write_iter type functions are turned into wrappers around netfslib API functions or are pointed directly at those functions: cifs_file_direct{,_nobrl}_ops switch to use netfs_unbuffered_read_iter and netfs_unbuffered_write_iter. Large pieces of code that will be removed are #if'd out and will be removed in subsequent patches. [?] Why does cifs mark the page dirty in the destination buffer of a DIO read? Should that happen automatically? Does netfs need to do that? Signed-off-by: David Howells cc: Steve French cc: Shyam Prasad N cc: Rohith Surabattula cc: Jeff Layton cc: linux-cifs@vger.kernel.org cc: netfs@lists.linux.dev cc: linux-fsdevel@vger.kernel.org cc: linux-mm@kvack.org --- fs/smb/client/cifsfs.c | 8 +-- fs/smb/client/cifsfs.h | 7 -- fs/smb/client/cifsglob.h | 5 +- fs/smb/client/cifsproto.h | 8 ++- fs/smb/client/cifssmb.c | 54 +++++++++------- fs/smb/client/file.c | 161 +++++++++++++++++++++++++--------------------- fs/smb/client/fscache.c | 2 + fs/smb/client/fscache.h | 4 ++ fs/smb/client/inode.c | 19 +++++- fs/smb/client/smb2pdu.c | 117 +++++++++++++++++++-------------- fs/smb/client/smb2proto.h | 2 +- fs/smb/client/trace.h | 144 +++++++++++++++++++++++++++++++++++------ fs/smb/client/transport.c | 3 + 13 files changed, 355 insertions(+), 179 deletions(-) (limited to 'fs/smb') diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c index 8f7165567be7..6e1698614745 100644 --- a/fs/smb/client/cifsfs.c +++ b/fs/smb/client/cifsfs.c @@ -1522,8 +1522,8 @@ const struct file_operations cifs_file_strict_ops = { }; const struct file_operations cifs_file_direct_ops = { - .read_iter = cifs_direct_readv, - .write_iter = cifs_direct_writev, + .read_iter = netfs_unbuffered_read_iter, + .write_iter = netfs_file_write_iter, .open = cifs_open, .release = cifs_close, .lock = cifs_lock, @@ -1578,8 +1578,8 @@ const struct file_operations cifs_file_strict_nobrl_ops = { }; const struct file_operations cifs_file_direct_nobrl_ops = { - .read_iter = cifs_direct_readv, - .write_iter = cifs_direct_writev, + .read_iter = netfs_unbuffered_read_iter, + .write_iter = netfs_file_write_iter, .open = cifs_open, .release = cifs_close, .fsync = cifs_fsync, diff --git a/fs/smb/client/cifsfs.h b/fs/smb/client/cifsfs.h index 922c10d7cfdd..87310f05d397 100644 --- a/fs/smb/client/cifsfs.h +++ b/fs/smb/client/cifsfs.h @@ -94,11 +94,7 @@ extern const struct file_operations cifs_file_strict_nobrl_ops; extern int cifs_open(struct inode *inode, struct file *file); extern int cifs_close(struct inode *inode, struct file *file); extern int cifs_closedir(struct inode *inode, struct file *file); -extern ssize_t cifs_user_readv(struct kiocb *iocb, struct iov_iter *to); -extern ssize_t cifs_direct_readv(struct kiocb *iocb, struct iov_iter *to); extern ssize_t cifs_strict_readv(struct kiocb *iocb, struct iov_iter *to); -extern ssize_t cifs_user_writev(struct kiocb *iocb, struct iov_iter *from); -extern ssize_t cifs_direct_writev(struct kiocb *iocb, struct iov_iter *from); extern ssize_t cifs_strict_writev(struct kiocb *iocb, struct iov_iter *from); ssize_t cifs_file_write_iter(struct kiocb *iocb, struct iov_iter *from); ssize_t cifs_loose_read_iter(struct kiocb *iocb, struct iov_iter *iter); @@ -112,9 +108,6 @@ extern int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma); extern const struct file_operations cifs_dir_ops; extern int cifs_dir_open(struct inode *inode, struct file *file); extern int cifs_readdir(struct file *file, struct dir_context *ctx); -extern void cifs_pages_written_back(struct inode *inode, loff_t start, unsigned int len); -extern void cifs_pages_write_failed(struct inode *inode, loff_t start, unsigned int len); -extern void cifs_pages_write_redirty(struct inode *inode, loff_t start, unsigned int len); /* Functions related to dir entries */ extern const struct dentry_operations cifs_dentry_ops; diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 4e9033b2f191..983860bf5fbb 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -451,7 +451,7 @@ struct smb_version_operations { /* async read from the server */ int (*async_readv)(struct cifs_io_subrequest *); /* async write to the server */ - int (*async_writev)(struct cifs_io_subrequest *); + void (*async_writev)(struct cifs_io_subrequest *); /* sync read from the server */ int (*sync_read)(const unsigned int, struct cifs_fid *, struct cifs_io_parms *, unsigned int *, char **, @@ -1516,7 +1516,7 @@ struct cifs_io_subrequest { #endif struct cifs_credits credits; - // TODO: Remove following elements +#if 0 // TODO: Remove following elements struct list_head list; struct completion done; struct work_struct work; @@ -1526,6 +1526,7 @@ struct cifs_io_subrequest { enum writeback_sync_modes sync_mode; bool uncached; struct bio_vec *bv; +#endif }; /* diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h index 103f264b42d7..d46ad86150cd 100644 --- a/fs/smb/client/cifsproto.h +++ b/fs/smb/client/cifsproto.h @@ -148,6 +148,8 @@ extern bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 eof, bool from_readdir); extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, unsigned int bytes_written); +void cifs_write_subrequest_terminated(struct cifs_io_subrequest *wdata, ssize_t result, + bool was_async); extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, int); extern int cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, int flags, @@ -599,6 +601,7 @@ void __cifs_put_smb_ses(struct cifs_ses *ses); extern struct cifs_ses * cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx); +#if 0 // TODO Remove void cifs_readdata_release(struct cifs_io_subrequest *rdata); static inline void cifs_get_readdata(struct cifs_io_subrequest *rdata) { @@ -609,11 +612,13 @@ static inline void cifs_put_readdata(struct cifs_io_subrequest *rdata) if (refcount_dec_and_test(&rdata->subreq.ref)) cifs_readdata_release(rdata); } +#endif int cifs_async_readv(struct cifs_io_subrequest *rdata); int cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid); -int cifs_async_writev(struct cifs_io_subrequest *wdata); +void cifs_async_writev(struct cifs_io_subrequest *wdata); void cifs_writev_complete(struct work_struct *work); +#if 0 // TODO Remove struct cifs_io_subrequest *cifs_writedata_alloc(work_func_t complete); void cifs_writedata_release(struct cifs_io_subrequest *rdata); static inline void cifs_get_writedata(struct cifs_io_subrequest *wdata) @@ -625,6 +630,7 @@ static inline void cifs_put_writedata(struct cifs_io_subrequest *wdata) if (refcount_dec_and_test(&wdata->subreq.ref)) cifs_writedata_release(wdata); } +#endif int cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, struct cifs_sb_info *cifs_sb, const unsigned char *path, char *pbuf, diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index 99b75102ba6b..25e9ab947c17 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -1265,7 +1265,7 @@ static void cifs_readv_callback(struct mid_q_entry *mid) { struct cifs_io_subrequest *rdata = mid->callback_data; - struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink); + struct cifs_tcon *tcon = tlink_tcon(rdata->req->cfile->tlink); struct TCP_Server_Info *server = tcon->ses->server; struct smb_rqst rqst = { .rq_iov = rdata->iov, .rq_nvec = 2, @@ -1306,7 +1306,13 @@ cifs_readv_callback(struct mid_q_entry *mid) rdata->result = -EIO; } - queue_work(cifsiod_wq, &rdata->work); + if (rdata->result == 0 || rdata->result == -EAGAIN) + iov_iter_advance(&rdata->subreq.io_iter, rdata->got_bytes); + rdata->credits.value = 0; + netfs_subreq_terminated(&rdata->subreq, + (rdata->result == 0 || rdata->result == -EAGAIN) ? + rdata->got_bytes : rdata->result, + false); release_mid(mid); add_credits(server, &credits, 0); } @@ -1318,7 +1324,7 @@ cifs_async_readv(struct cifs_io_subrequest *rdata) int rc; READ_REQ *smb = NULL; int wct; - struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink); + struct cifs_tcon *tcon = tlink_tcon(rdata->req->cfile->tlink); struct smb_rqst rqst = { .rq_iov = rdata->iov, .rq_nvec = 2 }; @@ -1343,7 +1349,7 @@ cifs_async_readv(struct cifs_io_subrequest *rdata) smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16)); smb->AndXCommand = 0xFF; /* none */ - smb->Fid = rdata->cfile->fid.netfid; + smb->Fid = rdata->req->cfile->fid.netfid; smb->OffsetLow = cpu_to_le32(rdata->subreq.start & 0xFFFFFFFF); if (wct == 12) smb->OffsetHigh = cpu_to_le32(rdata->subreq.start >> 32); @@ -1613,15 +1619,16 @@ static void cifs_writev_callback(struct mid_q_entry *mid) { struct cifs_io_subrequest *wdata = mid->callback_data; - struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink); - unsigned int written; + struct cifs_tcon *tcon = tlink_tcon(wdata->req->cfile->tlink); WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf; struct cifs_credits credits = { .value = 1, .instance = 0 }; + ssize_t result; + size_t written; switch (mid->mid_state) { case MID_RESPONSE_RECEIVED: - wdata->result = cifs_check_receive(mid, tcon->ses->server, 0); - if (wdata->result != 0) + result = cifs_check_receive(mid, tcon->ses->server, 0); + if (result != 0) break; written = le16_to_cpu(smb->CountHigh); @@ -1637,32 +1644,33 @@ cifs_writev_callback(struct mid_q_entry *mid) written &= 0xFFFF; if (written < wdata->subreq.len) - wdata->result = -ENOSPC; + result = -ENOSPC; else - wdata->subreq.len = written; + result = written; break; case MID_REQUEST_SUBMITTED: case MID_RETRY_NEEDED: - wdata->result = -EAGAIN; + result = -EAGAIN; break; default: - wdata->result = -EIO; + result = -EIO; break; } - queue_work(cifsiod_wq, &wdata->work); + wdata->credits.value = 0; + cifs_write_subrequest_terminated(wdata, result, true); release_mid(mid); add_credits(tcon->ses->server, &credits, 0); } /* cifs_async_writev - send an async write, and set up mid to handle result */ -int +void cifs_async_writev(struct cifs_io_subrequest *wdata) { int rc = -EACCES; WRITE_REQ *smb = NULL; int wct; - struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink); + struct cifs_tcon *tcon = tlink_tcon(wdata->req->cfile->tlink); struct kvec iov[2]; struct smb_rqst rqst = { }; @@ -1672,7 +1680,8 @@ cifs_async_writev(struct cifs_io_subrequest *wdata) wct = 12; if (wdata->subreq.start >> 32 > 0) { /* can not handle big offset for old srv */ - return -EIO; + rc = -EIO; + goto out; } } @@ -1684,7 +1693,7 @@ cifs_async_writev(struct cifs_io_subrequest *wdata) smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16)); smb->AndXCommand = 0xFF; /* none */ - smb->Fid = wdata->cfile->fid.netfid; + smb->Fid = wdata->req->cfile->fid.netfid; smb->OffsetLow = cpu_to_le32(wdata->subreq.start & 0xFFFFFFFF); if (wct == 14) smb->OffsetHigh = cpu_to_le32(wdata->subreq.start >> 32); @@ -1724,18 +1733,19 @@ cifs_async_writev(struct cifs_io_subrequest *wdata) iov[1].iov_len += 4; /* pad bigger by four bytes */ } - cifs_get_writedata(wdata); rc = cifs_call_async(tcon->ses->server, &rqst, NULL, cifs_writev_callback, NULL, wdata, 0, NULL); - + /* Can't touch wdata if rc == 0 */ if (rc == 0) cifs_stats_inc(&tcon->stats.cifs_stats.num_writes); - else - cifs_put_writedata(wdata); async_writev_out: cifs_small_buf_release(smb); - return rc; +out: + if (rc) { + add_credits_and_wake_if(wdata->server, &wdata->credits, 0); + cifs_write_subrequest_terminated(wdata, rc, false); + } } int diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c index c9c33b3a54f3..bb3adde9343e 100644 --- a/fs/smb/client/file.c +++ b/fs/smb/client/file.c @@ -119,7 +119,7 @@ fail: else trace_netfs_sreq(subreq, netfs_sreq_trace_fail); add_credits_and_wake_if(wdata->server, &wdata->credits, 0); - netfs_write_subrequest_terminated(wdata, rc, false); + cifs_write_subrequest_terminated(wdata, rc, false); goto out; } @@ -352,6 +352,7 @@ const struct netfs_request_ops cifs_req_ops = { .issue_write = cifs_issue_write, }; +#if 0 // TODO remove 397 /* * Remove the dirty flags from a span of pages. */ @@ -476,6 +477,7 @@ void cifs_pages_write_redirty(struct inode *inode, loff_t start, unsigned int le rcu_read_unlock(); } +#endif // end netfslib remove 397 /* * Mark as invalid, all open files on tree connections since they @@ -2522,20 +2524,23 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock) return rc; } -/* - * update the file size (if needed) after a write. Should be called with - * the inode->i_lock held - */ -void -cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, - unsigned int bytes_written) +void cifs_write_subrequest_terminated(struct cifs_io_subrequest *wdata, ssize_t result, + bool was_async) { - loff_t end_of_write = offset + bytes_written; + struct netfs_io_request *wreq = wdata->rreq; + loff_t new_server_eof; - if (end_of_write > cifsi->netfs.remote_i_size) - netfs_resize_file(&cifsi->netfs, end_of_write, true); + if (result > 0) { + new_server_eof = wdata->subreq.start + wdata->subreq.transferred + result; + + if (new_server_eof > netfs_inode(wreq->inode)->remote_i_size) + netfs_resize_file(netfs_inode(wreq->inode), new_server_eof, true); + } + + netfs_write_subrequest_terminated(&wdata->subreq, result, was_async); } +#if 0 // TODO remove 2483 static ssize_t cifs_write(struct cifsFileInfo *open_file, __u32 pid, const char *write_data, size_t write_size, loff_t *offset) @@ -2619,6 +2624,7 @@ cifs_write(struct cifsFileInfo *open_file, __u32 pid, const char *write_data, free_xid(xid); return total_written; } +#endif // end netfslib remove 2483 struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only) @@ -2824,6 +2830,7 @@ cifs_get_readable_path(struct cifs_tcon *tcon, const char *name, return -ENOENT; } +#if 0 // TODO remove 2773 void cifs_writedata_release(struct cifs_io_subrequest *wdata) { @@ -3454,7 +3461,11 @@ static int cifs_write_end(struct file *file, struct address_space *mapping, return rc; } +#endif // End netfs removal 2773 +/* + * Flush data on a strict file. + */ int cifs_strict_fsync(struct file *file, loff_t start, loff_t end, int datasync) { @@ -3509,6 +3520,9 @@ strict_fsync_exit: return rc; } +/* + * Flush data on a non-strict data. + */ int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync) { unsigned int xid; @@ -3575,6 +3589,7 @@ int cifs_flush(struct file *file, fl_owner_t id) return rc; } +#if 0 // TODO remove 3594 static void collect_uncached_write_data(struct cifs_aio_ctx *ctx); static void @@ -4037,6 +4052,7 @@ ssize_t cifs_user_writev(struct kiocb *iocb, struct iov_iter *from) { return __cifs_writev(iocb, from, false); } +#endif // TODO remove 3594 static ssize_t cifs_writev(struct kiocb *iocb, struct iov_iter *from) @@ -4048,7 +4064,10 @@ cifs_writev(struct kiocb *iocb, struct iov_iter *from) struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server; ssize_t rc; - inode_lock(inode); + rc = netfs_start_io_write(inode); + if (rc < 0) + return rc; + /* * We need to hold the sem to be sure nobody modifies lock list * with a brlock that prevents writing. @@ -4062,13 +4081,12 @@ cifs_writev(struct kiocb *iocb, struct iov_iter *from) if (!cifs_find_lock_conflict(cfile, iocb->ki_pos, iov_iter_count(from), server->vals->exclusive_lock_type, 0, NULL, CIFS_WRITE_OP)) - rc = __generic_file_write_iter(iocb, from); + rc = netfs_buffered_write_iter_locked(iocb, from, NULL); else rc = -EACCES; out: up_read(&cinode->lock_sem); - inode_unlock(inode); - + netfs_end_io_write(inode); if (rc > 0) rc = generic_write_sync(iocb, rc); return rc; @@ -4091,9 +4109,9 @@ cifs_strict_writev(struct kiocb *iocb, struct iov_iter *from) if (CIFS_CACHE_WRITE(cinode)) { if (cap_unix(tcon->ses) && - (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) - && ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) { - written = generic_file_write_iter(iocb, from); + (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) && + ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) { + written = netfs_file_write_iter(iocb, from); goto out; } written = cifs_writev(iocb, from); @@ -4105,7 +4123,7 @@ cifs_strict_writev(struct kiocb *iocb, struct iov_iter *from) * affected pages because it may cause a error with mandatory locks on * these pages but not on the region from pos to ppos+len-1. */ - written = cifs_user_writev(iocb, from); + written = netfs_file_write_iter(iocb, from); if (CIFS_CACHE_READ(cinode)) { /* * We have read level caching and we have just sent a write @@ -4124,6 +4142,7 @@ out: return written; } +#if 0 // TODO remove 4143 static struct cifs_io_subrequest *cifs_readdata_alloc(work_func_t complete) { struct cifs_io_subrequest *rdata; @@ -4563,7 +4582,9 @@ ssize_t cifs_direct_readv(struct kiocb *iocb, struct iov_iter *to) ssize_t cifs_user_readv(struct kiocb *iocb, struct iov_iter *to) { return __cifs_readv(iocb, to, false); + } +#endif // end netfslib removal 4143 ssize_t cifs_loose_read_iter(struct kiocb *iocb, struct iov_iter *iter) { @@ -4571,13 +4592,13 @@ ssize_t cifs_loose_read_iter(struct kiocb *iocb, struct iov_iter *iter) struct inode *inode = file_inode(iocb->ki_filp); if (iocb->ki_flags & IOCB_DIRECT) - return cifs_user_readv(iocb, iter); + return netfs_unbuffered_read_iter(iocb, iter); rc = cifs_revalidate_mapping(inode); if (rc) return rc; - return generic_file_read_iter(iocb, iter); + return netfs_file_read_iter(iocb, iter); } ssize_t cifs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) @@ -4588,7 +4609,7 @@ ssize_t cifs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) int rc; if (iocb->ki_filp->f_flags & O_DIRECT) { - written = cifs_user_writev(iocb, from); + written = netfs_unbuffered_write_iter(iocb, from); if (written > 0 && CIFS_CACHE_READ(cinode)) { cifs_zap_mapping(inode); cifs_dbg(FYI, @@ -4603,17 +4624,15 @@ ssize_t cifs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) if (written) return written; - written = generic_file_write_iter(iocb, from); - - if (CIFS_CACHE_WRITE(CIFS_I(inode))) - goto out; + written = netfs_file_write_iter(iocb, from); - rc = filemap_fdatawrite(inode->i_mapping); - if (rc) - cifs_dbg(FYI, "cifs_file_write_iter: %d rc on %p inode\n", - rc, inode); + if (!CIFS_CACHE_WRITE(CIFS_I(inode))) { + rc = filemap_fdatawrite(inode->i_mapping); + if (rc) + cifs_dbg(FYI, "cifs_file_write_iter: %d rc on %p inode\n", + rc, inode); + } -out: cifs_put_writer(cinode); return written; } @@ -4638,12 +4657,15 @@ cifs_strict_readv(struct kiocb *iocb, struct iov_iter *to) * pos+len-1. */ if (!CIFS_CACHE_READ(cinode)) - return cifs_user_readv(iocb, to); + return netfs_unbuffered_read_iter(iocb, to); if (cap_unix(tcon->ses) && (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) && - ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) - return generic_file_read_iter(iocb, to); + ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) { + if (iocb->ki_flags & IOCB_DIRECT) + return netfs_unbuffered_read_iter(iocb, to); + return netfs_buffered_read_iter(iocb, to); + } /* * We need to hold the sem to be sure nobody modifies lock list @@ -4652,12 +4674,17 @@ cifs_strict_readv(struct kiocb *iocb, struct iov_iter *to) down_read(&cinode->lock_sem); if (!cifs_find_lock_conflict(cfile, iocb->ki_pos, iov_iter_count(to), tcon->ses->server->vals->shared_lock_type, - 0, NULL, CIFS_READ_OP)) - rc = generic_file_read_iter(iocb, to); + 0, NULL, CIFS_READ_OP)) { + if (iocb->ki_flags & IOCB_DIRECT) + rc = netfs_unbuffered_read_iter(iocb, to); + else + rc = netfs_buffered_read_iter(iocb, to); + } up_read(&cinode->lock_sem); return rc; } +#if 0 // TODO remove 4633 static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, loff_t *offset) { @@ -4749,29 +4776,11 @@ cifs_read(struct file *file, char *read_data, size_t read_size, loff_t *offset) free_xid(xid); return total_read; } +#endif // end netfslib remove 4633 -/* - * If the page is mmap'ed into a process' page tables, then we need to make - * sure that it doesn't change while being written back. - */ static vm_fault_t cifs_page_mkwrite(struct vm_fault *vmf) { - struct folio *folio = page_folio(vmf->page); - - /* Wait for the folio to be written to the cache before we allow it to - * be modified. We then assume the entire folio will need writing back. - */ -#ifdef CONFIG_CIFS_FSCACHE - if (folio_test_private_2(folio) && /* [DEPRECATED] */ - folio_wait_private_2_killable(folio) < 0) - return VM_FAULT_RETRY; -#endif - - folio_wait_writeback(folio); - - if (folio_lock_killable(folio) < 0) - return VM_FAULT_RETRY; - return VM_FAULT_LOCKED; + return netfs_page_mkwrite(vmf, NULL); } static const struct vm_operations_struct cifs_file_vm_ops = { @@ -4817,6 +4826,7 @@ int cifs_file_mmap(struct file *file, struct vm_area_struct *vma) return rc; } +#if 0 // TODO remove 4794 /* * Unlock a bunch of folios in the pagecache. */ @@ -5101,6 +5111,7 @@ static int cifs_read_folio(struct file *file, struct folio *folio) free_xid(xid); return rc; } +#endif // end netfslib remove 4794 static int is_inode_writable(struct cifsInodeInfo *cifs_inode) { @@ -5149,6 +5160,7 @@ bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file, return true; } +#if 0 // TODO remove 5152 static int cifs_write_begin(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, struct page **pagep, void **fsdata) @@ -5244,6 +5256,7 @@ static void cifs_invalidate_folio(struct folio *folio, size_t offset, { folio_wait_private_2(folio); /* [DEPRECATED] */ } +#endif // end netfslib remove 5152 void cifs_oplock_break(struct work_struct *work) { @@ -5334,6 +5347,7 @@ out: cifs_done_oplock_break(cinode); } +#if 0 // TODO remove 5333 /* * The presence of cifs_direct_io() in the address space ops vector * allowes open() O_DIRECT flags which would have failed otherwise. @@ -5352,6 +5366,7 @@ cifs_direct_io(struct kiocb *iocb, struct iov_iter *iter) */ return -EINVAL; } +#endif // netfs end remove 5333 static int cifs_swap_activate(struct swap_info_struct *sis, struct file *swap_file, sector_t *span) @@ -5414,21 +5429,19 @@ static void cifs_swap_deactivate(struct file *file) } const struct address_space_operations cifs_addr_ops = { - .read_folio = cifs_read_folio, - .readahead = cifs_readahead, - .writepages = cifs_writepages, - .write_begin = cifs_write_begin, - .write_end = cifs_write_end, - .dirty_folio = netfs_dirty_folio, - .release_folio = cifs_release_folio, - .direct_IO = cifs_direct_io, - .invalidate_folio = cifs_invalidate_folio, - .migrate_folio = filemap_migrate_folio, + .read_folio = netfs_read_folio, + .readahead = netfs_readahead, + .writepages = netfs_writepages, + .dirty_folio = netfs_dirty_folio, + .release_folio = netfs_release_folio, + .direct_IO = noop_direct_IO, + .invalidate_folio = netfs_invalidate_folio, + .migrate_folio = filemap_migrate_folio, /* * TODO: investigate and if useful we could add an is_dirty_writeback * helper if needed */ - .swap_activate = cifs_swap_activate, + .swap_activate = cifs_swap_activate, .swap_deactivate = cifs_swap_deactivate, }; @@ -5438,12 +5451,10 @@ const struct address_space_operations cifs_addr_ops = { * to leave cifs_readahead out of the address space operations. */ const struct address_space_operations cifs_addr_ops_smallbuf = { - .read_folio = cifs_read_folio, - .writepages = cifs_writepages, - .write_begin = cifs_write_begin, - .write_end = cifs_write_end, - .dirty_folio = netfs_dirty_folio, - .release_folio = cifs_release_folio, - .invalidate_folio = cifs_invalidate_folio, - .migrate_folio = filemap_migrate_folio, + .read_folio = netfs_read_folio, + .writepages = netfs_writepages, + .dirty_folio = netfs_dirty_folio, + .release_folio = netfs_release_folio, + .invalidate_folio = netfs_invalidate_folio, + .migrate_folio = filemap_migrate_folio, }; diff --git a/fs/smb/client/fscache.c b/fs/smb/client/fscache.c index 1a895e6243ee..b36c493f4c56 100644 --- a/fs/smb/client/fscache.c +++ b/fs/smb/client/fscache.c @@ -171,6 +171,7 @@ void cifs_fscache_release_inode_cookie(struct inode *inode) } } +#if 0 // TODO remove /* * Fallback page reading interface. */ @@ -279,3 +280,4 @@ int __cifs_fscache_query_occupancy(struct inode *inode, fscache_end_operation(&cres); return ret; } +#endif diff --git a/fs/smb/client/fscache.h b/fs/smb/client/fscache.h index 1f2ea9f5cc9a..08b30f79d4cd 100644 --- a/fs/smb/client/fscache.h +++ b/fs/smb/client/fscache.h @@ -74,6 +74,7 @@ static inline void cifs_invalidate_cache(struct inode *inode, unsigned int flags i_size_read(inode), flags); } +#if 0 // TODO remove extern int __cifs_fscache_query_occupancy(struct inode *inode, pgoff_t first, unsigned int nr_pages, pgoff_t *_data_first, @@ -108,6 +109,7 @@ static inline void cifs_readahead_to_fscache(struct inode *inode, if (cifs_inode_cookie(inode)) __cifs_readahead_to_fscache(inode, pos, len); } +#endif static inline bool cifs_fscache_enabled(struct inode *inode) { @@ -131,6 +133,7 @@ static inline struct fscache_cookie *cifs_inode_cookie(struct inode *inode) { re static inline void cifs_invalidate_cache(struct inode *inode, unsigned int flags) {} static inline bool cifs_fscache_enabled(struct inode *inode) { return false; } +#if 0 // TODO remove static inline int cifs_fscache_query_occupancy(struct inode *inode, pgoff_t first, unsigned int nr_pages, pgoff_t *_data_first, @@ -149,6 +152,7 @@ cifs_readpage_from_fscache(struct inode *inode, struct page *page) static inline void cifs_readahead_to_fscache(struct inode *inode, loff_t pos, size_t len) {} +#endif #endif /* CONFIG_CIFS_FSCACHE */ diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c index 033948d34c5a..5239c823de86 100644 --- a/fs/smb/client/inode.c +++ b/fs/smb/client/inode.c @@ -28,14 +28,29 @@ #include "cached_dir.h" #include "reparse.h" +/* + * Set parameters for the netfs library + */ +static void cifs_set_netfs_context(struct inode *inode) +{ + struct cifsInodeInfo *cifs_i = CIFS_I(inode); + struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); + + netfs_inode_init(&cifs_i->netfs, &cifs_req_ops, true); + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) + __set_bit(NETFS_ICTX_WRITETHROUGH, &cifs_i->netfs.flags); +} + static void cifs_set_ops(struct inode *inode) { struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); + struct netfs_inode *ictx = netfs_inode(inode); switch (inode->i_mode & S_IFMT) { case S_IFREG: inode->i_op = &cifs_file_inode_ops; if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) { + set_bit(NETFS_ICTX_UNBUFFERED, &ictx->flags); if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) inode->i_fop = &cifs_file_direct_nobrl_ops; else @@ -221,8 +236,10 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr, if (fattr->cf_flags & CIFS_FATTR_JUNCTION) inode->i_flags |= S_AUTOMOUNT; - if (inode->i_state & I_NEW) + if (inode->i_state & I_NEW) { + cifs_set_netfs_context(inode); cifs_set_ops(inode); + } return 0; } diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index b063f5e95f5d..993ac36c3d58 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -4421,10 +4421,12 @@ smb2_new_read_req(void **buf, unsigned int *total_len, req->Length = cpu_to_le32(io_parms->length); req->Offset = cpu_to_le64(io_parms->offset); - trace_smb3_read_enter(0 /* xid */, - io_parms->persistent_fid, - io_parms->tcon->tid, io_parms->tcon->ses->Suid, - io_parms->offset, io_parms->length); + trace_smb3_read_enter(rdata ? rdata->rreq->debug_id : 0, + rdata ? rdata->subreq.debug_index : 0, + rdata ? rdata->xid : 0, + io_parms->persistent_fid, + io_parms->tcon->tid, io_parms->tcon->ses->Suid, + io_parms->offset, io_parms->length); #ifdef CONFIG_CIFS_SMB_DIRECT /* * If we want to do a RDMA write, fill in and append @@ -4486,7 +4488,7 @@ static void smb2_readv_callback(struct mid_q_entry *mid) { struct cifs_io_subrequest *rdata = mid->callback_data; - struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink); + struct cifs_tcon *tcon = tlink_tcon(rdata->req->cfile->tlink); struct TCP_Server_Info *server = rdata->server; struct smb2_hdr *shdr = (struct smb2_hdr *)rdata->iov[0].iov_base; @@ -4514,7 +4516,6 @@ smb2_readv_callback(struct mid_q_entry *mid) if (server->sign && !mid->decrypted) { int rc; - iov_iter_revert(&rqst.rq_iter, rdata->got_bytes); iov_iter_truncate(&rqst.rq_iter, rdata->got_bytes); rc = smb2_verify_signature(&rqst, server); if (rc) @@ -4555,17 +4556,33 @@ smb2_readv_callback(struct mid_q_entry *mid) #endif if (rdata->result && rdata->result != -ENODATA) { cifs_stats_fail_inc(tcon, SMB2_READ_HE); - trace_smb3_read_err(0 /* xid */, - rdata->cfile->fid.persistent_fid, + trace_smb3_read_err(rdata->rreq->debug_id, + rdata->subreq.debug_index, + rdata->xid, + rdata->req->cfile->fid.persistent_fid, tcon->tid, tcon->ses->Suid, rdata->subreq.start, rdata->subreq.len, rdata->result); } else - trace_smb3_read_done(0 /* xid */, - rdata->cfile->fid.persistent_fid, + trace_smb3_read_done(rdata->rreq->debug_id, + rdata->subreq.debug_index, + rdata->xid, + rdata->req->cfile->fid.persistent_fid, tcon->tid, tcon->ses->Suid, rdata->subreq.start, rdata->got_bytes); - queue_work(cifsiod_wq, &rdata->work); + if (rdata->result == -ENODATA) { + /* We may have got an EOF error because fallocate + * failed to enlarge the file. + */ + if (rdata->subreq.start < rdata->subreq.rreq->i_size) + rdata->result = 0; + } + if (rdata->result == 0 || rdata->result == -EAGAIN) + iov_iter_advance(&rdata->subreq.io_iter, rdata->got_bytes); + rdata->credits.value = 0; + netfs_subreq_terminated(&rdata->subreq, + (rdata->result == 0 || rdata->result == -EAGAIN) ? + rdata->got_bytes : rdata->result, true); release_mid(mid); add_credits(server, &credits, 0); } @@ -4581,7 +4598,7 @@ smb2_async_readv(struct cifs_io_subrequest *rdata) struct smb_rqst rqst = { .rq_iov = rdata->iov, .rq_nvec = 1 }; struct TCP_Server_Info *server; - struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink); + struct cifs_tcon *tcon = tlink_tcon(rdata->req->cfile->tlink); unsigned int total_len; int credit_request; @@ -4591,12 +4608,12 @@ smb2_async_readv(struct cifs_io_subrequest *rdata) if (!rdata->server) rdata->server = cifs_pick_channel(tcon->ses); - io_parms.tcon = tlink_tcon(rdata->cfile->tlink); + io_parms.tcon = tlink_tcon(rdata->req->cfile->tlink); io_parms.server = server = rdata->server; io_parms.offset = rdata->subreq.start; io_parms.length = rdata->subreq.len; - io_parms.persistent_fid = rdata->cfile->fid.persistent_fid; - io_parms.volatile_fid = rdata->cfile->fid.volatile_fid; + io_parms.persistent_fid = rdata->req->cfile->fid.persistent_fid; + io_parms.volatile_fid = rdata->req->cfile->fid.volatile_fid; io_parms.pid = rdata->pid; rc = smb2_new_read_req( @@ -4630,15 +4647,15 @@ smb2_async_readv(struct cifs_io_subrequest *rdata) flags |= CIFS_HAS_CREDITS; } - cifs_get_readdata(rdata); rc = cifs_call_async(server, &rqst, cifs_readv_receive, smb2_readv_callback, smb3_handle_read_data, rdata, flags, &rdata->credits); if (rc) { - cifs_put_readdata(rdata); cifs_stats_fail_inc(io_parms.tcon, SMB2_READ_HE); - trace_smb3_read_err(0 /* xid */, io_parms.persistent_fid, + trace_smb3_read_err(rdata->rreq->debug_id, + rdata->subreq.debug_index, + rdata->xid, io_parms.persistent_fid, io_parms.tcon->tid, io_parms.tcon->ses->Suid, io_parms.offset, io_parms.length, rc); @@ -4689,22 +4706,23 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms, if (rc != -ENODATA) { cifs_stats_fail_inc(io_parms->tcon, SMB2_READ_HE); cifs_dbg(VFS, "Send error in read = %d\n", rc); - trace_smb3_read_err(xid, + trace_smb3_read_err(0, 0, xid, req->PersistentFileId, io_parms->tcon->tid, ses->Suid, io_parms->offset, io_parms->length, rc); } else - trace_smb3_read_done(xid, req->PersistentFileId, io_parms->tcon->tid, + trace_smb3_read_done(0, 0, xid, + req->PersistentFileId, io_parms->tcon->tid, ses->Suid, io_parms->offset, 0); free_rsp_buf(resp_buftype, rsp_iov.iov_base); cifs_small_buf_release(req); return rc == -ENODATA ? 0 : rc; } else - trace_smb3_read_done(xid, - req->PersistentFileId, - io_parms->tcon->tid, ses->Suid, - io_parms->offset, io_parms->length); + trace_smb3_read_done(0, 0, xid, + req->PersistentFileId, + io_parms->tcon->tid, ses->Suid, + io_parms->offset, io_parms->length); cifs_small_buf_release(req); @@ -4738,11 +4756,12 @@ static void smb2_writev_callback(struct mid_q_entry *mid) { struct cifs_io_subrequest *wdata = mid->callback_data; - struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink); + struct cifs_tcon *tcon = tlink_tcon(wdata->req->cfile->tlink); struct TCP_Server_Info *server = wdata->server; - unsigned int written; struct smb2_write_rsp *rsp = (struct smb2_write_rsp *)mid->resp_buf; struct cifs_credits credits = { .value = 0, .instance = 0 }; + ssize_t result = 0; + size_t written; WARN_ONCE(wdata->server != mid->server, "wdata server %p != mid server %p", @@ -4752,8 +4771,8 @@ smb2_writev_callback(struct mid_q_entry *mid) case MID_RESPONSE_RECEIVED: credits.value = le16_to_cpu(rsp->hdr.CreditRequest); credits.instance = server->reconnect_instance; - wdata->result = smb2_check_receive(mid, server, 0); - if (wdata->result != 0) + result = smb2_check_receive(mid, server, 0); + if (result != 0) break; written = le32_to_cpu(rsp->DataLength); @@ -4770,17 +4789,18 @@ smb2_writev_callback(struct mid_q_entry *mid) wdata->result = -ENOSPC; else wdata->subreq.len = written; + iov_iter_advance(&wdata->subreq.io_iter, written); break; case MID_REQUEST_SUBMITTED: case MID_RETRY_NEEDED: - wdata->result = -EAGAIN; + result = -EAGAIN; break; case MID_RESPONSE_MALFORMED: credits.value = le16_to_cpu(rsp->hdr.CreditRequest); credits.instance = server->reconnect_instance; fallthrough; default: - wdata->result = -EIO; + result = -EIO; break; } #ifdef CONFIG_CIFS_SMB_DIRECT @@ -4796,10 +4816,10 @@ smb2_writev_callback(struct mid_q_entry *mid) wdata->mr = NULL; } #endif - if (wdata->result) { + if (result) { cifs_stats_fail_inc(tcon, SMB2_WRITE_HE); - trace_smb3_write_err(0 /* no xid */, - wdata->cfile->fid.persistent_fid, + trace_smb3_write_err(wdata->xid, + wdata->req->cfile->fid.persistent_fid, tcon->tid, tcon->ses->Suid, wdata->subreq.start, wdata->subreq.len, wdata->result); if (wdata->result == -ENOSPC) @@ -4807,27 +4827,28 @@ smb2_writev_callback(struct mid_q_entry *mid) tcon->tree_name); } else trace_smb3_write_done(0 /* no xid */, - wdata->cfile->fid.persistent_fid, + wdata->req->cfile->fid.persistent_fid, tcon->tid, tcon->ses->Suid, wdata->subreq.start, wdata->subreq.len); - queue_work(cifsiod_wq, &wdata->work); + wdata->credits.value = 0; + cifs_write_subrequest_terminated(wdata, result ?: written, true); release_mid(mid); add_credits(server, &credits, 0); } /* smb2_async_writev - send an async write, and set up mid to handle result */ -int +void smb2_async_writev(struct cifs_io_subrequest *wdata) { int rc = -EACCES, flags = 0; struct smb2_write_req *req = NULL; struct smb2_hdr *shdr; - struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink); + struct cifs_tcon *tcon = tlink_tcon(wdata->req->cfile->tlink); struct TCP_Server_Info *server = wdata->server; struct kvec iov[1]; struct smb_rqst rqst = { }; - unsigned int total_len; + unsigned int total_len, xid = wdata->xid; struct cifs_io_parms _io_parms; struct cifs_io_parms *io_parms = NULL; int credit_request; @@ -4844,8 +4865,8 @@ smb2_async_writev(struct cifs_io_subrequest *wdata) .server = server, .offset = wdata->subreq.start, .length = wdata->subreq.len, - .persistent_fid = wdata->cfile->fid.persistent_fid, - .volatile_fid = wdata->cfile->fid.volatile_fid, + .persistent_fid = wdata->req->cfile->fid.persistent_fid, + .volatile_fid = wdata->req->cfile->fid.volatile_fid, .pid = wdata->pid, }; io_parms = &_io_parms; @@ -4853,7 +4874,7 @@ smb2_async_writev(struct cifs_io_subrequest *wdata) rc = smb2_plain_req_init(SMB2_WRITE, tcon, server, (void **) &req, &total_len); if (rc) - return rc; + goto out; if (smb3_encryption_required(tcon)) flags |= CIFS_TRANSFORM_REQ; @@ -4871,7 +4892,7 @@ smb2_async_writev(struct cifs_io_subrequest *wdata) offsetof(struct smb2_write_req, Buffer)); req->RemainingBytes = 0; - trace_smb3_write_enter(0 /* xid */, + trace_smb3_write_enter(wdata->xid, io_parms->persistent_fid, io_parms->tcon->tid, io_parms->tcon->ses->Suid, @@ -4952,25 +4973,27 @@ smb2_async_writev(struct cifs_io_subrequest *wdata) flags |= CIFS_HAS_CREDITS; } - cifs_get_writedata(wdata); rc = cifs_call_async(server, &rqst, NULL, smb2_writev_callback, NULL, wdata, flags, &wdata->credits); - + /* Can't touch wdata if rc == 0 */ if (rc) { - trace_smb3_write_err(0 /* no xid */, + trace_smb3_write_err(xid, io_parms->persistent_fid, io_parms->tcon->tid, io_parms->tcon->ses->Suid, io_parms->offset, io_parms->length, rc); - cifs_put_writedata(wdata); cifs_stats_fail_inc(tcon, SMB2_WRITE_HE); } async_writev_out: cifs_small_buf_release(req); - return rc; +out: + if (rc) { + add_credits_and_wake_if(wdata->server, &wdata->credits, 0); + cifs_write_subrequest_terminated(wdata, rc, true); + } } /* diff --git a/fs/smb/client/smb2proto.h b/fs/smb/client/smb2proto.h index c781eaa0cba8..b208232b12a2 100644 --- a/fs/smb/client/smb2proto.h +++ b/fs/smb/client/smb2proto.h @@ -213,7 +213,7 @@ extern int SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon, extern int smb2_async_readv(struct cifs_io_subrequest *rdata); extern int SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms, unsigned int *nbytes, char **buf, int *buf_type); -extern int smb2_async_writev(struct cifs_io_subrequest *wdata); +extern void smb2_async_writev(struct cifs_io_subrequest *wdata); extern int SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms, unsigned int *nbytes, struct kvec *iov, int n_vec); extern int SMB2_echo(struct TCP_Server_Info *server); diff --git a/fs/smb/client/trace.h b/fs/smb/client/trace.h index 604e52876cd2..af97389e983e 100644 --- a/fs/smb/client/trace.h +++ b/fs/smb/client/trace.h @@ -85,6 +85,62 @@ smb3_tcon_ref_traces; /* For logging errors in read or write */ DECLARE_EVENT_CLASS(smb3_rw_err_class, + TP_PROTO(unsigned int rreq_debug_id, + unsigned int rreq_debug_index, + unsigned int xid, + __u64 fid, + __u32 tid, + __u64 sesid, + __u64 offset, + __u32 len, + int rc), + TP_ARGS(rreq_debug_id, rreq_debug_index, + xid, fid, tid, sesid, offset, len, rc), + TP_STRUCT__entry( + __field(unsigned int, rreq_debug_id) + __field(unsigned int, rreq_debug_index) + __field(unsigned int, xid) + __field(__u64, fid) + __field(__u32, tid) + __field(__u64, sesid) + __field(__u64, offset) + __field(__u32, len) + __field(int, rc) + ), + TP_fast_assign( + __entry->rreq_debug_id = rreq_debug_id; + __entry->rreq_debug_index = rreq_debug_index; + __entry->xid = xid; + __entry->fid = fid; + __entry->tid = tid; + __entry->sesid = sesid; + __entry->offset = offset; + __entry->len = len; + __entry->rc = rc; + ), + TP_printk("\tR=%08x[%x] xid=%u sid=0x%llx tid=0x%x fid=0x%llx offset=0x%llx len=0x%x rc=%d", + __entry->rreq_debug_id, __entry->rreq_debug_index, + __entry->xid, __entry->sesid, __entry->tid, __entry->fid, + __entry->offset, __entry->len, __entry->rc) +) + +#define DEFINE_SMB3_RW_ERR_EVENT(name) \ +DEFINE_EVENT(smb3_rw_err_class, smb3_##name, \ + TP_PROTO(unsigned int rreq_debug_id, \ + unsigned int rreq_debug_index, \ + unsigned int xid, \ + __u64 fid, \ + __u32 tid, \ + __u64 sesid, \ + __u64 offset, \ + __u32 len, \ + int rc), \ + TP_ARGS(rreq_debug_id, rreq_debug_index, xid, fid, tid, sesid, offset, len, rc)) + +DEFINE_SMB3_RW_ERR_EVENT(read_err); + +/* For logging errors in other file I/O ops */ +DECLARE_EVENT_CLASS(smb3_other_err_class, TP_PROTO(unsigned int xid, __u64 fid, __u32 tid, @@ -116,8 +172,8 @@ DECLARE_EVENT_CLASS(smb3_rw_err_class, __entry->offset, __entry->len, __entry->rc) ) -#define DEFINE_SMB3_RW_ERR_EVENT(name) \ -DEFINE_EVENT(smb3_rw_err_class, smb3_##name, \ +#define DEFINE_SMB3_OTHER_ERR_EVENT(name) \ +DEFINE_EVENT(smb3_other_err_class, smb3_##name, \ TP_PROTO(unsigned int xid, \ __u64 fid, \ __u32 tid, \ @@ -127,15 +183,67 @@ DEFINE_EVENT(smb3_rw_err_class, smb3_##name, \ int rc), \ TP_ARGS(xid, fid, tid, sesid, offset, len, rc)) -DEFINE_SMB3_RW_ERR_EVENT(write_err); -DEFINE_SMB3_RW_ERR_EVENT(read_err); -DEFINE_SMB3_RW_ERR_EVENT(query_dir_err); -DEFINE_SMB3_RW_ERR_EVENT(zero_err); -DEFINE_SMB3_RW_ERR_EVENT(falloc_err); +DEFINE_SMB3_OTHER_ERR_EVENT(write_err); +DEFINE_SMB3_OTHER_ERR_EVENT(query_dir_err); +DEFINE_SMB3_OTHER_ERR_EVENT(zero_err); +DEFINE_SMB3_OTHER_ERR_EVENT(falloc_err); /* For logging successful read or write */ DECLARE_EVENT_CLASS(smb3_rw_done_class, + TP_PROTO(unsigned int rreq_debug_id, + unsigned int rreq_debug_index, + unsigned int xid, + __u64 fid, + __u32 tid, + __u64 sesid, + __u64 offset, + __u32 len), + TP_ARGS(rreq_debug_id, rreq_debug_index, + xid, fid, tid, sesid, offset, len), + TP_STRUCT__entry( + __field(unsigned int, rreq_debug_id) + __field(unsigned int, rreq_debug_index) + __field(unsigned int, xid) + __field(__u64, fid) + __field(__u32, tid) + __field(__u64, sesid) + __field(__u64, offset) + __field(__u32, len) + ), + TP_fast_assign( + __entry->rreq_debug_id = rreq_debug_id; + __entry->rreq_debug_index = rreq_debug_index; + __entry->xid = xid; + __entry->fid = fid; + __entry->tid = tid; + __entry->sesid = sesid; + __entry->offset = offset; + __entry->len = len; + ), + TP_printk("R=%08x[%x] xid=%u sid=0x%llx tid=0x%x fid=0x%llx offset=0x%llx len=0x%x", + __entry->rreq_debug_id, __entry->rreq_debug_index, + __entry->xid, __entry->sesid, __entry->tid, __entry->fid, + __entry->offset, __entry->len) +) + +#define DEFINE_SMB3_RW_DONE_EVENT(name) \ +DEFINE_EVENT(smb3_rw_done_class, smb3_##name, \ + TP_PROTO(unsigned int rreq_debug_id, \ + unsigned int rreq_debug_index, \ + unsigned int xid, \ + __u64 fid, \ + __u32 tid, \ + __u64 sesid, \ + __u64 offset, \ + __u32 len), \ + TP_ARGS(rreq_debug_id, rreq_debug_index, xid, fid, tid, sesid, offset, len)) + +DEFINE_SMB3_RW_DONE_EVENT(read_enter); +DEFINE_SMB3_RW_DONE_EVENT(read_done); + +/* For logging successful other op */ +DECLARE_EVENT_CLASS(smb3_other_done_class, TP_PROTO(unsigned int xid, __u64 fid, __u32 tid, @@ -164,8 +272,8 @@ DECLARE_EVENT_CLASS(smb3_rw_done_class, __entry->offset, __entry->len) ) -#define DEFINE_SMB3_RW_DONE_EVENT(name) \ -DEFINE_EVENT(smb3_rw_done_class, smb3_##name, \ +#define DEFINE_SMB3_OTHER_DONE_EVENT(name) \ +DEFINE_EVENT(smb3_other_done_class, smb3_##name, \ TP_PROTO(unsigned int xid, \ __u64 fid, \ __u32 tid, \ @@ -174,16 +282,14 @@ DEFINE_EVENT(smb3_rw_done_class, smb3_##name, \ __u32 len), \ TP_ARGS(xid, fid, tid, sesid, offset, len)) -DEFINE_SMB3_RW_DONE_EVENT(write_enter); -DEFINE_SMB3_RW_DONE_EVENT(read_enter); -DEFINE_SMB3_RW_DONE_EVENT(query_dir_enter); -DEFINE_SMB3_RW_DONE_EVENT(zero_enter); -DEFINE_SMB3_RW_DONE_EVENT(falloc_enter); -DEFINE_SMB3_RW_DONE_EVENT(write_done); -DEFINE_SMB3_RW_DONE_EVENT(read_done); -DEFINE_SMB3_RW_DONE_EVENT(query_dir_done); -DEFINE_SMB3_RW_DONE_EVENT(zero_done); -DEFINE_SMB3_RW_DONE_EVENT(falloc_done); +DEFINE_SMB3_OTHER_DONE_EVENT(write_enter); +DEFINE_SMB3_OTHER_DONE_EVENT(query_dir_enter); +DEFINE_SMB3_OTHER_DONE_EVENT(zero_enter); +DEFINE_SMB3_OTHER_DONE_EVENT(falloc_enter); +DEFINE_SMB3_OTHER_DONE_EVENT(write_done); +DEFINE_SMB3_OTHER_DONE_EVENT(query_dir_done); +DEFINE_SMB3_OTHER_DONE_EVENT(zero_done); +DEFINE_SMB3_OTHER_DONE_EVENT(falloc_done); /* For logging successful set EOF (truncate) */ DECLARE_EVENT_CLASS(smb3_eof_class, diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c index 4c8af995c60b..012b9bd06995 100644 --- a/fs/smb/client/transport.c +++ b/fs/smb/client/transport.c @@ -1813,8 +1813,11 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) length = data_len; /* An RDMA read is already done. */ else #endif + { length = cifs_read_iter_from_socket(server, &rdata->subreq.io_iter, data_len); + iov_iter_revert(&rdata->subreq.io_iter, data_len); + } if (length > 0) rdata->got_bytes += length; server->total_read += length; -- cgit From 742b3443e23104fc81edbeccfb993ae350aae981 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 6 Oct 2023 22:27:15 +0100 Subject: cifs: Remove some code that's no longer used, part 1 Remove some code that was #if'd out with the netfslib conversion. This is split into parts for file.c as the diff generator otherwise produces a hard to read diff for part of it where a big chunk is cut out. Signed-off-by: David Howells cc: Steve French cc: Shyam Prasad N cc: Rohith Surabattula cc: Jeff Layton cc: linux-cifs@vger.kernel.org cc: netfs@lists.linux.dev cc: linux-fsdevel@vger.kernel.org cc: linux-mm@kvack.org --- fs/smb/client/cifsglob.h | 12 - fs/smb/client/cifsproto.h | 25 -- fs/smb/client/file.c | 619 ---------------------------------------------- fs/smb/client/fscache.c | 111 --------- fs/smb/client/fscache.h | 58 ----- 5 files changed, 825 deletions(-) (limited to 'fs/smb') diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 983860bf5fbb..65574e69ba4f 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -1515,18 +1515,6 @@ struct cifs_io_subrequest { struct smbd_mr *mr; #endif struct cifs_credits credits; - -#if 0 // TODO: Remove following elements - struct list_head list; - struct completion done; - struct work_struct work; - struct cifsFileInfo *cfile; - struct address_space *mapping; - struct cifs_aio_ctx *ctx; - enum writeback_sync_modes sync_mode; - bool uncached; - struct bio_vec *bv; -#endif }; /* diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h index d46ad86150cd..c15bb5ee7eb7 100644 --- a/fs/smb/client/cifsproto.h +++ b/fs/smb/client/cifsproto.h @@ -601,36 +601,11 @@ void __cifs_put_smb_ses(struct cifs_ses *ses); extern struct cifs_ses * cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx); -#if 0 // TODO Remove -void cifs_readdata_release(struct cifs_io_subrequest *rdata); -static inline void cifs_get_readdata(struct cifs_io_subrequest *rdata) -{ - refcount_inc(&rdata->subreq.ref); -} -static inline void cifs_put_readdata(struct cifs_io_subrequest *rdata) -{ - if (refcount_dec_and_test(&rdata->subreq.ref)) - cifs_readdata_release(rdata); -} -#endif int cifs_async_readv(struct cifs_io_subrequest *rdata); int cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid); void cifs_async_writev(struct cifs_io_subrequest *wdata); void cifs_writev_complete(struct work_struct *work); -#if 0 // TODO Remove -struct cifs_io_subrequest *cifs_writedata_alloc(work_func_t complete); -void cifs_writedata_release(struct cifs_io_subrequest *rdata); -static inline void cifs_get_writedata(struct cifs_io_subrequest *wdata) -{ - refcount_inc(&wdata->subreq.ref); -} -static inline void cifs_put_writedata(struct cifs_io_subrequest *wdata) -{ - if (refcount_dec_and_test(&wdata->subreq.ref)) - cifs_writedata_release(wdata); -} -#endif int cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, struct cifs_sb_info *cifs_sb, const unsigned char *path, char *pbuf, diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c index bb3adde9343e..6088d0f80522 100644 --- a/fs/smb/client/file.c +++ b/fs/smb/client/file.c @@ -352,133 +352,6 @@ const struct netfs_request_ops cifs_req_ops = { .issue_write = cifs_issue_write, }; -#if 0 // TODO remove 397 -/* - * Remove the dirty flags from a span of pages. - */ -static void cifs_undirty_folios(struct inode *inode, loff_t start, unsigned int len) -{ - struct address_space *mapping = inode->i_mapping; - struct folio *folio; - pgoff_t end; - - XA_STATE(xas, &mapping->i_pages, start / PAGE_SIZE); - - rcu_read_lock(); - - end = (start + len - 1) / PAGE_SIZE; - xas_for_each_marked(&xas, folio, end, PAGECACHE_TAG_DIRTY) { - if (xas_retry(&xas, folio)) - continue; - xas_pause(&xas); - rcu_read_unlock(); - folio_lock(folio); - folio_clear_dirty_for_io(folio); - folio_unlock(folio); - rcu_read_lock(); - } - - rcu_read_unlock(); -} - -/* - * Completion of write to server. - */ -void cifs_pages_written_back(struct inode *inode, loff_t start, unsigned int len) -{ - struct address_space *mapping = inode->i_mapping; - struct folio *folio; - pgoff_t end; - - XA_STATE(xas, &mapping->i_pages, start / PAGE_SIZE); - - if (!len) - return; - - rcu_read_lock(); - - end = (start + len - 1) / PAGE_SIZE; - xas_for_each(&xas, folio, end) { - if (xas_retry(&xas, folio)) - continue; - if (!folio_test_writeback(folio)) { - WARN_ONCE(1, "bad %x @%llx page %lx %lx\n", - len, start, folio->index, end); - continue; - } - - folio_detach_private(folio); - folio_end_writeback(folio); - } - - rcu_read_unlock(); -} - -/* - * Failure of write to server. - */ -void cifs_pages_write_failed(struct inode *inode, loff_t start, unsigned int len) -{ - struct address_space *mapping = inode->i_mapping; - struct folio *folio; - pgoff_t end; - - XA_STATE(xas, &mapping->i_pages, start / PAGE_SIZE); - - if (!len) - return; - - rcu_read_lock(); - - end = (start + len - 1) / PAGE_SIZE; - xas_for_each(&xas, folio, end) { - if (xas_retry(&xas, folio)) - continue; - if (!folio_test_writeback(folio)) { - WARN_ONCE(1, "bad %x @%llx page %lx %lx\n", - len, start, folio->index, end); - continue; - } - - folio_set_error(folio); - folio_end_writeback(folio); - } - - rcu_read_unlock(); -} - -/* - * Redirty pages after a temporary failure. - */ -void cifs_pages_write_redirty(struct inode *inode, loff_t start, unsigned int len) -{ - struct address_space *mapping = inode->i_mapping; - struct folio *folio; - pgoff_t end; - - XA_STATE(xas, &mapping->i_pages, start / PAGE_SIZE); - - if (!len) - return; - - rcu_read_lock(); - - end = (start + len - 1) / PAGE_SIZE; - xas_for_each(&xas, folio, end) { - if (!folio_test_writeback(folio)) { - WARN_ONCE(1, "bad %x @%llx page %lx %lx\n", - len, start, folio->index, end); - continue; - } - - filemap_dirty_folio(folio->mapping, folio); - folio_end_writeback(folio); - } - - rcu_read_unlock(); -} -#endif // end netfslib remove 397 - /* * Mark as invalid, all open files on tree connections since they * were closed when session to server was lost. @@ -2540,92 +2413,6 @@ void cifs_write_subrequest_terminated(struct cifs_io_subrequest *wdata, ssize_t netfs_write_subrequest_terminated(&wdata->subreq, result, was_async); } -#if 0 // TODO remove 2483 -static ssize_t -cifs_write(struct cifsFileInfo *open_file, __u32 pid, const char *write_data, - size_t write_size, loff_t *offset) -{ - int rc = 0; - unsigned int bytes_written = 0; - unsigned int total_written; - struct cifs_tcon *tcon; - struct TCP_Server_Info *server; - unsigned int xid; - struct dentry *dentry = open_file->dentry; - struct cifsInodeInfo *cifsi = CIFS_I(d_inode(dentry)); - struct cifs_io_parms io_parms = {0}; - - cifs_dbg(FYI, "write %zd bytes to offset %lld of %pd\n", - write_size, *offset, dentry); - - tcon = tlink_tcon(open_file->tlink); - server = tcon->ses->server; - - if (!server->ops->sync_write) - return -ENOSYS; - - xid = get_xid(); - - for (total_written = 0; write_size > total_written; - total_written += bytes_written) { - rc = -EAGAIN; - while (rc == -EAGAIN) { - struct kvec iov[2]; - unsigned int len; - - if (open_file->invalidHandle) { - /* we could deadlock if we called - filemap_fdatawait from here so tell - reopen_file not to flush data to - server now */ - rc = cifs_reopen_file(open_file, false); - if (rc != 0) - break; - } - - len = min(server->ops->wp_retry_size(d_inode(dentry)), - (unsigned int)write_size - total_written); - /* iov[0] is reserved for smb header */ - iov[1].iov_base = (char *)write_data + total_written; - iov[1].iov_len = len; - io_parms.pid = pid; - io_parms.tcon = tcon; - io_parms.offset = *offset; - io_parms.length = len; - rc = server->ops->sync_write(xid, &open_file->fid, - &io_parms, &bytes_written, iov, 1); - } - if (rc || (bytes_written == 0)) { - if (total_written) - break; - else { - free_xid(xid); - return rc; - } - } else { - spin_lock(&d_inode(dentry)->i_lock); - cifs_update_eof(cifsi, *offset, bytes_written); - spin_unlock(&d_inode(dentry)->i_lock); - *offset += bytes_written; - } - } - - cifs_stats_bytes_written(tcon, total_written); - - if (total_written > 0) { - spin_lock(&d_inode(dentry)->i_lock); - if (*offset > d_inode(dentry)->i_size) { - i_size_write(d_inode(dentry), *offset); - d_inode(dentry)->i_blocks = (512 - 1 + *offset) >> 9; - } - spin_unlock(&d_inode(dentry)->i_lock); - } - mark_inode_dirty_sync(d_inode(dentry)); - free_xid(xid); - return total_written; -} -#endif // end netfslib remove 2483 - struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only) { @@ -4826,293 +4613,6 @@ int cifs_file_mmap(struct file *file, struct vm_area_struct *vma) return rc; } -#if 0 // TODO remove 4794 -/* - * Unlock a bunch of folios in the pagecache. - */ -static void cifs_unlock_folios(struct address_space *mapping, pgoff_t first, pgoff_t last) -{ - struct folio *folio; - XA_STATE(xas, &mapping->i_pages, first); - - rcu_read_lock(); - xas_for_each(&xas, folio, last) { - folio_unlock(folio); - } - rcu_read_unlock(); -} - -static void cifs_readahead_complete(struct work_struct *work) -{ - struct cifs_io_subrequest *rdata = container_of(work, - struct cifs_io_subrequest, work); - struct folio *folio; - pgoff_t last; - bool good = rdata->result == 0 || (rdata->result == -EAGAIN && rdata->got_bytes); - - XA_STATE(xas, &rdata->mapping->i_pages, rdata->subreq.start / PAGE_SIZE); - - if (good) - cifs_readahead_to_fscache(rdata->mapping->host, - rdata->subreq.start, rdata->subreq.len); - - if (iov_iter_count(&rdata->subreq.io_iter) > 0) - iov_iter_zero(iov_iter_count(&rdata->subreq.io_iter), &rdata->subreq.io_iter); - - last = (rdata->subreq.start + rdata->subreq.len - 1) / PAGE_SIZE; - - rcu_read_lock(); - xas_for_each(&xas, folio, last) { - if (good) { - flush_dcache_folio(folio); - folio_mark_uptodate(folio); - } - folio_unlock(folio); - } - rcu_read_unlock(); - - cifs_put_readdata(rdata); -} - -static void cifs_readahead(struct readahead_control *ractl) -{ - struct cifsFileInfo *open_file = ractl->file->private_data; - struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(ractl->file); - struct TCP_Server_Info *server; - unsigned int xid, nr_pages, cache_nr_pages = 0; - unsigned int ra_pages; - pgoff_t next_cached = ULONG_MAX, ra_index; - bool caching = fscache_cookie_enabled(cifs_inode_cookie(ractl->mapping->host)) && - cifs_inode_cookie(ractl->mapping->host)->cache_priv; - bool check_cache = caching; - pid_t pid; - int rc = 0; - - /* Note that readahead_count() lags behind our dequeuing of pages from - * the ractl, wo we have to keep track for ourselves. - */ - ra_pages = readahead_count(ractl); - ra_index = readahead_index(ractl); - - xid = get_xid(); - - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD) - pid = open_file->pid; - else - pid = current->tgid; - - server = cifs_pick_channel(tlink_tcon(open_file->tlink)->ses); - - cifs_dbg(FYI, "%s: file=%p mapping=%p num_pages=%u\n", - __func__, ractl->file, ractl->mapping, ra_pages); - - /* - * Chop the readahead request up into rsize-sized read requests. - */ - while ((nr_pages = ra_pages)) { - unsigned int i; - struct cifs_io_subrequest *rdata; - struct cifs_credits credits_on_stack; - struct cifs_credits *credits = &credits_on_stack; - struct folio *folio; - pgoff_t fsize; - size_t rsize; - - /* - * Find out if we have anything cached in the range of - * interest, and if so, where the next chunk of cached data is. - */ - if (caching) { - if (check_cache) { - rc = cifs_fscache_query_occupancy( - ractl->mapping->host, ra_index, nr_pages, - &next_cached, &cache_nr_pages); - if (rc < 0) - caching = false; - check_cache = false; - } - - if (ra_index == next_cached) { - /* - * TODO: Send a whole batch of pages to be read - * by the cache. - */ - folio = readahead_folio(ractl); - fsize = folio_nr_pages(folio); - ra_pages -= fsize; - ra_index += fsize; - if (cifs_readpage_from_fscache(ractl->mapping->host, - &folio->page) < 0) { - /* - * TODO: Deal with cache read failure - * here, but for the moment, delegate - * that to readpage. - */ - caching = false; - } - folio_unlock(folio); - next_cached += fsize; - cache_nr_pages -= fsize; - if (cache_nr_pages == 0) - check_cache = true; - continue; - } - } - - if (open_file->invalidHandle) { - rc = cifs_reopen_file(open_file, true); - if (rc) { - if (rc == -EAGAIN) - continue; - break; - } - } - - if (cifs_sb->ctx->rsize == 0) - cifs_sb->ctx->rsize = - server->ops->negotiate_rsize(tlink_tcon(open_file->tlink), - cifs_sb->ctx); - - rc = server->ops->wait_mtu_credits(server, cifs_sb->ctx->rsize, - &rsize, credits); - if (rc) - break; - nr_pages = min_t(size_t, rsize / PAGE_SIZE, ra_pages); - if (next_cached != ULONG_MAX) - nr_pages = min_t(size_t, nr_pages, next_cached - ra_index); - - /* - * Give up immediately if rsize is too small to read an entire - * page. The VFS will fall back to readpage. We should never - * reach this point however since we set ra_pages to 0 when the - * rsize is smaller than a cache page. - */ - if (unlikely(!nr_pages)) { - add_credits_and_wake_if(server, credits, 0); - break; - } - - rdata = cifs_readdata_alloc(cifs_readahead_complete); - if (!rdata) { - /* best to give up if we're out of mem */ - add_credits_and_wake_if(server, credits, 0); - break; - } - - rdata->subreq.start = ra_index * PAGE_SIZE; - rdata->subreq.len = nr_pages * PAGE_SIZE; - rdata->cfile = cifsFileInfo_get(open_file); - rdata->server = server; - rdata->mapping = ractl->mapping; - rdata->pid = pid; - rdata->credits = credits_on_stack; - - for (i = 0; i < nr_pages; i++) { - if (!readahead_folio(ractl)) - WARN_ON(1); - } - ra_pages -= nr_pages; - ra_index += nr_pages; - - iov_iter_xarray(&rdata->subreq.io_iter, ITER_DEST, &rdata->mapping->i_pages, - rdata->subreq.start, rdata->subreq.len); - - rc = adjust_credits(server, &rdata->credits, rdata->subreq.len); - if (!rc) { - if (rdata->cfile->invalidHandle) - rc = -EAGAIN; - else - rc = server->ops->async_readv(rdata); - } - - if (rc) { - add_credits_and_wake_if(server, &rdata->credits, 0); - cifs_unlock_folios(rdata->mapping, - rdata->subreq.start / PAGE_SIZE, - (rdata->subreq.start + rdata->subreq.len - 1) / PAGE_SIZE); - /* Fallback to the readpage in error/reconnect cases */ - cifs_put_readdata(rdata); - break; - } - - cifs_put_readdata(rdata); - } - - free_xid(xid); -} - -/* - * cifs_readpage_worker must be called with the page pinned - */ -static int cifs_readpage_worker(struct file *file, struct page *page, - loff_t *poffset) -{ - struct inode *inode = file_inode(file); - struct timespec64 atime, mtime; - char *read_data; - int rc; - - /* Is the page cached? */ - rc = cifs_readpage_from_fscache(inode, page); - if (rc == 0) - goto read_complete; - - read_data = kmap(page); - /* for reads over a certain size could initiate async read ahead */ - - rc = cifs_read(file, read_data, PAGE_SIZE, poffset); - - if (rc < 0) - goto io_error; - else - cifs_dbg(FYI, "Bytes read %d\n", rc); - - /* we do not want atime to be less than mtime, it broke some apps */ - atime = inode_set_atime_to_ts(inode, current_time(inode)); - mtime = inode_get_mtime(inode); - if (timespec64_compare(&atime, &mtime) < 0) - inode_set_atime_to_ts(inode, inode_get_mtime(inode)); - - if (PAGE_SIZE > rc) - memset(read_data + rc, 0, PAGE_SIZE - rc); - - flush_dcache_page(page); - SetPageUptodate(page); - rc = 0; - -io_error: - kunmap(page); - -read_complete: - unlock_page(page); - return rc; -} - -static int cifs_read_folio(struct file *file, struct folio *folio) -{ - struct page *page = &folio->page; - loff_t offset = page_file_offset(page); - int rc = -EACCES; - unsigned int xid; - - xid = get_xid(); - - if (file->private_data == NULL) { - rc = -EBADF; - free_xid(xid); - return rc; - } - - cifs_dbg(FYI, "read_folio %p at offset %d 0x%x\n", - page, (int)offset, (int)offset); - - rc = cifs_readpage_worker(file, page, &offset); - - free_xid(xid); - return rc; -} -#endif // end netfslib remove 4794 - static int is_inode_writable(struct cifsInodeInfo *cifs_inode) { struct cifsFileInfo *open_file; @@ -5160,104 +4660,6 @@ bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file, return true; } -#if 0 // TODO remove 5152 -static int cifs_write_begin(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, - struct page **pagep, void **fsdata) -{ - int oncethru = 0; - pgoff_t index = pos >> PAGE_SHIFT; - loff_t offset = pos & (PAGE_SIZE - 1); - loff_t page_start = pos & PAGE_MASK; - loff_t i_size; - struct page *page; - int rc = 0; - - cifs_dbg(FYI, "write_begin from %lld len %d\n", (long long)pos, len); - -start: - page = grab_cache_page_write_begin(mapping, index); - if (!page) { - rc = -ENOMEM; - goto out; - } - - if (PageUptodate(page)) - goto out; - - /* - * If we write a full page it will be up to date, no need to read from - * the server. If the write is short, we'll end up doing a sync write - * instead. - */ - if (len == PAGE_SIZE) - goto out; - - /* - * optimize away the read when we have an oplock, and we're not - * expecting to use any of the data we'd be reading in. That - * is, when the page lies beyond the EOF, or straddles the EOF - * and the write will cover all of the existing data. - */ - if (CIFS_CACHE_READ(CIFS_I(mapping->host))) { - i_size = i_size_read(mapping->host); - if (page_start >= i_size || - (offset == 0 && (pos + len) >= i_size)) { - zero_user_segments(page, 0, offset, - offset + len, - PAGE_SIZE); - /* - * PageChecked means that the parts of the page - * to which we're not writing are considered up - * to date. Once the data is copied to the - * page, it can be set uptodate. - */ - SetPageChecked(page); - goto out; - } - } - - if ((file->f_flags & O_ACCMODE) != O_WRONLY && !oncethru) { - /* - * might as well read a page, it is fast enough. If we get - * an error, we don't need to return it. cifs_write_end will - * do a sync write instead since PG_uptodate isn't set. - */ - cifs_readpage_worker(file, page, &page_start); - put_page(page); - oncethru = 1; - goto start; - } else { - /* we could try using another file handle if there is one - - but how would we lock it to prevent close of that handle - racing with this read? In any case - this will be written out by write_end so is fine */ - } -out: - *pagep = page; - return rc; -} - -static bool cifs_release_folio(struct folio *folio, gfp_t gfp) -{ - if (folio_test_private(folio)) - return 0; - if (folio_test_private_2(folio)) { /* [DEPRECATED] */ - if (current_is_kswapd() || !(gfp & __GFP_FS)) - return false; - folio_wait_private_2(folio); - } - fscache_note_page_release(cifs_inode_cookie(folio->mapping->host)); - return true; -} - -static void cifs_invalidate_folio(struct folio *folio, size_t offset, - size_t length) -{ - folio_wait_private_2(folio); /* [DEPRECATED] */ -} -#endif // end netfslib remove 5152 - void cifs_oplock_break(struct work_struct *work) { struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, @@ -5347,27 +4749,6 @@ out: cifs_done_oplock_break(cinode); } -#if 0 // TODO remove 5333 -/* - * The presence of cifs_direct_io() in the address space ops vector - * allowes open() O_DIRECT flags which would have failed otherwise. - * - * In the non-cached mode (mount with cache=none), we shunt off direct read and write requests - * so this method should never be called. - * - * Direct IO is not yet supported in the cached mode. - */ -static ssize_t -cifs_direct_io(struct kiocb *iocb, struct iov_iter *iter) -{ - /* - * FIXME - * Eventually need to support direct IO for non forcedirectio mounts - */ - return -EINVAL; -} -#endif // netfs end remove 5333 - static int cifs_swap_activate(struct swap_info_struct *sis, struct file *swap_file, sector_t *span) { diff --git a/fs/smb/client/fscache.c b/fs/smb/client/fscache.c index b36c493f4c56..01424a5cdb99 100644 --- a/fs/smb/client/fscache.c +++ b/fs/smb/client/fscache.c @@ -170,114 +170,3 @@ void cifs_fscache_release_inode_cookie(struct inode *inode) cifsi->netfs.cache = NULL; } } - -#if 0 // TODO remove -/* - * Fallback page reading interface. - */ -static int fscache_fallback_read_page(struct inode *inode, struct page *page) -{ - struct netfs_cache_resources cres; - struct fscache_cookie *cookie = cifs_inode_cookie(inode); - struct iov_iter iter; - struct bio_vec bvec; - int ret; - - memset(&cres, 0, sizeof(cres)); - bvec_set_page(&bvec, page, PAGE_SIZE, 0); - iov_iter_bvec(&iter, ITER_DEST, &bvec, 1, PAGE_SIZE); - - ret = fscache_begin_read_operation(&cres, cookie); - if (ret < 0) - return ret; - - ret = fscache_read(&cres, page_offset(page), &iter, NETFS_READ_HOLE_FAIL, - NULL, NULL); - fscache_end_operation(&cres); - return ret; -} - -/* - * Fallback page writing interface. - */ -static int fscache_fallback_write_pages(struct inode *inode, loff_t start, size_t len, - bool no_space_allocated_yet) -{ - struct netfs_cache_resources cres; - struct fscache_cookie *cookie = cifs_inode_cookie(inode); - struct iov_iter iter; - int ret; - - memset(&cres, 0, sizeof(cres)); - iov_iter_xarray(&iter, ITER_SOURCE, &inode->i_mapping->i_pages, start, len); - - ret = fscache_begin_write_operation(&cres, cookie); - if (ret < 0) - return ret; - - ret = cres.ops->prepare_write(&cres, &start, &len, len, i_size_read(inode), - no_space_allocated_yet); - if (ret == 0) - ret = fscache_write(&cres, start, &iter, NULL, NULL); - fscache_end_operation(&cres); - return ret; -} - -/* - * Retrieve a page from FS-Cache - */ -int __cifs_readpage_from_fscache(struct inode *inode, struct page *page) -{ - int ret; - - cifs_dbg(FYI, "%s: (fsc:%p, p:%p, i:0x%p\n", - __func__, cifs_inode_cookie(inode), page, inode); - - ret = fscache_fallback_read_page(inode, page); - if (ret < 0) - return ret; - - /* Read completed synchronously */ - SetPageUptodate(page); - return 0; -} - -void __cifs_readahead_to_fscache(struct inode *inode, loff_t pos, size_t len) -{ - cifs_dbg(FYI, "%s: (fsc: %p, p: %llx, l: %zx, i: %p)\n", - __func__, cifs_inode_cookie(inode), pos, len, inode); - - fscache_fallback_write_pages(inode, pos, len, true); -} - -/* - * Query the cache occupancy. - */ -int __cifs_fscache_query_occupancy(struct inode *inode, - pgoff_t first, unsigned int nr_pages, - pgoff_t *_data_first, - unsigned int *_data_nr_pages) -{ - struct netfs_cache_resources cres; - struct fscache_cookie *cookie = cifs_inode_cookie(inode); - loff_t start, data_start; - size_t len, data_len; - int ret; - - ret = fscache_begin_read_operation(&cres, cookie); - if (ret < 0) - return ret; - - start = first * PAGE_SIZE; - len = nr_pages * PAGE_SIZE; - ret = cres.ops->query_occupancy(&cres, start, len, PAGE_SIZE, - &data_start, &data_len); - if (ret == 0) { - *_data_first = data_start / PAGE_SIZE; - *_data_nr_pages = len / PAGE_SIZE; - } - - fscache_end_operation(&cres); - return ret; -} -#endif diff --git a/fs/smb/client/fscache.h b/fs/smb/client/fscache.h index 08b30f79d4cd..f06cb24f5f3c 100644 --- a/fs/smb/client/fscache.h +++ b/fs/smb/client/fscache.h @@ -74,43 +74,6 @@ static inline void cifs_invalidate_cache(struct inode *inode, unsigned int flags i_size_read(inode), flags); } -#if 0 // TODO remove -extern int __cifs_fscache_query_occupancy(struct inode *inode, - pgoff_t first, unsigned int nr_pages, - pgoff_t *_data_first, - unsigned int *_data_nr_pages); - -static inline int cifs_fscache_query_occupancy(struct inode *inode, - pgoff_t first, unsigned int nr_pages, - pgoff_t *_data_first, - unsigned int *_data_nr_pages) -{ - if (!cifs_inode_cookie(inode)) - return -ENOBUFS; - return __cifs_fscache_query_occupancy(inode, first, nr_pages, - _data_first, _data_nr_pages); -} - -extern int __cifs_readpage_from_fscache(struct inode *pinode, struct page *ppage); -extern void __cifs_readahead_to_fscache(struct inode *pinode, loff_t pos, size_t len); - - -static inline int cifs_readpage_from_fscache(struct inode *inode, - struct page *page) -{ - if (cifs_inode_cookie(inode)) - return __cifs_readpage_from_fscache(inode, page); - return -ENOBUFS; -} - -static inline void cifs_readahead_to_fscache(struct inode *inode, - loff_t pos, size_t len) -{ - if (cifs_inode_cookie(inode)) - __cifs_readahead_to_fscache(inode, pos, len); -} -#endif - static inline bool cifs_fscache_enabled(struct inode *inode) { return fscache_cookie_enabled(cifs_inode_cookie(inode)); @@ -133,27 +96,6 @@ static inline struct fscache_cookie *cifs_inode_cookie(struct inode *inode) { re static inline void cifs_invalidate_cache(struct inode *inode, unsigned int flags) {} static inline bool cifs_fscache_enabled(struct inode *inode) { return false; } -#if 0 // TODO remove -static inline int cifs_fscache_query_occupancy(struct inode *inode, - pgoff_t first, unsigned int nr_pages, - pgoff_t *_data_first, - unsigned int *_data_nr_pages) -{ - *_data_first = ULONG_MAX; - *_data_nr_pages = 0; - return -ENOBUFS; -} - -static inline int -cifs_readpage_from_fscache(struct inode *inode, struct page *page) -{ - return -ENOBUFS; -} - -static inline -void cifs_readahead_to_fscache(struct inode *inode, loff_t pos, size_t len) {} -#endif - #endif /* CONFIG_CIFS_FSCACHE */ #endif /* _CIFS_FSCACHE_H */ -- cgit From 2f99c0bce6d30851313c150369cabfd74e594a45 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 6 Oct 2023 18:29:59 +0100 Subject: cifs: Remove some code that's no longer used, part 2 Remove some code that was #if'd out with the netfslib conversion. This is split into parts for file.c as the diff generator otherwise produces a hard to read diff for part of it where a big chunk is cut out. Signed-off-by: David Howells cc: Steve French cc: Shyam Prasad N cc: Rohith Surabattula cc: Jeff Layton cc: linux-cifs@vger.kernel.org cc: netfs@lists.linux.dev cc: linux-fsdevel@vger.kernel.org cc: linux-mm@kvack.org --- fs/smb/client/file.c | 634 +-------------------------------------------------- 1 file changed, 1 insertion(+), 633 deletions(-) (limited to 'fs/smb') diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c index 6088d0f80522..f504cda886f0 100644 --- a/fs/smb/client/file.c +++ b/fs/smb/client/file.c @@ -2617,639 +2617,6 @@ cifs_get_readable_path(struct cifs_tcon *tcon, const char *name, return -ENOENT; } -#if 0 // TODO remove 2773 -void -cifs_writedata_release(struct cifs_io_subrequest *wdata) -{ - if (wdata->uncached) - kref_put(&wdata->ctx->refcount, cifs_aio_ctx_release); -#ifdef CONFIG_CIFS_SMB_DIRECT - if (wdata->mr) { - smbd_deregister_mr(wdata->mr); - wdata->mr = NULL; - } -#endif - - if (wdata->cfile) - cifsFileInfo_put(wdata->cfile); - - kfree(wdata); -} - -/* - * Write failed with a retryable error. Resend the write request. It's also - * possible that the page was redirtied so re-clean the page. - */ -static void -cifs_writev_requeue(struct cifs_io_subrequest *wdata) -{ - int rc = 0; - struct inode *inode = d_inode(wdata->cfile->dentry); - struct TCP_Server_Info *server; - unsigned int rest_len = wdata->subreq.len; - loff_t fpos = wdata->subreq.start; - - server = tlink_tcon(wdata->cfile->tlink)->ses->server; - do { - struct cifs_io_subrequest *wdata2; - unsigned int wsize, cur_len; - - wsize = server->ops->wp_retry_size(inode); - if (wsize < rest_len) { - if (wsize < PAGE_SIZE) { - rc = -EOPNOTSUPP; - break; - } - cur_len = min(round_down(wsize, PAGE_SIZE), rest_len); - } else { - cur_len = rest_len; - } - - wdata2 = cifs_writedata_alloc(cifs_writev_complete); - if (!wdata2) { - rc = -ENOMEM; - break; - } - - wdata2->sync_mode = wdata->sync_mode; - wdata2->subreq.start = fpos; - wdata2->subreq.len = cur_len; - wdata2->subreq.io_iter = wdata->subreq.io_iter; - - iov_iter_advance(&wdata2->subreq.io_iter, fpos - wdata->subreq.start); - iov_iter_truncate(&wdata2->subreq.io_iter, wdata2->subreq.len); - - if (iov_iter_is_xarray(&wdata2->subreq.io_iter)) - /* Check for pages having been redirtied and clean - * them. We can do this by walking the xarray. If - * it's not an xarray, then it's a DIO and we shouldn't - * be mucking around with the page bits. - */ - cifs_undirty_folios(inode, fpos, cur_len); - - rc = cifs_get_writable_file(CIFS_I(inode), FIND_WR_ANY, - &wdata2->cfile); - if (!wdata2->cfile) { - cifs_dbg(VFS, "No writable handle to retry writepages rc=%d\n", - rc); - if (!is_retryable_error(rc)) - rc = -EBADF; - } else { - wdata2->pid = wdata2->cfile->pid; - rc = server->ops->async_writev(wdata2); - } - - cifs_put_writedata(wdata2); - if (rc) { - if (is_retryable_error(rc)) - continue; - fpos += cur_len; - rest_len -= cur_len; - break; - } - - fpos += cur_len; - rest_len -= cur_len; - } while (rest_len > 0); - - /* Clean up remaining pages from the original wdata */ - if (iov_iter_is_xarray(&wdata->subreq.io_iter)) - cifs_pages_write_failed(inode, fpos, rest_len); - - if (rc != 0 && !is_retryable_error(rc)) - mapping_set_error(inode->i_mapping, rc); - cifs_put_writedata(wdata); -} - -void -cifs_writev_complete(struct work_struct *work) -{ - struct cifs_io_subrequest *wdata = container_of(work, - struct cifs_io_subrequest, work); - struct inode *inode = d_inode(wdata->cfile->dentry); - - if (wdata->result == 0) { - spin_lock(&inode->i_lock); - cifs_update_eof(CIFS_I(inode), wdata->subreq.start, wdata->subreq.len); - spin_unlock(&inode->i_lock); - cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink), - wdata->subreq.len); - } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN) - return cifs_writev_requeue(wdata); - - if (wdata->result == -EAGAIN) - cifs_pages_write_redirty(inode, wdata->subreq.start, wdata->subreq.len); - else if (wdata->result < 0) - cifs_pages_write_failed(inode, wdata->subreq.start, wdata->subreq.len); - else - cifs_pages_written_back(inode, wdata->subreq.start, wdata->subreq.len); - - if (wdata->result != -EAGAIN) - mapping_set_error(inode->i_mapping, wdata->result); - cifs_put_writedata(wdata); -} - -struct cifs_io_subrequest *cifs_writedata_alloc(work_func_t complete) -{ - struct cifs_io_subrequest *wdata; - - wdata = kzalloc(sizeof(*wdata), GFP_NOFS); - if (wdata != NULL) { - refcount_set(&wdata->subreq.ref, 1); - INIT_LIST_HEAD(&wdata->list); - init_completion(&wdata->done); - INIT_WORK(&wdata->work, complete); - } - return wdata; -} - -/* - * Extend the region to be written back to include subsequent contiguously - * dirty pages if possible, but don't sleep while doing so. - */ -static void cifs_extend_writeback(struct address_space *mapping, - struct xa_state *xas, - long *_count, - loff_t start, - int max_pages, - loff_t max_len, - size_t *_len) -{ - struct folio_batch batch; - struct folio *folio; - unsigned int nr_pages; - pgoff_t index = (start + *_len) / PAGE_SIZE; - size_t len; - bool stop = true; - unsigned int i; - - folio_batch_init(&batch); - - do { - /* Firstly, we gather up a batch of contiguous dirty pages - * under the RCU read lock - but we can't clear the dirty flags - * there if any of those pages are mapped. - */ - rcu_read_lock(); - - xas_for_each(xas, folio, ULONG_MAX) { - stop = true; - if (xas_retry(xas, folio)) - continue; - if (xa_is_value(folio)) - break; - if (folio->index != index) { - xas_reset(xas); - break; - } - - if (!folio_try_get_rcu(folio)) { - xas_reset(xas); - continue; - } - nr_pages = folio_nr_pages(folio); - if (nr_pages > max_pages) { - xas_reset(xas); - break; - } - - /* Has the page moved or been split? */ - if (unlikely(folio != xas_reload(xas))) { - folio_put(folio); - xas_reset(xas); - break; - } - - if (!folio_trylock(folio)) { - folio_put(folio); - xas_reset(xas); - break; - } - if (!folio_test_dirty(folio) || - folio_test_writeback(folio)) { - folio_unlock(folio); - folio_put(folio); - xas_reset(xas); - break; - } - - max_pages -= nr_pages; - len = folio_size(folio); - stop = false; - - index += nr_pages; - *_count -= nr_pages; - *_len += len; - if (max_pages <= 0 || *_len >= max_len || *_count <= 0) - stop = true; - - if (!folio_batch_add(&batch, folio)) - break; - if (stop) - break; - } - - xas_pause(xas); - rcu_read_unlock(); - - /* Now, if we obtained any pages, we can shift them to being - * writable and mark them for caching. - */ - if (!folio_batch_count(&batch)) - break; - - for (i = 0; i < folio_batch_count(&batch); i++) { - folio = batch.folios[i]; - /* The folio should be locked, dirty and not undergoing - * writeback from the loop above. - */ - if (!folio_clear_dirty_for_io(folio)) - WARN_ON(1); - folio_start_writeback(folio); - folio_unlock(folio); - } - - folio_batch_release(&batch); - cond_resched(); - } while (!stop); -} - -/* - * Write back the locked page and any subsequent non-locked dirty pages. - */ -static ssize_t cifs_write_back_from_locked_folio(struct address_space *mapping, - struct writeback_control *wbc, - struct xa_state *xas, - struct folio *folio, - unsigned long long start, - unsigned long long end) -{ - struct inode *inode = mapping->host; - struct TCP_Server_Info *server; - struct cifs_io_subrequest *wdata; - struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); - struct cifs_credits credits_on_stack; - struct cifs_credits *credits = &credits_on_stack; - struct cifsFileInfo *cfile = NULL; - unsigned long long i_size = i_size_read(inode), max_len; - unsigned int xid; - size_t wsize; - size_t len = folio_size(folio); - long count = wbc->nr_to_write; - int rc; - - /* The folio should be locked, dirty and not undergoing writeback. */ - if (!folio_clear_dirty_for_io(folio)) - WARN_ON_ONCE(1); - folio_start_writeback(folio); - - count -= folio_nr_pages(folio); - - xid = get_xid(); - server = cifs_pick_channel(cifs_sb_master_tcon(cifs_sb)->ses); - - rc = cifs_get_writable_file(CIFS_I(inode), FIND_WR_ANY, &cfile); - if (rc) { - cifs_dbg(VFS, "No writable handle in writepages rc=%d\n", rc); - goto err_xid; - } - - rc = server->ops->wait_mtu_credits(server, cifs_sb->ctx->wsize, - &wsize, credits); - if (rc != 0) - goto err_close; - - wdata = cifs_writedata_alloc(cifs_writev_complete); - if (!wdata) { - rc = -ENOMEM; - goto err_uncredit; - } - - wdata->sync_mode = wbc->sync_mode; - wdata->subreq.start = folio_pos(folio); - wdata->pid = cfile->pid; - wdata->credits = credits_on_stack; - wdata->cfile = cfile; - wdata->server = server; - cfile = NULL; - - /* Find all consecutive lockable dirty pages that have contiguous - * written regions, stopping when we find a page that is not - * immediately lockable, is not dirty or is missing, or we reach the - * end of the range. - */ - if (start < i_size) { - /* Trim the write to the EOF; the extra data is ignored. Also - * put an upper limit on the size of a single storedata op. - */ - max_len = wsize; - max_len = min_t(unsigned long long, max_len, end - start + 1); - max_len = min_t(unsigned long long, max_len, i_size - start); - - if (len < max_len) { - int max_pages = INT_MAX; - -#ifdef CONFIG_CIFS_SMB_DIRECT - if (server->smbd_conn) - max_pages = server->smbd_conn->max_frmr_depth; -#endif - max_pages -= folio_nr_pages(folio); - - if (max_pages > 0) - cifs_extend_writeback(mapping, xas, &count, start, - max_pages, max_len, &len); - } - } - len = min_t(unsigned long long, len, i_size - start); - - /* We now have a contiguous set of dirty pages, each with writeback - * set; the first page is still locked at this point, but all the rest - * have been unlocked. - */ - folio_unlock(folio); - wdata->subreq.len = len; - - if (start < i_size) { - iov_iter_xarray(&wdata->subreq.io_iter, ITER_SOURCE, &mapping->i_pages, - start, len); - - rc = adjust_credits(wdata->server, &wdata->credits, wdata->subreq.len); - if (rc) - goto err_wdata; - - if (wdata->cfile->invalidHandle) - rc = -EAGAIN; - else - rc = wdata->server->ops->async_writev(wdata); - if (rc >= 0) { - cifs_put_writedata(wdata); - goto err_close; - } - } else { - /* The dirty region was entirely beyond the EOF. */ - cifs_pages_written_back(inode, start, len); - rc = 0; - } - -err_wdata: - cifs_put_writedata(wdata); -err_uncredit: - add_credits_and_wake_if(server, credits, 0); -err_close: - if (cfile) - cifsFileInfo_put(cfile); -err_xid: - free_xid(xid); - if (rc == 0) { - wbc->nr_to_write = count; - rc = len; - } else if (is_retryable_error(rc)) { - cifs_pages_write_redirty(inode, start, len); - } else { - cifs_pages_write_failed(inode, start, len); - mapping_set_error(mapping, rc); - } - /* Indication to update ctime and mtime as close is deferred */ - set_bit(CIFS_INO_MODIFIED_ATTR, &CIFS_I(inode)->flags); - return rc; -} - -/* - * write a region of pages back to the server - */ -static ssize_t cifs_writepages_begin(struct address_space *mapping, - struct writeback_control *wbc, - struct xa_state *xas, - unsigned long long *_start, - unsigned long long end) -{ - struct folio *folio; - unsigned long long start = *_start; - ssize_t ret; - int skips = 0; - -search_again: - /* Find the first dirty page. */ - rcu_read_lock(); - - for (;;) { - folio = xas_find_marked(xas, end / PAGE_SIZE, PAGECACHE_TAG_DIRTY); - if (xas_retry(xas, folio) || xa_is_value(folio)) - continue; - if (!folio) - break; - - if (!folio_try_get_rcu(folio)) { - xas_reset(xas); - continue; - } - - if (unlikely(folio != xas_reload(xas))) { - folio_put(folio); - xas_reset(xas); - continue; - } - - xas_pause(xas); - break; - } - rcu_read_unlock(); - if (!folio) - return 0; - - start = folio_pos(folio); /* May regress with THPs */ - - /* At this point we hold neither the i_pages lock nor the page lock: - * the page may be truncated or invalidated (changing page->mapping to - * NULL), or even swizzled back from swapper_space to tmpfs file - * mapping - */ -lock_again: - if (wbc->sync_mode != WB_SYNC_NONE) { - ret = folio_lock_killable(folio); - if (ret < 0) - return ret; - } else { - if (!folio_trylock(folio)) - goto search_again; - } - - if (folio->mapping != mapping || - !folio_test_dirty(folio)) { - start += folio_size(folio); - folio_unlock(folio); - goto search_again; - } - - if (folio_test_writeback(folio) || - folio_test_private_2(folio)) { /* [DEPRECATED] */ - folio_unlock(folio); - if (wbc->sync_mode != WB_SYNC_NONE) { - folio_wait_writeback(folio); -#ifdef CONFIG_CIFS_FSCACHE - folio_wait_private_2(folio); -#endif - goto lock_again; - } - - start += folio_size(folio); - if (wbc->sync_mode == WB_SYNC_NONE) { - if (skips >= 5 || need_resched()) { - ret = 0; - goto out; - } - skips++; - } - goto search_again; - } - - ret = cifs_write_back_from_locked_folio(mapping, wbc, xas, folio, start, end); -out: - if (ret > 0) - *_start = start + ret; - return ret; -} - -/* - * Write a region of pages back to the server - */ -static int cifs_writepages_region(struct address_space *mapping, - struct writeback_control *wbc, - unsigned long long *_start, - unsigned long long end) -{ - ssize_t ret; - - XA_STATE(xas, &mapping->i_pages, *_start / PAGE_SIZE); - - do { - ret = cifs_writepages_begin(mapping, wbc, &xas, _start, end); - if (ret > 0 && wbc->nr_to_write > 0) - cond_resched(); - } while (ret > 0 && wbc->nr_to_write > 0); - - return ret > 0 ? 0 : ret; -} - -/* - * Write some of the pending data back to the server - */ -static int cifs_writepages(struct address_space *mapping, - struct writeback_control *wbc) -{ - loff_t start, end; - int ret; - - /* We have to be careful as we can end up racing with setattr() - * truncating the pagecache since the caller doesn't take a lock here - * to prevent it. - */ - - if (wbc->range_cyclic && mapping->writeback_index) { - start = mapping->writeback_index * PAGE_SIZE; - ret = cifs_writepages_region(mapping, wbc, &start, LLONG_MAX); - if (ret < 0) - goto out; - - if (wbc->nr_to_write <= 0) { - mapping->writeback_index = start / PAGE_SIZE; - goto out; - } - - start = 0; - end = mapping->writeback_index * PAGE_SIZE; - mapping->writeback_index = 0; - ret = cifs_writepages_region(mapping, wbc, &start, end); - if (ret == 0) - mapping->writeback_index = start / PAGE_SIZE; - } else if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) { - start = 0; - ret = cifs_writepages_region(mapping, wbc, &start, LLONG_MAX); - if (wbc->nr_to_write > 0 && ret == 0) - mapping->writeback_index = start / PAGE_SIZE; - } else { - start = wbc->range_start; - ret = cifs_writepages_region(mapping, wbc, &start, wbc->range_end); - } - -out: - return ret; -} - -static int cifs_write_end(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *page, void *fsdata) -{ - int rc; - struct inode *inode = mapping->host; - struct cifsFileInfo *cfile = file->private_data; - struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->dentry->d_sb); - struct folio *folio = page_folio(page); - __u32 pid; - - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD) - pid = cfile->pid; - else - pid = current->tgid; - - cifs_dbg(FYI, "write_end for page %p from pos %lld with %d bytes\n", - page, pos, copied); - - if (folio_test_checked(folio)) { - if (copied == len) - folio_mark_uptodate(folio); - folio_clear_checked(folio); - } else if (!folio_test_uptodate(folio) && copied == PAGE_SIZE) - folio_mark_uptodate(folio); - - if (!folio_test_uptodate(folio)) { - char *page_data; - unsigned offset = pos & (PAGE_SIZE - 1); - unsigned int xid; - - xid = get_xid(); - /* this is probably better than directly calling - partialpage_write since in this function the file handle is - known which we might as well leverage */ - /* BB check if anything else missing out of ppw - such as updating last write time */ - page_data = kmap(page); - rc = cifs_write(cfile, pid, page_data + offset, copied, &pos); - /* if (rc < 0) should we set writebehind rc? */ - kunmap(page); - - free_xid(xid); - } else { - rc = copied; - pos += copied; - set_page_dirty(page); - } - - if (rc > 0) { - spin_lock(&inode->i_lock); - if (pos > inode->i_size) { - loff_t additional_blocks = (512 - 1 + copied) >> 9; - - i_size_write(inode, pos); - /* - * Estimate new allocation size based on the amount written. - * This will be updated from server on close (and on queryinfo) - */ - inode->i_blocks = min_t(blkcnt_t, (512 - 1 + pos) >> 9, - inode->i_blocks + additional_blocks); - } - spin_unlock(&inode->i_lock); - } - - unlock_page(page); - put_page(page); - /* Indication to update ctime and mtime as close is deferred */ - set_bit(CIFS_INO_MODIFIED_ATTR, &CIFS_I(inode)->flags); - - return rc; -} -#endif // End netfs removal 2773 - /* * Flush data on a strict file. */ @@ -4565,6 +3932,7 @@ cifs_read(struct file *file, char *read_data, size_t read_size, loff_t *offset) } #endif // end netfslib remove 4633 + static vm_fault_t cifs_page_mkwrite(struct vm_fault *vmf) { return netfs_page_mkwrite(vmf, NULL); -- cgit From b593634424d4ff1319226eb0187c634b0b819224 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 6 Oct 2023 22:36:30 +0100 Subject: cifs: Remove some code that's no longer used, part 3 Remove some code that was #if'd out with the netfslib conversion. This is split into parts for file.c as the diff generator otherwise produces a hard to read diff for part of it where a big chunk is cut out. Signed-off-by: David Howells cc: Steve French cc: Shyam Prasad N cc: Rohith Surabattula cc: Jeff Layton cc: linux-cifs@vger.kernel.org cc: netfs@lists.linux.dev cc: linux-fsdevel@vger.kernel.org cc: linux-mm@kvack.org --- fs/smb/client/file.c | 1004 -------------------------------------------------- 1 file changed, 1004 deletions(-) (limited to 'fs/smb') diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c index f504cda886f0..4c981ce89f8a 100644 --- a/fs/smb/client/file.c +++ b/fs/smb/client/file.c @@ -2743,471 +2743,6 @@ int cifs_flush(struct file *file, fl_owner_t id) return rc; } -#if 0 // TODO remove 3594 -static void collect_uncached_write_data(struct cifs_aio_ctx *ctx); - -static void -cifs_uncached_writev_complete(struct work_struct *work) -{ - struct cifs_io_subrequest *wdata = container_of(work, - struct cifs_io_subrequest, work); - struct inode *inode = d_inode(wdata->cfile->dentry); - struct cifsInodeInfo *cifsi = CIFS_I(inode); - - spin_lock(&inode->i_lock); - cifs_update_eof(cifsi, wdata->subreq.start, wdata->subreq.len); - if (cifsi->netfs.remote_i_size > inode->i_size) - i_size_write(inode, cifsi->netfs.remote_i_size); - spin_unlock(&inode->i_lock); - - complete(&wdata->done); - collect_uncached_write_data(wdata->ctx); - /* the below call can possibly free the last ref to aio ctx */ - cifs_put_writedata(wdata); -} - -static int -cifs_resend_wdata(struct cifs_io_subrequest *wdata, struct list_head *wdata_list, - struct cifs_aio_ctx *ctx) -{ - size_t wsize; - struct cifs_credits credits; - int rc; - struct TCP_Server_Info *server = wdata->server; - - do { - if (wdata->cfile->invalidHandle) { - rc = cifs_reopen_file(wdata->cfile, false); - if (rc == -EAGAIN) - continue; - else if (rc) - break; - } - - - /* - * Wait for credits to resend this wdata. - * Note: we are attempting to resend the whole wdata not in - * segments - */ - do { - rc = server->ops->wait_mtu_credits(server, wdata->subreq.len, - &wsize, &credits); - if (rc) - goto fail; - - if (wsize < wdata->subreq.len) { - add_credits_and_wake_if(server, &credits, 0); - msleep(1000); - } - } while (wsize < wdata->subreq.len); - wdata->credits = credits; - - rc = adjust_credits(server, &wdata->credits, wdata->subreq.len); - - if (!rc) { - if (wdata->cfile->invalidHandle) - rc = -EAGAIN; - else { - set_bit(NETFS_SREQ_RETRYING, &wdata->subreq.flags); -#ifdef CONFIG_CIFS_SMB_DIRECT - if (wdata->mr) { - wdata->mr->need_invalidate = true; - smbd_deregister_mr(wdata->mr); - wdata->mr = NULL; - } -#endif - rc = server->ops->async_writev(wdata); - } - } - - /* If the write was successfully sent, we are done */ - if (!rc) { - list_add_tail(&wdata->list, wdata_list); - return 0; - } - - /* Roll back credits and retry if needed */ - add_credits_and_wake_if(server, &wdata->credits, 0); - } while (rc == -EAGAIN); - -fail: - cifs_put_writedata(wdata); - return rc; -} - -/* - * Select span of a bvec iterator we're going to use. Limit it by both maximum - * size and maximum number of segments. - */ -static size_t cifs_limit_bvec_subset(const struct iov_iter *iter, size_t max_size, - size_t max_segs, unsigned int *_nsegs) -{ - const struct bio_vec *bvecs = iter->bvec; - unsigned int nbv = iter->nr_segs, ix = 0, nsegs = 0; - size_t len, span = 0, n = iter->count; - size_t skip = iter->iov_offset; - - if (WARN_ON(!iov_iter_is_bvec(iter)) || n == 0) - return 0; - - while (n && ix < nbv && skip) { - len = bvecs[ix].bv_len; - if (skip < len) - break; - skip -= len; - n -= len; - ix++; - } - - while (n && ix < nbv) { - len = min3(n, bvecs[ix].bv_len - skip, max_size); - span += len; - max_size -= len; - nsegs++; - ix++; - if (max_size == 0 || nsegs >= max_segs) - break; - skip = 0; - n -= len; - } - - *_nsegs = nsegs; - return span; -} - -static int -cifs_write_from_iter(loff_t fpos, size_t len, struct iov_iter *from, - struct cifsFileInfo *open_file, - struct cifs_sb_info *cifs_sb, struct list_head *wdata_list, - struct cifs_aio_ctx *ctx) -{ - int rc = 0; - size_t cur_len, max_len; - struct cifs_io_subrequest *wdata; - pid_t pid; - struct TCP_Server_Info *server; - unsigned int xid, max_segs = INT_MAX; - - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD) - pid = open_file->pid; - else - pid = current->tgid; - - server = cifs_pick_channel(tlink_tcon(open_file->tlink)->ses); - xid = get_xid(); - -#ifdef CONFIG_CIFS_SMB_DIRECT - if (server->smbd_conn) - max_segs = server->smbd_conn->max_frmr_depth; -#endif - - do { - struct cifs_credits credits_on_stack; - struct cifs_credits *credits = &credits_on_stack; - unsigned int nsegs = 0; - size_t wsize; - - if (signal_pending(current)) { - rc = -EINTR; - break; - } - - if (open_file->invalidHandle) { - rc = cifs_reopen_file(open_file, false); - if (rc == -EAGAIN) - continue; - else if (rc) - break; - } - - rc = server->ops->wait_mtu_credits(server, cifs_sb->ctx->wsize, - &wsize, credits); - if (rc) - break; - - max_len = min_t(const size_t, len, wsize); - if (!max_len) { - rc = -EAGAIN; - add_credits_and_wake_if(server, credits, 0); - break; - } - - cur_len = cifs_limit_bvec_subset(from, max_len, max_segs, &nsegs); - cifs_dbg(FYI, "write_from_iter len=%zx/%zx nsegs=%u/%lu/%u\n", - cur_len, max_len, nsegs, from->nr_segs, max_segs); - if (cur_len == 0) { - rc = -EIO; - add_credits_and_wake_if(server, credits, 0); - break; - } - - wdata = cifs_writedata_alloc(cifs_uncached_writev_complete); - if (!wdata) { - rc = -ENOMEM; - add_credits_and_wake_if(server, credits, 0); - break; - } - - wdata->uncached = true; - wdata->sync_mode = WB_SYNC_ALL; - wdata->subreq.start = (__u64)fpos; - wdata->cfile = cifsFileInfo_get(open_file); - wdata->server = server; - wdata->pid = pid; - wdata->subreq.len = cur_len; - wdata->credits = credits_on_stack; - wdata->subreq.io_iter = *from; - wdata->ctx = ctx; - kref_get(&ctx->refcount); - - iov_iter_truncate(&wdata->subreq.io_iter, cur_len); - - rc = adjust_credits(server, &wdata->credits, wdata->subreq.len); - - if (!rc) { - if (wdata->cfile->invalidHandle) - rc = -EAGAIN; - else - rc = server->ops->async_writev(wdata); - } - - if (rc) { - add_credits_and_wake_if(server, &wdata->credits, 0); - cifs_put_writedata(wdata); - if (rc == -EAGAIN) - continue; - break; - } - - list_add_tail(&wdata->list, wdata_list); - iov_iter_advance(from, cur_len); - fpos += cur_len; - len -= cur_len; - } while (len > 0); - - free_xid(xid); - return rc; -} - -static void collect_uncached_write_data(struct cifs_aio_ctx *ctx) -{ - struct cifs_io_subrequest *wdata, *tmp; - struct cifs_tcon *tcon; - struct cifs_sb_info *cifs_sb; - struct dentry *dentry = ctx->cfile->dentry; - ssize_t rc; - - tcon = tlink_tcon(ctx->cfile->tlink); - cifs_sb = CIFS_SB(dentry->d_sb); - - mutex_lock(&ctx->aio_mutex); - - if (list_empty(&ctx->list)) { - mutex_unlock(&ctx->aio_mutex); - return; - } - - rc = ctx->rc; - /* - * Wait for and collect replies for any successful sends in order of - * increasing offset. Once an error is hit, then return without waiting - * for any more replies. - */ -restart_loop: - list_for_each_entry_safe(wdata, tmp, &ctx->list, list) { - if (!rc) { - if (!try_wait_for_completion(&wdata->done)) { - mutex_unlock(&ctx->aio_mutex); - return; - } - - if (wdata->result) - rc = wdata->result; - else - ctx->total_len += wdata->subreq.len; - - /* resend call if it's a retryable error */ - if (rc == -EAGAIN) { - struct list_head tmp_list; - struct iov_iter tmp_from = ctx->iter; - - INIT_LIST_HEAD(&tmp_list); - list_del_init(&wdata->list); - - if (ctx->direct_io) - rc = cifs_resend_wdata( - wdata, &tmp_list, ctx); - else { - iov_iter_advance(&tmp_from, - wdata->subreq.start - ctx->pos); - - rc = cifs_write_from_iter(wdata->subreq.start, - wdata->subreq.len, &tmp_from, - ctx->cfile, cifs_sb, &tmp_list, - ctx); - - cifs_put_writedata(wdata); - } - - list_splice(&tmp_list, &ctx->list); - goto restart_loop; - } - } - list_del_init(&wdata->list); - cifs_put_writedata(wdata); - } - - cifs_stats_bytes_written(tcon, ctx->total_len); - set_bit(CIFS_INO_INVALID_MAPPING, &CIFS_I(dentry->d_inode)->flags); - - ctx->rc = (rc == 0) ? ctx->total_len : rc; - - mutex_unlock(&ctx->aio_mutex); - - if (ctx->iocb && ctx->iocb->ki_complete) - ctx->iocb->ki_complete(ctx->iocb, ctx->rc); - else - complete(&ctx->done); -} - -static ssize_t __cifs_writev( - struct kiocb *iocb, struct iov_iter *from, bool direct) -{ - struct file *file = iocb->ki_filp; - ssize_t total_written = 0; - struct cifsFileInfo *cfile; - struct cifs_tcon *tcon; - struct cifs_sb_info *cifs_sb; - struct cifs_aio_ctx *ctx; - int rc; - - rc = generic_write_checks(iocb, from); - if (rc <= 0) - return rc; - - cifs_sb = CIFS_FILE_SB(file); - cfile = file->private_data; - tcon = tlink_tcon(cfile->tlink); - - if (!tcon->ses->server->ops->async_writev) - return -ENOSYS; - - ctx = cifs_aio_ctx_alloc(); - if (!ctx) - return -ENOMEM; - - ctx->cfile = cifsFileInfo_get(cfile); - - if (!is_sync_kiocb(iocb)) - ctx->iocb = iocb; - - ctx->pos = iocb->ki_pos; - ctx->direct_io = direct; - ctx->nr_pinned_pages = 0; - - if (user_backed_iter(from)) { - /* - * Extract IOVEC/UBUF-type iterators to a BVEC-type iterator as - * they contain references to the calling process's virtual - * memory layout which won't be available in an async worker - * thread. This also takes a pin on every folio involved. - */ - rc = netfs_extract_user_iter(from, iov_iter_count(from), - &ctx->iter, 0); - if (rc < 0) { - kref_put(&ctx->refcount, cifs_aio_ctx_release); - return rc; - } - - ctx->nr_pinned_pages = rc; - ctx->bv = (void *)ctx->iter.bvec; - ctx->bv_need_unpin = iov_iter_extract_will_pin(from); - } else if ((iov_iter_is_bvec(from) || iov_iter_is_kvec(from)) && - !is_sync_kiocb(iocb)) { - /* - * If the op is asynchronous, we need to copy the list attached - * to a BVEC/KVEC-type iterator, but we assume that the storage - * will be pinned by the caller; in any case, we may or may not - * be able to pin the pages, so we don't try. - */ - ctx->bv = (void *)dup_iter(&ctx->iter, from, GFP_KERNEL); - if (!ctx->bv) { - kref_put(&ctx->refcount, cifs_aio_ctx_release); - return -ENOMEM; - } - } else { - /* - * Otherwise, we just pass the iterator down as-is and rely on - * the caller to make sure the pages referred to by the - * iterator don't evaporate. - */ - ctx->iter = *from; - } - - ctx->len = iov_iter_count(&ctx->iter); - - /* grab a lock here due to read response handlers can access ctx */ - mutex_lock(&ctx->aio_mutex); - - rc = cifs_write_from_iter(iocb->ki_pos, ctx->len, &ctx->iter, - cfile, cifs_sb, &ctx->list, ctx); - - /* - * If at least one write was successfully sent, then discard any rc - * value from the later writes. If the other write succeeds, then - * we'll end up returning whatever was written. If it fails, then - * we'll get a new rc value from that. - */ - if (!list_empty(&ctx->list)) - rc = 0; - - mutex_unlock(&ctx->aio_mutex); - - if (rc) { - kref_put(&ctx->refcount, cifs_aio_ctx_release); - return rc; - } - - if (!is_sync_kiocb(iocb)) { - kref_put(&ctx->refcount, cifs_aio_ctx_release); - return -EIOCBQUEUED; - } - - rc = wait_for_completion_killable(&ctx->done); - if (rc) { - mutex_lock(&ctx->aio_mutex); - ctx->rc = rc = -EINTR; - total_written = ctx->total_len; - mutex_unlock(&ctx->aio_mutex); - } else { - rc = ctx->rc; - total_written = ctx->total_len; - } - - kref_put(&ctx->refcount, cifs_aio_ctx_release); - - if (unlikely(!total_written)) - return rc; - - iocb->ki_pos += total_written; - return total_written; -} - -ssize_t cifs_direct_writev(struct kiocb *iocb, struct iov_iter *from) -{ - struct file *file = iocb->ki_filp; - - cifs_revalidate_mapping(file->f_inode); - return __cifs_writev(iocb, from, true); -} - -ssize_t cifs_user_writev(struct kiocb *iocb, struct iov_iter *from) -{ - return __cifs_writev(iocb, from, false); -} -#endif // TODO remove 3594 - static ssize_t cifs_writev(struct kiocb *iocb, struct iov_iter *from) { @@ -3296,450 +2831,6 @@ out: return written; } -#if 0 // TODO remove 4143 -static struct cifs_io_subrequest *cifs_readdata_alloc(work_func_t complete) -{ - struct cifs_io_subrequest *rdata; - - rdata = kzalloc(sizeof(*rdata), GFP_KERNEL); - if (rdata) { - refcount_set(&rdata->subreq.ref, 1); - INIT_LIST_HEAD(&rdata->list); - init_completion(&rdata->done); - INIT_WORK(&rdata->work, complete); - } - - return rdata; -} - -void -cifs_readdata_release(struct cifs_io_subrequest *rdata) -{ - if (rdata->ctx) - kref_put(&rdata->ctx->refcount, cifs_aio_ctx_release); -#ifdef CONFIG_CIFS_SMB_DIRECT - if (rdata->mr) { - smbd_deregister_mr(rdata->mr); - rdata->mr = NULL; - } -#endif - if (rdata->cfile) - cifsFileInfo_put(rdata->cfile); - - kfree(rdata); -} - -static void collect_uncached_read_data(struct cifs_aio_ctx *ctx); - -static void -cifs_uncached_readv_complete(struct work_struct *work) -{ - struct cifs_io_subrequest *rdata = - container_of(work, struct cifs_io_subrequest, work); - - complete(&rdata->done); - collect_uncached_read_data(rdata->ctx); - /* the below call can possibly free the last ref to aio ctx */ - cifs_put_readdata(rdata); -} - -static int cifs_resend_rdata(struct cifs_io_subrequest *rdata, - struct list_head *rdata_list, - struct cifs_aio_ctx *ctx) -{ - size_t rsize; - struct cifs_credits credits; - int rc; - struct TCP_Server_Info *server; - - /* XXX: should we pick a new channel here? */ - server = rdata->server; - - do { - if (rdata->cfile->invalidHandle) { - rc = cifs_reopen_file(rdata->cfile, true); - if (rc == -EAGAIN) - continue; - else if (rc) - break; - } - - /* - * Wait for credits to resend this rdata. - * Note: we are attempting to resend the whole rdata not in - * segments - */ - do { - rc = server->ops->wait_mtu_credits(server, rdata->subreq.len, - &rsize, &credits); - - if (rc) - goto fail; - - if (rsize < rdata->subreq.len) { - add_credits_and_wake_if(server, &credits, 0); - msleep(1000); - } - } while (rsize < rdata->subreq.len); - rdata->credits = credits; - - rc = adjust_credits(server, &rdata->credits, rdata->subreq.len); - if (!rc) { - if (rdata->cfile->invalidHandle) - rc = -EAGAIN; - else { -#ifdef CONFIG_CIFS_SMB_DIRECT - if (rdata->mr) { - rdata->mr->need_invalidate = true; - smbd_deregister_mr(rdata->mr); - rdata->mr = NULL; - } -#endif - rc = server->ops->async_readv(rdata); - } - } - - /* If the read was successfully sent, we are done */ - if (!rc) { - /* Add to aio pending list */ - list_add_tail(&rdata->list, rdata_list); - return 0; - } - - /* Roll back credits and retry if needed */ - add_credits_and_wake_if(server, &rdata->credits, 0); - } while (rc == -EAGAIN); - -fail: - cifs_put_readdata(rdata); - return rc; -} - -static int -cifs_send_async_read(loff_t fpos, size_t len, struct cifsFileInfo *open_file, - struct cifs_sb_info *cifs_sb, struct list_head *rdata_list, - struct cifs_aio_ctx *ctx) -{ - struct cifs_io_subrequest *rdata; - unsigned int nsegs, max_segs = INT_MAX; - struct cifs_credits credits_on_stack; - struct cifs_credits *credits = &credits_on_stack; - size_t cur_len, max_len, rsize; - int rc; - pid_t pid; - struct TCP_Server_Info *server; - - server = cifs_pick_channel(tlink_tcon(open_file->tlink)->ses); - -#ifdef CONFIG_CIFS_SMB_DIRECT - if (server->smbd_conn) - max_segs = server->smbd_conn->max_frmr_depth; -#endif - - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD) - pid = open_file->pid; - else - pid = current->tgid; - - do { - if (open_file->invalidHandle) { - rc = cifs_reopen_file(open_file, true); - if (rc == -EAGAIN) - continue; - else if (rc) - break; - } - - if (cifs_sb->ctx->rsize == 0) - cifs_sb->ctx->rsize = - server->ops->negotiate_rsize(tlink_tcon(open_file->tlink), - cifs_sb->ctx); - - rc = server->ops->wait_mtu_credits(server, cifs_sb->ctx->rsize, - &rsize, credits); - if (rc) - break; - - max_len = min_t(size_t, len, rsize); - - cur_len = cifs_limit_bvec_subset(&ctx->iter, max_len, - max_segs, &nsegs); - cifs_dbg(FYI, "read-to-iter len=%zx/%zx nsegs=%u/%lu/%u\n", - cur_len, max_len, nsegs, ctx->iter.nr_segs, max_segs); - if (cur_len == 0) { - rc = -EIO; - add_credits_and_wake_if(server, credits, 0); - break; - } - - rdata = cifs_readdata_alloc(cifs_uncached_readv_complete); - if (!rdata) { - add_credits_and_wake_if(server, credits, 0); - rc = -ENOMEM; - break; - } - - rdata->server = server; - rdata->cfile = cifsFileInfo_get(open_file); - rdata->subreq.start = fpos; - rdata->subreq.len = cur_len; - rdata->pid = pid; - rdata->credits = credits_on_stack; - rdata->ctx = ctx; - kref_get(&ctx->refcount); - - rdata->subreq.io_iter = ctx->iter; - iov_iter_truncate(&rdata->subreq.io_iter, cur_len); - - rc = adjust_credits(server, &rdata->credits, rdata->subreq.len); - - if (!rc) { - if (rdata->cfile->invalidHandle) - rc = -EAGAIN; - else - rc = server->ops->async_readv(rdata); - } - - if (rc) { - add_credits_and_wake_if(server, &rdata->credits, 0); - cifs_put_readdata(rdata); - if (rc == -EAGAIN) - continue; - break; - } - - list_add_tail(&rdata->list, rdata_list); - iov_iter_advance(&ctx->iter, cur_len); - fpos += cur_len; - len -= cur_len; - } while (len > 0); - - return rc; -} - -static void -collect_uncached_read_data(struct cifs_aio_ctx *ctx) -{ - struct cifs_io_subrequest *rdata, *tmp; - struct cifs_sb_info *cifs_sb; - int rc; - - cifs_sb = CIFS_SB(ctx->cfile->dentry->d_sb); - - mutex_lock(&ctx->aio_mutex); - - if (list_empty(&ctx->list)) { - mutex_unlock(&ctx->aio_mutex); - return; - } - - rc = ctx->rc; - /* the loop below should proceed in the order of increasing offsets */ -again: - list_for_each_entry_safe(rdata, tmp, &ctx->list, list) { - if (!rc) { - if (!try_wait_for_completion(&rdata->done)) { - mutex_unlock(&ctx->aio_mutex); - return; - } - - if (rdata->result == -EAGAIN) { - /* resend call if it's a retryable error */ - struct list_head tmp_list; - unsigned int got_bytes = rdata->got_bytes; - - list_del_init(&rdata->list); - INIT_LIST_HEAD(&tmp_list); - - if (ctx->direct_io) { - /* - * Re-use rdata as this is a - * direct I/O - */ - rc = cifs_resend_rdata( - rdata, - &tmp_list, ctx); - } else { - rc = cifs_send_async_read( - rdata->subreq.start + got_bytes, - rdata->subreq.len - got_bytes, - rdata->cfile, cifs_sb, - &tmp_list, ctx); - - cifs_put_readdata(rdata); - } - - list_splice(&tmp_list, &ctx->list); - - goto again; - } else if (rdata->result) - rc = rdata->result; - - /* if there was a short read -- discard anything left */ - if (rdata->got_bytes && rdata->got_bytes < rdata->subreq.len) - rc = -ENODATA; - - ctx->total_len += rdata->got_bytes; - } - list_del_init(&rdata->list); - cifs_put_readdata(rdata); - } - - /* mask nodata case */ - if (rc == -ENODATA) - rc = 0; - - ctx->rc = (rc == 0) ? (ssize_t)ctx->total_len : rc; - - mutex_unlock(&ctx->aio_mutex); - - if (ctx->iocb && ctx->iocb->ki_complete) - ctx->iocb->ki_complete(ctx->iocb, ctx->rc); - else - complete(&ctx->done); -} - -static ssize_t __cifs_readv( - struct kiocb *iocb, struct iov_iter *to, bool direct) -{ - size_t len; - struct file *file = iocb->ki_filp; - struct cifs_sb_info *cifs_sb; - struct cifsFileInfo *cfile; - struct cifs_tcon *tcon; - ssize_t rc, total_read = 0; - loff_t offset = iocb->ki_pos; - struct cifs_aio_ctx *ctx; - - len = iov_iter_count(to); - if (!len) - return 0; - - cifs_sb = CIFS_FILE_SB(file); - cfile = file->private_data; - tcon = tlink_tcon(cfile->tlink); - - if (!tcon->ses->server->ops->async_readv) - return -ENOSYS; - - if ((file->f_flags & O_ACCMODE) == O_WRONLY) - cifs_dbg(FYI, "attempting read on write only file instance\n"); - - ctx = cifs_aio_ctx_alloc(); - if (!ctx) - return -ENOMEM; - - ctx->pos = offset; - ctx->direct_io = direct; - ctx->len = len; - ctx->cfile = cifsFileInfo_get(cfile); - ctx->nr_pinned_pages = 0; - - if (!is_sync_kiocb(iocb)) - ctx->iocb = iocb; - - if (user_backed_iter(to)) { - /* - * Extract IOVEC/UBUF-type iterators to a BVEC-type iterator as - * they contain references to the calling process's virtual - * memory layout which won't be available in an async worker - * thread. This also takes a pin on every folio involved. - */ - rc = netfs_extract_user_iter(to, iov_iter_count(to), - &ctx->iter, 0); - if (rc < 0) { - kref_put(&ctx->refcount, cifs_aio_ctx_release); - return rc; - } - - ctx->nr_pinned_pages = rc; - ctx->bv = (void *)ctx->iter.bvec; - ctx->bv_need_unpin = iov_iter_extract_will_pin(to); - ctx->should_dirty = true; - } else if ((iov_iter_is_bvec(to) || iov_iter_is_kvec(to)) && - !is_sync_kiocb(iocb)) { - /* - * If the op is asynchronous, we need to copy the list attached - * to a BVEC/KVEC-type iterator, but we assume that the storage - * will be retained by the caller; in any case, we may or may - * not be able to pin the pages, so we don't try. - */ - ctx->bv = (void *)dup_iter(&ctx->iter, to, GFP_KERNEL); - if (!ctx->bv) { - kref_put(&ctx->refcount, cifs_aio_ctx_release); - return -ENOMEM; - } - } else { - /* - * Otherwise, we just pass the iterator down as-is and rely on - * the caller to make sure the pages referred to by the - * iterator don't evaporate. - */ - ctx->iter = *to; - } - - if (direct) { - rc = filemap_write_and_wait_range(file->f_inode->i_mapping, - offset, offset + len - 1); - if (rc) { - kref_put(&ctx->refcount, cifs_aio_ctx_release); - return -EAGAIN; - } - } - - /* grab a lock here due to read response handlers can access ctx */ - mutex_lock(&ctx->aio_mutex); - - rc = cifs_send_async_read(offset, len, cfile, cifs_sb, &ctx->list, ctx); - - /* if at least one read request send succeeded, then reset rc */ - if (!list_empty(&ctx->list)) - rc = 0; - - mutex_unlock(&ctx->aio_mutex); - - if (rc) { - kref_put(&ctx->refcount, cifs_aio_ctx_release); - return rc; - } - - if (!is_sync_kiocb(iocb)) { - kref_put(&ctx->refcount, cifs_aio_ctx_release); - return -EIOCBQUEUED; - } - - rc = wait_for_completion_killable(&ctx->done); - if (rc) { - mutex_lock(&ctx->aio_mutex); - ctx->rc = rc = -EINTR; - total_read = ctx->total_len; - mutex_unlock(&ctx->aio_mutex); - } else { - rc = ctx->rc; - total_read = ctx->total_len; - } - - kref_put(&ctx->refcount, cifs_aio_ctx_release); - - if (total_read) { - iocb->ki_pos += total_read; - return total_read; - } - return rc; -} - -ssize_t cifs_direct_readv(struct kiocb *iocb, struct iov_iter *to) -{ - return __cifs_readv(iocb, to, true); -} - -ssize_t cifs_user_readv(struct kiocb *iocb, struct iov_iter *to) -{ - return __cifs_readv(iocb, to, false); - -} -#endif // end netfslib removal 4143 - ssize_t cifs_loose_read_iter(struct kiocb *iocb, struct iov_iter *iter) { ssize_t rc; @@ -3838,101 +2929,6 @@ cifs_strict_readv(struct kiocb *iocb, struct iov_iter *to) return rc; } -#if 0 // TODO remove 4633 -static ssize_t -cifs_read(struct file *file, char *read_data, size_t read_size, loff_t *offset) -{ - int rc = -EACCES; - unsigned int bytes_read = 0; - unsigned int total_read; - unsigned int current_read_size; - unsigned int rsize; - struct cifs_sb_info *cifs_sb; - struct cifs_tcon *tcon; - struct TCP_Server_Info *server; - unsigned int xid; - char *cur_offset; - struct cifsFileInfo *open_file; - struct cifs_io_parms io_parms = {0}; - int buf_type = CIFS_NO_BUFFER; - __u32 pid; - - xid = get_xid(); - cifs_sb = CIFS_FILE_SB(file); - - /* FIXME: set up handlers for larger reads and/or convert to async */ - rsize = min_t(unsigned int, cifs_sb->ctx->rsize, CIFSMaxBufSize); - - if (file->private_data == NULL) { - rc = -EBADF; - free_xid(xid); - return rc; - } - open_file = file->private_data; - tcon = tlink_tcon(open_file->tlink); - server = cifs_pick_channel(tcon->ses); - - if (!server->ops->sync_read) { - free_xid(xid); - return -ENOSYS; - } - - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD) - pid = open_file->pid; - else - pid = current->tgid; - - if ((file->f_flags & O_ACCMODE) == O_WRONLY) - cifs_dbg(FYI, "attempting read on write only file instance\n"); - - for (total_read = 0, cur_offset = read_data; read_size > total_read; - total_read += bytes_read, cur_offset += bytes_read) { - do { - current_read_size = min_t(uint, read_size - total_read, - rsize); - /* - * For windows me and 9x we do not want to request more - * than it negotiated since it will refuse the read - * then. - */ - if (!(tcon->ses->capabilities & - tcon->ses->server->vals->cap_large_files)) { - current_read_size = min_t(uint, - current_read_size, CIFSMaxBufSize); - } - if (open_file->invalidHandle) { - rc = cifs_reopen_file(open_file, true); - if (rc != 0) - break; - } - io_parms.pid = pid; - io_parms.tcon = tcon; - io_parms.offset = *offset; - io_parms.length = current_read_size; - io_parms.server = server; - rc = server->ops->sync_read(xid, &open_file->fid, &io_parms, - &bytes_read, &cur_offset, - &buf_type); - } while (rc == -EAGAIN); - - if (rc || (bytes_read == 0)) { - if (total_read) { - break; - } else { - free_xid(xid); - return rc; - } - } else { - cifs_stats_bytes_read(tcon, total_read); - *offset += bytes_read; - } - } - free_xid(xid); - return total_read; -} -#endif // end netfslib remove 4633 - - static vm_fault_t cifs_page_mkwrite(struct vm_fault *vmf) { return netfs_page_mkwrite(vmf, NULL); -- cgit From 7c1ac89480e8d5d34d38a868642216c8f05ee602 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 17 Apr 2024 15:00:55 +0100 Subject: cifs: Enable large folio support Now that cifs is using netfslib for its VM interaction, it only sees I/O in terms of iov_iter iterators and does not see pages or folios. This makes large multipage folios transparent to cifs and so we can turn on multipage folios on regular files. Signed-off-by: David Howells cc: Steve French cc: Shyam Prasad N cc: Rohith Surabattula cc: Jeff Layton cc: linux-cifs@vger.kernel.org cc: netfs@lists.linux.dev cc: linux-fsdevel@vger.kernel.org cc: linux-mm@kvack.org --- fs/smb/client/inode.c | 1 + 1 file changed, 1 insertion(+) (limited to 'fs/smb') diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c index 5239c823de86..e8bfeea23660 100644 --- a/fs/smb/client/inode.c +++ b/fs/smb/client/inode.c @@ -72,6 +72,7 @@ static void cifs_set_ops(struct inode *inode) inode->i_data.a_ops = &cifs_addr_ops_smallbuf; else inode->i_data.a_ops = &cifs_addr_ops; + mapping_set_large_folios(inode->i_mapping); break; case S_IFDIR: if (IS_AUTOMOUNT(inode)) { -- cgit