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: Pavel Shilovsky <pshilov@microsoft.com> Signed-off-by: Steve French <smfrench@gmail.com>
This commit is contained in:
committed by
Steve French
parent
166cea4dc3
commit
f2cca6a7c9
@@ -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)
|
|||||||
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)
|
||||||
|
|||||||
Reference in New Issue
Block a user