diff options
| author | Enzo Matsumiya <ematsumiya@suse.de> | 2025-09-11 13:04:45 -0300 |
|---|---|---|
| committer | Enzo Matsumiya <ematsumiya@suse.de> | 2025-09-11 17:59:59 -0300 |
| commit | ead10532fb5ecd150cd94ab57649cc92bff5d4bc (patch) | |
| tree | 129ea42bf7d461b1942a85fae3da3c63b254a6a7 | |
| parent | 1add00d886388cfcf9b755500263b97f5d9d57e2 (diff) | |
| download | linux-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.c | 111 | ||||
| -rw-r--r-- | fs/smb/client/cached_dir.h | 4 | ||||
| -rw-r--r-- | fs/smb/client/file.c | 2 | ||||
| -rw-r--r-- | fs/smb/client/misc.c | 9 | ||||
| -rw-r--r-- | fs/smb/client/smb2pdu.c | 2 |
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, |
