diff options
author | Pavel Shilovsky <pshilov@microsoft.com> | 2016-10-07 17:26:36 -0700 |
---|---|---|
committer | Steve French <smfrench@gmail.com> | 2016-10-13 19:48:55 -0500 |
commit | f2cca6a7c99fdeadacd0bdc37d825c4bc2b03653 (patch) | |
tree | 56eb1f191ef0846f13f392bf2d207f0ba0460934 | |
parent | 166cea4dc3a4f66f020cfb9286225ecd228ab61d (diff) | |
download | linux-f2cca6a7c99fdeadacd0bdc37d825c4bc2b03653.tar.bz2 |
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>
-rw-r--r-- | fs/cifs/cifsglob.h | 1 | ||||
-rw-r--r-- | fs/cifs/file.c | 22 |
2 files changed, 18 insertions, 5 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index d9a17288baf3..0c828d3c48c3 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -1065,6 +1065,7 @@ struct cifsFileInfo { kuid_t uid; /* allows finding which FileInfo structure */ __u32 pid; /* process id who opened file */ struct cifs_fid fid; /* file id from remote */ + struct list_head rlist; /* reconnect list */ /* BB add lock scope info here if needed */ ; /* lock scope id (0 if none) */ struct dentry *dentry; diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 8f27c8a74384..07c14f9217cb 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -763,19 +763,31 @@ int cifs_close(struct inode *inode, struct file *file) void cifs_reopen_persistent_handles(struct cifs_tcon *tcon) { - struct cifsFileInfo *open_file = NULL; + struct cifsFileInfo *open_file; struct list_head *tmp; 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 */ 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); - spin_unlock(&tcon->open_file_lock); - cifs_reopen_file(open_file, false /* do not flush */); - spin_lock(&tcon->open_file_lock); + if (!open_file->invalidHandle) + continue; + cifsFileInfo_get(open_file); + list_add_tail(&open_file->rlist, &tmp_list); } 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) |