Merge branch 'stable/for-linus-5.14' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-microblaze.git] / fs / cifs / misc.c
index 524dbdf..7207a63 100644 (file)
@@ -672,6 +672,11 @@ cifs_add_pending_open(struct cifs_fid *fid, struct tcon_link *tlink,
        spin_unlock(&tlink_tcon(open->tlink)->open_file_lock);
 }
 
+/*
+ * Critical section which runs after acquiring deferred_lock.
+ * As there is no reference count on cifs_deferred_close, pdclose
+ * should not be used outside deferred_lock.
+ */
 bool
 cifs_is_deferred_close(struct cifsFileInfo *cfile, struct cifs_deferred_close **pdclose)
 {
@@ -688,6 +693,9 @@ cifs_is_deferred_close(struct cifsFileInfo *cfile, struct cifs_deferred_close **
        return false;
 }
 
+/*
+ * Critical section which runs after acquiring deferred_lock.
+ */
 void
 cifs_add_deferred_close(struct cifsFileInfo *cfile, struct cifs_deferred_close *dclose)
 {
@@ -707,6 +715,9 @@ cifs_add_deferred_close(struct cifsFileInfo *cfile, struct cifs_deferred_close *
        list_add_tail(&dclose->dlist, &CIFS_I(d_inode(cfile->dentry))->deferred_closes);
 }
 
+/*
+ * Critical section which runs after acquiring deferred_lock.
+ */
 void
 cifs_del_deferred_close(struct cifsFileInfo *cfile)
 {
@@ -738,15 +749,19 @@ void
 cifs_close_all_deferred_files(struct cifs_tcon *tcon)
 {
        struct cifsFileInfo *cfile;
-       struct cifsInodeInfo *cinode;
        struct list_head *tmp;
 
        spin_lock(&tcon->open_file_lock);
        list_for_each(tmp, &tcon->openFileList) {
                cfile = list_entry(tmp, struct cifsFileInfo, tlist);
-               cinode = CIFS_I(d_inode(cfile->dentry));
-               if (delayed_work_pending(&cfile->deferred))
-                       mod_delayed_work(deferredclose_wq, &cfile->deferred, 0);
+               if (delayed_work_pending(&cfile->deferred)) {
+                       /*
+                        * If there is no pending work, mod_delayed_work queues new work.
+                        * So, Increase the ref count to avoid use-after-free.
+                        */
+                       if (!mod_delayed_work(deferredclose_wq, &cfile->deferred, 0))
+                               cifsFileInfo_get(cfile);
+               }
        }
        spin_unlock(&tcon->open_file_lock);
 }