summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEnzo Matsumiya <ematsumiya@suse.de>2025-09-15 13:01:36 -0300
committerEnzo Matsumiya <ematsumiya@suse.de>2025-09-26 19:06:55 -0300
commit4b714a42755b80baff3fefc2705f983423c3edbf (patch)
treecc1c3fc8e316e3cfc4368cfaebe69585fbb982f1
parent16542cb85ddb9bccd6d12368484b277edda9180d (diff)
downloadlinux-4b714a42755b80baff3fefc2705f983423c3edbf.tar.gz
linux-4b714a42755b80baff3fefc2705f983423c3edbf.tar.bz2
linux-4b714a42755b80baff3fefc2705f983423c3edbf.zip
smb: client: split find_or_create_cached_dir()
This patch splits the function into 2 separate ones; it not only makes the code clearer, but also allows further and easier enhancements to both. So move the initialization part into init_cached_dir() and add find_cached_dir() for lookups. Other: - drop_cached_dir_by_name(): * use find_cached_dir() * remove no longer used args Signed-off-by: Enzo Matsumiya <ematsumiya@suse.de>
-rw-r--r--fs/smb/client/cached_dir.c95
-rw-r--r--fs/smb/client/cached_dir.h5
-rw-r--r--fs/smb/client/inode.c2
-rw-r--r--fs/smb/client/smb2inode.c6
4 files changed, 53 insertions, 55 deletions
diff --git a/fs/smb/client/cached_dir.c b/fs/smb/client/cached_dir.c
index 8c8ead6e96bd..92898880d20f 100644
--- a/fs/smb/client/cached_dir.c
+++ b/fs/smb/client/cached_dir.c
@@ -54,10 +54,7 @@ static inline void drop_cfid(struct cached_fid *cfid)
}
}
-static struct cached_fid *find_or_create_cached_dir(struct cached_fids *cfids,
- const char *path,
- bool lookup_only,
- __u32 max_cached_dirs)
+static struct cached_fid *find_cached_dir(struct cached_fids *cfids, const char *path)
{
struct cached_fid *cfid;
@@ -71,35 +68,13 @@ static struct cached_fid *find_or_create_cached_dir(struct cached_fids *cfids,
if (!cfid_is_valid(cfid))
return NULL;
+ cfid->last_access_time = jiffies;
kref_get(&cfid->refcount);
return cfid;
}
}
- if (lookup_only) {
- return NULL;
- }
- if (cfids->num_entries >= max_cached_dirs) {
- return NULL;
- }
- cfid = init_cached_dir(path);
- if (cfid == NULL) {
- return NULL;
- }
- cfid->cfids = cfids;
- cfids->num_entries++;
- list_add(&cfid->entry, &cfids->entries);
- kref_get(&cfid->refcount);
- /*
- * Set @cfid->has_lease to true during construction so that the lease
- * reference can be put in cached_dir_lease_break() due to a potential
- * lease break right after the request is sent or while @cfid is still
- * being cached, or if a reconnection is triggered during construction.
- * Concurrent processes won't be to use it yet due to @cfid->time being
- * zero.
- */
- cfid->has_lease = true;
- return cfid;
+ return NULL;
}
static struct dentry *
@@ -197,9 +172,8 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
ses = tcon->ses;
cfids = tcon->cfids;
- if (cfids == NULL)
+ if (!cfids)
return -EOPNOTSUPP;
-
replay_again:
/* reinitialize for possible replay */
flags = 0;
@@ -214,24 +188,31 @@ replay_again:
return -ENOMEM;
spin_lock(&cfids->cfid_list_lock);
- cfid = find_or_create_cached_dir(cfids, path, lookup_only, tcon->max_cached_dirs);
- if (cfid == NULL) {
+ if (cfids->num_entries >= tcon->max_cached_dirs) {
spin_unlock(&cfids->cfid_list_lock);
kfree(utf16_path);
return -ENOENT;
}
- /*
- * Return cached fid if it is valid (has a lease and has a time).
- * Otherwise, it is either a new entry or laundromat worker removed it
- * from @cfids->entries. Caller will put last reference if the latter.
- */
- if (cfid->has_lease && cfid->time) {
- cfid->last_access_time = jiffies;
- spin_unlock(&cfids->cfid_list_lock);
+
+ /* find_cached_dir() already checks if has_lease and time, so no need to check here */
+ cfid = find_cached_dir(cfids, path);
+ if (cfid || lookup_only) {
*ret_cfid = cfid;
+ spin_unlock(&cfids->cfid_list_lock);
+ kfree(utf16_path);
+ return cfid ? 0 : -ENOENT;
+ }
+
+ cfid = init_cached_dir(path);
+ if (!cfid) {
+ spin_unlock(&cfids->cfid_list_lock);
kfree(utf16_path);
- return 0;
+ return -ENOMEM;
}
+
+ cfid->cfids = cfids;
+ cfids->num_entries++;
+ list_add(&cfid->entry, &cfids->entries);
spin_unlock(&cfids->cfid_list_lock);
pfid = &cfid->fid;
@@ -487,19 +468,22 @@ smb2_close_cached_fid(struct kref *ref)
kfree(cfid);
}
-void drop_cached_dir_by_name(const unsigned int xid, struct cifs_tcon *tcon,
- const char *name, struct cifs_sb_info *cifs_sb)
+void drop_cached_dir_by_name(struct cached_fids *cfids, const char *name)
{
- struct cached_fid *cfid = NULL;
- int rc;
+ struct cached_fid *cfid;
- rc = open_cached_dir(xid, tcon, name, cifs_sb, true, &cfid);
- if (rc) {
+ if (!cfids)
+ return;
+
+ cfid = find_cached_dir(cfids, name);
+ if (!cfid) {
cifs_dbg(FYI, "no cached dir found for rmdir(%s)\n", name);
return;
}
drop_cfid(cfid);
+
+ /* put lookup ref */
kref_put(&cfid->refcount, smb2_close_cached_fid);
}
@@ -609,6 +593,7 @@ static struct cached_fid *init_cached_dir(const char *path)
cfid = kzalloc(sizeof(*cfid), GFP_ATOMIC);
if (!cfid)
return NULL;
+
cfid->path = kstrdup(path, GFP_ATOMIC);
if (!cfid->path) {
kfree(cfid);
@@ -619,7 +604,23 @@ static struct cached_fid *init_cached_dir(const char *path)
INIT_LIST_HEAD(&cfid->dirents.entries);
mutex_init(&cfid->dirents.de_mutex);
spin_lock_init(&cfid->fid_lock);
+
+ /* this is our ref */
kref_init(&cfid->refcount);
+
+ /* this is caller/lease ref */
+ kref_get(&cfid->refcount);
+
+ /*
+ * Set @cfid->has_lease to true during construction so that the lease
+ * reference can be put in cached_dir_lease_break() due to a potential
+ * lease break right after the request is sent or while @cfid is still
+ * being cached, or if a reconnection is triggered during construction.
+ * Concurrent processes won't be to use it yet due to @cfid->time being
+ * zero.
+ */
+ cfid->has_lease = true;
+
return cfid;
}
diff --git a/fs/smb/client/cached_dir.h b/fs/smb/client/cached_dir.h
index 47c0404ba84a..4bc93131275e 100644
--- a/fs/smb/client/cached_dir.h
+++ b/fs/smb/client/cached_dir.h
@@ -79,10 +79,7 @@ extern int open_cached_dir_by_dentry(struct cifs_tcon *tcon,
struct dentry *dentry,
struct cached_fid **cfid);
extern void close_cached_dir(struct cached_fid *cfid);
-extern void drop_cached_dir_by_name(const unsigned int xid,
- struct cifs_tcon *tcon,
- const char *name,
- struct cifs_sb_info *cifs_sb);
+extern void drop_cached_dir_by_name(struct cached_fids *cfids, const char *name);
extern void close_all_cached_dirs(struct cifs_sb_info *cifs_sb);
extern void invalidate_all_cached_dirs(struct cached_fids *cfids);
extern bool cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16]);
diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
index e80bf55765b6..9344a86f6d46 100644
--- a/fs/smb/client/inode.c
+++ b/fs/smb/client/inode.c
@@ -2615,7 +2615,7 @@ unlink_target:
* ->i_nlink and then mark it as delete pending.
*/
if (S_ISDIR(inode->i_mode)) {
- drop_cached_dir_by_name(xid, tcon, to_name, cifs_sb);
+ drop_cached_dir_by_name(tcon->cfids, to_name);
spin_lock(&inode->i_lock);
i_size_write(inode, 0);
clear_nlink(inode);
diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c
index 7cadc8ca4f55..f462845dd167 100644
--- a/fs/smb/client/smb2inode.c
+++ b/fs/smb/client/smb2inode.c
@@ -1162,7 +1162,7 @@ smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
{
struct cifs_open_parms oparms;
- drop_cached_dir_by_name(xid, tcon, name, cifs_sb);
+ drop_cached_dir_by_name(tcon->cfids, name);
oparms = CIFS_OPARMS(cifs_sb, tcon, name, DELETE,
FILE_OPEN, CREATE_NOT_FILE, ACL_NO_MODE);
return smb2_compound_op(xid, tcon, cifs_sb,
@@ -1240,7 +1240,7 @@ int smb2_rename_path(const unsigned int xid,
struct cifsFileInfo *cfile;
__u32 co = file_create_options(source_dentry);
- drop_cached_dir_by_name(xid, tcon, from_name, cifs_sb);
+ drop_cached_dir_by_name(tcon->cfids, from_name);
cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile);
int rc = smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
@@ -1522,7 +1522,7 @@ int smb2_rename_pending_delete(const char *full_path,
goto out;
}
- drop_cached_dir_by_name(xid, tcon, full_path, cifs_sb);
+ drop_cached_dir_by_name(tcon->cfids, full_path);
oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
DELETE | FILE_WRITE_ATTRIBUTES,
FILE_OPEN, co, ACL_NO_MODE);