On Tue, Dec 01, 2020 at 05:03:46PM -0500, Olga Kornievskaia wrote: > > On Tue, Dec 1, 2020 at 4:44 PM Frank van der Linden <fllinden@xxxxxxxxxx> wrote: > > > > XDRBUF_SPARSE_PAGES can cause problems for the RDMA transport, > > and it's easy enough to allocate enough pages for the request > > up front, so do that. > > > > Also, since we've allocated the pages anyway, use the full > > page aligned length for the receive buffer. This will allow > > caching of valid replies that are too large for the caller, > > but that still fit in the allocated pages. > > > > Signed-off-by: Frank van der Linden <fllinden@xxxxxxxxxx> > > --- > > fs/nfs/nfs42proc.c | 39 ++++++++++++++++++++++++++++++--------- > > fs/nfs/nfs42xdr.c | 22 +++++++++++++++++----- > > 2 files changed, 47 insertions(+), 14 deletions(-) > > > > diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c > > index 2b2211d1234e..bfe15ac77bd9 100644 > > --- a/fs/nfs/nfs42proc.c > > +++ b/fs/nfs/nfs42proc.c > > @@ -1176,11 +1176,9 @@ static ssize_t _nfs42_proc_getxattr(struct inode *inode, const char *name, > > void *buf, size_t buflen) > > { > > struct nfs_server *server = NFS_SERVER(inode); > > - struct page *pages[NFS4XATTR_MAXPAGES] = {}; > > + struct page **pages; > > struct nfs42_getxattrargs arg = { > > .fh = NFS_FH(inode), > > - .xattr_pages = pages, > > - .xattr_len = buflen, > > .xattr_name = name, > > }; > > struct nfs42_getxattrres res; > > @@ -1189,12 +1187,31 @@ static ssize_t _nfs42_proc_getxattr(struct inode *inode, const char *name, > > .rpc_argp = &arg, > > .rpc_resp = &res, > > }; > > - int ret, np; > > + ssize_t ret, np, i; > > + > > + arg.xattr_len = buflen ?: XATTR_SIZE_MAX; > > + > > + ret = -ENOMEM; > > + np = DIV_ROUND_UP(arg.xattr_len, PAGE_SIZE); > > + > > + pages = kcalloc(np, sizeof(struct page *), GFP_KERNEL); > > + if (pages == NULL) > > + return ret; > > + > > + for (i = 0; i < np; i++) { > > + pages[i] = alloc_page(GFP_KERNEL); > > + if (!pages[i]) > > + goto out_free; > > + } > > + > > + arg.xattr_pages = pages; > > > > ret = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, > > &res.seq_res, 0); > > if (ret < 0) > > - return ret; > > + goto out_free; > > + > > + ret = res.xattr_len; > > > > /* > > * Normally, the caching is done one layer up, but for successful > > @@ -1209,16 +1226,20 @@ static ssize_t _nfs42_proc_getxattr(struct inode *inode, const char *name, > > nfs4_xattr_cache_add(inode, name, NULL, pages, res.xattr_len); > > > > if (buflen) { > > - if (res.xattr_len > buflen) > > - return -ERANGE; > > + if (res.xattr_len > buflen) { > > + ret = -ERANGE; > > + goto out_free; > > + } > > _copy_from_pages(buf, pages, 0, res.xattr_len); > > } > > > > - np = DIV_ROUND_UP(res.xattr_len, PAGE_SIZE); > > +out_free: > > while (--np >= 0) > > __free_page(pages[np]); > > Looking at Chuck's page for listxattr, I think we need to check if > (pages[np) before freeing? > > Otherwise, looks fine to me. Reviewed-by. Hm, originally, yes, because of SPARSE_PAGES use. So that was actually a bug in the original code, which is now fixed. In other words, we need a Cc: -stable here (which I assume we want anyway, since this fixes RDMA). It's not needed anymore, and it's not needed for listxattr anymore either, although there the code was originally correct. - Frank