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