mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 10:41:38 -04:00
Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6
Pull CIFS updates from Steve French: "The most visible change in this set is the additional of multi-credit support for SMB2/SMB3 which dramatically improves the large file i/o performance for these dialects and significantly increases the maximum i/o size used on the wire for SMB2/SMB3. Also reconnection behavior after network failure is improved" * 'for-next' of git://git.samba.org/sfrench/cifs-2.6: (35 commits) Add worker function to set allocation size [CIFS] Fix incorrect hex vs. decimal in some debug print statements update CIFS TODO list Add Pavel to contributor list in cifs AUTHORS file Update cifs version CIFS: Fix STATUS_CANNOT_DELETE error mapping for SMB2 CIFS: Optimize readpages in a short read case on reconnects CIFS: Optimize cifs_user_read() in a short read case on reconnects CIFS: Improve indentation in cifs_user_read() CIFS: Fix possible buffer corruption in cifs_user_read() CIFS: Count got bytes in read_into_pages() CIFS: Use separate var for the number of bytes got in async read CIFS: Indicate reconnect with ECONNABORTED error code CIFS: Use multicredits for SMB 2.1/3 reads CIFS: Fix rsize usage for sync read CIFS: Fix rsize usage in user read CIFS: Separate page reading from user read CIFS: Fix rsize usage in readpages CIFS: Separate page search from readpages CIFS: Use multicredits for SMB 2.1/3 writes ...
This commit is contained in:
commit
023f78b02c
20 changed files with 1702 additions and 844 deletions
|
|
@ -213,7 +213,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
|
|||
tcon->nativeFileSystem);
|
||||
}
|
||||
seq_printf(m, "DevInfo: 0x%x Attributes: 0x%x"
|
||||
"\n\tPathComponentMax: %d Status: 0x%d",
|
||||
"\n\tPathComponentMax: %d Status: %d",
|
||||
le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics),
|
||||
le32_to_cpu(tcon->fsAttrInfo.Attributes),
|
||||
le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength),
|
||||
|
|
|
|||
|
|
@ -136,5 +136,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
|
|||
extern const struct export_operations cifs_export_ops;
|
||||
#endif /* CONFIG_CIFS_NFSD_EXPORT */
|
||||
|
||||
#define CIFS_VERSION "2.03"
|
||||
#define CIFS_VERSION "2.04"
|
||||
#endif /* _CIFSFS_H */
|
||||
|
|
|
|||
|
|
@ -404,6 +404,11 @@ struct smb_version_operations {
|
|||
const struct cifs_fid *, u32 *);
|
||||
int (*set_acl)(struct cifs_ntsd *, __u32, struct inode *, const char *,
|
||||
int);
|
||||
/* 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 *, unsigned int *);
|
||||
};
|
||||
|
||||
struct smb_version_values {
|
||||
|
|
@ -639,6 +644,16 @@ add_credits(struct TCP_Server_Info *server, const unsigned int add,
|
|||
server->ops->add_credits(server, add, optype);
|
||||
}
|
||||
|
||||
static inline void
|
||||
add_credits_and_wake_if(struct TCP_Server_Info *server, const unsigned int add,
|
||||
const int optype)
|
||||
{
|
||||
if (add) {
|
||||
server->ops->add_credits(server, add, optype);
|
||||
wake_up(&server->request_q);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
set_credits(struct TCP_Server_Info *server, const int val)
|
||||
{
|
||||
|
|
@ -1044,6 +1059,7 @@ struct cifs_readdata {
|
|||
struct address_space *mapping;
|
||||
__u64 offset;
|
||||
unsigned int bytes;
|
||||
unsigned int got_bytes;
|
||||
pid_t pid;
|
||||
int result;
|
||||
struct work_struct work;
|
||||
|
|
@ -1053,6 +1069,7 @@ struct cifs_readdata {
|
|||
struct kvec iov;
|
||||
unsigned int pagesz;
|
||||
unsigned int tailsz;
|
||||
unsigned int credits;
|
||||
unsigned int nr_pages;
|
||||
struct page *pages[];
|
||||
};
|
||||
|
|
@ -1073,6 +1090,7 @@ struct cifs_writedata {
|
|||
int result;
|
||||
unsigned int pagesz;
|
||||
unsigned int tailsz;
|
||||
unsigned int credits;
|
||||
unsigned int nr_pages;
|
||||
struct page *pages[];
|
||||
};
|
||||
|
|
@ -1398,6 +1416,7 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param,
|
|||
#define CIFS_OBREAK_OP 0x0100 /* oplock break request */
|
||||
#define CIFS_NEG_OP 0x0200 /* negotiate request */
|
||||
#define CIFS_OP_MASK 0x0380 /* mask request type */
|
||||
#define CIFS_HAS_CREDITS 0x0400 /* already has credits */
|
||||
|
||||
/* Security Flags: indicate type of session setup needed */
|
||||
#define CIFSSEC_MAY_SIGN 0x00001
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ extern struct smb_hdr *cifs_buf_get(void);
|
|||
extern void cifs_buf_release(void *);
|
||||
extern struct smb_hdr *cifs_small_buf_get(void);
|
||||
extern void cifs_small_buf_release(void *);
|
||||
extern void free_rsp_buf(int, void *);
|
||||
extern void cifs_rqst_page_to_kvec(struct smb_rqst *rqst, unsigned int idx,
|
||||
struct kvec *iov);
|
||||
extern int smb_send(struct TCP_Server_Info *, struct smb_hdr *,
|
||||
|
|
@ -89,6 +90,9 @@ extern struct mid_q_entry *cifs_setup_async_request(struct TCP_Server_Info *,
|
|||
struct smb_rqst *);
|
||||
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,
|
||||
unsigned int *credits);
|
||||
extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *,
|
||||
struct kvec *, int /* nvec to send */,
|
||||
int * /* type of buf returned */ , const int flags);
|
||||
|
|
|
|||
|
|
@ -196,10 +196,6 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
|
|||
if (rc)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* FIXME: check if wsize needs updated due to negotiated smb buffer
|
||||
* size shrinking
|
||||
*/
|
||||
atomic_inc(&tconInfoReconnectCount);
|
||||
|
||||
/* tell server Unix caps we support */
|
||||
|
|
@ -1517,7 +1513,6 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|||
return length;
|
||||
|
||||
server->total_read += length;
|
||||
rdata->bytes = length;
|
||||
|
||||
cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
|
||||
server->total_read, buflen, data_len);
|
||||
|
|
@ -1560,12 +1555,18 @@ cifs_readv_callback(struct mid_q_entry *mid)
|
|||
rc);
|
||||
}
|
||||
/* FIXME: should this be counted toward the initiating task? */
|
||||
task_io_account_read(rdata->bytes);
|
||||
cifs_stats_bytes_read(tcon, rdata->bytes);
|
||||
task_io_account_read(rdata->got_bytes);
|
||||
cifs_stats_bytes_read(tcon, rdata->got_bytes);
|
||||
break;
|
||||
case MID_REQUEST_SUBMITTED:
|
||||
case MID_RETRY_NEEDED:
|
||||
rdata->result = -EAGAIN;
|
||||
if (server->sign && rdata->got_bytes)
|
||||
/* reset bytes number since we can not check a sign */
|
||||
rdata->got_bytes = 0;
|
||||
/* FIXME: should this be counted toward the initiating task? */
|
||||
task_io_account_read(rdata->got_bytes);
|
||||
cifs_stats_bytes_read(tcon, rdata->got_bytes);
|
||||
break;
|
||||
default:
|
||||
rdata->result = -EIO;
|
||||
|
|
@ -1734,10 +1735,7 @@ CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
|
|||
|
||||
/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
|
||||
if (*buf) {
|
||||
if (resp_buf_type == CIFS_SMALL_BUFFER)
|
||||
cifs_small_buf_release(iov[0].iov_base);
|
||||
else if (resp_buf_type == CIFS_LARGE_BUFFER)
|
||||
cifs_buf_release(iov[0].iov_base);
|
||||
free_rsp_buf(resp_buf_type, iov[0].iov_base);
|
||||
} else if (resp_buf_type != CIFS_NO_BUFFER) {
|
||||
/* return buffer to caller to free */
|
||||
*buf = iov[0].iov_base;
|
||||
|
|
@ -1899,28 +1897,80 @@ cifs_writedata_release(struct kref *refcount)
|
|||
static void
|
||||
cifs_writev_requeue(struct cifs_writedata *wdata)
|
||||
{
|
||||
int i, rc;
|
||||
int i, rc = 0;
|
||||
struct inode *inode = wdata->cfile->dentry->d_inode;
|
||||
struct TCP_Server_Info *server;
|
||||
unsigned int rest_len;
|
||||
|
||||
for (i = 0; i < wdata->nr_pages; i++) {
|
||||
lock_page(wdata->pages[i]);
|
||||
clear_page_dirty_for_io(wdata->pages[i]);
|
||||
}
|
||||
|
||||
server = tlink_tcon(wdata->cfile->tlink)->ses->server;
|
||||
i = 0;
|
||||
rest_len = wdata->bytes;
|
||||
do {
|
||||
server = tlink_tcon(wdata->cfile->tlink)->ses->server;
|
||||
rc = server->ops->async_writev(wdata, cifs_writedata_release);
|
||||
} while (rc == -EAGAIN);
|
||||
struct cifs_writedata *wdata2;
|
||||
unsigned int j, nr_pages, wsize, tailsz, cur_len;
|
||||
|
||||
for (i = 0; i < wdata->nr_pages; i++) {
|
||||
unlock_page(wdata->pages[i]);
|
||||
if (rc != 0) {
|
||||
SetPageError(wdata->pages[i]);
|
||||
end_page_writeback(wdata->pages[i]);
|
||||
page_cache_release(wdata->pages[i]);
|
||||
wsize = server->ops->wp_retry_size(inode);
|
||||
if (wsize < rest_len) {
|
||||
nr_pages = wsize / PAGE_CACHE_SIZE;
|
||||
if (!nr_pages) {
|
||||
rc = -ENOTSUPP;
|
||||
break;
|
||||
}
|
||||
cur_len = nr_pages * PAGE_CACHE_SIZE;
|
||||
tailsz = PAGE_CACHE_SIZE;
|
||||
} else {
|
||||
nr_pages = DIV_ROUND_UP(rest_len, PAGE_CACHE_SIZE);
|
||||
cur_len = rest_len;
|
||||
tailsz = rest_len - (nr_pages - 1) * PAGE_CACHE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
wdata2 = cifs_writedata_alloc(nr_pages, cifs_writev_complete);
|
||||
if (!wdata2) {
|
||||
rc = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
for (j = 0; j < nr_pages; j++) {
|
||||
wdata2->pages[j] = wdata->pages[i + j];
|
||||
lock_page(wdata2->pages[j]);
|
||||
clear_page_dirty_for_io(wdata2->pages[j]);
|
||||
}
|
||||
|
||||
wdata2->sync_mode = wdata->sync_mode;
|
||||
wdata2->nr_pages = nr_pages;
|
||||
wdata2->offset = page_offset(wdata2->pages[0]);
|
||||
wdata2->pagesz = PAGE_CACHE_SIZE;
|
||||
wdata2->tailsz = tailsz;
|
||||
wdata2->bytes = cur_len;
|
||||
|
||||
wdata2->cfile = find_writable_file(CIFS_I(inode), false);
|
||||
if (!wdata2->cfile) {
|
||||
cifs_dbg(VFS, "No writable handles for inode\n");
|
||||
rc = -EBADF;
|
||||
break;
|
||||
}
|
||||
wdata2->pid = wdata2->cfile->pid;
|
||||
rc = server->ops->async_writev(wdata2, cifs_writedata_release);
|
||||
|
||||
for (j = 0; j < nr_pages; j++) {
|
||||
unlock_page(wdata2->pages[j]);
|
||||
if (rc != 0 && rc != -EAGAIN) {
|
||||
SetPageError(wdata2->pages[j]);
|
||||
end_page_writeback(wdata2->pages[j]);
|
||||
page_cache_release(wdata2->pages[j]);
|
||||
}
|
||||
}
|
||||
|
||||
if (rc) {
|
||||
kref_put(&wdata2->refcount, cifs_writedata_release);
|
||||
if (rc == -EAGAIN)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
rest_len -= cur_len;
|
||||
i += nr_pages;
|
||||
} while (i < wdata->nr_pages);
|
||||
|
||||
mapping_set_error(inode->i_mapping, rc);
|
||||
kref_put(&wdata->refcount, cifs_writedata_release);
|
||||
|
|
@ -2203,10 +2253,7 @@ CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
|
|||
}
|
||||
|
||||
/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
|
||||
if (resp_buf_type == CIFS_SMALL_BUFFER)
|
||||
cifs_small_buf_release(iov[0].iov_base);
|
||||
else if (resp_buf_type == CIFS_LARGE_BUFFER)
|
||||
cifs_buf_release(iov[0].iov_base);
|
||||
free_rsp_buf(resp_buf_type, iov[0].iov_base);
|
||||
|
||||
/* Note: On -EAGAIN error only caller can retry on handle based calls
|
||||
since file handle passed in no longer valid */
|
||||
|
|
@ -2451,10 +2498,7 @@ plk_err_exit:
|
|||
if (pSMB)
|
||||
cifs_small_buf_release(pSMB);
|
||||
|
||||
if (resp_buf_type == CIFS_SMALL_BUFFER)
|
||||
cifs_small_buf_release(iov[0].iov_base);
|
||||
else if (resp_buf_type == CIFS_LARGE_BUFFER)
|
||||
cifs_buf_release(iov[0].iov_base);
|
||||
free_rsp_buf(resp_buf_type, iov[0].iov_base);
|
||||
|
||||
/* Note: On -EAGAIN error only caller can retry on handle based calls
|
||||
since file handle passed in no longer valid */
|
||||
|
|
@ -3838,10 +3882,7 @@ CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
|
|||
}
|
||||
}
|
||||
qsec_out:
|
||||
if (buf_type == CIFS_SMALL_BUFFER)
|
||||
cifs_small_buf_release(iov[0].iov_base);
|
||||
else if (buf_type == CIFS_LARGE_BUFFER)
|
||||
cifs_buf_release(iov[0].iov_base);
|
||||
free_rsp_buf(buf_type, iov[0].iov_base);
|
||||
/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
|
||||
return rc;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -557,7 +557,7 @@ cifs_readv_from_socket(struct TCP_Server_Info *server, struct kvec *iov_orig,
|
|||
try_to_freeze();
|
||||
|
||||
if (server_unresponsive(server)) {
|
||||
total_read = -EAGAIN;
|
||||
total_read = -ECONNABORTED;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -571,7 +571,7 @@ cifs_readv_from_socket(struct TCP_Server_Info *server, struct kvec *iov_orig,
|
|||
break;
|
||||
} else if (server->tcpStatus == CifsNeedReconnect) {
|
||||
cifs_reconnect(server);
|
||||
total_read = -EAGAIN;
|
||||
total_read = -ECONNABORTED;
|
||||
break;
|
||||
} else if (length == -ERESTARTSYS ||
|
||||
length == -EAGAIN ||
|
||||
|
|
@ -588,7 +588,7 @@ cifs_readv_from_socket(struct TCP_Server_Info *server, struct kvec *iov_orig,
|
|||
cifs_dbg(FYI, "Received no data or error: expecting %d\n"
|
||||
"got %d", to_read, length);
|
||||
cifs_reconnect(server);
|
||||
total_read = -EAGAIN;
|
||||
total_read = -ECONNABORTED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -786,7 +786,7 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|||
cifs_dbg(VFS, "SMB response too long (%u bytes)\n", pdu_length);
|
||||
cifs_reconnect(server);
|
||||
wake_up(&server->response_q);
|
||||
return -EAGAIN;
|
||||
return -ECONNABORTED;
|
||||
}
|
||||
|
||||
/* switch to large buffer if too big for a small one */
|
||||
|
|
|
|||
910
fs/cifs/file.c
910
fs/cifs/file.c
File diff suppressed because it is too large
Load diff
|
|
@ -226,6 +226,15 @@ cifs_small_buf_release(void *buf_to_free)
|
|||
return;
|
||||
}
|
||||
|
||||
void
|
||||
free_rsp_buf(int resp_buftype, void *rsp)
|
||||
{
|
||||
if (resp_buftype == CIFS_SMALL_BUFFER)
|
||||
cifs_small_buf_release(rsp);
|
||||
else if (resp_buftype == CIFS_LARGE_BUFFER)
|
||||
cifs_buf_release(rsp);
|
||||
}
|
||||
|
||||
/* NB: MID can not be set if treeCon not passed in, in that
|
||||
case it is responsbility of caller to set the mid */
|
||||
void
|
||||
|
|
@ -414,7 +423,7 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
|
|||
return true;
|
||||
}
|
||||
if (pSMBr->hdr.Status.CifsError) {
|
||||
cifs_dbg(FYI, "notify err 0x%d\n",
|
||||
cifs_dbg(FYI, "notify err 0x%x\n",
|
||||
pSMBr->hdr.Status.CifsError);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -441,7 +450,7 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
|
|||
if (pSMB->hdr.WordCount != 8)
|
||||
return false;
|
||||
|
||||
cifs_dbg(FYI, "oplock type 0x%d level 0x%d\n",
|
||||
cifs_dbg(FYI, "oplock type 0x%x level 0x%x\n",
|
||||
pSMB->LockType, pSMB->OplockLevel);
|
||||
if (!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE))
|
||||
return false;
|
||||
|
|
|
|||
1266
fs/cifs/sess.c
1266
fs/cifs/sess.c
File diff suppressed because it is too large
Load diff
|
|
@ -1009,6 +1009,12 @@ cifs_is_read_op(__u32 oplock)
|
|||
return oplock == OPLOCK_READ;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
cifs_wp_retry_size(struct inode *inode)
|
||||
{
|
||||
return CIFS_SB(inode->i_sb)->wsize;
|
||||
}
|
||||
|
||||
struct smb_version_operations smb1_operations = {
|
||||
.send_cancel = send_nt_cancel,
|
||||
.compare_fids = cifs_compare_fids,
|
||||
|
|
@ -1019,6 +1025,7 @@ struct smb_version_operations smb1_operations = {
|
|||
.set_credits = cifs_set_credits,
|
||||
.get_credits_field = cifs_get_credits_field,
|
||||
.get_credits = cifs_get_credits,
|
||||
.wait_mtu_credits = cifs_wait_mtu_credits,
|
||||
.get_next_mid = cifs_get_next_mid,
|
||||
.read_data_offset = cifs_read_data_offset,
|
||||
.read_data_length = cifs_read_data_length,
|
||||
|
|
@ -1078,6 +1085,7 @@ struct smb_version_operations smb1_operations = {
|
|||
.query_mf_symlink = cifs_query_mf_symlink,
|
||||
.create_mf_symlink = cifs_create_mf_symlink,
|
||||
.is_read_op = cifs_is_read_op,
|
||||
.wp_retry_size = cifs_wp_retry_size,
|
||||
#ifdef CONFIG_CIFS_XATTR
|
||||
.query_all_EAs = CIFSSMBQAllEAs,
|
||||
.set_EA = CIFSSMBSetEA,
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
case SMB2_OP_SET_EOF:
|
||||
tmprc = SMB2_set_eof(xid, tcon, fid.persistent_fid,
|
||||
fid.volatile_fid, current->tgid,
|
||||
(__le64 *)data);
|
||||
(__le64 *)data, false);
|
||||
break;
|
||||
case SMB2_OP_SET_INFO:
|
||||
tmprc = SMB2_set_info(xid, tcon, fid.persistent_fid,
|
||||
|
|
|
|||
|
|
@ -605,7 +605,7 @@ static const struct status_to_posix_error smb2_error_map_table[] = {
|
|||
{STATUS_MAPPED_FILE_SIZE_ZERO, -EIO, "STATUS_MAPPED_FILE_SIZE_ZERO"},
|
||||
{STATUS_TOO_MANY_OPENED_FILES, -EMFILE, "STATUS_TOO_MANY_OPENED_FILES"},
|
||||
{STATUS_CANCELLED, -EIO, "STATUS_CANCELLED"},
|
||||
{STATUS_CANNOT_DELETE, -EIO, "STATUS_CANNOT_DELETE"},
|
||||
{STATUS_CANNOT_DELETE, -EACCES, "STATUS_CANNOT_DELETE"},
|
||||
{STATUS_INVALID_COMPUTER_NAME, -EIO, "STATUS_INVALID_COMPUTER_NAME"},
|
||||
{STATUS_FILE_DELETED, -EIO, "STATUS_FILE_DELETED"},
|
||||
{STATUS_SPECIAL_ACCOUNT, -EIO, "STATUS_SPECIAL_ACCOUNT"},
|
||||
|
|
|
|||
|
|
@ -437,7 +437,7 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp,
|
|||
continue;
|
||||
|
||||
cifs_dbg(FYI, "found in the open list\n");
|
||||
cifs_dbg(FYI, "lease key match, lease break 0x%d\n",
|
||||
cifs_dbg(FYI, "lease key match, lease break 0x%x\n",
|
||||
le32_to_cpu(rsp->NewLeaseState));
|
||||
|
||||
server->ops->set_oplock_level(cinode, lease_state, 0, NULL);
|
||||
|
|
@ -467,7 +467,7 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp,
|
|||
}
|
||||
|
||||
cifs_dbg(FYI, "found in the pending open list\n");
|
||||
cifs_dbg(FYI, "lease key match, lease break 0x%d\n",
|
||||
cifs_dbg(FYI, "lease key match, lease break 0x%x\n",
|
||||
le32_to_cpu(rsp->NewLeaseState));
|
||||
|
||||
open->oplock = lease_state;
|
||||
|
|
@ -546,7 +546,7 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
|
|||
return false;
|
||||
}
|
||||
|
||||
cifs_dbg(FYI, "oplock level 0x%d\n", rsp->OplockLevel);
|
||||
cifs_dbg(FYI, "oplock level 0x%x\n", rsp->OplockLevel);
|
||||
|
||||
/* look up tcon based on tid & uid */
|
||||
spin_lock(&cifs_tcp_ses_lock);
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/vfs.h>
|
||||
#include <linux/falloc.h>
|
||||
#include "cifsglob.h"
|
||||
#include "smb2pdu.h"
|
||||
#include "smb2proto.h"
|
||||
|
|
@ -112,6 +113,53 @@ smb2_get_credits(struct mid_q_entry *mid)
|
|||
return le16_to_cpu(((struct smb2_hdr *)mid->resp_buf)->CreditRequest);
|
||||
}
|
||||
|
||||
static int
|
||||
smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size,
|
||||
unsigned int *num, unsigned int *credits)
|
||||
{
|
||||
int rc = 0;
|
||||
unsigned int scredits;
|
||||
|
||||
spin_lock(&server->req_lock);
|
||||
while (1) {
|
||||
if (server->credits <= 0) {
|
||||
spin_unlock(&server->req_lock);
|
||||
cifs_num_waiters_inc(server);
|
||||
rc = wait_event_killable(server->request_q,
|
||||
has_credits(server, &server->credits));
|
||||
cifs_num_waiters_dec(server);
|
||||
if (rc)
|
||||
return rc;
|
||||
spin_lock(&server->req_lock);
|
||||
} else {
|
||||
if (server->tcpStatus == CifsExiting) {
|
||||
spin_unlock(&server->req_lock);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
scredits = server->credits;
|
||||
/* can deadlock with reopen */
|
||||
if (scredits == 1) {
|
||||
*num = SMB2_MAX_BUFFER_SIZE;
|
||||
*credits = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* leave one credit for a possible reopen */
|
||||
scredits--;
|
||||
*num = min_t(unsigned int, size,
|
||||
scredits * SMB2_MAX_BUFFER_SIZE);
|
||||
|
||||
*credits = DIV_ROUND_UP(*num, SMB2_MAX_BUFFER_SIZE);
|
||||
server->credits -= *credits;
|
||||
server->in_flight++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock(&server->req_lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static __u64
|
||||
smb2_get_next_mid(struct TCP_Server_Info *server)
|
||||
{
|
||||
|
|
@ -182,8 +230,9 @@ smb2_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
|
|||
/* start with specified wsize, or default */
|
||||
wsize = volume_info->wsize ? volume_info->wsize : CIFS_DEFAULT_IOSIZE;
|
||||
wsize = min_t(unsigned int, wsize, server->max_write);
|
||||
/* set it to the maximum buffer size value we can send with 1 credit */
|
||||
wsize = min_t(unsigned int, wsize, SMB2_MAX_BUFFER_SIZE);
|
||||
|
||||
if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
|
||||
wsize = min_t(unsigned int, wsize, SMB2_MAX_BUFFER_SIZE);
|
||||
|
||||
return wsize;
|
||||
}
|
||||
|
|
@ -197,8 +246,9 @@ smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
|
|||
/* start with specified rsize, or default */
|
||||
rsize = volume_info->rsize ? volume_info->rsize : CIFS_DEFAULT_IOSIZE;
|
||||
rsize = min_t(unsigned int, rsize, server->max_read);
|
||||
/* set it to the maximum buffer size value we can send with 1 credit */
|
||||
rsize = min_t(unsigned int, rsize, SMB2_MAX_BUFFER_SIZE);
|
||||
|
||||
if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
|
||||
rsize = min_t(unsigned int, rsize, SMB2_MAX_BUFFER_SIZE);
|
||||
|
||||
return rsize;
|
||||
}
|
||||
|
|
@ -687,7 +737,7 @@ smb2_set_file_size(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
{
|
||||
__le64 eof = cpu_to_le64(size);
|
||||
return SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid,
|
||||
cfile->fid.volatile_fid, cfile->pid, &eof);
|
||||
cfile->fid.volatile_fid, cfile->pid, &eof, false);
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -1104,6 +1154,13 @@ smb3_parse_lease_buf(void *buf, unsigned int *epoch)
|
|||
return le32_to_cpu(lc->lcontext.LeaseState);
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
smb2_wp_retry_size(struct inode *inode)
|
||||
{
|
||||
return min_t(unsigned int, CIFS_SB(inode->i_sb)->wsize,
|
||||
SMB2_MAX_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
struct smb_version_operations smb20_operations = {
|
||||
.compare_fids = smb2_compare_fids,
|
||||
.setup_request = smb2_setup_request,
|
||||
|
|
@ -1113,6 +1170,7 @@ struct smb_version_operations smb20_operations = {
|
|||
.set_credits = smb2_set_credits,
|
||||
.get_credits_field = smb2_get_credits_field,
|
||||
.get_credits = smb2_get_credits,
|
||||
.wait_mtu_credits = cifs_wait_mtu_credits,
|
||||
.get_next_mid = smb2_get_next_mid,
|
||||
.read_data_offset = smb2_read_data_offset,
|
||||
.read_data_length = smb2_read_data_length,
|
||||
|
|
@ -1177,6 +1235,7 @@ struct smb_version_operations smb20_operations = {
|
|||
.create_lease_buf = smb2_create_lease_buf,
|
||||
.parse_lease_buf = smb2_parse_lease_buf,
|
||||
.clone_range = smb2_clone_range,
|
||||
.wp_retry_size = smb2_wp_retry_size,
|
||||
};
|
||||
|
||||
struct smb_version_operations smb21_operations = {
|
||||
|
|
@ -1188,6 +1247,7 @@ struct smb_version_operations smb21_operations = {
|
|||
.set_credits = smb2_set_credits,
|
||||
.get_credits_field = smb2_get_credits_field,
|
||||
.get_credits = smb2_get_credits,
|
||||
.wait_mtu_credits = smb2_wait_mtu_credits,
|
||||
.get_next_mid = smb2_get_next_mid,
|
||||
.read_data_offset = smb2_read_data_offset,
|
||||
.read_data_length = smb2_read_data_length,
|
||||
|
|
@ -1252,6 +1312,7 @@ struct smb_version_operations smb21_operations = {
|
|||
.create_lease_buf = smb2_create_lease_buf,
|
||||
.parse_lease_buf = smb2_parse_lease_buf,
|
||||
.clone_range = smb2_clone_range,
|
||||
.wp_retry_size = smb2_wp_retry_size,
|
||||
};
|
||||
|
||||
struct smb_version_operations smb30_operations = {
|
||||
|
|
@ -1263,6 +1324,7 @@ struct smb_version_operations smb30_operations = {
|
|||
.set_credits = smb2_set_credits,
|
||||
.get_credits_field = smb2_get_credits_field,
|
||||
.get_credits = smb2_get_credits,
|
||||
.wait_mtu_credits = smb2_wait_mtu_credits,
|
||||
.get_next_mid = smb2_get_next_mid,
|
||||
.read_data_offset = smb2_read_data_offset,
|
||||
.read_data_length = smb2_read_data_length,
|
||||
|
|
@ -1330,6 +1392,7 @@ struct smb_version_operations smb30_operations = {
|
|||
.parse_lease_buf = smb3_parse_lease_buf,
|
||||
.clone_range = smb2_clone_range,
|
||||
.validate_negotiate = smb3_validate_negotiate,
|
||||
.wp_retry_size = smb2_wp_retry_size,
|
||||
};
|
||||
|
||||
struct smb_version_values smb20_values = {
|
||||
|
|
|
|||
|
|
@ -108,7 +108,6 @@ smb2_hdr_assemble(struct smb2_hdr *hdr, __le16 smb2_cmd /* command */ ,
|
|||
if (!tcon)
|
||||
goto out;
|
||||
|
||||
/* BB FIXME when we do write > 64K add +1 for every 64K in req or rsp */
|
||||
/* GLOBAL_CAP_LARGE_MTU will only be set if dialect > SMB2.02 */
|
||||
/* See sections 2.2.4 and 3.2.4.1.5 of MS-SMB2 */
|
||||
if ((tcon->ses) &&
|
||||
|
|
@ -245,10 +244,6 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
|
|||
if (rc)
|
||||
goto out;
|
||||
atomic_inc(&tconInfoReconnectCount);
|
||||
/*
|
||||
* BB FIXME add code to check if wsize needs update due to negotiated
|
||||
* smb buffer size shrinking.
|
||||
*/
|
||||
out:
|
||||
/*
|
||||
* Check if handle based operation so we know whether we can continue
|
||||
|
|
@ -309,16 +304,6 @@ small_smb2_init(__le16 smb2_command, struct cifs_tcon *tcon,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
free_rsp_buf(int resp_buftype, void *rsp)
|
||||
{
|
||||
if (resp_buftype == CIFS_SMALL_BUFFER)
|
||||
cifs_small_buf_release(rsp);
|
||||
else if (resp_buftype == CIFS_LARGE_BUFFER)
|
||||
cifs_buf_release(rsp);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* SMB2 Worker functions follow:
|
||||
|
|
@ -1738,12 +1723,18 @@ smb2_readv_callback(struct mid_q_entry *mid)
|
|||
rc);
|
||||
}
|
||||
/* FIXME: should this be counted toward the initiating task? */
|
||||
task_io_account_read(rdata->bytes);
|
||||
cifs_stats_bytes_read(tcon, rdata->bytes);
|
||||
task_io_account_read(rdata->got_bytes);
|
||||
cifs_stats_bytes_read(tcon, rdata->got_bytes);
|
||||
break;
|
||||
case MID_REQUEST_SUBMITTED:
|
||||
case MID_RETRY_NEEDED:
|
||||
rdata->result = -EAGAIN;
|
||||
if (server->sign && rdata->got_bytes)
|
||||
/* reset bytes number since we can not check a sign */
|
||||
rdata->got_bytes = 0;
|
||||
/* FIXME: should this be counted toward the initiating task? */
|
||||
task_io_account_read(rdata->got_bytes);
|
||||
cifs_stats_bytes_read(tcon, rdata->got_bytes);
|
||||
break;
|
||||
default:
|
||||
if (rdata->result != -ENODATA)
|
||||
|
|
@ -1762,11 +1753,12 @@ smb2_readv_callback(struct mid_q_entry *mid)
|
|||
int
|
||||
smb2_async_readv(struct cifs_readdata *rdata)
|
||||
{
|
||||
int rc;
|
||||
int rc, flags = 0;
|
||||
struct smb2_hdr *buf;
|
||||
struct cifs_io_parms io_parms;
|
||||
struct smb_rqst rqst = { .rq_iov = &rdata->iov,
|
||||
.rq_nvec = 1 };
|
||||
struct TCP_Server_Info *server;
|
||||
|
||||
cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
|
||||
__func__, rdata->offset, rdata->bytes);
|
||||
|
|
@ -1777,18 +1769,41 @@ smb2_async_readv(struct cifs_readdata *rdata)
|
|||
io_parms.persistent_fid = rdata->cfile->fid.persistent_fid;
|
||||
io_parms.volatile_fid = rdata->cfile->fid.volatile_fid;
|
||||
io_parms.pid = rdata->pid;
|
||||
|
||||
server = io_parms.tcon->ses->server;
|
||||
|
||||
rc = smb2_new_read_req(&rdata->iov, &io_parms, 0, 0);
|
||||
if (rc)
|
||||
if (rc) {
|
||||
if (rc == -EAGAIN && rdata->credits) {
|
||||
/* credits was reset by reconnect */
|
||||
rdata->credits = 0;
|
||||
/* reduce in_flight value since we won't send the req */
|
||||
spin_lock(&server->req_lock);
|
||||
server->in_flight--;
|
||||
spin_unlock(&server->req_lock);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
buf = (struct smb2_hdr *)rdata->iov.iov_base;
|
||||
/* 4 for rfc1002 length field */
|
||||
rdata->iov.iov_len = get_rfc1002_length(rdata->iov.iov_base) + 4;
|
||||
|
||||
if (rdata->credits) {
|
||||
buf->CreditCharge = cpu_to_le16(DIV_ROUND_UP(rdata->bytes,
|
||||
SMB2_MAX_BUFFER_SIZE));
|
||||
spin_lock(&server->req_lock);
|
||||
server->credits += rdata->credits -
|
||||
le16_to_cpu(buf->CreditCharge);
|
||||
spin_unlock(&server->req_lock);
|
||||
wake_up(&server->request_q);
|
||||
flags = CIFS_HAS_CREDITS;
|
||||
}
|
||||
|
||||
kref_get(&rdata->refcount);
|
||||
rc = cifs_call_async(io_parms.tcon->ses->server, &rqst,
|
||||
cifs_readv_receive, smb2_readv_callback,
|
||||
rdata, 0);
|
||||
rdata, flags);
|
||||
if (rc) {
|
||||
kref_put(&rdata->refcount, cifs_readdata_release);
|
||||
cifs_stats_fail_inc(io_parms.tcon, SMB2_READ_HE);
|
||||
|
|
@ -1906,15 +1921,25 @@ int
|
|||
smb2_async_writev(struct cifs_writedata *wdata,
|
||||
void (*release)(struct kref *kref))
|
||||
{
|
||||
int rc = -EACCES;
|
||||
int rc = -EACCES, flags = 0;
|
||||
struct smb2_write_req *req = NULL;
|
||||
struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
|
||||
struct TCP_Server_Info *server = tcon->ses->server;
|
||||
struct kvec iov;
|
||||
struct smb_rqst rqst;
|
||||
|
||||
rc = small_smb2_init(SMB2_WRITE, tcon, (void **) &req);
|
||||
if (rc)
|
||||
if (rc) {
|
||||
if (rc == -EAGAIN && wdata->credits) {
|
||||
/* credits was reset by reconnect */
|
||||
wdata->credits = 0;
|
||||
/* reduce in_flight value since we won't send the req */
|
||||
spin_lock(&server->req_lock);
|
||||
server->in_flight--;
|
||||
spin_unlock(&server->req_lock);
|
||||
}
|
||||
goto async_writev_out;
|
||||
}
|
||||
|
||||
req->hdr.ProcessId = cpu_to_le32(wdata->cfile->pid);
|
||||
|
||||
|
|
@ -1947,9 +1972,20 @@ smb2_async_writev(struct cifs_writedata *wdata,
|
|||
|
||||
inc_rfc1001_len(&req->hdr, wdata->bytes - 1 /* Buffer */);
|
||||
|
||||
if (wdata->credits) {
|
||||
req->hdr.CreditCharge = cpu_to_le16(DIV_ROUND_UP(wdata->bytes,
|
||||
SMB2_MAX_BUFFER_SIZE));
|
||||
spin_lock(&server->req_lock);
|
||||
server->credits += wdata->credits -
|
||||
le16_to_cpu(req->hdr.CreditCharge);
|
||||
spin_unlock(&server->req_lock);
|
||||
wake_up(&server->request_q);
|
||||
flags = CIFS_HAS_CREDITS;
|
||||
}
|
||||
|
||||
kref_get(&wdata->refcount);
|
||||
rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
|
||||
smb2_writev_callback, wdata, 0);
|
||||
rc = cifs_call_async(server, &rqst, NULL, smb2_writev_callback, wdata,
|
||||
flags);
|
||||
|
||||
if (rc) {
|
||||
kref_put(&wdata->refcount, release);
|
||||
|
|
@ -2325,7 +2361,7 @@ SMB2_set_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
|
||||
int
|
||||
SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
|
||||
u64 volatile_fid, u32 pid, __le64 *eof)
|
||||
u64 volatile_fid, u32 pid, __le64 *eof, bool is_falloc)
|
||||
{
|
||||
struct smb2_file_eof_info info;
|
||||
void *data;
|
||||
|
|
@ -2336,8 +2372,12 @@ SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
|
|||
data = &info;
|
||||
size = sizeof(struct smb2_file_eof_info);
|
||||
|
||||
return send_set_info(xid, tcon, persistent_fid, volatile_fid, pid,
|
||||
FILE_END_OF_FILE_INFORMATION, 1, &data, &size);
|
||||
if (is_falloc)
|
||||
return send_set_info(xid, tcon, persistent_fid, volatile_fid,
|
||||
pid, FILE_ALLOCATION_INFORMATION, 1, &data, &size);
|
||||
else
|
||||
return send_set_info(xid, tcon, persistent_fid, volatile_fid,
|
||||
pid, FILE_END_OF_FILE_INFORMATION, 1, &data, &size);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ extern int SMB2_set_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
__le16 *target_file);
|
||||
extern int SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid, u32 pid,
|
||||
__le64 *eof);
|
||||
__le64 *eof, bool is_fallocate);
|
||||
extern int SMB2_set_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid,
|
||||
FILE_BASIC_INFO *buf);
|
||||
|
|
|
|||
|
|
@ -466,7 +466,12 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
|
|||
static inline void
|
||||
smb2_seq_num_into_buf(struct TCP_Server_Info *server, struct smb2_hdr *hdr)
|
||||
{
|
||||
unsigned int i, num = le16_to_cpu(hdr->CreditCharge);
|
||||
|
||||
hdr->MessageId = get_next_mid64(server);
|
||||
/* skip message numbers according to CreditCharge field */
|
||||
for (i = 1; i < num; i++)
|
||||
get_next_mid(server);
|
||||
}
|
||||
|
||||
static struct mid_q_entry *
|
||||
|
|
|
|||
|
|
@ -448,6 +448,15 @@ wait_for_free_request(struct TCP_Server_Info *server, const int timeout,
|
|||
return wait_for_free_credits(server, timeout, val);
|
||||
}
|
||||
|
||||
int
|
||||
cifs_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size,
|
||||
unsigned int *num, unsigned int *credits)
|
||||
{
|
||||
*num = size;
|
||||
*credits = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
|
||||
struct mid_q_entry **ppmidQ)
|
||||
{
|
||||
|
|
@ -531,20 +540,23 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
|
|||
{
|
||||
int rc, timeout, optype;
|
||||
struct mid_q_entry *mid;
|
||||
unsigned int credits = 0;
|
||||
|
||||
timeout = flags & CIFS_TIMEOUT_MASK;
|
||||
optype = flags & CIFS_OP_MASK;
|
||||
|
||||
rc = wait_for_free_request(server, timeout, optype);
|
||||
if (rc)
|
||||
return rc;
|
||||
if ((flags & CIFS_HAS_CREDITS) == 0) {
|
||||
rc = wait_for_free_request(server, timeout, optype);
|
||||
if (rc)
|
||||
return rc;
|
||||
credits = 1;
|
||||
}
|
||||
|
||||
mutex_lock(&server->srv_mutex);
|
||||
mid = server->ops->setup_async_request(server, rqst);
|
||||
if (IS_ERR(mid)) {
|
||||
mutex_unlock(&server->srv_mutex);
|
||||
add_credits(server, 1, optype);
|
||||
wake_up(&server->request_q);
|
||||
add_credits_and_wake_if(server, credits, optype);
|
||||
return PTR_ERR(mid);
|
||||
}
|
||||
|
||||
|
|
@ -572,8 +584,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
|
|||
return 0;
|
||||
|
||||
cifs_delete_mid(mid);
|
||||
add_credits(server, 1, optype);
|
||||
wake_up(&server->request_q);
|
||||
add_credits_and_wake_if(server, credits, optype);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue