From 3d02bd42bd531fe86d7ec9dd46d4ee301d5c9f17 Mon Sep 17 00:00:00 2001 From: Enzo Matsumiya Date: Mon, 8 Sep 2025 16:03:39 -0300 Subject: smb: client: split find_or_create_cached_dir() Clearer semantics aside, this makes find_cached_dir() open to enhancements (and easier to do so). Other: - move initialization part into init_cached_dir() and add find_cached_dir() for lookups - drop_cached_dir_by_name(): * use find_cached_dir() * drop no longer used args Signed-off-by: Enzo Matsumiya --- fs/smb/client/cached_dir.c | 98 +++++++++++++++++++++++----------------------- fs/smb/client/cached_dir.h | 5 +-- fs/smb/client/inode.c | 2 +- fs/smb/client/smb2inode.c | 6 +-- 4 files changed, 54 insertions(+), 57 deletions(-) diff --git a/fs/smb/client/cached_dir.c b/fs/smb/client/cached_dir.c index d821b3a947ae..7b240e8d83f4 100644 --- a/fs/smb/client/cached_dir.c +++ b/fs/smb/client/cached_dir.c @@ -37,10 +37,7 @@ static inline void invalidate_cfid(struct cached_fid *cfid, bool 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, - __u32 max_cached_dirs) +static struct cached_fid *find_cached_dir(struct cached_fids *cfids, const char *path) { struct cached_fid *cfid; @@ -54,35 +51,13 @@ static struct cached_fid *find_or_create_cached_dir(struct cached_fids *cfids, if (!cfid_is_valid(cfid)) return NULL; + cfid->last_access_time = jiffies; kref_get(&cfid->refcount); return cfid; } } - if (lookup_only) { - return NULL; - } - if (cfids->num_entries >= max_cached_dirs) { - return NULL; - } - cfid = init_cached_dir(path); - if (cfid == NULL) { - return NULL; - } - cfid->cfids = cfids; - cfids->num_entries++; - list_add(&cfid->entry, &cfids->entries); - kref_get(&cfid->refcount); - /* - * Set @cfid->has_lease to true during construction so that the lease - * reference can be put in cached_dir_lease_break() due to a potential - * lease break right after the request is sent or while @cfid is still - * being cached, or if a reconnection is triggered during construction. - * Concurrent processes won't be to use it yet due to @cfid->time being - * zero. - */ - cfid->has_lease = true; - return cfid; + return NULL; } static struct dentry * @@ -180,9 +155,8 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, ses = tcon->ses; cfids = tcon->cfids; - if (cfids == NULL) + if (!cfids) return -EOPNOTSUPP; - replay_again: /* reinitialize for possible replay */ flags = 0; @@ -197,24 +171,31 @@ replay_again: return -ENOMEM; spin_lock(&cfids->cfid_list_lock); - cfid = find_or_create_cached_dir(cfids, path, lookup_only, tcon->max_cached_dirs); - if (cfid == NULL) { + if (cfids->num_entries >= tcon->max_cached_dirs) { spin_unlock(&cfids->cfid_list_lock); kfree(utf16_path); return -ENOENT; } - /* - * Return cached fid if it is valid (has a lease and has a time). - * Otherwise, it is either a new entry or laundromat worker removed it - * from @cfids->entries. Caller will put last reference if the latter. - */ - if (cfid->has_lease && cfid->time) { - cfid->last_access_time = jiffies; - spin_unlock(&cfids->cfid_list_lock); + + /* find_cached_dir() already checks if has_lease and time, so no need to check here */ + cfid = find_cached_dir(cfids, path); + if (cfid || lookup_only) { *ret_cfid = cfid; + spin_unlock(&cfids->cfid_list_lock); kfree(utf16_path); - return 0; + return cfid ? 0 : -ENOENT; } + + cfid = init_cached_dir(path); + if (!cfid) { + spin_unlock(&cfids->cfid_list_lock); + kfree(utf16_path); + return -ENOMEM; + } + + cfid->cfids = cfids; + cfids->num_entries++; + list_add(&cfid->entry, &cfids->entries); spin_unlock(&cfids->cfid_list_lock); pfid = &cfid->fid; @@ -473,22 +454,24 @@ smb2_close_cached_fid(struct kref *ref) kfree(cfid); } -void drop_cached_dir_by_name(const unsigned int xid, struct cifs_tcon *tcon, - const char *name, struct cifs_sb_info *cifs_sb) +void drop_cached_dir_by_name(struct cached_fids *cfids, const char *name) { - struct cached_fid *cfid = NULL; - int rc; + struct cached_fid *cfid; - rc = open_cached_dir(xid, tcon, name, cifs_sb, true, &cfid); - if (rc) { + if (!cfids) + return; + + cfid = find_cached_dir(cfids, name); + if (!cfid) { cifs_dbg(FYI, "no cached dir found for rmdir(%s)\n", name); return; } - spin_lock(&cfid->cfids->cfid_list_lock); + spin_lock(&cfids->cfid_list_lock); invalidate_cfid(cfid, false); - spin_unlock(&cfid->cfids->cfid_list_lock); + spin_unlock(&cfids->cfid_list_lock); + /* put lookup ref */ kref_put(&cfid->refcount, smb2_close_cached_fid); } @@ -597,6 +580,7 @@ static struct cached_fid *init_cached_dir(const char *path) cfid = kzalloc(sizeof(*cfid), GFP_ATOMIC); if (!cfid) return NULL; + cfid->path = kstrdup(path, GFP_ATOMIC); if (!cfid->path) { kfree(cfid); @@ -607,7 +591,23 @@ static struct cached_fid *init_cached_dir(const char *path) INIT_LIST_HEAD(&cfid->dirents.entries); mutex_init(&cfid->dirents.de_mutex); spin_lock_init(&cfid->fid_lock); + + /* this is our ref */ kref_init(&cfid->refcount); + + /* this is caller/lease ref */ + kref_get(&cfid->refcount); + + /* + * Set @cfid->has_lease to true during construction so that the lease + * reference can be put in cached_dir_lease_break() due to a potential + * lease break right after the request is sent or while @cfid is still + * being cached, or if a reconnection is triggered during construction. + * Concurrent processes won't be to use it yet due to @cfid->time being + * zero. + */ + cfid->has_lease = true; + return cfid; } diff --git a/fs/smb/client/cached_dir.h b/fs/smb/client/cached_dir.h index bd80a1a74922..59682fd30377 100644 --- a/fs/smb/client/cached_dir.h +++ b/fs/smb/client/cached_dir.h @@ -68,10 +68,7 @@ extern int open_cached_dir_by_dentry(struct cifs_tcon *tcon, struct dentry *dentry, struct cached_fid **cfid); extern void close_cached_dir(struct cached_fid *cfid); -extern void drop_cached_dir_by_name(const unsigned int xid, - struct cifs_tcon *tcon, - const char *name, - struct cifs_sb_info *cifs_sb); +extern void drop_cached_dir_by_name(struct cached_fids *cfids, const char *name); 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]); diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c index e80bf55765b6..9344a86f6d46 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(xid, tcon, to_name, cifs_sb); + drop_cached_dir_by_name(tcon->cfids, to_name); 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 7cadc8ca4f55..f462845dd167 100644 --- a/fs/smb/client/smb2inode.c +++ b/fs/smb/client/smb2inode.c @@ -1162,7 +1162,7 @@ smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name, { struct cifs_open_parms oparms; - drop_cached_dir_by_name(xid, tcon, name, cifs_sb); + drop_cached_dir_by_name(tcon->cfids, name); oparms = CIFS_OPARMS(cifs_sb, tcon, name, DELETE, FILE_OPEN, CREATE_NOT_FILE, ACL_NO_MODE); return smb2_compound_op(xid, tcon, cifs_sb, @@ -1240,7 +1240,7 @@ int smb2_rename_path(const unsigned int xid, struct cifsFileInfo *cfile; __u32 co = file_create_options(source_dentry); - drop_cached_dir_by_name(xid, tcon, from_name, cifs_sb); + drop_cached_dir_by_name(tcon->cfids, from_name); 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, @@ -1522,7 +1522,7 @@ int smb2_rename_pending_delete(const char *full_path, goto out; } - drop_cached_dir_by_name(xid, tcon, full_path, cifs_sb); + drop_cached_dir_by_name(tcon->cfids, full_path); oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, DELETE | FILE_WRITE_ATTRIBUTES, FILE_OPEN, co, ACL_NO_MODE); -- cgit v1.2.3