From 82722f5bb281fd1fc34f28b9fa3abf74c41b66fb Mon Sep 17 00:00:00 2001 From: Shyam Prasad N Date: Mon, 26 Apr 2021 12:28:50 +0000 Subject: [PATCH] cifs: when out of credits on one channel, retry on another. Following the fix: smb3: fix crediting for compounding when only one request in flight ... we're returning -EDEADLK when we run out of credits on a connection to the server, indicating a wrong accounting. However, for a multichannel scenario, we should not return this error straightaway, as there could be other channels that do have credits. We must try all channels before we give up. Today, we don't have a good way to know when to give up here. So we keep retrying indefinitely. Also, this fix assumes that cifs_pick_channel() selects a different channel on retry. When a new channel allocation strategy is implemented, we should make sure that we don't select a channel that ran out of credits, unless it received credits from the server. This fix mostly introduces a wrapper for all functions which call cifs_pick_channel. In the wrapper function, the function is retried when the error is -EDEADLK, and uses multichannel. Signed-off-by: Shyam Prasad N Signed-off-by: Steve French --- fs/cifs/file.c | 96 +++++++++++- fs/cifs/smb2inode.c | 93 ++++++++---- fs/cifs/smb2ops.c | 113 +++++++++++++- fs/cifs/smb2pdu.c | 359 ++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 593 insertions(+), 68 deletions(-) diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 3d4e6e7dac1d..5cf3ce25ffa2 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -2316,7 +2316,7 @@ wdata_send_pages(struct cifs_writedata *wdata, unsigned int nr_pages, return rc; } -static int cifs_writepages(struct address_space *mapping, +static int cifs_writepages_final(struct address_space *mapping, struct writeback_control *wbc) { struct inode *inode = mapping->host; @@ -2479,6 +2479,21 @@ static int cifs_writepages(struct address_space *mapping, return rc; } +static int cifs_writepages(struct address_space *mapping, + struct writeback_control *wbc) +{ + int rc; + struct inode *inode = mapping->host; + struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); + struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); + + do { + rc = cifs_writepages_final(mapping, wbc); + } while (tcon->ses->chan_count > 1 && rc == -EDEADLK); + + return rc; +} + static int cifs_writepage_locked(struct page *page, struct writeback_control *wbc) { @@ -2871,7 +2886,7 @@ cifs_resend_wdata(struct cifs_writedata *wdata, struct list_head *wdata_list, } static int -cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from, +cifs_write_from_iter_final(loff_t offset, 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) @@ -3036,6 +3051,24 @@ cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from, return rc; } +static int +cifs_write_from_iter(loff_t offset, 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; + struct cifs_tcon *tcon = tlink_tcon(open_file->tlink); + + do { + rc = cifs_write_from_iter_final(offset, len, from, + open_file, cifs_sb, + wdata_list, ctx); + } while (tcon->ses->chan_count > 1 && rc == -EDEADLK); + + return rc; +} + static void collect_uncached_write_data(struct cifs_aio_ctx *ctx) { struct cifs_writedata *wdata, *tmp; @@ -3605,7 +3638,7 @@ static int cifs_resend_rdata(struct cifs_readdata *rdata, } static int -cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file, +cifs_send_async_read_final(loff_t offset, size_t len, struct cifsFileInfo *open_file, struct cifs_sb_info *cifs_sb, struct list_head *rdata_list, struct cifs_aio_ctx *ctx) { @@ -3746,6 +3779,23 @@ cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file, return rc; } +static int +cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file, + struct cifs_sb_info *cifs_sb, struct list_head *rdata_list, + struct cifs_aio_ctx *ctx) +{ + int rc; + struct cifs_tcon *tcon = tlink_tcon(open_file->tlink); + + do { + rc = cifs_send_async_read_final(offset, len, + open_file, cifs_sb, + rdata_list, ctx); + } while (tcon->ses->chan_count > 1 && rc == -EDEADLK); + + return rc; +} + static void collect_uncached_read_data(struct cifs_aio_ctx *ctx) { @@ -4005,7 +4055,7 @@ cifs_strict_readv(struct kiocb *iocb, struct iov_iter *to) } static ssize_t -cifs_read(struct file *file, char *read_data, size_t read_size, loff_t *offset) +cifs_read_final(struct file *file, char *read_data, size_t read_size, loff_t *offset) { int rc = -EACCES; unsigned int bytes_read = 0; @@ -4096,6 +4146,24 @@ cifs_read(struct file *file, char *read_data, size_t read_size, loff_t *offset) return total_read; } +static ssize_t +cifs_read(struct file *file, char *read_data, size_t read_size, loff_t *offset) +{ + int rc; + struct cifsFileInfo *open_file; + struct cifs_tcon *tcon; + + open_file = file->private_data; + tcon = tlink_tcon(open_file->tlink); + + do { + rc = cifs_read_final(file, read_data, + read_size, offset); + } while (tcon->ses->chan_count > 1 && rc == -EDEADLK); + + return rc; +} + /* * 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. @@ -4346,7 +4414,7 @@ readpages_get_pages(struct address_space *mapping, struct list_head *page_list, return rc; } -static int cifs_readpages(struct file *file, struct address_space *mapping, +static int cifs_readpages_final(struct file *file, struct address_space *mapping, struct list_head *page_list, unsigned num_pages) { int rc; @@ -4501,6 +4569,24 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, return rc; } +static int cifs_readpages(struct file *file, struct address_space *mapping, + struct list_head *page_list, unsigned int num_pages) +{ + int rc; + struct cifsFileInfo *open_file; + struct cifs_tcon *tcon; + + open_file = file->private_data; + tcon = tlink_tcon(open_file->tlink); + + do { + rc = cifs_readpages_final(file, mapping, + page_list, num_pages); + } while (tcon->ses->chan_count > 1 && rc == -EDEADLK); + + return rc; +} + /* * cifs_readpage_worker must be called with the page pinned */ diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c index 9a61209a283e..24c02a989d1d 100644 --- a/fs/cifs/smb2inode.c +++ b/fs/cifs/smb2inode.c @@ -60,7 +60,7 @@ struct cop_vars { }; static int -smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, +smb2_compound_op_final(const unsigned int xid, struct cifs_tcon *tcon, struct cifs_sb_info *cifs_sb, const char *full_path, __u32 desired_access, __u32 create_disposition, __u32 create_options, umode_t mode, void *ptr, int command, @@ -371,8 +371,6 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, num_rqst++; if (cfile) { - cifsFileInfo_put(cfile); - cfile = NULL; rc = compound_send_recv(xid, ses, server, flags, num_rqst - 2, &rqst[1], &resp_buftype[1], @@ -384,9 +382,6 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, rsp_iov); finished: - if (cfile) - cifsFileInfo_put(cfile); - SMB2_open_free(&rqst[0]); if (rc == -EREMCHG) { pr_warn_once("server share %s deleted\n", tcon->treeName); @@ -494,6 +489,43 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, return rc; } +static int +smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, + struct cifs_sb_info *cifs_sb, const char *full_path, + __u32 desired_access, __u32 create_disposition, + __u32 create_options, umode_t mode, void *ptr, int command, + bool check_open, bool writable_path) +{ + int flags; + int rc; + struct cifsFileInfo *cfile; + + /* Check if we have the handle open */ + if (check_open) { + if (writable_path) { + if (command == SMB2_OP_RENAME) + flags = FIND_WR_WITH_DELETE; + else + flags = FIND_WR_ANY; + + cifs_get_writable_path(tcon, full_path, flags, &cfile); + } else + cifs_get_readable_path(tcon, full_path, &cfile); + } + + /* If we ran out of credits, and ses uses multichannel, try again on another chan */ + do { + rc = smb2_compound_op_final(xid, tcon, cifs_sb, full_path, + desired_access, create_disposition, create_options, + mode, ptr, command, cfile); + } while (tcon->ses->chan_count > 1 && rc == -EDEADLK); + + if (check_open && cfile) + cifsFileInfo_put(cfile); + + return rc; +} + void move_smb2_info_to_cifs(FILE_ALL_INFO *dst, struct smb2_file_all_info *src) { @@ -512,7 +544,6 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, int rc; struct smb2_file_all_info *smb2_data; __u32 create_options = 0; - struct cifsFileInfo *cfile; struct cached_fid *cfid = NULL; *adjust_tz = false; @@ -540,10 +571,11 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, goto out; } - cifs_get_readable_path(tcon, full_path, &cfile); rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, FILE_OPEN, create_options, - ACL_NO_MODE, smb2_data, SMB2_OP_QUERY_INFO, cfile); + ACL_NO_MODE, smb2_data, SMB2_OP_QUERY_INFO, + true, false); + if (rc == -EOPNOTSUPP) { *reparse = true; create_options |= OPEN_REPARSE_POINT; @@ -552,7 +584,8 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, FILE_OPEN, create_options, ACL_NO_MODE, - smb2_data, SMB2_OP_QUERY_INFO, NULL); + smb2_data, SMB2_OP_QUERY_INFO, + false, false); } if (rc) goto out; @@ -571,7 +604,6 @@ smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, { int rc; __u32 create_options = 0; - struct cifsFileInfo *cfile; struct smb311_posix_qinfo *smb2_data; *adjust_tz = false; @@ -590,10 +622,10 @@ smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, * (always using the compounded version). */ - cifs_get_readable_path(tcon, full_path, &cfile); rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, FILE_OPEN, create_options, - ACL_NO_MODE, smb2_data, SMB2_OP_POSIX_QUERY_INFO, cfile); + ACL_NO_MODE, smb2_data, SMB2_OP_POSIX_QUERY_INFO, + true, false); if (rc == -EOPNOTSUPP) { /* BB TODO: When support for special files added to Samba re-verify this path */ *reparse = true; @@ -603,7 +635,8 @@ smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, FILE_OPEN, create_options, ACL_NO_MODE, - smb2_data, SMB2_OP_POSIX_QUERY_INFO, NULL); + smb2_data, SMB2_OP_POSIX_QUERY_INFO, + false, false); } if (rc) goto out; @@ -624,7 +657,7 @@ smb2_mkdir(const unsigned int xid, struct inode *parent_inode, umode_t mode, return smb2_compound_op(xid, tcon, cifs_sb, name, FILE_WRITE_ATTRIBUTES, FILE_CREATE, CREATE_NOT_FILE, mode, NULL, SMB2_OP_MKDIR, - NULL); + false, false); } void @@ -634,7 +667,6 @@ smb2_mkdir_setinfo(struct inode *inode, const char *name, { FILE_BASIC_INFO data; struct cifsInodeInfo *cifs_i; - struct cifsFileInfo *cfile; u32 dosattrs; int tmprc; @@ -642,11 +674,11 @@ smb2_mkdir_setinfo(struct inode *inode, const char *name, cifs_i = CIFS_I(inode); dosattrs = cifs_i->cifsAttrs | ATTR_READONLY; data.Attributes = cpu_to_le32(dosattrs); - cifs_get_writable_path(tcon, name, FIND_WR_ANY, &cfile); tmprc = smb2_compound_op(xid, tcon, cifs_sb, name, FILE_WRITE_ATTRIBUTES, FILE_CREATE, CREATE_NOT_FILE, ACL_NO_MODE, - &data, SMB2_OP_SET_INFO, cfile); + &data, SMB2_OP_SET_INFO, + true, true); if (tmprc == 0) cifs_i->cifsAttrs = dosattrs; } @@ -657,7 +689,8 @@ smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name, { return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN, CREATE_NOT_FILE, ACL_NO_MODE, - NULL, SMB2_OP_RMDIR, NULL); + NULL, SMB2_OP_RMDIR, + false, false); } int @@ -666,14 +699,15 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name, { return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN, CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT, - ACL_NO_MODE, NULL, SMB2_OP_DELETE, NULL); + ACL_NO_MODE, NULL, SMB2_OP_DELETE, + false, false); } static int smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon, const char *from_name, const char *to_name, struct cifs_sb_info *cifs_sb, __u32 access, int command, - struct cifsFileInfo *cfile) + bool check_open, bool writable_path) { __le16 *smb2_to_name = NULL; int rc; @@ -685,7 +719,7 @@ smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon, } rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access, FILE_OPEN, 0, ACL_NO_MODE, smb2_to_name, - command, cfile); + command, check_open, writable_path); smb2_rename_path: kfree(smb2_to_name); return rc; @@ -696,12 +730,9 @@ smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon, const char *from_name, const char *to_name, struct cifs_sb_info *cifs_sb) { - struct cifsFileInfo *cfile; - - cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile); - return smb2_set_path_attr(xid, tcon, from_name, to_name, - cifs_sb, DELETE, SMB2_OP_RENAME, cfile); + cifs_sb, DELETE, SMB2_OP_RENAME, + true, true); } int @@ -711,7 +742,7 @@ smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon, { return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb, FILE_READ_ATTRIBUTES, SMB2_OP_HARDLINK, - NULL); + false, false); } int @@ -723,7 +754,8 @@ smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon, return smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_WRITE_DATA, FILE_OPEN, 0, ACL_NO_MODE, - &eof, SMB2_OP_SET_EOF, NULL); + &eof, SMB2_OP_SET_EOF, + false, false); } int @@ -745,7 +777,8 @@ smb2_set_file_info(struct inode *inode, const char *full_path, rc = smb2_compound_op(xid, tlink_tcon(tlink), cifs_sb, full_path, FILE_WRITE_ATTRIBUTES, FILE_OPEN, - 0, ACL_NO_MODE, buf, SMB2_OP_SET_INFO, NULL); + 0, ACL_NO_MODE, buf, SMB2_OP_SET_INFO, + false, false); cifs_put_tlink(tlink); return rc; } diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index dd0eb665b680..5bcfa7904fba 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -1222,7 +1222,7 @@ smb2_query_eas(const unsigned int xid, struct cifs_tcon *tcon, static int -smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, +smb2_set_ea_final(const unsigned int xid, struct cifs_tcon *tcon, const char *path, const char *ea_name, const void *ea_value, const __u16 ea_value_len, const struct nls_table *nls_codepage, struct cifs_sb_info *cifs_sb) @@ -1377,6 +1377,23 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base); return rc; } + +static int +smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, + const char *path, const char *ea_name, const void *ea_value, + const __u16 ea_value_len, const struct nls_table *nls_codepage, + struct cifs_sb_info *cifs_sb) +{ + int rc; + + do { + rc = smb2_set_ea_final(xid, tcon, path, + ea_name, ea_value, ea_value_len, + nls_codepage, cifs_sb); + } while (tcon->ses->chan_count > 1 && rc == -EDEADLK); + + return rc; +} #endif static bool @@ -1597,7 +1614,7 @@ struct iqi_vars { }; static int -smb2_ioctl_query_info(const unsigned int xid, +smb2_ioctl_query_info_final(const unsigned int xid, struct cifs_tcon *tcon, struct cifs_sb_info *cifs_sb, __le16 *path, int is_dir, @@ -1817,6 +1834,23 @@ smb2_ioctl_query_info(const unsigned int xid, goto iqinf_exit; } +static int +smb2_ioctl_query_info(const unsigned int xid, + struct cifs_tcon *tcon, + struct cifs_sb_info *cifs_sb, + __le16 *path, int is_dir, + unsigned long p) +{ + int rc; + + do { + rc = smb2_ioctl_query_info_final(xid, tcon, cifs_sb, + path, is_dir, p); + } while (tcon->ses->chan_count > 1 && rc == -EDEADLK); + + return rc; +} + static ssize_t smb2_copychunk_range(const unsigned int xid, struct cifsFileInfo *srcfile, @@ -2306,7 +2340,7 @@ smb3_notify(const unsigned int xid, struct file *pfile, } static int -smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon, +smb2_query_dir_first_final(const unsigned int xid, struct cifs_tcon *tcon, const char *path, struct cifs_sb_info *cifs_sb, struct cifs_fid *fid, __u16 search_flags, struct cifs_search_info *srch_inf) @@ -2424,6 +2458,23 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon, return rc; } +static int +smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon, + const char *path, struct cifs_sb_info *cifs_sb, + struct cifs_fid *fid, __u16 search_flags, + struct cifs_search_info *srch_inf) +{ + int rc; + + do { + rc = smb2_query_dir_first_final(xid, tcon, + path, cifs_sb, fid, + search_flags, srch_inf); + } while (tcon->ses->chan_count > 1 && rc == -EDEADLK); + + return rc; +} + static int smb2_query_dir_next(const unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *fid, __u16 search_flags, @@ -2617,7 +2668,7 @@ smb2_set_next_command(struct cifs_tcon *tcon, struct smb_rqst *rqst) * Caller need to free this with free_rsp_buf(). */ int -smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon, +smb2_query_info_compound_final(const unsigned int xid, struct cifs_tcon *tcon, __le16 *utf16_path, u32 desired_access, u32 class, u32 type, u32 output_len, struct kvec *rsp, int *buftype, @@ -2709,6 +2760,25 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon, return rc; } +int +smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon, + __le16 *utf16_path, u32 desired_access, + u32 class, u32 type, u32 output_len, + struct kvec *rsp, int *buftype, + struct cifs_sb_info *cifs_sb) +{ + int rc; + + do { + rc = smb2_query_info_compound_final(xid, tcon, + utf16_path, desired_access, + class, type, output_len, + rsp, buftype, cifs_sb); + } while (tcon->ses->chan_count > 1 && rc == -EDEADLK); + + return rc; +} + static int smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon, struct cifs_sb_info *cifs_sb, struct kstatfs *buf) @@ -3006,7 +3076,7 @@ parse_reparse_point(struct reparse_data_buffer *buf, (sizeof(struct smb2_err_rsp) - 1 + sizeof(struct smb2_symlink_err_rsp)) static int -smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, +smb2_query_symlink_final(const unsigned int xid, struct cifs_tcon *tcon, struct cifs_sb_info *cifs_sb, const char *full_path, char **target_path, bool is_reparse_point) { @@ -3194,8 +3264,24 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, return rc; } +static int +smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, + struct cifs_sb_info *cifs_sb, const char *full_path, + char **target_path, bool is_reparse_point) +{ + int rc; + + do { + rc = smb2_query_symlink_final(xid, tcon, + cifs_sb, full_path, target_path, + is_reparse_point); + } while (tcon->ses->chan_count > 1 && rc == -EDEADLK); + + return rc; +} + int -smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon, +smb2_query_reparse_tag_final(const unsigned int xid, struct cifs_tcon *tcon, struct cifs_sb_info *cifs_sb, const char *full_path, __u32 *tag) { @@ -3321,6 +3407,21 @@ smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon, return rc; } +int +smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon, + struct cifs_sb_info *cifs_sb, const char *full_path, + __u32 *tag) +{ + int rc; + + do { + rc = smb2_query_reparse_tag_final(xid, tcon, + cifs_sb, full_path, tag); + } while (tcon->ses->chan_count > 1 && rc == -EDEADLK); + + return rc; +} + static struct cifs_ntsd * get_smb2_acl_by_fid(struct cifs_sb_info *cifs_sb, const struct cifs_fid *cifsfid, u32 *pacllen, u32 info) diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index e36c2a867783..9b38be5f5c9b 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -2475,7 +2475,7 @@ alloc_path_with_tree_prefix(__le16 **out_path, int *out_size, int *out_len, return 0; } -int smb311_posix_mkdir(const unsigned int xid, struct inode *inode, +int smb311_posix_mkdir_final(const unsigned int xid, struct inode *inode, umode_t mode, struct cifs_tcon *tcon, const char *full_path, struct cifs_sb_info *cifs_sb) @@ -2628,6 +2628,22 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode, return rc; } +int smb311_posix_mkdir(const unsigned int xid, struct inode *inode, + umode_t mode, struct cifs_tcon *tcon, + const char *full_path, + struct cifs_sb_info *cifs_sb) +{ + int rc; + + do { + rc = smb311_posix_mkdir_final(xid, inode, + mode, tcon, full_path, + cifs_sb); + } while (tcon->ses->chan_count > 1 && rc == -EDEADLK); + + return rc; +} + int SMB2_open_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server, struct smb_rqst *rqst, __u8 *oplock, @@ -2823,7 +2839,7 @@ SMB2_open_free(struct smb_rqst *rqst) } int -SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, +SMB2_open_final(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, __u8 *oplock, struct smb2_file_all_info *buf, struct create_posix_rsp *posix, struct kvec *err_iov, int *buftype) @@ -2911,6 +2927,24 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, return rc; } +int +SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, + __u8 *oplock, struct smb2_file_all_info *buf, + struct create_posix_rsp *posix, + struct kvec *err_iov, int *buftype) +{ + int rc; + struct cifs_tcon *tcon = oparms->tcon; + + do { + rc = SMB2_open_final(xid, oparms, path, + oplock, buf, + posix, err_iov, buftype); + } while (tcon->ses->chan_count > 1 && rc == -EDEADLK); + + return rc; +} + int SMB2_ioctl_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server, struct smb_rqst *rqst, @@ -3019,7 +3053,7 @@ SMB2_ioctl_free(struct smb_rqst *rqst) * SMB2 IOCTL is used for both IOCTLs and FSCTLs */ int -SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, +SMB2_ioctl_final(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid, u32 opcode, bool is_fsctl, char *in_data, u32 indatalen, u32 max_out_data_len, char **out_data, u32 *plen /* returned data len */) @@ -3130,6 +3164,25 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, return rc; } +int +SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, + u64 volatile_fid, u32 opcode, bool is_fsctl, + char *in_data, u32 indatalen, u32 max_out_data_len, + char **out_data, u32 *plen /* returned data len */) +{ + int rc; + + do { + rc = SMB2_ioctl_final(xid, tcon, + persistent_fid, volatile_fid, + opcode, is_fsctl, + in_data, indatalen, + max_out_data_len, out_data, plen); + } while (tcon->ses->chan_count > 1 && rc == -EDEADLK); + + return rc; +} + /* * Individual callers to ioctl worker function follow */ @@ -3191,7 +3244,7 @@ SMB2_close_free(struct smb_rqst *rqst) } int -__SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, +__SMB2_close_final(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid, struct smb2_file_network_open_info *pbuf) { @@ -3268,6 +3321,22 @@ __SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, return rc; } +int +__SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, + u64 persistent_fid, u64 volatile_fid, + struct smb2_file_network_open_info *pbuf) +{ + int rc; + + do { + rc = __SMB2_close_final(xid, tcon, + persistent_fid, volatile_fid, + pbuf); + } while (tcon->ses->chan_count > 1 && rc == -EDEADLK); + + return rc; +} + int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid) @@ -3375,7 +3444,7 @@ SMB2_query_info_free(struct smb_rqst *rqst) } static int -query_info(const unsigned int xid, struct cifs_tcon *tcon, +query_info_final(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid, u8 info_class, u8 info_type, u32 additional_info, size_t output_len, size_t min_len, void **data, u32 *dlen) @@ -3462,6 +3531,26 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon, return rc; } +static int +query_info(const unsigned int xid, struct cifs_tcon *tcon, + u64 persistent_fid, u64 volatile_fid, u8 info_class, u8 info_type, + u32 additional_info, size_t output_len, size_t min_len, void **data, + u32 *dlen) +{ + int rc; + + do { + rc = query_info_final(xid, tcon, + persistent_fid, volatile_fid, + info_class, info_type, + additional_info, + output_len, min_len, + data, dlen); + } while (tcon->ses->chan_count > 1 && rc == -EDEADLK); + + return rc; +} + int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid, struct smb2_file_all_info *data) { @@ -3549,7 +3638,7 @@ SMB2_notify_init(const unsigned int xid, struct smb_rqst *rqst, } int -SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon, +SMB2_change_notify_final(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid, bool watch_tree, u32 completion_filter) { @@ -3600,7 +3689,21 @@ SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon, return rc; } +int +SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon, + u64 persistent_fid, u64 volatile_fid, bool watch_tree, + u32 completion_filter) +{ + int rc; + do { + rc = SMB2_change_notify_final(xid, tcon, + persistent_fid, volatile_fid, + watch_tree, completion_filter); + } while (tcon->ses->chan_count > 1 && rc == -EDEADLK); + + return rc; +} /* * This is a no-op for now. We're not really interested in the reply, but @@ -3764,7 +3867,7 @@ SMB2_flush_init(const unsigned int xid, struct smb_rqst *rqst, } int -SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, +SMB2_flush_final(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid) { struct cifs_ses *ses = tcon->ses; @@ -3811,6 +3914,20 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, return rc; } +int +SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, + u64 volatile_fid) +{ + int rc; + + do { + rc = SMB2_flush_final(xid, tcon, + persistent_fid, volatile_fid); + } while (tcon->ses->chan_count > 1 && rc == -EDEADLK); + + return rc; +} + /* * To form a chain of read requests, any read requests after the first should * have the end_of_chain boolean set to true. @@ -3997,9 +4114,8 @@ smb2_readv_callback(struct mid_q_entry *mid) add_credits(server, &credits, 0); } -/* 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_final(struct cifs_readdata *rdata) { int rc, flags = 0; char *buf; @@ -4069,8 +4185,24 @@ smb2_async_readv(struct cifs_readdata *rdata) return rc; } +/* smb2_async_readv - send an async read, and set up mid to handle result */ int -SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms, +smb2_async_readv(struct cifs_readdata *rdata) +{ + int rc; + struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink); + + do { + rc = smb2_async_readv_final(rdata); + } while (!rdata->server && + tcon->ses->chan_count > 1 && + rc == -EDEADLK); + + return rc; +} + +int +SMB2_read_final(const unsigned int xid, struct cifs_io_parms *io_parms, unsigned int *nbytes, char **buf, int *buf_type) { struct smb_rqst rqst; @@ -4149,6 +4281,23 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms, return rc; } +int +SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms, + unsigned int *nbytes, char **buf, int *buf_type) +{ + int rc; + struct cifs_tcon *tcon = io_parms->tcon; + + do { + rc = SMB2_read_final(xid, io_parms, + nbytes, buf, buf_type); + } while (!io_parms->server && + tcon->ses->chan_count > 1 && + rc == -EDEADLK); + + return rc; +} + /* * Check the mid_state and signature on received buffer (if any), and queue the * workqueue completion task. @@ -4235,9 +4384,8 @@ smb2_writev_callback(struct mid_q_entry *mid) add_credits(server, &credits, 0); } -/* smb2_async_writev - send an async write, and set up mid to handle result */ int -smb2_async_writev(struct cifs_writedata *wdata, +smb2_async_writev_final(struct cifs_writedata *wdata, void (*release)(struct kref *kref)) { int rc = -EACCES, flags = 0; @@ -4373,14 +4521,25 @@ smb2_async_writev(struct cifs_writedata *wdata, return rc; } -/* - * SMB2_write function gets iov pointer to kvec array with n_vec as a length. - * The length field from io_parms must be at least 1 and indicates a number of - * elements with data to write that begins with position 1 in iov array. All - * data length is specified by count. - */ +/* smb2_async_writev - send an async write, and set up mid to handle result */ int -SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms, +smb2_async_writev(struct cifs_writedata *wdata, + void (*release)(struct kref *kref)) +{ + int rc; + struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink); + + do { + rc = smb2_async_writev_final(wdata, release); + } while (!wdata->server && + tcon->ses->chan_count > 1 && + rc == -EDEADLK); + + return rc; +} + +int +SMB2_write_final(const unsigned int xid, struct cifs_io_parms *io_parms, unsigned int *nbytes, struct kvec *iov, int n_vec) { struct smb_rqst rqst; @@ -4462,6 +4621,29 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms, return rc; } +/* + * SMB2_write function gets iov pointer to kvec array with n_vec as a length. + * The length field from io_parms must be at least 1 and indicates a number of + * elements with data to write that begins with position 1 in iov array. All + * data length is specified by count. + */ +int +SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms, + unsigned int *nbytes, struct kvec *iov, int n_vec) +{ + int rc; + struct cifs_tcon *tcon = io_parms->tcon; + + do { + rc = SMB2_write_final(xid, io_parms, + nbytes, iov, n_vec); + } while (!io_parms->server && + tcon->ses->chan_count > 1 && + rc == -EDEADLK); + + return rc; +} + int posix_info_sid_size(const void *beg, const void *end) { size_t subauth; @@ -4761,7 +4943,7 @@ smb2_parse_query_directory(struct cifs_tcon *tcon, } int -SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, +SMB2_query_directory_final(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid, int index, struct cifs_search_info *srch_inf) { @@ -4830,6 +5012,22 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, return rc; } +int +SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, + u64 persistent_fid, u64 volatile_fid, int index, + struct cifs_search_info *srch_inf) +{ + int rc; + + do { + rc = SMB2_query_directory_final(xid, tcon, + persistent_fid, volatile_fid, index, + srch_inf); + } while (tcon->ses->chan_count > 1 && rc == -EDEADLK); + + return rc; +} + int SMB2_set_info_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server, struct smb_rqst *rqst, @@ -4882,7 +5080,7 @@ SMB2_set_info_free(struct smb_rqst *rqst) } static int -send_set_info(const unsigned int xid, struct cifs_tcon *tcon, +send_set_info_final(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid, u32 pid, u8 info_class, u8 info_type, u32 additional_info, unsigned int num, void **data, unsigned int *size) @@ -4941,6 +5139,25 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon, return rc; } +static int +send_set_info(const unsigned int xid, struct cifs_tcon *tcon, + u64 persistent_fid, u64 volatile_fid, u32 pid, u8 info_class, + u8 info_type, u32 additional_info, unsigned int num, + void **data, unsigned int *size) +{ + int rc; + + do { + rc = send_set_info_final(xid, tcon, + persistent_fid, volatile_fid, + pid, info_class, info_type, + additional_info, + num, data, size); + } while (tcon->ses->chan_count > 1 && rc == -EDEADLK); + + return rc; +} + int SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid, u32 pid, __le64 *eof) @@ -4980,7 +5197,7 @@ SMB2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, } int -SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon, +SMB2_oplock_break_final(const unsigned int xid, struct cifs_tcon *tcon, const u64 persistent_fid, const u64 volatile_fid, __u8 oplock_level) { @@ -5030,6 +5247,22 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon, return rc; } +int +SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon, + const u64 persistent_fid, const u64 volatile_fid, + __u8 oplock_level) +{ + int rc; + + do { + rc = SMB2_oplock_break_final(xid, tcon, + persistent_fid, volatile_fid, + oplock_level); + } while (tcon->ses->chan_count > 1 && rc == -EDEADLK); + + return rc; +} + void smb2_copy_fs_info_to_kstatfs(struct smb2_fs_full_size_info *pfs_inf, struct kstatfs *kst) @@ -5097,7 +5330,7 @@ build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon, } int -SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon, +SMB311_posix_qfs_info_final(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid, struct kstatfs *fsdata) { struct smb_rqst rqst; @@ -5148,7 +5381,21 @@ SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon, } int -SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon, +SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon, + u64 persistent_fid, u64 volatile_fid, struct kstatfs *fsdata) +{ + int rc; + + do { + rc = SMB311_posix_qfs_info_final(xid, tcon, + persistent_fid, volatile_fid, fsdata); + } while (tcon->ses->chan_count > 1 && rc == -EDEADLK); + + return rc; +} + +int +SMB2_QFS_info_final(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid, struct kstatfs *fsdata) { struct smb_rqst rqst; @@ -5199,7 +5446,21 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon, } int -SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon, +SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon, + u64 persistent_fid, u64 volatile_fid, struct kstatfs *fsdata) +{ + int rc; + + do { + rc = SMB2_QFS_info_final(xid, tcon, + persistent_fid, volatile_fid, fsdata); + } while (tcon->ses->chan_count > 1 && rc == -EDEADLK); + + return rc; +} + +int +SMB2_QFS_attr_final(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid, int level) { struct smb_rqst rqst; @@ -5284,7 +5545,21 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon, } int -smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon, +SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon, + u64 persistent_fid, u64 volatile_fid, int level) +{ + int rc; + + do { + rc = SMB2_QFS_attr_final(xid, tcon, + persistent_fid, volatile_fid, level); + } while (tcon->ses->chan_count > 1 && rc == -EDEADLK); + + return rc; +} + +int +smb2_lockv_final(const unsigned int xid, struct cifs_tcon *tcon, const __u64 persist_fid, const __u64 volatile_fid, const __u32 pid, const __u32 num_lock, struct smb2_lock_element *buf) { @@ -5342,6 +5617,22 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon, return rc; } +int +smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon, + const __u64 persist_fid, const __u64 volatile_fid, const __u32 pid, + const __u32 num_lock, struct smb2_lock_element *buf) +{ + int rc; + + do { + rc = smb2_lockv_final(xid, tcon, + persist_fid, volatile_fid, pid, + num_lock, buf); + } while (tcon->ses->chan_count > 1 && rc == -EDEADLK); + + return rc; +} + int SMB2_lock(const unsigned int xid, struct cifs_tcon *tcon, const __u64 persist_fid, const __u64 volatile_fid, const __u32 pid, @@ -5360,7 +5651,7 @@ SMB2_lock(const unsigned int xid, struct cifs_tcon *tcon, } int -SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon, +SMB2_lease_break_final(const unsigned int xid, struct cifs_tcon *tcon, __u8 *lease_key, const __le32 lease_state) { struct smb_rqst rqst; @@ -5418,3 +5709,17 @@ SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon, return rc; } + +int +SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon, + __u8 *lease_key, const __le32 lease_state) +{ + int rc; + + do { + rc = SMB2_lease_break_final(xid, tcon, + lease_key, lease_state); + } while (tcon->ses->chan_count > 1 && rc == -EDEADLK); + + return rc; +} -- 2.27.0