Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

cifs: find and use the dentry for cached non-root directories also

This allows us to use cached attributes for the entries in a cached
directory for as long as a lease is held on the directory itself.
Previously we have always allowed "used cached attributes for 1 second"
but this extends this to the lifetime of the lease as well as making the
caching safer.

Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com>
Signed-off-by: Steve French <stfrench@microsoft.com>

authored by

Ronnie Sahlberg and committed by
Steve French
e4029e07 ebe98f14

+49 -14
+49 -14
fs/cifs/cached_dir.c
··· 5 5 * Copyright (c) 2022, Ronnie Sahlberg <lsahlber@redhat.com> 6 6 */ 7 7 8 + #include <linux/namei.h> 8 9 #include "cifsglob.h" 9 10 #include "cifsproto.h" 10 11 #include "cifs_debug.h" ··· 60 59 return cfid; 61 60 } 62 61 62 + static struct dentry * 63 + path_to_dentry(struct cifs_sb_info *cifs_sb, const char *path) 64 + { 65 + struct dentry *dentry; 66 + const char *s, *p; 67 + char sep; 68 + 69 + sep = CIFS_DIR_SEP(cifs_sb); 70 + dentry = dget(cifs_sb->root); 71 + s = path; 72 + 73 + do { 74 + struct inode *dir = d_inode(dentry); 75 + struct dentry *child; 76 + 77 + if (!S_ISDIR(dir->i_mode)) { 78 + dput(dentry); 79 + dentry = ERR_PTR(-ENOTDIR); 80 + break; 81 + } 82 + 83 + /* skip separators */ 84 + while (*s == sep) 85 + s++; 86 + if (!*s) 87 + break; 88 + p = s++; 89 + /* next separator */ 90 + while (*s && *s != sep) 91 + s++; 92 + 93 + child = lookup_positive_unlocked(p, dentry, s - p); 94 + dput(dentry); 95 + dentry = child; 96 + } while (!IS_ERR(dentry)); 97 + return dentry; 98 + } 99 + 63 100 /* 64 101 * Open the and cache a directory handle. 65 102 * If error then *cfid is not initialized. ··· 125 86 struct cached_fid *cfid; 126 87 struct cached_fids *cfids; 127 88 128 - 129 89 if (tcon == NULL || tcon->cfids == NULL || tcon->nohandlecache || 130 90 is_smb1_server(tcon->ses->server)) 131 91 return -EOPNOTSUPP; ··· 138 100 139 101 if (cifs_sb->root == NULL) 140 102 return -ENOENT; 141 - 142 - /* 143 - * TODO: for better caching we need to find and use the dentry also 144 - * for non-root directories. 145 - */ 146 - if (!path[0]) 147 - dentry = cifs_sb->root; 148 103 149 104 utf16_path = cifs_convert_path_to_utf16(path, cifs_sb); 150 105 if (!utf16_path) ··· 230 199 oparms.fid->mid = le64_to_cpu(o_rsp->hdr.MessageId); 231 200 #endif /* CIFS_DEBUG2 */ 232 201 233 - cfid->tcon = tcon; 234 - if (dentry) { 235 - cfid->dentry = dentry; 236 - dget(dentry); 237 - } 238 - /* BB TBD check to see if oplock level check can be removed below */ 239 202 if (o_rsp->OplockLevel != SMB2_OPLOCK_LEVEL_LEASE) 240 203 goto oshr_free; 241 204 ··· 248 223 &rsp_iov[1], sizeof(struct smb2_file_all_info), 249 224 (char *)&cfid->file_all_info)) 250 225 cfid->file_all_info_is_valid = true; 226 + 227 + if (!path[0]) 228 + dentry = dget(cifs_sb->root); 229 + else { 230 + dentry = path_to_dentry(cifs_sb, path); 231 + if (IS_ERR(dentry)) 232 + goto oshr_free; 233 + } 234 + cfid->dentry = dentry; 235 + cfid->tcon = tcon; 251 236 cfid->time = jiffies; 252 237 cfid->is_open = true; 253 238 cfid->has_lease = true;