summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEnzo Matsumiya <ematsumiya@suse.de>2025-09-11 13:04:45 -0300
committerEnzo Matsumiya <ematsumiya@suse.de>2025-09-11 17:59:59 -0300
commitead10532fb5ecd150cd94ab57649cc92bff5d4bc (patch)
tree129ea42bf7d461b1942a85fae3da3c63b254a6a7
parent1add00d886388cfcf9b755500263b97f5d9d57e2 (diff)
downloadlinux-ead10532fb5ecd150cd94ab57649cc92bff5d4bc.tar.gz
linux-ead10532fb5ecd150cd94ab57649cc92bff5d4bc.tar.bz2
linux-ead10532fb5ecd150cd94ab57649cc92bff5d4bc.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.c111
-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, 93 deletions
diff --git a/fs/smb/client/cached_dir.c b/fs/smb/client/cached_dir.c
index a32d71540bba..1da4e1d83728 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 bool cfid_expired(const struct cached_fid *cfid)
{
return (cfid->last_access_time &&
@@ -493,6 +488,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 if requested. They'll be cleaned up by laundromat. */
+ spin_lock(&cfids->cfid_list_lock);
+ list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
+ invalidate_cfid(cfid, true);
+ 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
*/
@@ -500,12 +516,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)) {
@@ -513,44 +525,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) {
- 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);
}
@@ -559,24 +538,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, true);
- 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);
}
@@ -730,33 +697,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, false);
- 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);
- free_cached_dir(cfid);
- }
-
- kfree(cfids);
-}
diff --git a/fs/smb/client/cached_dir.h b/fs/smb/client/cached_dir.h
index feca9a361635..bd80a1a74922 100644
--- a/fs/smb/client/cached_dir.h
+++ b/fs/smb/client/cached_dir.h
@@ -60,7 +60,6 @@ struct cached_fids {
};
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,
@@ -74,7 +73,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,