summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEnzo Matsumiya <ematsumiya@suse.de>2025-09-24 19:38:17 -0300
committerEnzo Matsumiya <ematsumiya@suse.de>2025-09-26 19:06:54 -0300
commitd2eceb4e7b9bfde214d1f489f59d89c061f89957 (patch)
tree51b5101abeeca91d05dda28dd2c7509460c2c55e
parent0c5b5cf37953335c6cda3acef4888c8e9e2a91f7 (diff)
downloadlinux-d2eceb4e7b9bfde214d1f489f59d89c061f89957.tar.gz
linux-d2eceb4e7b9bfde214d1f489f59d89c061f89957.tar.bz2
linux-d2eceb4e7b9bfde214d1f489f59d89c061f89957.zip
smb: client: merge {close,invalidate}_all_cached_dirs()
close_all_cached_dirs(), invalidate_all_cached_dirs() and free_cached_dirs() have become too similar now, merge their functionality in a single static invalidate_all_cfids() function. This also allows removing free_cached_dirs() altogether as it only requires cancelling the work afterwards (done directly in tconInfoFree()). Other changes: - remove struct cached_dir_dentry Signed-off-by: Enzo Matsumiya <ematsumiya@suse.de>
-rw-r--r--fs/smb/client/cached_dir.c114
-rw-r--r--fs/smb/client/cached_dir.h4
-rw-r--r--fs/smb/client/file.c2
-rw-r--r--fs/smb/client/misc.c9
-rw-r--r--fs/smb/client/smb2pdu.c2
5 files changed, 35 insertions, 96 deletions
diff --git a/fs/smb/client/cached_dir.c b/fs/smb/client/cached_dir.c
index 9b4045a57f12..36a1e1436502 100644
--- a/fs/smb/client/cached_dir.c
+++ b/fs/smb/client/cached_dir.c
@@ -16,11 +16,6 @@ static struct cached_fid *init_cached_dir(const char *path);
static void free_cached_dir(struct cached_fid *cfid);
static void smb2_close_cached_fid(struct kref *ref);
-struct cached_dir_dentry {
- struct list_head entry;
- struct dentry *dentry;
-};
-
static inline void invalidate_cfid(struct cached_fid *cfid)
{
/* callers must hold the list lock and do any list operations (del/move) themselves */
@@ -503,6 +498,27 @@ void close_cached_dir(struct cached_fid *cfid)
kref_put(&cfid->refcount, smb2_close_cached_fid);
}
+static void invalidate_all_cfids(struct cached_fids *cfids, bool closed)
+{
+ struct cached_fid *cfid, *q;
+
+ if (!cfids)
+ return;
+
+ /* mark all the cfids as closed and invalidate them for laundromat cleanup */
+ spin_lock(&cfids->cfid_list_lock);
+ list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
+ invalidate_cfid(cfid);
+ cfid->has_lease = false;
+ if (closed)
+ cfid->is_open = false;
+ }
+ spin_unlock(&cfids->cfid_list_lock);
+
+ /* run laundromat unconditionally now as there might have been previously queued work */
+ mod_delayed_work(cfid_put_wq, &cfids->laundromat_work, 0);
+}
+
/*
* Called from cifs_kill_sb when we unmount a share
*/
@@ -510,12 +526,8 @@ void close_all_cached_dirs(struct cifs_sb_info *cifs_sb)
{
struct rb_root *root = &cifs_sb->tlink_tree;
struct rb_node *node;
- struct cached_fid *cfid;
struct cifs_tcon *tcon;
struct tcon_link *tlink;
- struct cached_fids *cfids;
- struct cached_dir_dentry *tmp_list, *q;
- LIST_HEAD(entry);
spin_lock(&cifs_sb->tlink_tree_lock);
for (node = rb_first(root); node; node = rb_next(node)) {
@@ -523,46 +535,11 @@ void close_all_cached_dirs(struct cifs_sb_info *cifs_sb)
tcon = tlink_tcon(tlink);
if (IS_ERR(tcon))
continue;
- cfids = tcon->cfids;
- if (cfids == NULL)
- continue;
- spin_lock(&cfids->cfid_list_lock);
- list_for_each_entry(cfid, &cfids->entries, entry) {
- invalidate_cfid(cfid);
-
- tmp_list = kmalloc(sizeof(*tmp_list), GFP_ATOMIC);
- if (tmp_list == NULL) {
- /*
- * If the malloc() fails, we won't drop all
- * dentries, and unmounting is likely to trigger
- * a 'Dentry still in use' error.
- */
- cifs_tcon_dbg(VFS, "Out of memory while dropping dentries\n");
- spin_unlock(&cfids->cfid_list_lock);
- spin_unlock(&cifs_sb->tlink_tree_lock);
- goto done;
- }
- spin_lock(&cfid->fid_lock);
- tmp_list->dentry = cfid->dentry;
- cfid->dentry = NULL;
- spin_unlock(&cfid->fid_lock);
- list_add_tail(&tmp_list->entry, &entry);
- }
- spin_unlock(&cfids->cfid_list_lock);
-
- /* run laundromat now as it might not have been queued */
- mod_delayed_work(cfid_put_wq, &cfids->laundromat_work, 0);
+ invalidate_all_cfids(tcon->cfids, false);
}
spin_unlock(&cifs_sb->tlink_tree_lock);
-done:
- list_for_each_entry_safe(tmp_list, q, &entry, entry) {
- list_del(&tmp_list->entry);
- dput(tmp_list->dentry);
- kfree(tmp_list);
- }
-
/* Flush any pending work that will drop dentries */
flush_workqueue(cfid_put_wq);
}
@@ -571,24 +548,12 @@ done:
* Invalidate all cached dirs when a TCON has been reset
* due to a session loss.
*/
-void invalidate_all_cached_dirs(struct cifs_tcon *tcon)
+void invalidate_all_cached_dirs(struct cached_fids *cfids)
{
- struct cached_fids *cfids = tcon->cfids;
- struct cached_fid *cfid;
-
if (!cfids)
return;
- /* mark all the cfids as closed and invalidate them for laundromat cleanup */
- spin_lock(&cfids->cfid_list_lock);
- list_for_each_entry(cfid, &cfids->entries, entry) {
- invalidate_cfid(cfid);
- cfid->is_open = false;
- }
- spin_unlock(&cfids->cfid_list_lock);
-
- /* run laundromat unconditionally now as there might have been previously queued work */
- mod_delayed_work(cfid_put_wq, &cfids->laundromat_work, 0);
+ invalidate_all_cfids(cfids, true);
flush_delayed_work(&cfids->laundromat_work);
}
@@ -719,34 +684,3 @@ struct cached_fids *init_cached_dirs(void)
return cfids;
}
-
-/*
- * Called from tconInfoFree when we are tearing down the tcon.
- * There are no active users or open files/directories at this point.
- */
-void free_cached_dirs(struct cached_fids *cfids)
-{
- struct cached_fid *cfid, *q;
- LIST_HEAD(entry);
-
- if (cfids == NULL)
- return;
-
- cancel_delayed_work_sync(&cfids->laundromat_work);
-
- spin_lock(&cfids->cfid_list_lock);
- list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
- invalidate_cfid(cfid);
- cfid->is_open = false;
- list_move(&cfid->entry, &entry);
- }
- spin_unlock(&cfids->cfid_list_lock);
-
- list_for_each_entry_safe(cfid, q, &entry, entry) {
- list_del(&cfid->entry);
- drop_cfid(cfid);
- free_cached_dir(cfid);
- }
-
- kfree(cfids);
-}
diff --git a/fs/smb/client/cached_dir.h b/fs/smb/client/cached_dir.h
index 92e95c56fd1c..47c0404ba84a 100644
--- a/fs/smb/client/cached_dir.h
+++ b/fs/smb/client/cached_dir.h
@@ -71,7 +71,6 @@ static inline bool cfid_is_valid(const struct cached_fid *cfid)
}
extern struct cached_fids *init_cached_dirs(void);
-extern void free_cached_dirs(struct cached_fids *cfids);
extern int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
const char *path,
struct cifs_sb_info *cifs_sb,
@@ -85,7 +84,6 @@ extern void drop_cached_dir_by_name(const unsigned int xid,
const char *name,
struct cifs_sb_info *cifs_sb);
extern void close_all_cached_dirs(struct cifs_sb_info *cifs_sb);
-extern void invalidate_all_cached_dirs(struct cifs_tcon *tcon);
+extern void invalidate_all_cached_dirs(struct cached_fids *cfids);
extern bool cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16]);
-
#endif /* _CACHED_DIR_H */
diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c
index cb907e18cc35..5c195ffa3ead 100644
--- a/fs/smb/client/file.c
+++ b/fs/smb/client/file.c
@@ -386,7 +386,7 @@ cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
}
spin_unlock(&tcon->open_file_lock);
- invalidate_all_cached_dirs(tcon);
+ invalidate_all_cached_dirs(tcon->cfids);
spin_lock(&tcon->tc_lock);
if (tcon->status == TID_IN_FILES_INVALIDATE)
tcon->status = TID_NEED_TCON;
diff --git a/fs/smb/client/misc.c b/fs/smb/client/misc.c
index da23cc12a52c..8d70333a6a3d 100644
--- a/fs/smb/client/misc.c
+++ b/fs/smb/client/misc.c
@@ -169,7 +169,14 @@ tconInfoFree(struct cifs_tcon *tcon, enum smb3_tcon_ref_trace trace)
return;
}
trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count, trace);
- free_cached_dirs(tcon->cfids);
+
+ if (tcon->cfids) {
+ invalidate_all_cached_dirs(tcon->cfids);
+ cancel_delayed_work_sync(&tcon->cfids->laundromat_work);
+ kfree(tcon->cfids);
+ tcon->cfids = NULL;
+ }
+
atomic_dec(&tconInfoAllocCount);
kfree(tcon->nativeFileSystem);
kfree_sensitive(tcon->password);
diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index c3b9d3f6210f..07ba61583114 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -2197,7 +2197,7 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
}
spin_unlock(&ses->chan_lock);
- invalidate_all_cached_dirs(tcon);
+ invalidate_all_cached_dirs(tcon->cfids);
rc = smb2_plain_req_init(SMB2_TREE_DISCONNECT, tcon, server,
(void **) &req,