Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9ccee940 authored by Trond Myklebust's avatar Trond Myklebust
Browse files

Support statx() mask and query flags parameters



Support the query flags AT_STATX_FORCE_SYNC by forcing an attribute
revalidation, and AT_STATX_DONT_SYNC by returning cached attributes
only.

Use the mask to optimise away server revalidation for attributes
that are not being requested by the user.

Signed-off-by: default avatarTrond Myklebust <trond.myklebust@primarydata.com>
parent 8634ef5e
Loading
Loading
Loading
Loading
+39 −13
Original line number Diff line number Diff line
@@ -735,12 +735,20 @@ int nfs_getattr(const struct path *path, struct kstat *stat,
		u32 request_mask, unsigned int query_flags)
{
	struct inode *inode = d_inode(path->dentry);
	int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME;
	struct nfs_server *server = NFS_SERVER(inode);
	unsigned long cache_validity;
	int err = 0;
	bool force_sync = query_flags & AT_STATX_FORCE_SYNC;
	bool do_update = false;

	trace_nfs_getattr_enter(inode);

	if ((query_flags & AT_STATX_DONT_SYNC) && !force_sync)
		goto out_no_update;

	/* Flush out writes to the server in order to update c/mtime.  */
	if (S_ISREG(inode->i_mode)) {
	if ((request_mask & (STATX_CTIME|STATX_MTIME)) &&
			S_ISREG(inode->i_mode)) {
		err = filemap_write_and_wait(inode->i_mapping);
		if (err)
			goto out;
@@ -757,24 +765,42 @@ int nfs_getattr(const struct path *path, struct kstat *stat,
	 */
	if ((path->mnt->mnt_flags & MNT_NOATIME) ||
	    ((path->mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode)))
		need_atime = 0;

	if (need_atime || nfs_need_revalidate_inode(inode)) {
		struct nfs_server *server = NFS_SERVER(inode);

		request_mask &= ~STATX_ATIME;

	/* Is the user requesting attributes that might need revalidation? */
	if (!(request_mask & (STATX_MODE|STATX_NLINK|STATX_ATIME|STATX_CTIME|
					STATX_MTIME|STATX_UID|STATX_GID|
					STATX_SIZE|STATX_BLOCKS)))
		goto out_no_revalidate;

	/* Check whether the cached attributes are stale */
	do_update |= force_sync || nfs_attribute_cache_expired(inode);
	cache_validity = READ_ONCE(NFS_I(inode)->cache_validity);
	do_update |= cache_validity &
		(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_LABEL);
	if (request_mask & STATX_ATIME)
		do_update |= cache_validity & NFS_INO_INVALID_ATIME;
	if (request_mask & (STATX_CTIME|STATX_MTIME))
		do_update |= cache_validity & NFS_INO_REVAL_PAGECACHE;
	if (do_update) {
		/* Update the attribute cache */
		if (!(server->flags & NFS_MOUNT_NOAC))
			nfs_readdirplus_parent_cache_miss(path->dentry);
		else
			nfs_readdirplus_parent_cache_hit(path->dentry);
		err = __nfs_revalidate_inode(server, inode);
		if (err)
			goto out;
	} else
		nfs_readdirplus_parent_cache_hit(path->dentry);
	if (!err) {
out_no_revalidate:
	/* Only return attributes that were revalidated. */
	stat->result_mask &= request_mask;
out_no_update:
	generic_fillattr(inode, stat);
	stat->ino = nfs_compat_user_ino64(NFS_FILEID(inode));
	if (S_ISDIR(inode->i_mode))
		stat->blksize = NFS_SERVER(inode)->dtsize;
	}
out:
	trace_nfs_getattr_exit(inode, err);
	return err;