Commit 28865d68 authored by Chuck Lever's avatar Chuck Lever Committed by Linus Torvalds

[PATCH] use kmap_atomic instaed of kmap in NFS client

Description:
  andrew morton suggested there are places in the NFS client that could
  make use of kmap_atomic instead of vanilla kmap in order to improve
  scalability on 8-way and higher SMP systems.

Test status:
  Passes all Connectathon '02 tests with v2 and v3, UDP and TCP; passes
  NFS torture tests on a UP HIGHMEM x86 system.
parent 1ae41b20
...@@ -208,7 +208,7 @@ int find_dirent_page(nfs_readdir_descriptor_t *desc) ...@@ -208,7 +208,7 @@ int find_dirent_page(nfs_readdir_descriptor_t *desc)
/* NOTE: Someone else may have changed the READDIRPLUS flag */ /* NOTE: Someone else may have changed the READDIRPLUS flag */
desc->page = page; desc->page = page;
desc->ptr = kmap(page); desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */
status = find_dirent(desc, page); status = find_dirent(desc, page);
if (status < 0) if (status < 0)
dir_page_release(desc); dir_page_release(desc);
...@@ -345,7 +345,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, ...@@ -345,7 +345,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
NFS_SERVER(inode)->dtsize, NFS_SERVER(inode)->dtsize,
desc->plus); desc->plus);
desc->page = page; desc->page = page;
desc->ptr = kmap(page); desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */
if (desc->error >= 0) { if (desc->error >= 0) {
if ((status = dir_decode(desc)) == 0) if ((status = dir_decode(desc)) == 0)
desc->entry->prev_cookie = desc->target; desc->entry->prev_cookie = desc->target;
...@@ -717,9 +717,9 @@ int nfs_cached_lookup(struct inode *dir, struct dentry *dentry, ...@@ -717,9 +717,9 @@ int nfs_cached_lookup(struct inode *dir, struct dentry *dentry,
res = -EIO; res = -EIO;
if (PageUptodate(page)) { if (PageUptodate(page)) {
desc.ptr = kmap(page); desc.ptr = kmap_atomic(page, KM_USER0);
res = find_dirent_name(&desc, page, dentry); res = find_dirent_name(&desc, page, dentry);
kunmap(page); kunmap_atomic(desc.ptr, KM_USER0);
} }
page_cache_release(page); page_cache_release(page);
......
...@@ -378,7 +378,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, void *dummy) ...@@ -378,7 +378,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, void *dummy)
int hdrlen, recvd; int hdrlen, recvd;
int status, nr; int status, nr;
unsigned int len, pglen; unsigned int len, pglen;
u32 *end, *entry; u32 *end, *entry, *kaddr;
if ((status = ntohl(*p++))) if ((status = ntohl(*p++)))
return -nfs_stat_to_errno(status); return -nfs_stat_to_errno(status);
...@@ -398,7 +398,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, void *dummy) ...@@ -398,7 +398,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, void *dummy)
if (pglen > recvd) if (pglen > recvd)
pglen = recvd; pglen = recvd;
page = rcvbuf->pages; page = rcvbuf->pages;
p = kmap(*page); kaddr = p = (u32 *)kmap_atomic(*page, KM_USER0);
end = (u32 *)((char *)p + pglen); end = (u32 *)((char *)p + pglen);
entry = p; entry = p;
for (nr = 0; *p++; nr++) { for (nr = 0; *p++; nr++) {
...@@ -419,7 +419,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, void *dummy) ...@@ -419,7 +419,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, void *dummy)
if (!nr && (entry[0] != 0 || entry[1] == 0)) if (!nr && (entry[0] != 0 || entry[1] == 0))
goto short_pkt; goto short_pkt;
out: out:
kunmap(*page); kunmap_atomic(kaddr, KM_USER0);
return nr; return nr;
short_pkt: short_pkt:
entry[0] = entry[1] = 0; entry[0] = entry[1] = 0;
...@@ -430,8 +430,8 @@ nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, void *dummy) ...@@ -430,8 +430,8 @@ nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, void *dummy)
} }
goto out; goto out;
err_unmap: err_unmap:
kunmap(*page); nr = -errno_NFSERR_IO;
return -errno_NFSERR_IO; goto out;
} }
u32 * u32 *
...@@ -542,7 +542,7 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, void *dummy) ...@@ -542,7 +542,7 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, void *dummy)
xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen); xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
} }
strlen = (u32*)kmap(rcvbuf->pages[0]); strlen = (u32*)kmap_atomic(rcvbuf->pages[0], KM_USER0);
/* Convert length of symlink */ /* Convert length of symlink */
len = ntohl(*strlen); len = ntohl(*strlen);
if (len > rcvbuf->page_len) if (len > rcvbuf->page_len)
...@@ -551,7 +551,7 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, void *dummy) ...@@ -551,7 +551,7 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, void *dummy)
/* NULL terminate the string we got */ /* NULL terminate the string we got */
string = (char *)(strlen + 1); string = (char *)(strlen + 1);
string[len] = 0; string[len] = 0;
kunmap(rcvbuf->pages[0]); kunmap_atomic(strlen, KM_USER0);
return 0; return 0;
} }
......
...@@ -488,7 +488,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res) ...@@ -488,7 +488,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res)
int hdrlen, recvd; int hdrlen, recvd;
int status, nr; int status, nr;
unsigned int len, pglen; unsigned int len, pglen;
u32 *entry, *end; u32 *entry, *end, *kaddr;
status = ntohl(*p++); status = ntohl(*p++);
/* Decode post_op_attrs */ /* Decode post_op_attrs */
...@@ -518,7 +518,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res) ...@@ -518,7 +518,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res)
if (pglen > recvd) if (pglen > recvd)
pglen = recvd; pglen = recvd;
page = rcvbuf->pages; page = rcvbuf->pages;
p = kmap(*page); kaddr = p = (u32 *)kmap_atomic(*page, KM_USER0);
end = (u32 *)((char *)p + pglen); end = (u32 *)((char *)p + pglen);
entry = p; entry = p;
for (nr = 0; *p++; nr++) { for (nr = 0; *p++; nr++) {
...@@ -563,7 +563,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res) ...@@ -563,7 +563,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res)
if (!nr && (entry[0] != 0 || entry[1] == 0)) if (!nr && (entry[0] != 0 || entry[1] == 0))
goto short_pkt; goto short_pkt;
out: out:
kunmap(*page); kunmap_atomic(kaddr, KM_USER0);
return nr; return nr;
short_pkt: short_pkt:
entry[0] = entry[1] = 0; entry[0] = entry[1] = 0;
...@@ -574,8 +574,8 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res) ...@@ -574,8 +574,8 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res)
} }
goto out; goto out;
err_unmap: err_unmap:
kunmap(*page); nr = -errno_NFSERR_IO;
return -errno_NFSERR_IO; goto out;
} }
u32 * u32 *
...@@ -738,7 +738,7 @@ nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr) ...@@ -738,7 +738,7 @@ nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen); xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
} }
strlen = (u32*)kmap(rcvbuf->pages[0]); strlen = (u32*)kmap_atomic(rcvbuf->pages[0], KM_USER0);
/* Convert length of symlink */ /* Convert length of symlink */
len = ntohl(*strlen); len = ntohl(*strlen);
if (len > rcvbuf->page_len) if (len > rcvbuf->page_len)
...@@ -747,7 +747,7 @@ nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr) ...@@ -747,7 +747,7 @@ nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
/* NULL terminate the string we got */ /* NULL terminate the string we got */
string = (char *)(strlen + 1); string = (char *)(strlen + 1);
string[len] = 0; string[len] = 0;
kunmap(rcvbuf->pages[0]); kunmap_atomic(strlen, KM_USER0);
return 0; return 0;
} }
......
...@@ -447,7 +447,7 @@ nfs4_setup_readdir(struct nfs4_compound *cp, u64 cookie, u32 *verifier, ...@@ -447,7 +447,7 @@ nfs4_setup_readdir(struct nfs4_compound *cp, u64 cookie, u32 *verifier,
* when talking to the server, we always send cookie 0 * when talking to the server, we always send cookie 0
* instead of 1 or 2. * instead of 1 or 2.
*/ */
start = p = (u32 *)kmap(*pages); start = p = (u32 *)kmap_atomic(*pages, KM_USER0);
if (cookie == 0) { if (cookie == 0) {
*p++ = xdr_one; /* next */ *p++ = xdr_one; /* next */
...@@ -475,7 +475,7 @@ nfs4_setup_readdir(struct nfs4_compound *cp, u64 cookie, u32 *verifier, ...@@ -475,7 +475,7 @@ nfs4_setup_readdir(struct nfs4_compound *cp, u64 cookie, u32 *verifier,
readdir->rd_pgbase = (char *)p - (char *)start; readdir->rd_pgbase = (char *)p - (char *)start;
readdir->rd_count -= readdir->rd_pgbase; readdir->rd_count -= readdir->rd_pgbase;
kunmap(*pages); kunmap_atomic(start, KM_USER0);
} }
static void static void
......
...@@ -1410,7 +1410,7 @@ decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir ...@@ -1410,7 +1410,7 @@ decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir
struct page *page = *rcvbuf->pages; struct page *page = *rcvbuf->pages;
struct iovec *iov = rcvbuf->head; struct iovec *iov = rcvbuf->head;
unsigned int nr, pglen = rcvbuf->page_len; unsigned int nr, pglen = rcvbuf->page_len;
uint32_t *end, *entry, *p; uint32_t *end, *entry, *p, *kaddr;
uint32_t len, attrlen, word; uint32_t len, attrlen, word;
int i, hdrlen, recvd, status; int i, hdrlen, recvd, status;
...@@ -1434,7 +1434,7 @@ decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir ...@@ -1434,7 +1434,7 @@ decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir
pglen = recvd; pglen = recvd;
BUG_ON(pglen + readdir->rd_pgbase > PAGE_CACHE_SIZE); BUG_ON(pglen + readdir->rd_pgbase > PAGE_CACHE_SIZE);
p = (uint32_t *) kmap(page); kaddr = p = (uint32_t *) kmap_atomic(page, KM_USER0);
end = (uint32_t *) ((char *)p + pglen + readdir->rd_pgbase); end = (uint32_t *) ((char *)p + pglen + readdir->rd_pgbase);
entry = p; entry = p;
for (nr = 0; *p++; nr++) { for (nr = 0; *p++; nr++) {
...@@ -1480,7 +1480,7 @@ decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir ...@@ -1480,7 +1480,7 @@ decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir
if (!nr && (entry[0] != 0 || entry[1] == 0)) if (!nr && (entry[0] != 0 || entry[1] == 0))
goto short_pkt; goto short_pkt;
out: out:
kunmap(page); kunmap_atomic(kaddr, KM_USER0);
return 0; return 0;
short_pkt: short_pkt:
entry[0] = entry[1] = 0; entry[0] = entry[1] = 0;
...@@ -1491,7 +1491,7 @@ decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir ...@@ -1491,7 +1491,7 @@ decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir
} }
goto out; goto out;
err_unmap: err_unmap:
kunmap(page); kunmap_atomic(kaddr, KM_USER0);
return -errno_NFSERR_IO; return -errno_NFSERR_IO;
} }
...@@ -1522,18 +1522,18 @@ decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readli ...@@ -1522,18 +1522,18 @@ decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readli
* and and null-terminate the text (the VFS expects * and and null-terminate the text (the VFS expects
* null-termination). * null-termination).
*/ */
strlen = (uint32_t *) kmap(rcvbuf->pages[0]); strlen = (uint32_t *) kmap_atomic(rcvbuf->pages[0], KM_USER0);
len = ntohl(*strlen); len = ntohl(*strlen);
if (len > PAGE_CACHE_SIZE - 5) { if (len > PAGE_CACHE_SIZE - 5) {
printk(KERN_WARNING "nfs: server returned giant symlink!\n"); printk(KERN_WARNING "nfs: server returned giant symlink!\n");
kunmap(rcvbuf->pages[0]); kunmap_atomic(strlen, KM_USER0);
return -EIO; return -EIO;
} }
*strlen = len; *strlen = len;
string = (char *)(strlen + 1); string = (char *)(strlen + 1);
string[len] = '\0'; string[len] = '\0';
kunmap(rcvbuf->pages[0]); kunmap_atomic(strlen, KM_USER0);
return 0; return 0;
} }
......
...@@ -118,12 +118,8 @@ nfs_readpage_sync(struct file *file, struct inode *inode, struct page *page) ...@@ -118,12 +118,8 @@ nfs_readpage_sync(struct file *file, struct inode *inode, struct page *page)
break; break;
} while (count); } while (count);
if (count) { if (count)
char *kaddr = kmap(page); memclear_highpage_flush(page, offset, count);
memset(kaddr + offset, 0, count);
kunmap(page);
}
flush_dcache_page(page);
SetPageUptodate(page); SetPageUptodate(page);
if (PageError(page)) if (PageError(page))
ClearPageError(page); ClearPageError(page);
...@@ -272,12 +268,9 @@ nfs_readpage_result(struct rpc_task *task, unsigned int count, int eof) ...@@ -272,12 +268,9 @@ nfs_readpage_result(struct rpc_task *task, unsigned int count, int eof)
if (task->tk_status >= 0) { if (task->tk_status >= 0) {
if (count < PAGE_CACHE_SIZE) { if (count < PAGE_CACHE_SIZE) {
char *p = kmap(page); memclear_highpage_flush(page,
req->wb_offset + count,
if (count < req->wb_bytes)
memset(p + req->wb_offset + count, 0,
req->wb_bytes - count); req->wb_bytes - count);
kunmap(page);
if (eof || if (eof ||
((fattr->valid & NFS_ATTR_FATTR) && ((fattr->valid & NFS_ATTR_FATTR) &&
...@@ -293,7 +286,6 @@ nfs_readpage_result(struct rpc_task *task, unsigned int count, int eof) ...@@ -293,7 +286,6 @@ nfs_readpage_result(struct rpc_task *task, unsigned int count, int eof)
} }
} else } else
SetPageError(page); SetPageError(page);
flush_dcache_page(page);
unlock_page(page); unlock_page(page);
dprintk("NFS: read (%s/%Ld %d@%Ld)\n", dprintk("NFS: read (%s/%Ld %d@%Ld)\n",
......
...@@ -306,6 +306,7 @@ xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, ...@@ -306,6 +306,7 @@ xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base,
len = pglen; len = pglen;
ret = copy_actor(desc, kaddr, len); ret = copy_actor(desc, kaddr, len);
} }
flush_dcache_page(*ppage);
kunmap_atomic(kaddr, KM_SKB_SUNRPC_DATA); kunmap_atomic(kaddr, KM_SKB_SUNRPC_DATA);
if (ret != len || !desc->count) if (ret != len || !desc->count)
return; return;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment