2022-02-28 02:08:24

by Trond Myklebust

[permalink] [raw]
Subject: [PATCH v9 26/27] NFS: Optimise away the previous cookie field

From: Trond Myklebust <[email protected]>

Replace the 'previous cookie' field in struct nfs_entry with the
array->last_cookie.

Signed-off-by: Trond Myklebust <[email protected]>
---
fs/nfs/dir.c | 26 ++++++++++++++------------
fs/nfs/nfs2xdr.c | 1 -
fs/nfs/nfs3xdr.c | 1 -
fs/nfs/nfs4xdr.c | 1 -
include/linux/nfs_xdr.h | 3 +--
5 files changed, 15 insertions(+), 17 deletions(-)

diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 5a2c98b2cc15..c2c847845464 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -296,19 +296,20 @@ static int nfs_readdir_array_can_expand(struct nfs_cache_array *array)
return 0;
}

-static
-int nfs_readdir_add_to_array(struct nfs_entry *entry, struct page *page)
+static int nfs_readdir_page_array_append(struct page *page,
+ const struct nfs_entry *entry,
+ u64 *cookie)
{
struct nfs_cache_array *array;
struct nfs_cache_array_entry *cache_entry;
const char *name;
- int ret;
+ int ret = -ENOMEM;

name = nfs_readdir_copy_name(entry->name, entry->len);
- if (!name)
- return -ENOMEM;

array = kmap_atomic(page);
+ if (!name)
+ goto out;
ret = nfs_readdir_array_can_expand(array);
if (ret) {
kfree(name);
@@ -316,7 +317,7 @@ int nfs_readdir_add_to_array(struct nfs_entry *entry, struct page *page)
}

cache_entry = &array->array[array->size];
- cache_entry->cookie = entry->prev_cookie;
+ cache_entry->cookie = array->last_cookie;
cache_entry->ino = entry->ino;
cache_entry->d_type = entry->d_type;
cache_entry->name_len = entry->len;
@@ -328,6 +329,7 @@ int nfs_readdir_add_to_array(struct nfs_entry *entry, struct page *page)
if (entry->eof != 0)
nfs_readdir_array_set_eof(array);
out:
+ *cookie = array->last_cookie;
kunmap_atomic(array);
return ret;
}
@@ -791,6 +793,7 @@ static int nfs_readdir_page_filler(struct nfs_readdir_descriptor *desc,
struct xdr_stream stream;
struct xdr_buf buf;
struct page *scratch, *new, *page = *arrays;
+ u64 cookie;
int status;

scratch = alloc_page(GFP_KERNEL);
@@ -812,22 +815,21 @@ static int nfs_readdir_page_filler(struct nfs_readdir_descriptor *desc,
nfs_prime_dcache(file_dentry(desc->file), entry,
desc->dir_verifier);

- status = nfs_readdir_add_to_array(entry, page);
+ status = nfs_readdir_page_array_append(page, entry, &cookie);
if (status != -ENOSPC)
continue;

if (page->mapping != mapping) {
if (!--narrays)
break;
- new = nfs_readdir_page_array_alloc(entry->prev_cookie,
- GFP_KERNEL);
+ new = nfs_readdir_page_array_alloc(cookie, GFP_KERNEL);
if (!new)
break;
arrays++;
*arrays = page = new;
} else {
- new = nfs_readdir_page_get_next(
- mapping, entry->prev_cookie, change_attr);
+ new = nfs_readdir_page_get_next(mapping, cookie,
+ change_attr);
if (!new)
break;
if (page != *arrays)
@@ -835,7 +837,7 @@ static int nfs_readdir_page_filler(struct nfs_readdir_descriptor *desc,
page = new;
}
desc->page_index_max++;
- status = nfs_readdir_add_to_array(entry, page);
+ status = nfs_readdir_page_array_append(page, entry, &cookie);
} while (!status && !entry->eof);

switch (status) {
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
index 3d5ba43f44bb..05c3b4b2b3dd 100644
--- a/fs/nfs/nfs2xdr.c
+++ b/fs/nfs/nfs2xdr.c
@@ -955,7 +955,6 @@ int nfs2_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
* The type (size and byte order) of nfscookie isn't defined in
* RFC 1094. This implementation assumes that it's an XDR uint32.
*/
- entry->prev_cookie = entry->cookie;
p = xdr_inline_decode(xdr, 4);
if (unlikely(!p))
return -EAGAIN;
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
index d6779ceeb39e..3b0b650c9c5a 100644
--- a/fs/nfs/nfs3xdr.c
+++ b/fs/nfs/nfs3xdr.c
@@ -2024,7 +2024,6 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
zero_nfs_fh3(entry->fh);
}

- entry->prev_cookie = entry->cookie;
entry->cookie = new_cookie;

return 0;
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index b7780b97dc4d..86a5f6516928 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -7508,7 +7508,6 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
if (entry->fattr->valid & NFS_ATTR_FATTR_TYPE)
entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);

- entry->prev_cookie = entry->cookie;
entry->cookie = new_cookie;

return 0;
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 728cb0c1f0b6..82f7c2730b9a 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -745,8 +745,7 @@ struct nfs_auth_info {
*/
struct nfs_entry {
__u64 ino;
- __u64 cookie,
- prev_cookie;
+ __u64 cookie;
const char * name;
unsigned int len;
int eof;
--
2.35.1


2022-02-28 07:12:10

by Trond Myklebust

[permalink] [raw]
Subject: [PATCH v9 27/27] NFS: Cache all entries in the readdirplus reply

From: Trond Myklebust <[email protected]>

Even if we're not able to cache all the entries in the readdir buffer,
let's ensure that we do prime the dcache.

Signed-off-by: Trond Myklebust <[email protected]>
---
fs/nfs/dir.c | 40 ++++++++++++++++++++++++++--------------
1 file changed, 26 insertions(+), 14 deletions(-)

diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index c2c847845464..4cd77bc5022d 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -782,6 +782,21 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry,
dput(dentry);
}

+static int nfs_readdir_entry_decode(struct nfs_readdir_descriptor *desc,
+ struct nfs_entry *entry,
+ struct xdr_stream *stream)
+{
+ int ret;
+
+ if (entry->fattr->label)
+ entry->fattr->label->len = NFS4_MAXLABELLEN;
+ ret = xdr_decode(desc, entry, stream);
+ if (ret || !desc->plus)
+ return ret;
+ nfs_prime_dcache(file_dentry(desc->file), entry, desc->dir_verifier);
+ return 0;
+}
+
/* Perform conversion from xdr to cache array */
static int nfs_readdir_page_filler(struct nfs_readdir_descriptor *desc,
struct nfs_entry *entry,
@@ -804,17 +819,10 @@ static int nfs_readdir_page_filler(struct nfs_readdir_descriptor *desc,
xdr_set_scratch_page(&stream, scratch);

do {
- if (entry->fattr->label)
- entry->fattr->label->len = NFS4_MAXLABELLEN;
-
- status = xdr_decode(desc, entry, &stream);
+ status = nfs_readdir_entry_decode(desc, entry, &stream);
if (status != 0)
break;

- if (desc->plus)
- nfs_prime_dcache(file_dentry(desc->file), entry,
- desc->dir_verifier);
-
status = nfs_readdir_page_array_append(page, entry, &cookie);
if (status != -ENOSPC)
continue;
@@ -842,15 +850,19 @@ static int nfs_readdir_page_filler(struct nfs_readdir_descriptor *desc,

switch (status) {
case -EBADCOOKIE:
- if (entry->eof) {
- nfs_readdir_page_set_eof(page);
- status = 0;
- }
- break;
- case -ENOSPC:
+ if (!entry->eof)
+ break;
+ nfs_readdir_page_set_eof(page);
+ fallthrough;
case -EAGAIN:
status = 0;
break;
+ case -ENOSPC:
+ status = 0;
+ if (!desc->plus)
+ break;
+ while (!nfs_readdir_entry_decode(desc, entry, &stream))
+ ;
}

if (page != *arrays)
--
2.35.1