Skip to content

Commit e4029e0

Browse files
Ronnie SahlbergSteve French
authored andcommitted
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 <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent ebe98f1 commit e4029e0

File tree

1 file changed

+49
-14
lines changed

1 file changed

+49
-14
lines changed

fs/cifs/cached_dir.c

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
* Copyright (c) 2022, Ronnie Sahlberg <[email protected]>
66
*/
77

8+
#include <linux/namei.h>
89
#include "cifsglob.h"
910
#include "cifsproto.h"
1011
#include "cifs_debug.h"
@@ -59,6 +60,44 @@ static struct cached_fid *find_or_create_cached_dir(struct cached_fids *cfids,
5960
return cfid;
6061
}
6162

63+
static struct dentry *
64+
path_to_dentry(struct cifs_sb_info *cifs_sb, const char *path)
65+
{
66+
struct dentry *dentry;
67+
const char *s, *p;
68+
char sep;
69+
70+
sep = CIFS_DIR_SEP(cifs_sb);
71+
dentry = dget(cifs_sb->root);
72+
s = path;
73+
74+
do {
75+
struct inode *dir = d_inode(dentry);
76+
struct dentry *child;
77+
78+
if (!S_ISDIR(dir->i_mode)) {
79+
dput(dentry);
80+
dentry = ERR_PTR(-ENOTDIR);
81+
break;
82+
}
83+
84+
/* skip separators */
85+
while (*s == sep)
86+
s++;
87+
if (!*s)
88+
break;
89+
p = s++;
90+
/* next separator */
91+
while (*s && *s != sep)
92+
s++;
93+
94+
child = lookup_positive_unlocked(p, dentry, s - p);
95+
dput(dentry);
96+
dentry = child;
97+
} while (!IS_ERR(dentry));
98+
return dentry;
99+
}
100+
62101
/*
63102
* Open the and cache a directory handle.
64103
* If error then *cfid is not initialized.
@@ -86,7 +125,6 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
86125
struct cached_fid *cfid;
87126
struct cached_fids *cfids;
88127

89-
90128
if (tcon == NULL || tcon->cfids == NULL || tcon->nohandlecache ||
91129
is_smb1_server(tcon->ses->server))
92130
return -EOPNOTSUPP;
@@ -101,13 +139,6 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
101139
if (cifs_sb->root == NULL)
102140
return -ENOENT;
103141

104-
/*
105-
* TODO: for better caching we need to find and use the dentry also
106-
* for non-root directories.
107-
*/
108-
if (!path[0])
109-
dentry = cifs_sb->root;
110-
111142
utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
112143
if (!utf16_path)
113144
return -ENOMEM;
@@ -199,12 +230,6 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
199230
oparms.fid->mid = le64_to_cpu(o_rsp->hdr.MessageId);
200231
#endif /* CIFS_DEBUG2 */
201232

202-
cfid->tcon = tcon;
203-
if (dentry) {
204-
cfid->dentry = dentry;
205-
dget(dentry);
206-
}
207-
/* BB TBD check to see if oplock level check can be removed below */
208233
if (o_rsp->OplockLevel != SMB2_OPLOCK_LEVEL_LEASE)
209234
goto oshr_free;
210235

@@ -223,6 +248,16 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
223248
&rsp_iov[1], sizeof(struct smb2_file_all_info),
224249
(char *)&cfid->file_all_info))
225250
cfid->file_all_info_is_valid = true;
251+
252+
if (!path[0])
253+
dentry = dget(cifs_sb->root);
254+
else {
255+
dentry = path_to_dentry(cifs_sb, path);
256+
if (IS_ERR(dentry))
257+
goto oshr_free;
258+
}
259+
cfid->dentry = dentry;
260+
cfid->tcon = tcon;
226261
cfid->time = jiffies;
227262
cfid->is_open = true;
228263
cfid->has_lease = true;

0 commit comments

Comments
 (0)