summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEnzo Matsumiya <ematsumiya@suse.de>2025-09-08 15:29:31 -0300
committerEnzo Matsumiya <ematsumiya@suse.de>2025-09-08 15:40:47 -0300
commit3340c6434cd8928eaef51662f47b1f27d730428c (patch)
tree85ce62479562eeb65cb992ef525ff2b4186de3d7
parentdb28092064f679cdbe1bb0a4228a62918190bf96 (diff)
downloadlinux-3340c6434cd8928eaef51662f47b1f27d730428c.tar.gz
linux-3340c6434cd8928eaef51662f47b1f27d730428c.tar.bz2
linux-3340c6434cd8928eaef51662f47b1f27d730428c.zip
smb: client: remove cached_fids->dying list
Since any cleanup is done on laundromat, the dying list can be removed. - entries stays on the main list until they're schedule for cleanup (->last_access_time = 1) - cached_fids->num_entries is decremented only when cfid transitions from on_list true -> false cached_fid lifecycle on the list becomes: - list_add() on find_or_create_cached_dir() - list_move() to local list on laundromat - list_del_init() from local list - list_del() on release callback Other changes: - add invalidate_cfid() helper to centralize cfid invalidation criteria Signed-off-by: Enzo Matsumiya <ematsumiya@suse.de>
-rw-r--r--fs/smb/client/cached_dir.c83
-rw-r--r--fs/smb/client/cached_dir.h3
2 files changed, 28 insertions, 58 deletions
diff --git a/fs/smb/client/cached_dir.c b/fs/smb/client/cached_dir.c
index 8912c27cbc23..af2fe416ddcf 100644
--- a/fs/smb/client/cached_dir.c
+++ b/fs/smb/client/cached_dir.c
@@ -22,6 +22,18 @@ struct cached_dir_dentry {
struct dentry *dentry;
};
+static inline void invalidate_cfid(struct cached_fid *cfid, bool force_expire)
+{
+ if (cfid->on_list)
+ cfid->cfids->num_entries--;
+
+ /* do not change other fields here! */
+ cfid->on_list = false;
+ cfid->time = 0;
+ if (force_expire)
+ cfid->last_access_time = 1;
+}
+
static struct cached_fid *find_or_create_cached_dir(struct cached_fids *cfids,
const char *path,
bool lookup_only,
@@ -437,11 +449,8 @@ smb2_close_cached_fid(struct kref *ref)
struct cached_fid *cfid = container_of(ref, struct cached_fid, refcount);
spin_lock(&cfid->cfids->cfid_list_lock);
- if (cfid->on_list) {
- list_del(&cfid->entry);
- cfid->on_list = false;
- cfid->cfids->num_entries--;
- }
+ list_del(&cfid->entry);
+ invalidate_cfid(cfid, true);
spin_unlock(&cfid->cfids->cfid_list_lock);
dput(cfid->dentry);
@@ -461,15 +470,13 @@ void drop_cached_dir_by_name(const unsigned int xid, struct cifs_tcon *tcon,
cifs_dbg(FYI, "no cached dir found for rmdir(%s)\n", name);
return;
}
+
spin_lock(&cfid->cfids->cfid_list_lock);
- if (cfid->has_lease) {
- cfid->has_lease = false;
- kref_put(&cfid->refcount, smb2_close_cached_fid);
- }
+ invalidate_cfid(cfid, false);
spin_unlock(&cfid->cfids->cfid_list_lock);
- close_cached_dir(cfid);
-}
+ kref_put(&cfid->refcount, smb2_close_cached_fid);
+}
void close_cached_dir(struct cached_fid *cfid)
{
@@ -550,25 +557,11 @@ void invalidate_all_cached_dirs(struct cifs_tcon *tcon)
if (!cfids)
return;
- /*
- * Mark all the cfids as closed, and move them to the cfids->dying list.
- * They'll be cleaned up by laundromat. Take a reference to each cfid
- * during this process.
- */
+ /* 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) {
- list_move(&cfid->entry, &cfids->dying);
- cfids->num_entries--;
+ invalidate_cfid(cfid, true);
cfid->is_open = false;
- cfid->on_list = false;
- if (cfid->has_lease) {
- /*
- * The lease was never cancelled from the server,
- * so steal that reference.
- */
- cfid->has_lease = false;
- } else
- kref_get(&cfid->refcount);
}
spin_unlock(&cfids->cfid_list_lock);
@@ -592,17 +585,13 @@ bool cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16])
!memcmp(lease_key,
cfid->fid.lease_key,
SMB2_LEASE_KEY_SIZE)) {
- cfid->has_lease = false;
- cfid->time = 0;
-
/*
- * We found a lease, move it to the dying list and schedule immediate
- * cleanup on laundromat.
+ * We found a lease, invalidate cfid and schedule immediate cleanup on
+ * laundromat.
* No need to take a ref here, as we still hold our initial one.
*/
- list_move(&cfid->entry, &cfids->dying);
- cfids->num_entries--;
- cfid->on_list = false;
+ invalidate_cfid(cfid, true);
+ cfid->has_lease = false;
found = true;
break;
}
@@ -667,29 +656,17 @@ static void cfids_laundromat_worker(struct work_struct *work)
cfids = container_of(work, struct cached_fids, laundromat_work.work);
spin_lock(&cfids->cfid_list_lock);
- /* move cfids->dying to the local list */
- list_cut_before(&entry, &cfids->dying, &cfids->dying);
-
list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
if (cfid->last_access_time &&
time_after(jiffies, cfid->last_access_time + HZ * dir_cache_timeout)) {
- cfid->on_list = false;
+ invalidate_cfid(cfid, true);
list_move(&cfid->entry, &entry);
- cfids->num_entries--;
- if (cfid->has_lease) {
- /*
- * Our lease has not yet been cancelled from the
- * server. Steal that reference.
- */
- cfid->has_lease = false;
- } else
- kref_get(&cfid->refcount);
}
}
spin_unlock(&cfids->cfid_list_lock);
list_for_each_entry_safe(cfid, q, &entry, entry) {
- list_del(&cfid->entry);
+ list_del_init(&cfid->entry);
/*
* If a cfid reached here, we must cleanup anything unrelated to it, i.e. dentry and
@@ -732,7 +709,6 @@ struct cached_fids *init_cached_dirs(void)
return NULL;
spin_lock_init(&cfids->cfid_list_lock);
INIT_LIST_HEAD(&cfids->entries);
- INIT_LIST_HEAD(&cfids->dying);
INIT_DELAYED_WORK(&cfids->laundromat_work, cfids_laundromat_worker);
queue_delayed_work(cfid_put_wq, &cfids->laundromat_work,
@@ -757,12 +733,7 @@ void free_cached_dirs(struct cached_fids *cfids)
spin_lock(&cfids->cfid_list_lock);
list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
- cfid->on_list = false;
- cfid->is_open = false;
- list_move(&cfid->entry, &entry);
- }
- list_for_each_entry_safe(cfid, q, &cfids->dying, entry) {
- cfid->on_list = false;
+ invalidate_cfid(cfid, false);
cfid->is_open = false;
list_move(&cfid->entry, &entry);
}
diff --git a/fs/smb/client/cached_dir.h b/fs/smb/client/cached_dir.h
index 5e892d53a67a..e549f019b923 100644
--- a/fs/smb/client/cached_dir.h
+++ b/fs/smb/client/cached_dir.h
@@ -52,12 +52,11 @@ struct cached_fid {
struct cached_fids {
/* Must be held when:
* - accessing the cfids->entries list
- * - accessing the cfids->dying list
+ * - accessing cfids->num_entries
*/
spinlock_t cfid_list_lock;
int num_entries;
struct list_head entries;
- struct list_head dying;
struct delayed_work laundromat_work;
};