Skip to content

Commit 9e99275

Browse files
rohiths-msftsmfrench
authored andcommitted
cifs: Call close synchronously during unlink/rename/lease break.
During unlink/rename/lease break, deferred work for close is scheduled immediately but in an asynchronous manner which might lead to race with actual(unlink/rename) commands. This change will schedule close synchronously which will avoid the race conditions with other commands. Signed-off-by: Rohith Surabattula <[email protected]> Reviewed-by: Shyam Prasad N <[email protected]> Cc: [email protected] # 5.13 Signed-off-by: Steve French <[email protected]>
1 parent 4153570 commit 9e99275

File tree

3 files changed

+56
-30
lines changed

3 files changed

+56
-30
lines changed

fs/cifs/cifsglob.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1611,6 +1611,11 @@ struct dfs_info3_param {
16111611
int ttl;
16121612
};
16131613

1614+
struct file_list {
1615+
struct list_head list;
1616+
struct cifsFileInfo *cfile;
1617+
};
1618+
16141619
/*
16151620
* common struct for holding inode info when searching for or updating an
16161621
* inode with new info

fs/cifs/file.c

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4847,35 +4847,34 @@ void cifs_oplock_break(struct work_struct *work)
48474847
cifs_dbg(VFS, "Push locks rc = %d\n", rc);
48484848

48494849
oplock_break_ack:
4850-
/*
4851-
* releasing stale oplock after recent reconnect of smb session using
4852-
* a now incorrect file handle is not a data integrity issue but do
4853-
* not bother sending an oplock release if session to server still is
4854-
* disconnected since oplock already released by the server
4855-
*/
4856-
if (!cfile->oplock_break_cancelled) {
4857-
rc = tcon->ses->server->ops->oplock_response(tcon, &cfile->fid,
4858-
cinode);
4859-
cifs_dbg(FYI, "Oplock release rc = %d\n", rc);
4860-
}
48614850
/*
48624851
* When oplock break is received and there are no active
48634852
* file handles but cached, then schedule deferred close immediately.
48644853
* So, new open will not use cached handle.
48654854
*/
48664855
spin_lock(&CIFS_I(inode)->deferred_lock);
48674856
is_deferred = cifs_is_deferred_close(cfile, &dclose);
4857+
spin_unlock(&CIFS_I(inode)->deferred_lock);
48684858
if (is_deferred &&
48694859
cfile->deferred_close_scheduled &&
48704860
delayed_work_pending(&cfile->deferred)) {
4871-
/*
4872-
* If there is no pending work, mod_delayed_work queues new work.
4873-
* So, Increase the ref count to avoid use-after-free.
4874-
*/
4875-
if (!mod_delayed_work(deferredclose_wq, &cfile->deferred, 0))
4876-
cifsFileInfo_get(cfile);
4861+
if (cancel_delayed_work(&cfile->deferred)) {
4862+
_cifsFileInfo_put(cfile, false, false);
4863+
goto oplock_break_done;
4864+
}
48774865
}
4878-
spin_unlock(&CIFS_I(inode)->deferred_lock);
4866+
/*
4867+
* releasing stale oplock after recent reconnect of smb session using
4868+
* a now incorrect file handle is not a data integrity issue but do
4869+
* not bother sending an oplock release if session to server still is
4870+
* disconnected since oplock already released by the server
4871+
*/
4872+
if (!cfile->oplock_break_cancelled) {
4873+
rc = tcon->ses->server->ops->oplock_response(tcon, &cfile->fid,
4874+
cinode);
4875+
cifs_dbg(FYI, "Oplock release rc = %d\n", rc);
4876+
}
4877+
oplock_break_done:
48794878
_cifsFileInfo_put(cfile, false /* do not wait for ourself */, false);
48804879
cifs_done_oplock_break(cinode);
48814880
}

fs/cifs/misc.c

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -723,41 +723,63 @@ void
723723
cifs_close_deferred_file(struct cifsInodeInfo *cifs_inode)
724724
{
725725
struct cifsFileInfo *cfile = NULL;
726+
struct file_list *tmp_list, *tmp_next_list;
727+
struct list_head file_head;
726728

727729
if (cifs_inode == NULL)
728730
return;
729731

732+
INIT_LIST_HEAD(&file_head);
733+
spin_lock(&cifs_inode->open_file_lock);
730734
list_for_each_entry(cfile, &cifs_inode->openFileList, flist) {
731735
if (delayed_work_pending(&cfile->deferred)) {
732-
/*
733-
* If there is no pending work, mod_delayed_work queues new work.
734-
* So, Increase the ref count to avoid use-after-free.
735-
*/
736-
if (!mod_delayed_work(deferredclose_wq, &cfile->deferred, 0))
737-
cifsFileInfo_get(cfile);
736+
if (cancel_delayed_work(&cfile->deferred)) {
737+
tmp_list = kmalloc(sizeof(struct file_list), GFP_ATOMIC);
738+
if (tmp_list == NULL)
739+
continue;
740+
tmp_list->cfile = cfile;
741+
list_add_tail(&tmp_list->list, &file_head);
742+
}
738743
}
739744
}
745+
spin_unlock(&cifs_inode->open_file_lock);
746+
747+
list_for_each_entry_safe(tmp_list, tmp_next_list, &file_head, list) {
748+
_cifsFileInfo_put(tmp_list->cfile, true, false);
749+
list_del(&tmp_list->list);
750+
kfree(tmp_list);
751+
}
740752
}
741753

742754
void
743755
cifs_close_all_deferred_files(struct cifs_tcon *tcon)
744756
{
745757
struct cifsFileInfo *cfile;
746758
struct list_head *tmp;
759+
struct file_list *tmp_list, *tmp_next_list;
760+
struct list_head file_head;
747761

762+
INIT_LIST_HEAD(&file_head);
748763
spin_lock(&tcon->open_file_lock);
749764
list_for_each(tmp, &tcon->openFileList) {
750765
cfile = list_entry(tmp, struct cifsFileInfo, tlist);
751766
if (delayed_work_pending(&cfile->deferred)) {
752-
/*
753-
* If there is no pending work, mod_delayed_work queues new work.
754-
* So, Increase the ref count to avoid use-after-free.
755-
*/
756-
if (!mod_delayed_work(deferredclose_wq, &cfile->deferred, 0))
757-
cifsFileInfo_get(cfile);
767+
if (cancel_delayed_work(&cfile->deferred)) {
768+
tmp_list = kmalloc(sizeof(struct file_list), GFP_ATOMIC);
769+
if (tmp_list == NULL)
770+
continue;
771+
tmp_list->cfile = cfile;
772+
list_add_tail(&tmp_list->list, &file_head);
773+
}
758774
}
759775
}
760776
spin_unlock(&tcon->open_file_lock);
777+
778+
list_for_each_entry_safe(tmp_list, tmp_next_list, &file_head, list) {
779+
_cifsFileInfo_put(tmp_list->cfile, true, false);
780+
list_del(&tmp_list->list);
781+
kfree(tmp_list);
782+
}
761783
}
762784

763785
/* parses DFS refferal V3 structure

0 commit comments

Comments
 (0)