fs/cifs: reopen persistent handles on reconnect
authorSteve French <smfrench@gmail.com>
Fri, 23 Sep 2016 00:23:56 +0000 (19:23 -0500)
committerSteve French <smfrench@gmail.com>
Wed, 12 Oct 2016 17:08:33 +0000 (12:08 -0500)
Continuous Availability features like persistent handles
require that clients reconnect their open files, not
just the sessions, soon after the network connection comes
back up, otherwise the server will throw away the state
(byte range locks, leases, deny modes) on those handles
after a timeout.

Add code to reconnect handles when use_persistent set
(e.g. Continuous Availability shares) after tree reconnect.

Signed-off-by: Aurelien Aptel <aaptel@suse.com>
Reviewed-by: Germano Percossi <germano.percossi@citrix.com>
Signed-off-by: Steve French <smfrench@gmail.com>
fs/cifs/cifsproto.h
fs/cifs/file.c
fs/cifs/smb2pdu.c

index 4ead72a001f974d4e3b18dedf7a2466f4426c0e9..ced0e42ce460963104d89bb8b941b899ceb33dea 100644 (file)
@@ -193,6 +193,8 @@ extern struct smb_vol *cifs_get_volume_info(char *mount_data,
 extern int cifs_mount(struct cifs_sb_info *, struct smb_vol *);
 extern void cifs_umount(struct cifs_sb_info *);
 extern void cifs_mark_open_files_invalid(struct cifs_tcon *tcon);
+extern void cifs_reopen_persistent_handles(struct cifs_tcon *tcon);
+
 extern bool cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset,
                                    __u64 length, __u8 type,
                                    struct cifsLockInfo **conf_lock,
index ee5ceae224118ceef87f6cab05344ce97ec1da14..8f27c8a74384beccf721ff96e9849b373a997c26 100644 (file)
@@ -760,6 +760,24 @@ int cifs_close(struct inode *inode, struct file *file)
        return 0;
 }
 
+void
+cifs_reopen_persistent_handles(struct cifs_tcon *tcon)
+{
+       struct cifsFileInfo *open_file = NULL;
+       struct list_head *tmp;
+       struct list_head *tmp1;
+
+       /* list all files open on tree connection, reopen resilient handles  */
+       spin_lock(&tcon->open_file_lock);
+       list_for_each_safe(tmp, tmp1, &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);
+       }
+       spin_unlock(&tcon->open_file_lock);
+}
+
 int cifs_closedir(struct inode *inode, struct file *file)
 {
        int rc = 0;
index 3eec96ca87d9955e0e1fe6c77df7e20961f6dec1..4d944c4c55a825241118756c9c0776b42378d196 100644 (file)
@@ -250,8 +250,13 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
        }
 
        cifs_mark_open_files_invalid(tcon);
+
        rc = SMB2_tcon(0, tcon->ses, tcon->treeName, tcon, nls_codepage);
        mutex_unlock(&tcon->ses->session_mutex);
+
+       if (tcon->use_persistent)
+               cifs_reopen_persistent_handles(tcon);
+
        cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
        if (rc)
                goto out;