2016-08-24 17:27:11

by Benjamin Coddington

[permalink] [raw]
Subject: [PATCH] NFS: Don't invalidate directory mapping until attributes expire

Commit 311324ad1713666a6e803aecf0d4e1a136a5b34a ("NFS: Be more aggressive
in using readdirplus for 'ls -l' situations") removed the optimization
added by commit 07b5ce8ef2d87f1914054804720d6facbaa3f4ce ("NFS: Make nfs_readdir
revalidate less often") to bypass the revalidation of the directory mapping
on subsequent calls into nfs_readdir(). Add that optimization back here.

A directory modified once every second and containing 40k entries takes my
system around 80 seconds to list. With this patch, that time is reduced to
7 seconds.

Signed-off-by: Benjamin Coddington <[email protected]>
---
fs/nfs/dir.c | 13 +------------
1 file changed, 1 insertion(+), 12 deletions(-)

diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 19d93d0cd400..9a036dc6caa3 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -872,17 +872,6 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc)
goto out;
}

-static bool nfs_dir_mapping_need_revalidate(struct inode *dir)
-{
- struct nfs_inode *nfsi = NFS_I(dir);
-
- if (nfs_attribute_cache_expired(dir))
- return true;
- if (nfsi->cache_validity & NFS_INO_INVALID_DATA)
- return true;
- return false;
-}
-
/* The file offset position represents the dirent entry number. A
last cookie cache takes care of the common case of reading the
whole directory.
@@ -914,7 +903,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
desc->decode = NFS_PROTO(inode)->decode_dirent;
desc->plus = nfs_use_readdirplus(inode, ctx) ? 1 : 0;

- if (ctx->pos == 0 || nfs_dir_mapping_need_revalidate(inode))
+ if (ctx->pos == 0 || nfs_attribute_cache_expired(inode))
res = nfs_revalidate_mapping(inode, file->f_mapping);
if (res < 0)
goto out;
--
2.5.5



2016-08-24 17:49:59

by Trond Myklebust

[permalink] [raw]
Subject: Re: [PATCH] NFS: Don't invalidate directory mapping until attributes expire


> On Aug 24, 2016, at 13:27, Benjamin Coddington <[email protected]> wrot=
e:
>=20
> Commit 311324ad1713666a6e803aecf0d4e1a136a5b34a ("NFS: Be more aggressive
> in using readdirplus for 'ls -l' situations") removed the optimization
> added by commit 07b5ce8ef2d87f1914054804720d6facbaa3f4ce ("NFS: Make nfs_=
readdir
> revalidate less often") to bypass the revalidation of the directory mappi=
ng
> on subsequent calls into nfs_readdir(). Add that optimization back here.
>=20
> A directory modified once every second and containing 40k entries takes m=
y
> system around 80 seconds to list. With this patch, that time is reduced =
to
> 7 seconds.
>=20
> Signed-off-by: Benjamin Coddington <[email protected]>
> ---
> fs/nfs/dir.c | 13 +------------
> 1 file changed, 1 insertion(+), 12 deletions(-)
>=20
> diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
> index 19d93d0cd400..9a036dc6caa3 100644
> --- a/fs/nfs/dir.c
> +++ b/fs/nfs/dir.c
> @@ -872,17 +872,6 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc)
> =09goto out;
> }
>=20
> -static bool nfs_dir_mapping_need_revalidate(struct inode *dir)
> -{
> -=09struct nfs_inode *nfsi =3D NFS_I(dir);
> -
> -=09if (nfs_attribute_cache_expired(dir))
> -=09=09return true;
> -=09if (nfsi->cache_validity & NFS_INO_INVALID_DATA)
> -=09=09return true;
> -=09return false;
> -}
> -
> /* The file offset position represents the dirent entry number. A
> last cookie cache takes care of the common case of reading the
> whole directory.
> @@ -914,7 +903,7 @@ static int nfs_readdir(struct file *file, struct dir_=
context *ctx)
> =09desc->decode =3D NFS_PROTO(inode)->decode_dirent;
> =09desc->plus =3D nfs_use_readdirplus(inode, ctx) ? 1 : 0;
>=20
> -=09if (ctx->pos =3D=3D 0 || nfs_dir_mapping_need_revalidate(inode))
> +=09if (ctx->pos =3D=3D 0 || nfs_attribute_cache_expired(inode))
> =09=09res =3D nfs_revalidate_mapping(inode, file->f_mapping);
> =09if (res < 0)
> =09=09goto out;
> --=20
> 2.5.5
>=20

NACK.

As already discussed, this patch will break the functionality introduced in=
commit 311324ad1713. You need at least to ensure that we respect nfs_force=
_use_readdirplus().

2016-08-26 15:31:15

by Benjamin Coddington

[permalink] [raw]
Subject: Re: [PATCH] Don't invalidate directory mapping until attributes expire


>> On Aug 24, 2016, at 13:27, Benjamin Coddington <[email protected]>
>> wrote:
>>
>> Commit 311324ad1713666a6e803aecf0d4e1a136a5b34a ("NFS: Be more
>> aggressive
>> in using readdirplus for 'ls -l' situations") removed the
>> optimization
>> added by commit 07b5ce8ef2d87f1914054804720d6facbaa3f4ce ("NFS: Make
>> nfs_readdir
>> revalidate less often") to bypass the revalidation of the directory
>> mapping
>> on subsequent calls into nfs_readdir(). Add that optimization back
>> here.
>>
>> A directory modified once every second and containing 40k entries
>> takes my
>> system around 80 seconds to list. With this patch, that time is
>> reduced to
>> 7 seconds.
>>
>> Signed-off-by: Benjamin Coddington <[email protected]>
>> ---
>> fs/nfs/dir.c | 13 +------------
>> 1 file changed, 1 insertion(+), 12 deletions(-)
>>
>> diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
>> index 19d93d0cd400..9a036dc6caa3 100644
>> --- a/fs/nfs/dir.c
>> +++ b/fs/nfs/dir.c
>> @@ -872,17 +872,6 @@ int uncached_readdir(nfs_readdir_descriptor_t
>> *desc)
>> goto out;
>> }
>>
>> -static bool nfs_dir_mapping_need_revalidate(struct inode *dir)
>> -{
>> - struct nfs_inode *nfsi = NFS_I(dir);
>> -
>> - if (nfs_attribute_cache_expired(dir))
>> - return true;
>> - if (nfsi->cache_validity & NFS_INO_INVALID_DATA)
>> - return true;
>> - return false;
>> -}
>> -
>> /* The file offset position represents the dirent entry number. A
>> last cookie cache takes care of the common case of reading the
>> whole directory.
>> @@ -914,7 +903,7 @@ static int nfs_readdir(struct file *file, struct
>> dir_context *ctx)
>> desc->decode = NFS_PROTO(inode)->decode_dirent;
>> desc->plus = nfs_use_readdirplus(inode, ctx) ? 1 : 0;
>>
>> - if (ctx->pos == 0 || nfs_dir_mapping_need_revalidate(inode))
>> + if (ctx->pos == 0 || nfs_attribute_cache_expired(inode))
>> res = nfs_revalidate_mapping(inode, file->f_mapping);
>> if (res < 0)
>> goto out;
>> --
>> 2.5.5
>>
>
> NACK.
>
> As already discussed, this patch will break the functionality
> introduced
> in commit 311324ad1713. You need at least to ensure that we respect
> nfs_force_use_readdirplus().

Hi Trond, I did not correctly understand the case for commit
311324ad1713,
but re-reading the original posting thread has fixed me up. I'll send a
v2
that handles both cases.

Ben

2016-08-26 15:38:25

by Benjamin Coddington

[permalink] [raw]
Subject: [PATCH v2] NFS: Don't invalidate directory mapping until attributes expire

This approach uses another bit in the inode flags.. if that's too expensive
for this ls -l optimization, I will look for another way.

Change from v1:
Doesn't completely break the commit 311324ad1713 functionality.

8<-----------------------------------------------------------------------------

Commit 311324ad1713666a6e803aecf0d4e1a136a5b34a ("NFS: Be more aggressive
in using readdirplus for 'ls -l' situations") removed the optimization
added by commit 07b5ce8ef2d87f1914054804720d6facbaa3f4ce ("NFS: Make nfs_readdir
revalidate less often") to bypass the revalidation of the directory mapping
on subsequent calls into nfs_readdir(). Add that optimization back here.

A directory modified once every second and containing 40k entries takes my
system around 80 seconds to list. With this patch, that time is reduced to
7 seconds.

Signed-off-by: Benjamin Coddington <[email protected]>
---
fs/nfs/dir.c | 3 ++-
include/linux/nfs_fs.h | 1 +
2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 19d93d0cd400..88f5dd561025 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -477,6 +477,7 @@ void nfs_force_use_readdirplus(struct inode *dir)
{
if (!list_empty(&NFS_I(dir)->open_files)) {
nfs_advise_use_readdirplus(dir);
+ set_bit(NFS_INO_FORCE_RDPLUS, &NFS_I(dir)->flags);
nfs_zap_mapping(dir, dir->i_mapping);
}
}
@@ -878,7 +879,7 @@ static bool nfs_dir_mapping_need_revalidate(struct inode *dir)

if (nfs_attribute_cache_expired(dir))
return true;
- if (nfsi->cache_validity & NFS_INO_INVALID_DATA)
+ if (test_and_clear_bit(NFS_INO_FORCE_RDPLUS, &nfsi->flags))
return true;
return false;
}
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index d71278c3c5bd..729cddb7364f 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -211,6 +211,7 @@ struct nfs_inode {
#define NFS_INO_LAYOUTCOMMIT (9) /* layoutcommit required */
#define NFS_INO_LAYOUTCOMMITTING (10) /* layoutcommit inflight */
#define NFS_INO_LAYOUTSTATS (11) /* layoutstats inflight */
+#define NFS_INO_FORCE_RDPLUS (12) /* force readdirplus */

static inline struct nfs_inode *NFS_I(const struct inode *inode)
{
--
2.5.5


2016-11-18 13:28:34

by Benjamin Coddington

[permalink] [raw]
Subject: Re: [PATCH v2] Don't invalidate directory mapping until attributes expire

Any issues with this one?

On 26 Aug 2016, at 11:37, Benjamin Coddington wrote:

> This approach uses another bit in the inode flags.. if that's too
> expensive
> for this ls -l optimization, I will look for another way.
>
> Change from v1:
> Doesn't completely break the commit 311324ad1713 functionality.
>
> 8<-----------------------------------------------------------------------------
>
> Commit 311324ad1713666a6e803aecf0d4e1a136a5b34a ("NFS: Be more
> aggressive
> in using readdirplus for 'ls -l' situations") removed the optimization
> added by commit 07b5ce8ef2d87f1914054804720d6facbaa3f4ce ("NFS: Make
> nfs_readdir
> revalidate less often") to bypass the revalidation of the directory
> mapping
> on subsequent calls into nfs_readdir(). Add that optimization back
> here.
>
> A directory modified once every second and containing 40k entries
> takes my
> system around 80 seconds to list. With this patch, that time is
> reduced to
> 7 seconds.
>
> Signed-off-by: Benjamin Coddington <[email protected]>
> ---
> fs/nfs/dir.c | 3 ++-
> include/linux/nfs_fs.h | 1 +
> 2 files changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
> index 19d93d0cd400..88f5dd561025 100644
> --- a/fs/nfs/dir.c
> +++ b/fs/nfs/dir.c
> @@ -477,6 +477,7 @@ void nfs_force_use_readdirplus(struct inode *dir)
> {
> if (!list_empty(&NFS_I(dir)->open_files)) {
> nfs_advise_use_readdirplus(dir);
> + set_bit(NFS_INO_FORCE_RDPLUS, &NFS_I(dir)->flags);
> nfs_zap_mapping(dir, dir->i_mapping);
> }
> }
> @@ -878,7 +879,7 @@ static bool nfs_dir_mapping_need_revalidate(struct
> inode *dir)
>
> if (nfs_attribute_cache_expired(dir))
> return true;
> - if (nfsi->cache_validity & NFS_INO_INVALID_DATA)
> + if (test_and_clear_bit(NFS_INO_FORCE_RDPLUS, &nfsi->flags))
> return true;
> return false;
> }
> diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
> index d71278c3c5bd..729cddb7364f 100644
> --- a/include/linux/nfs_fs.h
> +++ b/include/linux/nfs_fs.h
> @@ -211,6 +211,7 @@ struct nfs_inode {
> #define NFS_INO_LAYOUTCOMMIT (9) /* layoutcommit required */
> #define NFS_INO_LAYOUTCOMMITTING (10) /* layoutcommit inflight */
> #define NFS_INO_LAYOUTSTATS (11) /* layoutstats inflight */
> +#define NFS_INO_FORCE_RDPLUS (12) /* force readdirplus */
>
> static inline struct nfs_inode *NFS_I(const struct inode *inode)
> {
> --
> 2.5.5
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs"
> in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html