Skip to content

Commit

Permalink
cifs: find and use the dentry for cached non-root directories also
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Ronnie Sahlberg authored and Steve French committed Oct 13, 2022
1 parent ebe98f1 commit e4029e0
Showing 1 changed file with 49 additions and 14 deletions.
63 changes: 49 additions & 14 deletions fs/cifs/cached_dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* Copyright (c) 2022, Ronnie Sahlberg <lsahlber@redhat.com>
*/

#include <linux/namei.h>
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"
Expand Down Expand Up @@ -59,6 +60,44 @@ static struct cached_fid *find_or_create_cached_dir(struct cached_fids *cfids,
return cfid;
}

static struct dentry *
path_to_dentry(struct cifs_sb_info *cifs_sb, const char *path)
{
struct dentry *dentry;
const char *s, *p;
char sep;

sep = CIFS_DIR_SEP(cifs_sb);
dentry = dget(cifs_sb->root);
s = path;

do {
struct inode *dir = d_inode(dentry);
struct dentry *child;

if (!S_ISDIR(dir->i_mode)) {
dput(dentry);
dentry = ERR_PTR(-ENOTDIR);
break;
}

/* skip separators */
while (*s == sep)
s++;
if (!*s)
break;
p = s++;
/* next separator */
while (*s && *s != sep)
s++;

child = lookup_positive_unlocked(p, dentry, s - p);
dput(dentry);
dentry = child;
} while (!IS_ERR(dentry));
return dentry;
}

/*
* Open the and cache a directory handle.
* If error then *cfid is not initialized.
Expand Down Expand Up @@ -86,7 +125,6 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
struct cached_fid *cfid;
struct cached_fids *cfids;


if (tcon == NULL || tcon->cfids == NULL || tcon->nohandlecache ||
is_smb1_server(tcon->ses->server))
return -EOPNOTSUPP;
Expand All @@ -101,13 +139,6 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
if (cifs_sb->root == NULL)
return -ENOENT;

/*
* TODO: for better caching we need to find and use the dentry also
* for non-root directories.
*/
if (!path[0])
dentry = cifs_sb->root;

utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
if (!utf16_path)
return -ENOMEM;
Expand Down Expand Up @@ -199,12 +230,6 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
oparms.fid->mid = le64_to_cpu(o_rsp->hdr.MessageId);
#endif /* CIFS_DEBUG2 */

cfid->tcon = tcon;
if (dentry) {
cfid->dentry = dentry;
dget(dentry);
}
/* BB TBD check to see if oplock level check can be removed below */
if (o_rsp->OplockLevel != SMB2_OPLOCK_LEVEL_LEASE)
goto oshr_free;

Expand All @@ -223,6 +248,16 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
&rsp_iov[1], sizeof(struct smb2_file_all_info),
(char *)&cfid->file_all_info))
cfid->file_all_info_is_valid = true;

if (!path[0])
dentry = dget(cifs_sb->root);
else {
dentry = path_to_dentry(cifs_sb, path);
if (IS_ERR(dentry))
goto oshr_free;
}
cfid->dentry = dentry;
cfid->tcon = tcon;
cfid->time = jiffies;
cfid->is_open = true;
cfid->has_lease = true;
Expand Down

0 comments on commit e4029e0

Please sign in to comment.