|
@@ -87,7 +87,6 @@ static struct {
|
|
|
#endif /* CIFS_POSIX */
|
|
|
|
|
|
/* Forward declarations */
|
|
|
-static void cifs_readv_complete(struct work_struct *work);
|
|
|
|
|
|
/* Mark as invalid, all open files on tree connections since they
|
|
|
were closed when session to server was lost */
|
|
@@ -461,7 +460,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
|
|
|
server->maxReq = min_t(unsigned int,
|
|
|
le16_to_cpu(rsp->MaxMpxCount),
|
|
|
cifs_max_pending);
|
|
|
- cifs_set_credits(server, server->maxReq);
|
|
|
+ set_credits(server, server->maxReq);
|
|
|
server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
|
|
|
server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
|
|
|
/* even though we do not use raw we might as well set this
|
|
@@ -569,7 +568,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
|
|
|
little endian */
|
|
|
server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
|
|
|
cifs_max_pending);
|
|
|
- cifs_set_credits(server, server->maxReq);
|
|
|
+ set_credits(server, server->maxReq);
|
|
|
/* probably no need to store and check maxvcs */
|
|
|
server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
|
|
|
server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
|
|
@@ -721,7 +720,7 @@ cifs_echo_callback(struct mid_q_entry *mid)
|
|
|
struct TCP_Server_Info *server = mid->callback_data;
|
|
|
|
|
|
DeleteMidQEntry(mid);
|
|
|
- cifs_add_credits(server, 1);
|
|
|
+ add_credits(server, 1);
|
|
|
}
|
|
|
|
|
|
int
|
|
@@ -1385,28 +1384,6 @@ openRetry:
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
-struct cifs_readdata *
|
|
|
-cifs_readdata_alloc(unsigned int nr_pages)
|
|
|
-{
|
|
|
- struct cifs_readdata *rdata;
|
|
|
-
|
|
|
- /* readdata + 1 kvec for each page */
|
|
|
- rdata = kzalloc(sizeof(*rdata) +
|
|
|
- sizeof(struct kvec) * nr_pages, GFP_KERNEL);
|
|
|
- if (rdata != NULL) {
|
|
|
- INIT_WORK(&rdata->work, cifs_readv_complete);
|
|
|
- INIT_LIST_HEAD(&rdata->pages);
|
|
|
- }
|
|
|
- return rdata;
|
|
|
-}
|
|
|
-
|
|
|
-void
|
|
|
-cifs_readdata_free(struct cifs_readdata *rdata)
|
|
|
-{
|
|
|
- cifsFileInfo_put(rdata->cfile);
|
|
|
- kfree(rdata);
|
|
|
-}
|
|
|
-
|
|
|
/*
|
|
|
* Discard any remaining data in the current SMB. To do this, we borrow the
|
|
|
* current bigbuf.
|
|
@@ -1423,7 +1400,7 @@ cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|
|
|
|
|
length = cifs_read_from_socket(server, server->bigbuf,
|
|
|
min_t(unsigned int, remaining,
|
|
|
- CIFSMaxBufSize + max_header_size()));
|
|
|
+ CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
|
|
|
if (length < 0)
|
|
|
return length;
|
|
|
server->total_read += length;
|
|
@@ -1434,38 +1411,14 @@ cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static inline size_t
|
|
|
-read_rsp_size(void)
|
|
|
-{
|
|
|
- return sizeof(READ_RSP);
|
|
|
-}
|
|
|
-
|
|
|
-static inline unsigned int
|
|
|
-read_data_offset(char *buf)
|
|
|
-{
|
|
|
- READ_RSP *rsp = (READ_RSP *)buf;
|
|
|
- return le16_to_cpu(rsp->DataOffset);
|
|
|
-}
|
|
|
-
|
|
|
-static inline unsigned int
|
|
|
-read_data_length(char *buf)
|
|
|
-{
|
|
|
- READ_RSP *rsp = (READ_RSP *)buf;
|
|
|
- return (le16_to_cpu(rsp->DataLengthHigh) << 16) +
|
|
|
- le16_to_cpu(rsp->DataLength);
|
|
|
-}
|
|
|
-
|
|
|
static int
|
|
|
cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|
|
{
|
|
|
int length, len;
|
|
|
- unsigned int data_offset, remaining, data_len;
|
|
|
+ unsigned int data_offset, data_len;
|
|
|
struct cifs_readdata *rdata = mid->callback_data;
|
|
|
char *buf = server->smallbuf;
|
|
|
unsigned int buflen = get_rfc1002_length(buf) + 4;
|
|
|
- u64 eof;
|
|
|
- pgoff_t eof_index;
|
|
|
- struct page *page, *tpage;
|
|
|
|
|
|
cFYI(1, "%s: mid=%llu offset=%llu bytes=%u", __func__,
|
|
|
mid->mid, rdata->offset, rdata->bytes);
|
|
@@ -1475,9 +1428,10 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|
|
* can if there's not enough data. At this point, we've read down to
|
|
|
* the Mid.
|
|
|
*/
|
|
|
- len = min_t(unsigned int, buflen, read_rsp_size()) - header_size() + 1;
|
|
|
+ len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
|
|
|
+ HEADER_SIZE(server) + 1;
|
|
|
|
|
|
- rdata->iov[0].iov_base = buf + header_size() - 1;
|
|
|
+ rdata->iov[0].iov_base = buf + HEADER_SIZE(server) - 1;
|
|
|
rdata->iov[0].iov_len = len;
|
|
|
|
|
|
length = cifs_readv_from_socket(server, rdata->iov, 1, len);
|
|
@@ -1486,7 +1440,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|
|
server->total_read += length;
|
|
|
|
|
|
/* Was the SMB read successful? */
|
|
|
- rdata->result = map_smb_to_linux_error(buf, false);
|
|
|
+ rdata->result = server->ops->map_error(buf, false);
|
|
|
if (rdata->result != 0) {
|
|
|
cFYI(1, "%s: server returned error %d", __func__,
|
|
|
rdata->result);
|
|
@@ -1494,14 +1448,15 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|
|
}
|
|
|
|
|
|
/* Is there enough to get to the rest of the READ_RSP header? */
|
|
|
- if (server->total_read < read_rsp_size()) {
|
|
|
+ if (server->total_read < server->vals->read_rsp_size) {
|
|
|
cFYI(1, "%s: server returned short header. got=%u expected=%zu",
|
|
|
- __func__, server->total_read, read_rsp_size());
|
|
|
+ __func__, server->total_read,
|
|
|
+ server->vals->read_rsp_size);
|
|
|
rdata->result = -EIO;
|
|
|
return cifs_readv_discard(server, mid);
|
|
|
}
|
|
|
|
|
|
- data_offset = read_data_offset(buf) + 4;
|
|
|
+ data_offset = server->ops->read_data_offset(buf) + 4;
|
|
|
if (data_offset < server->total_read) {
|
|
|
/*
|
|
|
* win2k8 sometimes sends an offset of 0 when the read
|
|
@@ -1540,7 +1495,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|
|
rdata->iov[0].iov_base, rdata->iov[0].iov_len);
|
|
|
|
|
|
/* how much data is in the response? */
|
|
|
- data_len = read_data_length(buf);
|
|
|
+ data_len = server->ops->read_data_length(buf);
|
|
|
if (data_offset + data_len > buflen) {
|
|
|
/* data_len is corrupt -- discard frame */
|
|
|
rdata->result = -EIO;
|
|
@@ -1548,64 +1503,8 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|
|
}
|
|
|
|
|
|
/* marshal up the page array */
|
|
|
- len = 0;
|
|
|
- remaining = data_len;
|
|
|
- rdata->nr_iov = 1;
|
|
|
-
|
|
|
- /* determine the eof that the server (probably) has */
|
|
|
- eof = CIFS_I(rdata->mapping->host)->server_eof;
|
|
|
- eof_index = eof ? (eof - 1) >> PAGE_CACHE_SHIFT : 0;
|
|
|
- cFYI(1, "eof=%llu eof_index=%lu", eof, eof_index);
|
|
|
-
|
|
|
- list_for_each_entry_safe(page, tpage, &rdata->pages, lru) {
|
|
|
- if (remaining >= PAGE_CACHE_SIZE) {
|
|
|
- /* enough data to fill the page */
|
|
|
- rdata->iov[rdata->nr_iov].iov_base = kmap(page);
|
|
|
- rdata->iov[rdata->nr_iov].iov_len = PAGE_CACHE_SIZE;
|
|
|
- cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu",
|
|
|
- rdata->nr_iov, page->index,
|
|
|
- rdata->iov[rdata->nr_iov].iov_base,
|
|
|
- rdata->iov[rdata->nr_iov].iov_len);
|
|
|
- ++rdata->nr_iov;
|
|
|
- len += PAGE_CACHE_SIZE;
|
|
|
- remaining -= PAGE_CACHE_SIZE;
|
|
|
- } else if (remaining > 0) {
|
|
|
- /* enough for partial page, fill and zero the rest */
|
|
|
- rdata->iov[rdata->nr_iov].iov_base = kmap(page);
|
|
|
- rdata->iov[rdata->nr_iov].iov_len = remaining;
|
|
|
- cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu",
|
|
|
- rdata->nr_iov, page->index,
|
|
|
- rdata->iov[rdata->nr_iov].iov_base,
|
|
|
- rdata->iov[rdata->nr_iov].iov_len);
|
|
|
- memset(rdata->iov[rdata->nr_iov].iov_base + remaining,
|
|
|
- '\0', PAGE_CACHE_SIZE - remaining);
|
|
|
- ++rdata->nr_iov;
|
|
|
- len += remaining;
|
|
|
- remaining = 0;
|
|
|
- } else if (page->index > eof_index) {
|
|
|
- /*
|
|
|
- * The VFS will not try to do readahead past the
|
|
|
- * i_size, but it's possible that we have outstanding
|
|
|
- * writes with gaps in the middle and the i_size hasn't
|
|
|
- * caught up yet. Populate those with zeroed out pages
|
|
|
- * to prevent the VFS from repeatedly attempting to
|
|
|
- * fill them until the writes are flushed.
|
|
|
- */
|
|
|
- zero_user(page, 0, PAGE_CACHE_SIZE);
|
|
|
- list_del(&page->lru);
|
|
|
- lru_cache_add_file(page);
|
|
|
- flush_dcache_page(page);
|
|
|
- SetPageUptodate(page);
|
|
|
- unlock_page(page);
|
|
|
- page_cache_release(page);
|
|
|
- } else {
|
|
|
- /* no need to hold page hostage */
|
|
|
- list_del(&page->lru);
|
|
|
- lru_cache_add_file(page);
|
|
|
- unlock_page(page);
|
|
|
- page_cache_release(page);
|
|
|
- }
|
|
|
- }
|
|
|
+ len = rdata->marshal_iov(rdata, data_len);
|
|
|
+ data_len -= len;
|
|
|
|
|
|
/* issue the read if we have any iovecs left to fill */
|
|
|
if (rdata->nr_iov > 1) {
|
|
@@ -1621,7 +1520,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|
|
rdata->bytes = length;
|
|
|
|
|
|
cFYI(1, "total_read=%u buflen=%u remaining=%u", server->total_read,
|
|
|
- buflen, remaining);
|
|
|
+ buflen, data_len);
|
|
|
|
|
|
/* discard anything left over */
|
|
|
if (server->total_read < buflen)
|
|
@@ -1631,33 +1530,6 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|
|
return length;
|
|
|
}
|
|
|
|
|
|
-static void
|
|
|
-cifs_readv_complete(struct work_struct *work)
|
|
|
-{
|
|
|
- struct cifs_readdata *rdata = container_of(work,
|
|
|
- struct cifs_readdata, work);
|
|
|
- struct page *page, *tpage;
|
|
|
-
|
|
|
- list_for_each_entry_safe(page, tpage, &rdata->pages, lru) {
|
|
|
- list_del(&page->lru);
|
|
|
- lru_cache_add_file(page);
|
|
|
-
|
|
|
- if (rdata->result == 0) {
|
|
|
- kunmap(page);
|
|
|
- flush_dcache_page(page);
|
|
|
- SetPageUptodate(page);
|
|
|
- }
|
|
|
-
|
|
|
- unlock_page(page);
|
|
|
-
|
|
|
- if (rdata->result == 0)
|
|
|
- cifs_readpage_to_fscache(rdata->mapping->host, page);
|
|
|
-
|
|
|
- page_cache_release(page);
|
|
|
- }
|
|
|
- cifs_readdata_free(rdata);
|
|
|
-}
|
|
|
-
|
|
|
static void
|
|
|
cifs_readv_callback(struct mid_q_entry *mid)
|
|
|
{
|
|
@@ -1691,7 +1563,7 @@ cifs_readv_callback(struct mid_q_entry *mid)
|
|
|
|
|
|
queue_work(cifsiod_wq, &rdata->work);
|
|
|
DeleteMidQEntry(mid);
|
|
|
- cifs_add_credits(server, 1);
|
|
|
+ add_credits(server, 1);
|
|
|
}
|
|
|
|
|
|
/* cifs_async_readv - send an async write, and set up mid to handle result */
|
|
@@ -1744,12 +1616,15 @@ cifs_async_readv(struct cifs_readdata *rdata)
|
|
|
rdata->iov[0].iov_base = smb;
|
|
|
rdata->iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
|
|
|
|
|
|
+ kref_get(&rdata->refcount);
|
|
|
rc = cifs_call_async(tcon->ses->server, rdata->iov, 1,
|
|
|
cifs_readv_receive, cifs_readv_callback,
|
|
|
rdata, false);
|
|
|
|
|
|
if (rc == 0)
|
|
|
cifs_stats_inc(&tcon->num_reads);
|
|
|
+ else
|
|
|
+ kref_put(&rdata->refcount, cifs_readdata_release);
|
|
|
|
|
|
cifs_small_buf_release(smb);
|
|
|
return rc;
|
|
@@ -2135,7 +2010,7 @@ cifs_writev_callback(struct mid_q_entry *mid)
|
|
|
|
|
|
queue_work(cifsiod_wq, &wdata->work);
|
|
|
DeleteMidQEntry(mid);
|
|
|
- cifs_add_credits(tcon->ses->server, 1);
|
|
|
+ add_credits(tcon->ses->server, 1);
|
|
|
}
|
|
|
|
|
|
/* cifs_async_writev - send an async write, and set up mid to handle result */
|
|
@@ -4344,7 +4219,7 @@ int
|
|
|
CIFSFindFirst(const int xid, struct cifs_tcon *tcon,
|
|
|
const char *searchName,
|
|
|
const struct nls_table *nls_codepage,
|
|
|
- __u16 *pnetfid,
|
|
|
+ __u16 *pnetfid, __u16 search_flags,
|
|
|
struct cifs_search_info *psrch_inf, int remap, const char dirsep)
|
|
|
{
|
|
|
/* level 257 SMB_ */
|
|
@@ -4416,8 +4291,7 @@ findFirstRetry:
|
|
|
cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
|
|
|
ATTR_DIRECTORY);
|
|
|
pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
|
|
|
- pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
|
|
|
- CIFS_SEARCH_RETURN_RESUME);
|
|
|
+ pSMB->SearchFlags = cpu_to_le16(search_flags);
|
|
|
pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
|
|
|
|
|
|
/* BB what should we set StorageType to? Does it matter? BB */
|
|
@@ -4487,8 +4361,8 @@ findFirstRetry:
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
-int CIFSFindNext(const int xid, struct cifs_tcon *tcon,
|
|
|
- __u16 searchHandle, struct cifs_search_info *psrch_inf)
|
|
|
+int CIFSFindNext(const int xid, struct cifs_tcon *tcon, __u16 searchHandle,
|
|
|
+ __u16 search_flags, struct cifs_search_info *psrch_inf)
|
|
|
{
|
|
|
TRANSACTION2_FNEXT_REQ *pSMB = NULL;
|
|
|
TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
|
|
@@ -4531,8 +4405,7 @@ int CIFSFindNext(const int xid, struct cifs_tcon *tcon,
|
|
|
cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
|
|
|
pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
|
|
|
pSMB->ResumeKey = psrch_inf->resume_key;
|
|
|
- pSMB->SearchFlags =
|
|
|
- cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
|
|
|
+ pSMB->SearchFlags = cpu_to_le16(search_flags);
|
|
|
|
|
|
name_len = psrch_inf->resume_name_len;
|
|
|
params += name_len;
|