cifs: add a helper to find an existing readable handle to a file
authorRonnie Sahlberg <lsahlber@redhat.com>
Mon, 9 Sep 2019 05:30:00 +0000 (15:30 +1000)
committerSteve French <stfrench@microsoft.com>
Mon, 16 Sep 2019 16:43:38 +0000 (11:43 -0500)
and convert smb2_query_path_info() to use it.
This will eliminate the need for a SMB2_Create when we already have an
open handle that can be used. This will also prevent a oplock break
in case the other handle holds a lease.

Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/cifs/cifsproto.h
fs/cifs/file.c
fs/cifs/smb2inode.c

index 7b69037..99b1b1e 100644 (file)
@@ -140,6 +140,8 @@ extern int cifs_get_writable_file(struct cifsInodeInfo *cifs_inode,
 extern int cifs_get_writable_path(struct cifs_tcon *tcon, const char *name,
                                  struct cifsFileInfo **ret_file);
 extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool);
+extern int cifs_get_readable_path(struct cifs_tcon *tcon, const char *name,
+                                 struct cifsFileInfo **ret_file);
 extern unsigned int smbCalcSize(void *buf, struct TCP_Server_Info *server);
 extern int decode_negTokenInit(unsigned char *security_blob, int length,
                        struct TCP_Server_Info *server);
index 6124b1d..4b95700 100644 (file)
@@ -2008,6 +2008,42 @@ cifs_get_writable_path(struct cifs_tcon *tcon, const char *name,
        return -ENOENT;
 }
 
+int
+cifs_get_readable_path(struct cifs_tcon *tcon, const char *name,
+                      struct cifsFileInfo **ret_file)
+{
+       struct list_head *tmp;
+       struct cifsFileInfo *cfile;
+       struct cifsInodeInfo *cinode;
+       char *full_path;
+
+       *ret_file = NULL;
+
+       spin_lock(&tcon->open_file_lock);
+       list_for_each(tmp, &tcon->openFileList) {
+               cfile = list_entry(tmp, struct cifsFileInfo,
+                            tlist);
+               full_path = build_path_from_dentry(cfile->dentry);
+               if (full_path == NULL) {
+                       spin_unlock(&tcon->open_file_lock);
+                       return -ENOMEM;
+               }
+               if (strcmp(full_path, name)) {
+                       kfree(full_path);
+                       continue;
+               }
+
+               kfree(full_path);
+               cinode = CIFS_I(d_inode(cfile->dentry));
+               spin_unlock(&tcon->open_file_lock);
+               *ret_file = find_readable_file(cinode, 0);
+               return *ret_file ? 0 : -ENOENT;
+       }
+
+       spin_unlock(&tcon->open_file_lock);
+       return -ENOENT;
+}
+
 static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
 {
        struct address_space *mapping = page->mapping;
index 9bb0a5b..c866555 100644 (file)
@@ -125,15 +125,31 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
                rqst[num_rqst].rq_iov = qi_iov;
                rqst[num_rqst].rq_nvec = 1;
 
-               rc = SMB2_query_info_init(tcon, &rqst[num_rqst], COMPOUND_FID,
-                               COMPOUND_FID, FILE_ALL_INFORMATION,
+               if (cfile)
+                       rc = SMB2_query_info_init(tcon, &rqst[num_rqst],
+                               cfile->fid.persistent_fid,
+                               cfile->fid.volatile_fid,
+                               FILE_ALL_INFORMATION,
                                SMB2_O_INFO_FILE, 0,
                                sizeof(struct smb2_file_all_info) +
                                          PATH_MAX * 2, 0, NULL);
+               else {
+                       rc = SMB2_query_info_init(tcon, &rqst[num_rqst],
+                               COMPOUND_FID,
+                               COMPOUND_FID,
+                                FILE_ALL_INFORMATION,
+                               SMB2_O_INFO_FILE, 0,
+                               sizeof(struct smb2_file_all_info) +
+                                         PATH_MAX * 2, 0, NULL);
+                       if (!rc) {
+                               smb2_set_next_command(tcon, &rqst[num_rqst]);
+                               smb2_set_related(&rqst[num_rqst]);
+                       }
+               }
+
                if (rc)
                        goto finished;
-               smb2_set_next_command(tcon, &rqst[num_rqst]);
-               smb2_set_related(&rqst[num_rqst++]);
+               num_rqst++;
                trace_smb3_query_info_compound_enter(xid, ses->Suid, tcon->tid,
                                                     full_path);
                break;
@@ -421,6 +437,7 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
        __u32 create_options = 0;
        struct cifs_fid fid;
        bool no_cached_open = tcon->nohandlecache;
+       struct cifsFileInfo *cfile;
 
        *adjust_tz = false;
        *symlink = false;
@@ -452,9 +469,10 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
        if (backup_cred(cifs_sb))
                create_options |= CREATE_OPEN_BACKUP_INTENT;
 
+       cifs_get_readable_path(tcon, full_path, &cfile);
        rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
                              FILE_READ_ATTRIBUTES, FILE_OPEN, create_options,
-                             smb2_data, SMB2_OP_QUERY_INFO, NULL);
+                             smb2_data, SMB2_OP_QUERY_INFO, cfile);
        if (rc == -EOPNOTSUPP) {
                *symlink = true;
                create_options |= OPEN_REPARSE_POINT;