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.c114
1 files changed, 24 insertions, 90 deletions
diff --git a/fs/smb/client/cached_dir.c b/fs/smb/client/cached_dir.c
index 9b4045a57f12..36a1e1436502 100644
--- a/fs/smb/client/cached_dir.c
+++ b/fs/smb/client/cached_dir.c
@@ -16,11 +16,6 @@ static struct cached_fid *init_cached_dir(const char *path);
static void free_cached_dir(struct cached_fid *cfid);
static void smb2_close_cached_fid(struct kref *ref);
-struct cached_dir_dentry {
- struct list_head entry;
- struct dentry *dentry;
-};
-
static inline void invalidate_cfid(struct cached_fid *cfid)
{
/* callers must hold the list lock and do any list operations (del/move) themselves */
@@ -503,6 +498,27 @@ void close_cached_dir(struct cached_fid *cfid)
kref_put(&cfid->refcount, smb2_close_cached_fid);
}
+static void invalidate_all_cfids(struct cached_fids *cfids, bool closed)
+{
+ struct cached_fid *cfid, *q;
+
+ if (!cfids)
+ return;
+
+ /* 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) {
+ invalidate_cfid(cfid);
+ cfid->has_lease = false;
+ if (closed)
+ cfid->is_open = false;
+ }
+ spin_unlock(&cfids->cfid_list_lock);
+
+ /* run laundromat unconditionally now as there might have been previously queued work */
+ mod_delayed_work(cfid_put_wq, &cfids->laundromat_work, 0);
+}
+
/*
* Called from cifs_kill_sb when we unmount a share
*/
@@ -510,12 +526,8 @@ void close_all_cached_dirs(struct cifs_sb_info *cifs_sb)
{
struct rb_root *root = &cifs_sb->tlink_tree;
struct rb_node *node;
- struct cached_fid *cfid;
struct cifs_tcon *tcon;
struct tcon_link *tlink;
- struct cached_fids *cfids;
- struct cached_dir_dentry *tmp_list, *q;
- LIST_HEAD(entry);
spin_lock(&cifs_sb->tlink_tree_lock);
for (node = rb_first(root); node; node = rb_next(node)) {
@@ -523,46 +535,11 @@ void close_all_cached_dirs(struct cifs_sb_info *cifs_sb)
tcon = tlink_tcon(tlink);
if (IS_ERR(tcon))
continue;
- cfids = tcon->cfids;
- if (cfids == NULL)
- continue;
- spin_lock(&cfids->cfid_list_lock);
- list_for_each_entry(cfid, &cfids->entries, entry) {
- invalidate_cfid(cfid);
-
- tmp_list = kmalloc(sizeof(*tmp_list), GFP_ATOMIC);
- if (tmp_list == NULL) {
- /*
- * If the malloc() fails, we won't drop all
- * dentries, and unmounting is likely to trigger
- * a 'Dentry still in use' error.
- */
- cifs_tcon_dbg(VFS, "Out of memory while dropping dentries\n");
- spin_unlock(&cfids->cfid_list_lock);
- spin_unlock(&cifs_sb->tlink_tree_lock);
- goto done;
- }
- spin_lock(&cfid->fid_lock);
- tmp_list->dentry = cfid->dentry;
- cfid->dentry = NULL;
- spin_unlock(&cfid->fid_lock);
- 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);
+ invalidate_all_cfids(tcon->cfids, false);
}
spin_unlock(&cifs_sb->tlink_tree_lock);
-done:
- list_for_each_entry_safe(tmp_list, q, &entry, entry) {
- list_del(&tmp_list->entry);
- dput(tmp_list->dentry);
- kfree(tmp_list);
- }
-
/* Flush any pending work that will drop dentries */
flush_workqueue(cfid_put_wq);
}
@@ -571,24 +548,12 @@ done:
* Invalidate all cached dirs when a TCON has been reset
* due to a session loss.
*/
-void invalidate_all_cached_dirs(struct cifs_tcon *tcon)
+void invalidate_all_cached_dirs(struct cached_fids *cfids)
{
- struct cached_fids *cfids = tcon->cfids;
- struct cached_fid *cfid;
-
if (!cfids)
return;
- /* mark all the cfids as closed and invalidate them for laundromat cleanup */
- spin_lock(&cfids->cfid_list_lock);
- list_for_each_entry(cfid, &cfids->entries, entry) {
- invalidate_cfid(cfid);
- cfid->is_open = false;
- }
- spin_unlock(&cfids->cfid_list_lock);
-
- /* run laundromat unconditionally now as there might have been previously queued work */
- mod_delayed_work(cfid_put_wq, &cfids->laundromat_work, 0);
+ invalidate_all_cfids(cfids, true);
flush_delayed_work(&cfids->laundromat_work);
}
@@ -719,34 +684,3 @@ struct cached_fids *init_cached_dirs(void)
return cfids;
}
-
-/*
- * Called from tconInfoFree when we are tearing down the tcon.
- * There are no active users or open files/directories at this point.
- */
-void free_cached_dirs(struct cached_fids *cfids)
-{
- struct cached_fid *cfid, *q;
- LIST_HEAD(entry);
-
- if (cfids == NULL)
- return;
-
- cancel_delayed_work_sync(&cfids->laundromat_work);
-
- spin_lock(&cfids->cfid_list_lock);
- list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
- invalidate_cfid(cfid);
- cfid->is_open = false;
- list_move(&cfid->entry, &entry);
- }
- spin_unlock(&cfids->cfid_list_lock);
-
- list_for_each_entry_safe(cfid, q, &entry, entry) {
- list_del(&cfid->entry);
- drop_cfid(cfid);
- free_cached_dir(cfid);
- }
-
- kfree(cfids);
-}