summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEnzo Matsumiya <ematsumiya@suse.de>2025-09-08 18:11:16 -0300
committerEnzo Matsumiya <ematsumiya@suse.de>2025-09-12 17:27:38 -0300
commitd5db635bbcf732be94e0808f74e00a9476509ed0 (patch)
tree3b8212b7f2e1b1229d0a2a378e2d4ff4bd76a862
parentda0242dd604d645a0622dcfab75573e29c986d68 (diff)
downloadlinux-d5db635bbcf732be94e0808f74e00a9476509ed0.tar.gz
linux-d5db635bbcf732be94e0808f74e00a9476509ed0.tar.bz2
linux-d5db635bbcf732be94e0808f74e00a9476509ed0.zip
smb: client: add is_dir argument to query_path_info
When we have an inode on upper levels, pass is_dir down to smb2_query_path_info() so we can lookup for a cached dir there. Signed-off-by: Enzo Matsumiya <ematsumiya@suse.de>
-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.c18
-rw-r--r--fs/smb/client/smb2proto.h2
5 files changed, 21 insertions, 14 deletions
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 192645a891c8..6127e659cb6a 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,19 +963,22 @@ 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->info) {
memcpy(&data->fi, cfid->info, sizeof(data->fi));
} else {
- rc = SMB2_query_info(xid, tcon,
- cfid->fid.persistent_fid,
- cfid->fid.volatile_fid,
- &data->fi);
+ rc = SMB2_query_info(xid, tcon, cfid->fid.persistent_fid,
+ cfid->fid.volatile_fid, &data->fi);
if (!rc) {
cfid->info = kmemdup(&data->fi, sizeof(data->fi),
GFP_KERNEL);
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,