summaryrefslogtreecommitdiff
path: root/fs/smb/client/cached_dir.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/smb/client/cached_dir.c')
-rw-r--r--fs/smb/client/cached_dir.c78
1 files changed, 22 insertions, 56 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;