18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  linux/fs/9p/vfs_dentry.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * This file contians vfs dentry ops for the 9P2000 protocol.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
88c2ecf20Sopenharmony_ci *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/module.h>
128c2ecf20Sopenharmony_ci#include <linux/errno.h>
138c2ecf20Sopenharmony_ci#include <linux/fs.h>
148c2ecf20Sopenharmony_ci#include <linux/file.h>
158c2ecf20Sopenharmony_ci#include <linux/pagemap.h>
168c2ecf20Sopenharmony_ci#include <linux/stat.h>
178c2ecf20Sopenharmony_ci#include <linux/string.h>
188c2ecf20Sopenharmony_ci#include <linux/inet.h>
198c2ecf20Sopenharmony_ci#include <linux/namei.h>
208c2ecf20Sopenharmony_ci#include <linux/idr.h>
218c2ecf20Sopenharmony_ci#include <linux/sched.h>
228c2ecf20Sopenharmony_ci#include <linux/slab.h>
238c2ecf20Sopenharmony_ci#include <net/9p/9p.h>
248c2ecf20Sopenharmony_ci#include <net/9p/client.h>
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#include "v9fs.h"
278c2ecf20Sopenharmony_ci#include "v9fs_vfs.h"
288c2ecf20Sopenharmony_ci#include "fid.h"
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci/**
318c2ecf20Sopenharmony_ci * v9fs_cached_dentry_delete - called when dentry refcount equals 0
328c2ecf20Sopenharmony_ci * @dentry:  dentry in question
338c2ecf20Sopenharmony_ci *
348c2ecf20Sopenharmony_ci */
358c2ecf20Sopenharmony_cistatic int v9fs_cached_dentry_delete(const struct dentry *dentry)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	p9_debug(P9_DEBUG_VFS, " dentry: %pd (%p)\n",
388c2ecf20Sopenharmony_ci		 dentry, dentry);
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	/* Don't cache negative dentries */
418c2ecf20Sopenharmony_ci	if (d_really_is_negative(dentry))
428c2ecf20Sopenharmony_ci		return 1;
438c2ecf20Sopenharmony_ci	return 0;
448c2ecf20Sopenharmony_ci}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci/**
478c2ecf20Sopenharmony_ci * v9fs_dentry_release - called when dentry is going to be freed
488c2ecf20Sopenharmony_ci * @dentry:  dentry that is being release
498c2ecf20Sopenharmony_ci *
508c2ecf20Sopenharmony_ci */
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistatic void v9fs_dentry_release(struct dentry *dentry)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	struct hlist_node *p, *n;
558c2ecf20Sopenharmony_ci	p9_debug(P9_DEBUG_VFS, " dentry: %pd (%p)\n",
568c2ecf20Sopenharmony_ci		 dentry, dentry);
578c2ecf20Sopenharmony_ci	hlist_for_each_safe(p, n, (struct hlist_head *)&dentry->d_fsdata)
588c2ecf20Sopenharmony_ci		p9_client_clunk(hlist_entry(p, struct p9_fid, dlist));
598c2ecf20Sopenharmony_ci	dentry->d_fsdata = NULL;
608c2ecf20Sopenharmony_ci}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_cistatic int v9fs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
638c2ecf20Sopenharmony_ci{
648c2ecf20Sopenharmony_ci	struct p9_fid *fid;
658c2ecf20Sopenharmony_ci	struct inode *inode;
668c2ecf20Sopenharmony_ci	struct v9fs_inode *v9inode;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	if (flags & LOOKUP_RCU)
698c2ecf20Sopenharmony_ci		return -ECHILD;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	inode = d_inode(dentry);
728c2ecf20Sopenharmony_ci	if (!inode)
738c2ecf20Sopenharmony_ci		goto out_valid;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	v9inode = V9FS_I(inode);
768c2ecf20Sopenharmony_ci	if (v9inode->cache_validity & V9FS_INO_INVALID_ATTR) {
778c2ecf20Sopenharmony_ci		int retval;
788c2ecf20Sopenharmony_ci		struct v9fs_session_info *v9ses;
798c2ecf20Sopenharmony_ci		fid = v9fs_fid_lookup(dentry);
808c2ecf20Sopenharmony_ci		if (IS_ERR(fid))
818c2ecf20Sopenharmony_ci			return PTR_ERR(fid);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci		v9ses = v9fs_inode2v9ses(inode);
848c2ecf20Sopenharmony_ci		if (v9fs_proto_dotl(v9ses))
858c2ecf20Sopenharmony_ci			retval = v9fs_refresh_inode_dotl(fid, inode);
868c2ecf20Sopenharmony_ci		else
878c2ecf20Sopenharmony_ci			retval = v9fs_refresh_inode(fid, inode);
888c2ecf20Sopenharmony_ci		if (retval == -ENOENT)
898c2ecf20Sopenharmony_ci			return 0;
908c2ecf20Sopenharmony_ci		if (retval < 0)
918c2ecf20Sopenharmony_ci			return retval;
928c2ecf20Sopenharmony_ci	}
938c2ecf20Sopenharmony_ciout_valid:
948c2ecf20Sopenharmony_ci	return 1;
958c2ecf20Sopenharmony_ci}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ciconst struct dentry_operations v9fs_cached_dentry_operations = {
988c2ecf20Sopenharmony_ci	.d_revalidate = v9fs_lookup_revalidate,
998c2ecf20Sopenharmony_ci	.d_weak_revalidate = v9fs_lookup_revalidate,
1008c2ecf20Sopenharmony_ci	.d_delete = v9fs_cached_dentry_delete,
1018c2ecf20Sopenharmony_ci	.d_release = v9fs_dentry_release,
1028c2ecf20Sopenharmony_ci};
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ciconst struct dentry_operations v9fs_dentry_operations = {
1058c2ecf20Sopenharmony_ci	.d_delete = always_delete_dentry,
1068c2ecf20Sopenharmony_ci	.d_release = v9fs_dentry_release,
1078c2ecf20Sopenharmony_ci};
108