xref: /openbmc/linux/fs/smb/client/cached_dir.c (revision ecc23d0a422a3118fcf6e4f0a46e17a6c2047b02)
138c8a9a5SSteve French // SPDX-License-Identifier: GPL-2.0
238c8a9a5SSteve French /*
338c8a9a5SSteve French  *  Functions to handle the cached directory entries
438c8a9a5SSteve French  *
538c8a9a5SSteve French  *  Copyright (c) 2022, Ronnie Sahlberg <lsahlber@redhat.com>
638c8a9a5SSteve French  */
738c8a9a5SSteve French 
838c8a9a5SSteve French #include <linux/namei.h>
938c8a9a5SSteve French #include "cifsglob.h"
1038c8a9a5SSteve French #include "cifsproto.h"
1138c8a9a5SSteve French #include "cifs_debug.h"
1238c8a9a5SSteve French #include "smb2proto.h"
1338c8a9a5SSteve French #include "cached_dir.h"
1438c8a9a5SSteve French 
1538c8a9a5SSteve French static struct cached_fid *init_cached_dir(const char *path);
1638c8a9a5SSteve French static void free_cached_dir(struct cached_fid *cfid);
1738c8a9a5SSteve French static void smb2_close_cached_fid(struct kref *ref);
18e95f3f74SPaulo Alcantara static void cfids_laundromat_worker(struct work_struct *work);
1938c8a9a5SSteve French 
2073934e53SPaul Aurich struct cached_dir_dentry {
2173934e53SPaul Aurich 	struct list_head entry;
2273934e53SPaul Aurich 	struct dentry *dentry;
2373934e53SPaul Aurich };
2473934e53SPaul Aurich 
find_or_create_cached_dir(struct cached_fids * cfids,const char * path,bool lookup_only,__u32 max_cached_dirs)2538c8a9a5SSteve French static struct cached_fid *find_or_create_cached_dir(struct cached_fids *cfids,
2638c8a9a5SSteve French 						    const char *path,
276a50d71dSSteve French 						    bool lookup_only,
286a50d71dSSteve French 						    __u32 max_cached_dirs)
2938c8a9a5SSteve French {
3038c8a9a5SSteve French 	struct cached_fid *cfid;
3138c8a9a5SSteve French 
3238c8a9a5SSteve French 	spin_lock(&cfids->cfid_list_lock);
3338c8a9a5SSteve French 	list_for_each_entry(cfid, &cfids->entries, entry) {
3438c8a9a5SSteve French 		if (!strcmp(cfid->path, path)) {
3538c8a9a5SSteve French 			/*
3638c8a9a5SSteve French 			 * If it doesn't have a lease it is either not yet
3738c8a9a5SSteve French 			 * fully cached or it may be in the process of
3838c8a9a5SSteve French 			 * being deleted due to a lease break.
3938c8a9a5SSteve French 			 */
4093877b9aSPaulo Alcantara 			if (!cfid->time || !cfid->has_lease) {
4138c8a9a5SSteve French 				spin_unlock(&cfids->cfid_list_lock);
4238c8a9a5SSteve French 				return NULL;
4338c8a9a5SSteve French 			}
4438c8a9a5SSteve French 			kref_get(&cfid->refcount);
4538c8a9a5SSteve French 			spin_unlock(&cfids->cfid_list_lock);
4638c8a9a5SSteve French 			return cfid;
4738c8a9a5SSteve French 		}
4838c8a9a5SSteve French 	}
4938c8a9a5SSteve French 	if (lookup_only) {
5038c8a9a5SSteve French 		spin_unlock(&cfids->cfid_list_lock);
5138c8a9a5SSteve French 		return NULL;
5238c8a9a5SSteve French 	}
536a50d71dSSteve French 	if (cfids->num_entries >= max_cached_dirs) {
5438c8a9a5SSteve French 		spin_unlock(&cfids->cfid_list_lock);
5538c8a9a5SSteve French 		return NULL;
5638c8a9a5SSteve French 	}
5738c8a9a5SSteve French 	cfid = init_cached_dir(path);
5838c8a9a5SSteve French 	if (cfid == NULL) {
5938c8a9a5SSteve French 		spin_unlock(&cfids->cfid_list_lock);
6038c8a9a5SSteve French 		return NULL;
6138c8a9a5SSteve French 	}
6238c8a9a5SSteve French 	cfid->cfids = cfids;
6338c8a9a5SSteve French 	cfids->num_entries++;
6438c8a9a5SSteve French 	list_add(&cfid->entry, &cfids->entries);
6538c8a9a5SSteve French 	cfid->on_list = true;
6638c8a9a5SSteve French 	kref_get(&cfid->refcount);
6731fabf70SPaul Aurich 	/*
6831fabf70SPaul Aurich 	 * Set @cfid->has_lease to true during construction so that the lease
6931fabf70SPaul Aurich 	 * reference can be put in cached_dir_lease_break() due to a potential
7031fabf70SPaul Aurich 	 * lease break right after the request is sent or while @cfid is still
7131fabf70SPaul Aurich 	 * being cached, or if a reconnection is triggered during construction.
7231fabf70SPaul Aurich 	 * Concurrent processes won't be to use it yet due to @cfid->time being
7331fabf70SPaul Aurich 	 * zero.
7431fabf70SPaul Aurich 	 */
7531fabf70SPaul Aurich 	cfid->has_lease = true;
7631fabf70SPaul Aurich 
7738c8a9a5SSteve French 	spin_unlock(&cfids->cfid_list_lock);
7838c8a9a5SSteve French 	return cfid;
7938c8a9a5SSteve French }
8038c8a9a5SSteve French 
8138c8a9a5SSteve French static struct dentry *
path_to_dentry(struct cifs_sb_info * cifs_sb,const char * path)8238c8a9a5SSteve French path_to_dentry(struct cifs_sb_info *cifs_sb, const char *path)
8338c8a9a5SSteve French {
8438c8a9a5SSteve French 	struct dentry *dentry;
8538c8a9a5SSteve French 	const char *s, *p;
8638c8a9a5SSteve French 	char sep;
8738c8a9a5SSteve French 
8838c8a9a5SSteve French 	sep = CIFS_DIR_SEP(cifs_sb);
8938c8a9a5SSteve French 	dentry = dget(cifs_sb->root);
9038c8a9a5SSteve French 	s = path;
9138c8a9a5SSteve French 
9238c8a9a5SSteve French 	do {
9338c8a9a5SSteve French 		struct inode *dir = d_inode(dentry);
9438c8a9a5SSteve French 		struct dentry *child;
9538c8a9a5SSteve French 
9638c8a9a5SSteve French 		if (!S_ISDIR(dir->i_mode)) {
9738c8a9a5SSteve French 			dput(dentry);
9838c8a9a5SSteve French 			dentry = ERR_PTR(-ENOTDIR);
9938c8a9a5SSteve French 			break;
10038c8a9a5SSteve French 		}
10138c8a9a5SSteve French 
10238c8a9a5SSteve French 		/* skip separators */
10338c8a9a5SSteve French 		while (*s == sep)
10438c8a9a5SSteve French 			s++;
10538c8a9a5SSteve French 		if (!*s)
10638c8a9a5SSteve French 			break;
10738c8a9a5SSteve French 		p = s++;
10838c8a9a5SSteve French 		/* next separator */
10938c8a9a5SSteve French 		while (*s && *s != sep)
11038c8a9a5SSteve French 			s++;
11138c8a9a5SSteve French 
11238c8a9a5SSteve French 		child = lookup_positive_unlocked(p, dentry, s - p);
11338c8a9a5SSteve French 		dput(dentry);
11438c8a9a5SSteve French 		dentry = child;
11538c8a9a5SSteve French 	} while (!IS_ERR(dentry));
11638c8a9a5SSteve French 	return dentry;
11738c8a9a5SSteve French }
11838c8a9a5SSteve French 
path_no_prefix(struct cifs_sb_info * cifs_sb,const char * path)11938c8a9a5SSteve French static const char *path_no_prefix(struct cifs_sb_info *cifs_sb,
12038c8a9a5SSteve French 				  const char *path)
12138c8a9a5SSteve French {
12238c8a9a5SSteve French 	size_t len = 0;
12338c8a9a5SSteve French 
12438c8a9a5SSteve French 	if (!*path)
12538c8a9a5SSteve French 		return path;
12638c8a9a5SSteve French 
12738c8a9a5SSteve French 	if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) &&
12838c8a9a5SSteve French 	    cifs_sb->prepath) {
12938c8a9a5SSteve French 		len = strlen(cifs_sb->prepath) + 1;
13038c8a9a5SSteve French 		if (unlikely(len > strlen(path)))
13138c8a9a5SSteve French 			return ERR_PTR(-EINVAL);
13238c8a9a5SSteve French 	}
13338c8a9a5SSteve French 	return path + len;
13438c8a9a5SSteve French }
13538c8a9a5SSteve French 
13638c8a9a5SSteve French /*
13738c8a9a5SSteve French  * Open the and cache a directory handle.
13838c8a9a5SSteve French  * If error then *cfid is not initialized.
13938c8a9a5SSteve French  */
open_cached_dir(unsigned int xid,struct cifs_tcon * tcon,const char * path,struct cifs_sb_info * cifs_sb,bool lookup_only,struct cached_fid ** ret_cfid)14038c8a9a5SSteve French int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
14138c8a9a5SSteve French 		    const char *path,
14238c8a9a5SSteve French 		    struct cifs_sb_info *cifs_sb,
14338c8a9a5SSteve French 		    bool lookup_only, struct cached_fid **ret_cfid)
14438c8a9a5SSteve French {
14538c8a9a5SSteve French 	struct cifs_ses *ses;
14638c8a9a5SSteve French 	struct TCP_Server_Info *server;
14738c8a9a5SSteve French 	struct cifs_open_parms oparms;
14838c8a9a5SSteve French 	struct smb2_create_rsp *o_rsp = NULL;
14938c8a9a5SSteve French 	struct smb2_query_info_rsp *qi_rsp = NULL;
15038c8a9a5SSteve French 	int resp_buftype[2];
15138c8a9a5SSteve French 	struct smb_rqst rqst[2];
15238c8a9a5SSteve French 	struct kvec rsp_iov[2];
15338c8a9a5SSteve French 	struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
15438c8a9a5SSteve French 	struct kvec qi_iov[1];
15538c8a9a5SSteve French 	int rc, flags = 0;
15638c8a9a5SSteve French 	__le16 *utf16_path = NULL;
15738c8a9a5SSteve French 	u8 oplock = SMB2_OPLOCK_LEVEL_II;
15838c8a9a5SSteve French 	struct cifs_fid *pfid;
15938c8a9a5SSteve French 	struct dentry *dentry = NULL;
16038c8a9a5SSteve French 	struct cached_fid *cfid;
16138c8a9a5SSteve French 	struct cached_fids *cfids;
16238c8a9a5SSteve French 	const char *npath;
163433042a9SShyam Prasad N 	int retries = 0, cur_sleep = 1;
16438c8a9a5SSteve French 
16538c8a9a5SSteve French 	if (tcon == NULL || tcon->cfids == NULL || tcon->nohandlecache ||
166238b351dSSteve French 	    is_smb1_server(tcon->ses->server) || (dir_cache_timeout == 0))
16738c8a9a5SSteve French 		return -EOPNOTSUPP;
16838c8a9a5SSteve French 
16938c8a9a5SSteve French 	ses = tcon->ses;
17038c8a9a5SSteve French 	cfids = tcon->cfids;
17138c8a9a5SSteve French 
17238c8a9a5SSteve French 	if (cifs_sb->root == NULL)
17338c8a9a5SSteve French 		return -ENOENT;
17438c8a9a5SSteve French 
175433042a9SShyam Prasad N replay_again:
176433042a9SShyam Prasad N 	/* reinitialize for possible replay */
177433042a9SShyam Prasad N 	flags = 0;
178433042a9SShyam Prasad N 	oplock = SMB2_OPLOCK_LEVEL_II;
179433042a9SShyam Prasad N 	server = cifs_pick_channel(ses);
180433042a9SShyam Prasad N 
181433042a9SShyam Prasad N 	if (!server->ops->new_lease_key)
182433042a9SShyam Prasad N 		return -EIO;
183433042a9SShyam Prasad N 
18438c8a9a5SSteve French 	utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
18538c8a9a5SSteve French 	if (!utf16_path)
18638c8a9a5SSteve French 		return -ENOMEM;
18738c8a9a5SSteve French 
1886a50d71dSSteve French 	cfid = find_or_create_cached_dir(cfids, path, lookup_only, tcon->max_cached_dirs);
18938c8a9a5SSteve French 	if (cfid == NULL) {
19038c8a9a5SSteve French 		kfree(utf16_path);
19138c8a9a5SSteve French 		return -ENOENT;
19238c8a9a5SSteve French 	}
19338c8a9a5SSteve French 	/*
19431fabf70SPaul Aurich 	 * Return cached fid if it is valid (has a lease and has a time).
19531fabf70SPaul Aurich 	 * Otherwise, it is either a new entry or laundromat worker removed it
19631fabf70SPaul Aurich 	 * from @cfids->entries.  Caller will put last reference if the latter.
19738c8a9a5SSteve French 	 */
19881ba1095SPaulo Alcantara 	spin_lock(&cfids->cfid_list_lock);
19931fabf70SPaul Aurich 	if (cfid->has_lease && cfid->time) {
20081ba1095SPaulo Alcantara 		spin_unlock(&cfids->cfid_list_lock);
20138c8a9a5SSteve French 		*ret_cfid = cfid;
20238c8a9a5SSteve French 		kfree(utf16_path);
20338c8a9a5SSteve French 		return 0;
20438c8a9a5SSteve French 	}
20581ba1095SPaulo Alcantara 	spin_unlock(&cfids->cfid_list_lock);
20638c8a9a5SSteve French 
20738c8a9a5SSteve French 	/*
20838c8a9a5SSteve French 	 * Skip any prefix paths in @path as lookup_positive_unlocked() ends up
20938c8a9a5SSteve French 	 * calling ->lookup() which already adds those through
21038c8a9a5SSteve French 	 * build_path_from_dentry().  Also, do it earlier as we might reconnect
21138c8a9a5SSteve French 	 * below when trying to send compounded request and then potentially
21238c8a9a5SSteve French 	 * having a different prefix path (e.g. after DFS failover).
21338c8a9a5SSteve French 	 */
21438c8a9a5SSteve French 	npath = path_no_prefix(cifs_sb, path);
21538c8a9a5SSteve French 	if (IS_ERR(npath)) {
21638c8a9a5SSteve French 		rc = PTR_ERR(npath);
21793877b9aSPaulo Alcantara 		goto out;
21838c8a9a5SSteve French 	}
21938c8a9a5SSteve French 
22093877b9aSPaulo Alcantara 	if (!npath[0]) {
22193877b9aSPaulo Alcantara 		dentry = dget(cifs_sb->root);
22293877b9aSPaulo Alcantara 	} else {
22393877b9aSPaulo Alcantara 		dentry = path_to_dentry(cifs_sb, npath);
22493877b9aSPaulo Alcantara 		if (IS_ERR(dentry)) {
22593877b9aSPaulo Alcantara 			rc = -ENOENT;
22693877b9aSPaulo Alcantara 			goto out;
22793877b9aSPaulo Alcantara 		}
22893877b9aSPaulo Alcantara 	}
22993877b9aSPaulo Alcantara 	cfid->dentry = dentry;
230*625e2357SPaul Aurich 	cfid->tcon = tcon;
23193877b9aSPaulo Alcantara 
23238c8a9a5SSteve French 	/*
23338c8a9a5SSteve French 	 * We do not hold the lock for the open because in case
23438c8a9a5SSteve French 	 * SMB2_open needs to reconnect.
23538c8a9a5SSteve French 	 * This is safe because no other thread will be able to get a ref
23638c8a9a5SSteve French 	 * to the cfid until we have finished opening the file and (possibly)
23738c8a9a5SSteve French 	 * acquired a lease.
23838c8a9a5SSteve French 	 */
23938c8a9a5SSteve French 	if (smb3_encryption_required(tcon))
24038c8a9a5SSteve French 		flags |= CIFS_TRANSFORM_REQ;
24138c8a9a5SSteve French 
24238c8a9a5SSteve French 	pfid = &cfid->fid;
24338c8a9a5SSteve French 	server->ops->new_lease_key(pfid);
24438c8a9a5SSteve French 
24538c8a9a5SSteve French 	memset(rqst, 0, sizeof(rqst));
24638c8a9a5SSteve French 	resp_buftype[0] = resp_buftype[1] = CIFS_NO_BUFFER;
24738c8a9a5SSteve French 	memset(rsp_iov, 0, sizeof(rsp_iov));
24838c8a9a5SSteve French 
24938c8a9a5SSteve French 	/* Open */
25038c8a9a5SSteve French 	memset(&open_iov, 0, sizeof(open_iov));
25138c8a9a5SSteve French 	rqst[0].rq_iov = open_iov;
25238c8a9a5SSteve French 	rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
25338c8a9a5SSteve French 
25438c8a9a5SSteve French 	oparms = (struct cifs_open_parms) {
25538c8a9a5SSteve French 		.tcon = tcon,
25638c8a9a5SSteve French 		.path = path,
25738c8a9a5SSteve French 		.create_options = cifs_create_options(cifs_sb, CREATE_NOT_FILE),
258da291179SEugene Korenevsky 		.desired_access =  FILE_READ_DATA | FILE_READ_ATTRIBUTES |
259da291179SEugene Korenevsky 				   FILE_READ_EA,
26038c8a9a5SSteve French 		.disposition = FILE_OPEN,
26138c8a9a5SSteve French 		.fid = pfid,
2621b5f2928SSteve French 		.replay = !!(retries),
26338c8a9a5SSteve French 	};
26438c8a9a5SSteve French 
26538c8a9a5SSteve French 	rc = SMB2_open_init(tcon, server,
26638c8a9a5SSteve French 			    &rqst[0], &oplock, &oparms, utf16_path);
26738c8a9a5SSteve French 	if (rc)
26838c8a9a5SSteve French 		goto oshr_free;
26938c8a9a5SSteve French 	smb2_set_next_command(tcon, &rqst[0]);
27038c8a9a5SSteve French 
27138c8a9a5SSteve French 	memset(&qi_iov, 0, sizeof(qi_iov));
27238c8a9a5SSteve French 	rqst[1].rq_iov = qi_iov;
27338c8a9a5SSteve French 	rqst[1].rq_nvec = 1;
27438c8a9a5SSteve French 
27538c8a9a5SSteve French 	rc = SMB2_query_info_init(tcon, server,
27638c8a9a5SSteve French 				  &rqst[1], COMPOUND_FID,
27738c8a9a5SSteve French 				  COMPOUND_FID, FILE_ALL_INFORMATION,
27838c8a9a5SSteve French 				  SMB2_O_INFO_FILE, 0,
27938c8a9a5SSteve French 				  sizeof(struct smb2_file_all_info) +
28038c8a9a5SSteve French 				  PATH_MAX * 2, 0, NULL);
28138c8a9a5SSteve French 	if (rc)
28238c8a9a5SSteve French 		goto oshr_free;
28338c8a9a5SSteve French 
28438c8a9a5SSteve French 	smb2_set_related(&rqst[1]);
28538c8a9a5SSteve French 
286433042a9SShyam Prasad N 	if (retries) {
287433042a9SShyam Prasad N 		smb2_set_replay(server, &rqst[0]);
288433042a9SShyam Prasad N 		smb2_set_replay(server, &rqst[1]);
289433042a9SShyam Prasad N 	}
290433042a9SShyam Prasad N 
29138c8a9a5SSteve French 	rc = compound_send_recv(xid, ses, server,
29238c8a9a5SSteve French 				flags, 2, rqst,
29338c8a9a5SSteve French 				resp_buftype, rsp_iov);
29438c8a9a5SSteve French 	if (rc) {
29538c8a9a5SSteve French 		if (rc == -EREMCHG) {
29638c8a9a5SSteve French 			tcon->need_reconnect = true;
29738c8a9a5SSteve French 			pr_warn_once("server share %s deleted\n",
29838c8a9a5SSteve French 				     tcon->tree_name);
29938c8a9a5SSteve French 		}
30038c8a9a5SSteve French 		goto oshr_free;
30138c8a9a5SSteve French 	}
30238c8a9a5SSteve French 	cfid->is_open = true;
30338c8a9a5SSteve French 
30493877b9aSPaulo Alcantara 	spin_lock(&cfids->cfid_list_lock);
30593877b9aSPaulo Alcantara 
30638c8a9a5SSteve French 	o_rsp = (struct smb2_create_rsp *)rsp_iov[0].iov_base;
30738c8a9a5SSteve French 	oparms.fid->persistent_fid = o_rsp->PersistentFileId;
30838c8a9a5SSteve French 	oparms.fid->volatile_fid = o_rsp->VolatileFileId;
30938c8a9a5SSteve French #ifdef CONFIG_CIFS_DEBUG2
31038c8a9a5SSteve French 	oparms.fid->mid = le64_to_cpu(o_rsp->hdr.MessageId);
31138c8a9a5SSteve French #endif /* CIFS_DEBUG2 */
31238c8a9a5SSteve French 
31317a0f64cSPaulo Alcantara 
31493877b9aSPaulo Alcantara 	if (o_rsp->OplockLevel != SMB2_OPLOCK_LEVEL_LEASE) {
31593877b9aSPaulo Alcantara 		spin_unlock(&cfids->cfid_list_lock);
31617a0f64cSPaulo Alcantara 		rc = -EINVAL;
31717a0f64cSPaulo Alcantara 		goto oshr_free;
31817a0f64cSPaulo Alcantara 	}
31917a0f64cSPaulo Alcantara 
32017a0f64cSPaulo Alcantara 	rc = smb2_parse_contexts(server, rsp_iov,
32117a0f64cSPaulo Alcantara 				 &oparms.fid->epoch,
32217a0f64cSPaulo Alcantara 				 oparms.fid->lease_key,
32317a0f64cSPaulo Alcantara 				 &oplock, NULL, NULL);
32417a0f64cSPaulo Alcantara 	if (rc) {
32517a0f64cSPaulo Alcantara 		spin_unlock(&cfids->cfid_list_lock);
32638c8a9a5SSteve French 		goto oshr_free;
32793877b9aSPaulo Alcantara 	}
32838c8a9a5SSteve French 
32917a0f64cSPaulo Alcantara 	rc = -EINVAL;
33093877b9aSPaulo Alcantara 	if (!(oplock & SMB2_LEASE_READ_CACHING_HE)) {
33193877b9aSPaulo Alcantara 		spin_unlock(&cfids->cfid_list_lock);
33238c8a9a5SSteve French 		goto oshr_free;
33393877b9aSPaulo Alcantara 	}
33438c8a9a5SSteve French 	qi_rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base;
33593877b9aSPaulo Alcantara 	if (le32_to_cpu(qi_rsp->OutputBufferLength) < sizeof(struct smb2_file_all_info)) {
33693877b9aSPaulo Alcantara 		spin_unlock(&cfids->cfid_list_lock);
33738c8a9a5SSteve French 		goto oshr_free;
33893877b9aSPaulo Alcantara 	}
33938c8a9a5SSteve French 	if (!smb2_validate_and_copy_iov(
34038c8a9a5SSteve French 				le16_to_cpu(qi_rsp->OutputBufferOffset),
34138c8a9a5SSteve French 				sizeof(struct smb2_file_all_info),
34238c8a9a5SSteve French 				&rsp_iov[1], sizeof(struct smb2_file_all_info),
34338c8a9a5SSteve French 				(char *)&cfid->file_all_info))
34438c8a9a5SSteve French 		cfid->file_all_info_is_valid = true;
34538c8a9a5SSteve French 
34638c8a9a5SSteve French 	cfid->time = jiffies;
34781ba1095SPaulo Alcantara 	spin_unlock(&cfids->cfid_list_lock);
34893877b9aSPaulo Alcantara 	/* At this point the directory handle is fully cached */
34993877b9aSPaulo Alcantara 	rc = 0;
35038c8a9a5SSteve French 
35138c8a9a5SSteve French oshr_free:
35238c8a9a5SSteve French 	SMB2_open_free(&rqst[0]);
35338c8a9a5SSteve French 	SMB2_query_info_free(&rqst[1]);
35438c8a9a5SSteve French 	free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
35538c8a9a5SSteve French 	free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
356791f8330SPaul Aurich out:
35781ba1095SPaulo Alcantara 	if (rc) {
35893877b9aSPaulo Alcantara 		spin_lock(&cfids->cfid_list_lock);
35938c8a9a5SSteve French 		if (cfid->on_list) {
36038c8a9a5SSteve French 			list_del(&cfid->entry);
36138c8a9a5SSteve French 			cfid->on_list = false;
36238c8a9a5SSteve French 			cfids->num_entries--;
36338c8a9a5SSteve French 		}
36493877b9aSPaulo Alcantara 		if (cfid->has_lease) {
36581ba1095SPaulo Alcantara 			/*
36681ba1095SPaulo Alcantara 			 * We are guaranteed to have two references at this
36781ba1095SPaulo Alcantara 			 * point. One for the caller and one for a potential
368791f8330SPaul Aurich 			 * lease. Release one here, and the second below.
36981ba1095SPaulo Alcantara 			 */
37093877b9aSPaulo Alcantara 			cfid->has_lease = false;
37181ba1095SPaulo Alcantara 			kref_put(&cfid->refcount, smb2_close_cached_fid);
37281ba1095SPaulo Alcantara 		}
37338c8a9a5SSteve French 		spin_unlock(&cfids->cfid_list_lock);
374791f8330SPaul Aurich 
375791f8330SPaul Aurich 		kref_put(&cfid->refcount, smb2_close_cached_fid);
37693877b9aSPaulo Alcantara 	} else {
37738c8a9a5SSteve French 		*ret_cfid = cfid;
37838c8a9a5SSteve French 		atomic_inc(&tcon->num_remote_opens);
37938c8a9a5SSteve French 	}
38093877b9aSPaulo Alcantara 	kfree(utf16_path);
381f642fcf3SShyam Prasad N 
382433042a9SShyam Prasad N 	if (is_replayable_error(rc) &&
383433042a9SShyam Prasad N 	    smb2_should_replay(tcon, &retries, &cur_sleep))
384433042a9SShyam Prasad N 		goto replay_again;
385433042a9SShyam Prasad N 
38638c8a9a5SSteve French 	return rc;
38738c8a9a5SSteve French }
38838c8a9a5SSteve French 
open_cached_dir_by_dentry(struct cifs_tcon * tcon,struct dentry * dentry,struct cached_fid ** ret_cfid)38938c8a9a5SSteve French int open_cached_dir_by_dentry(struct cifs_tcon *tcon,
39038c8a9a5SSteve French 			      struct dentry *dentry,
39138c8a9a5SSteve French 			      struct cached_fid **ret_cfid)
39238c8a9a5SSteve French {
39338c8a9a5SSteve French 	struct cached_fid *cfid;
39438c8a9a5SSteve French 	struct cached_fids *cfids = tcon->cfids;
39538c8a9a5SSteve French 
39638c8a9a5SSteve French 	if (cfids == NULL)
39738c8a9a5SSteve French 		return -ENOENT;
39838c8a9a5SSteve French 
39938c8a9a5SSteve French 	spin_lock(&cfids->cfid_list_lock);
40038c8a9a5SSteve French 	list_for_each_entry(cfid, &cfids->entries, entry) {
40138c8a9a5SSteve French 		if (dentry && cfid->dentry == dentry) {
402ebe0f8dcSPaul Aurich 			cifs_dbg(FYI, "found a cached file handle by dentry\n");
40338c8a9a5SSteve French 			kref_get(&cfid->refcount);
40438c8a9a5SSteve French 			*ret_cfid = cfid;
40538c8a9a5SSteve French 			spin_unlock(&cfids->cfid_list_lock);
40638c8a9a5SSteve French 			return 0;
40738c8a9a5SSteve French 		}
40838c8a9a5SSteve French 	}
40938c8a9a5SSteve French 	spin_unlock(&cfids->cfid_list_lock);
41038c8a9a5SSteve French 	return -ENOENT;
41138c8a9a5SSteve French }
41238c8a9a5SSteve French 
41338c8a9a5SSteve French static void
smb2_close_cached_fid(struct kref * ref)41438c8a9a5SSteve French smb2_close_cached_fid(struct kref *ref)
41538c8a9a5SSteve French {
41638c8a9a5SSteve French 	struct cached_fid *cfid = container_of(ref, struct cached_fid,
41738c8a9a5SSteve French 					       refcount);
4186f17163bSRitvik Budhiraja 	int rc;
41938c8a9a5SSteve French 
42038c8a9a5SSteve French 	spin_lock(&cfid->cfids->cfid_list_lock);
42138c8a9a5SSteve French 	if (cfid->on_list) {
42238c8a9a5SSteve French 		list_del(&cfid->entry);
42338c8a9a5SSteve French 		cfid->on_list = false;
42438c8a9a5SSteve French 		cfid->cfids->num_entries--;
42538c8a9a5SSteve French 	}
42638c8a9a5SSteve French 	spin_unlock(&cfid->cfids->cfid_list_lock);
42738c8a9a5SSteve French 
42838c8a9a5SSteve French 	dput(cfid->dentry);
42938c8a9a5SSteve French 	cfid->dentry = NULL;
43038c8a9a5SSteve French 
43138c8a9a5SSteve French 	if (cfid->is_open) {
4326f17163bSRitvik Budhiraja 		rc = SMB2_close(0, cfid->tcon, cfid->fid.persistent_fid,
43338c8a9a5SSteve French 			   cfid->fid.volatile_fid);
43405eedb5aSSteve French 		if (rc) /* should we retry on -EBUSY or -EAGAIN? */
43505eedb5aSSteve French 			cifs_dbg(VFS, "close cached dir rc %d\n", rc);
43638c8a9a5SSteve French 	}
43738c8a9a5SSteve French 
43838c8a9a5SSteve French 	free_cached_dir(cfid);
43938c8a9a5SSteve French }
44038c8a9a5SSteve French 
drop_cached_dir_by_name(const unsigned int xid,struct cifs_tcon * tcon,const char * name,struct cifs_sb_info * cifs_sb)44138c8a9a5SSteve French void drop_cached_dir_by_name(const unsigned int xid, struct cifs_tcon *tcon,
44238c8a9a5SSteve French 			     const char *name, struct cifs_sb_info *cifs_sb)
44338c8a9a5SSteve French {
44438c8a9a5SSteve French 	struct cached_fid *cfid = NULL;
44538c8a9a5SSteve French 	int rc;
44638c8a9a5SSteve French 
44738c8a9a5SSteve French 	rc = open_cached_dir(xid, tcon, name, cifs_sb, true, &cfid);
44838c8a9a5SSteve French 	if (rc) {
44938c8a9a5SSteve French 		cifs_dbg(FYI, "no cached dir found for rmdir(%s)\n", name);
45038c8a9a5SSteve French 		return;
45138c8a9a5SSteve French 	}
45238c8a9a5SSteve French 	spin_lock(&cfid->cfids->cfid_list_lock);
45338c8a9a5SSteve French 	if (cfid->has_lease) {
45438c8a9a5SSteve French 		cfid->has_lease = false;
45538c8a9a5SSteve French 		kref_put(&cfid->refcount, smb2_close_cached_fid);
45638c8a9a5SSteve French 	}
45738c8a9a5SSteve French 	spin_unlock(&cfid->cfids->cfid_list_lock);
45838c8a9a5SSteve French 	close_cached_dir(cfid);
45938c8a9a5SSteve French }
46038c8a9a5SSteve French 
46138c8a9a5SSteve French 
close_cached_dir(struct cached_fid * cfid)46238c8a9a5SSteve French void close_cached_dir(struct cached_fid *cfid)
46338c8a9a5SSteve French {
46438c8a9a5SSteve French 	kref_put(&cfid->refcount, smb2_close_cached_fid);
46538c8a9a5SSteve French }
46638c8a9a5SSteve French 
46738c8a9a5SSteve French /*
46838c8a9a5SSteve French  * Called from cifs_kill_sb when we unmount a share
46938c8a9a5SSteve French  */
close_all_cached_dirs(struct cifs_sb_info * cifs_sb)47038c8a9a5SSteve French void close_all_cached_dirs(struct cifs_sb_info *cifs_sb)
47138c8a9a5SSteve French {
47238c8a9a5SSteve French 	struct rb_root *root = &cifs_sb->tlink_tree;
47338c8a9a5SSteve French 	struct rb_node *node;
47438c8a9a5SSteve French 	struct cached_fid *cfid;
47538c8a9a5SSteve French 	struct cifs_tcon *tcon;
47638c8a9a5SSteve French 	struct tcon_link *tlink;
47738c8a9a5SSteve French 	struct cached_fids *cfids;
47873934e53SPaul Aurich 	struct cached_dir_dentry *tmp_list, *q;
47973934e53SPaul Aurich 	LIST_HEAD(entry);
48038c8a9a5SSteve French 
48173934e53SPaul Aurich 	spin_lock(&cifs_sb->tlink_tree_lock);
48238c8a9a5SSteve French 	for (node = rb_first(root); node; node = rb_next(node)) {
48338c8a9a5SSteve French 		tlink = rb_entry(node, struct tcon_link, tl_rbnode);
48438c8a9a5SSteve French 		tcon = tlink_tcon(tlink);
48538c8a9a5SSteve French 		if (IS_ERR(tcon))
48638c8a9a5SSteve French 			continue;
48738c8a9a5SSteve French 		cfids = tcon->cfids;
48838c8a9a5SSteve French 		if (cfids == NULL)
48938c8a9a5SSteve French 			continue;
49073934e53SPaul Aurich 		spin_lock(&cfids->cfid_list_lock);
49138c8a9a5SSteve French 		list_for_each_entry(cfid, &cfids->entries, entry) {
49273934e53SPaul Aurich 			tmp_list = kmalloc(sizeof(*tmp_list), GFP_ATOMIC);
49373934e53SPaul Aurich 			if (tmp_list == NULL)
49473934e53SPaul Aurich 				break;
49573934e53SPaul Aurich 			spin_lock(&cfid->fid_lock);
49673934e53SPaul Aurich 			tmp_list->dentry = cfid->dentry;
49738c8a9a5SSteve French 			cfid->dentry = NULL;
49873934e53SPaul Aurich 			spin_unlock(&cfid->fid_lock);
49973934e53SPaul Aurich 
50073934e53SPaul Aurich 			list_add_tail(&tmp_list->entry, &entry);
50138c8a9a5SSteve French 		}
50273934e53SPaul Aurich 		spin_unlock(&cfids->cfid_list_lock);
50338c8a9a5SSteve French 	}
50473934e53SPaul Aurich 	spin_unlock(&cifs_sb->tlink_tree_lock);
50573934e53SPaul Aurich 
50673934e53SPaul Aurich 	list_for_each_entry_safe(tmp_list, q, &entry, entry) {
50773934e53SPaul Aurich 		list_del(&tmp_list->entry);
50873934e53SPaul Aurich 		dput(tmp_list->dentry);
50973934e53SPaul Aurich 		kfree(tmp_list);
51073934e53SPaul Aurich 	}
51173934e53SPaul Aurich 
51273934e53SPaul Aurich 	/* Flush any pending work that will drop dentries */
51373934e53SPaul Aurich 	flush_workqueue(cfid_put_wq);
51438c8a9a5SSteve French }
51538c8a9a5SSteve French 
51638c8a9a5SSteve French /*
51738c8a9a5SSteve French  * Invalidate all cached dirs when a TCON has been reset
51838c8a9a5SSteve French  * due to a session loss.
51938c8a9a5SSteve French  */
invalidate_all_cached_dirs(struct cifs_tcon * tcon)52038c8a9a5SSteve French void invalidate_all_cached_dirs(struct cifs_tcon *tcon)
52138c8a9a5SSteve French {
52238c8a9a5SSteve French 	struct cached_fids *cfids = tcon->cfids;
52338c8a9a5SSteve French 	struct cached_fid *cfid, *q;
52438c8a9a5SSteve French 
5252da338ffSSteve French 	if (cfids == NULL)
5262da338ffSSteve French 		return;
5272da338ffSSteve French 
52873934e53SPaul Aurich 	/*
52973934e53SPaul Aurich 	 * Mark all the cfids as closed, and move them to the cfids->dying list.
53073934e53SPaul Aurich 	 * They'll be cleaned up later by cfids_invalidation_worker. Take
53173934e53SPaul Aurich 	 * a reference to each cfid during this process.
53273934e53SPaul Aurich 	 */
53338c8a9a5SSteve French 	spin_lock(&cfids->cfid_list_lock);
53438c8a9a5SSteve French 	list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
53573934e53SPaul Aurich 		list_move(&cfid->entry, &cfids->dying);
53638c8a9a5SSteve French 		cfids->num_entries--;
53738c8a9a5SSteve French 		cfid->is_open = false;
53838c8a9a5SSteve French 		cfid->on_list = false;
539791f8330SPaul Aurich 		if (cfid->has_lease) {
540791f8330SPaul Aurich 			/*
541791f8330SPaul Aurich 			 * The lease was never cancelled from the server,
542791f8330SPaul Aurich 			 * so steal that reference.
543791f8330SPaul Aurich 			 */
544791f8330SPaul Aurich 			cfid->has_lease = false;
545791f8330SPaul Aurich 		} else
54638c8a9a5SSteve French 			kref_get(&cfid->refcount);
54738c8a9a5SSteve French 	}
54838c8a9a5SSteve French 	/*
54973934e53SPaul Aurich 	 * Queue dropping of the dentries once locks have been dropped
55038c8a9a5SSteve French 	 */
55173934e53SPaul Aurich 	if (!list_empty(&cfids->dying))
55273934e53SPaul Aurich 		queue_work(cfid_put_wq, &cfids->invalidation_work);
55373934e53SPaul Aurich 	spin_unlock(&cfids->cfid_list_lock);
55438c8a9a5SSteve French }
55538c8a9a5SSteve French 
55638c8a9a5SSteve French static void
cached_dir_offload_close(struct work_struct * work)55773934e53SPaul Aurich cached_dir_offload_close(struct work_struct *work)
55838c8a9a5SSteve French {
55938c8a9a5SSteve French 	struct cached_fid *cfid = container_of(work,
56073934e53SPaul Aurich 				struct cached_fid, close_work);
56173934e53SPaul Aurich 	struct cifs_tcon *tcon = cfid->tcon;
56273934e53SPaul Aurich 
56373934e53SPaul Aurich 	WARN_ON(cfid->on_list);
56438c8a9a5SSteve French 
56538c8a9a5SSteve French 	kref_put(&cfid->refcount, smb2_close_cached_fid);
56673934e53SPaul Aurich 	cifs_put_tcon(tcon, netfs_trace_tcon_ref_put_cached_close);
56773934e53SPaul Aurich }
56873934e53SPaul Aurich 
56973934e53SPaul Aurich /*
57073934e53SPaul Aurich  * Release the cached directory's dentry, and then queue work to drop cached
57173934e53SPaul Aurich  * directory itself (closing on server if needed).
57273934e53SPaul Aurich  *
57373934e53SPaul Aurich  * Must be called with a reference to the cached_fid and a reference to the
57473934e53SPaul Aurich  * tcon.
57573934e53SPaul Aurich  */
cached_dir_put_work(struct work_struct * work)57673934e53SPaul Aurich static void cached_dir_put_work(struct work_struct *work)
57773934e53SPaul Aurich {
57873934e53SPaul Aurich 	struct cached_fid *cfid = container_of(work, struct cached_fid,
57973934e53SPaul Aurich 					       put_work);
58073934e53SPaul Aurich 	struct dentry *dentry;
58173934e53SPaul Aurich 
58273934e53SPaul Aurich 	spin_lock(&cfid->fid_lock);
58373934e53SPaul Aurich 	dentry = cfid->dentry;
58473934e53SPaul Aurich 	cfid->dentry = NULL;
58573934e53SPaul Aurich 	spin_unlock(&cfid->fid_lock);
58673934e53SPaul Aurich 
58773934e53SPaul Aurich 	dput(dentry);
58873934e53SPaul Aurich 	queue_work(serverclose_wq, &cfid->close_work);
58938c8a9a5SSteve French }
59038c8a9a5SSteve French 
cached_dir_lease_break(struct cifs_tcon * tcon,__u8 lease_key[16])59138c8a9a5SSteve French int cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16])
59238c8a9a5SSteve French {
59338c8a9a5SSteve French 	struct cached_fids *cfids = tcon->cfids;
59438c8a9a5SSteve French 	struct cached_fid *cfid;
59538c8a9a5SSteve French 
59638c8a9a5SSteve French 	if (cfids == NULL)
59738c8a9a5SSteve French 		return false;
59838c8a9a5SSteve French 
59938c8a9a5SSteve French 	spin_lock(&cfids->cfid_list_lock);
60038c8a9a5SSteve French 	list_for_each_entry(cfid, &cfids->entries, entry) {
60138c8a9a5SSteve French 		if (cfid->has_lease &&
60238c8a9a5SSteve French 		    !memcmp(lease_key,
60338c8a9a5SSteve French 			    cfid->fid.lease_key,
60438c8a9a5SSteve French 			    SMB2_LEASE_KEY_SIZE)) {
605791f8330SPaul Aurich 			cfid->has_lease = false;
60638c8a9a5SSteve French 			cfid->time = 0;
60738c8a9a5SSteve French 			/*
60838c8a9a5SSteve French 			 * We found a lease remove it from the list
60938c8a9a5SSteve French 			 * so no threads can access it.
61038c8a9a5SSteve French 			 */
61138c8a9a5SSteve French 			list_del(&cfid->entry);
61238c8a9a5SSteve French 			cfid->on_list = false;
61338c8a9a5SSteve French 			cfids->num_entries--;
61438c8a9a5SSteve French 
61573934e53SPaul Aurich 			++tcon->tc_count;
61673934e53SPaul Aurich 			trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count,
61773934e53SPaul Aurich 					    netfs_trace_tcon_ref_get_cached_lease_break);
61873934e53SPaul Aurich 			queue_work(cfid_put_wq, &cfid->put_work);
61938c8a9a5SSteve French 			spin_unlock(&cfids->cfid_list_lock);
62038c8a9a5SSteve French 			return true;
62138c8a9a5SSteve French 		}
62238c8a9a5SSteve French 	}
62338c8a9a5SSteve French 	spin_unlock(&cfids->cfid_list_lock);
62438c8a9a5SSteve French 	return false;
62538c8a9a5SSteve French }
62638c8a9a5SSteve French 
init_cached_dir(const char * path)62738c8a9a5SSteve French static struct cached_fid *init_cached_dir(const char *path)
62838c8a9a5SSteve French {
62938c8a9a5SSteve French 	struct cached_fid *cfid;
63038c8a9a5SSteve French 
63138c8a9a5SSteve French 	cfid = kzalloc(sizeof(*cfid), GFP_ATOMIC);
63238c8a9a5SSteve French 	if (!cfid)
63338c8a9a5SSteve French 		return NULL;
63438c8a9a5SSteve French 	cfid->path = kstrdup(path, GFP_ATOMIC);
63538c8a9a5SSteve French 	if (!cfid->path) {
63638c8a9a5SSteve French 		kfree(cfid);
63738c8a9a5SSteve French 		return NULL;
63838c8a9a5SSteve French 	}
63938c8a9a5SSteve French 
64073934e53SPaul Aurich 	INIT_WORK(&cfid->close_work, cached_dir_offload_close);
64173934e53SPaul Aurich 	INIT_WORK(&cfid->put_work, cached_dir_put_work);
64238c8a9a5SSteve French 	INIT_LIST_HEAD(&cfid->entry);
64338c8a9a5SSteve French 	INIT_LIST_HEAD(&cfid->dirents.entries);
64438c8a9a5SSteve French 	mutex_init(&cfid->dirents.de_mutex);
64538c8a9a5SSteve French 	spin_lock_init(&cfid->fid_lock);
64638c8a9a5SSteve French 	kref_init(&cfid->refcount);
64738c8a9a5SSteve French 	return cfid;
64838c8a9a5SSteve French }
64938c8a9a5SSteve French 
free_cached_dir(struct cached_fid * cfid)65038c8a9a5SSteve French static void free_cached_dir(struct cached_fid *cfid)
65138c8a9a5SSteve French {
65238c8a9a5SSteve French 	struct cached_dirent *dirent, *q;
65338c8a9a5SSteve French 
65473934e53SPaul Aurich 	WARN_ON(work_pending(&cfid->close_work));
65573934e53SPaul Aurich 	WARN_ON(work_pending(&cfid->put_work));
65673934e53SPaul Aurich 
65738c8a9a5SSteve French 	dput(cfid->dentry);
65838c8a9a5SSteve French 	cfid->dentry = NULL;
65938c8a9a5SSteve French 
66038c8a9a5SSteve French 	/*
66138c8a9a5SSteve French 	 * Delete all cached dirent names
66238c8a9a5SSteve French 	 */
66338c8a9a5SSteve French 	list_for_each_entry_safe(dirent, q, &cfid->dirents.entries, entry) {
66438c8a9a5SSteve French 		list_del(&dirent->entry);
66538c8a9a5SSteve French 		kfree(dirent->name);
66638c8a9a5SSteve French 		kfree(dirent);
66738c8a9a5SSteve French 	}
66838c8a9a5SSteve French 
66938c8a9a5SSteve French 	kfree(cfid->path);
67038c8a9a5SSteve French 	cfid->path = NULL;
67138c8a9a5SSteve French 	kfree(cfid);
67238c8a9a5SSteve French }
67338c8a9a5SSteve French 
cfids_invalidation_worker(struct work_struct * work)67473934e53SPaul Aurich static void cfids_invalidation_worker(struct work_struct *work)
67573934e53SPaul Aurich {
67673934e53SPaul Aurich 	struct cached_fids *cfids = container_of(work, struct cached_fids,
67773934e53SPaul Aurich 						 invalidation_work);
67873934e53SPaul Aurich 	struct cached_fid *cfid, *q;
67973934e53SPaul Aurich 	LIST_HEAD(entry);
68073934e53SPaul Aurich 
68173934e53SPaul Aurich 	spin_lock(&cfids->cfid_list_lock);
68273934e53SPaul Aurich 	/* move cfids->dying to the local list */
68373934e53SPaul Aurich 	list_cut_before(&entry, &cfids->dying, &cfids->dying);
68473934e53SPaul Aurich 	spin_unlock(&cfids->cfid_list_lock);
68573934e53SPaul Aurich 
68673934e53SPaul Aurich 	list_for_each_entry_safe(cfid, q, &entry, entry) {
68773934e53SPaul Aurich 		list_del(&cfid->entry);
68873934e53SPaul Aurich 		/* Drop the ref-count acquired in invalidate_all_cached_dirs */
68973934e53SPaul Aurich 		kref_put(&cfid->refcount, smb2_close_cached_fid);
69073934e53SPaul Aurich 	}
69173934e53SPaul Aurich }
69273934e53SPaul Aurich 
cfids_laundromat_worker(struct work_struct * work)693e95f3f74SPaulo Alcantara static void cfids_laundromat_worker(struct work_struct *work)
694d14de806SRonnie Sahlberg {
695e95f3f74SPaulo Alcantara 	struct cached_fids *cfids;
696d14de806SRonnie Sahlberg 	struct cached_fid *cfid, *q;
69773934e53SPaul Aurich 	struct dentry *dentry;
698e95f3f74SPaulo Alcantara 	LIST_HEAD(entry);
699d14de806SRonnie Sahlberg 
700e95f3f74SPaulo Alcantara 	cfids = container_of(work, struct cached_fids, laundromat_work.work);
701e95f3f74SPaulo Alcantara 
702d14de806SRonnie Sahlberg 	spin_lock(&cfids->cfid_list_lock);
703d14de806SRonnie Sahlberg 	list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
70481ba1095SPaulo Alcantara 		if (cfid->time &&
70581ba1095SPaulo Alcantara 		    time_after(jiffies, cfid->time + HZ * dir_cache_timeout)) {
70681ba1095SPaulo Alcantara 			cfid->on_list = false;
707e95f3f74SPaulo Alcantara 			list_move(&cfid->entry, &entry);
708d14de806SRonnie Sahlberg 			cfids->num_entries--;
709791f8330SPaul Aurich 			if (cfid->has_lease) {
710791f8330SPaul Aurich 				/*
711791f8330SPaul Aurich 				 * Our lease has not yet been cancelled from the
712791f8330SPaul Aurich 				 * server. Steal that reference.
713791f8330SPaul Aurich 				 */
714791f8330SPaul Aurich 				cfid->has_lease = false;
715791f8330SPaul Aurich 			} else
71681ba1095SPaulo Alcantara 				kref_get(&cfid->refcount);
717d14de806SRonnie Sahlberg 		}
718d14de806SRonnie Sahlberg 	}
719d14de806SRonnie Sahlberg 	spin_unlock(&cfids->cfid_list_lock);
720d14de806SRonnie Sahlberg 
721d14de806SRonnie Sahlberg 	list_for_each_entry_safe(cfid, q, &entry, entry) {
722d14de806SRonnie Sahlberg 		list_del(&cfid->entry);
72373934e53SPaul Aurich 
72473934e53SPaul Aurich 		spin_lock(&cfid->fid_lock);
72573934e53SPaul Aurich 		dentry = cfid->dentry;
72673934e53SPaul Aurich 		cfid->dentry = NULL;
72773934e53SPaul Aurich 		spin_unlock(&cfid->fid_lock);
72873934e53SPaul Aurich 
72973934e53SPaul Aurich 		dput(dentry);
73073934e53SPaul Aurich 		if (cfid->is_open) {
73173934e53SPaul Aurich 			spin_lock(&cifs_tcp_ses_lock);
73273934e53SPaul Aurich 			++cfid->tcon->tc_count;
73373934e53SPaul Aurich 			trace_smb3_tcon_ref(cfid->tcon->debug_id, cfid->tcon->tc_count,
73473934e53SPaul Aurich 					    netfs_trace_tcon_ref_get_cached_laundromat);
73573934e53SPaul Aurich 			spin_unlock(&cifs_tcp_ses_lock);
73673934e53SPaul Aurich 			queue_work(serverclose_wq, &cfid->close_work);
73773934e53SPaul Aurich 		} else
738d14de806SRonnie Sahlberg 			/*
739791f8330SPaul Aurich 			 * Drop the ref-count from above, either the lease-ref (if there
740791f8330SPaul Aurich 			 * was one) or the extra one acquired.
741d14de806SRonnie Sahlberg 			 */
74281ba1095SPaulo Alcantara 			kref_put(&cfid->refcount, smb2_close_cached_fid);
743d14de806SRonnie Sahlberg 	}
74473934e53SPaul Aurich 	queue_delayed_work(cfid_put_wq, &cfids->laundromat_work,
745e95f3f74SPaulo Alcantara 			   dir_cache_timeout * HZ);
746d14de806SRonnie Sahlberg }
747d14de806SRonnie Sahlberg 
init_cached_dirs(void)74838c8a9a5SSteve French struct cached_fids *init_cached_dirs(void)
74938c8a9a5SSteve French {
75038c8a9a5SSteve French 	struct cached_fids *cfids;
75138c8a9a5SSteve French 
75238c8a9a5SSteve French 	cfids = kzalloc(sizeof(*cfids), GFP_KERNEL);
75338c8a9a5SSteve French 	if (!cfids)
75438c8a9a5SSteve French 		return NULL;
75538c8a9a5SSteve French 	spin_lock_init(&cfids->cfid_list_lock);
75638c8a9a5SSteve French 	INIT_LIST_HEAD(&cfids->entries);
75773934e53SPaul Aurich 	INIT_LIST_HEAD(&cfids->dying);
758d14de806SRonnie Sahlberg 
75973934e53SPaul Aurich 	INIT_WORK(&cfids->invalidation_work, cfids_invalidation_worker);
760e95f3f74SPaulo Alcantara 	INIT_DELAYED_WORK(&cfids->laundromat_work, cfids_laundromat_worker);
76173934e53SPaul Aurich 	queue_delayed_work(cfid_put_wq, &cfids->laundromat_work,
762e95f3f74SPaulo Alcantara 			   dir_cache_timeout * HZ);
763e95f3f74SPaulo Alcantara 
76438c8a9a5SSteve French 	return cfids;
76538c8a9a5SSteve French }
76638c8a9a5SSteve French 
76738c8a9a5SSteve French /*
76838c8a9a5SSteve French  * Called from tconInfoFree when we are tearing down the tcon.
76938c8a9a5SSteve French  * There are no active users or open files/directories at this point.
77038c8a9a5SSteve French  */
free_cached_dirs(struct cached_fids * cfids)77138c8a9a5SSteve French void free_cached_dirs(struct cached_fids *cfids)
77238c8a9a5SSteve French {
77338c8a9a5SSteve French 	struct cached_fid *cfid, *q;
77438c8a9a5SSteve French 	LIST_HEAD(entry);
77538c8a9a5SSteve French 
7762da338ffSSteve French 	if (cfids == NULL)
7772da338ffSSteve French 		return;
7782da338ffSSteve French 
779e95f3f74SPaulo Alcantara 	cancel_delayed_work_sync(&cfids->laundromat_work);
78073934e53SPaul Aurich 	cancel_work_sync(&cfids->invalidation_work);
781d14de806SRonnie Sahlberg 
78238c8a9a5SSteve French 	spin_lock(&cfids->cfid_list_lock);
78338c8a9a5SSteve French 	list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
78438c8a9a5SSteve French 		cfid->on_list = false;
78538c8a9a5SSteve French 		cfid->is_open = false;
78638c8a9a5SSteve French 		list_move(&cfid->entry, &entry);
78738c8a9a5SSteve French 	}
78873934e53SPaul Aurich 	list_for_each_entry_safe(cfid, q, &cfids->dying, entry) {
78973934e53SPaul Aurich 		cfid->on_list = false;
79073934e53SPaul Aurich 		cfid->is_open = false;
79173934e53SPaul Aurich 		list_move(&cfid->entry, &entry);
79273934e53SPaul Aurich 	}
79338c8a9a5SSteve French 	spin_unlock(&cfids->cfid_list_lock);
79438c8a9a5SSteve French 
79538c8a9a5SSteve French 	list_for_each_entry_safe(cfid, q, &entry, entry) {
79638c8a9a5SSteve French 		list_del(&cfid->entry);
79738c8a9a5SSteve French 		free_cached_dir(cfid);
79838c8a9a5SSteve French 	}
79938c8a9a5SSteve French 
80038c8a9a5SSteve French 	kfree(cfids);
80138c8a9a5SSteve French }
802