cifs: fallback to older infolevels on findfirst queryinfo retry
authorSteve French <stfrench@microsoft.com>
Fri, 19 Oct 2018 06:58:22 +0000 (01:58 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 20 Apr 2019 07:15:05 +0000 (09:15 +0200)
[ Upstream commit 3b7960caceafdfc2cdfe2850487f8d091eb41144 ]

In cases where queryinfo fails, we have cases in cifs (vers=1.0)
where with backupuid mounts we retry the query info with findfirst.
This doesn't work to some NetApp servers which don't support
WindowsXP (and later) infolevel 261 (SMB_FIND_FILE_ID_FULL_DIR_INFO)
so in this case use other info levels (in this case it will usually
be level 257, SMB_FIND_FILE_DIRECTORY_INFO).

(Also fixes some indentation)

See kernel bugzilla 201435

Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/cifs/inode.c

index a90a637ae79ab6d1f8fda503463396e26ba65acc..6fd4a6a752341ec38e9afcc1651f517e7eca106b 100644 (file)
@@ -779,43 +779,50 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
        } else if ((rc == -EACCES) && backup_cred(cifs_sb) &&
                   (strcmp(server->vals->version_string, SMB1_VERSION_STRING)
                      == 0)) {
-                       /*
-                        * For SMB2 and later the backup intent flag is already
-                        * sent if needed on open and there is no path based
-                        * FindFirst operation to use to retry with
-                        */
+               /*
+                * For SMB2 and later the backup intent flag is already
+                * sent if needed on open and there is no path based
+                * FindFirst operation to use to retry with
+                */
 
-                       srchinf = kzalloc(sizeof(struct cifs_search_info),
-                                               GFP_KERNEL);
-                       if (srchinf == NULL) {
-                               rc = -ENOMEM;
-                               goto cgii_exit;
-                       }
+               srchinf = kzalloc(sizeof(struct cifs_search_info),
+                                       GFP_KERNEL);
+               if (srchinf == NULL) {
+                       rc = -ENOMEM;
+                       goto cgii_exit;
+               }
 
-                       srchinf->endOfSearch = false;
+               srchinf->endOfSearch = false;
+               if (tcon->unix_ext)
+                       srchinf->info_level = SMB_FIND_FILE_UNIX;
+               else if ((tcon->ses->capabilities &
+                        tcon->ses->server->vals->cap_nt_find) == 0)
+                       srchinf->info_level = SMB_FIND_FILE_INFO_STANDARD;
+               else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
                        srchinf->info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO;
+               else /* no srvino useful for fallback to some netapp */
+                       srchinf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
 
-                       srchflgs = CIFS_SEARCH_CLOSE_ALWAYS |
-                                       CIFS_SEARCH_CLOSE_AT_END |
-                                       CIFS_SEARCH_BACKUP_SEARCH;
+               srchflgs = CIFS_SEARCH_CLOSE_ALWAYS |
+                               CIFS_SEARCH_CLOSE_AT_END |
+                               CIFS_SEARCH_BACKUP_SEARCH;
 
-                       rc = CIFSFindFirst(xid, tcon, full_path,
-                               cifs_sb, NULL, srchflgs, srchinf, false);
-                       if (!rc) {
-                               data =
-                               (FILE_ALL_INFO *)srchinf->srch_entries_start;
+               rc = CIFSFindFirst(xid, tcon, full_path,
+                       cifs_sb, NULL, srchflgs, srchinf, false);
+               if (!rc) {
+                       data = (FILE_ALL_INFO *)srchinf->srch_entries_start;
 
-                               cifs_dir_info_to_fattr(&fattr,
-                               (FILE_DIRECTORY_INFO *)data, cifs_sb);
-                               fattr.cf_uniqueid = le64_to_cpu(
-                               ((SEARCH_ID_FULL_DIR_INFO *)data)->UniqueId);
-                               validinum = true;
+                       cifs_dir_info_to_fattr(&fattr,
+                       (FILE_DIRECTORY_INFO *)data, cifs_sb);
+                       fattr.cf_uniqueid = le64_to_cpu(
+                       ((SEARCH_ID_FULL_DIR_INFO *)data)->UniqueId);
+                       validinum = true;
 
-                               cifs_buf_release(srchinf->ntwrk_buf_start);
-                       }
-                       kfree(srchinf);
-                       if (rc)
-                               goto cgii_exit;
+                       cifs_buf_release(srchinf->ntwrk_buf_start);
+               }
+               kfree(srchinf);
+               if (rc)
+                       goto cgii_exit;
        } else
                goto cgii_exit;