cifs: convert async write code to pass in data via rq_pages array
Reviewed-by: Pavel Shilovsky <pshilovsky@samba.org> Signed-off-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Steve French <smfrench@gmail.com>
This commit is contained in:
parent
fec344e3f3
commit
eddb079deb
|
@ -999,8 +999,8 @@ struct cifs_writedata {
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
unsigned int bytes;
|
unsigned int bytes;
|
||||||
int result;
|
int result;
|
||||||
void (*marshal_iov) (struct kvec *iov,
|
unsigned int pagesz;
|
||||||
struct cifs_writedata *wdata);
|
unsigned int tailsz;
|
||||||
unsigned int nr_pages;
|
unsigned int nr_pages;
|
||||||
struct page *pages[1];
|
struct page *pages[1];
|
||||||
};
|
};
|
||||||
|
|
|
@ -2033,11 +2033,11 @@ cifs_writev_callback(struct mid_q_entry *mid)
|
||||||
int
|
int
|
||||||
cifs_async_writev(struct cifs_writedata *wdata)
|
cifs_async_writev(struct cifs_writedata *wdata)
|
||||||
{
|
{
|
||||||
int i, rc = -EACCES;
|
int rc = -EACCES;
|
||||||
WRITE_REQ *smb = NULL;
|
WRITE_REQ *smb = NULL;
|
||||||
int wct;
|
int wct;
|
||||||
struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
|
struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
|
||||||
struct kvec *iov = NULL;
|
struct kvec iov;
|
||||||
struct smb_rqst rqst = { };
|
struct smb_rqst rqst = { };
|
||||||
|
|
||||||
if (tcon->ses->capabilities & CAP_LARGE_FILES) {
|
if (tcon->ses->capabilities & CAP_LARGE_FILES) {
|
||||||
|
@ -2054,15 +2054,6 @@ cifs_async_writev(struct cifs_writedata *wdata)
|
||||||
if (rc)
|
if (rc)
|
||||||
goto async_writev_out;
|
goto async_writev_out;
|
||||||
|
|
||||||
/* 1 iov per page + 1 for header */
|
|
||||||
rqst.rq_nvec = wdata->nr_pages + 1;
|
|
||||||
iov = kzalloc((rqst.rq_nvec) * sizeof(*iov), GFP_NOFS);
|
|
||||||
if (iov == NULL) {
|
|
||||||
rc = -ENOMEM;
|
|
||||||
goto async_writev_out;
|
|
||||||
}
|
|
||||||
rqst.rq_iov = iov;
|
|
||||||
|
|
||||||
smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
|
smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
|
||||||
smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
|
smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
|
||||||
|
|
||||||
|
@ -2079,18 +2070,15 @@ cifs_async_writev(struct cifs_writedata *wdata)
|
||||||
cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
|
cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
|
||||||
|
|
||||||
/* 4 for RFC1001 length + 1 for BCC */
|
/* 4 for RFC1001 length + 1 for BCC */
|
||||||
iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
|
iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
|
||||||
iov[0].iov_base = smb;
|
iov.iov_base = smb;
|
||||||
|
|
||||||
/*
|
rqst.rq_iov = &iov;
|
||||||
* This function should marshal up the page array into the kvec
|
rqst.rq_nvec = 1;
|
||||||
* array, reserving [0] for the header. It should kmap the pages
|
rqst.rq_pages = wdata->pages;
|
||||||
* and set the iov_len properly for each one. It may also set
|
rqst.rq_npages = wdata->nr_pages;
|
||||||
* wdata->bytes too.
|
rqst.rq_pagesz = wdata->pagesz;
|
||||||
*/
|
rqst.rq_tailsz = wdata->tailsz;
|
||||||
cifs_kmap_lock();
|
|
||||||
wdata->marshal_iov(iov, wdata);
|
|
||||||
cifs_kmap_unlock();
|
|
||||||
|
|
||||||
cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
|
cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
|
||||||
|
|
||||||
|
@ -2106,7 +2094,7 @@ cifs_async_writev(struct cifs_writedata *wdata)
|
||||||
(struct smb_com_writex_req *)smb;
|
(struct smb_com_writex_req *)smb;
|
||||||
inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
|
inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
|
||||||
put_bcc(wdata->bytes + 5, &smbw->hdr);
|
put_bcc(wdata->bytes + 5, &smbw->hdr);
|
||||||
iov[0].iov_len += 4; /* pad bigger by four bytes */
|
iov.iov_len += 4; /* pad bigger by four bytes */
|
||||||
}
|
}
|
||||||
|
|
||||||
kref_get(&wdata->refcount);
|
kref_get(&wdata->refcount);
|
||||||
|
@ -2118,13 +2106,8 @@ cifs_async_writev(struct cifs_writedata *wdata)
|
||||||
else
|
else
|
||||||
kref_put(&wdata->refcount, cifs_writedata_release);
|
kref_put(&wdata->refcount, cifs_writedata_release);
|
||||||
|
|
||||||
/* send is done, unmap pages */
|
|
||||||
for (i = 0; i < wdata->nr_pages; i++)
|
|
||||||
kunmap(wdata->pages[i]);
|
|
||||||
|
|
||||||
async_writev_out:
|
async_writev_out:
|
||||||
cifs_small_buf_release(smb);
|
cifs_small_buf_release(smb);
|
||||||
kfree(iov);
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1738,27 +1738,6 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Marshal up the iov array, reserving the first one for the header. Also,
|
|
||||||
* set wdata->bytes.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
cifs_writepages_marshal_iov(struct kvec *iov, struct cifs_writedata *wdata)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
struct inode *inode = wdata->cfile->dentry->d_inode;
|
|
||||||
loff_t size = i_size_read(inode);
|
|
||||||
|
|
||||||
/* marshal up the pages into iov array */
|
|
||||||
wdata->bytes = 0;
|
|
||||||
for (i = 0; i < wdata->nr_pages; i++) {
|
|
||||||
iov[i + 1].iov_len = min(size - page_offset(wdata->pages[i]),
|
|
||||||
(loff_t)PAGE_CACHE_SIZE);
|
|
||||||
iov[i + 1].iov_base = kmap(wdata->pages[i]);
|
|
||||||
wdata->bytes += iov[i + 1].iov_len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cifs_writepages(struct address_space *mapping,
|
static int cifs_writepages(struct address_space *mapping,
|
||||||
struct writeback_control *wbc)
|
struct writeback_control *wbc)
|
||||||
{
|
{
|
||||||
|
@ -1769,6 +1748,7 @@ static int cifs_writepages(struct address_space *mapping,
|
||||||
struct TCP_Server_Info *server;
|
struct TCP_Server_Info *server;
|
||||||
struct page *page;
|
struct page *page;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
loff_t isize = i_size_read(mapping->host);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If wsize is smaller than the page cache size, default to writing
|
* If wsize is smaller than the page cache size, default to writing
|
||||||
|
@ -1873,7 +1853,7 @@ retry:
|
||||||
*/
|
*/
|
||||||
set_page_writeback(page);
|
set_page_writeback(page);
|
||||||
|
|
||||||
if (page_offset(page) >= mapping->host->i_size) {
|
if (page_offset(page) >= isize) {
|
||||||
done = true;
|
done = true;
|
||||||
unlock_page(page);
|
unlock_page(page);
|
||||||
end_page_writeback(page);
|
end_page_writeback(page);
|
||||||
|
@ -1904,7 +1884,12 @@ retry:
|
||||||
wdata->sync_mode = wbc->sync_mode;
|
wdata->sync_mode = wbc->sync_mode;
|
||||||
wdata->nr_pages = nr_pages;
|
wdata->nr_pages = nr_pages;
|
||||||
wdata->offset = page_offset(wdata->pages[0]);
|
wdata->offset = page_offset(wdata->pages[0]);
|
||||||
wdata->marshal_iov = cifs_writepages_marshal_iov;
|
wdata->pagesz = PAGE_CACHE_SIZE;
|
||||||
|
wdata->tailsz =
|
||||||
|
min(isize - page_offset(wdata->pages[nr_pages - 1]),
|
||||||
|
(loff_t)PAGE_CACHE_SIZE);
|
||||||
|
wdata->bytes = ((nr_pages - 1) * PAGE_CACHE_SIZE) +
|
||||||
|
wdata->tailsz;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (wdata->cfile != NULL)
|
if (wdata->cfile != NULL)
|
||||||
|
@ -2205,20 +2190,6 @@ size_t get_numpages(const size_t wsize, const size_t len, size_t *cur_len)
|
||||||
return num_pages;
|
return num_pages;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
cifs_uncached_marshal_iov(struct kvec *iov, struct cifs_writedata *wdata)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
size_t bytes = wdata->bytes;
|
|
||||||
|
|
||||||
/* marshal up the pages into iov array */
|
|
||||||
for (i = 0; i < wdata->nr_pages; i++) {
|
|
||||||
iov[i + 1].iov_len = min_t(size_t, bytes, PAGE_SIZE);
|
|
||||||
iov[i + 1].iov_base = kmap(wdata->pages[i]);
|
|
||||||
bytes -= iov[i + 1].iov_len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cifs_uncached_writev_complete(struct work_struct *work)
|
cifs_uncached_writev_complete(struct work_struct *work)
|
||||||
{
|
{
|
||||||
|
@ -2339,7 +2310,8 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
|
||||||
wdata->cfile = cifsFileInfo_get(open_file);
|
wdata->cfile = cifsFileInfo_get(open_file);
|
||||||
wdata->pid = pid;
|
wdata->pid = pid;
|
||||||
wdata->bytes = cur_len;
|
wdata->bytes = cur_len;
|
||||||
wdata->marshal_iov = cifs_uncached_marshal_iov;
|
wdata->pagesz = PAGE_SIZE;
|
||||||
|
wdata->tailsz = cur_len - ((nr_pages - 1) * PAGE_SIZE);
|
||||||
rc = cifs_uncached_retry_writev(wdata);
|
rc = cifs_uncached_retry_writev(wdata);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
kref_put(&wdata->refcount, cifs_writedata_release);
|
kref_put(&wdata->refcount, cifs_writedata_release);
|
||||||
|
|
|
@ -1484,25 +1484,16 @@ smb2_writev_callback(struct mid_q_entry *mid)
|
||||||
int
|
int
|
||||||
smb2_async_writev(struct cifs_writedata *wdata)
|
smb2_async_writev(struct cifs_writedata *wdata)
|
||||||
{
|
{
|
||||||
int i, rc = -EACCES;
|
int rc = -EACCES;
|
||||||
struct smb2_write_req *req = NULL;
|
struct smb2_write_req *req = NULL;
|
||||||
struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
|
struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
|
||||||
struct kvec *iov = NULL;
|
struct kvec iov;
|
||||||
struct smb_rqst rqst;
|
struct smb_rqst rqst;
|
||||||
|
|
||||||
rc = small_smb2_init(SMB2_WRITE, tcon, (void **) &req);
|
rc = small_smb2_init(SMB2_WRITE, tcon, (void **) &req);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto async_writev_out;
|
goto async_writev_out;
|
||||||
|
|
||||||
/* 1 iov per page + 1 for header */
|
|
||||||
iov = kzalloc((wdata->nr_pages + 1) * sizeof(*iov), GFP_NOFS);
|
|
||||||
if (iov == NULL) {
|
|
||||||
rc = -ENOMEM;
|
|
||||||
goto async_writev_out;
|
|
||||||
}
|
|
||||||
rqst.rq_iov = iov;
|
|
||||||
rqst.rq_nvec = wdata->nr_pages + 1;
|
|
||||||
|
|
||||||
req->hdr.ProcessId = cpu_to_le32(wdata->cfile->pid);
|
req->hdr.ProcessId = cpu_to_le32(wdata->cfile->pid);
|
||||||
|
|
||||||
req->PersistentFileId = wdata->cfile->fid.persistent_fid;
|
req->PersistentFileId = wdata->cfile->fid.persistent_fid;
|
||||||
|
@ -1517,18 +1508,15 @@ smb2_async_writev(struct cifs_writedata *wdata)
|
||||||
req->RemainingBytes = 0;
|
req->RemainingBytes = 0;
|
||||||
|
|
||||||
/* 4 for rfc1002 length field and 1 for Buffer */
|
/* 4 for rfc1002 length field and 1 for Buffer */
|
||||||
iov[0].iov_len = get_rfc1002_length(req) + 4 - 1;
|
iov.iov_len = get_rfc1002_length(req) + 4 - 1;
|
||||||
iov[0].iov_base = (char *)req;
|
iov.iov_base = req;
|
||||||
|
|
||||||
/*
|
rqst.rq_iov = &iov;
|
||||||
* This function should marshal up the page array into the kvec
|
rqst.rq_nvec = 1;
|
||||||
* array, reserving [0] for the header. It should kmap the pages
|
rqst.rq_pages = wdata->pages;
|
||||||
* and set the iov_len properly for each one. It may also set
|
rqst.rq_npages = wdata->nr_pages;
|
||||||
* wdata->bytes too.
|
rqst.rq_pagesz = wdata->pagesz;
|
||||||
*/
|
rqst.rq_tailsz = wdata->tailsz;
|
||||||
cifs_kmap_lock();
|
|
||||||
wdata->marshal_iov(iov, wdata);
|
|
||||||
cifs_kmap_unlock();
|
|
||||||
|
|
||||||
cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
|
cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
|
||||||
|
|
||||||
|
@ -1543,13 +1531,8 @@ smb2_async_writev(struct cifs_writedata *wdata)
|
||||||
if (rc)
|
if (rc)
|
||||||
kref_put(&wdata->refcount, cifs_writedata_release);
|
kref_put(&wdata->refcount, cifs_writedata_release);
|
||||||
|
|
||||||
/* send is done, unmap pages */
|
|
||||||
for (i = 0; i < wdata->nr_pages; i++)
|
|
||||||
kunmap(wdata->pages[i]);
|
|
||||||
|
|
||||||
async_writev_out:
|
async_writev_out:
|
||||||
cifs_small_buf_release(req);
|
cifs_small_buf_release(req);
|
||||||
kfree(iov);
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue