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
|
@ -40,6 +40,7 @@ Gunter Kukkukk (testing and suggestions for support of old servers)
|
|||
Igor Mammedov (DFS support)
|
||||
Jeff Layton (many, many fixes, as well as great work on the cifs Kerberos code)
|
||||
Scott Lovenberg
|
||||
Pavel Shilovsky (for great work adding SMB2 support, and various SMB3 features)
|
||||
|
||||
Test case and Bug Report contributors
|
||||
-------------------------------------
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Version 1.53 May 20, 2008
|
||||
Version 2.03 August 1, 2014
|
||||
|
||||
A Partial List of Missing Features
|
||||
==================================
|
||||
|
@ -7,63 +7,49 @@ Contributions are welcome. There are plenty of opportunities
|
|||
for visible, important contributions to this module. Here
|
||||
is a partial list of the known problems and missing features:
|
||||
|
||||
a) Support for SecurityDescriptors(Windows/CIFS ACLs) for chmod/chgrp/chown
|
||||
so that these operations can be supported to Windows servers
|
||||
a) SMB3 (and SMB3.02) missing optional features:
|
||||
- RDMA
|
||||
- multichannel (started)
|
||||
- directory leases (improved metadata caching)
|
||||
- T10 copy offload (copy chunk is only mechanism supported)
|
||||
- encrypted shares
|
||||
|
||||
b) Mapping POSIX ACLs (and eventually NFSv4 ACLs) to CIFS
|
||||
SecurityDescriptors
|
||||
b) improved sparse file support
|
||||
|
||||
c) Better pam/winbind integration (e.g. to handle uid mapping
|
||||
better)
|
||||
|
||||
d) Cleanup now unneeded SessSetup code in
|
||||
fs/cifs/connect.c and add back in NTLMSSP code if any servers
|
||||
need it
|
||||
|
||||
e) fix NTLMv2 signing when two mounts with different users to same
|
||||
server.
|
||||
|
||||
f) Directory entry caching relies on a 1 second timer, rather than
|
||||
c) Directory entry caching relies on a 1 second timer, rather than
|
||||
using FindNotify or equivalent. - (started)
|
||||
|
||||
g) quota support (needs minor kernel change since quota calls
|
||||
d) quota support (needs minor kernel change since quota calls
|
||||
to make it to network filesystems or deviceless filesystems)
|
||||
|
||||
h) investigate sync behavior (including syncpage) and check
|
||||
for proper behavior of intr/nointr
|
||||
|
||||
i) improve support for very old servers (OS/2 and Win9x for example)
|
||||
e) improve support for very old servers (OS/2 and Win9x for example)
|
||||
Including support for changing the time remotely (utimes command).
|
||||
|
||||
j) hook lower into the sockets api (as NFS/SunRPC does) to avoid the
|
||||
f) hook lower into the sockets api (as NFS/SunRPC does) to avoid the
|
||||
extra copy in/out of the socket buffers in some cases.
|
||||
|
||||
k) Better optimize open (and pathbased setfilesize) to reduce the
|
||||
g) Better optimize open (and pathbased setfilesize) to reduce the
|
||||
oplock breaks coming from windows srv. Piggyback identical file
|
||||
opens on top of each other by incrementing reference count rather
|
||||
than resending (helps reduce server resource utilization and avoid
|
||||
spurious oplock breaks).
|
||||
|
||||
l) Improve performance of readpages by sending more than one read
|
||||
at a time when 8 pages or more are requested. In conjuntion
|
||||
add support for async_cifs_readpages.
|
||||
|
||||
m) Add support for storing symlink info to Windows servers
|
||||
h) Add support for storing symlink info to Windows servers
|
||||
in the Extended Attribute format their SFU clients would recognize.
|
||||
|
||||
n) Finish fcntl D_NOTIFY support so kde and gnome file list windows
|
||||
i) Finish inotify support so kde and gnome file list windows
|
||||
will autorefresh (partially complete by Asser). Needs minor kernel
|
||||
vfs change to support removing D_NOTIFY on a file.
|
||||
|
||||
o) Add GUI tool to configure /proc/fs/cifs settings and for display of
|
||||
j) Add GUI tool to configure /proc/fs/cifs settings and for display of
|
||||
the CIFS statistics (started)
|
||||
|
||||
p) implement support for security and trusted categories of xattrs
|
||||
k) implement support for security and trusted categories of xattrs
|
||||
(requires minor protocol extension) to enable better support for SELINUX
|
||||
|
||||
q) Implement O_DIRECT flag on open (already supported on mount)
|
||||
l) Implement O_DIRECT flag on open (already supported on mount)
|
||||
|
||||
r) Create UID mapping facility so server UIDs can be mapped on a per
|
||||
m) Create UID mapping facility so server UIDs can be mapped on a per
|
||||
mount or a per server basis to client UIDs or nobody if no mapping
|
||||
exists. This is helpful when Unix extensions are negotiated to
|
||||
allow better permission checking when UIDs differ on the server
|
||||
|
@ -71,28 +57,29 @@ and client. Add new protocol request to the CIFS protocol
|
|||
standard for asking the server for the corresponding name of a
|
||||
particular uid.
|
||||
|
||||
s) Add support for CIFS Unix and also the newer POSIX extensions to the
|
||||
server side for Samba 4.
|
||||
n) DOS attrs - returned as pseudo-xattr in Samba format (check VFAT and NTFS for this too)
|
||||
|
||||
t) In support for OS/2 (LANMAN 1.2 and LANMAN2.1 based SMB servers)
|
||||
need to add ability to set time to server (utimes command)
|
||||
o) mount check for unmatched uids
|
||||
|
||||
u) DOS attrs - returned as pseudo-xattr in Samba format (check VFAT and NTFS for this too)
|
||||
p) Add support for new vfs entry point for fallocate
|
||||
|
||||
v) mount check for unmatched uids
|
||||
q) Add tools to take advantage of cifs/smb3 specific ioctls and features
|
||||
such as "CopyChunk" (fast server side file copy)
|
||||
|
||||
w) Add support for new vfs entry point for fallocate
|
||||
r) encrypted file support
|
||||
|
||||
x) Fix Samba 3 server to handle Linux kernel aio so dbench with lots of
|
||||
processes can proceed better in parallel (on the server)
|
||||
s) improved stats gathering, tools (perhaps integration with nfsometer?)
|
||||
|
||||
y) Fix Samba 3 to handle reads/writes over 127K (and remove the cifs mount
|
||||
restriction of wsize max being 127K)
|
||||
t) allow setting more NTFS/SMB3 file attributes remotely (currently limited to compressed
|
||||
file attribute via chflags)
|
||||
|
||||
KNOWN BUGS (updated April 24, 2007)
|
||||
u) mount helper GUI (to simplify the various configuration options on mount)
|
||||
|
||||
|
||||
KNOWN BUGS
|
||||
====================================
|
||||
See http://bugzilla.samba.org - search on product "CifsVFS" for
|
||||
current bug list.
|
||||
current bug list. Also check http://bugzilla.kernel.org (Product = File System, Component = CIFS)
|
||||
|
||||
1) existing symbolic links (Windows reparse points) are recognized but
|
||||
can not be created remotely. They are implemented for Samba and those that
|
||||
|
@ -100,30 +87,18 @@ support the CIFS Unix extensions, although earlier versions of Samba
|
|||
overly restrict the pathnames.
|
||||
2) follow_link and readdir code does not follow dfs junctions
|
||||
but recognizes them
|
||||
3) create of new files to FAT partitions on Windows servers can
|
||||
succeed but still return access denied (appears to be Windows
|
||||
server not cifs client problem) and has not been reproduced recently.
|
||||
NTFS partitions do not have this problem.
|
||||
4) Unix/POSIX capabilities are reset after reconnection, and affect
|
||||
a few fields in the tree connection but we do do not know which
|
||||
superblocks to apply these changes to. We should probably walk
|
||||
the list of superblocks to set these. Also need to check the
|
||||
flags on the second mount to the same share, and see if we
|
||||
can do the same trick that NFS does to remount duplicate shares.
|
||||
|
||||
Misc testing to do
|
||||
==================
|
||||
1) check out max path names and max path name components against various server
|
||||
types. Try nested symlinks (8 deep). Return max path name in stat -f information
|
||||
|
||||
2) Modify file portion of ltp so it can run against a mounted network
|
||||
share and run it against cifs vfs in automated fashion.
|
||||
2) Improve xfstest's cifs enablement and adapt xfstests where needed to test
|
||||
cifs better
|
||||
|
||||
3) Additional performance testing and optimization using iozone and similar -
|
||||
there are some easy changes that can be done to parallelize sequential writes,
|
||||
and when signing is disabled to request larger read sizes (larger than
|
||||
negotiated size) and send larger write sizes to modern servers.
|
||||
|
||||
4) More exhaustively test against less common servers. More testing
|
||||
against Windows 9x, Windows ME servers.
|
||||
|
||||
4) More exhaustively test against less common servers
|
||||
|
|
|
@ -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 New Issue