diff options
| author | Enzo Matsumiya <ematsumiya@suse.de> | 2025-09-08 10:09:32 -0300 |
|---|---|---|
| committer | Enzo Matsumiya <ematsumiya@suse.de> | 2025-09-08 10:09:32 -0300 |
| commit | 3f134bd4192d4b5285b254167b392d67bf89e7b5 (patch) | |
| tree | 1ca87737d34eb2a13084c993413686a853bae9d9 | |
| parent | 3c670b5d27ff05fffe4b2ea764c75ca37b191a8c (diff) | |
| download | linux-3f134bd4192d4b5285b254167b392d67bf89e7b5.tar.gz linux-3f134bd4192d4b5285b254167b392d67bf89e7b5.tar.bz2 linux-3f134bd4192d4b5285b254167b392d67bf89e7b5.zip | |
smb: client: remove cached_dir_offload_close/close_work
Make put_work an 'async dput' and then move cfid to dying list so
laundromat can clean it up (put last ref).
Other changes:
- move SMB2_close() from release callback to laundromat
Signed-off-by: Enzo Matsumiya <ematsumiya@suse.de>
| -rw-r--r-- | fs/smb/client/cached_dir.c | 95 | ||||
| -rw-r--r-- | fs/smb/client/cached_dir.h | 1 |
2 files changed, 41 insertions, 55 deletions
diff --git a/fs/smb/client/cached_dir.c b/fs/smb/client/cached_dir.c index f61fef810a23..7c992141576c 100644 --- a/fs/smb/client/cached_dir.c +++ b/fs/smb/client/cached_dir.c @@ -434,9 +434,7 @@ int open_cached_dir_by_dentry(struct cifs_tcon *tcon, static void smb2_close_cached_fid(struct kref *ref) { - struct cached_fid *cfid = container_of(ref, struct cached_fid, - refcount); - int rc; + struct cached_fid *cfid = container_of(ref, struct cached_fid, refcount); spin_lock(&cfid->cfids->cfid_list_lock); if (cfid->on_list) { @@ -449,13 +447,6 @@ smb2_close_cached_fid(struct kref *ref) dput(cfid->dentry); cfid->dentry = NULL; - if (cfid->is_open) { - rc = SMB2_close(0, cfid->tcon, cfid->fid.persistent_fid, - cfid->fid.volatile_fid); - if (rc) /* should we retry on -EBUSY or -EAGAIN? */ - cifs_dbg(VFS, "close cached dir rc %d\n", rc); - } - free_cached_dir(cfid); } @@ -530,6 +521,9 @@ void close_all_cached_dirs(struct cifs_sb_info *cifs_sb) 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); } spin_unlock(&cifs_sb->tlink_tree_lock); @@ -583,30 +577,15 @@ void invalidate_all_cached_dirs(struct cifs_tcon *tcon) flush_delayed_work(&cfids->laundromat_work); } -static void -cached_dir_offload_close(struct work_struct *work) -{ - struct cached_fid *cfid = container_of(work, - struct cached_fid, close_work); - struct cifs_tcon *tcon = cfid->tcon; - - WARN_ON(cfid->on_list); - - kref_put(&cfid->refcount, smb2_close_cached_fid); - cifs_put_tcon(tcon, netfs_trace_tcon_ref_put_cached_close); -} - /* - * Release the cached directory's dentry, and then queue work to drop cached - * directory itself (closing on server if needed). - * - * Must be called with a reference to the cached_fid and a reference to the - * tcon. + * Release the cached directory's dentry and schedule immediate cleanup on laundromat. + * Must be called with a reference to the cached_fid and a reference to the tcon. */ static void cached_dir_put_work(struct work_struct *work) { - struct cached_fid *cfid = container_of(work, struct cached_fid, - put_work); + struct cached_fid *cfid = container_of(work, struct cached_fid, put_work); + struct cached_fids *cfids = cfid->cfids; + struct cifs_tcon *tcon = cfid->tcon; struct dentry *dentry; spin_lock(&cfid->fid_lock); @@ -615,7 +594,16 @@ static void cached_dir_put_work(struct work_struct *work) spin_unlock(&cfid->fid_lock); dput(dentry); - queue_work(serverclose_wq, &cfid->close_work); + + /* move to dying list so laundromat can clean it up */ + spin_lock(&cfids->cfid_list_lock); + list_move(&cfid->entry, &cfids->dying); + cfid->on_list = false; + cfids->num_entries--; + spin_unlock(&cfids->cfid_list_lock); + + cifs_put_tcon(tcon, netfs_trace_tcon_ref_put_cached_close); + mod_delayed_work(cfid_put_wq, &cfids->laundromat_work, 0); } bool cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16]) @@ -634,13 +622,6 @@ bool cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16]) SMB2_LEASE_KEY_SIZE)) { cfid->has_lease = false; cfid->time = 0; - /* - * We found a lease remove it from the list - * so no threads can access it. - */ - list_del(&cfid->entry); - cfid->on_list = false; - cfids->num_entries--; ++tcon->tc_count; trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count, @@ -667,7 +648,6 @@ static struct cached_fid *init_cached_dir(const char *path) return NULL; } - INIT_WORK(&cfid->close_work, cached_dir_offload_close); INIT_WORK(&cfid->put_work, cached_dir_put_work); INIT_LIST_HEAD(&cfid->entry); INIT_LIST_HEAD(&cfid->dirents.entries); @@ -681,7 +661,6 @@ static void free_cached_dir(struct cached_fid *cfid) { struct cached_dirent *dirent, *q; - WARN_ON(work_pending(&cfid->close_work)); WARN_ON(work_pending(&cfid->put_work)); dput(cfid->dentry); @@ -735,28 +714,36 @@ static void cfids_laundromat_worker(struct work_struct *work) list_for_each_entry_safe(cfid, q, &entry, entry) { list_del(&cfid->entry); + /* + * If a cfid reached here, we must cleanup anything unrelated to it, i.e. dentry and + * remote fid. + * + * For the cfid itself, we only drop only our own (kref_init). If there are + * still concurrent ref-holders, they'll drop it later (cfid is already invalid at + * this point, so can't be found anymore). + */ spin_lock(&cfid->fid_lock); dentry = cfid->dentry; cfid->dentry = NULL; spin_unlock(&cfid->fid_lock); dput(dentry); + if (cfid->is_open) { - spin_lock(&cifs_tcp_ses_lock); - ++cfid->tcon->tc_count; - trace_smb3_tcon_ref(cfid->tcon->debug_id, cfid->tcon->tc_count, - netfs_trace_tcon_ref_get_cached_laundromat); - spin_unlock(&cifs_tcp_ses_lock); - queue_work(serverclose_wq, &cfid->close_work); - } else - /* - * Drop the ref-count from above, either the lease-ref (if there - * was one) or the extra one acquired. - */ - kref_put(&cfid->refcount, smb2_close_cached_fid); + int rc = SMB2_close(0, cfid->tcon, cfid->fid.persistent_fid, + cfid->fid.volatile_fid); + + cfid->is_open = false; + + /* SMB2_close should handle -EBUSY or -EAGAIN */ + if (rc) + cifs_dbg(VFS, "close cached dir rc %d\n", rc); + } + + kref_put(&cfid->refcount, smb2_close_cached_fid); } - queue_delayed_work(cfid_put_wq, &cfids->laundromat_work, - dir_cache_timeout * HZ); + + queue_delayed_work(cfid_put_wq, &cfids->laundromat_work, dir_cache_timeout * HZ); } struct cached_fids *init_cached_dirs(void) diff --git a/fs/smb/client/cached_dir.h b/fs/smb/client/cached_dir.h index a3757a736d3e..e5445e3a7bd3 100644 --- a/fs/smb/client/cached_dir.h +++ b/fs/smb/client/cached_dir.h @@ -45,7 +45,6 @@ struct cached_fid { struct cifs_tcon *tcon; struct dentry *dentry; struct work_struct put_work; - struct work_struct close_work; struct smb2_file_all_info file_all_info; struct cached_dirents dirents; }; |
