diff options
author | Pavel Shilovsky <pshilovsky@samba.org> | 2014-06-25 03:28:57 -0400 |
---|---|---|
committer | Steve French <smfrench@gmail.com> | 2014-08-02 02:23:03 -0400 |
commit | bed9da0213f2174719b68012bd60735a11cfe244 (patch) | |
tree | 3a88a92dcf884d1a31a8896e9513a5124cbddebb | |
parent | e374d90f8a7693f24635bca9e5d56f3775bb36e2 (diff) |
CIFS: Use multicredits for SMB 2.1/3 reads
If we negotiate SMB 2.1 and higher version of the protocol and
a server supports large read buffer size, we need to consume 1
credit per 65536 bytes. So, we need to know how many credits
we have and obtain the required number of them before constructing
a readdata structure in readpages and user read.
Reviewed-by: Shirish Pargaonkar <spargaonkar@suse.com>
Signed-off-by: Pavel Shilovsky <pshilovsky@samba.org>
Signed-off-by: Steve French <smfrench@gmail.com>
-rw-r--r-- | fs/cifs/cifsglob.h | 1 | ||||
-rw-r--r-- | fs/cifs/file.c | 35 | ||||
-rw-r--r-- | fs/cifs/smb2ops.c | 5 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.c | 30 |
4 files changed, 59 insertions, 12 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 54ca2b985a0d..f33ff4c7b8a8 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -1068,6 +1068,7 @@ struct cifs_readdata { | |||
1068 | struct kvec iov; | 1068 | struct kvec iov; |
1069 | unsigned int pagesz; | 1069 | unsigned int pagesz; |
1070 | unsigned int tailsz; | 1070 | unsigned int tailsz; |
1071 | unsigned int credits; | ||
1071 | unsigned int nr_pages; | 1072 | unsigned int nr_pages; |
1072 | struct page *pages[]; | 1073 | struct page *pages[]; |
1073 | }; | 1074 | }; |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 00b2a254ff1c..ebdeb56f8d30 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -2917,7 +2917,7 @@ cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file, | |||
2917 | struct cifs_sb_info *cifs_sb, struct list_head *rdata_list) | 2917 | struct cifs_sb_info *cifs_sb, struct list_head *rdata_list) |
2918 | { | 2918 | { |
2919 | struct cifs_readdata *rdata; | 2919 | struct cifs_readdata *rdata; |
2920 | unsigned int npages; | 2920 | unsigned int npages, rsize, credits; |
2921 | size_t cur_len; | 2921 | size_t cur_len; |
2922 | int rc; | 2922 | int rc; |
2923 | pid_t pid; | 2923 | pid_t pid; |
@@ -2931,13 +2931,19 @@ cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file, | |||
2931 | pid = current->tgid; | 2931 | pid = current->tgid; |
2932 | 2932 | ||
2933 | do { | 2933 | do { |
2934 | cur_len = min_t(const size_t, len, cifs_sb->rsize); | 2934 | rc = server->ops->wait_mtu_credits(server, cifs_sb->rsize, |
2935 | &rsize, &credits); | ||
2936 | if (rc) | ||
2937 | break; | ||
2938 | |||
2939 | cur_len = min_t(const size_t, len, rsize); | ||
2935 | npages = DIV_ROUND_UP(cur_len, PAGE_SIZE); | 2940 | npages = DIV_ROUND_UP(cur_len, PAGE_SIZE); |
2936 | 2941 | ||
2937 | /* allocate a readdata struct */ | 2942 | /* allocate a readdata struct */ |
2938 | rdata = cifs_readdata_alloc(npages, | 2943 | rdata = cifs_readdata_alloc(npages, |
2939 | cifs_uncached_readv_complete); | 2944 | cifs_uncached_readv_complete); |
2940 | if (!rdata) { | 2945 | if (!rdata) { |
2946 | add_credits_and_wake_if(server, credits, 0); | ||
2941 | rc = -ENOMEM; | 2947 | rc = -ENOMEM; |
2942 | break; | 2948 | break; |
2943 | } | 2949 | } |
@@ -2953,12 +2959,14 @@ cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file, | |||
2953 | rdata->pid = pid; | 2959 | rdata->pid = pid; |
2954 | rdata->pagesz = PAGE_SIZE; | 2960 | rdata->pagesz = PAGE_SIZE; |
2955 | rdata->read_into_pages = cifs_uncached_read_into_pages; | 2961 | rdata->read_into_pages = cifs_uncached_read_into_pages; |
2962 | rdata->credits = credits; | ||
2956 | 2963 | ||
2957 | if (!rdata->cfile->invalidHandle || | 2964 | if (!rdata->cfile->invalidHandle || |
2958 | !cifs_reopen_file(rdata->cfile, true)) | 2965 | !cifs_reopen_file(rdata->cfile, true)) |
2959 | rc = server->ops->async_readv(rdata); | 2966 | rc = server->ops->async_readv(rdata); |
2960 | error: | 2967 | error: |
2961 | if (rc) { | 2968 | if (rc) { |
2969 | add_credits_and_wake_if(server, rdata->credits, 0); | ||
2962 | kref_put(&rdata->refcount, | 2970 | kref_put(&rdata->refcount, |
2963 | cifs_uncached_readdata_release); | 2971 | cifs_uncached_readdata_release); |
2964 | if (rc == -EAGAIN) | 2972 | if (rc == -EAGAIN) |
@@ -3458,10 +3466,16 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
3458 | * the rdata->pages, then we want them in increasing order. | 3466 | * the rdata->pages, then we want them in increasing order. |
3459 | */ | 3467 | */ |
3460 | while (!list_empty(page_list)) { | 3468 | while (!list_empty(page_list)) { |
3461 | unsigned int i, nr_pages, bytes; | 3469 | unsigned int i, nr_pages, bytes, rsize; |
3462 | loff_t offset; | 3470 | loff_t offset; |
3463 | struct page *page, *tpage; | 3471 | struct page *page, *tpage; |
3464 | struct cifs_readdata *rdata; | 3472 | struct cifs_readdata *rdata; |
3473 | unsigned credits; | ||
3474 | |||
3475 | rc = server->ops->wait_mtu_credits(server, cifs_sb->rsize, | ||
3476 | &rsize, &credits); | ||
3477 | if (rc) | ||
3478 | break; | ||
3465 | 3479 | ||
3466 | /* | 3480 | /* |
3467 | * Give up immediately if rsize is too small to read an entire | 3481 | * Give up immediately if rsize is too small to read an entire |
@@ -3469,13 +3483,17 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
3469 | * reach this point however since we set ra_pages to 0 when the | 3483 | * reach this point however since we set ra_pages to 0 when the |
3470 | * rsize is smaller than a cache page. | 3484 | * rsize is smaller than a cache page. |
3471 | */ | 3485 | */ |
3472 | if (unlikely(cifs_sb->rsize < PAGE_CACHE_SIZE)) | 3486 | if (unlikely(rsize < PAGE_CACHE_SIZE)) { |
3487 | add_credits_and_wake_if(server, credits, 0); | ||
3473 | return 0; | 3488 | return 0; |
3489 | } | ||
3474 | 3490 | ||
3475 | rc = readpages_get_pages(mapping, page_list, cifs_sb->rsize, | 3491 | rc = readpages_get_pages(mapping, page_list, rsize, &tmplist, |
3476 | &tmplist, &nr_pages, &offset, &bytes); | 3492 | &nr_pages, &offset, &bytes); |
3477 | if (rc) | 3493 | if (rc) { |
3494 | add_credits_and_wake_if(server, credits, 0); | ||
3478 | break; | 3495 | break; |
3496 | } | ||
3479 | 3497 | ||
3480 | rdata = cifs_readdata_alloc(nr_pages, cifs_readv_complete); | 3498 | rdata = cifs_readdata_alloc(nr_pages, cifs_readv_complete); |
3481 | if (!rdata) { | 3499 | if (!rdata) { |
@@ -3487,6 +3505,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
3487 | page_cache_release(page); | 3505 | page_cache_release(page); |
3488 | } | 3506 | } |
3489 | rc = -ENOMEM; | 3507 | rc = -ENOMEM; |
3508 | add_credits_and_wake_if(server, credits, 0); | ||
3490 | break; | 3509 | break; |
3491 | } | 3510 | } |
3492 | 3511 | ||
@@ -3497,6 +3516,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
3497 | rdata->pid = pid; | 3516 | rdata->pid = pid; |
3498 | rdata->pagesz = PAGE_CACHE_SIZE; | 3517 | rdata->pagesz = PAGE_CACHE_SIZE; |
3499 | rdata->read_into_pages = cifs_readpages_read_into_pages; | 3518 | rdata->read_into_pages = cifs_readpages_read_into_pages; |
3519 | rdata->credits = credits; | ||
3500 | 3520 | ||
3501 | list_for_each_entry_safe(page, tpage, &tmplist, lru) { | 3521 | list_for_each_entry_safe(page, tpage, &tmplist, lru) { |
3502 | list_del(&page->lru); | 3522 | list_del(&page->lru); |
@@ -3507,6 +3527,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
3507 | !cifs_reopen_file(rdata->cfile, true)) | 3527 | !cifs_reopen_file(rdata->cfile, true)) |
3508 | rc = server->ops->async_readv(rdata); | 3528 | rc = server->ops->async_readv(rdata); |
3509 | if (rc) { | 3529 | if (rc) { |
3530 | add_credits_and_wake_if(server, rdata->credits, 0); | ||
3510 | for (i = 0; i < rdata->nr_pages; i++) { | 3531 | for (i = 0; i < rdata->nr_pages; i++) { |
3511 | page = rdata->pages[i]; | 3532 | page = rdata->pages[i]; |
3512 | lru_cache_add_file(page); | 3533 | lru_cache_add_file(page); |
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 3427c1fa3806..d0210a8e9829 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c | |||
@@ -245,8 +245,9 @@ smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info) | |||
245 | /* start with specified rsize, or default */ | 245 | /* start with specified rsize, or default */ |
246 | rsize = volume_info->rsize ? volume_info->rsize : CIFS_DEFAULT_IOSIZE; | 246 | rsize = volume_info->rsize ? volume_info->rsize : CIFS_DEFAULT_IOSIZE; |
247 | rsize = min_t(unsigned int, rsize, server->max_read); | 247 | rsize = min_t(unsigned int, rsize, server->max_read); |
248 | /* set it to the maximum buffer size value we can send with 1 credit */ | 248 | |
249 | rsize = min_t(unsigned int, rsize, SMB2_MAX_BUFFER_SIZE); | 249 | if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU)) |
250 | rsize = min_t(unsigned int, rsize, SMB2_MAX_BUFFER_SIZE); | ||
250 | 251 | ||
251 | return rsize; | 252 | return rsize; |
252 | } | 253 | } |
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index be7b2eb55134..c31e5a060338 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c | |||
@@ -1747,11 +1747,12 @@ smb2_readv_callback(struct mid_q_entry *mid) | |||
1747 | int | 1747 | int |
1748 | smb2_async_readv(struct cifs_readdata *rdata) | 1748 | smb2_async_readv(struct cifs_readdata *rdata) |
1749 | { | 1749 | { |
1750 | int rc; | 1750 | int rc, flags = 0; |
1751 | struct smb2_hdr *buf; | 1751 | struct smb2_hdr *buf; |
1752 | struct cifs_io_parms io_parms; | 1752 | struct cifs_io_parms io_parms; |
1753 | struct smb_rqst rqst = { .rq_iov = &rdata->iov, | 1753 | struct smb_rqst rqst = { .rq_iov = &rdata->iov, |
1754 | .rq_nvec = 1 }; | 1754 | .rq_nvec = 1 }; |
1755 | struct TCP_Server_Info *server; | ||
1755 | 1756 | ||
1756 | cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n", | 1757 | cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n", |
1757 | __func__, rdata->offset, rdata->bytes); | 1758 | __func__, rdata->offset, rdata->bytes); |
@@ -1762,18 +1763,41 @@ smb2_async_readv(struct cifs_readdata *rdata) | |||
1762 | io_parms.persistent_fid = rdata->cfile->fid.persistent_fid; | 1763 | io_parms.persistent_fid = rdata->cfile->fid.persistent_fid; |
1763 | io_parms.volatile_fid = rdata->cfile->fid.volatile_fid; | 1764 | io_parms.volatile_fid = rdata->cfile->fid.volatile_fid; |
1764 | io_parms.pid = rdata->pid; | 1765 | io_parms.pid = rdata->pid; |
1766 | |||
1767 | server = io_parms.tcon->ses->server; | ||
1768 | |||
1765 | rc = smb2_new_read_req(&rdata->iov, &io_parms, 0, 0); | 1769 | rc = smb2_new_read_req(&rdata->iov, &io_parms, 0, 0); |
1766 | if (rc) | 1770 | if (rc) { |
1771 | if (rc == -EAGAIN && rdata->credits) { | ||
1772 | /* credits was reset by reconnect */ | ||
1773 | rdata->credits = 0; | ||
1774 | /* reduce in_flight value since we won't send the req */ | ||
1775 | spin_lock(&server->req_lock); | ||
1776 | server->in_flight--; | ||
1777 | spin_unlock(&server->req_lock); | ||
1778 | } | ||
1767 | return rc; | 1779 | return rc; |
1780 | } | ||
1768 | 1781 | ||
1769 | buf = (struct smb2_hdr *)rdata->iov.iov_base; | 1782 | buf = (struct smb2_hdr *)rdata->iov.iov_base; |
1770 | /* 4 for rfc1002 length field */ | 1783 | /* 4 for rfc1002 length field */ |
1771 | rdata->iov.iov_len = get_rfc1002_length(rdata->iov.iov_base) + 4; | 1784 | rdata->iov.iov_len = get_rfc1002_length(rdata->iov.iov_base) + 4; |
1772 | 1785 | ||
1786 | if (rdata->credits) { | ||
1787 | buf->CreditCharge = cpu_to_le16(DIV_ROUND_UP(rdata->bytes, | ||
1788 | SMB2_MAX_BUFFER_SIZE)); | ||
1789 | spin_lock(&server->req_lock); | ||
1790 | server->credits += rdata->credits - | ||
1791 | le16_to_cpu(buf->CreditCharge); | ||
1792 | spin_unlock(&server->req_lock); | ||
1793 | wake_up(&server->request_q); | ||
1794 | flags = CIFS_HAS_CREDITS; | ||
1795 | } | ||
1796 | |||
1773 | kref_get(&rdata->refcount); | 1797 | kref_get(&rdata->refcount); |
1774 | rc = cifs_call_async(io_parms.tcon->ses->server, &rqst, | 1798 | rc = cifs_call_async(io_parms.tcon->ses->server, &rqst, |
1775 | cifs_readv_receive, smb2_readv_callback, | 1799 | cifs_readv_receive, smb2_readv_callback, |
1776 | rdata, 0); | 1800 | rdata, flags); |
1777 | if (rc) { | 1801 | if (rc) { |
1778 | kref_put(&rdata->refcount, cifs_readdata_release); | 1802 | kref_put(&rdata->refcount, cifs_readdata_release); |
1779 | cifs_stats_fail_inc(io_parms.tcon, SMB2_READ_HE); | 1803 | cifs_stats_fail_inc(io_parms.tcon, SMB2_READ_HE); |