summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/smb/client/cached_dir.c12
-rw-r--r--fs/smb/client/cifsglob.h2
-rw-r--r--fs/smb/client/inode.c9
-rw-r--r--fs/smb/client/smb1ops.c4
-rw-r--r--fs/smb/client/smb2inode.c12
-rw-r--r--fs/smb/client/smb2proto.h2
6 files changed, 27 insertions, 14 deletions
diff --git a/fs/smb/client/cached_dir.c b/fs/smb/client/cached_dir.c
index ad455c067cba..c9e3e71e3f1f 100644
--- a/fs/smb/client/cached_dir.c
+++ b/fs/smb/client/cached_dir.c
@@ -277,12 +277,9 @@ replay_again:
}
cfid->cfids = cfids;
- cfids->num_entries++;
- list_add(&cfid->entry, &cfids->entries);
+ cfid->tcon = tcon;
spin_unlock(&cfids->cfid_list_lock);
- pfid = &cfid->fid;
-
/*
* Skip any prefix paths in @path as lookup_noperm_positive_unlocked() ends up
* calling ->lookup() which already adds those through
@@ -310,6 +307,13 @@ replay_again:
cfid->tcon = tcon;
dentry = NULL;
+ spin_lock(&cfids->cfid_list_lock);
+ cfids->num_entries++;
+ list_add(&cfid->entry, &cfids->entries);
+ spin_unlock(&cfids->cfid_list_lock);
+
+ pfid = &cfid->fid;
+
/*
* We do not hold the lock for the open because in case
* SMB2_open needs to reconnect.
diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 9a86efddc3c4..08c8131c8018 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -401,7 +401,7 @@ struct smb_version_operations {
struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb,
const char *full_path,
- struct cifs_open_info_data *data);
+ struct cifs_open_info_data *data, bool is_dir);
/* query file data from the server */
int (*query_file_info)(const unsigned int xid, struct cifs_tcon *tcon,
struct cifsFileInfo *cfile, struct cifs_open_info_data *data);
diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
index f2eff1138ed0..35c5557d5ea1 100644
--- a/fs/smb/client/inode.c
+++ b/fs/smb/client/inode.c
@@ -1283,8 +1283,13 @@ static int cifs_get_fattr(struct cifs_open_info_data *data,
*/
if (!data) {
+ bool is_dir = false;
+
+ if (inode && *inode)
+ is_dir = S_ISDIR((*inode)->i_mode);
+
rc = server->ops->query_path_info(xid, tcon, cifs_sb,
- full_path, &tmp_data);
+ full_path, &tmp_data, is_dir);
data = &tmp_data;
}
@@ -1470,7 +1475,7 @@ static int smb311_posix_get_fattr(struct cifs_open_info_data *data,
*/
if (!data) {
rc = server->ops->query_path_info(xid, tcon, cifs_sb,
- full_path, &tmp_data);
+ full_path, &tmp_data, false);
data = &tmp_data;
}
diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c
index a02d41d1ce4a..d964bc9c2823 100644
--- a/fs/smb/client/smb1ops.c
+++ b/fs/smb/client/smb1ops.c
@@ -543,7 +543,7 @@ static int cifs_query_path_info(const unsigned int xid,
struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb,
const char *full_path,
- struct cifs_open_info_data *data)
+ struct cifs_open_info_data *data, bool is_dir)
{
int rc = -EOPNOTSUPP;
FILE_ALL_INFO fi = {};
@@ -934,7 +934,7 @@ smb_set_file_info(struct inode *inode, const char *full_path,
if (!(tcon->ses->capabilities & CAP_NT_SMBS) &&
(!buf->CreationTime || !buf->LastAccessTime ||
!buf->LastWriteTime || !buf->ChangeTime)) {
- rc = cifs_query_path_info(xid, tcon, cifs_sb, full_path, &query_data);
+ rc = cifs_query_path_info(xid, tcon, cifs_sb, full_path, &query_data, false);
if (rc) {
if (open_file) {
cifsFileInfo_put(open_file);
diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c
index 6d643b8b9547..280aa033b06a 100644
--- a/fs/smb/client/smb2inode.c
+++ b/fs/smb/client/smb2inode.c
@@ -940,10 +940,9 @@ int smb2_query_path_info(const unsigned int xid,
struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb,
const char *full_path,
- struct cifs_open_info_data *data)
+ struct cifs_open_info_data *data, bool is_dir)
{
struct kvec in_iov[3], out_iov[5] = {};
- struct cached_fid *cfid = NULL;
struct cifs_open_parms oparms;
struct cifsFileInfo *cfile;
__u32 create_options = 0;
@@ -964,12 +963,17 @@ int smb2_query_path_info(const unsigned int xid,
* is fast enough (always using the compounded version).
*/
if (!tcon->posix_extensions) {
+ struct cached_fid *cfid = NULL;
+
rc = -ENOENT;
if (!*full_path)
rc = open_cached_dir(xid, tcon, full_path, cifs_sb, &cfid);
+ else if (is_dir)
+ cfid = find_cached_dir(tcon->cfids, full_path, CFID_LOOKUP_PATH);
+
+ if (cfid) {
+ rc = 0;
- /* If it is a root and its handle is cached then use it */
- if (!rc) {
if (cfid->file_all_info) {
memcpy(&data->fi, cfid->file_all_info, sizeof(data->fi));
} else {
diff --git a/fs/smb/client/smb2proto.h b/fs/smb/client/smb2proto.h
index ac6db1f18b5b..3e3faa7cf633 100644
--- a/fs/smb/client/smb2proto.h
+++ b/fs/smb/client/smb2proto.h
@@ -72,7 +72,7 @@ int smb2_query_path_info(const unsigned int xid,
struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb,
const char *full_path,
- struct cifs_open_info_data *data);
+ struct cifs_open_info_data *data, bool is_dir);
extern int smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
const char *full_path, __u64 size,
struct cifs_sb_info *cifs_sb, bool set_alloc,