CIFS: Fix persistent handles re-opening on reconnect
authorPavel Shilovsky <pshilov@microsoft.com>
Sat, 8 Oct 2016 00:26:36 +0000 (17:26 -0700)
committerSteve French <smfrench@gmail.com>
Fri, 14 Oct 2016 00:48:55 +0000 (19:48 -0500)
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>
fs/cifs/cifsglob.h
fs/cifs/file.c

index d9a1728..0c828d3 100644 (file)
@@ -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;
index 8f27c8a..07c14f9 100644 (file)
@@ -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)