]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/cifs/file.c
NFS: Clear key construction data if the idmap upcall fails
[karo-tx-linux.git] / fs / cifs / file.c
index 81725e9286e911f501e4a78d1d7c28768753d118..e7ebb5a2ed1c8c154d7bd7d6770cd5ca64ba2aa1 100644 (file)
@@ -1539,10 +1539,11 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
 struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
                                        bool fsuid_only)
 {
-       struct cifsFileInfo *open_file;
+       struct cifsFileInfo *open_file, *inv_file = NULL;
        struct cifs_sb_info *cifs_sb;
        bool any_available = false;
        int rc;
+       unsigned int refind = 0;
 
        /* Having a null inode here (because mapping->host was set to zero by
        the VFS or MM) should not happen but we had reports of on oops (due to
@@ -1562,40 +1563,25 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
 
        spin_lock(&cifs_file_list_lock);
 refind_writable:
+       if (refind > MAX_REOPEN_ATT) {
+               spin_unlock(&cifs_file_list_lock);
+               return NULL;
+       }
        list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
                if (!any_available && open_file->pid != current->tgid)
                        continue;
                if (fsuid_only && open_file->uid != current_fsuid())
                        continue;
                if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
-                       cifsFileInfo_get(open_file);
-
                        if (!open_file->invalidHandle) {
                                /* found a good writable file */
+                               cifsFileInfo_get(open_file);
                                spin_unlock(&cifs_file_list_lock);
                                return open_file;
+                       } else {
+                               if (!inv_file)
+                                       inv_file = open_file;
                        }
-
-                       spin_unlock(&cifs_file_list_lock);
-
-                       /* Had to unlock since following call can block */
-                       rc = cifs_reopen_file(open_file, false);
-                       if (!rc)
-                               return open_file;
-
-                       /* if it fails, try another handle if possible */
-                       cFYI(1, "wp failed on reopen file");
-                       cifsFileInfo_put(open_file);
-
-                       spin_lock(&cifs_file_list_lock);
-
-                       /* else we simply continue to the next entry. Thus
-                          we do not loop on reopen errors.  If we
-                          can not reopen the file, for example if we
-                          reconnected to a server with another client
-                          racing to delete or lock the file we would not
-                          make progress if we restarted before the beginning
-                          of the loop here. */
                }
        }
        /* couldn't find useable FH with same pid, try any available */
@@ -1603,7 +1589,30 @@ refind_writable:
                any_available = true;
                goto refind_writable;
        }
+
+       if (inv_file) {
+               any_available = false;
+               cifsFileInfo_get(inv_file);
+       }
+
        spin_unlock(&cifs_file_list_lock);
+
+       if (inv_file) {
+               rc = cifs_reopen_file(inv_file, false);
+               if (!rc)
+                       return inv_file;
+               else {
+                       spin_lock(&cifs_file_list_lock);
+                       list_move_tail(&inv_file->flist,
+                                       &cifs_inode->openFileList);
+                       spin_unlock(&cifs_file_list_lock);
+                       cifsFileInfo_put(inv_file);
+                       spin_lock(&cifs_file_list_lock);
+                       ++refind;
+                       goto refind_writable;
+               }
+       }
+
        return NULL;
 }