diff options
| author | Enzo Matsumiya <ematsumiya@suse.de> | 2025-09-19 13:26:59 -0300 |
|---|---|---|
| committer | Enzo Matsumiya <ematsumiya@suse.de> | 2025-09-26 19:08:09 -0300 |
| commit | f7cbec4f774920ad6678b30ac52e3c4e0ba2b018 (patch) | |
| tree | 7faa74507d0be05b5858d617518363483b5716c5 | |
| parent | 116380c666e04fc3fa75cdcec279d8f16512682d (diff) | |
| download | linux-f7cbec4f774920ad6678b30ac52e3c4e0ba2b018.tar.gz linux-f7cbec4f774920ad6678b30ac52e3c4e0ba2b018.tar.bz2 linux-f7cbec4f774920ad6678b30ac52e3c4e0ba2b018.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.
Since we now have a possible recursive lookup in open_cached_dir() e.g.:
cifs_readdir
open_cached_dir
lookup_noperm_positive_unlocked
...
cifs_d_revalidate
...
smb2_query_path_info
find_cached_dir
the cfid must be added to the entries list only after dentry lookup, so
we don't hang on an infinite recursion while waiting for itself to open.
Signed-off-by: Enzo Matsumiya <ematsumiya@suse.de>
| -rw-r--r-- | fs/smb/client/cached_dir.c | 12 | ||||
| -rw-r--r-- | fs/smb/client/cifsglob.h | 2 | ||||
| -rw-r--r-- | fs/smb/client/inode.c | 9 | ||||
| -rw-r--r-- | fs/smb/client/smb1ops.c | 4 | ||||
| -rw-r--r-- | fs/smb/client/smb2inode.c | 12 | ||||
| -rw-r--r-- | fs/smb/client/smb2proto.h | 2 |
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, |
