Commit 95ad37f9 authored by Frank van der Linden's avatar Frank van der Linden Committed by Trond Myklebust
Browse files

NFSv4.2: add client side xattr caching.



Implement client side caching for NFSv4.2 extended attributes. The cache
is a per-inode hashtable, with name/value entries. There is one special
entry for the listxattr cache.

NFS inodes have a pointer to a cache structure. The cache structure is
allocated on demand, freed when the cache is invalidated.

Memory shrinkers keep the size in check. Large entries (> PAGE_SIZE)
are collected by a separate shrinker, and freed more aggressively
than others.

Signed-off-by: default avatarFrank van der Linden <fllinden@amazon.com>
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
parent 012a211a
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -30,7 +30,7 @@ nfsv4-y := nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o nfs4super.o nfs4file.o
nfsv4-$(CONFIG_NFS_USE_LEGACY_DNS) += cache_lib.o
nfsv4-$(CONFIG_SYSCTL)	+= nfs4sysctl.o
nfsv4-$(CONFIG_NFS_V4_1)	+= pnfs.o pnfs_dev.o pnfs_nfs.o
nfsv4-$(CONFIG_NFS_V4_2)	+= nfs42proc.o
nfsv4-$(CONFIG_NFS_V4_2)	+= nfs42proc.o nfs42xattr.o

obj-$(CONFIG_PNFS_FILE_LAYOUT) += filelayout/
obj-$(CONFIG_PNFS_BLOCK) += blocklayout/
+8 −1
Original line number Diff line number Diff line
@@ -193,6 +193,7 @@ bool nfs_check_cache_invalid(struct inode *inode, unsigned long flags)

	return nfs_check_cache_invalid_not_delegated(inode, flags);
}
EXPORT_SYMBOL_GPL(nfs_check_cache_invalid);

static void nfs_set_cache_invalid(struct inode *inode, unsigned long flags)
{
@@ -234,11 +235,13 @@ static void nfs_zap_caches_locked(struct inode *inode)
					| NFS_INO_INVALID_DATA
					| NFS_INO_INVALID_ACCESS
					| NFS_INO_INVALID_ACL
					| NFS_INO_INVALID_XATTR
					| NFS_INO_REVAL_PAGECACHE);
	} else
		nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR
					| NFS_INO_INVALID_ACCESS
					| NFS_INO_INVALID_ACL
					| NFS_INO_INVALID_XATTR
					| NFS_INO_REVAL_PAGECACHE);
	nfs_zap_label_cache_locked(nfsi);
}
@@ -1897,7 +1900,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
			if (!(have_writers || have_delegation)) {
				invalid |= NFS_INO_INVALID_DATA
					| NFS_INO_INVALID_ACCESS
					| NFS_INO_INVALID_ACL;
					| NFS_INO_INVALID_ACL
					| NFS_INO_INVALID_XATTR;
				/* Force revalidate of all attributes */
				save_cache_validity |= NFS_INO_INVALID_CTIME
					| NFS_INO_INVALID_MTIME
@@ -2100,6 +2104,9 @@ struct inode *nfs_alloc_inode(struct super_block *sb)
#if IS_ENABLED(CONFIG_NFS_V4)
	nfsi->nfs4_acl = NULL;
#endif /* CONFIG_NFS_V4 */
#ifdef CONFIG_NFS_V4_2
	nfsi->xattr_cache = NULL;
#endif
	return &nfsi->vfs_inode;
}
EXPORT_SYMBOL_GPL(nfs_alloc_inode);
+12 −0
Original line number Diff line number Diff line
@@ -1182,6 +1182,18 @@ static ssize_t _nfs42_proc_getxattr(struct inode *inode, const char *name,
	if (ret < 0)
		return ret;

	/*
	 * Normally, the caching is done one layer up, but for successful
	 * RPCS, always cache the result here, even if the caller was
	 * just querying the length, or if the reply was too big for
	 * the caller. This avoids a second RPC in the case of the
	 * common query-alloc-retrieve cycle for xattrs.
	 *
	 * Note that xattr_len is always capped to XATTR_SIZE_MAX.
	 */

	nfs4_xattr_cache_add(inode, name, NULL, pages, res.xattr_len);

	if (buflen) {
		if (res.xattr_len > buflen)
			return -ERANGE;

fs/nfs/nfs42xattr.c

0 → 100644
+1083 −0

File added.

Preview size limit exceeded, changes collapsed.

+22 −0
Original line number Diff line number Diff line
@@ -626,12 +626,34 @@ static inline bool nfs4_state_match_open_stateid_other(const struct nfs4_state *
		nfs4_stateid_match_other(&state->open_stateid, stateid);
}

/* nfs42xattr.c */
#ifdef CONFIG_NFS_V4_2
extern int __init nfs4_xattr_cache_init(void);
extern void nfs4_xattr_cache_exit(void);
extern void nfs4_xattr_cache_add(struct inode *inode, const char *name,
				 const char *buf, struct page **pages,
				 ssize_t buflen);
extern void nfs4_xattr_cache_remove(struct inode *inode, const char *name);
extern ssize_t nfs4_xattr_cache_get(struct inode *inode, const char *name,
				char *buf, ssize_t buflen);
extern void nfs4_xattr_cache_set_list(struct inode *inode, const char *buf,
				      ssize_t buflen);
extern ssize_t nfs4_xattr_cache_list(struct inode *inode, char *buf,
				     ssize_t buflen);
extern void nfs4_xattr_cache_zap(struct inode *inode);
#else
static inline void nfs4_xattr_cache_zap(struct inode *inode)
{
}
#endif /* CONFIG_NFS_V4_2 */

#else /* CONFIG_NFS_V4 */

#define nfs4_close_state(a, b) do { } while (0)
#define nfs4_close_sync(a, b) do { } while (0)
#define nfs4_state_protect(a, b, c, d) do { } while (0)
#define nfs4_state_protect_write(a, b, c, d) do { } while (0)


#endif /* CONFIG_NFS_V4 */
#endif /* __LINUX_FS_NFS_NFS4_FS.H */
Loading