summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEnzo Matsumiya <ematsumiya@suse.de>2025-09-26 10:37:28 -0300
committerEnzo Matsumiya <ematsumiya@suse.de>2025-09-26 19:06:58 -0300
commit23a06eacf4fe17601c1476bd4dd28daafc5da897 (patch)
tree75b78dfa4033cd5bd98a7c3286b7d25dbbc76a9c
parente69f4d4f92fde896c9503760854903f24301e6d5 (diff)
downloadlinux-23a06eacf4fe17601c1476bd4dd28daafc5da897.tar.gz
linux-23a06eacf4fe17601c1476bd4dd28daafc5da897.tar.bz2
linux-23a06eacf4fe17601c1476bd4dd28daafc5da897.zip
smb: client: refactor dropping cached dirs
- s/drop_cached_dir_by_name/drop_cached_dir/ make it a generic find + invalidate function to replace drop_cached_dir_by_name() and cached_dir_lease_break() We now funnel any cleanup to laundromat, so we can make the release callback free only dirents, path, and cfid itself. Signed-off-by: Enzo Matsumiya <ematsumiya@suse.de>
-rw-r--r--fs/smb/client/cached_dir.c78
-rw-r--r--fs/smb/client/cached_dir.h3
-rw-r--r--fs/smb/client/inode.c2
-rw-r--r--fs/smb/client/smb2inode.c7
-rw-r--r--fs/smb/client/smb2misc.c2
5 files changed, 29 insertions, 63 deletions
diff --git a/fs/smb/client/cached_dir.c b/fs/smb/client/cached_dir.c
index 37a9bff26da7..84ea2653cdb9 100644
--- a/fs/smb/client/cached_dir.c
+++ b/fs/smb/client/cached_dir.c
@@ -476,22 +476,6 @@ static void smb2_close_cached_fid(struct kref *ref)
struct cached_fid *cfid = container_of(ref, struct cached_fid, refcount);
struct cached_dirent *de, *q;
- /*
- * There's no way a valid cfid can reach here.
- *
- * This is because we hould our own ref, and whenever we put it, we invalidate the cfid.
- *
- * So even if an external caller puts the last ref, cfid will already have been invalidated
- * by then by one of the invalidations that can happen concurrently, e.g. lease break,
- * invalidate_all_cached_dirs().
- *
- * So this check is mostly for precaution, but since we can still take the correct action
- * (just list_del()) if it's the case, do so.
- */
- if (WARN_ON(cfid_is_valid(cfid)))
- /* remaining invalidation done by drop_cfid() below */
- list_del(&cfid->entry);
-
drop_cfid(cfid);
/* Delete all cached dirent names */
@@ -506,23 +490,36 @@ static void smb2_close_cached_fid(struct kref *ref)
kfree(cfid);
}
-void drop_cached_dir_by_name(struct cached_fids *cfids, const char *name)
+bool drop_cached_dir(struct cached_fids *cfids, const void *key, int mode)
{
struct cached_fid *cfid;
- if (!cfids)
- return;
+ if (!cfids || !key)
+ return false;
- cfid = find_cached_dir(cfids, name, CFID_LOOKUP_PATH);
- if (!cfid) {
- cifs_dbg(FYI, "no cached dir found for rmdir(%s)\n", name);
- return;
- }
+ /*
+ * Raw lookup here as we _must_ find any matching cfid, no matter its state.
+ * Also, we might be racing with the SMB2 open in open_cached_dir(), so no need to wait
+ * for it to finish.
+ */
+ cfid = find_cfid(cfids, key, mode, false);
+ if (!cfid)
+ return false;
- drop_cfid(cfid);
+ if (mode != CFID_LOOKUP_LEASEKEY) {
+ drop_cfid(cfid);
+ } else {
+ /* we're locked in smb2_is_valid_lease_break(), so can't dput/close here */
+ spin_lock(&cfids->cfid_list_lock);
+ invalidate_cfid(cfid);
+ spin_unlock(&cfids->cfid_list_lock);
+ }
/* put lookup ref */
kref_put(&cfid->refcount, smb2_close_cached_fid);
+ mod_delayed_work(cfid_put_wq, &cfids->laundromat_work, 0);
+
+ return true;
}
void close_cached_dir(struct cached_fid *cfid)
@@ -589,37 +586,6 @@ void invalidate_all_cached_dirs(struct cached_fids *cfids)
flush_delayed_work(&cfids->laundromat_work);
}
-bool cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16])
-{
- struct cached_fids *cfids = tcon->cfids;
- struct cached_fid *cfid;
-
- if (cfids == NULL)
- return false;
-
- /*
- * Raw lookup here as we _must_ find our lease, no matter cfid state.
- * Also, this lease break might be coming from the SMB2 open in open_cached_dir(), so no
- * need to wait for it to finish.
- */
- cfid = find_cfid(cfids, lease_key, CFID_LOOKUP_LEASEKEY, false);
- if (cfid) {
- /* found a lease, invalidate cfid and schedule immediate cleanup on laundromat */
- spin_lock(&cfids->cfid_list_lock);
- invalidate_cfid(cfid);
- cfid->has_lease = false;
- spin_unlock(&cfids->cfid_list_lock);
-
- /* put lookup ref */
- kref_put(&cfid->refcount, smb2_close_cached_fid);
- mod_delayed_work(cfid_put_wq, &cfids->laundromat_work, 0);
-
- return true;
- }
-
- return false;
-}
-
static struct cached_fid *init_cached_dir(const char *path)
{
struct cached_fid *cfid;
diff --git a/fs/smb/client/cached_dir.h b/fs/smb/client/cached_dir.h
index afb9af227219..bed5ba68b07f 100644
--- a/fs/smb/client/cached_dir.h
+++ b/fs/smb/client/cached_dir.h
@@ -82,8 +82,7 @@ extern struct cached_fid *find_cached_dir(struct cached_fids *cfids, const void
extern int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, const char *path,
struct cifs_sb_info *cifs_sb, struct cached_fid **cfid);
extern void close_cached_dir(struct cached_fid *cfid);
-extern void drop_cached_dir_by_name(struct cached_fids *cfids, const char *name);
+extern bool drop_cached_dir(struct cached_fids *cfids, const void *key, int mode);
extern void close_all_cached_dirs(struct cifs_sb_info *cifs_sb);
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/inode.c b/fs/smb/client/inode.c
index df236c844611..f2eff1138ed0 100644
--- a/fs/smb/client/inode.c
+++ b/fs/smb/client/inode.c
@@ -2615,7 +2615,7 @@ unlink_target:
* ->i_nlink and then mark it as delete pending.
*/
if (S_ISDIR(inode->i_mode)) {
- drop_cached_dir_by_name(tcon->cfids, to_name);
+ drop_cached_dir(tcon->cfids, to_name, CFID_LOOKUP_PATH);
spin_lock(&inode->i_lock);
i_size_write(inode, 0);
clear_nlink(inode);
diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c
index c76fe1dec390..62d6adf50ad1 100644
--- a/fs/smb/client/smb2inode.c
+++ b/fs/smb/client/smb2inode.c
@@ -1160,7 +1160,7 @@ smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
{
struct cifs_open_parms oparms;
- drop_cached_dir_by_name(tcon->cfids, name);
+ drop_cached_dir(tcon->cfids, name, CFID_LOOKUP_PATH);
oparms = CIFS_OPARMS(cifs_sb, tcon, name, DELETE,
FILE_OPEN, CREATE_NOT_FILE, ACL_NO_MODE);
return smb2_compound_op(xid, tcon, cifs_sb,
@@ -1238,7 +1238,7 @@ int smb2_rename_path(const unsigned int xid,
struct cifsFileInfo *cfile;
__u32 co = file_create_options(source_dentry);
- drop_cached_dir_by_name(tcon->cfids, from_name);
+ drop_cached_dir(tcon->cfids, from_name, CFID_LOOKUP_PATH);
cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile);
int rc = smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
@@ -1520,7 +1520,8 @@ int smb2_rename_pending_delete(const char *full_path,
goto out;
}
- drop_cached_dir_by_name(tcon->cfids, full_path);
+ drop_cached_dir(tcon->cfids, full_path, CFID_LOOKUP_PATH);
+
oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
DELETE | FILE_WRITE_ATTRIBUTES,
FILE_OPEN, co, ACL_NO_MODE);
diff --git a/fs/smb/client/smb2misc.c b/fs/smb/client/smb2misc.c
index 89d933b4a8bc..71d987f76a12 100644
--- a/fs/smb/client/smb2misc.c
+++ b/fs/smb/client/smb2misc.c
@@ -660,7 +660,7 @@ smb2_is_valid_lease_break(char *buffer, struct TCP_Server_Info *server)
}
spin_unlock(&tcon->open_file_lock);
- if (cached_dir_lease_break(tcon, rsp->LeaseKey)) {
+ if (drop_cached_dir(tcon->cfids, rsp->LeaseKey, CFID_LOOKUP_LEASEKEY)) {
spin_unlock(&cifs_tcp_ses_lock);
return true;
}