Commit f2cca6a7 authored by Pavel Shilovsky's avatar Pavel Shilovsky Committed by Steve French

CIFS: Fix persistent handles re-opening on reconnect

openFileList of tcon can be changed while cifs_reopen_file() is called
that can lead to an unexpected behavior when we return to the loop.
Fix this by introducing a temp list for keeping all file handles that
need to be reopen.
Signed-off-by: default avatarPavel Shilovsky <pshilov@microsoft.com>
Signed-off-by: default avatarSteve French <smfrench@gmail.com>
parent 166cea4d
...@@ -1065,6 +1065,7 @@ struct cifsFileInfo { ...@@ -1065,6 +1065,7 @@ struct cifsFileInfo {
kuid_t uid; /* allows finding which FileInfo structure */ kuid_t uid; /* allows finding which FileInfo structure */
__u32 pid; /* process id who opened file */ __u32 pid; /* process id who opened file */
struct cifs_fid fid; /* file id from remote */ struct cifs_fid fid; /* file id from remote */
struct list_head rlist; /* reconnect list */
/* BB add lock scope info here if needed */ ; /* BB add lock scope info here if needed */ ;
/* lock scope id (0 if none) */ /* lock scope id (0 if none) */
struct dentry *dentry; struct dentry *dentry;
......
...@@ -763,19 +763,31 @@ int cifs_close(struct inode *inode, struct file *file) ...@@ -763,19 +763,31 @@ int cifs_close(struct inode *inode, struct file *file)
void void
cifs_reopen_persistent_handles(struct cifs_tcon *tcon) cifs_reopen_persistent_handles(struct cifs_tcon *tcon)
{ {
struct cifsFileInfo *open_file = NULL; struct cifsFileInfo *open_file;
struct list_head *tmp; struct list_head *tmp;
struct list_head *tmp1; struct list_head *tmp1;
struct list_head tmp_list;
cifs_dbg(FYI, "Reopen persistent handles");
INIT_LIST_HEAD(&tmp_list);
/* list all files open on tree connection, reopen resilient handles */ /* list all files open on tree connection, reopen resilient handles */
spin_lock(&tcon->open_file_lock); spin_lock(&tcon->open_file_lock);
list_for_each_safe(tmp, tmp1, &tcon->openFileList) { list_for_each(tmp, &tcon->openFileList) {
open_file = list_entry(tmp, struct cifsFileInfo, tlist); open_file = list_entry(tmp, struct cifsFileInfo, tlist);
spin_unlock(&tcon->open_file_lock); if (!open_file->invalidHandle)
cifs_reopen_file(open_file, false /* do not flush */); continue;
spin_lock(&tcon->open_file_lock); cifsFileInfo_get(open_file);
list_add_tail(&open_file->rlist, &tmp_list);
} }
spin_unlock(&tcon->open_file_lock); spin_unlock(&tcon->open_file_lock);
list_for_each_safe(tmp, tmp1, &tmp_list) {
open_file = list_entry(tmp, struct cifsFileInfo, rlist);
cifs_reopen_file(open_file, false /* do not flush */);
list_del_init(&open_file->rlist);
cifsFileInfo_put(open_file);
}
} }
int cifs_closedir(struct inode *inode, struct file *file) int cifs_closedir(struct inode *inode, struct file *file)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment